././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707393948.6585588 reportlab-4.1.0/0000775000175000017500000000000014561141635013110 5ustar00rptlabrptlab././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1707393617.0 reportlab-4.1.0/CHANGES.md0000664000175000017500000014355614561141121014506 0ustar00rptlabrptlabCHANGES ======= This is a summary of changes made to the reportlab source code for each release. Please refer to subversion backlogs (using the release dates) for more details or for releases which we have not provide a higher level changes list for. E.g. to retrieve the changes made between release 3.4 and release 3.5, type:: $ hg log -r 54ce2469ba5c The contributors lists are in no order and apologies to those accidentally not mentioned. If we missed you, please let us know! CHANGES 4.1.0 08/02/2024 ------------------------- * No change. Changes to commercial package, re-released with same version number CHANGES 4.0.9.1 23/01/2024 --------------------------- * use ttf subsets[0][1:32] fillin * implement drawBoundary as a proper canvas method (removing it from Frame) CHANGES 4.0.9 08/01/2024 --------------------------- * fix TTFont hmtx bug and force index 0(.notdef) in subsets as better for PDFUA CHANGES 4.0.8 11/12/2023 --------------------------- * fix rparsexml bug contributed by Matt Folwell mjf at pearson co uk * allow class ddf attributes for Labels * add rl_settings.defCWRF defined col width reduction fraction * fix table wrapping bug contributed by Manuel Koch manuel koch at shinefour de CHANGES 4.0.7 06/11/2023 --------------------------- * allow testutils.makeSuiteForClasses to specify a prefix for test method names * SpiderChart can have direct draw flowable labels * fix and improve tests for python -mreportlab.lib.rl_accel * fix barchart 3D stacked case & fix barchart valueAxis reverseDirection behaviour. CHANGES 4.0.6 10/10/2023 --------------------------- * fix importlib usage in reportlab init, reported by Frank Epperlein and others * add value axes extraMinMaxValues as aid to parallel axes * add styles str2alignment maps left/right/center/centre/justify etc * fix validators.isSubclassOf * test ddfStyle as instance first in textlabels.py * allow Pie Doughnut classes to control label class CHANGES 4.0.5 12/07/2023 --------------------------- * add in test for alpha composite colour * Added an SvgPath class; as used in github.com/deeplook/svglib * Added a simple log axis ticklabeller class * Allow for strokeWidth in LineSwatch CHANGES 4.0.4 01/06/2023 --------------------------- * update extension alias' CHANGES 4.0.3 31/05/2023 --------------------------- * allow BalancedColumns to work in a container flowable (ie with no frame) * allow custom styles for inrowsplitStaart & inrowsplitend CHANGES 4.0.2 16/05/2023 --------------------------- * setup.py test --failfast works * allow running all tests without renderPM support CHANGES 4.0.1 12/05/2023 --------------------------- * AR made some changes to allow running without renderPM support CHANGES 4.0.0 04/05/2023 --------------------------- * AR merged accessibility branch and released 4.0.0 CHANGES 4.0.0a3 18/04/2023 --------------------------- * initial support for rml ul ol dl tagging * added support for an ol/ul/dl caption paragraph * implement a safer toColor with rl_config.toColorCanUse option and rl_extended_literal_eval CHANGES 4.0.0a2 14/03/2023 --------------------------- * added _ExpandedCellTupleEx for more tagging support CHANGES 4.0.0a1 08/03/2023 --------------------------- * release 4.0.0a1 with support for rlextra pluscode CHANGES 3.6.13 24/04/2023 --------------------------- * fixes for python 3.12.0a1 * tables.py error improvement * allow exclusions in tests in runAll.py and setup.py; allows for coverage.py importing failures. * implement a safer toColor with rl_config.toColorCanUse option and rl_extended_literal_eval CHANGES 3.6.12 25/10/2022 --------------------------- * fix dpi handling in renderPM.py; bug found by Terry Zhao Terry dot Zhao at fil dot com * attempt fix in rparsexml.py * add rl_settings.xmlParser with default 'lxml' * nano RHEL related fix to setup.py contributed by James Brown jbrown at easypost dot com * minor speedup in reportlab.graphics.transform functions * allow usage of freetype testpaths via rl_config/rl_settings textPaths * _renderPM.c remove parse_utf8, make pict_putrow same as for rlPyCairo CHANGES 3.6.11 24/06/2022 --------------------------- * support HORIZONTAL2 & VERTICAL2 table cell backgrounds; as suggested by Sina Khelil < sina at khelil dot com > * support general LINEAR & RADIAL gradient table cell backgrounds * support ShowBoundaryValue in canv.drawImage CHANGES 3.6.10 31/05/2022 --------------------------- * fix symlink looping in setup.py reported by Michał Górny < mgorny at gentoo dot org > * allow bearerBox attribute for some barcodes * require pillow>=9.0.0 patch contributed by Claude Paroz claude at 2xlibre.net * Apply Claude Paroz < claude at 2xlibre dot net > patch to assume hashlib md5 exists * ImageReader updated to allow deepcopy; similarly for doctemplate.onDrawStr * fix 3.11.0b2 regression in rl_safe_eval. * apply massive contribution for Table inRowSplit from Lennart Regebro < lregebro at shoobx dot com > CHANGES 3.6.9 22/03/2022 --------------------------- * fix up _rl_accel.c 0.81 to allow better error messages and support python 3.11.0a6 * change the cibuildwheel setup to support macos M1 build CHANGES 3.6.8 28/02/2022 --------------------------- * remove old Python2 constructs; patch from Claude Paroz < claude at 2xlibre dot net > CHANGES 3.6.7 18/02/2022 --------------------------- * Remove use of cPickle; patch from Claude Paroz < claude at 2xlibre dot net > * Remove unneccessary object inheritance; patch by Claude Paroz * minor changes to python rendering in shapes.Drawing * remove jython (dead project no python3) patch by Claude Paroz < claude at 2xlibre dot net > * remove unicodeT/bytesT patch by Claude Paroz < claude at 2xlibre dot net > * import directly from string module patch by Claude Paroz < claude at 2xlibre dot net > * eliminate getBytesIO and getStringIO patch by Claude Paroz < claude at 2xlibre dot net > * remove unused and indirect imports patch by Claude Paroz < claude at 2xlibre dot net > CHANGES 3.6.6 24/01/2022 --------------------------- * remove uniChr alias of chr (patch contribution from Claude Paroz) * modify pdfdoc template to be eventually compatible with pikepdf suggested by Lennart Regebro lregebro at shoobx.com * fix bug in table gradient bg; contribution by Justin Brzozoski justin.brzozoski at gmail.com * fix bug in validateSetattr (__dict__) discovered and reported by Chris Buergi cb at enerweb dot ch * fix handling of ddfStyle in XLabel class CHANGES 3.6.5 24/12/2021 --------------------------- * only skip listwrap on for small height objects * changes to allow for deprecated stuff in Python-3.11 CHANGES 3.6.4 7/12/2021 --------------------------- * try to improve multi-frag paragraph justification * fix justification condition * allow validator OneOf to take re.Pattern CHANGES 3.6.3 4/11/2021 --------------------------- * modernisation of para.py contribution from * many changes to .github workflows * changes to setup.py to support cibuildwheel * _FindSplitterMixin protect against deepcopy failure * allow textAnnotation to have QuadPoints keyword CHANGES 3.6.2 1/10/2021 --------------------------- * minor changes to datareader * fix XLabel argument usage CHANGES 3.6.1 6/08/2021 --------------------------- * add mock for urlopen calls so tests can run off line. Contribution by Antonio Trande sagitter at fedoraproject dot org CHANGES 3.6.0 23/07/2021 --------------------------- * create py-2-3 branch * Cease support for Python-2.7 CHANGES 3.5.68 25/06/2021 --------------------------- * graphics improve some error messages for renderPM * changed lib.urilt.recursiveImport after errors in python3.10, reflect changes in readJPEGInfo * pdfutils readJPEGInfo extracts dpi if present defaults to (72, 72) * Image flowable allows a useDPI argument * paraparser annotate some errors CHANGES 3.5.67 12/04/2021 --------------------------- * Allow unicode PDFString to use encoding directly; fixes bug where colorspace indexes are broken * Ensure PIL images can be size checked CHANGES 3.5.66 19/03/2021 --------------------------- * fix obvious bug in renderPS.py cut'n'paste bah :( * fix bug saving to SpooledtemporaryFile's reported by Robert Schroll * fix bug in justified RTL paragraphs example & bugfix contributed by Moshe Uminer * fix regex deprecation reported by Jürgen Gmach CHANGES 3.5.65 10/03/2021 --------------------------- * add yieldNoneSplits utility function * fix BarChart so it lines can have markers and Nones in their data CHANGES 3.5.64 09/03/2021 --------------------------- * add ability to have lineplots in barcharts; no support yet for line markers * added checkAttr method to TypedPropertyCollection CHANGES 3.5.63 05/03/2021 --------------------------- * ensure setup.py works from sdist; bug reported by Antonio P. Sagitter (sagitter at fedoraproject.org) * restore broken MANIFEST.in somehow overwritten by Robin :( CHANGES 3.5.62 03/03/2021 --------------------------- * simplify annotateException and add better error messages for asUnicode/Bytes etc * improve embeddedHyphenation in paragraph.py CHANGES 3.5.61 25/02/2021 --------------------------- * add adjustableArrow widget * allow para tag borderPadding attribute * minor cosmetics in renderPM C extension and add fontSize setattr * allow a bounding box constraint in definePath * efficiency savings in text2Path * refactor transformation math and text2Path functionality * allow a renderPM plugin cairo backend package rlPyCairo CHANGES 3.5.60 22/01/2021 --------------------------- * Allow legend column control of vertical alignment * Allow renderTextMode attribute in reportlab.graphics.shapes.String * Allow renderTextMode drawString handling in renderPDF/PM/PS/SVG * Some fixes to fillMode handling CHANGES 3.5.59 04/01/2021 --------------------------- * Minor changes to table rounded corners; some documentation updates CHANGES 3.5.58 01/01/2021 --------------------------- * Allow variant corners in Canvas.roundRect * Allow tables to have rounded corners CHANGES 3.5.57 27/12/2020 --------------------------- * added ddfStyle to Label * allowed for embedded(and ordinary)Hyphenation to pre-empt splitting when embeddedHyphenation>=2 * fix extension escapePDF so it can handle unicode * fix poundsign in Ean5BarcodeWidget * Table can use __styledWrap__ for sizing * test fixes so 3.9 and 2.7 produce same pdf CHANGES 3.5.56 10/12/2020 --------------------------- * added .github action wheel.yml * micro change to userguide doc RELEASE 3.5.56 01/12/2020 --------------------------- * micro changes for Big Sur in C extensions * allow Drawing.outDir to be a callable for more control in save method RELEASE 3.5.55 29/10/2020 --------------------------- * add trustedHosts and trustedSchemes for url management * deifinitely drop 3.5 support (Jon Ribbens points out it may have happened in 3.5.54). RELEASE 3.5.54 23/10/2020 --------------------------- * Allow extra fields in AcroForm suggested by Chris Else ubuntu247 at gmail.com * Allow DocTemplate.\_firstPageTemplateIndex to be a list of PageTemplate ids * improve PageBreak repr * minor changes to travis & appveyor scripts; drop forml support for python 3.5 RELEASE 3.5.53 02/10/2020 --------------------------- * Fix bug that allowed type 0 postscript commands to persist RELEASE 3.5.52 01/10/2020 --------------------------- * add support for DataMatrix barcode RELEASE 3.5.51 24/09/2020 --------------------------- * fix malloc(0) issue in \_rl_accel.c \_fp_str thanks to Hans-Peter Jansen @ openSUSE RELEASE 3.5.50 18/09/2020 --------------------------- * Add BM ExtGState option (suggestion by tjj021 @ github * Fix memory leak in \_renderPM.c RELEASE 3.5.49 02/09/2020 --------------------------- * ViewerPreferencesPDFDictionary add /Duplex as possibility * Doctemplate add support for all ViewerPreferencesPDFDictionary keys * fix bugs in USPS_4State; Barcode inherits from Flowable and object. RELEASE 3.5.48 18/08/2020 --------------------------- * bug fix for balanced column special case unsplittable half column RELEASE 3.5.47 7/08/2020 --------------------------- * try to limit table style cell ranges RELEASE 3.5.46 22/07/2020 --------------------------- * fix style-data mismatch in LinePlot found by Anshika Sahay RELEASE 3.5.45 10/07/2020 --------------------------- * fix some documentation bugs reported by Lele Gaifax * fix error in BarChart axes joining reported by Faisal.Fareed RELEASE 3.5.44 26/06/2020 --------------------------- * ensure qr bar colour is passed (contrib by Lele Gaifax) * fix img layout bug (reported by Lele Gaifax) RELEASE 3.5.43 03/06/2020 --------------------------- * small change to improve strokeDashArray handling to allow [phase, [values]] and allow stroke-dashoffset * Hatching class which inherits from shapes.Path * add support for soft hyphens u'\xad' * apply a pr from KENLYST @ bitbucket (gfe.py) RELEASE 3.5.42 17/03/2020 -------------------------- * fix bug in tables.py reported by Kamil Niski https://bitbucket.org/rptlab/reportlab/issues/182 & Adam Kalinsky RELEASE 3.5.41 4/03/2020 -------------------------- * fix python3 bug in DDIndenter.__getattr__ RELEASE 3.5.40 28/02/2020 -------------------------- * fix broken (by robin) simple bar lables found by Djan RELEASE 3.5.39 26/02/2020 -------------------------- * allow selection of ttf subfonts by PS name * revert to old style recursiveGetAttr * raise error for problematic Canvas.setDash reported by Mike Carter from sitemorse RELEASE 3.5.38 14/02/2020 -------------------------- * bug fix for normalDate monthnames; bump travis; version-->3.5.38 RELEASE 3.5.37 07/02/2020 -------------------------- * experimental support for 2d pie/doughnut shading RELEASE 3.5.36 28/01/2020 -------------------------- * update travis version of multibuild contrib by Matthew Brett * fixes to cope with python 3.9 * imrove Drawing formats handling and ensure asString can do svg RELEASE 3.5.35 22/01/2020 -------------------------- * test fixes * Label enhancement * added isSubclassOf validator * added CrossHair widget RELEASE 3.5.34 14/01/2020 -------------------------- * attempted restriction of the reportlab.lib.color.toColor function RELEASE 3.5.33 30/10/2019 -------------------------- * fix bug in Pie3d reported by Eldon Ziegler * fix bug in background splitting in repeatRows cases reported by David VanEe * small improvements to CandleSticks * created NotSet validator (use in CandleStickProperties) * update .travis.yml and .appeyor.yml hopefully to create 3.8 wheels RELEASE 3.5.32 24/10/2019 -------------------------- * some chart efficiency changes * use clock in fontFinder contributed by Matěj Cepl @ bitbucket * improve recursive access and do some minor eval/exec fixes * improve use of eval/exec RELEASE 3.5.31 15/10/2019 -------------------------- * paraparser fix contributed by ravi prakash giri RELEASE 3.5.30 15/10/2019 -------------------------- * better support for candlestick charts using smartGetItem RELEASE 3.5.29 14/10/2019 -------------------------- * Support for candlestick charts and infilled pair plots RELEASE 3.5.28 02/10/2019 -------------------------- * improve support for AES encryption RELEASE 3.5.27 01/10/2019 -------------------------- * fix to justified para splits contributed by Niharika Singh * fix BalanceColumn width calculation * preliminary support for AES encryption (contributed by https://github.com/talebi1) RELEASE 3.5.26 17/09/2019 -------------------------- * micro changes to normalDate * fix warnings about is not (detected in python 3.8b4) * implement PR #59 bug fix contributed by Vytis Banaitis RELEASE 3.5.25 23/08/2019 -------------------------- * add recursive ttf searching * sync with rlextra * fix Barchart axis crossing issue reported by Martin Jones (Zeidler) RELEASE 3.5.24 07/08/2019 -------------------------- * prepare for python3.8, drop support for python3.4 RELEASE 3.5.23 31/05/2019 -------------------------- * fix issue #180 raised by Christoph Berg * fix issue #181 raised by Daniel Terecuk * brutalist fix for Marius Gedminas' issue #183 * add wordSpace keyword to Canvas draw methods * fix for Marius Gedminas' issue #184 RELEASE 3.5.22 23/05/2019 -------------------------- * Allow kewords in PDFResourceDictionary * pr #58 issue #174 contribution by Marius Gedminas * Allow AcroForm to have SigFlags * Bug Fixes and tests RELEASE 3.5.21 3/05/2019 -------------------------- * fix bug in legends * add extra table info in spanning error case RELEASE 3.5.20 25/04/2019 -------------------------- * Preliminary MultiCol implementation * fix missing xrange import * allow rgb to have fractions of 1 in css colors RELEASE 3.5.19 15/04/2019 -------------------------- * fix bug with a tag href not having a scheme * all0w LineChart/LinePlot area fills to differe from the stroke colour * add canvas setProducer method RELEASE 3.5.18 03/04/2019 -------------------------- * more FrameBG changes vs BalancedColumns * fix bb issues #176/#177 reported by graingert & droidzone RELEASE 3.5.17 29/03/2019 -------------------------- * more FrameBG fixes; added canvas cross method, frame static drawBoundary RELEASE 3.5.16 27/03/2019 -------------------------- * fix stroking for frame background in container RELEASE 3.5.15 27/03/2019 -------------------------- * add stroking for frame background RELEASE 3.5.14 14/03/2019 -------------------------- * added axes tickStrokeWidth etc etc RELEASE 3.5.13 15/01/2019 -------------------------- * added rl_setting.reserveTTFNotdef inspired by e3office at bitbucket (pr #50) RELEASE 3.5.12 30/11/2018 -------------------------- * log axis handles rangeRound & avoidBoundspace * FrameBG can start with "frame" & frame-permanent" start options RELEASE 3.5.11 20/11/2018 -------------------------- * Improve log axis ticks & grids * move some samples into tests RELEASE 3.5.10 15/11/2018 -------------------------- * Bug fix for underline (contrib. Lennart Regebro @ bitbucket) * Paragraph indentation bug fix * Initial support for richtext graphics text labels * Initial support for log axes (ideas from hoel@germanlloyd.org) RELEASE 3.5.9 01/10/2018 ------------------------- * add hyphenationMinWordLength to address PR #44 (contrib Michael V. Reztsov) RELEASE 3.5.8 21/09/2018 ------------------------- * Allow structured barLabelFormat (suggestion from Ravinder Baid) RELEASE 3.5.7 22/08/2018 ------------------------- * Fix tables.py splitting for line comands. RELEASE 3.5.6 20/08/2018 ------------------------- * Restore DocTemplate seq attribute lost in rev c985bd7093ad (4405) version 3.4.41 bug report from Jim Parinisi jimandkimparinisi@yahoo.com RELEASE 3.5.5 14/08/2018 ------------------------- * Bug fix underlined space in XPreformatted RELEASE 3.5.4 06/08/2018 ------------------------- * Bug fix for Paragraph space bugs reported by Kayley Lane * Use local libart code by default (libart 2.3.21-3) RELEASE 3.5.3 06/07/2018 ------------------------- * Bug fix release to make really simple paras work OK Reported by Kayley.Lane @ oracle.com * Use local libart by default * Use upgrade libart source to 2.3.21-3 https://salsa.debian.org/gnome-team/libart-lgpl@aa059539 RELEASE 3.5.2 23/07/2018 ------------------------- * Bug fix release to make th sdist work properly RELEASE 3.5.1 17/07/2018 ------------------------- * Bug fix for infinite looping in Paragraph (likely caused by small available Widths). Reported by Kayley.Lane @ oracle.com RELEASE 3.5 07/07/2018 ----------------------- * BalancedColumns flowable added * primitive hyphenation functionality (with Pyphen installed) * simple paragraphs now allow space shrinkage * mixed parallel / stacked barcharts mechanism * makeStream compression fix for python 3.x * reproducibility fixes * Bugfix for KeepWithNext and None * Fix pie chart issue * allow canvas filename to be a wrapped OS level file * added DocTemplate._makeCanvas * _text2Path fix * AcroForm improvements * added anchorAtXY parameter for images * fix PDF syntax error with no Outlines * fix bullet code * qrencoder fix * table minRowHeights support * stopped abusing builtins to aid compatibility * fix embedded font & fontfinder bugs * fix zero width paragraph layout error * doughnut charts support innerRadiusFraction * more controllable under and strike lines ### Contributors: * Axel P. Kielhorn * ben @ readingtype.org.uk * Chris Jerdonek cjerdonek @ bitbucket * Dan Palmer danpalmer @ bitbucket * Garry Williams gary_williams @ bit_bucket * Greg Svitak * htgoebel @ bitbucket * Johann Du Toit https://bitbucket.org/johanndt/ * Jon Hinton (inivatajon @ bitbucket.org) * Lele Gaifax * lisandrija @ bitbucket.org * lostbard @ bitbucket * Martin J. Laubach bitbucket issue #140 * Moritz Pfeiffer moritzpfeiffer @ bitbucket * Raji Sundar * Silas Sewell silassewell @ bitbucket * simonkagwe @ bitbucket * Tom Alexander @ bitbucket * Trevor Bullock * Waldemar Osuch RELEASE 3.4 07/03/2017 ----------------------- * More pagesizes from https://en.wikipedia.org/wiki/Paper_size (contributed by https://bitbucket.org/alainchiasson/) * add in fillMode (fill-rule) variable to the graphics state for drawings * add support for automatic bullet rotation in ListFlowables. * fix acroform annotation bug in radios (reported by Olivia Zhang) * fix split paragraph rendering bug (reported by Olivia Zhang & Echo Bell) * Allow Image to have a drawing as argument * support for Path autoclose & fillMode; version --> 3.3.29 * add support for different fill policies in renderXX drawPath; version-->3.3.28 * allow for UTF_16_LE BOM, fix for bug contributed by Michael Poindexter mpoindexter@housecanary.com * improved support for images in renderPM/renderSVG bug report from Claude Paroz * add AcroForm support to canvas; version --> 3.3.22 * avoid cr lf line endings * attempt to ensure zipImported has some files or returns None * added additonal test to barcode/test.py * add an invisible font test thanks https://bitbucket.org/kb/ Konstantin Baierer * add mailto href test * improve UPCA barcode contribution by Kyle McFarlane https://bitbucket.org/kylemacfarlane/ * attempt to fix __loader__ issues in pyinstaller suggested by dbrnz @ bitbucket * fix NormalDate comprisons in python3.x * fix ypad use in ParagraphAndImage contrib annamarianfr@bitbucket, version-->3.3.16 * try to prevent multiple saving contrib by Tim Meneely * fix problems with svg drawToString contrib by Eric Gillet & Johann Du Toit * fix issue reported by Yitzchak Scott-Thoennes * fix fake KeepTogether setup in handle_keepWithNext * add NullActionFlowable, fix empty KeepTogether * really merge para-measure-fix * merge para-measure-fix changes * fixes to TypedPropertyCollection * changes to Render class; allow drawings to specify initialFontName/Size * fix python>=3.2 default axis labelling to match python2.x; bugfix contributed by Robin Westin bitbucket issue #82 * fix AttributeError reported by Kay Schluehr bitbucket issue #81 * add experimental time value axis * fix bug in python shapes rendering * add negative span style to test_platypus_tables splitting example * fix segfault in _rl_accel.c; fix contributed by Neil Schemenauer as issue #78 * attempt to remove quadratic performance hit when longTableOptimize is set * allow DATA: scheme in open for read * import Table _rowpositions calculation * support small ttfs which do not allow subsets * add rl_settings allowTTFSubsetting * address issue #76 (deprecated immports) reported by Richard Eames * add table cell support for simple background shadings, contributed by Jeffrey Creem jcreem@bitbucket * fix bug in tables.py reported by Vytis Banaitis @ bitbucket; version-->3.3.2 * minor change to allow barWidth setting in ecc200datamatrix.py (suggested by Kyle MacFarlane @ bitbucket) * make paraparser syntax errors real and fix tags to have relative values; version-->3.3.1 * ReportLab now runs all tests under Python 2.7, 3.3, 3.4, 3.5 & 3.6. ### Contributors: * Alain Chiasson https://bitbucket.org/alainchiasson/ * annamarianfr@bitbucket * Claude Paroz * dbrnz @ bitbucket * Dinu Gherman * Echo Bell * Eric Gillet * Jeffrey Creem jcreem@bitbucket * Johann Du Toit * Kay Schluehr bitbucket issue #81 * Konstantin Baierer * Kyle McFarlane https://bitbucket.org/kylemacfarlane/ * Michael Poindexter mpoindexter@housecanary.com * Neil Schemenauer * Olivia Zhang * Richard Eames * Robin Westin * Tim Meneely * Vytis Banaitis @ bitbucket * Yitzchak Scott-Thoennes RELEASE 3.3 17/02/2016 ----------------------- * Canvas & Doctemplate now allow specification of the initial font Name, Size & Leading. Prevously you had to mess with rl_settings to accomplish this. * Canvas & Doctemplate now support specification of the crop/art/trim/bleed boxes. * Add option to auto generate missing TTF font names. Handy for CJKers with home produced fonts. Also attempt to prevent usage of multiple TTFs with same name. * Paragraph styles now have justifyBreaks to control justification of lines broken with
. * Paragraph styles now have justifyLastLine=n to control justification of last lines with more than n words (0 means do not). * Added EAN-5 and ISBN barcode widgets (contribution by Edward Greve). * Bug fix of QrCodeWidget (prompted by https://bitbucket.org/fubu/). * Frames now have support for automatic flowables at the top of frame. story support via the class reportlab.platypus.flowables.SetTopFlowables. * Added support for Trapped and ModDate PDF info dictionary keys. * Bug fix for pie charts with no data (raised by Michael Spector). * New barcodes BarcodeCode128Auto & BarcodeECC200DataMatrix (contributed by Kyle MacFarlane). * Improved LinePlot marker handling. * PyPy improvements inspired by Marius Gedminas. * Bug fix in reportlab.lib.utils.simpleSplit (reported by Chris Buergi ). * Unwanted escaping in renderSVG fixed (reported by Ruby Yocum). * Bug fix in _rl_accel.c (remove excess state and fix refcount breakage reported by Mark De Wit ). * Code128 barcode length optimization inspired by Klaas Feenstra. * Paragraph / & tags now support rise & size attributes to allow special control over position & font size. * Splitting tables now remove unwanted styles in the first part of the split (reported by Lele Gaifax). * test changes inspired by https://bitbucket.org/stoneleaf * ReportLab now runs all tests under Python 2.7, 3.3, 3.4 & 3.5. ### Contributors: * Edward Greve * https://bitbucket.org/fubu/ * Michael Spector * Kyle MacFarlane * Marius Gedminas * Chris Buergi * Ruby Yocum * Mark de Wit * Klaas Feenstra * Lele Gaifax * https://bitbucket.org/stoneleaf RELEASE 3.2 01/06/2015 ----------------------- * Added proportional underlining specific to font sizes, set via the `underlineProportion` attribute of ParagraphStyles. * TrueType fonts: added support for cmaps 10 & 13 * DocTemplate class now supports a boolean `displayDocTitle` argument. * TableofContents now supports a formatter argument to allow formatting of the displayed page numbers (eg for appendices etc). * Table `repeatRows` can now be a tuple of row numbers to allow incomplete ranges of rows to be repeated. * Tables now do pass instance.`spaceBefore` & `spaceAfter` to their split children when split * Several strangenesses were fixed in the pdfbase.pdfform module; Multiple usage is now allowed. * Error message fixes * Various environment fixes for Google Application Environment * Resource fixes * PDFDoc can now set the `Lang` attribute * canvas.drawString and similar now allow the character spacing to be set * Index of accented stuff has been improved * RTL code was improved * fix Propertyset.clone * `flowables.py`: fix ImageAndFlowables so it avoids testing negative availableWidth ### Contributors: * Steven Jacobs * Philip Semanchuk * Marius Gedminas * masklinn * Kale Franz * Albertas Agejavas • Anders Hammarquist * jvanzuela @ bitbucket * Glen Lindermann * Greg Jones * James Bynd * fcoelho @ bitbucket RELEASE 3.1 22/04/2014 ----------------------- If you are running ReportLab 3.0.x, the changes are minor. * support for emoji - characters outside the Unicode basic multilingual plane * improved pip-based installers will pull in all the needed dependencies; Pillow 2.4 appears to deal with all our issues. ### Contributors * Ivan Tchomgue * Waldemar Osuch * masayuku * alexandrel_sgi RELEASE 3.0 14/02/2014 ----------------------- ReportLab 3.0 now supports Python 2.7, 3.3 and higher. There has been a substantial internal rewrite to ensure consistent use of unicode strings for natural-language text, and of bytes for all file format internals. The intent is to make as few API changes as possible so that there should be little or no impact on users and their applications. Changes are too numerous but can be seen on Bitbucket. ### Python 3.x compatibility * Python 3.x compatibility. A single line of code should run on 2.7 and 3.3 * __init__.py restricts to 2.7 or >=3.3 * __init__.py allow the import of on optional reportlab.local_rl_mods to allow monkey patching etc. * rl_config now imports rl_settings & optionally local_rl_settings * ReportLab C extensions now live inside reportlab; _rl_accel is no longer required; All _rl_accel imports now pass through reportlab.lib.rl_accel * xmllib is gone, alongside the paraparser stuff that caused issues in favour of HTMLParser. * some obsolete C extensions (sgmlop and pyHnj) are gone * Improved support for multi-threaded systems to the _rl_accel extension module. * Removed reportlab/lib/ para.py & pycanvas.py; these would better belong in third party packages, which can make use of the monkeypatching feature above. ### New features * Add ability to output greyscale and 1-bit PIL images without conversion to RGB. (contributed by Matthew Duggan) * highlight annotation (contributed by Ben Echols) ### Other * numerous very minor fixes, visible through BitBucket. RELEASE 2.7 04/04/2013 ----------------------- #### Charts / graphics enhancements * Added SimpleTimeSeriesPlot * added _computeMaxSpace * added in lineStyle (for bars) * improved SVG rendering * Pie Chart now has an `innerRadiusFraction` to allow doughnut-like appearance for 2d charts (it has no effect with 3d charts). The separate 'doughnut' chart lacks many pie chart features and should only be used if you wanted multiple nested doughnuts. #### Charts/graphics bug fixes * piecharts.py: fix Pie3d __init__ to call its superclass * linecharts.py: fix swatch creation * fixed `y` axis in the simple time series plot #### PDF * Fixes to testshapes & pdfform resetting * colors.py * various minor fixes #### Platypus * Defined a small bullet rather than a big circle as the default for unordered lists * fixed attribute spelling bug * fixed CJK + endDots ### Acknowledgements Many thanks to Andrew Cutler, Dinu Gherman, Matthias Kirst and Stephan Richter for their contributions to this release. RELEASE 2.6 27/09/2012 ----------------------- This is a minor release focusing mainly on improved documentation. There are a number of minor enhancements, and a larger number of previous-undocumented enhancements which we have documented better. #### General changes * Manuals have been reformatted with more pleasing code snippets and tables of contents, and reviewed and expanded #### Flowing documents (Platypus) * Added support for HTML-style list objects * Added flexible mechanism for drawing bullets * Allowed XPreformatted objects to use Asian line wrapping * Added an `autoNextPageTemplate` attribute to PageTemplates. For example you can now set up a 'chapter first page template' which will always be followed by a 'continuation template' on the next page break, saving the programmer from having to issue control flow commands in the story. * added a TopPadder flowable, which will 'wrap' another Flowable and move it to the bottom of the current page. * More helpful error messages when large tables cannot be rendered * Documentation for images within text (`test_032_images`) * Trailing dots for use on contents pages #### Charts and graphics * Support for UPCA bar codes * We now have a semi-intelligent system for labelling pie charts with callout lines. Thanks to James Martin-Collar, a maths student at Warwick University, who did this as his summer internship. * Axes - added startOffset and endOffset properties; allowed for axis background annotations. * Bar charts - allow more control of z Index (i.e. drawing order of axes and lines) * Pie charts - fixed bugs in 3d appearance * SVG output back end has seen some bugs fixed and now outputs resizeable SVG ### Contributors * Alex Buck * Felix Labrecque * Peter Johnson * James Martin-Collar * Guillaume Francois RELEASE 2.5 at 18:00 GMT 01/Oct/2010 -------------------------------------- Many new features have been added and numerous bugs have been fixed. Thanks to everybody who has contributed to the open-source toolkit in the run-up to the 2.5 release, whether by reporting bugs, sending patches, or contributing to the reportlab-users mailing list. Major contributors are credited in the user documentation. * Support for colour separated PDF output and other optimisations and features for high-quality printing, including enforcement of colour models for CMYK, RGB, and "spot colours" * Long table optimisations are now turned on by default. Previously, documents with very long tables spanning many pages could take a long time to create because we considered the whole table to work out row and column sizes. A patch was submitted some time ago to fix this controlled by a flag in the rl_config file, but this was set 'off' for compatibility. Users are often not aware of this and we haven't found any real-world cases where the new layout technique works badly, so we are turning this behaviour on. * New support for QR barcodes - [try our demo!](https://www.reportlab.com/demos/qr/) #### PDF * Colour separation and other enhancements for high-end print * Python 2.7 support #### Charts * reportlab.graphics.charts.axes * ValueAxis * avoidBoundSpace - Space to allow above and below * abf_ignore_zero - Set to True to make the avoidBoundFrac calculations treat zero as non-special * keepTickLabelsInside - Ensure tick labels do not project beyond bounds of axis if true * NormalDateXValueAxis * specialTickClear - clear rather than delete close ticks when forced first/end dates * AdjYValueAxis * labelVOffset - add this to the labels * reportlab.graphics.charts.barcharts * BarChart * categoryLabelBarSize - width to leave for a category label to go between categories * categoryLabelBarOrder - where any label bar should appear first/last * barRecord (advanced) - callable(bar,label=labelText,value=value,**kwds) to record bar information * reportlab.graphics.charts.legends * SubColProperty * dx - x offset from default position * dy - y offset from default position * Legend * swdx - x position adjustment for the swatch * swdy - y position adjustment for the swatch * reportlab.graphics.charts.piecharts * Pie * wedgeRecord (advanced) - callable(wedge,*args,**kwds) * reportlab.graphics.charts.utils * DrawTimeCollector - generic mechanism for collecting information about nodes at the time they are about to be drawn RELEASE 2.4 at 18:00 GMT 20/Jan/2010 -------------------------------------- #### PDF * lots of improvements and verbosity to error messages and the way they are handled. * font size can now be specified in pixels * unicode file names are now accepted #### Platypus * canvas auto cropmarks * added support for styles h4-h6 * Improved support for onDraw and SimpleIndex * Add support for index tableStyle * Added an alphabetic grouping indexing class * Added support for multi-level and alphabetical indexes * Added support for an unlimited number of TOC levels with default styles * Index entries can now be clickable. #### Graphics * Axes values can be reversible. * Labels on the axes can now be drawn above or below the axes (hi or low). * A per swatch callout is now allowed in the legend. * A new anchroing mode for string 'numeric' that align numerical strings by their decimal place. * Shapes have new attributes to specify if the shape should grow to take all canvas area (vertically or horizontally) or if the canvas should shrink to fit the shape size. * color objects now have a clone method. * colors module has a fade function that returns a list of different shades made up of one base colour. * added in support for Overprint/Opacity & Separated colours #### Bugs fixes * word counting in complex paragraphs has been fixed. * SimpleIndex and TableOfContents bugs have been fixed. * Fix for position of hyperlinks when crop marks are added. * flowables.py: fix special case of doctemplate with no frames * PDFFormXObject.format missing Resources bug patch from Scott Meyer * KeepInFrame justification bug has been fixed. * paragraph.py: fix linebreaking bug thanks to Roberto Alsina * fix unicode/str issue bug found by Michael Egorov * YCategoryAxis makeTickLabels fix contributed by Mike Folwell * pdfdoc.py: fix ro PDFDate contributed by Robert Alsina * and others .. ### Contributors * PJACock's () * Hans Brand * Ian Stevens * Yoann Roman * Randolph Bentson * Volker Haas * Simon King * Henning Vonbargen * Michael Egorov * Mike Folwell * Robert Alsina * and more ... RELEASE 2.3 at 18:00 GMT 04/Feb/2009 -------------------------------------- #### PDF * Encryption support (see encrypt parameter on Canvas and BaseDocTemplate constructor) #### Platypus * TableOfContents - Creates clickable tables of contents * Variable border padding for paragraphs (using the borderPadding style attribute) * New programming Flowable, docAssert, used to assert expressions on wrap time. #### Bug fixes * Fixed old documentation and installation issues * 610 - Fixed Image anchoring code to match documentation * 704 - renderSVG groups problem * 706 - rl_codecs.py now compatible with WordAxe * and others... ### Contributors * Yoann Roman * Dinu Gherman * Dirk Holtwick * Marcel Tromp * Henning von Bargen * Paul Barrass * Adrian Klaver * Hans Brand * Ian Stevens RELEASE 2.2 at 18:00 GMT 10/Sep/2008 -------------------------------------- #### PDF * pdfmetrics: Added registerFontFamily function * Basic support for pdf document viewer preferences (e.g.: fullscreen). #### Platypus * Paragraph tag support for inline images. * Paragraph autoleading support (helps with tags). * Platypus doctemplate programming support. * Support for tables with non-uniform row length. #### Graphics * RGBA image support for suitable bitmap types. * LTO labelling barcode. And many bugfixes... ### Contributors * Matt Folwell * Jerome Alet * Harald Armin Massa * kevin@booksys.com * Sebastian Ware * Martin Tate * Wietse Jacobs * Christian Jacobs * Volker Haas * Dinu Gherman * Dirk Datzert * Yuan Hong * Ilpo Nyyss�nen * Thomas Heller * Gael Chardon * Alex Smishlajev * Martin Loewis * Dirk Holtwick * Philippe Makowskic * Ian Sparks * Albertas Agejevas * Gary Poster * Martin Zohlhuber * Francesco Pierfederici * michael@stroeder.com * Derik Barclay * Publio da Costa Melo * Jon Dyte * David Horkoff * picodello@yahoo.it * R�diger M�hl * Paul Winkler * Bernhard Herzog * Alex Martelli * Stuart Bishop * Gael Chardon RELEASE 2.1 at 15:00 GMT 24/May/2007 -------------------------------------- ### Contributors * Ilpo Nyyss�nen * Thomas Heller * Gael Chardon * Alex Smishlajev * Martin Loewis * Dirk Holtwick * Philippe Makowskic * Dinu Gherman * Ian Sparks RELEASE 2.0 at 15:00 GMT 23/May/2006 -------------------------------------- ### Contributions * Andre Reitz * Max M * Albertas Agejevas * T Blatter * Ron Peleg * Gary Poster * Steve Halasz * Andrew Mercer * Paul McNett * Chad Miller ### Unicode support This is the Big One, and the reason some apps may break. You must now pass in text either in UTF-8 or as unicode string objects. The library will handle everything to do with output encoding. There is more information on this below. Since this is the biggest change, we'll start by reviewing how it worked in the past. In ReportLab 1.x, any string input you passed to our APIs was supposed to be in the same encoding as the font you selected for output. If using the default fonts in Acrobat Reader (Helvetica/Times/Courier), you would have implicitly used WinAnsi encoding, which is almost exactly the same as Latin-1. However, if using TrueType fonts, you would have been using UTF-8. For Asian fonts, you had a wide choice of encodings but had to specify which one (e.g Shift-JIS or EUC for Japanese). This state of affairs meant that you had to make sure that every piece of text input was in the same encoding as the font used to display it. With ReportLab 2, none of that necessary. Instead: Here is what's different now: #### Input text encoding is UTF-8 or Python Unicode strings Any text you pass to a canvas API (drawString etc.), Paragraph or other flowable constructor, into a table cell, or as an attribute of a graphic (e.g. chart.title.text), is supposed to be unicode. If you use a traditional Python string, it is assumed to be UTF-8. If you pass a Unicode object, we know it's unicode. #### Font encodings Fonts still work in different ways, and the built-in ones will still use WinAnsi or MacRoman internally while TrueType will use UTF-8. However, the library hides this from you; it converts as it writes out the PDF file. As before, it's still your job to make sure the font you use has the characters you need, or you may get either a traceback or a visible error character. Asian CID fonts You no longer need to specify the encoding for the built-in Asian fonts, just the face name. ReportLab knows about the standard fonts in Adobe's Asian Language Packs. #### Asian Truetype fonts The standard Truetype fonts differ slightly for Asian languages (e.g msmincho.ttc). These can now be read and used, albeit somewhat inefficiently. Asian word wrapping Previously we could display strings in Asian languages, but could not properly wrap paragraphs as there are no gaps between the words. We now have a basic word wrapping algorithm. #### unichar tag A convenience tag, has also been added. You can now do or and get a lowercase u umlaut. Names should be those in the Unicode Character Database. Accents, Greeks and symbols The correct way to refer to all non-ASCII characters is to use their unicode representation. This can be literal Unicode or UTF-8. Special symbols and Greek letters (collectively, "greeks") inserted in paragraphs using the greek tag (e.g. lambda) or using the entity references (e.g. λ) are now processed in a different way than in version 1. Previously, these were always rendered using the Zapf Dingbats font. Now they are always output in the font you specified, unless that font does not support that character. If the font does not support the character, and the font you specified was an Adobe Type 1 font, Zapf Dingbats is used as a fallback. However, at present there is no fallback in the case of TTF fonts. Note that this means that documents that contain greeks and specify a TTF font may need changing to explicitly specify the font to use for the greek character, or you will see a black square in place of that character when you view your PDF output in Acrobat Reader. ### Other New Features #### PDF * Improved low-level annotation support for PDF "free text annotations" FreeTextAnnotation allows showing and hiding of an arbitrary PDF "form" (reusable chunk of PDF content) depending on whether the document is printed or viewed on-screen, or depending on whether the mouse is hovered over the content, etc. * TTC font collection files are now readable: ReportLab now supports using TTF fonts packaged in .TTC files * East Asian font support (CID and TTF): You no longer need to specify the encoding for the built-in Asian fonts, just the face name. ReportLab knows about the standard fonts in Adobe's Asian Language Packs. * Native support for JPEG CMYK images: ReportLab now takes advantage of PDF's native JPEG CMYK image support, so that JPEG CMYK images are no longer (lossily) converted to RGB format before including them in PDF. #### Platypus * Link support in paragraphs: Platypus paragraphs can now contain link elements, which support both internal links to the same PDF document, links to other local PDF documents, and URL links to pages on the web. Some examples: Web links:: ReportLab Internal link to current PDF document:: ReportLab External link to a PDF document on the local filesystem:: ReportLab * Improved wrapping support: Support for wrapping arbitrary sequence of flowables around an image, using reportlab.platypus.flowables.ImageAndFlowables (similar to ParagraphAndImage). * `KeepInFrame`: Sometimes the length of a piece of text you'd like to include in a fixed piece of page "real estate" is not guaranteed to be constrained to a fixed maximum length. In these cases, KeepInFrame allows you to specify an appropriate action to take when the text is too long for the space allocated for it. In particular, it can shrink the text to fit, mask (truncate) overflowing text, allow the text to overflow into the rest of the document, or raise an error. * Improved convenience features for inserting unicode symbols and other characters: `` lets you conveniently insert unicode characters using the standard long name or code point. Characters inserted with the `` tags (e.g. `lambda`) or corresponding entity references (e.g. λ) support arbitrary fonts (rather than only Zapf Dingbats). * Table spans and splitting improved: Cell spanning in tables used to go wrong sometimes when the table split over a page. We believe this is improved, although there are so many table features that it's hard to define correct behaviour in all cases. * `KeepWithNext` improved: Paragraph styles have long had an attribute keepWithNext, but this was buggy when set to True. We believe this is fixed now. keepWithNext is important for widows and orphans control; you typically set it to True on headings, to ensure at least one paragraph appears after the heading and that you don't get headings alone at the bottom of a column. #### Graphics * Barcodes: The barcode package has been added to the standard reportlab toolkit distribution (it used to live separately in our contributions area). It has also seen fairly extensive reworking for production use in a recent project. These changes include adding support for the standard European EAN barcodes (EAN 8 and EAN13). * Improvements to Legending: Instead of manual placement, there is now a attachment point (N, S, E, W, etc.), so that the legend is always automatically positioned correctly relative to the chart. Swatches (the small sample squares of colour / pattern fill sometimes displayed in the legend) can now be automatically created from the graph data. Legends can now have automatically-computed totals (useful for financial applications). * More and better ways to place piechart labels: New smart algorithms for automatic pie chart label positioning have been added. You can now produce nice-looking labels without manual positioning even for awkward cases in big runs of charts. * Adjustable piechart slice ordering: For example. pie charts with lots of small slices can be configured to alternate thin and thick slices to help the label placement algorithm work better. * Improved spiderplots #### Noteworthy bug fixes * Fixes to TTF splitting (patch from Albertas Agejevas): This affected some documents using font subsetting * Tables with spans improved splitting: Splitting of tables across pages did not work correctly when the table had row/column spans * Fix runtime error affecting keepWithNext Older releases -------------- Please refer to subversion backlogs for a low level change list RELEASE 1.20 at 18:00 GMT 25/Nov/2004 RELEASE 1.19 at 18:00 GMT 21/Jan/2004 RELEASE 1.18 at 12:00 GMT 9/Jul/2003 RELEASE 1.17 at 16:00 GMT 3/Jan/2003 RELEASE 1.16 at 16:00 GMT 7/Nov/2002 RELEASE 1.15 at 14:00 GMT 9/Aug/2002 RELEASE 1.14 at 18:00 GMT 28/May/2002 RELEASE 1.13 at 15:00 GMT 27/March/2002 RELEASE 1.12 at 17:00 GMT 28/February/2002 RELEASE 1.11 at 14:00 GMT 12/December/2001 RELEASE 1.10 at 14:00 GMT 06/November/2001 RELEASE 1.09 at 14:00 BST 13/August/2001 RELEASE 1.08 at 12:00 BST 19/June/2001 RELEASE 1.07 at 11:54 BST 2001/05/02 RELEASE 1.06 at 14:00 BST 2001/03/30 RELEASE 1.03 on 2001/02/09 RELEASE 1.02 on 2000/12/11 RELEASE 1.01 on 2000/10/10 RELEASE 1.00 on 2000/07/20 RELEASE 0.95 on 2000/07/14 RELEASE 0.94 on 2000/06/20 ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1691062242.0 reportlab-4.1.0/INSTALL.txt0000664000175000017500000000006514462707742014767 0ustar00rptlabrptlabPlease see README.txt for installation instructions. ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1691062243.0 reportlab-4.1.0/LICENSE0000664000175000017500000000325314462707743014130 0ustar00rptlabrptlab##################################################################################### # # Copyright (c) 2000-2018, ReportLab Inc. # All rights reserved. # # Redistribution and use in source and binary forms, with or without modification, # are permitted provided that the following conditions are met: # # * Redistributions of source code must retain the above copyright notice, # this list of conditions and the following disclaimer. # * 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. # * Neither the name of the company nor the names of its contributors may be # used to endorse or promote products derived from this software without # specific prior written permission. # # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 OFFICERS 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. # ##################################################################################### ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1691062243.0 reportlab-4.1.0/MANIFEST.in0000664000175000017500000000072414462707743014661 0ustar00rptlabrptlabinclude *.txt *.yml CHANGES.md include src/reportlab/graphics/barcode/README include src/reportlab/graphics/barcode/TODO include src/reportlab/LICENSE include src/reportlab/MANIFEST.in recursive-include demos *.py *.txt recursive-include docs *.py *.txt *.gif *.a85 *.png *.jpg *.rst *.html gen_epydoc *.bat Makefile *.yml *.css recursive-include tests *.py *.gif *.jpg *.png 00readme.txt *.tiff recursive-include tools *.py *.dtd *.xml *.a85 *.gif README *.jpg *.png ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707393948.6585588 reportlab-4.1.0/PKG-INFO0000644000175000017500000000251214561141635014203 0ustar00rptlabrptlabMetadata-Version: 2.1 Name: reportlab Version: 4.1.0 Summary: The Reportlab Toolkit Home-page: https://www.reportlab.com/ Author: Andy Robinson, Robin Becker, the ReportLab team and the community Author-email: reportlab-users@lists2.reportlab.com License: BSD license (see license.txt for details), Copyright (c) 2000-2022, ReportLab Inc. Classifier: Development Status :: 5 - Production/Stable Classifier: Intended Audience :: Developers Classifier: License :: OSI Approved :: BSD License Classifier: Topic :: Printing Classifier: Topic :: Text Processing :: Markup Classifier: Programming Language :: Python :: 3 Classifier: Programming Language :: Python :: 3.7 Classifier: Programming Language :: Python :: 3.8 Classifier: Programming Language :: Python :: 3.9 Classifier: Programming Language :: Python :: 3.10 Classifier: Programming Language :: Python :: 3.11 Requires-Python: >=3.7,<4 License-File: LICENSE Requires-Dist: pillow>=9.0.0 Requires-Dist: chardet Provides-Extra: accel Requires-Dist: rl_accel<1.1,>=0.9.0; extra == "accel" Provides-Extra: renderpm Requires-Dist: rl_renderPM<4.1,>=4.0.3; extra == "renderpm" Provides-Extra: pycairo Requires-Dist: rlPyCairo<1,>=0.2.0; extra == "pycairo" Requires-Dist: freetype-py<2.4,>=2.3.0; extra == "pycairo" The ReportLab Toolkit. An Open Source Python library for generating PDFs and graphics. ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1691062243.0 reportlab-4.1.0/README.txt0000664000175000017500000001160214462707743014616 0ustar00rptlabrptlab===================================== README ===================================== (C) Copyright ReportLab Europe Ltd. 2000-2023. See ``LICENSE.txt`` for license details. This is the ReportLab PDF Toolkit. It allows rapid creation of rich PDF documents, and also creation of charts in a variety of bitmap and vector formats. This library is also the foundation for our commercial product Report Markup Language (RML), available in the ReportLab PLUS package (see https://docs.reportlab.com/rmlfornewbies/). RML offers many more features, a template-based style of document development familiar to all web developers, and higher development productivity. Please consider trying out RML for your project, as the license sales support our open source development. Contents of this file: 1. Licensing 2. Installation 2.1 Source Distribution or Subversion 2.2 Manual Installation without C Compiler (e.g. Windows) 2.3 Windows packages 2.4 Mac OSX installation 2.5 Ubuntu and other Debian-based Systems 3. Prerequisites / Dependencies 4. Documentation 5. Acknowledgements and Thanks 1. Licensing ============ BSD license. See ``LICENSE.txt`` for details. 2. Installation =============== In most cases, ``pip install reportlab`` will do the job. Full details follow below for each platform if you want to build from source. 2.1 General prerequisites -------------------------- ReportLab requires Python 3.7 or higher. From version 4.0 onwards we are "c-less" - maintaining extensions are now Somebody Else's Problem. To include images in PDFs (other than JPG, which PDF natively supports), we depend on `pillow`. To render bitmaps with correct text metrics, we depend on three other python packages:`pyCairo` and `freetype-py`. These should be included in the wheels, or you can build from source 2.2. Where to get the code ------------------------------------------ Latest builds are available from ReportLab's open source download area:: https://www.reportlab.com/pypi/ Main releases are also available from the Python Package Index: http://pypi.python.org/ The code is currently hosted in Mercurial at https://hg.reportlab.com/hg-public/. You can obtain the latest code from our Mercurial repository with:: hg clone https://hg.reportlab.com/hg-public/reportlab A mirror only repository is available for git users at https://github.com/MrBitBucket/reportlab-mirror Please do not use this for issue reporting etc; use the mail list at https://pairlist2.pair.net/mailman/listinfo/reportlab-users Users of our commercial libraries, and/or anyone who registers on our site, can also access our commercial area which has exactly the same packages, paired with the matching commercial ones (rlextra); it is important to keep both in sync. 3. Documentation ================ The latest documentation is available at https://docs.reportlab.com/ For over 20 years we generated our own manuals using the library. In a 'built' distribution, they may already be present in the docs/ directory. If not, execute ``python genAll.py`` in that directory, and it will create three PDF manuals:: reportlab-userguide.pdf reportlab-reference.pdf reportlab-graphics-reference.pdf These are also available in daily build form from the documentation page on our web site. The manuals are very useful 'how-to' examples if you are aiming to create long documents. However, they will gradually become out of date. 4. Test suite ============= Tests are in the ``tests/`` directory. They can be executed by cd'ing into the directory and executing ``python runAll.py``. The tests will simply try to 'import reportlab'. Be warned that if you are not in a virtual environment, and you already have a copy of reportlab installed (which happens by default in Ubuntu 12.04 desktop), it may try to run the installed reportlab and cause permission errors as it can't generate PDF files without sudo rights. The tests mostly produce output files with the same name as the test, but extension .pdf. It is worth reviewing the list of test scripts as they provide valuable 'how to' information. 6. Demos ======== A small number of demo programs are included in ``demos/`` in the source distribution, none of which are particularly exciting, but which may have some intructional value. These were the first programs we wrote back in 2000. The *odyssey* demo serves as our benchmark suite. If you download the full Odyssey text, you can generate a PDF of Homer's Odyssey with either (a) no wrapping, (b) simple paragraphs or (c) paragraphs with enough artificial markup (bold/italic on certain words) to exercise the parser. 7. Acknowledgements and Thanks ============================== ``lib/normalDate.py`` originally by Jeff Bauer. Many, many contributors have helped out between 2000 and 2016. We try to keep a list in the first chapter of the User Guide; if you have contributed and are not listed there, please let us know. ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1691062243.0 reportlab-4.1.0/VERSION.txt0000664000175000017500000000011014462707743014776 0ustar00rptlabrptlabThe "master version number" lives in src/reportlab/__init__.py. Sorry! ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707393948.3345587 reportlab-4.1.0/demos/0000775000175000017500000000000014561141634014216 5ustar00rptlabrptlab././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707393948.3345587 reportlab-4.1.0/demos/colors/0000775000175000017500000000000014561141634015517 5ustar00rptlabrptlab././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1691062242.0 reportlab-4.1.0/demos/colors/colortest.py0000664000175000017500000000525014462707742020121 0ustar00rptlabrptlab#Copyright ReportLab Europe Ltd. 2000-2017 #see license.txt for license details __version__='3.3.0' import reportlab.pdfgen.canvas from reportlab.lib import colors from reportlab.lib.units import inch def run(): c = reportlab.pdfgen.canvas.Canvas('colortest.pdf') #do a test of CMYK interspersed with RGB #first do RGB values framePage(c, 'Color Demo - RGB Space and CMYK spaces interspersed' ) y = 700 c.setFillColorRGB(0,0,0) c.drawString(100, y, 'cyan') c.setFillColorCMYK(1,0,0,0) c.rect(200, y, 300, 30, fill=1) y = y - 40 c.setFillColorRGB(0,0,0) c.drawString(100, y, 'red') c.setFillColorRGB(1,0,0) c.rect(200, y, 300, 30, fill=1) y = y - 40 c.setFillColorRGB(0,0,0) c.drawString(100, y, 'magenta') c.setFillColorCMYK(0,1,0,0) c.rect(200, y, 300, 30, fill=1) y = y - 40 c.setFillColorRGB(0,0,0) c.drawString(100, y, 'green') c.setFillColorRGB(0,1,0) c.rect(200, y, 300, 30, fill=1) y = y - 40 c.setFillColorRGB(0,0,0) c.drawString(100, y, 'yellow') c.setFillColorCMYK(0,0,1,0) c.rect(200, y, 300, 30, fill=1) y = y - 40 c.setFillColorRGB(0,0,0) c.drawString(100, y, 'blue') c.setFillColorRGB(0,0,1) c.rect(200, y, 300, 30, fill=1) y = y - 40 c.setFillColorRGB(0,0,0) c.drawString(100, y, 'black') c.setFillColorCMYK(0,0,0,1) c.rect(200, y, 300, 30, fill=1) y = y - 40 c.showPage() #do all named colors framePage(c, 'Color Demo - RGB Space - page %d' % c.getPageNumber()) all_colors = list(reportlab.lib.colors.getAllNamedColors().items()) all_colors.sort() # alpha order by name c.setFont('Times-Roman', 12) c.drawString(72,730, 'This shows all the named colors in the HTML standard.') y = 700 for (name, color) in all_colors: c.setFillColor(colors.black) c.drawString(100, y, name) c.setFillColor(color) c.rect(200, y-10, 300, 30, fill=1) y = y - 40 if y < 100: c.showPage() framePage(c, 'Color Demo - RGB Space - page %d' % c.getPageNumber()) y = 700 c.save() def framePage(canvas, title): canvas.setFont('Times-BoldItalic',20) canvas.drawString(inch, 10.5 * inch, title) canvas.setFont('Times-Roman',10) canvas.drawCentredString(4.135 * inch, 0.75 * inch, 'Page %d' % canvas.getPageNumber()) #draw a border canvas.setStrokeColorRGB(1,0,0) canvas.setLineWidth(5) canvas.line(0.8 * inch, inch, 0.8 * inch, 10.75 * inch) #reset carefully afterwards canvas.setLineWidth(1) canvas.setStrokeColorRGB(0,0,0) if __name__ == '__main__': run() ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707393948.3345587 reportlab-4.1.0/demos/gadflypaper/0000775000175000017500000000000014561141634016514 5ustar00rptlabrptlab././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1691062242.0 reportlab-4.1.0/demos/gadflypaper/00readme.txt0000664000175000017500000000015114462707742020657 0ustar00rptlabrptlabThis is Aaron Watters' first script; it renders his paper for IPC8 into PDF. A fascinating read, as well.././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1691062242.0 reportlab-4.1.0/demos/gadflypaper/gfe.py0000664000175000017500000007734614462707742017660 0ustar00rptlabrptlab#Copyright ReportLab Europe Ltd. 2000-2017 #see license.txt for license details __doc__='' __version__='3.3.0' #REPORTLAB_TEST_SCRIPT import sys from reportlab.platypus import * from reportlab.lib.styles import getSampleStyleSheet from reportlab.rl_config import defaultPageSize PAGE_HEIGHT=defaultPageSize[1] styles = getSampleStyleSheet() Title = "Integrating Diverse Data Sources with Gadfly 2" Author = "Aaron Watters" URL = "http://www.chordate.com/" email = "arw@ifu.net" Abstract = """This paper describes the primative methods underlying the implementation of SQL query evaluation in Gadfly 2, a database management system implemented in Python [Van Rossum]. The major design goals behind the architecture described here are to simplify the implementation and to permit flexible and efficient extensions to the gadfly engine. Using this architecture and its interfaces programmers can add functionality to the engine such as alternative disk based indexed table implementations, dynamic interfaces to remote data bases or other data sources, and user defined computations.""" from reportlab.lib.units import inch pageinfo = "%s / %s / %s" % (Author, email, Title) def myFirstPage(canvas, doc): canvas.saveState() #canvas.setStrokeColorRGB(1,0,0) #canvas.setLineWidth(5) #canvas.line(66,72,66,PAGE_HEIGHT-72) canvas.setFont('Times-Bold',16) canvas.drawString(108, PAGE_HEIGHT-108, Title) canvas.setFont('Times-Roman',9) canvas.drawString(inch, 0.75 * inch, "First Page / %s" % pageinfo) canvas.restoreState() def myLaterPages(canvas, doc): #canvas.drawImage("snkanim.gif", 36, 36) canvas.saveState() #canvas.setStrokeColorRGB(1,0,0) #canvas.setLineWidth(5) #canvas.line(66,72,66,PAGE_HEIGHT-72) canvas.setFont('Times-Roman',9) canvas.drawString(inch, 0.75 * inch, "Page %d %s" % (doc.page, pageinfo)) canvas.restoreState() def go(): Elements.insert(0,Spacer(0,inch)) doc = SimpleDocTemplate('gfe.pdf') doc.build(Elements,onFirstPage=myFirstPage, onLaterPages=myLaterPages) Elements = [] HeaderStyle = styles["Heading1"] # XXXX def header(txt, style=HeaderStyle, klass=Paragraph, sep=0.3): s = Spacer(0.2*inch, sep*inch) Elements.append(s) para = klass(txt, style) Elements.append(para) ParaStyle = styles["Normal"] def p(txt): return header(txt, style=ParaStyle, sep=0.1) #pre = p # XXX PreStyle = styles["Code"] def pre(txt): s = Spacer(0.1*inch, 0.1*inch) Elements.append(s) p = Preformatted(txt, PreStyle) Elements.append(p) #header(Title, sep=0.1. style=ParaStyle) header(Author, sep=0.1, style=ParaStyle) header(URL, sep=0.1, style=ParaStyle) header(email, sep=0.1, style=ParaStyle) header("ABSTRACT") p(Abstract) header("Backgrounder") p("""\ The term "database" usually refers to a persistent collection of data. Data is persistent if it continues to exist whether or not it is associated with a running process on the computer, or even if the computer is shut down and restarted at some future time. Database management systems provide support for constructing databases, maintaining databases, and extracting information from databases.""") p("""\ Relational databases manipulate and store persistent table structures called relations, such as the following three tables""") pre("""\ -- drinkers who frequent bars (this is a comment) select * from frequents DRINKER | PERWEEK | BAR ============================ adam | 1 | lolas woody | 5 | cheers sam | 5 | cheers norm | 3 | cheers wilt | 2 | joes norm | 1 | joes lola | 6 | lolas norm | 2 | lolas woody | 1 | lolas pierre | 0 | frankies ) """) pre("""\ -- drinkers who like beers select * from likes DRINKER | PERDAY | BEER =============================== adam | 2 | bud wilt | 1 | rollingrock sam | 2 | bud norm | 3 | rollingrock norm | 2 | bud nan | 1 | sierranevada woody | 2 | pabst lola | 5 | mickies """) pre("""\ -- beers served from bars select * from serves BAR | QUANTITY | BEER ================================= cheers | 500 | bud cheers | 255 | samadams joes | 217 | bud joes | 13 | samadams joes | 2222 | mickies lolas | 1515 | mickies lolas | 333 | pabst winkos | 432 | rollingrock frankies | 5 | snafu """) p(""" The relational model for database structures makes the simplifying assumption that all data in a database can be represented in simple table structures such as these. Although this assumption seems extreme it provides a good foundation for defining solid and well defined database management systems and some of the most successful software companies in the world, such as Oracle, Sybase, IBM, and Microsoft, have marketed database management systems based on the relational model quite successfully. """) p(""" SQL stands for Structured Query Language. The SQL language defines industry standard mechanisms for creating, querying, and modified relational tables. Several years ago SQL was one of many Relational Database Management System (RDBMS) query languages in use, and many would argue not the best on. Now, largely due to standardization efforts and the backing of IBM, SQL is THE standard way to talk to database systems. """) p(""" There are many advantages SQL offers over other database query languages and alternative paradigms at this time (please see [O'Neill] or [Korth and Silberschatz] for more extensive discussions and comparisons between the SQL/relational approach and others.) """) p(""" The chief advantage over all contenders at this time is that SQL and the relational model are now widely used as interfaces and back end data stores to many different products with different performance characteristics, user interfaces, and other qualities: Oracle, Sybase, Ingres, SQL Server, Access, Outlook, Excel, IBM DB2, Paradox, MySQL, MSQL, POSTgres, and many others. For this reason, a program designed to use an SQL database as its data storage mechanism can easily be ported from one SQL data manager to another, possibly on different platforms. In fact the same program can seamlessly use several backends and/or import/export data between different data base platforms with trivial ease. No other paradigm offers such flexibility at the moment. """) p(""" Another advantage which is not as immediately obvious is that the relational model and the SQL query language are easily understood by semi-technical and non-technical professionals, such as business people and accountants. Human resources managers who would be terrified by an object model diagram or a snippet of code that resembles a conventional programming language will frequently feel quite at ease with a relational model which resembles the sort of tabular data they deal with on paper in reports and forms on a daily basis. With a little training the same HR managers may be able to translate the request "Who are the drinkers who like bud and frequent cheers?" into the SQL query """) pre(""" select drinker from frequents where bar='cheers' and drinker in ( select drinker from likes where beer='bud') """) p(""" (or at least they have some hope of understanding the query once it is written by a technical person or generated by a GUI interface tool). Thus the use of SQL and the relational model enables communication between different communities which must understand and interact with stored information. In contrast, many other approaches cannot be understood easily by people without extensive programming experience. """) p(""" Furthermore the declarative nature of SQL lends itself to automatic query optimization, and engines such as Gadfly can automatically translate a user query into an optimized query plan which takes advantage of available indices and other data characteristics. In contrast, more navigational techniques require the application program itself to optimize the accesses to the database and explicitly make use of indices. """) # HACK Elements.append(PageBreak()) p(""" While it must be admitted that there are application domains such as computer aided engineering design where the relational model is unnatural, it is also important to recognize that for many application domains (such as scheduling, accounting, inventory, finance, personal information management, electronic mail) the relational model is a very natural fit and the SQL query language make most accesses to the underlying data (even sophisticated ones) straightforward. """) p("""For an example of a moderately sophisticated query using the tables given above, the following query lists the drinkers who frequent lolas bar and like at least two beers not served by lolas """) if 0: go() sys.exit(1) pre(""" select f.drinker from frequents f, likes l where f.drinker=l.drinker and f.bar='lolas' and l.beer not in (select beer from serves where bar='lolas') group by f.drinker having count(distinct beer)>=2 """) p(""" yielding the result """) pre(""" DRINKER ======= norm """) p(""" Experience shows that queries of this sort are actually quite common in many applications, and are often much more difficult to formulate using some navigational database organizations, such as some "object oriented" database paradigms. """) p(""" Certainly, SQL does not provide all you need to interact with databases -- in order to do "real work" with SQL you need to use SQL and at least one other language (such as C, Pascal, C++, Perl, Python, TCL, Visual Basic or others) to do work (such as readable formatting a report from raw data) that SQL was not designed to do. """) header("Why Gadfly 1?") p("""Gadfly 1.0 is an SQL based relational database implementation implemented entirely in the Python programming language, with optional fast data structure accellerators implemented in the C programming language. Gadfly is relatively small, highly portable, very easy to use (especially for programmers with previous experience with SQL databases such as MS Access or Oracle), and reasonably fast (especially when the kjbuckets C accellerators are used). For moderate sized problems Gadfly offers a fairly complete set of features such as transaction semantics, failure recovery, and a TCP/IP based client/server mode (Please see [Gadfly] for detailed discussion).""") header("Why Gadfly 2?") p("""Gadfly 1.0 also has significant limitations. An active Gadfly 1.0 database keeps all data in (virtual) memory, and hence a Gadfly 1.0 database is limited in size to available virtual memory. Important features such as date/time/interval operations, regular expression matching and other standard SQL features are not implemented in Gadfly 1.0. The optimizer and the query evaluator perform optimizations using properties of the equality predicate but do not optimize using properties of inequalities such as BETWEEN or less-than. It is possible to add "extension views" to a Gadfly 1.0 database, but the mechanism is somewhat clumsy and indices over extension views are not well supported. The features of Gadfly 2.0 discussed here attempt to address these deficiencies by providing a uniform extension model that permits addition of alternate table, function, and predicate implementations.""") p("""Other deficiencies, such as missing constructs like "ALTER TABLE" and the lack of outer joins and NULL values are not addressed here, although they may be addressed in Gadfly 2.0 or a later release. This paper also does not intend to explain the complete operations of the internals; it is intended to provide at least enough information to understand the basic mechanisms for extending gadfly.""") p("""Some concepts and definitions provided next help with the description of the gadfly interfaces. [Note: due to the terseness of this format the ensuing is not a highly formal presentation, but attempts to approach precision where precision is important.]""") header("The semilattice of substitutions") p("""Underlying the gadfly implementation are the basic concepts associated with substitutions. A substitution is a mapping of attribute names to values (implemented in gadfly using kjbuckets.kjDict objects). Here an attribute refers to some sort of "descriptive variable", such as NAME and a value is an assignment for that variable, like "Dave Ascher". In Gadfly a table is implemented as a sequence of substitutions, and substitutions are used in many other ways as well. """) p(""" For example consider the substitutions""") pre(""" A = [DRINKER=>'sam'] B = [DRINKER=>'sam', BAR=>'cheers'] C = [DRINKER=>'woody', BEER=>'bud'] D = [DRINKER=>'sam', BEER=>'mickies'] E = [DRINKER=>'sam', BAR=>'cheers', BEER=>'mickies'] F = [DRINKER=>'sam', BEER=>'mickies'] G = [BEER=>'bud', BAR=>'lolas'] H = [] # the empty substitution I = [BAR=>'cheers', CAPACITY=>300]""") p("""A trivial but important observation is that since substitutions are mappings, no attribute can assume more than one value in a substitution. In the operations described below whenever an operator "tries" to assign more than one value to an attribute the operator yields an "overdefined" or "inconsistent" result.""") header("Information Semi-order:") p("""Substitution B is said to be more informative than A because B agrees with all assignments in A (in addition to providing more information as well). Similarly we say that E is more informative than A, B, D, F and H but E is not more informative than the others since, for example, G disagrees with E on the value assigned to the BEER attribute and I provides additional CAPACITY information not provided in E.""") header("Joins and Inconsistency:") p("""A join of two substitutions X and Y is the least informative substitution Z such that Z is more informative (or equally informative) than both X and Y. For example, B is the join of B with A, E is the join of B with D and""") pre(""" E join I = [DRINKER=>'sam', BAR=>'cheers', BEER=>'mickies', CAPACITY=>300]""") p("""For any two substitutions either (1) they disagree on the value assigned to some attribute and have no join or (2) they agree on all common attributes (if there are any) and their join is the union of all (name, value) assignments in both substitutions. Written in terms of kjbucket.kjDict operations two kjDicts X and Y have a join Z = (X+Y) if and only if Z.Clean() is not None. Two substitutions that have no join are said to be inconsistent. For example, I and G are inconsistent since they disagree on the value assigned to the BAR attribute and therefore have no join. The algebra of substitutions with joins technically defines an abstract algebraic structure called a semilattice.""") header("Name space remapping") p("""Another primitive operation over substitutions is the remap operation S2 = S.remap(R) where S is a substitution and R is a graph of attribute names and S2 is a substitution. This operation is defined to produce the substitution S2 such that""") pre(""" Name=>Value in S2 if and only if Name1=>Value in S and Name<=Name1 in R """) p("""or if there is no such substitution S2 the remap value is said to be overdefined.""") p("""For example the remap operation may be used to eliminate attributes from a substitution. For example""") pre(""" E.remap([DRINKER<=DRINKER, BAR<=BAR]) = [DRINKER=>'sam', BAR=>'cheers'] """) p("""Illustrating that remapping using the [DRINKER<=DRINKER, BAR<=BAR] graph eliminates all attributes except DRINKER and BAR, such as BEER. More generally remap can be used in this way to implement the classical relational projection operation. (See [Korth and Silberschatz] for a detailed discussion of the projection operator and other relational algebra operators such as selection, rename, difference and joins.)""") p("""The remap operation can also be used to implement "selection on attribute equality". For example, if we are interested in the employee names of employees who are their own bosses we can use the remapping graph""") pre(""" R1 = [NAME<=NAME, NAME<=BOSS] """) p("""and reject substitutions where remapping using R1 is overdefined. For example""") pre(""" S1 = [NAME=>'joe', BOSS=>'joe'] S1.remap(R1) = [NAME=>'joe'] S2 = [NAME=>'fred', BOSS=>'joe'] S2.remap(R1) is overdefined. """) p("""The last remap is overdefined because the NAME attribute cannot assume both the values 'fred' and 'joe' in a substitution.""") p("""Furthermore, of course, the remap operation can be used to "rename attributes" or "copy attribute values" in substitutions. Note below that the missing attribute CAPACITY in B is effectively ignored in the remapping operation.""") pre(""" B.remap([D<=DRINKER, B<=BAR, B2<=BAR, C<=CAPACITY]) = [D=>'sam', B=>'cheers', B2=>'cheers'] """) p("""More interestingly, a single remap operation can be used to perform a combination of renaming, projection, value copying, and attribute equality selection as one operation. In kjbuckets the remapper graph is implemented using a kjbuckets.kjGraph and the remap operation is an intrinsic method of kjbuckets.kjDict objects.""") header("Generalized Table Joins and the Evaluator Mainloop""") p("""Strictly speaking the Gadfly 2.0 query evaluator only uses the join and remap operations as its "basic assembly language" -- all other computations, including inequality comparisons and arithmetic, are implemented externally to the evaluator as "generalized table joins." """) p("""A table is a sequence of substitutions (which in keeping with SQL semantics may contain redundant entries). The join between two tables T1 and T2 is the sequence of all possible defined joins between pairs of elements from the two tables. Procedurally we might compute the join as""") pre(""" T1JoinT2 = empty for t1 in T1: for t2 in T2: if t1 join t2 is defined: add t1 join t2 to T1joinT2""") p("""In general circumstances, this intuitive implementation is a very inefficient way to compute the join, and Gadfly almost always uses other methods, particularly since, as described below, a "generalized table" can have an "infinite" number of entries.""") p("""For an example of a table join consider the EMPLOYEES table containing""") pre(""" [NAME=>'john', JOB=>'executive'] [NAME=>'sue', JOB=>'programmer'] [NAME=>'eric', JOB=>'peon'] [NAME=>'bill', JOB=>'peon'] """) p("""and the ACTIVITIES table containing""") pre(""" [JOB=>'peon', DOES=>'windows'] [JOB=>'peon', DOES=>'floors'] [JOB=>'programmer', DOES=>'coding'] [JOB=>'secretary', DOES=>'phone']""") p("""then the join between EMPLOYEES and ACTIVITIES must containing""") pre(""" [NAME=>'sue', JOB=>'programmer', DOES=>'coding'] [NAME=>'eric', JOB=>'peon', DOES=>'windows'] [NAME=>'bill', JOB=>'peon', DOES=>'windows'] [NAME=>'eric', JOB=>'peon', DOES=>'floors'] [NAME=>'bill', JOB=>'peon', DOES=>'floors']""") p("""A compiled gadfly subquery ultimately appears to the evaluator as a sequence of generalized tables that must be joined (in combination with certain remapping operations that are beyond the scope of this discussion). The Gadfly mainloop proceeds following the very loose pseudocode:""") pre(""" Subs = [ [] ] # the unary sequence containing "true" While some table hasn't been chosen yet: Choose an unchosen table with the least cost join estimate. Subs = Subs joined with the chosen table return Subs""") p("""[Note that it is a property of the join operation that the order in which the joins are carried out will not affect the result, so the greedy strategy of evaluating the "cheapest join next" will not affect the result. Also, note that the treatment of logical OR and NOT as well as EXIST, IN, UNION, and aggregation and so forth are not discussed here, even though they do fit into this approach.]""") p("""The actual implementation is a bit more complex than this, but the above outline may provide some useful intuition. The "cost estimation" step and the implementation of the join operation itself are left up to the generalized table object implementation. A table implementation has the ability to give an "infinite" cost estimate, which essentially means "don't join me in yet under any circumstances." """) header("Implementing Functions") p("""As mentioned above operations such as arithmetic are implemented using generalized tables. For example, the arithmetic Add operation is implemented in Gadfly internally as an "infinite generalized table" containing all possible substitutions""") pre(""" ARG0=>a, ARG1=>b, RESULT=>a+b] """) p("""Where a and b are all possible values which can be summed. Clearly, it is not possible to enumerate this table, but given a sequence of substitutions with defined values for ARG0 and ARG1 such as""") pre(""" [ARG0=>1, ARG1=-4] [ARG0=>2.6, ARG1=50] [ARG0=>99, ARG1=1] """) p("""it is possible to implement a "join operation" against this sequence that performs the same augmentation as a join with the infinite table defined above:""") pre(""" [ARG0=>1, ARG1=-4, RESULT=-3] [ARG0=>2.6, ARG1=50, RESULT=52.6] [ARG0=>99, ARG1=1, RESULT=100] """) p("""Furthermore by giving an "infinite estimate" for all attempts to evaluate the join where ARG0 and ARG1 are not available the generalized table implementation for the addition operation can refuse to compute an "infinite join." """) p("""More generally all functions f(a,b,c,d) are represented in gadfly as generalized tables containing all possible relevant entries""") pre(""" [ARG0=>a, ARG1=>b, ARG2=>c, ARG3=>d, RESULT=>f(a,b,c,d)]""") p("""and the join estimation function refuses all attempts to perform a join unless all the arguments are provided by the input substitution sequence.""") header("Implementing Predicates") p("""Similarly to functions, predicates such as less-than and BETWEEN and LIKE are implemented using the generalized table mechanism. For example, the "x BETWEEN y AND z" predicate is implemented as a generalized table "containing" all possible""") pre(""" [ARG0=>a, ARG1=>b, ARG2=>c]""") p("""where b<a<c. Furthermore joins with this table are not permitted unless all three arguments are available in the sequence of input substitutions.""") header("Some Gadfly extension interfaces") p("""A gadfly database engine may be extended with user defined functions, predicates, and alternative table and index implementations. This section snapshots several Gadfly 2.0 interfaces, currently under development and likely to change before the package is released.""") p("""The basic interface for adding functions and predicates (logical tests) to a gadfly engine are relatively straightforward. For example, to add the ability to match a regular expression within a gadfly query use the following implementation.""") pre(""" from re import match def addrematch(gadflyinstance): gadflyinstance.add_predicate("rematch", match) """) p(""" Then upon connecting to the database execute """) pre(""" g = gadfly(...) ... addrematch(g) """) p(""" In this case the "semijoin operation" associated with the new predicate "rematch" is automatically generated, and after the add_predicate binding operation the gadfly instance supports queries such as""") pre(""" select drinker, beer from likes where rematch('b*', beer) and drinker not in (select drinker from frequents where rematch('c*', bar)) """) p(""" By embedding the "rematch" operation within the query the SQL engine can do "more work" for the programmer and reduce or eliminate the need to process the query result externally to the engine. """) p(""" In a similar manner functions may be added to a gadfly instance,""") pre(""" def modulo(x,y): return x % y def addmodulo(gadflyinstance): gadflyinstance.add_function("modulo", modulo) ... g = gadfly(...) ... addmodulo(g) """) p(""" Then after the binding, the modulo function can be used wherever an SQL expression can occur. """) p(""" Adding alternative table implementations to a Gadfly instance is more interesting and more difficult. An "extension table" implementation must conform to the following interface:""") pre(""" # get the kjbuckets.kjSet set of attribute names for this table names = table.attributes() # estimate the difficulty of evaluating a join given known attributes # return None for "impossible" or n>=0 otherwise with larger values # indicating greater difficulty or expense estimate = table.estimate(known_attributes) # return the join of the rows of the table with # the list of kjbuckets.kjDict mappings as a list of mappings. resultmappings = table.join(listofmappings) """) p(""" In this case, add the table to a gadfly instance using""") pre(""" gadflyinstance.add_table("table_name", table) """) p(""" For example to add a table which automatically queries filenames in the filesystems of the host computer a gadfly instance could be augmented with a GLOB table implemented using the standard library function glob.glob as follows:""") pre(""" import kjbuckets class GlobTable: def __init__(self): pass def attributes(self): return kjbuckets.kjSet("PATTERN", "NAME") def estimate(self, known_attributes): if known_attributes.member("PATTERN"): return 66 # join not too difficult else: return None # join is impossible (must have PATTERN) def join(self, listofmappings): from glob import glob result = [] for m in listofmappings: pattern = m["PATTERN"] for name in glob(pattern): newmapping = kjbuckets.kjDict(m) newmapping["NAME"] = name if newmapping.Clean(): result.append(newmapping) return result ... gadfly_instance.add_table("GLOB", GlobTable()) """) p(""" Then one could formulate queries such as "list the files in directories associated with packages installed by guido" """) pre(""" select g.name as filename from packages p, glob g where p.installer = 'guido' and g.pattern=p.root_directory """) p(""" Note that conceptually the GLOB table is an infinite table including all filenames on the current computer in the "NAME" column, paired with a potentially infinite number of patterns. """) p(""" More interesting examples would allow queries to remotely access data served by an HTTP server, or from any other resource. """) p(""" Furthermore, an extension table can be augmented with update methods """) pre(""" table.insert_rows(listofmappings) table.update_rows(oldlist, newlist) table.delete_rows(oldlist) """) p(""" Note: at present, the implementation does not enforce recovery or transaction semantics for updates to extension tables, although this may change in the final release. """) p(""" The table implementation is free to provide its own implementations of indices that take advantage of data provided by the join argument. """) header("Efficiency Notes") p("""The following thought experiment attempts to explain why the Gadfly implementation is surprisingly fast considering that it is almost entirely implemented in Python (an interpreted programming language which is not especially fast when compared to alternatives). Although Gadfly is quite complex, at an abstract level the process of query evaluation boils down to a series of embedded loops. Consider the following nested loops:""") pre(""" iterate 1000: f(...) # fixed cost of outer loop iterate 10: g(...) # fixed cost of middle loop iterate 10: # the real work (string parse, matrix mul, query eval...) h(...)""") p("""In my experience, many computations follow this pattern where f, g, are complex, dynamic, special purpose and h is simple, general purpose, static. Some example computations that follow this pattern include: file massaging (perl), matrix manipulation (python, tcl), database/cgi page generation, and vector graphics/imaging.""") p("""Suppose implementing f, g, h in python is easy but result in execution times10 times slower than a much harder implementation in C, choosing arbitrary and debatable numbers assume each function call consumes 1 tick in C, 5 ticks in java, 10 ticks in python for a straightforward implementation of each function f, g, and h. Under these conditions, we get the following cost analysis, eliminating some uninteresting combinations, of implementing the function f, g, and h in combinations of Python, C and java:""") pre(""" COST | FLANG | GLANG | HLANG ================================== 111000 | C | C | C 115000 | java | C | C 120000 | python | C | C 155000 | java | java | C 210000 | python | python | C 555000 | java | java | java 560000 | python | java | java 610000 | python | python | java 1110000 | python | python | python """) p("""Note that moving only the innermost loop to C (python/python/C) speeds up the calculation by half an order of magnitude compared to the python-only implementation and brings the speed to within a factor of 2 of an implementation done entirely in C.""") p("""Although this artificial and contrived thought experiment is far from conclusive, we may be tempted to draw the conclusion that generally programmers should focus first on obtaining a working implementation (because as John Ousterhout is reported to have said "the biggest performance improvement is the transition from non-working to working") using the methodology that is most likely to obtain a working solution the quickest (Python). Only then if the performance is inadequate should the programmer focus on optimizing the inner most loops, perhaps moving them to a very efficient implementation (C). Optimizing the outer loops will buy little improvement, and should be done later, if ever.""") p("""This was precisely the strategy behind the gadfly implementations, where most of the inner loops are implemented in the kjbuckets C extension module and the higher level logic is all in Python. This also explains why gadfly appears to be "slower" for simple queries over small data sets, but seems to be relatively "faster" for more complex queries over larger data sets, since larger queries and data sets take better advantage of the optimized inner loops.""") header("A Gadfly variant for OLAP?") p("""In private correspondence Andy Robinson points out that the basic logical design underlying Gadfly could be adapted to provide Online Analytical Processing (OLAP) and other forms of data warehousing and data mining. Since SQL is not particularly well suited for the kinds of requests common in these domains the higher level interfaces would require modification, but the underlying logic of substitutions and name mappings seems to be appropriate.""") header("Conclusion") p("""The revamped query engine design in Gadfly 2 supports a flexible and general extension methodology that permits programmers to extend the gadfly engine to include additional computations and access to remote data sources. Among other possibilities, this will permit the gadfly engine to make use of disk based indexed tables and to dynamically retrieve information from remote data sources (such as an Excel spreadsheet or an Oracle database). These features will make gadfly a very useful tool for data manipulation and integration.""") header("References") p("""[Van Rossum] Van Rossum, Python Reference Manual, Tutorial, and Library Manuals, please look to http://www.python.org for the latest versions, downloads and links to printed versions.""") p("""[O'Neill] O'Neill, P., Data Base Principles, Programming, Performance, Morgan Kaufmann Publishers, San Francisco, 1994.""") p("""[Korth and Silberschatz] Korth, H. and Silberschatz, A. and Sudarshan, S. Data Base System Concepts, McGraw-Hill Series in Computer Science, Boston, 1997""") p("""[Gadfly]Gadfly: SQL Relational Database in Python, http://www.chordate.com/kwParsing/gadfly.html""") go() ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707393948.3385587 reportlab-4.1.0/demos/odyssey/0000775000175000017500000000000014561141634015715 5ustar00rptlabrptlab././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1691062242.0 reportlab-4.1.0/demos/odyssey/00readme.txt0000664000175000017500000000406214462707742020065 0ustar00rptlabrptlabThis contains a number of benchmarks and demos based on Homer's Odyssey (which is widely available in plain, line-oriented text format). The version used here was obtained from Project Gutenberg. The URL is as follows: http://www.gutenberg.org/etext/1727 Our distribution ships with just the first chapter in odyssey.txt. For a more meaningful speed test, download the full copy from http://www.reportlab.com/ftp/odyssey.full.zip and unzip to extract odyssey.full.txt (608kb). Benchmark speed depends quite critically on the presence of our accelerator module, _rl_accel, which is a C extension. Serious users ought to compile or download this! The times quoted are from one machine (Andy Robinson's home PC, approx 1.2Ghz 128Mb Ram, Win2k in Sep 2003) in order to give a rough idea of what features cost what performance. The tests are as follows: (1) odyssey.py (produces odyssey.pdf) This demo takes a large volume of text and prints it in the simplest way possible. It is a demo of the basic technique of looping down a page manually and breaking at the bottom. On my 1.2 Ghz machine this takes 1.91 seconds (124 pages per second) (2) fodyssey.py (produces fodyssey.pdf) This is a 'flowing document' we parse the file and throw away line breaks to make proper paragraphs. The Platypus framework renders these. This necessitates measuring the width of every word in every paragraph for wrapping purposes. This takes 3.27 seconds on the same machine. Paragraph wrapping basically doubles the work. The text is more compact with about 50% more words per page. Very roughly, we can wrap 40 pages of ten-point text per second and save to PDF. (3) dodyssey.py (produced dodyssey.pdf) This is a slightly fancier version which uses different page templates (one column for first page in a chapter, two column for body poages). The additional layout logic adds about 15%, going up to 3.8 seconds. This is probably a realistic benchmark for a simple long text document with a single pass. Documents doing cross-references and a table of contents might need twice as long. ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1691062242.0 reportlab-4.1.0/demos/odyssey/dodyssey.py0000664000175000017500000001674114462707742020153 0ustar00rptlabrptlab#Copyright ReportLab Europe Ltd. 2000-2017 #see license.txt for license details __version__='3.3.0' __doc__='' #REPORTLAB_TEST_SCRIPT import sys, copy, os from reportlab.platypus import * _NEW_PARA=os.environ.get('NEW_PARA','0')[0] in ('y','Y','1') _REDCAP=int(os.environ.get('REDCAP','0')) _CALLBACK=os.environ.get('CALLBACK','0')[0] in ('y','Y','1') if _NEW_PARA: def Paragraph(s,style): from rlextra.radxml.para import Paragraph as PPPP return PPPP(s,style) from reportlab.lib.units import inch from reportlab.lib.styles import getSampleStyleSheet from reportlab.lib.enums import TA_LEFT, TA_RIGHT, TA_CENTER, TA_JUSTIFY import reportlab.rl_config reportlab.rl_config.invariant = 1 styles = getSampleStyleSheet() Title = "The Odyssey" Author = "Homer" def myTitlePage(canvas, doc): canvas.saveState() canvas.restoreState() def myLaterPages(canvas, doc): canvas.saveState() canvas.setFont('Times-Roman',9) canvas.drawString(inch, 0.75 * inch, "Page %d" % doc.page) canvas.restoreState() def go(): def myCanvasMaker(fn,**kw): from reportlab.pdfgen.canvas import Canvas canv = Canvas(fn,**kw) # attach our callback to the canvas canv.myOnDrawCB = myOnDrawCB return canv doc = BaseDocTemplate('dodyssey.pdf',showBoundary=0) #normal frame as for SimpleFlowDocument frameT = Frame(doc.leftMargin, doc.bottomMargin, doc.width, doc.height, id='normal') #Two Columns frame1 = Frame(doc.leftMargin, doc.bottomMargin, doc.width/2-6, doc.height, id='col1') frame2 = Frame(doc.leftMargin+doc.width/2+6, doc.bottomMargin, doc.width/2-6, doc.height, id='col2') doc.addPageTemplates([PageTemplate(id='First',frames=frameT, onPage=myTitlePage), PageTemplate(id='OneCol',frames=frameT, onPage=myLaterPages), PageTemplate(id='TwoCol',frames=[frame1,frame2], onPage=myLaterPages), ]) doc.build(Elements,canvasmaker=myCanvasMaker) Elements = [] ChapterStyle = copy.deepcopy(styles["Heading1"]) ChapterStyle.alignment = TA_CENTER ChapterStyle.fontsize = 14 InitialStyle = copy.deepcopy(ChapterStyle) InitialStyle.fontsize = 16 InitialStyle.leading = 20 PreStyle = styles["Code"] def newPage(): Elements.append(PageBreak()) chNum = 0 def myOnDrawCB(canv,kind,label): print('myOnDrawCB(%s)'%kind, 'Page number=', canv.getPageNumber(), 'label value=', label) def chapter(txt, style=ChapterStyle): global chNum Elements.append(NextPageTemplate('OneCol')) newPage() chNum += 1 if _NEW_PARA or not _CALLBACK: Elements.append(Paragraph(txt, style)) else: Elements.append(Paragraph(('foo '%chNum)+txt, style)) Elements.append(Spacer(0.2*inch, 0.3*inch)) if useTwoCol: Elements.append(NextPageTemplate('TwoCol')) def fTitle(txt,style=InitialStyle): Elements.append(Paragraph(txt, style)) ParaStyle = copy.deepcopy(styles["Normal"]) ParaStyle.spaceBefore = 0.1*inch if 'right' in sys.argv: ParaStyle.alignment = TA_RIGHT elif 'left' in sys.argv: ParaStyle.alignment = TA_LEFT elif 'justify' in sys.argv: ParaStyle.alignment = TA_JUSTIFY elif 'center' in sys.argv or 'centre' in sys.argv: ParaStyle.alignment = TA_CENTER else: ParaStyle.alignment = TA_JUSTIFY useTwoCol = 'notwocol' not in sys.argv def spacer(inches): Elements.append(Spacer(0.1*inch, inches*inch)) def p(txt, style=ParaStyle): if _REDCAP: fs, fe = '', '' n = len(txt) for i in range(n): if 'a'<=txt[i]<='z' or 'A'<=txt[i]<='Z': txt = (txt[:i]+(fs+txt[i]+fe))+txt[i+1:] break if _REDCAP>=2 and n>20: j = i+len(fs)+len(fe)+1+int((n-1)/2) while not ('a'<=txt[j]<='z' or 'A'<=txt[j]<='Z'): j += 1 txt = (txt[:j]+(''+txt[j]+''))+txt[j+1:] if _REDCAP==3 and n>20: n = len(txt) fs = '' for i in range(n-1,-1,-1): if 'a'<=txt[i]<='z' or 'A'<=txt[i]<='Z': txt = txt[:i]+((fs+txt[i]+fe)+txt[i+1:]) break Elements.append(Paragraph(txt, style)) firstPre = 1 def pre(txt, style=PreStyle): global firstPre if firstPre: Elements.append(NextPageTemplate('OneCol')) newPage() firstPre = 0 spacer(0.1) p = Preformatted(txt, style) Elements.append(p) def parseOdyssey(fn): from time import time E = [] t0=time() text = open(fn,'r').read() i0 = text.index('Book I') endMarker = 'covenant of peace between the two contending parties.' i1 = text.index(endMarker)+len(endMarker) PREAMBLE=list(map(str.strip,text[0:i0].split('\n'))) L=list(map(str.strip,text[i0:i1].split('\n'))) POSTAMBLE=list(map(str.strip,text[i1:].split('\n'))) def ambleText(L): while L and not L[0]: L.pop(0) while L: T=[] while L and L[0]: T.append(L.pop(0)) yield T while L and not L[0]: L.pop(0) def mainText(L): while L: B = L.pop(0) while not L[0]: L.pop(0) T=[] while L and L[0]: T.append(L.pop(0)) while not L[0]: L.pop(0) P = [] while L and not (L[0].startswith('Book ') and len(L[0].split())==2): E=[] while L and L[0]: E.append(L.pop(0)) P.append(E) if L: while not L[0]: L.pop(0) yield B,T,P t1 = time() print("open(%s,'r').read() took %.4f seconds" %(fn,t1-t0)) E.append([spacer,2]) E.append([fTitle,'%s' % Title, InitialStyle]) E.append([fTitle,'by %s' % Author, InitialStyle]) for T in ambleText(PREAMBLE): E.append([p,'\n'.join(T)]) for (B,T,P) in mainText(L): E.append([chapter,B]) E.append([p,'%s' % '\n'.join(T),ParaStyle]) for x in P: E.append([p,' '.join(x)]) firstPre = 1 for T in ambleText(POSTAMBLE): E.append([p,'\n'.join(T)]) t3 = time() print("Parsing into memory took %.4f seconds" %(t3-t1)) del L t4 = time() print("Deleting list of lines took %.4f seconds" %(t4-t3)) for i in range(len(E)): E[i][0](*E[i][1:]) t5 = time() print("Moving into platypus took %.4f seconds" %(t5-t4)) del E t6 = time() print("Deleting list of actions took %.4f seconds" %(t6-t5)) go() t7 = time() print("saving to PDF took %.4f seconds" %(t7-t6)) print("Total run took %.4f seconds"%(t7-t0)) import hashlib print('file digest: %s' % hashlib.md5(open('dodyssey.pdf','rb').read()).hexdigest()) def run(): for fn in ('odyssey.full.txt','odyssey.txt'): if os.path.isfile(fn): parseOdyssey(fn) break def doProf(profname,func,*args,**kwd): import hotshot, hotshot.stats prof = hotshot.Profile(profname) prof.runcall(func) prof.close() stats = hotshot.stats.load(profname) stats.strip_dirs() stats.sort_stats('time', 'calls') stats.print_stats(20) if __name__=='__main__': if '--prof' in sys.argv: doProf('dodyssey.prof',run) else: run() ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1691062242.0 reportlab-4.1.0/demos/odyssey/fodyssey.py0000664000175000017500000001074414462707742020152 0ustar00rptlabrptlab#Copyright ReportLab Europe Ltd. 2000-2017 #see license.txt for license details __version__='3.3.0' __doc__='' #REPORTLAB_TEST_SCRIPT import sys, copy, os from reportlab.platypus import * from reportlab.lib.units import inch from reportlab.lib.styles import getSampleStyleSheet from reportlab.lib.enums import TA_LEFT, TA_RIGHT, TA_CENTER, TA_JUSTIFY import reportlab.rl_config reportlab.rl_config.invariant = 1 styles = getSampleStyleSheet() Title = "The Odyssey" Author = "Homer" def myFirstPage(canvas, doc): canvas.saveState() canvas.restoreState() def myLaterPages(canvas, doc): canvas.saveState() canvas.setFont('Times-Roman',9) canvas.drawString(inch, 0.75 * inch, "Page %d" % doc.page) canvas.restoreState() def go(): doc = SimpleDocTemplate('fodyssey.pdf',showBoundary='showboundary' in sys.argv) doc.allowSplitting = not 'nosplitting' in sys.argv doc.build(Elements,myFirstPage,myLaterPages) Elements = [] ChapterStyle = copy.copy(styles["Heading1"]) ChapterStyle.alignment = TA_CENTER ChapterStyle.fontsize = 16 InitialStyle = copy.deepcopy(ChapterStyle) InitialStyle.fontsize = 16 InitialStyle.leading = 20 PreStyle = styles["Code"] def newPage(): Elements.append(PageBreak()) def chapter(txt, style=ChapterStyle): newPage() Elements.append(Paragraph(txt, style)) Elements.append(Spacer(0.2*inch, 0.3*inch)) def fTitle(txt,style=InitialStyle): Elements.append(Paragraph(txt, style)) ParaStyle = copy.deepcopy(styles["Normal"]) ParaStyle.spaceBefore = 0.1*inch if 'right' in sys.argv: ParaStyle.alignment = TA_RIGHT elif 'left' in sys.argv: ParaStyle.alignment = TA_LEFT elif 'justify' in sys.argv: ParaStyle.alignment = TA_JUSTIFY elif 'center' in sys.argv or 'centre' in sys.argv: ParaStyle.alignment = TA_CENTER else: ParaStyle.alignment = TA_JUSTIFY def spacer(inches): Elements.append(Spacer(0.1*inch, inches*inch)) def p(txt, style=ParaStyle): Elements.append(Paragraph(txt, style)) def pre(txt, style=PreStyle): spacer(0.1) p = Preformatted(txt, style) Elements.append(p) def parseOdyssey(fn): from time import time E = [] t0=time() text = open(fn,'r').read() i0 = text.index('Book I') endMarker = 'covenant of peace between the two contending parties.' i1 = text.index(endMarker)+len(endMarker) PREAMBLE=list(map(str.strip,text[0:i0].split('\n'))) L=list(map(str.strip,text[i0:i1].split('\n'))) POSTAMBLE=list(map(str.strip,text[i1:].split('\n'))) def ambleText(L): while L and not L[0]: L.pop(0) while L: T=[] while L and L[0]: T.append(L.pop(0)) yield T while L and not L[0]: L.pop(0) def mainText(L): while L: B = L.pop(0) while not L[0]: L.pop(0) T=[] while L and L[0]: T.append(L.pop(0)) while not L[0]: L.pop(0) P = [] while L and not (L[0].startswith('Book ') and len(L[0].split())==2): E=[] while L and L[0]: E.append(L.pop(0)) P.append(E) if L: while not L[0]: L.pop(0) yield B,T,P t1 = time() print("open(%s,'r').read() took %.4f seconds" %(fn,t1-t0)) E.append([spacer,2]) E.append([fTitle,'%s' % Title, InitialStyle]) E.append([fTitle,'by %s' % Author, InitialStyle]) for T in ambleText(PREAMBLE): E.append([p,'\n'.join(T)]) for (B,T,P) in mainText(L): E.append([chapter,B]) E.append([p,'%s' % '\n'.join(T),ParaStyle]) for x in P: E.append([p,' '.join(x)]) firstPre = 1 for T in ambleText(POSTAMBLE): E.append([p,'\n'.join(T)]) t3 = time() print("Parsing into memory took %.4f seconds" %(t3-t1)) del L t4 = time() print("Deleting list of lines took %.4f seconds" %(t4-t3)) for i in range(len(E)): E[i][0](*E[i][1:]) t5 = time() print("Moving into platypus took %.4f seconds" %(t5-t4)) del E t6 = time() print("Deleting list of actions took %.4f seconds" %(t6-t5)) go() t7 = time() print("saving to PDF took %.4f seconds" %(t7-t6)) print("Total run took %.4f seconds"%(t7-t0)) for fn in ('odyssey.full.txt','odyssey.txt'): if os.path.isfile(fn): break if __name__=='__main__': parseOdyssey(fn) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1691062242.0 reportlab-4.1.0/demos/odyssey/odyssey.py0000664000175000017500000001021314462707742017773 0ustar00rptlabrptlab#Copyright ReportLab Europe Ltd. 2000-2017 #see license.txt for license details __version__='3.3.0' ___doc__='' #odyssey.py # #Demo/benchmark of PDFgen rendering Homer's Odyssey. #results on my humble P266 with 64MB: # Without page compression: # 239 pages in 3.76 seconds = 77 pages per second # With textOut rather than textLine, i.e. computing width # of every word as we would for wrapping: # 239 pages in 10.83 seconds = 22 pages per second # With page compression and textLine(): # 239 pages in 39.39 seconds = 6 pages per second from reportlab.pdfgen import canvas import time, os, sys #find out what platform we are on and whether accelerator is #present, in order to print this as part of benchmark info. try: import _rl_accel ACCEL = 1 except ImportError: ACCEL = 0 from reportlab.lib.units import inch, cm from reportlab.lib.pagesizes import A4 #precalculate some basics top_margin = A4[1] - inch bottom_margin = inch left_margin = inch right_margin = A4[0] - inch frame_width = right_margin - left_margin def drawPageFrame(canv): canv.line(left_margin, top_margin, right_margin, top_margin) canv.setFont('Times-Italic',12) canv.drawString(left_margin, top_margin + 2, "Homer's Odyssey") canv.line(left_margin, top_margin, right_margin, top_margin) canv.line(left_margin, bottom_margin, right_margin, bottom_margin) canv.drawCentredString(0.5*A4[0], 0.5 * inch, "Page %d" % canv.getPageNumber()) def run(verbose=1): verStr = '%d.%d' % (sys.version_info[0:2]) if ACCEL: accelStr = 'with _rl_accel' else: accelStr = 'without _rl_accel' print('Benchmark of Python %s %s' % (verStr, accelStr)) started = time.time() canv = canvas.Canvas('odyssey.pdf', invariant=1) canv.setPageCompression(1) drawPageFrame(canv) #do some title page stuff canv.setFont("Times-Bold", 36) canv.drawCentredString(0.5 * A4[0], 7 * inch, "Homer's Odyssey") canv.setFont("Times-Bold", 18) canv.drawCentredString(0.5 * A4[0], 5 * inch, "Translated by Samuel Burton") canv.setFont("Times-Bold", 12) tx = canv.beginText(left_margin, 3 * inch) tx.textLine("This is a demo-cum-benchmark for PDFgen. It renders the complete text of Homer's Odyssey") tx.textLine("from a text file. On my humble P266, it does 77 pages per secondwhile creating a 238 page") tx.textLine("document. If it is asked to computer text metrics, measuring the width of each word as ") tx.textLine("one would for paragraph wrapping, it still manages 22 pages per second.") tx.textLine("") tx.textLine("Andy Robinson, Robinson Analytics Ltd.") canv.drawText(tx) canv.showPage() #on with the text... drawPageFrame(canv) canv.setFont('Times-Roman', 12) tx = canv.beginText(left_margin, top_margin - 0.5*inch) for fn in ('odyssey.full.txt','odyssey.txt'): if os.path.isfile(fn): break data = open(fn,'r').readlines() for line in data: #this just does it the fast way... tx.textLine(line.rstrip()) #page breaking y = tx.getY() #get y coordinate if y < bottom_margin + 0.5*inch: canv.drawText(tx) canv.showPage() drawPageFrame(canv) canv.setFont('Times-Roman', 12) tx = canv.beginText(left_margin, top_margin - 0.5*inch) #page pg = canv.getPageNumber() if verbose and pg % 10 == 0: print('formatted page %d' % canv.getPageNumber()) if tx: canv.drawText(tx) canv.showPage() drawPageFrame(canv) if verbose: print('about to write to disk...') canv.save() finished = time.time() elapsed = finished - started pages = canv.getPageNumber()-1 speed = pages / elapsed fileSize = os.stat('odyssey.pdf')[6] / 1024 print('%d pages in %0.2f seconds = %0.2f pages per second, file size %d kb' % ( pages, elapsed, speed, fileSize)) import hashlib print('file digest: %s' % hashlib.md5(open('odyssey.pdf','rb').read()).hexdigest()) if __name__=='__main__': quiet = ('-q' in sys.argv) run(verbose = not quiet) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1691062242.0 reportlab-4.1.0/demos/odyssey/odyssey.txt0000664000175000017500000002530614462707742020173 0ustar00rptlabrptlabThe Odyssey By Homer rendered into English prose by Samuel Butler Book I THE GODS IN COUNCIL--MIVERVA'S VISIT TO ITHACA--THE CHALLENGE FROM TELEMACHUS TO THE SUITORS. ITellme, O Muse, of that ingenious hero who travelled far and a b c &| & | A' A ' wide after he had sacked the famous town of Troy. Many cities did he visit, and many were the nations with whose manners and customs he was acquainted; moreover he suffered much by sea while trying to save his own life and bring his men safely home; but do what he might he could not save his men, for they perished through their own sheer folly in eating the cattle of the Sun-god Hyperion; so the god prevented them from ever reaching home. Tell me, too, about all these things, oh daughter of Jove, from whatsoever source you may know them. So now all who escaped death in battle or by shipwreck had got safely home except Ulysses, and he, though he was longing to return to his wife and country, was detained by the goddess Calypso, who had got him into a large cave and wanted to marry him. But as years went by, there came a time when the gods settled that he should go back to Ithaca; even then, however, when he was among his own people, his troubles were not yet over; nevertheless all the gods had now begun to pity him except Neptune, who still persecuted him without ceasing and would not let him get home. Now Neptune had gone off to the Ethiopians, who are at the world's end, and lie in two halves, the one looking West and the other East.1 He had gone there to accept a hecatomb of sheep and oxen, and was enjoying himself at his festival; but the other gods met in the house of Olympian Jove, and the sire of gods and men spoke first. At that moment he was thinking of Aegisthus, who had been killed by Agamemnon's son Orestes; so he said to the other gods: "See now, how men lay blame upon us gods for what is after all nothing but their own folly. Look at Aegisthus; he must needs make love to Agamemnon's wife unrighteously and then kill Agamemnon, though he knew it would be the death of him; for I sent Mercury to warn him not to do either of these things, inasmuch as Orestes would be sure to take his revenge when he grew up and wanted to return home. Mercury told him this in all good will but he would not listen, and now he has paid for everything in full." Then Minerva said, "Father, son of Saturn, King of kings, it served Aegisthus right, and so it would any one else who does as he did; but Aegisthus is neither here nor there; it is for Ulysses that my heart bleeds, when I think of his sufferings in that lonely sea-girt island, far away, poor man, from all his friends. It is an island covered with forest, in the very middle of the sea, and a goddess lives there, daughter of the magician Atlas, who looks after the bottom of the ocean, and carries the great columns that keep heaven and earth asunder. This daughter of Atlas has got hold of poor unhappy Ulysses, and keeps trying by every kind of blandishment to make him forget his home, so that he is tired of life, and thinks of nothing but how he may once more see the smoke of his own chimneys. You, sir, take no heed of this, and yet when Ulysses was before Troy did he not propitiate you with many a burnt sacrifice? Why then should you keep on being so angry with him?" And Jove said, "My child, what are you talking about? How can I forget Ulysses than whom there is no more capable man on earth, nor more liberal in his offerings to the immortal gods that live in heaven? Bear in mind, however, that Neptune is still furious with Ulysses for having blinded an eye of Polyphemus king of the Cyclopes. Polyphemus is son to Neptune by the nymph Thoosa, daughter to the sea-king Phorcys; therefore though he will not kill Ulysses outright, he torments him by preventing him from getting home. Still, let us lay our heads together and see how we can help him to return; Neptune will then be pacified, for if we are all of a mind he can hardly stand out against us." And Minerva said, "Father, son of Saturn, King of kings, if, then, the gods now mean that Ulysses should get home, we should first send Mercury to the Ogygian island to tell Calypso that we have made up our minds and that he is to return. In the meantime I will go to Ithaca, to put heart into Ulysses' son Telemachus; I will embolden him to call the Achaeans in assembly, and speak out to the suitors of his mother Penelope, who persist in eating up any number of his sheep and oxen; I will also conduct him to Sparta and to Pylos, to see if he can hear anything about the return of his dear father--for this will make people speak well of him." Ellipsis ellipsis ellipsis ellipsis ellipsis ellipsis ellipsis ellipsis. Ellipsis ellipsis ellipsis ellipsis ellipsis ellipsis ellipsis ellipsis. Ellipsis ellipsis ellipsis ellipsis ellipsis ellipsis ellipsis ellipsis. Ellipsis ellipsis ellipsis ellipsis ellipsis ellipsis ellipsis ellipsis. Ellipsis ellipsis ellipsis ellipsis ellipsis ellipsis ellipsis ellipsis. Ellipsis ellipsis ellipsis ellipsis ellipsis ellipsis ellipsis ellipsis. Ellipsis ellipsis ellipsis ellipsis ellipsis ellipsis ellipsis ellipsis. Ellipsis ellipsis ellipsis ellipsis ellipsis ellipsis ellipsis ellipsis. Ellipsis ellipsis ellipsis ellipsis ellipsis ellipsis ellipsis ellipsis. "Men of Ithaca, it is all your own fault that things have turned out as they have; you would not listen to me, nor yet to Mentor, when we bade you check the folly of your sons who were doing much wrong in the wantonness of their hearts--wasting the substance and dishonouring the wife of a chieftain who they thought would not return. Now, however, let it be as I say, and do as I tell you. Do not go out against Ulysses, or you may find that you have been drawing down evil on your own heads." This was what he said, and more than half raised a loud shout, and at once left the assembly. But the rest stayed where they were, for the speech of Halitherses displeased them, and they sided with Eupeithes; they therefore hurried off for their armour, and when they had armed themselves, they met together in front of the city, and Eupeithes led them on in their folly. He thought he was going to avenge the murder of his son, whereas in truth he was never to return, but was himself to perish in his attempt. Then Minerva said to Jove, "Father, son of Saturn, king of kings, answer me this question--What do you propose to do? Will you set them fighting still further, or will you make peace between them?" And Jove answered, "My child, why should you ask me? Was it not by your own arrangement that Ulysses came home and took his revenge upon the suitors? Do whatever you like, but I will tell you what I think will be most reasonable arrangement. Now that Ulysses is revenged, let them swear to a solemn covenant, in virtue of which he shall continue to rule, while we cause the others to forgive and forget the massacre of their sons and brothers. Let them then all become friends as heretofore, and let peace and plenty reign." This was what Minerva was already eager to bring about, so down she darted from off the topmost summits of Olympus. Now when Laertes and the others had done dinner, Ulysses began by saying, "Some of you go out and see if they are not getting close up to us." So one of Dolius's sons went as he was bid. Standing on the threshold he could see them all quite near, and said to Ulysses, "Here they are, let us put on our armour at once." They put on their armour as fast as they could--that is to say Ulysses, his three men, and the six sons of Dolius. Laertes also and Dolius did the same--warriors by necessity in spite of their grey hair. When they had all put on their armour, they opened the gate and sallied forth, Ulysses leading the way. Then Jove's daughter Minerva came up to them, having assumed the form and voice of Mentor. Ulysses was glad when he saw her, and said to his son Telemachus, "Telemachus, now that you are about to fight in an engagement, which will show every man's mettle, be sure not to disgrace your ancestors, who were eminent for their strength and courage all the world over." "You say truly, my dear father," answered Telemachus, "and you shall see, if you will, that I am in no mind to disgrace your family." Laertes was delighted when he heard this. "Good heavens," he exclaimed, "what a day I am enjoying: I do indeed rejoice at it. My son and grandson are vying with one another in the matter of valour." On this Minerva came close up to him and said, "Son of Arceisius---best friend I have in the world--pray to the blue-eyed damsel, and to Jove her father; then poise your spear and hurl it." As she spoke she infused fresh vigour into him, and when he had prayed to her he poised his spear and hurled it. He hit Eupeithes' helmet, and the spear went right through it, for the helmet stayed it not, and his armour rang rattling round him as he fell heavily to the ground. Meantime Ulysses and his son fell upon the front line of the foe and smote them with their swords and spears; indeed, they would have killed every one of them, and prevented them from ever getting home again, only Minerva raised her voice aloud, and made every one pause. "Men of Ithaca," she cried, "cease this dreadful war, and settle the matter at once without further bloodshed." On this pale fear seized every one; they were so frightened that their arms dropped from their hands and fell upon the ground at the sound of the goddess' voice, and they fled back to the city for their lives. But Ulysses gave a great cry, and gathering himself together swooped down like a soaring eagle. Then the son of Saturn sent a thunderbolt of fire that fell just in front of Minerva, so she said to Ulysses, "Ulysses, noble son of Laertes, stop this warful strife, or Jove will be angry with you." Thus spoke Minerva, and Ulysses obeyed her gladly. Then Minerva assumed the form and voice of Mentor, and presently made a covenant of peace between the two contending parties. ---------------------------------------------------------------------- Copyright statement: This text is in the public domain and has been modified by ReportLab. The source of the text specifies that all references to them must be removed if the text is distributed in modified form, so we cannot mention them here. They are credited in the 00readme.txt. This modified form of the text remains in the public domain. No copyright is asserted. To really test that reportlab can produce pages quickly download the complete version of the test from ftp://ftp.reportlab.com/odyssey.full.zip and copy it to this directory as odyssey.full.txt. ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707393948.3385587 reportlab-4.1.0/demos/rlzope/0000775000175000017500000000000014561141634015531 5ustar00rptlabrptlab././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1691062242.0 reportlab-4.1.0/demos/rlzope/readme.txt0000664000175000017500000000475214462707742017547 0ustar00rptlabrptlab# rlzope : an external Zope method to show people how to use # the ReportLab toolkit from within Zope. # # this method searches an image named 'logo' in the # ZODB then prints it at the top of a simple PDF # document made with ReportLab # # the resulting PDF document is returned to the # user's web browser and, if possible, it is # simultaneously saved into the ZODB. # # this method illustrates how to use both the platypus # and canvas frameworks. # # License : The ReportLab Toolkit's license (similar to BSD) # # Author : Jerome Alet - alet@librelogiciel.com # Installation instructions : =========================== 0 - If not installed then install Zope. 1 - Install reportlab in the Zope/lib/python/Shared directory by unpacking the tarball and putting a reportlabs.pth file in site-packages for the Zope used with Python. The path value in the reportlabs.pth file must be relative. For a typical Zope installation, the path is "../../python/Shared". Remember to restart Zope so the new path is instantiated. 2 - Install PIL in the Zope/lib/python/Shared directory. You need to ensure that the _imaging.so or .pyd is also installed appropriately. It should be compatible with the python running the zope site. 3 - Copy rlzope.py to your Zope installation's "Extensions" subdirectory, e.g. /var/lib/zope/Extensions/ under Debian GNU/Linux. 4 - From within Zope's management interface, add an External Method with these parameters : Id : rlzope Title : rlzope Module Name : rlzope Function Name : rlzope 5 - From within Zope's management interface, add an image called "logo" in the same Folder than rlzope, or somewhere above in the Folder hierarchy. For example you can use ReportLab's logo which you can find in reportlab/docs/images/replogo.gif 6 - Point your web browser to rlzope, e.g. on my laptop under Debian GNU/Linux : http://localhost:9673/rlzope This will send a simple PDF document named 'dummy.pdf' to your web browser, and if possible save it as a File object in the Zope Object DataBase, with this name. Note, however, that if an object with the same name already exists then it won't be replaced for security reasons. You can optionally add a parameter called 'name' with a filename as the value, to specify another filename, e.g. : logo http://localhost:9673/rlzope?name=sample.pdf 7 - Adapt it to your own needs. 8 - Enjoy ! Send comments or bug reports at : alet@librelogiciel.com ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1691062242.0 reportlab-4.1.0/demos/rlzope/rlzope.py0000664000175000017500000001520714462707742017433 0ustar00rptlabrptlab# # Using the ReportLab toolkit from within Zope # # WARNING : The MyPDFDoc class deals with ReportLab's platypus framework, # while the MyPageTemplate class directly deals with ReportLab's # canvas, this way you know how to do with both... # # License : the ReportLab Toolkit's one # see : http://www.reportlab.com # # Author : Jerome Alet - alet@librelogiciel.com # # from io import BytesIO try : from Shared.reportlab.platypus.paragraph import Paragraph from Shared.reportlab.platypus.doctemplate import * from Shared.reportlab.lib.units import inch from Shared.reportlab.lib import styles from Shared.reportlab.lib.utils import ImageReader except ImportError : from reportlab.platypus.paragraph import Paragraph from reportlab.platypus.doctemplate import * from reportlab.lib.units import inch from reportlab.lib import styles from reportlab.lib.utils import ImageReader class MyPDFDoc : class MyPageTemplate(PageTemplate) : """Our own page template.""" def __init__(self, parent) : """Initialise our page template.""" # # we must save a pointer to our parent somewhere self.parent = parent # Our doc is made of a single frame content = Frame(0.75 * inch, 0.5 * inch, parent.document.pagesize[0] - 1.25 * inch, parent.document.pagesize[1] - (1.5 * inch)) PageTemplate.__init__(self, "MyTemplate", [content]) # get all the images we need now, in case we've got # several pages this will save some CPU self.logo = self.getImageFromZODB("logo") def getImageFromZODB(self, name) : """Retrieves an Image from the ZODB, converts it to PIL, and makes it 0.75 inch high. """ try : # try to get it from ZODB logo = getattr(self.parent.context, name) except AttributeError : # not found ! return None # Convert it to PIL image = ImageReader(BytesIO(logo.data)) (width, height) = image.getSize() # scale it to be 0.75 inch high multi = ((height + 0.0) / (0.75 * inch)) width = int(width / multi) height = int(height / multi) return ((width, height), image) def beforeDrawPage(self, canvas, doc) : """Draws a logo and an contribution message on each page.""" canvas.saveState() if self.logo is not None : # draws the logo if it exists ((width, height), image) = self.logo canvas.drawImage(image, inch, doc.pagesize[1] - inch, width, height) canvas.setFont('Times-Roman', 10) canvas.drawCentredString(inch + (doc.pagesize[0] - (1.5 * inch)) / 2, 0.25 * inch, "Contributed by Jerome Alet - alet@librelogiciel.com") canvas.restoreState() def __init__(self, context, filename) : # save some datas self.context = context self.built = 0 self.objects = [] # we will build an in-memory document # instead of creating an on-disk file. self.report = BytesIO() # initialise a PDF document using ReportLab's platypus self.document = BaseDocTemplate(self.report) # add our page template # (we could add more than one, but I prefer to keep it simple) self.document.addPageTemplates(self.MyPageTemplate(self)) # get the default style sheets self.StyleSheet = styles.getSampleStyleSheet() # then build a simple doc with ReportLab's platypus sometext = "A sample script to show how to use ReportLab from within Zope" url = self.escapexml(context.absolute_url()) urlfilename = self.escapexml(context.absolute_url() + '/%s' % filename) self.append(Paragraph("Using ReportLab from within Zope", self.StyleSheet["Heading3"])) self.append(Spacer(0, 10)) self.append(Paragraph("You launched it from : %s" % url, self.StyleSheet['Normal'])) self.append(Spacer(0, 40)) self.append(Paragraph("If possible, this report will be automatically saved as : %s" % urlfilename, self.StyleSheet['Normal'])) # generation du document PDF self.document.build(self.objects) self.built = 1 def __str__(self) : """Returns the PDF document as a string of text, or None if it's not ready yet.""" if self.built : return self.report.getvalue() else : return None def append(self, object) : """Appends an object to our platypus "story" (using ReportLab's terminology).""" self.objects.append(object) def escapexml(self, s) : """Escape some xml entities.""" s = s.strip() s = s.replace("&", "&") s = s.replace("<", "<") return s.replace(">", ">") def rlzope(self) : """A sample external method to show people how to use ReportLab from within Zope.""" try: # # which file/object name to use ? # append ?name=xxxxx to rlzope's url to # choose another name filename = self.REQUEST.get("name", "dummy.pdf") if filename[-4:] != '.pdf' : filename = filename + '.pdf' # tell the browser we send some PDF document # with the requested filename # get the document's content itself as a string of text content = str(MyPDFDoc(self, filename)) # we will return it to the browser, but before that we also want to # save it into the ZODB into the current folder try : self.manage_addFile(id = filename, file = content, title = "A sample PDF document produced with ReportLab", precondition = '', content_type = "application/pdf") except : # it seems an object with this name already exists in the ZODB: # it's more secure to not replace it, since we could possibly # destroy an important PDF document of this name. pass self.REQUEST.RESPONSE.setHeader('Content-Type', 'application/pdf') self.REQUEST.RESPONSE.setHeader('Content-Disposition', 'attachment; filename=%s' % filename) except: import traceback, sys, cgi content = sys.stdout = sys.stderr = BytesIO() self.REQUEST.RESPONSE.setHeader('Content-Type', 'text/html') traceback.print_exc() sys.stdout = sys.__stdout__ sys.stderr = sys.__stderr__ content = '
%s
' % cgi.escape(content.getvalue()) # then we also return the PDF content to the browser return content ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707393948.3385587 reportlab-4.1.0/demos/stdfonts/0000775000175000017500000000000014561141634016062 5ustar00rptlabrptlab././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1691062242.0 reportlab-4.1.0/demos/stdfonts/00readme.txt0000664000175000017500000000034514462707742020232 0ustar00rptlabrptlabThis lists out the standard 14 fonts in a very plain and simple fashion. Notably, the output is huge - it makes two separate text objects for each glyph. Smarter programming would make tighter PDF, but more lines of Python! ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1691062242.0 reportlab-4.1.0/demos/stdfonts/stdfonts.py0000664000175000017500000000451514462707742020315 0ustar00rptlabrptlab#Copyright ReportLab Europe Ltd. 2000-2017 #see license.txt for license details __doc__=""" This generates tables showing the 14 standard fonts in both WinAnsi and MacRoman encodings, and their character codes. Supply an argument of 'hex' or 'oct' to get code charts in those encodings; octal is what you need for \\n escape sequences in Python literals. usage: standardfonts.py [dec|hex|oct] """ __version__='3.3.0' import sys from reportlab.pdfbase import pdfmetrics from reportlab.pdfgen import canvas import string label_formats = {'dec':('%d=', 'Decimal'), 'oct':('%o=','Octal'), 'hex':('0x%x=', 'Hexadecimal')} def run(mode): label_formatter, caption = label_formats[mode] for enc in ['MacRoman', 'WinAnsi']: canv = canvas.Canvas( 'StandardFonts_%s.pdf' % enc, ) canv.setPageCompression(0) for faceName in pdfmetrics.standardFonts: if faceName in ['Symbol', 'ZapfDingbats']: encLabel = faceName+'Encoding' else: encLabel = enc + 'Encoding' fontName = faceName + '-' + encLabel pdfmetrics.registerFont(pdfmetrics.Font(fontName, faceName, encLabel) ) canv.setFont('Times-Bold', 18) canv.drawString(80, 744, fontName) canv.setFont('Times-BoldItalic', 12) canv.drawRightString(515, 744, 'Labels in ' + caption) #for dingbats, we need to use another font for the numbers. #do two parallel text objects. for byt in range(32, 256): col, row = divmod(byt - 32, 32) x = 72 + (66*col) y = 720 - (18*row) canv.setFont('Helvetica', 14) canv.drawString(x, y, label_formatter % byt) canv.setFont(fontName, 14) canv.drawString(x+44, y, chr(byt).decode(encLabel,'ignore').encode('utf8')) canv.showPage() canv.save() if __name__ == '__main__': if len(sys.argv)==2: mode = string.lower(sys.argv[1]) if mode not in ['dec','oct','hex']: print(__doc__) elif len(sys.argv) == 1: mode = 'dec' run(mode) else: print(__doc__) ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707393948.3385587 reportlab-4.1.0/demos/tests/0000775000175000017500000000000014561141634015360 5ustar00rptlabrptlab././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1691062242.0 reportlab-4.1.0/demos/tests/testdemos.py0000664000175000017500000000101514462707742017746 0ustar00rptlabrptlab#!/bin/env python #Copyright ReportLab Europe Ltd. 2000-2017 #see license.txt for license details __doc__='Test all demos' __version__='3.3.0' _globals=globals().copy() import os, sys from reportlab import pdfgen for p in ('pythonpoint/pythonpoint.py','stdfonts/stdfonts.py','odyssey/odyssey.py', 'gadflypaper/gfe.py'): fn = os.path.normcase(os.path.normpath(os.path.join(os.path.dirname(pdfgen.__file__),'..','demos',p))) os.chdir(os.path.dirname(fn)) exec(compile(open(fn).read(), fn, 'exec'),_globals.copy()) ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707393948.3385587 reportlab-4.1.0/docs/0000775000175000017500000000000014561141634014037 5ustar00rptlabrptlab././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1691062243.0 reportlab-4.1.0/docs/00readme.txt0000664000175000017500000000047114462707743016210 0ustar00rptlabrptlabThid directory holds documentation. For end users, it should contain a number of PDF manuals. For people working with the source, this directory will be the destination for any manuals built. If you don't see the pdf manual you expected or you wich to ensure an up to date copy run the script tools/genAll.py! ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1691062243.0 reportlab-4.1.0/docs/Makefile0000664000175000017500000000610014462707743015505 0ustar00rptlabrptlab# Makefile for Sphinx documentation # # You can set these variables from the command line. SPHINXOPTS = SPHINXBUILD = sphinx-build PAPER = BUILDDIR = build # Internal variables. PAPEROPT_a4 = -D latex_paper_size=a4 PAPEROPT_letter = -D latex_paper_size=letter ALLSPHINXOPTS = -d $(BUILDDIR)/doctrees $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) source .PHONY: help clean html dirhtml pickle json htmlhelp qthelp latex changes linkcheck doctest help: @echo "Please use \`make ' where is one of" @echo " html to make standalone HTML files" @echo " dirhtml to make HTML files named index.html in directories" @echo " pickle to make pickle files" @echo " json to make JSON files" @echo " htmlhelp to make HTML files and a HTML help project" @echo " qthelp to make HTML files and a qthelp project" @echo " latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter" @echo " changes to make an overview of all changed/added/deprecated items" @echo " linkcheck to check all external links for integrity" @echo " doctest to run all doctests embedded in the documentation (if enabled)" clean: -rm -rf $(BUILDDIR)/* html: $(SPHINXBUILD) -b html $(ALLSPHINXOPTS) $(BUILDDIR)/html @echo @echo "Build finished. The HTML pages are in $(BUILDDIR)/html." dirhtml: $(SPHINXBUILD) -b dirhtml $(ALLSPHINXOPTS) $(BUILDDIR)/dirhtml @echo @echo "Build finished. The HTML pages are in $(BUILDDIR)/dirhtml." pickle: $(SPHINXBUILD) -b pickle $(ALLSPHINXOPTS) $(BUILDDIR)/pickle @echo @echo "Build finished; now you can process the pickle files." json: $(SPHINXBUILD) -b json $(ALLSPHINXOPTS) $(BUILDDIR)/json @echo @echo "Build finished; now you can process the JSON files." htmlhelp: $(SPHINXBUILD) -b htmlhelp $(ALLSPHINXOPTS) $(BUILDDIR)/htmlhelp @echo @echo "Build finished; now you can run HTML Help Workshop with the" \ ".hhp project file in $(BUILDDIR)/htmlhelp." qthelp: $(SPHINXBUILD) -b qthelp $(ALLSPHINXOPTS) $(BUILDDIR)/qthelp @echo @echo "Build finished; now you can run "qcollectiongenerator" with the" \ ".qhcp project file in $(BUILDDIR)/qthelp, like this:" @echo "# qcollectiongenerator $(BUILDDIR)/qthelp/reportlab.qhcp" @echo "To view the help file:" @echo "# assistant -collectionFile $(BUILDDIR)/qthelp/reportlab.qhc" latex: $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex @echo @echo "Build finished; the LaTeX files are in $(BUILDDIR)/latex." @echo "Run \`make all-pdf' or \`make all-ps' in that directory to" \ "run these through (pdf)latex." changes: $(SPHINXBUILD) -b changes $(ALLSPHINXOPTS) $(BUILDDIR)/changes @echo @echo "The overview file is in $(BUILDDIR)/changes." linkcheck: $(SPHINXBUILD) -b linkcheck $(ALLSPHINXOPTS) $(BUILDDIR)/linkcheck @echo @echo "Link check complete; look for any errors in the above output " \ "or in $(BUILDDIR)/linkcheck/output.txt." doctest: $(SPHINXBUILD) -b doctest $(ALLSPHINXOPTS) $(BUILDDIR)/doctest @echo "Testing of doctests in the sources finished, look at the " \ "results in $(BUILDDIR)/doctest/output.txt." ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1691062243.0 reportlab-4.1.0/docs/genAll.py0000775000175000017500000000273114462707743015632 0ustar00rptlabrptlab#!/bin/env python import os, sys, traceback def _genAll(verbose=1): from reportlab.lib.testutils import setOutDir setOutDir(__name__) from reportlab.lib.testutils import testsFolder topDir=os.path.dirname(testsFolder) L = [os.path.join(topDir,f) for f in ( #'docs/reference/genreference.py', 'docs/userguide/genuserguide.py', #'tools/docco/graphdocpy.py', ) ] for f in ('src/rl_addons/pyRXP/docs/PyRXP_Documentation.rml', ): f = os.path.join(topDir,f) if os.path.isfile(f): L += [f] break for p in L: os.chdir(os.path.dirname(p)) if p[-4:]=='.rml': try: from rlextra.rml2pdf.rml2pdf import main main(exe=0,fn=[os.path.basename(p)], quiet=not verbose, outDir=d) except: if verbose: traceback.print_exc() else: cmd = '"%s" %s %s' % (sys.executable,os.path.basename(p), not verbose and '-s' or '') if verbose: print(cmd) os.system(cmd) """Runs the manual-building scripts""" if __name__=='__main__': #need a quiet mode for the test suite if '-s' in sys.argv: # 'silent verbose = 0 else: verbose = 1 d = os.path.dirname(sys.argv[0]) if not d: d = os.getcwd() elif not os.path.isabs(d): d = os.path.abspath(d) sys.path.insert(0,os.path.dirname(d)) _genAll(verbose) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1691062243.0 reportlab-4.1.0/docs/gen_epydoc0000775000175000017500000000021714462707743016112 0ustar00rptlabrptlab#!/bin/sh d=`dirname $0` [ x$d = x ] && d=`pwd` export PYTHONPATH=$d/../src epydoc --html reportlab --docformat=restructuredtext --no-private ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707393948.3425586 reportlab-4.1.0/docs/images/0000775000175000017500000000000014561141634015304 5ustar00rptlabrptlab././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1691062243.0 reportlab-4.1.0/docs/images/Edit_Prefs.gif0000664000175000017500000002272514462707743020040 0ustar00rptlabrptlabGIF89a>{f3̙f3f3ffffff3f3333f333f3f3̙f3̙̙̙̙f̙3̙ffffff3f3333f333f3̙f3̙̙f3̙f3ff̙ffff3f33̙33f333̙f3ffffff3ffff̙fff3fffffff3ffffffffffff3fff3f3f3f3ff33f3ffffff3f3333f333333̙3f3333333f3333f3f3f3ff3f33f33333333f333333333f333f3̙f3f3ffffff3f3333f333f3wUD"wUD"wUD"ݻwwwUUUDDD""",>{G HGp#JH"EX3f# Ңɓ(S|ر˖+cL?ۙիׯ~C }PJJիXjʵׯ`ÊKYN|ٷpʝKݻXӮ7߿ LÈ Wǐ#KL˘3k̹sA+6޼?+T5WmOo]7oAwou"?wrװ=K>aou ӫ_}wP|Ͽ'Z~h&i&qkm҄YX>gwHraoE@ d" EυbH'H4f#Ћ5!+y">衎K"ə`ddBN^'ץq $pۉ\phdq%qJ> gF2 e}F#3y$:as|xhdfޘY1d驨ꪬ꫰*무j뭸Z*BZYK?jEC&,F -RB,bfܪϮ ([m覫+,jkBo {HV - ^Jc6lgYYk0+Z!% Ģ7C:\DqkjL7-~K$5].C]RC3cp{tWSrx筷as[Y#+;3k8؈]8H/|6kls(4ZD29|9󻷷U$/[WԷux[Ϙ'^Ϲ }9k^z[$k#VǟMǎlxڇ_X3=B߶>u :Gl]k>cqO k_'Ƒ]j'+w+mf3zSg ɻ)ArWۡb /=F}mWBQ1-ؿ$1taL8zYEIz6kW81xD2!K?*"LW1t/6G?Q!w&7:э1dFIRL*WV򕰌,gIZLH%S%''\c,׏H uΑ"uQQ=)mUqԣp¦6ʐP8)uP@ jB{*Ԣ QP POT\b"5i+lNdp9Fߤ/us3fM*Hzֺ^節 `KMb:ld Xͬf7z hGKҚMhX٦嵰lgK%Xͭnw j?yYPpqԣ(@[Arz! mf6Z(姖Ӛ IDE᩽]ԃX_GGLJGC13C|1ɝ'S3o5S (~CP&dR&;/jqgӂxK+fg_,_s%=L"w1s̀iRiѬby_r5e;ayJ?49a |I!{V8׺B~A> !&H& h=V "FgQ~6MFwGhCb~-6ݹوQ3 ZH45Q]i`;|/ߨ^=ZG"ⱋlY뺝Q417mg[!u"[MoXᲘVZMuk6[{e?C[Lw|[\{_vGX 5 `n?}z3K}l~W[ޝޡɛ8p=cCdw]l7p.cod8ײ~񞿼Rc#]aNɵVg[Qu>;׷ɸnZȳ40.u§+>Ȣ!9wʥswێEd{x +7֧i?B >Qwl-M^N~rve1)eO\h.WϾ{}O OYqBJgot|jvo|Gf85}FWjuՀU}2wQuU(T~~ !(#(TV)8bLV3(e5S%h jK$hM O;9 ;x G]+PJUQXSB3`b8Qq[ldjlfZnцr8tHo(\xz|؇~hYj8XxfhP8O(vh^T_6cB|,%#)fh""Q^R#(XtV֡Mo Q6dL66&$ʔJ&MWfgv6pp ufUNc%P7e(`֎ шxb92yAGgre} r|Ec顐I6eLhs‘HƗAffaVx] Iӈ37aq3R#_!`U!/|FR1)/&zdv_{LbRLi&M0%!$`{8zLД$]gp nٕMWbL)5зgLbZ.b1ɒg`uB敏Q9$?ٙBqf0#QVvYHi-_%Ly^Rd9iɕYiuVyJrJyxdW-V!6/E/303s6vV-D@ǝ-!G9$3<\rYjɹA;o6ډt39Al!!giGYSv :D}T2y9:3:vaG%7Gt Q )#2 6nfx&4*J[C3 zANE_ c=ђ69 7;פRjOm=Z6z22 j, Zo]kEfJqSJ(z*#1z/3J05 qyHhJmhu5֖Ux٩B v;SGJ0~1A2pڢ[Qr/٧x'h YZoF 5H,:m*C([ZǮJgWHҥ}G#fDoGlipʞ6_¬PׇЪu_7o zGw4'DjnzJ13lvb$ICZ [F>'ykZɪʭ@;=ꥴ*Jz;p8:fnb"y,sfkHkΪr[SJg]7JhM.{<0ˠұ5B.mL:VymäEE4s&kڷL6P+36[?gt+4k vz*,$kwf",vZ9moKD{i# 3#˻F`D2k6  a괤;,Q;Kk[t{1{w >5Ú/ڻ˸|&W2+ʒrt7JCD+۫JW[3紏{óxzc+I;KX'ܪ[{9{brhGne;CVGy;5W!zD¬n8xs~x WZKD.,/ԝkÃC*B3 =G+7|B|@v˥ PK^;Bʸ o_<+flYj@8A^F~H[j^NPR>T^V~XZ\^`b{Afbl~nrt^u]]Uf!-ҕq)͕QKD!؜l=' "}: 190\|>ő!э8hab mTь^i |{$uQЍP՛]=-fΘLym&NN`EݮWfٸk¸)> f`P+`8Ve_xTzΎRH9oy9 ߁"?X&z(k,od42a1ϗXBLc2e.|NeI/"")L%<=XeKUh5 h&ImbQma-|~chbm~vގ!eAN1%]UyDI5?/&N+ CT(@S4XY^2aq>NUO σMjAar/48?MY]Oҭ.cr鍍iuЦ^biX/v6I)Ϟ D8pE~ "|? RcD b(1dH +nDqJ)[,̏ZIG,E ʾ gA|7W=0=Zq9VR:DHK5 WgD벬θoNvbݖ|RjW`C%4Ą/nY2@3jYfΝFFZ> d[ΤMƝ[n޽}+pōtd@͝?]tխ_Ǟ]vݽ^tDK ܼ4ݿ_|ǟ_~0@iÖkL=A0B '?1<SpdO+|HD1EW oj!+j@{qAYaaI'2>G3V JR0"$sH/$=<3J7߄)E"m z bM M4{$4ˌ3QEoNH=\ptA zIFOEQG"m;˳RDL}R5W7W-JIM]%XyH9:4YgY{1Nߣ5N ep2T3\1y\SMtSNWUpUՒ{R݁EX$5=3B 7]}qG> ^vn̏YӞ "\86Zr_6@ yn|U7=zT=X 2U0NxB?\.s6B֪~Ӻ Ӻgޡ-l=8,Ƕlz˒tF;#rQ&h8ǯ]1ncFx{"RlBx <~Ep /4N3\ uCdZ(E]RJ:?1tF<+:&JwO19MiNxta.%9;{G0ajK $F]oA"XKi͂eӖ@'PV'RerLd&ԡZHPQ] s46" D)AH*._e% 9/}~d?FJ- X Ou:.< -7K֝q¥;ѳ Cj K1 F '>ɴF4MPebЂ,v`n,HO?I [bϼ ʣ5&׷ܶt~{.Xk"\1fTֹaitO*Y>ĺwu<.f\TyUHNX_oҷL]~׿Fm*Z f\eOQAرG" 7 h33͖*cx]5:2`HVQuꊍz+-(muMZZ}#9EYt;_%jӶ(BSV󧲬_&u/+sV3b͂._uTtCJ|&=M g7 {{p95m/!i# <8stRԴ-a2̔4d9O|)Uy~mmJ\#R:q W>{ZQ#-\n|gt^ kBeg]: o7k|x ^UGW}WNw7zp3r\惊9)f^N)|O~-SO?|G_t4χ>(~}w?~IC3wo=~1k e0?0؈ 뛉@{?ȍ @! ?@D@  1 |A! きDPA!п ? H)|žP@p * 3,þh%Ȭ  p /|C;L5Ĉ0A0?,DhC&Aj9|pBD{ B-t!B@[QD"5pq$rDtTG utwG }x{Ǡ zC|Ȁ,X?slsȅdȸ&4~䍇 ,Ȁ˘ lHxF< 5 -B;Ԉ{ lH ȽC?IItaHDPC艱ZȄđpʙ0dZD$Jaǣ ɽqKCI Jd @ F(ʰ䒤Đ$GTL( qp?h$4DTMڴ?$IzdG$DNGLtX|ά:ԌNÔNDπdO\|OOɠ#DHG|DpzH3o ώXMɤ|E͘m+ILLD\E.LEP C ݌Ռ"$D F}!eN T=͍,T;TA]SDTިHT JLTNUIMP%UREUXiVuWXYZ[\]^_`aU\cEdUeef;z!clip2gif 0.7.2 by Yves Piguet;././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1691062243.0 reportlab-4.1.0/docs/images/Python_21.gif0000664000175000017500000006671214462707743017603 0ustar00rptlabrptlabGIF87aGv!)!!))J!B1!c!k!{!!!)!!!!B!))!)J)Z))R))c)kB11111k111!11)B11)19J19k1{R999!9)!9)19)Z9)k91{99199J999ZJ9sRBB!{B)sB1B9BB9cBB{BBBJcBJ{BZRBcRB{ZJJ!ZJ1JB1JB{JBJJBJJRJJJJJJJRR)R19R9R9RJ1RJcRRRZRRZkRccRskZRkZRZRZRZRZZZZcc1c9cBcRcRcRccccccccccckBkBkJkZkZRkZkkckkkkk{kskssJksJsZ1sZJsZsccskZsksksksscssss{s{B{R!{R{R{Zc{cJ{ck{kJ{kc{sk{s{{s{s{s{{k{{{{{{{s{{ք焄ƥksJsksƌsss{R{sƔ֔ޜΜޜΥޥ1sΥ޵J֭cε޵ֵֵ絵޽RƜƭƭƵƽΥsνֵ֭sֵֽcs!,Gv@ZWlڮuĦEK0ffFŋ3jȱǏNSm$:h6X(MSˑ͎Ț"y,LbҶIs)m״rNGJU#IڼP z-٬u drߺPQڥ޽RKo~Ífx2€)KW+]pJ?wC"`$5 Grv9 @W~˶./wc 0-_9i#ͧG=lr^P%WDCH$Q`9Pp4(8 gsSUrj"p"rX"'V4x=%b0C9*x"^>G΋$M%:48"D^^)ָA:i<>)eJڈ%\~h!DNcW4$6f#jÏ]g>rS>oCnxgY9(?}*碍*꧛wɧHӏ#cg3!]l:E%4xJi&J]f$*l -#g^L#^D&\?㏂bgD?عWg衁"g}yyΫn"-Hp9 Zkaع'ɰYhx~iFr;P𛛺Nʒ:n{/pl罄ț[ÏVLi!-:]L(S>t + r#tmx|1lH&Ґ`m7?R?H" R78>Ls?ηHX?fSDn<[Ɩlxo:|S駫Z% fק=;#./Nw{_#1es?;]QgTkЙ9 !f (v6FqEHИu@]Z688 RKhG&ve%6LH1?AaacXĸ3HE (ļAp{ 9>wlCC_IB[8 ^,ha'DZqD.%X ‚d1$@re!wAX rY8tJ,[bd, Is0C7<|;WVr 4HPGwRH 3tXjAOԜ枧yF/v~HSpt|gIJSZ7=(BONWX}S`C#Wo@pF81pҏ0+v>r2mѢ/ d&T-HRTEULiU7JkquP qf?@UnMG @<[jdW uOqe Cg?*vs&Kud!((]8nD, ei%;F6pmC{7u(E%ĎhP@feyiNG2QE`PE&ju-c;uxuiJ:glbXoW Sȸ]b_PTO&w4.nI8jR;uS]]Wo +ZRnܦ2~* EQc6?Ab;}f^n9U" !;B>"x!D9B/cDvg(lVlKt|cظVБo#zu+xyX6qFV[6 bCcrnb4PщTq(@*Ra ks@BT߷N2Up:=qs@06 ]7*%x Kx(-Ag#]✠EvpD퀁(,0LOlc$=;`ߠ7nQ qF,=[p#pS:H-C$UL20;mR34e\b %o4cstƹuHjK<n- 9Lrya{ 9rpGL9T Z懃Zk$9W Fq@>xUzwFC^xj [[@ @ i Pd i@@TXOaO Qd`BrD  İppCLru&Mg-R' hF)>H=` ޣ h0V `d0_` uR M%@WvC&q@ àxRE iWhv(  8y 8DT@!(w7d"&E#C#rNM:Pmy?H(`)yq+ze;@PxؕzMdٸ6x~Ń+8_}2Pv Te9@ T9)e iP~ ax88 hP iπ2qT|ُ } vibIs [p p `T9DǍ[ :` ȸ >ri^97 iR>`t8P `Ǩ x^c9 ΐȝ <@ПzI f ""Ж%9p t0 3 :#0 ]4'ZR u &eT +^RtӤ ݠ1@f 8` t@ ^3JA HW`ÕrFr  s 0:@dې pC\'  ]p!sG@++j;d?99aH_Ys`Ur&2]6~p,1#68L/K15/1d|b/Q' j'K-(E. p ~j^+~0 jES-@n;עr,us(f` 0}L-9uH ,$Eý(26/;1,[(]$BƎ0NSG' `y}ь^ăH`=`Z`Z@%jV#`W$Sn^fPHgz_AY \ ᣍEw?:0S@0c`YPKsit ^0]:Ypvrmfmpqwz3'<'ay~F`m5Ubw; ~6j`ΔtwF\8a'D9 A$pp98I *$OvA9|,[$cx&`a g ^DBrcF}j8 ؐ7MF_ӏyKә3PZJmA` t 9*{Au& ĩ p ` ځ}4t,ِ%??w;thc iʈOIR3ٜJ Z>@Cq5C #ghh > uPgWS%>POOH /}7N6p  @q6'&/.7EvD"@1M@d`p0d=D$ D澔#0@6,nI4ӏs4PDf-R8ԍv ":F0 AzqGm~M6e@ y爞H4ݘx}CZ[XՑ.Cf*nt=iGشY9H980!` @%  Xuw趌[vm ٔ@\ H sP 7p~<άa\Li \}G8Hq|,$9Y=(HxOE] qf;@x<7TbDu8RxgP2(Fc~X": 8e.# c+_[Q#p` x &,IPcrL0գe7( ՏNAT䰋~X)^E/ԁF]㏨A7,[b2B$ OQK[Ჹc P?Rb0sPcTt']LL& 0?*4TC 1@bAS!EGTBց3HLnʄ>9\)N92 (1HY6~ @(G)AMCX*(-6ԡhD%:QVԢhF5QRtzrh4v7R}=1 e(cbd,0iLe:SԦ7h? Z&HS2<N;F>y̔BZVիeYWb'@Np B^5`J%JVVWT!$%.[jg=ZEmj={Zі6uhe תֵm?[ע-m[ղM-fI e`90F|N=TO⇞J-񖗼ozͫ^׽/{^v=t~hWI ۧB?I}2)J𒷼p kE{ؼepl㵯Iíg9 W'X9Ѱf4EF h(Lv2&OYK2e*oVB,h4 ʝnޔ<'kI&5,Zɮ>Kj4aC>*W9L \G4P`5uH).(`2GH %/STng{o[w-uٞ2;Q vc`+lаvC;x>: "=TI5 [DH@^PSA$dt>vuf7Սr%x9*T<$I:8Tb]:zCX^*nw<{zֳnV׽wC.NA&la : fb6?^;~c;/F4m+VyyO6]E:}q5 m5rx}9\]~=i/ֿ>>Gs/|~ĐeMofu}^Z5A ɻ1OY?ېiziLп6nO'C>l>+?;@i?5eci ɇ9H< úúlA\D{1}A SA9l$R!yA " ۻ0@:*D%4k”J1A+[63TA6LA9lAB<%|C2;T' zikB.$/3B.DId:4- 0>Ot/qʒ~=)ȇ^(h@h iHDih|bu}ѹ]E xX@xr //Їh` z1H|r@L‘/G0kc:$DyKIE{DHDI$ ۰}<1| $0DB{D< 3͘!׬۱К5R )c>Yv9Qۭŋw])U@K -\'`[*0SP Yw f [ }}@xw@dA@w5ÚxZlZXia 4@^-^/vHZPmW\y\WUH0 (dXL GmCYƠ7D]M4KvEZ8^' }͇#]=at`\zvzFJ WZ ߯&Gt^L:Q[Zqiq% JH&EޛU^vظljƉ~d 14? $$:^7-N$09>S@50~@ M$2MJ(MՈp*   =%[흈p)ػr k੅hEwuh0" U9$ .x ؃0*Fm a*^bhT\S"MδiVfE7l x䶕E(VDf: BwPFeYÎ %Ygh@ йX$@UF G \d옆@l@1@% iCFfp)c<uP6&uVzp$0O`㢖jM\$%чTBΌN^ ([k궶3mp䨆k?b# 6f" {(xG5o&k ^deq޻kNxpI(F.\&yi3NDPE]E e&LfP$Hlx(zr^Th ʒ0';ZS} /@m^hcE)ȃlz|9]Z%'Yܻԡ[t22rk] Oy0uQ^Tr菊`MP &5эk≈]؅FRQ#rVVö"[ۈ5 m ]hb3r!U T>fr@c =1 XkaVh Vp] @m_ȪNxc^#~qq}9=m@Г<ۉXVPF}أ*t 9sfVvU_U%A{ d rK?\U<XPʁcP2VimĈؙ vZhcapv>䅘ו> kW }UnV ZiY"=wZMQ_9VoՆr&되Z^U ;T菂xwXYWʽVG4 i{g m(Zph x`Dtxuh+plP'ѦihXƘllz؀ƘkeToeu+<pov/pui5=VP %6bO%mm(؈n^Sov((rWj@zzpƿf8u"pZ/j@Hug)vvg HJzꨆXxp``CqV@(x"PTZj|Fm@639"ƌ7r#Ȑ";Xrg:رbnYN7v=J=*ȠBz, !5>lpA 66E.DY(ذ!u|x AN N@Dw1~kغu/JTfRA[Ŭj#8$5lh{mȟA~D4r^Mg.q"Kb?Cߺ@(.H!)$wBOi ?$:ĠWk}YB Q \&!ep3#S?S?9@?oxK*RI0dRFiDPJrJ"9$odUX ZTBHVnrYde$FHpgr%ڒOif\tFlXeׇ~*(֚?#}2 Y\P`"::*T)4Їj]ϞZh㥧Z*?| 8DA |5:eeb:ja-ډ,`I3:讳Cb im*/F^4XO>9꬙V˥;vHѮJmĺ'htc*$@Ir_϶>GɌ|c!9iH* J?|8\ 8Ep J `Ԛ7#@:hr,F${7Edx! bwIuBQ":cxFpxFƠQr,&Y?p! 'I=G8NhJ3 h5`Q:&s.S"g̐* _|B#CINaJ94/GZLv Ŵh/@e) HE4A ncc4 UO݀zFg +ᐣ "8P"şE 4 WBưCAKġᴨ1zLtpǸBٛ;Ab8: B <3!44nڰ/TBiUgr`Ld@ 89BH$@G;$] KLQщ ь)z B_hB P9A棠I Ka0/Z02[ !y'5ԕaiPYaƖ#A1|Z&@+c%{L*i\>qF)b/Cq)LeJSn7"ةXOc X " = ".E?:CG9$ar?Ьn] ʄQhl)bh4 ;dpgSkd̴QN&]Y %8B_B>P1sP{wISpLghlC9 w= [WϞ4A:u첣-1w|1fk}I:uCF)z0[=Ze(5'%f1%LA3~)?䢂0&aW4XA%P q/.! N;z'ArDj LRⳊڋ3zIGp h")AItqG:N; 9-'uo|si$rJ" T]^yv—qIy@lo)7@|tSÙ/15х.0R '^ _M0!M;NOfsSS /{j0p>s}%L`H&18.LbFȀk^=1q ΕtQAF#]I'ߨfa60b@dBϼIA l4d` su0pL K04ѰE\D;AʁAr=& xA3H@pth?Å!eZI|)AĂA }-I ́qW8^@HkmWC)$܂l tE||-l&@tqVi F$?* L>٣E#d}uF{Pv8>TH,Õ,?C)@ VѮmT!͘HC9C46XxCP|cԈC\{E?B44G?_FH@i$AxMA{}?@?x>HCzA>H^)H.F>\IH@S  H-J).?C6  ?@| |Qi[f NAڬ%>̝|-!gW4GLjG6*GCC G1@z$NI:X?I]|hF4D49a9$1A?C&PCQ%R&R.%S6S>%TFTN%UBppU?\9tL)m4H4lG4P@KU%\ƥ\%]֥]V"N$|xg4Wa>Ѝ^ t̺H@WLC `cVޥdN&eVe^&Tj[&:&Ce>tp(.L9z:8%&b&nn&oo&pp'qq'r'\"*s\i *&ݜr^=3Nv:X#<#4#dBy>Bdg&8x#|g|'|:%dL&c $$8} dBd># `is*++&&;;X$DP~:VFN~+^^kwa>ꮺ+k++kҫj*az+ 4ZҸ$Aj 4p4L4lj,vzlƂȊlnlɢɆʒʦ,lV4Q :;3B)$t%jNNtkts|2@Ǯ4LIdžm~,َlٚl˞mښ-ۢھb6U`zTxetHClNe)ln. x4fUBj[db.iOp?x.^fnnvBned>%4Q9YCGP|D@ NH K@&~ <C<9墮~. ~fe/oo,NtV+!%&C4;nL'ź$_> B9,xXf+.gm+n^m"fgn0k0oK9`k:13 C@óKbU` @ꐇ4aC"+^L#ho0 /qsqcScÉ}`:H?́#S[D\Iuiۺ B$2zP"+#7"?2z8r$C2%&G$o%[&_">~BAmPa"k3!@N1o9:C^@4ҍC&k2"/2"[2(G4g'+532'W's572%4'@T6oT< HxxA?C@֒+34A3C!A/4C7C?4DGA+B#2.) (-?T ?óHGӞ>ܪ`MDwBCS4PtBOQC4fBt{%Pc)*4D=ަ +4YjXԎ5Z5[\[+Z:C/$@ @B>kpovv+bggZ渮4+\ 66zJ5[_ekZugW6n5oÉ1D:$l˶m6mӶl#nn6o7pvpqn7q'lWorvrrw s׶l@$At7v6tO<7Tmvp߶sw{wx߷p7u6rpu3w8|pw|?v:bannqFFpl pdFp8SfFMVJ4? c/fHHdOkx;d.{`>`>Pxf8gs˹ǸMGpxK=ǝgeMCNJ+a6Gyy3zk-s9c:59_si^3 4B Έ?:yygeUyCzoesxC9 i:pH.z-̿LCt. :HV;o?J(:xIa8K͗p$A|`\:zy9.Ǹyaj!1 6fE<|r-9{;a<<|p;>8ѯ&Ā^o9TDs?[ z$? |ԼL% mu1HtF*,?DH,v|;<3}-{<@󗏟>"[K s("| 14hp`Gv\Q@/^Iɖ(,9ӤK%WdiպPerwQ|E7QFwR~2KR&Arʙqo$*TSMFs@`u_&29_TwBoے~5vbI'1g,c攞5slGf^Y%uF@48) k_b~s̖/87snD":Y'SFڈ1w21r)u< DG EDJEADJDSD]<?FmqEuDr"\g]DRԑQ,sLEGڅ9r1wQ,Wf]VZT̊f*IP;Sig"M1iס(޸ w*Aŋx_.\ؕCC}Z}֑ƭ+`Td~oք|$m9 ci4ق9P T!TZGjT \7Ո#8g69@!r& p"GKv1ÌPW|)SA)C* Qd}H5r#Ճo -ba.}ov`ȶ bBjH[v1|aExC#Qz0XG)Tּ$TU:-8 oMToD@;FgEU;oD 4r EϊvgTߖVƞ!Y.vq /LU"c5Glf^F?";̛f !9)*RS26*uvi"05ʘ,LFOz{$"\ƒRy)5+t<%QSrT(SZBe$^◓ fYLX slf1 g %fɴj.ot4vٕ:q(`GR tMd*GT,T%SG9HPrHr8P(QFR 4,LF7`)_jپ)ZZGK 9*֑y#m^ja Txr` 2W "6F~+G@ãXS@qG󱾋d *WH7GШg/Zu$cu!Ieb% G&B8$"1$QĽ0#fY&c+ XmT!e:X~)@E4$(*u8֏Uwɱ!60:4c68f 9sFCMhSBޣcTD|Y_~U1ӿt+<Jw?հxvxFЀZbDpsVvlk68݈; w@F?U67 ޏ<x%dMPpSNpw@h: ƠYD{3G;jv[ ~V|h]ƅn/*- ICP\é8/ׂ:A2oiډۇmf]Q A?|$ H .W&H<:0;ĉg+ʺ)yGJ$bK)?&Ӽ98ga& |Hy\FhBy80nq /rAovx1 :Pַͳ4a2 i_OM-Q$A}(bq `m)T jn d @!(2$_v!f*J(!vR& Ot @va2:)ܚl)(,v0% z,k!AArDHZF |@.&nį܁0NpGE*4GGh:xϽ )TA.Eb1e}H nsǿpjSh "B̪SHT,S8 쇌 lNx/䠷v!zjV/밹b(`֢.g*/6(4e*k z J `*" aX+ |"X  WXK/WJ `@0!A NtM EL%C%KAΑ!Wn-פ*24jb`!pf2 p$G%()-i&KUf"G' b;*S mdti.@҂/l12"((0/xJ> ,E=6b敶c⟤t%PXӠB3:%v!.b3wJ'*'"¯ [,҈!F *3X,O{"A2p<ӟ,}.*Ai+>syR&> A4~ʳBG1Eэr&CAШa(DQ4Ϥ-O4EFC>H$Dˎ3/2tǾ r lnEoi),9@$P!,6 -z 75lDCܬL1>*/`*ʢ( .24rI`ܳB?0  bb0FtX',ēxab6Dz#;xŲ ܢ 6&2$ F+`q< 5C% V  A(DκI,``r(#-.vt @"dK㐕*7 A A@`UU_^-0z-hOa T*aJP;5QlV!Th \\5U oR"cgt$F Ԡ Ta ?sZ5Z#An_{l^hQh66(am6d/.ʨTMeV!JHVlh,lUA> `C3(!*7P@K *p7Uwtab>zὐuvlGyAaj6l>/rn~՚i)"/F%2ΑJsQl|Y)H1q$a.B2,o Lo؈"uyɔF՘ ngs[8N^ɏPnwY jES *J x:j!B(N22r`!RnGF,~*H"_2P/TE!` a-2r7T//e"Q%(fPFP2"jIuVr5L{,x8hq`pxK5 ahãJ@]E1A` q!H.)0Q Ī\"5zĘr ()U2"@z|ozȞuДy0b&00d!2e S&62*|Q,/% @6vab1 (%MBva + jSܖ’XɌÝPLj~wW5a 5) <6^~/a< Z6ڻ@M5Ī 2G7St.: /<<ZA"a}uԣK E a mZ"H.":ar3[=,;w;L>,PY JJL*:Ǟ_H/ /`:ȷ6c 0EB#"McV\ f J!:߅/F(Zk6j UZAF<d_AM   !hH PιP7 0zu% 6s $n.A։5RA\!X^_W[UmiEyR x!})2+W,ƁTX!T @} ͧ zB\)nOT" "xRAs{a!8 F`\!8` ,}\㝁T׿c@d0  ~ A9#(Bu|[ءJa&}˹tAz'kUl-`p5}Q  `` c z hߛ!CJ0eEɣaW/uB_)W`[f ` jClȢ@#$'_Ha% _?v :|1j FsMHĕ,[| 3$S[x\ 'BI IW|*u^*ڿu*IsOjiD爬9ECE_r Ye0GB3/?w7 X/ncȑ%?L9fam6l]>ú3if䔻ߺ* #qWمaU0Zx/z+tw0|'}(|EBL"ǐ=IrwpusfS?Sc ďa5]v_K@5aB!pRX!T5^dLn1J%ΨNO P9?O:tc4afP#MNI--^Fqrd@IjtPVjh)y%4>ey2P^fb'{,W2h>zޏBhқ249S{^Jjj>Hq⎞rbbR(}kȓ=Q<Bg i)'kNk4z*ݙ:czΡeZԮ!8B V?v)TkҺޗa笢A OaH;QR@C$.+.я y1xc:p9 mtfoFғMS6:$P\,.GMvHMvfD]% OC.,c(-Zv~?uMܔn21`WON<%q84Ukc媯ΐ?38hx+2Izji'!Q$ED7K?bo};ٺJe}\\=s=IUG?t<6\:om d.WTI-N;Oy-oa UNr -d1OōDnMgRCI0[C%??GQ L:Eav 9dB0C&#$/ҳ[2DQ5'&K"A:5TC>>! ȍR)4@xAz o. vq8xa.l!W '  2)e 1D썍e` H#qqS].=ŀC=00}L(K93~C_Lɍ̴T,<`(ˡ/8v_49P˹DHczQ bL.I&PgN>6Q~K{pLRK($j*PdR8v s$x('^tb8'sj-UBvj:" YvCkǛO$QG C&ы:ZQF0t0%, [X&0P`NwY#Ԭ䐄 tx>a 8$NKG̡j,pT@~R ؚrhxR7( 2 I & $MDnP8%UAC%>ێ#@ MBi(7H:>cH4ы%P0!>uI,D?W#"[E/xJ#NKBBo#A#p:!~LC>auOj֛e} ?#q-?1Ӹi$(q Jb_;NK7)@ShDd5!!Yp=|DËx*VM֬lF\NH)k\cM:ؕw۱φ1:1$=_F3zH(A HP!b&s4v!Ss邮ʹ2 tnbgEzk @LAvՏI1 .ԡS쏓W! о&Qh-9+S;1@x68nϰh aKAM G;>6 ::~ʸ1n [#hXMX#sR 1m1B3ja,a ;#L!GMo*h6JE7x/( 6s9( ?d>&g.Ox/8cKӁދ&p0CA~@"sρ @@,N 58x`>ID*,fP-z,87qSrY! MA p88b8G?A2*&^98?3̂@EN āsѫQ߹ߤSZI7 9$^ڟ{wrwtPQ>s02` u0 7px}>PTpr jUyG^F pSqS_p^`7zAve 9 b"VU@9Ucw9@(wMwXT0% FW _ >0RJЇ@S T%gz5j :K#V2>!W#9`U`Ad^<h(Ug SiC"'AM>`1 ]nR% LVZ`:PE+~Ѱa5zbOGI$ s0@CYR! 7 R_kbBhvWy0F}:PWш3zirg otQ5ԁ0FIJ 1CgZbD?Q BW %G @OQzzѰ&Y$QX + TJ-o>p\#4 ܰbp =1f |pS5F MpdZd_׈lmE Kpd\6 WFdȝ j^@ _`d@_`Ԫyl Jʜ;ǵu 2du (75h6;  l˷O ]^G*Ng&`]ʸq[c&Z_Yߠt5wΠ %7C@"p  nz'a f4`;Pa p[ u s9 C>ZZ F^P JNuZhsxx8Smf ki?_PP %fvy gWsg~k=`f %!0 Xf mϠ Tp`r аk"%)e,|7 2 1 ?9o3v "O V `/c0yIi0 @BlV` g e kL0S`o Ee h@ `O `%ev[HPgB%'%NYq`F0`@s4I窲P>`V(-R_W <+KK_`/ [\#yetzkGgZׅNee\|#p _01@ T` [;1 RZʛP2Je8o+#)w Ra9RN) oE0VnձPx P2j1NDI`VAJ! x#J`"pTI-g됈D6&i-IH$ W aɢ-`S<}"זNeVFXD>BHA6߲a%e>9-Ց~՘>韞>.nꥎ꧞Ճ.0P~3$I0HNo# ɮ.Nn׎nnBbtnnUS:E 5.$$  M~aqG +Hs/Ow"$W>aUbGo>d-/1oXQ{8D+bdxqG!5XH&9dŖ0eF S_~<ShѠF*S^+%*(_ yʴٲHo۷{.\y_&\ذ]ˆ҅xݴ|;././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1691062243.0 reportlab-4.1.0/docs/images/Python_21_HINT.gif0000664000175000017500000007067514462707743020430 0ustar00rptlabrptlabGIF87aGv!)!!J!B1!k!{!!!)!!!!B!))!)J)Z))R))c)kB11111k111!11)B11)19J19k1{R999!9)!9)19)Z9)k91{99199J9ZJ9sRBB!{B1B9BB9cBB{BB{BJcBJ{BZRBcRB{ZJJ!ZJ1JB1JBJJBJJRJJJJR)R19R9R9RJ1RJcRRRZRRZZRccZRkZRZRZRZcc1c9cBcRcRcRccccccccckBkBkZkZRkZkkckkkkk{kskssJksJsZ1sZJsZcsZskZskcskskssss{s{B{R!{R{R{cJ{ck{kJ{sk{s{{s{s{s{{k{{{{{{{s{{ք焌ƥksJsks{ƌss{RsƔΔޜΜޜΥޥ1s޵J֭c޵εֵ絵RƜƭƭƽΥsνֵ֭sֵcs!!))99BBJJRRZZcckkss{{!,Gv@iK֩hdJ0![\vEŋ3jȱǏRk3]*&(uRˑfRLdM;oܧKh Ot+hℜ2Ē>1/-Iǂə~#nb ,i?p-tmx|=NK(‹7ߊ9&3 @w7 #讌N:# (fC.zS;؍S"H8Al9{9O~(l׺Awm1^zjrH@f^K+O"y9|ӳ/9e~`tKr=1L{AyCt0-p0CXj# 8<n"`L4!E`.ocNvnZ. :CdcP# 8p<eXSa?g: JߣF1.H> IȽ]`1: ΏؿI}Ǜ/9BP'W@h9ʹ1 B;ВnVtV!PP (,9?_~Γu(8i[3% iEzY P>,L㝧1n~Fd Ej$X\ \ iQA3`T"|$?+>1@%J=%KoxcjSRZҼc ̠-Uqc%+͘&H8xдq<ڡr `vbՀ.2|bwu6#e?$9I12[]XEHd'tVO8c<*x d|[`ё[@ `q71Rc .$ .vzݔvϺ\EH)HA$`ZEo,Wu񹛍p{+rW΂p*Y|- D&Pq)!?vv>؅W4 '.D*Q;9rt!js;bɹzM(awNTQa/-IG48CKO`zLRn\^h99aТzb!9!3BOcN'' ejFcjC D ղ>ZwhNvorlkAg. ?яj 8A?m,oCcT,4K<13˕KyQ%^q28B3 aZfƶZƇq$Ԓ4PTN p3uCy4bzVcBC0!QsdXb@.`aN\G@AL@5j Ld @D2٢45!؊xG8\pcDFGq26'(P#AMxe-fY}X ZXs?5i7tK>q7~;p\41L5#8 bW0Wg"p3!_&H-Y F 4k^rJ֎tn ` b f0jj$UQU=uGyTvU68Er03>5 @ t{x>+7~9&HImBVU JXVǐ laa 3W#5FzY}e0 8 SPP 0^%H ȠF Z aĈm U0 iEF?ߦq` ! M !Ѓ~^X@_ K1O1 Q! PReEO! 0O ]PLb,@OET(O`i$CD`J P р8gAe8yLG-2'&)GH\B 9p ܳ]pO` hx gPɰa"%J`70M)fifP y"]MPOtjX7D! PP ee%7A  ]Ɔ o7_EI/4?K7_ԅtxVd 4iٍo9tIv $˸X/wgak7D#isiiC-W< uixۤPٛSniԖܨ I'Y3 ؙ ^s d8 I]^-P[ 0@rr ǀPqs 9 Sp ȠI?ępo |3 NOi7)H p' s$KYp Y9O"v7 &J)jpM` J9CiIMq j  b9ǀh@ 6p!pq _" `i !d&ORy P pƏ@/\` =8ph a*A Cp4;8h'.0fa-v e7th` @C7_ q0P`oagGt +y*;`?dCxDGK 3`ӣ8hI9ZI-j֘~c64g0@G75o2e_up0hd;[{۱08؂y+k!m,#  $hr4C?4³>۳@%'"ac. 'r*BN4Eó2Q+Q[dU[ZK\R V+[f;g[hj۶^o˶q?M_x_Ұua<w0Bf+԰(۴;[4<Y <} !ˣ Kӥ0kۻz!"Bk@g0<tܻ"<+L/63蛾껾۾I31U`hГOi9`upmB"PHFlb*Ez  0uC%Y.dPDp ހ .#=3ô!5[1/%.+ oL[1Bӷk5@fkq;& #.u(s(#5#/x'\5RO]cL_5M2M4zB]!E]%"./ $\'0k_X(c(22[-CW\R #ŔL6Wr1rܲ<+}K%)62`SB/'.Ns1rK)D 6stiYBY$B@| )%0h] Y; ˰{S-ya"|@}bC70",Y1)l2,C3RsЯ\Ã-2/(08Jo5@c9C9RRC ox c8]P%"PS>5OA\\ GC@er@]s46L@pYQK#XO^]6@Q@d0zBrjbr7[ѪdL 7fc8dѱ1n ӏD cD)odPuC &~ t ~V"T(9V4u7Wc5^H{ELD-Z9jL X|4YM= 8MvY~?旇Jr=HMA[ Xt vP P 6*zu> tOO_ P X HMHws>>vA8>;TyS BZ9OaQ@ M 1,O4<<.V怇0 :pN) d2Y-D)0/M6"6j.*0f@ps;MH7"t  ?j7I$&~ h;,9`@j̢FwhV# ٍS4F-7N{ v}0a  =A.;HoM > X0A@`*6头GHWVu=6;[}>`뎠0 lynU]M9RYXE7jDMa]p905;Nvޥ=uu}X@cX?TiXdǓ琢o|Sb:_X@7@P,2ŀfu{wf&9np0  2` Đ8mؿgPB >QbBDKƍV ŸD-] q`1Kj',KOB)ĄMB3N 2l C L`5a0eT1jԘQqdIQ˸h*]XpӴRU@BYB*ȈP!L~YvVPB, k(lB$*0H,h^䘌\49An\"\%Mf.f.3 E^8/AYGE^9蔾!hyB̐ Lv9%:"Ȑ1NPbBzbA$>qf!b3PdYrhHH3;E.;q\ʺS0't76E8@ RZJ1$L  XȆh@L n\<SN?σ2#qX&,`bР -APU=H@>ShCÌ.C  L44sEnr\6׹υnt;]V׺=А CvVX9Suջ^׽o|+`PW*G\vp#Ɓ Xh@@€-L W81Z>uC 0Ѓ1Az0c  "h {#1 nLa!g0:H"rE( Te,OPֲuQjUԘ qMTQP /6\́W+޹~vv iK֦mmw;۞}l`5;R<:Q3t! fD, q. p]b(np '#p7x!nq\qԣш{&c^B Zi;Dz3A| 28mq"? `z3V8peq8]$.U$qO:!.v}f׻v %dWɂ .X5b)$ Zv〉*m`G~+g^|Cуa iLCy4  i,cU0p4$8q=q]| <3$0]P?z>?zc迿gF1 KTD}4DLhBvub4t (k*N.>+=\@iy@@@@ <=oÆS&0)` Ph 0E0wp`| 0oċj8ws9:s D@ГCB!#cs#B]YpH"e;23d2KCzc7\7$C3DC8l:C84C7=l;3WIC/zC30G5 249+5 s5$E܅b6\C3Y EBbWWHeE7CNC>DH3T]C: D@84ESEWTTŹ<W o8AB$0A, @BFqFp4nBts ]@ uȃB7$IxIxtɗ OCo PSvQqҗe[y `8jY;jqqdip-.H9*H*QaXPE.)!n(ЄYP"?ad[`=1D^'F/0Ci#l-VY9~FT7(Jû4am^PW( =eaC0#k bNd.ȘAL\?QTqFTHIWP((`K0Uc 6,e8KBɗ*dDR+Tx=}!3Y3MFMs^`ƄГrJ`ڄd(&ڱepNq 1a?h2ÍdpA(kk1ѨIE !؏nU p0Kq ~']H۶<\kѨq` =fYp4>5ܜ`FS8a„[`Q#1jv L(aP^(n]{7??$q܏eh˲PYI8 ݏ JA%f%fJN[H`?9XhH1ZvߩZM<0G`h"`A.I M*^@l.8V|urF\` (p|0XYzT[Fۂ #y MoP2Ih=k<؆qX8q q1Q/ &OѸ>`'_:wN}X:X6NX6m؆knVh0'+ '$ Fpy s!쀢P]d^pzl+ 7ev@)`!¡['8ۅqf\^b %3P ps8`vpBy[99rՇ'' fQ)ٔ\91 G\WP]?m\ޗ h4twW%O ؅^0zKW D6YW AY,h „ 8&ʕEdt`bD+E?f,i$ʁԕk=G̜oϠ>uwetR2=&OB: 7M@r-!Ĉ&Q̸&+ܸqC;{w:-ݓp='n1ׯ%Rhw ƐG.;unZzJN3Tpر/fqyݍ::iڵlŌ*Efw%C .qOH,8ORC4D\deMȰ Aؔ 0Вu6Ş(cITV|uVH#xI8E[D4@1/HcDsb?i!"$Ѵv n%dPU)oEDQY `GaTgVy1gc!SI #4Ȑ`I#0aMm7N/` ~ȡ |Y2BEku3i㩱 I D. 4L #M ."Kʟ/pAyt<lDg޲'ڢD#AZrCg8RwJ6H#Ҡ ,b 2R%IeTٰ >ȠP3d'dpIiJbojjC@hb +ؠ ,O|%BpiP(ZU}t[*K2#nb@4»riYy8Q?7A]OJ7mH 8l?Q.G2 A|C"A sAMPi0x8"B4㼠[մmj|껰=P\HOݙ,8LD?5t;5@b7"MYSXc5PrLbcb9^M#bM39۾)!k|b|qEY솣 ~ `rp? ,#[_[4܁6$M80ÒJ (#H Gs\$0#cn()'O#o"]F4ҒS.TQn< %0&@>t!8rW(AN;N!SB{~hvrb#!3ެn#, )rFt'd 5)0 8  =a&*73p#g72LOP :j &C(8ѠC"!ۉ|:x3Px $]D?}?/8Y0g t xG,~chNz-tC@q ˰ Dž֙t)OK$XND&i,$[h (uW|$=i E5(R\b,]74XF1:f# M`n%.ziI,(?Y.,XxuSc삠fP{qbQJt1*ٻn,VHe('x',a#^@uNXF f}p)qgu iPH0Cds88b5VrB(.4\]*YDME!ЅBa/,r&r>p @MImg74𪺹n2d8Blɻ$nE1*xU8Ccq BH4{ sqCFѸ/(T)edx@2;\#a$k]C\f2BRTJ b&qF⠕+ ?&,y9f=MCH(h=\20 4 <Ё"@:O`C(b*!pL0BG$Jd8XB+$d,ə( +sYM@LCa\.0B 3a5Oݠ7MwC4]Fnd=F1PBȁ'Ya%ɕ\2"QM%A å_u pAhBE NCTA(dW1"@AA8|&n 7'r]dM߄}vQ)@H% lV6 4A8$ f30.,C1']N[,&C1N3,FN,V^zSzbMz^+aݐ,3)͇T`4L", *Ȭm")B[4@AB ց"[Vrmmצb͢٪aڲٺmܾ-ݶm- n-&.ݦ[ۦ-.n2ڬͺ^-f嚁F+x&\.SӼɓ˹.Ʈ.֮ޮӻ<.h$$/s.1SKo*o1n &o/N/.$,40}5`7`봖'0/70?G0OM7P7H!½1D40ʥ7ѵr%Byё\~ 001p3 ,. 3ʂ)5,B&N62,B{q1qӱq۱q5ZE7H&*"^B(B#4<)d%qʊl80 01X+ݜˆB1,q,ϱr-2.Ӳ-2q1dE>B=1CB 0Y/pFql22)*1CA[U*Mw3Cwj939D:8;3޷}׿>~쿾Mڜܜyj hy '~[쯪LU>F_%~Mk{=f-X,Fr>>~W?@N`q TX`Å:0ܷqѼ=UtF [4EBlhe`ƛ7 " x.DB E J-.T0aUO. eՈJe%*P޲Ʃq0,"zې?gP?5Ll' Ǣz@!zo~hq`"FrL!&µ !Yz0/򂅴1(\Q`9ɂD$5 ABb38>D7ㅹ`Hr42Em, jΓ#:y8LA  XPzZMKOJL/DxKQ#pe dD H z X8_a)S0m_ ה0K(ӧ10F|0=K)ϦJx&Pi KKPPB40?[n K`-W>CpBDKϞlf2R7Jsx`k(! x Ni < d!>ax,HYԠKjhK.0bedv8P^B#lko*>&) !W|5,3kbdgcJ]+Ϝ<>ZTa"9]yudz{:B&K*hdx86_0 Z^mGAI8hA Z8jO<^8!H7Ofm#_ߘ6: a af<} 7!$)8b)v>o,C(i\( qoIwIj<`$OǙmN"F0-M`.sP('H&t= ~sAfSG'41Ԅ(b&xR&I$c:SwyiE$u^mgdP9S(Bx ,MFeued? u􏓰.P 4YL DA#aDnjnic,n58ÇX''ؽlOAu1wr;W,4d]PVhGJOvmʷME3Uwݮ>ݟhwiߡ4w7Oc x>!_K80ج*=6^1+anLO{%Sb>~7-$P(죯k_跋&JU u F8ġ`-<6!QTF=`@HnU}08 <"LCϧaRP !HЏĒ/N|xA` \00 @ pa! .<ʠ Fĭ Շ`@H_l8dn! 0 5 M HDNm@Gq 6n<ި ..13qP pfirK0z){ # OAᾆ A1s qlJ91 w։`.͐P ! 2HbRM3gg6J8CE v4cN8I\PON=HFI9w,Ta VQNӷՈ a{ABFMOAN\ qix4mTAKEޭTӐ4#,Ե4 fN`Z؄;l bԒ@nd )4/t?F,J,MMpԩ^,g |RА}m^ LZ"NXd~n,\(qK^B( -sal!rbo @nHa`02OW1dCdT(1ځaag!|B0e1 j!qagjj}jkܡd*V9Ъ:,V̡kaA6kȖS<-IAp%jv8jnkalmIgkAt/6V m IFvm6HLiA1yrynK(@nU7i7kV&ɵAʈkAuZ \np_7:(I PhKY aJFiT}tQ$dlbIl&q5 hM* LKYj|ZT.`.Rga܀\L|j!~2 \ $0+0-"8|~ꣲ&9~iLzG|Ϟk2a5,}Nϧ (|kp1>? |Rj_SnN:X}ms.濎!WL]"hx]nn~{g!*~!>G i|22~$=G!s5R%KYtE&޽{qƬ(ӉO@d:-E= 7&*โ  8$׬8JF#hcH# @YLȈg'3@YN9d㕥*9(.\<|AJy[6 k)>rǏ"݊enL`d\#"B4RD3%%C6 I4bNUAQZgl@Z$NAYh~$#ES̀ap=.w&r TJ!(gd1`Bqa2TA7hE d Ë1 G&ddIQS$/Gb ," ӄ44q .b%E%OR@gh&0c2ƹAz(tgA(s¶FcLĆKh( 2"+dѨÊ:P.>przlWWbi M7(p:Kb%2 , .P oi3bp&̠ jP35g'Hl` 5$x)* #1e K .X2&6nj \-aԂ$`'<ÁYͫ+IB on/I \(4.F#1ǜq1 {t7M GVܡy1SywbV;og| QD4Q c b(DiHc4Pb&Cs0-ń`Z~iOW~nVKP1-SkեȦ!5]CҰR*_ԻiKռD 1Kj+~O*Vֽ*vM%^nzHlK@0eg?$C xJ&0A .D 8(^Ts8a׬LIgq+vqNJ@XLuޣny vDA, MT;5rY 5Iz'?B  λ ? t&1qOx* oܱPĄrG0" .(<7rej5yք &cE@>b""/tE<3`^;xEbx@,pV>.X)4anh"j޺enxڭXw9尥X :znHfujWT[8Fl ?o87d!1fW#e F>۔Nmk؆ZBUѣ?x]q0Pps o /Q-l[nڏ B÷Ww]PtW?4v1D{BrW,x˖8Pp~b*kL"EUgl' ~75g6 1r/qhP ip2-Mw TbgPE`SPUF@u%*zK`@G@f@7${2Ӑ UP QpS eh` \ ZX `EecPPC.x"ezC!e@#xI8  ]r [p Qr0 ^@ EB: 2QmuxЁS p:P0S1gMdb рѐiJP}9$0d=p՘ ( ]@s&@ՈM@0 PP <x p @i% 2tpH苲 8 ``5lČV]HGҀ8~ؘٸrC0 "ɠ c 83 sPM rt 9|ii=MpN9‘^V )٨ɀ 'yg3,@( 2Ir TrEBKh'YL8O Qy ("Ѱ |$im%9 Q& hS@ Hu EI*P`f9 PuIF9prփq)gPYC5Ź  e}pLz1 z绎cV[i+⑹uH &( ʋ7%bi; ||y !yH}N:r+2+\ Pz9fj|jrəTMy*\KeNuV{rX\YnFŷY |FVkCL Y j\">i̿Tz7VN;:hPpwa=ӧ@e,Hڋ&;P e 00 }3hh '5 <ѾXߵ5 u)Ep 2؅Urٷ R } P ZP YP)$r 0 pM,<üDJ Y:Ӏ  ^0SpͿv1 ȐX ]0]0P] I0 s0P1S_ЈEُp^#MTGƼ=s`s0PSFX (XF؎U0 Gk+9 PM0}u(0Շ Px MP~ȔO\UӠʁ٣r ] V1 c J|U8 T#MQ? `sTP 8 ~'pא _ E!QM̻=1 @3YK 7`Շ Ǡ:`F)eYsz{d F]eLL 7\ J(97!&9>Z,$h훂q)p[<f)Z7~hE6,&6ɝ ZO zJ*#(>@$p!p4>тKh8:y " 0=.`" "lسĀ*~$# Oq n~{Qټ K xO, N #JJ΢!eQ;5iJ 1 U|#p# \/G 9#!$\j@Xn` M fp ꩸UЏ-nr-fw|fcMM`5B@ 7Qe:.* e!13 >a [ R~NFLcg: p$0qa 0jbf~Ұe gP Kh-׾i$ЪX?LAUKB*?O $p;@FqOR N:UlJMPՃ P g}<; 0U9v W1x `{qEe=fwHHT!W LT[|J45/0. /`C :aO@? &"n^ DL`7(4 ՀmY=y_4.1/ܠS pa6ɸ!A$YI)I艢q1A )J9u$牷 #Js̕yw>j1~&fpO⍇|?y}}巿~?_X .| L1zc{AU` * P#$ax'T pjPE+` EXC4diC<WXDQG$bhD(&ObxE'NQA"*QZ8qo^jdhF7pc(l ՘,?BBF8T8`GG;ұWS]a{_=IPR$e)MYNz2㍀;././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1691062243.0 reportlab-4.1.0/docs/images/fileExchange.gif0000664000175000017500000011166414462707743020377 0ustar00rptlabrptlabGIF89a+kk1R)))!!9s99RR!!B){9s!k!k!!!!!!)!Js)!))))9)J)R))1))!))!1)!J)!))!)11)Zk1c11s1c11!1)s1)11c1119919191J{999)91s99999BcBB!1B)B1)B9B9B9BB1BB9BBJBBkBBBBJ)kJJR!BR)R9R9R9RB!RBRRBkRJBRRJRRRRRRRcR{Z)Z9Z9ZB!ZBBZBkZJZRZRZR9ZRRZRkZcBcBcZccRccccccccsckB)kBBkJkcBkckckssRsRsZsZscskskskskssssss{ss{ZZ{c1{cB{sB{s{{{{{{{΄csBsR{Z{{{cΌks֌猌֌kss{9ޔ{ޔk9{{ޜR֥֜省R{{sRεֵƥ)オ)cZֽƌkƭsƽ9ƽƽΔεεBsޭ֜{΄9֥޵޽ZƥޜZk!,+_H*\ȰÇ#J@ Nc"?D\ssZ6 gj4U45aXvT5*0IEzcdhXz8U6XS&0dihlp),*ؽK2"ٕEucahp\Ng,P)vL^';quh,v͘tꪬ*֐ u)멸뮼+k5nPE"^8&N@*Bx< ^ 7G+1Sb;Srq#Lq'ז(r0/l33͌< p\M+^n>/X"_)rFZ>p]A xb);C..>fO9w;{7γ~̘oB섐G.f:q)).ㄺ!/:q .\:ktƯ~5 g]<c>GDbĹ41LD"('ZXTb.rTb lֈ`@PA= lA&zX7,׾r],bg+2-nw+%CL jHMr:R\ }C8F=Og=vR2TJq :C|Kw/X.0`+8}p' a3^؄1, K0=_4Y-McXL:ӿb|X՘M%KLcf8b_K𓥬a%O"˔430h&߸4pn3\@g:yuvPWf3Yz9GhAЁ3sь^Qw3n@Y{^Cқߜh::Ґ3_-k99ַuk^̾f`8 m$KΩc-T ζn{{9GAuF@!oC~~8.O8sWNN2ġF*gy+qǭ]0cN/y7!}|цt;KyEt;}x7+'=>DGnuog;v_K@Ehۗ~]*gLx?C<ҋ>[x1{2]O؆Kw$=GH#$xy8z{Pht~3#sx2HzWz8H~8чx|'qǃׇW3m\g{Xzb 8'St@8׈xztvxQH|ˈ,+'W|׋FhݧsXx蘎1'x 8Xvϧj8Hy-㌸Ȅ׍8|a wmq:hiwu)u.!bxx$22#i%'v)v9g7 (7G脵\Wwt yǔMM ШwKQPtb|@KvXX}Wrivڳ^iyR!`Rk)uyv y=ǎrGc (}@gm12=zhu(G%X}WZ}Ct2uXq!u,xhq)Y{shw|YY~ yuQ#HSאUYIi8%x8IG!؞ۘhKY8Ǟ)RщQW(~F yt!*.Zz9gQrrv؈x!hHVo(5*x+S2 F6aha.@M@8?sFCj`hְjffffgbi.@KjgvFi&h`i.I[g^+cmI}!0q] !~퇘Lp 4#P h|xXNj;),ژR qӲ; K11j C{K3Gxj&mR~h8Ùm o:WDx$듒S$qTayAw4; qsudVU/]x tZw@ K \P l\ E`*Sj}騘*;/ !,m{!#)i@< YqYX9ᙜ"OB<1cL@ l : P2@Jy/ʬy\z Yܿi<42 O ĄKo? A[% ɕvPGq!mҦ/V B3m֦tTb|@|\  uLwD}v&zW)ڐl\G(3'{{x9.Nk7&QS?4;R24ҺvGt1.[.Fp)Px=S/ "K0mQ` v :Ll:ܼ=VA {5Va^(Ӳ1@5E tpKe1-g5ZU0-l5A)z2L U!B/-@9З(+1+Oh\3nH*&C:.P0 C\,NCE:з!~ lu,r Gq6GaY1|ދ:R *TuNI-.,B ^p+.`)!AB"uP-zbl ש3/ A"עDU3Ix/A@ $ V##V{H6.c4 ijO0+]c@"#T$1Ԇ/` ļFםL  U~v~=(y!;,;NKCA?|3Rf@ ks tO0q/0 .1TEc* r!u`qfX-,"iAߢ8nx1."^^$cA e6Oe_د+_N UE,MdjԔ@Yit)+X!|7 M`KFt5(),r=qO1*.E:/q?n20?ގ^@.M8n$Ǖ͗zRяA ."_Cn/p@/.^͓*$ k n` @ p hl:x sH㢸 ߏ1=*<@#cC֔>#4[N4tNb-ŨM7Tj^N@mLѧ'S2~mrK7ԡ(kҚVfmk\ٺVw+\JWկ|_WVtWv:XWU^%귞}%pM>3tLȪnUc6J6mvl%U좙m=bE(-%lV-ps[6%.n+ =npRuΊG86eL${5Y?}&G΄ǾHߑ7}﫿-UaKLa"3%&g+T^e,up%,HcyFOmmgHnFMiY}e)Xr%sx$4%#e×Kp*pg5:1A엤ðUK.gڏcpO-dvnVh#Yp]M_lYws\5ld#9b'ObUa]I\R12ZՌ4;cX4_EI|5ߍWxA!h]腵 v\2/T6i21$v3fq͑Px5nͲh ~@w78XJ1{  ™g1iXB>l32V&kH!}r! a*޺n@R<*u0Sn֎-n-Y%3O7;sEoAf'xk^P`D.HM=jop,.%vuÆ6acyJ#E.Jy(I((( /(8kHѐk88C-yZ *3' C ;h': жx~P0=ÿ=о:о' /X h h08 3 tx~>ĠkAXx   ؍k?}qR `/ t9( (ȿz؁ҘO'%Û43fy&u¤IM *r(Nzxk0>D`LjtxD,: _-4#[*KhB&|HHP pژ0~`$5\~3C n뿫@ "l ĕxcpCLdrCr\1󧂊'!~'Drڪb305ہcAyBcف&:DEjY;m[5C6(1XJ7k:8FFLmċ*k''wyƯ#S$*)I  ;Kph:0ls|aˇv|;DjkS*{L *L$ʋ,'>жk D|9pYĊ= k` `9!:h;@B$шE0ηx s"x(q7<4,Kwp\pdR|Tc15 a4bp1v* =DEP%QGMQETHUTJeTTFTL]Q5*Y`2Ys™l0lLi-a "_q/P # `Q1 ͔hlZځ jO짯5(:6 Vab$rJ%d!,C i <EIZ/I m;)Pmꪦjjꫮ .Fkk걶 883B{"Jf!Y/6e*4^&3V`s<A_Qrf2b P lNkk6&.VNmՆmF kv. =k`fMDii.쥦6dZ]^i^k~꜈0o=F6ffP i&ooovopoov؍pTPXB攭hZn^V쇪zzFed鮈=mp@HzȆ:Ȇ tJэB!7r"7#/r$/omAkVS y}9$0depgڮSFJ(fr1=e c "OOWJBJ`UQ?9?GgtL$tNuM/3tns;1d@JIlVnoV\CEݚksꩨODյhLΊnW֛S >Άh ' @B/䋅PUcJ` {FEoOp?$w"_%wO$.T+7X2gi4u٢^qCuEluuرQ*^=^vsv gZJXȆҠML'?#d;^b?c85CFGX&?{K7gwzޞwo :5*'%TY0M{VYcz_);axsF^!&X0yF&:F|{pzp? lzuB&P(ng|}%u'}o'T^0"&򺩄iV^8eʞGd {j9Z,*o'7ۂJv7=UC$O|':6OŭV7zzwxW}?}Շzbxc EթCh"k2x^IŔA$D(+ 2$Y$e?`qh?v2}rL)uRDWU)9"dX$١jV ڲVɢcg-5tѹ7ƪ"JeyQ$PF`b)Rag'e[VrZ)sެd%M;ZƂxCɱ܄)qfE,(]X1%=TZk;Ϧ)ٽ]@C_,Z[n4l|)XVu8w=N |Wd_fYdID5dJsY&[JV?rրV&Zh}F#n+fW9hUmEIO/3?ӏ" YS=0^T+]'I#AD 01ņz 0d?GddL/p@O׼F'a_Zt %\ҙ]O+0w[iH*_'צ&ւ r&aj}i+JY*ʢ4К@cYմCHIT5<"0 4 ^PeR!^HN@9IP;\b⺤[>u8 m!ɁPR?At&t$ya cWB^ t,HκO,Dr:\׸b%u<7E\!T(?N6m]z~%YYr)tԵ8"!uP3֤A=6ch)=ZQK%ә9BMB LxO@ y}Bp>#@"97C/ɎP@8KIu  /gĮeW b5ddQ?o? |M ?p6(/$"[O7OIv=J(!pNUrB៼O?(.t()B?v{$)uy@BX"+_(Jlwu2 ^h%^HxQąX5Q \_hįQ#c=zȉ_SHI^0hF/PҌuJrܤ'CHQr<%*S9T D/ | 2')AˇFKpC/Je]=8\'Mra^z<K^ n#ZD?X~"-gJs\C/yA#cth:` Kk,$;*zq0d=2!!H\ȥW Maӑ씧:NmJ|W? QTULUQ*ԟ>"*VoUFu1KM vCbm"C F]~4O}[W.. }&xP 8Gb=kbiT\㱦RR窱hC91Q^MA= \#m$I.+(j;v;R2TW6W$HD[ѴX.x+񒷼=/zPyoz26?q†h ˍր#F2z .b)Y-]VpB\ f"(l<(̿DIwi.vh"H4M@cYiu1'Q6'&_LnXٽaɜaϾA Ё70zӬ5n^ozב9_#Q[٤Qa`ADxmEDc*t䘱bأI" D.'F-4e,g&I4 [.U=v(-Ǥ]a$T !S73~z`yM<%]Z(bDNBh :YK,ȓUGbbN4-`J4V,%8IZ XA+waRAIQ1M]X M 8%DID]L^%i~viC\^%a"Ҙ` E>4Pp监Нa^nDLZ~EL-[EUgեi 7v3f dfwe"(C*(2$B.@q/Vd H]PDR@L<D4^ބS2t^V`DLI Jդ`V Z؁ ֨~E"Lp}j脾]:hwV#xIvf JL^2qgz(& Fw5ܨ鐄&eҥIFhǿ F)z"j`hibƵM~M&6pZ/ef$tvq$uW(rE骶xQ| 8hDzt 04ܗpbE_EIWD jjf:*eʪ>B$DB*.p']05ǚ!"Ec) H KA1$ShKs0Foߌ3@Ԗ]F| ^~v)ڢ'ɖϡDZW=;C*A(74w%_׽>,,vZ`=NVFķX_η(F^ P`mFΞ,"Vc{,d C9\C40䐸G|DLB-ɿZQ$ ɴV.6rlNMcsP֍xA;9FD5ܑ/|I9uV^Ff+lB,C3/t EDcbQ!: %(Er1BCa%",6^fr^Y&@^iBqV EgؓL=4TmZh _]ڱDIq_1\_]Dlv̪wA, <.0 sAƐh+w?B0aq?Ƃ 0 F@؅{ 1PAJsE\k V M:<bI ZKCp% d1U[X u739Y73::s:3;/Ʀ>~ip=<0 ;,D>ܶu.z 7_6ڪ\6H|N|tU7G1Ć`NIYZZnAp![yӥzUI򐬬$7;7uq{W7+WQaL4hs`mL#y_iYP}%mclTeynEX^vbp^\4l$H9lQ"8■FVDTz)ǭ%]S0\Eݒ)4EyzU߷`*g=Ayz66IO [`g"S=Ev\1H񥓹4[9m#6h"%.k!J ^DG \ Lq7|`o&ե~KzgYk%~W'wWr@_D R.dK4uaqҥ=`|e_Iz䙏Ϸs"w!o_滟#.{yb5pЃ&xp+yf>cSLh }/ tN'1u+Ǜ{0tx(Kpy*1Mzw? 8=/tQ-W IŅB407ys4E<^ N@ b~4'y ͬsNԒdn$/I_>H>{Vk05@!Ap&-<*B֋y1cHQa೙_ j[ga(s%Ty<[-̲Z\AFYF8i,٦m&M8D5@#c%\H󷐡 ݀S.{Ğ?t;I~OrׯN?v59fM7qԹE;˗^Ң6]zMRK)dXOb,bД]N]z\{:`\Pz@I `ܸ ]˷A-&Uje˖Bsɞ~`kf⦝fz#!=x%fj‹'l :  4fSN8>;*O?RL3ib+tqSQ0qPDEbtQbabp"^'ЩmQؖ4[{\yݵpjֈϪdʊJ#yAJ\h(FI51@4څ2\$7ÝSuٝiJ,>L*?3vbi?cSщ%+bꠐX +zq!/@`2}쳗]eZqfl0^36:l)@@b1Y/tl43y!oz҅9v.uOyE^,St2ЉXĸk(Bտ(q '~Cxd{@‹cqBB$_p iJof`F}`|tHɊDvB8)>j .&I+a3oz;*(PWA/;7QBvbU6#C*?@F"{)BReGי3#f\3ȮH}f'`[` #z=&`ڈ1͇2Ly۠4/`;qB5.]WJd)?VY1LPGTn kXʊ$E@P&+q V~! G8"Ɇ?j*.lTF m>tIbdfM}F0fdl4Z̰J50cr4)Q9 I(u$ :h2|(#<,3b$h-*tRt/EŮg|*ybhB^*EHJ-o8\вĨJjB2+`|Sw8bL~fjT$3/ 닁La{cG;(ڎ~( h?*QqL(EG*Q-E] ӐZ4iJMR.OTE5jPřAC|U4ceURy'*}fՑ}f'sLu1QJoFI;ڎp(]iG pu0mH֦ؗ*I RȆ=>5iQZբ֢찇8cQTX?yMN!OSEGqE2R8~TbJ4 f=jOjr[*Jb1q 53#-LQRn(,h_ZQ'=N1S7})HQ46pK7!aRt$bZtop U4#8au1YF1sJg2e/uhȂ?"/- Sw Me4OQ "bzp i1,:xm`=+Zn%sHk``EE@6Т- -7ZфNk`0œ1^s2Te Bl’D)u؅r1aLXr\ƀ$,u%M^2@. b?^6hG)pPvvv=r(|A퇛 =Ar6p8 ȊhOj`A6nZ%iM~p' wxR 0" 6_%=Bu)$ LJX\%@qaјzt1_Z0U՜S>ad5$yַ8czha62i lpA+^~ ,A8|NG0`Apwqc=NB;Fe <|XD;PNzoG;y7}m ^0%N}Eܬ!bLN Ɂ񝦐ԯ 0|ȉ ;Is j 0叻,ʗ.[et{Kw:gb 2F_-QL ฀D  d ځ  d 8v !@~ŀL+prpuy}0Sj. >h.ALa(!5\- @,0|rD1(_ GS-^.TSG`)BB+n4Њ>ʮVD!j`4@ Bk  .ځAwa>!ĀX> (eA^`_/Bq' LQ߬qqQh* ATHA??F 8`?q8r% -`?bb_B#@ԀAB?خ(隮H>¨0@\RVaDa:m  !¡/QA>G )CX8ހary@mݲq-ؒ!{!c?B_$c)R,Ṳ|U Z$ PB$6 @330Y,> ¨f/` 1}$լSB%8X( ޠ>\aq:Aݢm* P:: Blq @ے-@@GF**a*B_`b2c:DnbA*6d6rHFC (ȫK@m5Ff6,ҠXa ګ<᣶T>v͂A͆1>+&JͨjJ-\a9,ԽؒP +h Q#PU/AJ0##XPhFbdԧ|2c?vlKU#cCPG=Wns5z : X > 2K`XͽQL.lJvj@lrL[RP#+.nVVvi,Ja 3)·3lfU~P)O"hni&>tVAvvTW_'Vb#I*Q˾(&:b}wTT˗~y$_a&a^4l ĆH1^,2'pja,BxaÅindm CF:dlzU{("niy=Ozv{AK n)1sS\ES1./]TkD8r2D"ԧz7 o+zqf&TСzX' ~y8`̂x Rvz#A6my>F& 0` `ęIz @ Y Y. fDmW04|RCJ cdv@Z$)@*@I;S@%)zYs`{En(RdϏl!fa !G:'b!A[84v}Dd:=(A &[0a6u\0%t‚*DmR46S1  2AD܀|C$'!':cq/w)o4 ^`BDLCbEC9AKOlo8E9(8?ּW½D3d"h]k1f`@haj#GF*ƪBU>eLI q^ D$,Jm 쁮kCV? djG#s z:~dȒMh(M(%zGa b"(&γ'b:<蠍J!bλb3 zx @=a hZ)aCQNJ”m b6b1\CFb@CB) x׍pux3"fĀX`ba| e';̅))BB& BdAbcF@D11p( @bB `kBIkM@zbgg90=*VBrvX>C?TQI/Y|eF9wfС:E{ k\hDy }lԆ"!q*ez.ă;RKG{>ݗv_0aZWJ7Gak;oNY% ` .%f5fB$EMRMIzu]H%܅Aw6Wy6ވ#x.fтVvؕNe cMm5[FP2ɴQFǥXQ`8g1ɔ]?uHhYw@ SZbY[u:;p喝~ j5ژb‰0¡JuRwq'!nv*kL/ȧJlĚSPIt3=1s]nmj@, ,b(jL6\oKм ̻o;[ /p? q=ˆG r(Bk]CLmot{lTq5r(, S& 'FtItL?]ѯB-:dmqV rؤl'l,[>ܱ(wvywsj=- .xN8'˲w&BF#ݥל ;q1ESݮ!D;a YˤI.$3"?}`>8&m.иv$ͤ{9&+ޏOw)P5M?>nxO,n,e`?e,%^g~ AHE+4rJ.թ{+ O8>9%=  !q 2ڜYF3XP1KGh)B4@b!k4_ekf6xMi:4qSB9O+0-⑊=! v(H|e)/c! ux qDx!+̟5J8!/NX5\ 8[`P [EtST,XCj#UD1LbL\&3hBsϬ4LXl=$|VıdH FԁTQ2@ƈ'NЊ>飑Ab"#f* :d3>Ff)~)`<7RHO#gGs &T؂H6H-R^܀E#  b@kPB|M`+3'<@Z)d,-ڥ?DkZm8WiOU3A[7g 'V0-HMhIۋ<G"@%"z Y#p1ɬ3GC=)ӔD\+Ҭ_* )5鲖iur]pR,Uny۔ p[\*]Rb $  |8&I cGRU,nGY!nFH5@S!S\Jv0rB&ÃaApwl&y h0LCHE@2YJ>U{"y(d|qpw 9|Q)S`KX?H!<(,/ ̲2CjԆ il>\5 H #!we-{/p\{]^Z7^nrku&޴+J6'zbI"d?&OƾQ#flONtf5{Om.v͠p4y?eN&XM$93 lݭ~%Qhh"Q@+GQ4*bS ہIH~&u._ak`p r&(A .X>;Wsi8@ b  R5WjW9@ZvI? V8Vwʡ* )mp,p򽩃mVچ4l+ۮA,CLokF+J !!CzZR1n(*cLe@@R1\"k.m:P2pl%fPW8,M佊M}B@/x!IG؜mZ+Wj,hR+>a )b=:&$/ yď/xxx} :I"y}Xt ⩔hKۨk>=?C.E!춚s!={dtI+b`֩H'@G=BaVH,o*!M#t"jB*Lc"&ǗbF".!-xa ^ `.q(a l|ݻ~TwyD2&حҶZ&HZ+l[+X<+q'r' -g+'gLK+Lt쵚2<߹"4!A['`ܷ=x@m+n}j˪!es!y`XU^Ȯn;AAQKv|r@M0~0kK sN0q-^0k;@^I0?/3ƏA_} م1$A?qVw|M/D$?@ߣ5*bQ| ݇Ik @Xok@;pyg%1;[@.`E35ށvy+4$1sߘZ&R[>-1!) !;"Nl !G4DOT1EWt"Akŋ:Jv8m8"Ic'fIA'GRkҭ~xm-x2jlj7Žᢞ7| p FE8|j@FFͺcjk 4; B#MHAÈDI%Ĺh"JnuX(^U`|U_)YacYhUZjWkviVo-/ܨ'p\Ef%js€R#+b :q_[9Rv !'vE_H~\ &h g{jc!k(A5[x {֌tb \w0Ӫ xi"ٳ`Ǽi` .2k܂"v@k&f/*@"YV?&}cz`+,l Bg+,G>xX"$>bhD"QIdiXA&U#%$җq%-|0Mstq,PJ\ 67@4{, &y~"R;!G+*_€ѣch( )akJ``ʔ'0 #B %.evFM2D&iP_YC&3LhFS|1S!*P+G_@$R2D"D3aud!x=T,lw}b%hCj冤8MS׫.fv:[{n.SNv4nW{Tqv1fr dc,]~\vtYE`I@@4x4H9^xZen'B)mWЁKAp#p:"-&* ^.&X>dd'~Tu\n2E?n"ۚiY=]u1L̡C},n愢2 te.J`K׸O C_Go>OCZdx-_B,X5m_F;Zf+ bW(wh :5k-\5j@,@Z;K@$ 䑹?ʢ+[ ˸ YHXxpHAtt|AlA BB|#*ɲ̿[&eHH"YCX[V/ؕ`VapPIlPMٽ.Q ƳPKkD)iϭIJz=9 6(C.+=%T jཬ<2M|8[ ΄d >;exiӺrPa6DQe 8@_- ̻b[}3N!Ψ{3LS3s Sn6BO# %Ar5S }} %DT,0Ql^`ުImK)4xT 2&}b<#ƻwueDYZ6LKt37s\ӼHH$;>C郾ghب)ԕ=MV)(#$N 22|4.:OaqFX'$F s{&NSo,[`Ӛ&Z`19j1@j4+ {}q0/ x/ݹ'Qc+Rq5-'J%sЌ|~92JBXxXhXI7`/iCQM̋dϏe\ [d3 gTY$D3kaA#TL}RJ 70xFb2j%vp@&#)zx[UB'p4&\ P2P+8C2 sI.ңe/Xhm3ULdI eMnM|mڬMkFj*nz\Vmu{-xo ب:0X`0(r2:~o`7xѭq2ɊvJRB%ZᩇY՛1+'Ho$JDY\Ѹ )oʣLjFRf.dx]jeqTO l82p~8O'CځrکbAl3z.pj#:8Qڌ 1/0s'P+JoIz aW `P'#,w|i3`DܿOu|N@v:@iWϭÜC:pwP~qn&oQx)X :xc?zuAv#%\z8p5/@hї4o)74U#K;L&}x8y荟yUcҗ-P呿Nλ𩯞{/K.>Cs;s߻cn5?/w~~ZV-_㟿IO65Մ@#!:ҍWfii6ʋ (}<En68D}P `>cJ+\h6Y7ܡq'!CATE<`SHh;sˁZ-] ̀D"l/Zc w֤U)т D#xE)zwxG+jD)b(H"dy!kT[g*II=g,$T6Ă \7H!WXg,`r׺j~sn壑؜lfL`$&jk] 륏Tm,m+a3ߔę~O]#K6@XR^J9kVEfυ,kӠki|c"(܏+*8YVclpE;} 3J=cS7N4 ܔUg)DE.>?-Pi#a˜ b;C٨h2żVALR\K>_Qp*iT;*3Og1ḑ7SyIWS?IOF45:vCќ^v8}f;rVuP3L(6Lk/:lTH$C,lkOhɜ׃kFQXTp{sBpP5 T$ w84=K 0VQjO}R%0k7/B"$@;8 6p,`_7\ԳWA~8~*Wz_ߛ|+Xԏ@ƴu&BMKyGquCNرM;:udE`9bqc&Sy%uCA9`% Jh; 7<X<]bs9usG?$tA %hJ7ZszŠXKJLnPJC!u;W-oiba sX|$46J(zL`/ě___lpB5LGգ· u@(^cEmJ]C m$upT:+j>n^37|~[ޗqcay#Ϫ-*oc-C0^ȑ':6vz?r S #nx@gUs6jb=GA?BF UP!5"r pZ4Tj 46`Xx8\H ^? !?A><@!! "Qi5 PE0_>"8< \'ҝ(]>UBصH]>Bp([p_8 3>ԩS^-KR]4iH} qi%deCqS%0"p@gz@ڱ ^i%p e@vcl)O*DBbbud)ɝ?[Ai[)dLj1ɥfeIHfUSQqyuaƿdG;]Me{IDuIuq ;ŝMf%@[%Gܵp`dT2f `3?$L|fo=8Hf:TQ؞Z ):pPՙFCPV\Ӻ;Td͟ -HԥQ̚d`Qb!2Rg!wVE`fg,E/*;XQ\EzIpKdQLO)d`^VP5Pß6jwŊ580d5蝪m ȇEF`PbLhgVt%J켞jzMjbD`(Ư. kP4LFd؇WyXѡ +jb{Ձ$)qY0_Z$>Շ5tN=  &k,kn@(.pz_CƬA>2,O@P, ,r@VbgVbPvɮ9(%6mȈЩP8:ӒU_BlnЁ(,mJp@ɺYĴXٚ٢mڊBij \h%](L⭩HmNHP< jl:nnJ.B ^!]TNI-ޒӆiԓp |lKڠ DR(r.*d|:D#*"N6UtѴL 'ȐǴjY#EDzʉPS ̜ zo/o/o+R =Xno,0]AA.*Tbpk4>#m=q>ʤLnp kI`jĘSѓgRkMIV(IN7401#[cqksq{q'q;11+qJ 1?qsWCZ6 *FRd(X%`4ra(&dL2#Sr#W2&_2#s&w&{r((r)))r*2*/"r++r-& k)+#+r$kdx";F$o/ a(e 3&"2l lb53j3OlͪVV6Ζs5s63ʲ::s<6c3=o=[<3;s?s==t>3~<9'46B3C?t:+tCC=sgsgֳF,GF۬85K5ƚ3G˚tI4@g4IkLstKtKtIl>X'PPQ#uR+R3uS;SCuTK"TSuU[UcuVkVGPsQ{W'X5Y5Y;././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1691062243.0 reportlab-4.1.0/docs/images/jpn.gif0000664000175000017500000002442114462707743016576 0ustar00rptlabrptlabGIF89a!!!111BBBRRRcccsss!,!H*\ȰÇ#JHŋ3jȱǏ CIɓ(S\ɲ˗0cʜI͛8sɳϟ@ JѣH*]ʴӧPJJիXjʵׯ`ÊKٳhӪ]˶۷pʝKݻx˷߿ LÈ+^̸ǐ#KL˘7@``ΠCn@@: @X۸=lPmh-5KcϮnxe`ȕ*?W6ߧ7t }e:>xG/!TهTpK9T@)SXT)pZj$A paBZpWgZb)tcj:>D$cx*@eBhqAZ%bLrAP"h!Q*nl90Оm Xt6G%0vg gpD  @\{VCClD f@ږApD*i@%z[lB]s֩mw9@"I='Pzك+6mvX) v:;AJ/ պ nsڦHh$@*tk+Y-8P k@{~ tkZ9ڬOi @ @PI.y{ҵl#JGoQ`=6(P1 Z\@>4t5AUnaxO2@Sߝŀb`mBิjnP*׹ :C@:Cf2Z hр.O6obtA -.[k٬=a@ @/O \Ignmz{?E+s|jG }%?(M(=vA4 D20,HٜrMl2YrԺ`ñeH6&`NyKݫ @v{)Ag$zq]Weu/@mbB-n_`0Dr܈#|j] YƊ,p,4B1B@ ,S&b`dIbnDn  B2JHcCɥ"2KGBHrR)HH0}w#yɗ8 DCPc'D_µn%Tkd- +Td3 %WL fq ̟5S&be}|г!Ȃ_"dH㢌Z$ 5(NRUxcJve@M2B$(:U R'Wgd-ɑ)2+VyP>9/C<"ncDN.b'HףύtQiIo,|–/jj>_侱\ٌ|>g<Iz$ml81Zp~N^yk:ZJ()+! pGm.5H5ȩǒps^%3~9P*'ؙ*UW+$O2O ,y'&[`5ɞag!$?zk]MH&报YY1g֙Q2B@MԤmVz䔀 aBKI3 > 9O'l /MJrDnWICD))3k-:/uE\aӅƎ_,ٳl1B. <ڔ6*n{wA@rNvnq·{xMLljY"̅3ZH Ca3@h-8 2)Ij[v5DHS8*C2;3n @P9|<]9`ӂ 0_\Rb!^I!:껲J.hΆRyD݀Z`g,5@7k 0< C \h=\ΒDM&4M{0CKww (VF@\LOx[HBQ | . TT͑t'f@ p4D5M+>+IcR{]i#_I7< $NWN*}4wDZw! 0Hab7&f -@q|$.hq7 Uztwcwu&u's'PH0W'D@B2-st&csH}un'<؃Z%,&'A"$-/qx}aC}1X35ʧx`=veHq/$tg8RBzAvauՇ64Ax  * `c'US:q A|PB%Cv~!+@=5tR8nx32w/(6b*()s"97.p(\rBh96VCg5EC҄@(E2X6Yy oil\u-$2&Vb#V-i&(@p &(е&_r,ْ.0294Y6y8:  ٓ>@Bn;)nGYNƔJNY!!hrk[U=(j:r:TQ3pvl9\y&EsXȃ}Ƣ; x'#a525"trw*r Qwi3?tr% 2b)!&#(US%@b*Vw2XoJiƁt1qw( dв5YO~D7ѝ6C'#icu *+35?f^sCC n2+|XERh>3x 23ũ; PO )'^T tZB94[)U3ȉ16cd%u?aA@%rT;:PlW2;LF:T25/c68ʝ2;!H#؉ H-r0x:9Di*ty&1RJR ahC:1e:vpC'l_ĦcR&raht"?1ġF1jUf#887 :"U@MJ9cd6ѤTRZ6i%?G  *2h>TOEܱ}x:.-ziڹ3֐² q9 *cJ&[?qH 3G's{ YZH 9LǗ' * 2-"XSފ!84R1J; @G?c(+ j?S$ES,k@?Ҳ[hbY=C9t[v{&AnBn*.C h#a!@ӱ65~":Rpag/bƳ;ŚJt!7( ԏ\Lwp><gB3ܿszA-'޿}}i͔H$4Clٱ=@xB whҰ:߷*d]t 8qH 0 ~Gم\ S Rڠd)?X~h$nDL 8 a~cYI&G" QTN*lcLilψKn4E"*ޝ&ԑXkrs6 ''s<ߵ~iTœ¢L a{ypi&@ T'SnP>]xN ‘6L8i~Iw~rB Q3|h/R4-d.ݸ1/D/  Bҹ חPR?T_P%|ϯT#PdHPi'fjE`Ckp/ipf¢pis=\km')HԈm al렏,_&.LjM7=_?f߃< ,K}pDnU66TS#oolُ|mkσ7oo$N9p. 0ƞ,!A  D`B >QD-^Ę= A;"4PF-]t , HSaMN<0iĥE>Uæ' pVl_"(If!2(p@%D (iWOj l:e` 7<,XbO"PӀ "lZJt2'rV0gDC( ue!F9ԴJ W,>\rCJ h.q hn@an@Z?C- qn٬Z dP  ' BB5 𰁠 "q@`OTQF dP Bȳ U&p`ؑJ@C K+10#:2 r ЀX lF* b |3Hrе j: Qdz9/4, N'BR0I F?5l2'|5VXCKe%KDǯx ȇfsqA4Zg/ `\hMXCWL3QD=[55 2p%"5~ 5<.≯d6c-LRKU$L^͗mlu褿NY `>qdH ~򊺗 N:7̫ 0!Yz!t `یt6foy;?{r[̻ſz3JXj!l鞛 Nh0C?6ws&}AUm(nс؆6ܞSND/[y]MBGz;\Oh;{:D}X(3_v!GibK} `BgkR2%H(p0=@~]` M ƚD!29>RB<ʧDSc_Ї?b8D"шGDbD&6щI$ /9c:b~DTE3AHJ Ka xNB#3j| vMOCNhwQq8cEn!-/6@L)#EJtIBVaLY$T%c8 OҖ)H(Q&y-9̚XMAψL3Nf LjVӚ|lvӛ$JnӜD'5qӝיrƓOg>O~ӟh@{MlS& T}<(CcPV4@Tw J*b4C-ɦH";iJr:)yR\*S|0 2+!Hg$G[y"e'Ddib:ݱHVČ)eᤀ=!.c(QS!$S^+UUj%bFhŰLhCX~)^MeRHdgEX=&2苎e4$̈́ YdOZ s8e!<ԳqoIZZ:8Tu@&H$bւ)O|sYb4VAP p̆L2(Pu&Rd}ȿ݋6Io{U`8E\ ZA m袴N,V6L_D15<=>Ċ/SY dC2׮ qtA8Kn(Ir%QhZ[Dܨ#357K\$mnluPTvHdDL!}SQ0"v5|ĭ_0u ٠fuc';>4>ן̵Hyoֳl$@A lxg&FEfPQ'o\9 XA!&6Rj7b!(\sriYtlnd 8蚾ͭ{>v>]ķvna4 ƚ E=JA@yKԕ[ ^GIϛɱ"/Q}cW]j"tQ Β XĞki۹{/aON'χ||O~j廒~ůtտ澨?{I6#=׏")mrDyJtS@| *Ø > @[ ?m4> Ts> A[ $B{ =[;$,%#B'dA&BBK)«%0 .+C1DÑ"C\CL7cFaע(8eDc<lJ,: ʹHj,L gO,Og^^^ __+=K_q]>}_ $ZΛ]=`#F`Uv`6B9<&Ԋ`a#6MC>f1ta>*al2$At* ޕ=b*b%^bjb}bwbpbb"5'xb⅒E/!E 4^Ĺ64vc9'c.WdaJd-^d:>\a}dB] dsjd1dodKodPdQn eI>eD^UdX:eV[DIsSU ePQ9b&1=GVSRE~斃RfN.,}k0şflJSigFSr.StN. IvfH]T{g>;[Z}h ;././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1691062243.0 reportlab-4.1.0/docs/images/jpnchars.jpg0000664000175000017500000010215214462707743017630 0ustar00rptlabrptlabJFIF,,C     C   v" }!1AQa"q2#BR$3br %&'()*456789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz w!1AQaq"2B #3Rbr $4%&'()*56789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz ?7_߈_5O xKQa:v$ΉsK4W7;uUUB9v8Co#/oIo:ؙ.֫N8|cP>$ ߝio7x+Cԏ{vGi?ڧ;<{Fr:}OVM-dtT:ΪîdO|||]`xÃ#ݕv ㏍F|[t2ZU#> 35$/pFyQ>;Ab 2FHM [_{"(ԉ+g<dsΤ rr~)/\x_UI}k5/7ڮrzu/sss&v)fsOҀ a]z< w[HxꚎ#FB~{5jo7wc'=.-B.-wnMT^=z37^$v?|oj'O/Q1v<%|C Px]oN#+kWg ~}z#|d(9/]jeai<ڧn3 O: G4UfʡaHbWrQ=|O8#)mS?/j쇍~7 w;_ޑm??&_ڥm S/|ϱid.4.TrO@ 4?YxZ<,nî\`8ݑې  |d]g /ZQ40xB+[p.mg mdJZ~?}&2~sIxG6 sjiVAUc@Ω.L;w6cLe s^*ú4/܏jGlTvm7V^q&{ XU m|73EY H*&D6?2G?L2?7YZoۏl?s9:ON>7[Go4M.|r/5;[5%N l;x' h< ,BC6w\}'nIWlnTvcy='me-M~`S?5Juoã%kWRZA$n&Kyg&Vȥa`v =o[;<Ğ]oKY<ڣp]qWQkC Ķ$ɴLcb31v˕*~o \0_ idR="'ǃ߇?%޹ |d-ow$~TM7BV[6[1yύNhMR6j-tG0ʡPI =ILitq߇F_ޥZg?5j?[2xXEMWYP~9 yx⎗'Sd;`O&KB (,LRHëPg? |Hڅp.|4+Kou42lqPmoj^jVtyw\ʰ͑*,d} xg?-:t#hK57#sZX!T|UAfZxLӯ=-]_ЎU2:VWRYUெt5<]G,k-.pG pơGÀ;ǝq~(i N_Ğ 55k20 7a>y'&E߃|O`뚣a'<8hʇ;SMƉ^wVj3FA4TKc,:/ě<:?%<4VV$Bz)6C$~~[KҴ6:W&K*E $P]z{2T};Asj1Z 2bp dM{ĞW~%C֩#Re/*s$/N<=㈊FśK@ Ub>۟kKK|Gb5y!w{hc0690^9ʉ?w7 5cF/|ek~K?rfϹOnc ה{,SAU?hoag_o8-}fY31,ĒI&Qt/6˭B w ei_4wg]Tr ػw.[U}xV/ tRܲy$NĻ+?xv>$YWvxK%l2(;wî]) R9׋<0cx™X5co+3ҎV#il!T@@z}k{\xW,a)%_x4bv薠H܅pBV2^ˬj{CL۫k2u}A- r8?͕ Ŀksy,gemu?V EH aVGۅiIP>?L &x{I?(ķ>mBֲ Z*F9,FI m|Cu+ C:yIѰ#!  kc{_Bgn֏{yatq>R&K+ $TcOAZ KimUE!I>0XGu.yA-4_ |C=F C#3If%I$ |K^|m9>&|N>xnKBe$20e`G|4ߌ:7>/=^kdIKaCoU|d /x3jW6^(Z\L%uRDIɌ!|"dst}:{o |AK!|4V"14 H-I5V-C6uM}if% m73*1u7o^/MMT]3šK%GmJ Yk;o u+VZwbhc^h,7#pyV@'x@um3R}i'"pإ2(Z81V7$['|qMJ1-߁xPY^Y-#QbG$+<;Zxg6ik:^uC_YX*yZN+ݳT!Y|A1A5=WIRS%r+"2H8[e3A7 4rF8#ȴb*}ú]#0Kxf8jbq񧍵/>V ml*I ThIOy63_?k2km RB ck)=S]tB>ӝ_:HAd.} .hcfşnMvxuwPlOGtr\y^k_ۋZa>ͭŭKeig$k3)gs d0<B@8}su|t|='o}dLۮb6FR뻲~ w_R[H_kH'f"G/{ +Sas/Fڳ0rAGR?GOţbc7&'Wp 8- 84l?ghZWmmmٺ"$ j$Ku- ׏68%~XgGUnjM/>0^Zizۻ^rϧNJhch`ʾӾ`+ AginSR $:|v&ݱ*:ʀU>A.xK1`2G-$GWaFGE~|Jņ6nE5RM?-Jv\G(;YC72HW_o5-mo<[4ctPok +8ѡdP?6Y/@u?/=Gls\/}_{P|5Ƴ_#Z5-m/,ZQw`$=s2_k!Ŀ) M Z32#8㟍'7~n<'oKk WFcI{tmɪ'ƌDCȈLFj H{ϊmR’xN-A 40DZtRФ#[b[~վ?Ե_mjvvCDkhf"+<<ě|JgsR=.#VFUm퍨w➔|+&&|??5ֿ]Z8scV3ֺb<=>+ mƭ̒u\pfc4#@9|1A$cqHՌsjUx*`|C~kZ x4W7-Q"Ȅy+d 6o]o"%d\# d’ 8gx:Gu~-U< UCeDRw2B(ß0ⴣ7n!KuxMm_CvZ"$(ġT6[_r)i9ru Zd$ Uƌ )ztmf,=߉_×oB}JÈC(G[*+F)A1/5\}ޑ%׌k uHe8efVe$hI<8~ݭU]{Ñkzmm0sua 3}œȍ\A#o %ڣ_[F(^-aЃ}gnv.q9#[Z*G}NG\zWg:Wᯄ^_xrKE.gq*쬧A+g?/Qx-A쁷y;NYX`n?|ga2|=hY=uklFl+_gOđɧ|#Ze3%hfȿ4# Ãؚ? ?g|35Cᎇf2&-+MzޠJ|@<$x/'?L ^t x "?%2i7K(-o~x[ ^yl3iC5Ӡּ=:CĶwZ4+e<;㟅?<#lj!xGXeͣZ%αsisfpufȑ$|P%> cSx w䶏~DGy,RUPA H 3gf쵤xRڟ>hq˨.$2ĿvXe@z @9K뽟]"OQuxK] [Gf͜,$\3PΎ&jO o'|4A4{Z$Z = R:bfb %稩_Go ?7EMbO-łx8d:Ez?5=6o^7I$G.y7\}@I)>%Kɮɫi7ex|UMƩow-Ab"[x1 [&bUeSF 0|A/k^6Wp}oSm,~ ! ױY5O[kۻoDmG NV m)$l |)gZl:ٕ֯rp5<[}^vDxPuٴx Amis ,V$FKm5QMK/? ![!k3Ks/BI>~ڮ R??c.,)i2^Iy) xM[@~ ^-oO}#ö(4gH9.ck(#*IBKit 47Nѵ]/NO ]Of4TĖ /no/J@>v rKz¯٦H5I>xl@iwR gL-"2K;b|YF34gne=ZÖp g++aApA ڃ6ڗ5[fѯQk>t]kᴼ{a3;cVf 0I"iJ&]|qm_ Mj)Lj6v%Ǜĉ&LfuyU!ql߳ M _QK62 D%+Uq̊9gfw7׬? gV$O!uD6_J ?LBbkk9F\{P[5z|#tՇXqD+su !d0Y,e+G2y__|3zK#A߈cl[il;H"-|%e{~~3vßqGGuj3vyB-D0sœ#&gGQYa},ekԂ0T@C|V"ԵoZMee kRѦR{{8WlhഌJG}AV5ٛ_U.|'Kf$W2G# ʳJ61x|| ]gzoZ.g5"vy0D} f©8PI7ƚNJfob V[~ o}4;ogU cN+hOxYk:dWu,q)IrV,(ܘg W65|c%qE--V>jq\c ˟Am}#*-[{DsHnUK ~:4Z$ڧ›XƲ*K, Gc~r61u ILIrvU J52K+^z@0|&24MӼ_5yk᯶5W+adbt&?g(SwFfoٱMe|]{!;&M [G`tBc8Iٗzou?mR\\ƞ(Ŗ}4&ѭ{{yIgG,2|/T Ih^j!~.-rg"WglO|?';=4z|$̐F2@2XG-)gmOJsދ%4R+ě`J rEt,zů4:ZSX},lf+FUnngv@:h|mA6j7RŦ\iu s\3;%;;bBQyPۧf?lx7)|!O/K3ۼn:n_Q\(Z_.n AeLv(wH VR@/xX;zZωѴŵ"oĸ$4I>7o–R|V6w律w[xᎱ)4o4!s +WӼ';g=~&eG1,4ls({8f")#F@9*YjС}kM}6l9Z2$dE3^^77/ށijWjPundyX,c43|;ing_|KP]ŭZzR4ivH?DNF*O=C,²h%xO09@oi8k\<=+w+Qob"K~"2RC9-i^#)x'zޣJH _NC\-ų7*#, | i0j^_Q/69c;K0^Ms߳/?g=Hֵ iwl4{kHKɺ`F,fcw>~"x'g5~%mh}imL es([b@12$J=oYAGn...o9@r7x^Uh:,%w &)Ҵ}}QY[Ew"6[ykhz5;+ŦQMaoҨ%V"I'ufu3H>g옗rٷ--Q'ʓ-_u,[-J]BBۈ6<kƟ xw~2t4EhS*41ʻf @6wj=OǎOa^Ɨ1oUBmLiq~%ha>n|_ oxqPGKu1u&ʬPHaR5'_?K`| }®}<߱VaU<ѠޡMru&)$7Iv4-i/yk)! Uv3^|6n7db:'yW?~"x-Rӯugmf+!xK4)Rcw˳v ~&~;ү'obS$ Skl! ?P_Kis[[L6 Ϳ[Gc-!KX6wkV?vposy-Meh 6T2Tq9kK kxq|'o}Y*շ+ 9vUK|Ç;-&X :\ "wJcUkx1ñGjWgzK6)k&QhOl|GF3;eٽ >.x+GMwY홮2!y~%4o-Ήzqwwk[V(.g.S* +&C(Guw-wٴMpX^qqu⻈m$@ K$}"@HR}{ÿͧ5)4mŝ[Q'f+p !2iMw&<}/.|kj/\Aq"tHX%\3ß|iZƍ/nŪCKs$Ĵceo3.$rZɶDTGbA9㴆T[ƌ}𖻠/-hoǨF䗐O;VqKx`.yXv^;O7uGдSaЭ-fg^Q0[1dDА$WО&4O|6kmk"PX=k4/?5VujךNKT q$Fy3߉?jֺ5j7#%ҥȝ?.)Jnogğ4*Mc}mΧ{e{cnז o Vq,I ߣ"Q\> :3Wx3Rx&c$:ڷV@wB}'R񆍫Yj)<~ J<@dծeqqUAi2Tr?|)uJ[˭Ӿ+fH4tD^[QTFirVEhQEygK/x΅O ͬ^x/Z>yu fGLɐWAƿ/5xc%Vu.|-W3`ia]V-^2`#K2G xͫ:VdBʝp3n# B\_f Y"R_8Z o,>v0sxč'_Ԟ,Eηq:CZVm ph$fW\s3~_GmVXhm#12#Ã79pn?\Ӎ­.W_=:Rc+-լZr!C2  [CGG[-4;Vl{ YH$V=ÖHduv'> Ǎ]٬F + #l\$ԬunRҭH#_]24QAXzbN&Zw|kLѡ-ݥQ :czF.JGN|Dt}SĞO4ۋMY|=̷%lnƤ˹&di'F-_ wh%Ɲ%1^S/'FuSb X*էPO,V,0Ey/Uj/O.RVVPX\Zd<)Ur,|+$[+ί3ú_m⫨x%蚳|]Jt{HHgWhWzMϋ>Xuxi~,<տKqZ1!(A?e់ts\<~ttK$ IiDT"NL{H-6,+_|#RZޝaXZ)ehՂ$6A/ᶵGo j:ηkzL({zFUcHrqkS~=[W/o,<)K麿u mG`x]H$j%Xv"8WZě[-wP񽽾:ljn<>ַr<7+KDiU"D`>ho<#S:y8 SL7_kuyc^jw]^=q#WF%U+ Oq|sRe`k&x0{d7ݤȮgGM, O|eMZi_5>q,\7F]$Ć]ĸ; >6wj[ƗvmAl.d`^^WBK"IFU]'? |Hڅp.|4+Kou42lqf7 ʌ0 xY$ry}OH7xKb+s <1"w 1 ?4xrIVWaH|Yb% dWuTAsPX}^32h=t^KZX'G5XIl7.&ȱi(vȠ abPS\oOjq/g4(xdo#4~ K yŗآ<"{e3LXš^|O4?Cx0Mq_P|Gw86q nVV?yb7|Swa6#Gk1gl%iY@Y2Hn_[xFo?iF$ /|0KDt2U ЊFu%^mF-wt ڦX\*>=xnOv^8[h4~xKhh>]WB9G |3GO $ֵ_iGre.i.߅>,4 x]CMO\K3.κxLWU– 05|38"궚%~]gLDw,y,)?'x⏉^4L%zh X_/ JvJ:807៉7 ͢0?wH| M2_ǚaaY>GCb.LZkĒ|{Guz4UWlmefϚ(ؓ|B֗ß'uiR^){}>渘%ބbrT$I|iovgG= un{ ɦ\j66Rjq5j %_%aPr)yn>>heOkr|;׭D%kgG8.#܊ϗMwhگtYihZsWZח-IjH%KX>T@=Su~5=WZRxc\Ϥ[ 1,)52VE wƷdoVrn-BL% ydEW>:|77X<5c:-Nl2KUc@T`+66K+Zx`xkPoQ>kS^1IQ'eܬP̠?|LmFKӮgԡ_͍ndi_+kƓm T0k]ޭqi|I@֮4q䦳HeCcR9|O>$i In߃Gpы*Q,}$Mۘ ,Yk\SkoiAGw:MdR϶` fD(@K~&oڗtfi,?k`!බLHq `U~'> ?fKQկ~77rK3,ʼn$I'5W. 7\&El`iE7WpK$vZc/Eu⟀c3RЯZ^t} ج`&(iu~)|nĭNz_:RF HF>zg%&Sk.0k%&j> 2^YN~UhIF# T1Xv־Ask/hg+LW¯D]9wkH2ꡢ"L0~1EwmX-~xN[o$ƫ(J"GP /چƞ*v~n4Y/!2ܲiK]RlJ$w2řf`8[ß^x2 x}xI+[˒MZt2+0jI T[¿+UsxA5ɵK6I$H] erA:81=<+ U̫Yl$X,^$rەRĄTMu i_/|=IR~WS(ÖҰ*g˙Z6sX񇍼p><ͬoMֵXNXMkgo-1h8s ¤=b/5ϋ c6]c-7D8D"Z.C6\DӴi3&ሣ>#KkG[ݜGc1@2ΪmbF~E]jww_ϭ,+z/4xy~fxm.sG5VON}9-"O*H-Qi%#MB=lI kӾ5:x_ԭ#Hoo#qZ4MȢ_4R*ݗbG-"ci}j|E7PȺSl隸Ƀ2Gv> *!b^_~)]tdnڽ؁vy)ДMTeVOf /pXim-x ԴĸG2|ܐ>,~ @o;mWQE٥M>(y&Y]3oo)|j:w"D#4"eņ61̘$>0@G#^$5 luOu |c*>DZ#+XF<9nѲ:0`A#߳oÚυn@ѴKD{Oeɏ_fQQK"4,D]_>'EuoP|`x{Y.KdI9t hǟ ɥ&;I[LV5nf#as*L^oZ]jk⫗ᶷa%bj,H=q$8P4Vlf(`4v*΍i kfj/jVJKH4W?V>j5?gZ+}hp" RY6Υ#% cw^/}sE5~B/|_Z[-tYxVgYZFcouc~?MՎ\摥/֬,mIo-Y'&5m꿷xW&-;QtDՅs_jYݠ_K-@.Uad8FscޒĻ)4K*,oq л%Vid!nv,D#/8čwgZܧۗᇈ/ḿGgo6!xeRGXǃi+a&IkWxt];{ieif)o:y×w7$qz.OKt{GuAM649;WQTC[+N |ANu-.H[[]]:KqnDiBˆc<|FwOº:暶/5k#R+=.'kw : m(*6,4;:ƍ+YĚq7}&xny,DjvFw?p'}PVmK/OdXv3(\n,p'wUkSye >+-Kqqª 2AvIjm!Ў6_q0n}YUXMVÞ>-ȑDai<ui]4 Fu?ɭ[[ѼE "5t. FyW YPl?*<_bgZ6y - K mgc猜g5?jOcj^&՞}9ўK>MĊs$F {6*$9,3>i!eOU9WSw~/) E[IR?eVQ&vS7Xl ;XxS#Im F2FґXy qZ?MHEKn R= )t.X+L^3J0Xn=wH׮_[CsuYY4vk; BݛrYn0WQn-u/~'kűb$ 0Fn$!3d^+ѵc~ կ9nMF#4T M]|3 ]G^ }Ɵ곦SZ}CK.mƦTaeIB |Jt ^jZ֢Wz]+MXU1]DbKm;p!H|Xm™f"^;Tf9 s|"WƝ A?i^Y6xV[캂M݁62C(bJTaDo&pO YI})諥ڛ,k?6P𷗤o75ix${8dYW .ao݌u_t wZ|uusgH:R\"p$ni0M3^$Ҿ5|E5N]2D^%K[e/垞X!kW&ңҥҍ1̷H=}Ecsg£>$pVRotA_[O qk|@o :mi-baTglc|52[0Sԭna7I%ݳAsBRHaaϋ < Eug[K4 $ZFHt) X535oš'UtuAg8Wg1sf#'&`XxSyx45Os;CS[;ĉm hmd2nQ!\iwQFsL|]3gvwӤlxn.ItrrȎ _޻ΕxKH?Q[{v{KRK<>Fp#-K^}4U[v%aəbkeI2/80*k_i_'Q/$4WЕGVO@Eazmٿ_~O,xKvYEVI"<ኅ<[?x{qim+@zmơpwh* [$ Cp#ҿm&xcNJOZqV>T0| ̗r%/ؑy4jNHͽŀ?8RI*a}am^>o/kVvLtXuG[E)%.eX"}C~ u t"4`{)U^6C) EriZ?­o Ol|E둖hI{F@~@x;Zτ.?dkmՌH,C_~ΚޣnThzZ&b^j:l|W?i?%$YO[eUSkM0 ]Q%PD 8{Y<eSu}O״X8Vwh ME6#egSG7xo7^x_L4]Nm3[}Hof,ۭL1 ~6ϥi Kż꺜ݣhq{,%Ӵ\2](Q|OowD>z NQ&h0<-H6@ ^5<[Jմ_Jfnul;[hU![Ye1hCWQg4-:O_iD.mKu=2c&AgMLڳϋ>6x#6U$/3]c +2Cꪢ(\N>og;k>/uo^5 :xO:rYA!c 2%l 'fKx?9ێOq^Ha^uVkhw23ڄbHeۡh.p!cϾPb?b &WY2\_گZcuyڕ ؤ[IwM($?p:p h"x@oϞƓihv~3>a:ԏG@]ُ׆d)/H u=;YXյw0PyɧOŕUDF@2C1Oř~)h3c۟,]}i8%1889⼣SyWN6.p+eKbya]"vM(]aI]+2At4:]QdQq$3W4j\J4ᙤg/ZVzg» fMwZO<vYKRJ:}fh|Qbcޒ(߇Y-P M Kjl{UCg!@> }6kmPգTOgiupma<-|Q~!+I]7A؞SXۆנDi":#<'T Z1g;LB*~qU.UԴjznrK%vn 6sڪ0+dj%O(u52Bn-䷓k#  YA|åV^zocAl!=qYGqs-ŕ' ,/9];Pp8(gJR gylM1d*ŝ1 n Q/J-xYx/BVAXݳS;8U-o-?u6wjƷF4KO&е%Pw?m߰/*(?,Ҽ<ֿ |%jÖvZ)u8CWGee<b ^ծ6<15$dEkmo< pD.egs<%}BU69 eCV1Hqr +/-I?tC4l[r%|EIL]OEo#_mlv+*civXa7  q?|3 w|3AE59h SŞnSW^ѭÙ1ہW H1m~×6%֏{Ka"*)1]}7v' : [! %ǵY6"$v|iѴ+ǭGo iqz4:NKys=sݯ`fHY?N}BR[ h?ʺ}"_"(ČYʹ#$ dKmCvx'x";~?DbxOɍý0@'ॿ4˽ᧀ6O*$,#2GVV^ ޝzEwCxZ滵M0O,:]oT?tWw vxZ)֝k`Y$p[PPdc t_5?ז;>igG[Q9]1=y n]߳Vs-/]\|Qsng*ʟdB_J>) ڙuY_H`_+H` Tvc#'v7?msS*lOy|9i30kwƣDHUUPWxJ-bOkg ɭ66+i<֑l r\A3GmGMHm]3Qݬ LDֵ6RQՕz@mlemZݭզ!5zƁ5 Xs^?f6t&=2 [%嘅FXdYDnH}㟛 ['U5-żteK*1BG"#tQP$! 8 gd|d[:x]_aY5i[중q4*JHG!A U66[ [C׼IzNx4k&ܤM%5rn#.UQهo&i~.a|[cwKq0=7,e"8TQ(ٵdž [ëmͪMsX%AUWp'$p  7] RJvvv~K4),ňrHkȿnB xǂ aK>A3_FyA $:vZf>sVnGO[f5T"8E|1[/|3/ڟ<I[T4}>+KEX y,hfUKfj k^o4;J3Hq-oCM>.W7^( rE_YSA̸'/@<+ccUıx/Y.NZl:з`HU~̿!<ŸǦ\OR/,2K挑 ʳJ61Agf>|2%wLH7+8JUd[2R? vBKC Xka]k~/~(ڹk-Vhx[yGFP-g+|HG7O/QԬ/b𭵥?2IЬH)e# ?e߇o"V}*jNjb1聏FrF|CqyGT֯\W^Mc=p%3]YBiO>9v 4s"H=l|xi-Oqpvɔ>~^7,,|5ljʶz/-om3m1@F8 a w_>ǍO? < ,-߇44B/v gBݘ&>|I)%{쭿]x1ӭ\={ w*m Jjܗ=/ğ#GL:G'ͣ/ ïwXnċ4!4ȋ&IYRH؀$Bٻ> c6:|7hqеYJ_̻"c _5sodM;ZWۊ}s*\IiEF7|H[4_xK8_؏J=#yL;kE?-Һ& +.r]vX;Ap%x_`0UO //|jq\hZEfPKo *HՐNj< ~yMGD슞"n-SYaKGa [H{gI_мyx=,'VXkֺeF 3"18ɹQDjq@=}?e߃RmeKn,үOSJƟx2Aoj~Ֆ΋JR5d!,p7;ez'3$nQG_7[HL'ο |#_kkou>E1ꒄp#|qӑS#?> $/v_joJO?ëקPsa/A ʼo~k_-OSeGQƙqqwsGi"c%K19$zy&'HoكR?RgvjSŻ{φ [Z/`d#_ʻ呰;82E#ƿäP~ nW=ywߍ x~ԤEݻhLxvEOj>ҟ.0[#f(? Ͽ<#GN׃Rw&,)5=,-|pC~4\hǾK[R|sj7Ǭ#JuRrĢ*,|o;w-#H]G{&n oK1%I ^+GUt k-ܱq,A )xݖKk.gg+b>1=ֳYxWW;[ȵոI' φ}BS54{rfܰ**6/]xWOih:x3S26"&;70V9eM5ŌYl6ҧu%h '@F#Cq$=5O[I[MuK'oG"YW˴IXð|cxem GI4Rjֵ d񛛍y 咡U]WJ(~-> ]KJ/c_yM ԶX_%YD #VkZDZ#(Rd&#$\H5\m28#ƚ?lρtgKjh^"3*FF8 U@ڏ_Zjx1j֛{}i=Zvx-qLEZr2 (w}F.<x|<7f$hEbil\iI<|JǞ ԭ|O[k֓2"[#K Po~>7Ew3xOV[w`wuu%}wSL>$vӾ!FݠšMkum!kjIe/%)ԭ~%1MkȶcƮ_.3N7?Z|e_!oqEKx_Rĸa^F+ :캐Aܫ2+OQ -.(V[\V~|W{[LtM=JĬuu@N'E 2 |G(?"<=⿆6|gUm-@ \m_.3IXQ@>2G/߂/!x+_W|7i&Gń7V`d'Bݳ}̒ddE././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1691062243.0 reportlab-4.1.0/docs/images/lj8100.jpg0000664000175000017500000003025714462707743016744 0ustar00rptlabrptlabJFIFHH Photoshop 3.08BIMHH8BIM x8BIM8BIM 8BIM' 8BIMH/fflff/ff2Z5-8BIMp8BIM@@8BIM8BIM @pHP^ $JFIFHH&File written by Adobe Photoshop 5.0Adobed            Hp"?   3!1AQa"q2B#$Rb34rC%Scs5&DTdE£t6UeuF'Vfv7GWgw5!1AQaq"2B#R3$brCScs4%&5DTdEU6teuFVfv'7GWgw ?U{~cU6i"@, ˀ A*W5{^{uR_mݿlTpr\,pzvыUvS]uF-c]{N9__M[Ձx7MUsqok\s\[@ Wܟs|uzWRdG.Y߁?87cm&gYVۼ2sHuOځ4\}v‹7+8̆2p#E7 Wְcݻvxi *7x<"We*k#Ȭ <|OJ9Owb86]sYF Klۿ?Eӓ̎c1`7WVlu)ظg,{L9TL@ `w"e㲊WXV?nOJ3״|dd}ЦRֿkt贏C]UޙffrǗ9 .s|-ed!qr\?σŖf'-??Ѓu[)mn}IL O#A'ܭ5cEmKlkeگ^@ǾN^tog\w=os=rp,1jn\C뗫"\9>&S\ >zŝ7j~m,. GMo[?XXnk[nFe>skqX[Ѫ}xκbM sDsms=M=5!׬tv?ZQ;V{>-=A Oc]ymzgN{bF,H@(SuGe5mӷkmr,;^̌չ+{} S&(}2hs"|Nlbcq#ᢥ'dZ׹H}۾V%:bw.'kkKcsrcq%'CrD{i&0|1Mȯ&_d[<c;P,ZXs%8zN}*/6V*Y]Q\w7os< f%(iaഇ>JBecXegUk"&lN#t\xv_UWGkgKcl-\I~qYCH %;|Gˌ@~qg-i4h"9C.4;v$S<~95_Z]cZ w-OXa Kg,ĵC/imvkc uy?f7a4[\vϧ5kw}{L|>{g⣑5a5lb* va5ձʹdSvѠmTnکf9nx9P9϶ =k-tm I$K"r#7wh+C~X< [hn ~NHk$֎I#+C Nk H:uޑomh};G9Nek;XV>CS0܏_O vw(r5{6OuZڝg)+anq\U[n/.IMEgBe^R0̋~/=I:7|ioNO ZXuU &c\V$çA{F^:>eiTyIfnyH I\W8BIM XICC_PROFILE HLinomntrRGB XYZ  1acspMSFTIEC sRGB-HP cprtP3desclwtptbkptrXYZgXYZ,bXYZ@dmndTpdmddvuedLview$lumimeas $tech0 rTRC< gTRC< bTRC< textCopyright (c) 1998 Hewlett-Packard CompanydescsRGB IEC61966-2.1sRGB IEC61966-2.1XYZ QXYZ XYZ o8XYZ bXYZ $descIEC http://www.iec.chIEC http://www.iec.chdesc.IEC 61966-2.1 Default RGB colour space - sRGB.IEC 61966-2.1 Default RGB colour space - sRGBdesc,Reference Viewing Condition in IEC61966-2.1,Reference Viewing Condition in IEC61966-2.1view_. \XYZ L VPWmeassig CRT curv #(-27;@EJOTY^chmrw| %+28>ELRY`gnu| &/8AKT]gqz !-8COZfr~ -;HUcq~ +:IXgw'7HYj{+=Oat 2FZn  % : O d y  ' = T j " 9 Q i  * C \ u & @ Z t .Id %A^z &Ca~1Om&Ed#Cc'Ij4Vx&IlAe@e Ek*Qw;c*R{Gp@j>i  A l !!H!u!!!"'"U"""# #8#f###$$M$|$$% %8%h%%%&'&W&&&''I'z''( (?(q(())8)k))**5*h**++6+i++,,9,n,,- -A-v--..L.../$/Z///050l0011J1112*2c223 3F3334+4e4455M555676r667$7`7788P8899B999:6:t::;-;k;;<' >`>>?!?a??@#@d@@A)AjAAB0BrBBC:C}CDDGDDEEUEEF"FgFFG5G{GHHKHHIIcIIJ7J}JK KSKKL*LrLMMJMMN%NnNOOIOOP'PqPQQPQQR1R|RSS_SSTBTTU(UuUVV\VVWDWWX/X}XYYiYZZVZZ[E[[\5\\]']x]^^l^__a_``W``aOaabIbbcCccd@dde=eef=ffg=ggh?hhiCiijHjjkOkklWlmm`mnnknooxop+ppq:qqrKrss]sttptu(uuv>vvwVwxxnxy*yyzFz{{c{|!||}A}~~b~#G k͂0WGrׇ;iΉ3dʋ0cʍ1fΏ6n֑?zM _ɖ4 uL$h՛BdҞ@iءG&vVǥ8nRĩ7u\ЭD-u`ֲK³8%yhYѹJº;.! zpg_XQKFAǿ=ȼ:ɹ8ʷ6˶5̵5͵6ζ7ϸ9к<Ѿ?DINU\dlvۀ܊ݖޢ)߯6DScs 2F[p(@Xr4Pm8Ww)Km&File written by Adobe Photoshop 5.0Adobed              "   s!1AQa"q2B#R3b$r%C4Scs5D'6Tdt& EFVU(eufv7GWgw8HXhx)9IYiy*:JZjzm!1AQa"q2#BRbr3$4CS%cs5DT &6E'dtU7()󄔤euFVfvGWgw8HXhx9IYiy*:JZjz ?X6H"oLz 4I%>}$zL6rw]BGkAb$q)$oGs'T42Jp#^Azo9#>1I6Aq-9vhU^;juEèizpjiK!-?VV{4e¨3ᓏPDJ w@żn+iȞ̙?"9x;Oqd2VCt[\p[][v$ ͺa^^oYccm6MGOhT1ˇgˬS1۩AY[נV`WrY1d; . mN. tGX~#HIJ1V Iph#=*թ9ϵL^}^ x8wE?ucl &~#&8Lj#>%64X$Ь Ο:bzwc"5ܾOsTzN}د,1ʼnN҆5Hy>φ>CqIxj>'ijd&q<''S6l|g|17JK 2|rAxf#FѶkJaݷl#nsjզ^4 i {oV"":bMfbSrA bʖf4%]Gx_ݿkb@nINq/=Z[ʲ>UZG22X,/JW" A0d^U:(mdp @a|K+9"ѣjδFYxZrn>)Ny l.$B^I X;{A4)5jV֐tvz~c=톜EPBE6E9!Tk ĔiBc5>Col?͔?uTk}Q⪫r8cm)$OeV9~l6Wh JῑY?ݲB)k|'bdLDՔv'E}@B5ސ͂f1Ӎ7=l"J )r|{a+ @vh:SvY>/0,b@1:8wm7|~JOKgP8;JK1T e?Fn-D-p ~TˡP~.TZ\Kk1 ,,Q} \i/>O3KƽUK37PBs;A#1ҁpp'jwrB"!@FZt8^"Svm"@uȐzݹpV#$>a؆>2"7IpA#emjҾdL`'?KAjo78Txፖ/[bK֟ͅ?*3)A^' ʧt{oS~i4P=ŏM+>lQot)@ nT'7դ{Cib}M~JAoWͳ/[8V(rRi:y&#tQt ?\LFIVk>zmOMj#?&/n~Beɴ3J]"乺ǫ{xD/=Jsz$R( sΡu<2k^$Zf//y"{)=* 3}D<7PAߎ\M`ޗ`1 3gn]6Ëh`n9EA*6 [c]m€ =2*}K%qNWb̸3Fl(8.75޸$%dTjR+|[̠Մ7~3 h=D58oo- '6Q0@I'`C]>F?XKYIzE{T xL\z-UkJu%q^!ؙT=>E?|35 @ B7 ^q"mq7n[C$E[[[Y,Ik֜(JׯO[h^ǫLERqG41a䱙s^]cM IbNΑI _/'-B;N@nİ"m`=##[ /K[aB]6rߐs~bԘF đv(7Z&#Fp M#`)\ce>b@ԻWMxrskf/\CM!C3t#/wq_L}1|1ypV.eCCKW6\PB`#A@bwJ [*T؊e.ZB?`dy2+-Ub*I")插'6Q$f6&Euhڤn`+N&6߈,:} C2S^2*NZR:R?)wW@`Hu4s"qf<沮-٫bPM|}Wi2*dHAgkwor.-h~@k`I$J0֪4F `4Vy]E+ (|g6#{x`.%j)ǕPOVe!5 n4N ܁ ?-X<9,~y$789BjƖ~+@?}icw930:8go@0e+_PFFle0)KL6"pldٲ _'#=՞/p`*7d#.E{%!{dDZS}#-Y c AW]ΪWE(e-?aivo' !Rȍau7Uԃ\8qIHl@ja|m# dM"̛u%4U--'$'3Wlqp͕2͞m͛syɁPv5fɫa-g3bM<y6J,e8\'\AfCC#pB̀l^3dK Flٰ gͅ^׍=sfʼn{98lP././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1691062243.0 reportlab-4.1.0/docs/images/redsquare.png0000664000175000017500000000061114462707743020014 0ustar00rptlabrptlabPNG  IHDR$$nbPIDATxb@?b] eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee{GIkIENDB`././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1691062243.0 reportlab-4.1.0/docs/images/replogo.a850000664000175000017500000006366414462707743017322 0ustar00rptlabrptlabBI /W 283 /H 181 /BPC 8 /CS /RGB /F [/A85 /Fl] ID Gb"/lGEc',,kl8"&2NBd%Kaogum165&NYZBITmkcQDo:\lEnA GJETphXmY&(BXdG&0O5g!!*-(#S8+DJ,fTO":,P]5_&h8!X&eu$f\(VI^5_q jm)jbosgIBN01+GE&G/,0E`$J,.ogcq?_*e\?bYbO$E4*_M&A1cC@I!9Dd\' +4?4QDr'3BbF=2qLTa,V3(b)tC;HhK!DHiEs= #e!]_gC"9\WeUZ]%d_rZDm+pZHhMjerV*pJn(tTrkH8+&G'_fGA&n<1gUDI\ )T%dl>;gEVr7uSSD=[2`\)2)Y\8d.Vp$:55>ISM;g9k_IXBE5_odUJ&4fhbj +t4u*CCeUS/R,f.kn4Mb(GB+%B[KmgIC4%Q_Cr\%1,1M'_1Dj^kKfbZDr.!E F(WairP]R[bk1DXB:hnj5(2_GWLnY9BgP/'PUTNpnM"tB`!I)(N#O]nba:,[ 7un]KC=L=e,=d\00l5LHTgOSF))>aLTKrYb%NI015l^i^qt9:L_$;(Sl-nh/ pYP5l]D"DU][No_Y;b?do<#LYHN!Ng-V^$t+XoX`J[UDW6NstgiU^:#aXJYf @T/-h#kbk9#UMApV<$^um2e#j'7`g:&J1#=2rAubQ**M!it6f3,*@pVZY%I6 6o/H!J4.k`9lkR_-;U4ln3a&Bj2[3$3u/IFT]*eDlR2scpu.!iLu\C$^CPtn H@SNS^AI?QDnk,W"$D00h*&FIlDn4&G3't(Uo5[]m!,=p/AQ+U,=dd\o,oLh `[7$Kifm(afHdLC\5iol9&c'@AXlrl+e2TcVCt*"D43P1/tBd4IK''*Z:Y1g &tsE#;eD`AXDo:8;HP?kPAJ]<++5EP`)3&A0_Gc=bj+0GNAo^=jcrnRI.>2- ?@.[$o*RI.f9aJ`&3E/CRVaf0!I//;.6.N@dhWJ":#_Dm4P7SLk/f_K3$fY" @lB&>=ZT!#RpKMq"Z6@j)ODfZ2)o?9+0oW[2)q0V"P i5SJT2Aq@18&2N,MORue((.$!o41l.*at,LGSoZG'&i)k+_>o\;RS\8iUnSbf.@["h4W^daDC< [+g5DH18l\"e-&NZV?P&#\?tUg#Q>8N;^H/+c'&47a2<,ZndtDk/m0)o'Y9I "Af)p(^a#(U5qJ$"NO<.;GoitP^.[:Han@R-"EJk':6\TnrLq,.c]R(i1M-HV6>$DWiJnWu`pbXf8^#tsp$Blf[o2f0&&E8Fj;UkH;2KPeTN'9<-` _E>O(dS$eNYO@/]?Jm>IbNhuC)(3i7QGjt[o_n[]],>Y46C;2%ZOfU,n6RL6 pQXGh.Ts48AWn&r=TE#APblWI!jfTH5qs'iZ7I([Rcm#)4]s3/IWG@.!hl8% k"5Ai2hk31"fITC&?Wl%R3r7DZT<9r#jE`;DgM?VnOPTHJ6NEF=DX0oV=;jR N"ee-'gN(,,1IMA,*\r!P!#ZJb/Yi%P$?h-bS)ApoF1$2S`.D2UXU#ifa/5t gE^EM\-Jt.FMpZj7&UVY^aA_J@B/D`\QM+D5?Y%:r8SkQX)mILmG#,5Qa$@m 8\`%IN+JM>F2lkn-6bE9+'C"P4$:%88J]Hko.1njrgkG16n$[KbII#_p%Qu7 AE+ku0`TXT)a,W-TbqN<#jU93V[&HNckm'+eCt(+$2Wka!3/NpDgDtsPjuY! &Osl;iABPJ;B\[/"UG*'SNM&U8$BW">.&+qW`H6*^OH,o4LAeL 6:XCa%o6PiB$Hd`4)!?TBp0l=C<`"Pp/ m\$/,\foSn:tn@>>.&+rXN:c=IYfebFG+3NbiMdW>Wh$%Tb9lJ,Z=l?0N&Gh %hOq[K8PLeJg*I1A&jUDW1GZEB0I@H?K&bTn$qD<]C*82Gk'c!.Um,ORPB1S X.(7fr^"6`JoT&6a&>eUf-b?fn#),:EYL950ZtXh\U7\pG(iO\9lOq# XrZT?%Us\o*&sSo7H!XR3"?ul#`4f!Zb])99lfrHjSo#-^]+6,^OPUTa&(g] ,XjL"\_WnqMA+tu)_%J0.!LUQk"/iU(.j?`YBf'ePuh98R"@p`^A)0l[V`R2 gPKuukg6#2UgK&_!SG#.Y9G=NE!Qjc;%hIeB-:05)Dr'p+snP*bJ%1&i@((p'?IgAp1[a)GE\GTFH2IL`l^S2o(A6m?6E<2l$L ;Y'R(,(@?ZKiF0"q<+@tT&PK,F%g#(oSZil5CQj_]O[q`Br_?MX^AjBUQ7T" @`4'cHhKk=]U=,@T<#7>mE&],fEsJ/^mkC9$&OG7q&6HTG\$(lqac@H(VP3,j+0.uF2VMDhWa371^%^Af^3o`WX]fl=THUV8 ;J-N15UCZnZ$lNCS@!1iRd72#ac[r!.4H&c>e#3_/&6:Xk!k\T$ULAU46i)h KH%IBj[)gcEr,Fm8/F9"JG-bqWJ=P0'Sa_a8O+\a'e<<9=gB:gLMs_TH*TS32)&7f!:AMCG&[J)1AofJl$\;g^ZSq!^Cknt;Dc rq^D)=Ld1@AECt!d)V]q@7Ekg^RdT8Q7,V)DV_mO20\KDKS0K@4tMr8-me_+ 6ALSS;34Fo$;PSrC"&qrfWZNdMAT:eiJ/N9h/.>n:)McoCDR=g&EbB?cmQGOOBGCXu1L3)ObU2-@^S6cq05 nc5;/mQ%?`p.hBGdaHQ]G81hMC-X9k5CORVD$e$*2eaH?-X<`[^HO@dZM4=l hab9!R=Or%o^Ut^'0p7ELITD^<^"+ Y!l5XU?A.u?="`9krB9aJ"#6+F6Cj4:db>5(9+:4@Z;6SRum`F3IA4r#nnWs&Oa4CR=Gqu:(/!q"AuW/k>2KVoY(R4ecMKT7N&8fNoIBR'&aTu _%a8nlP$gt1hjg.A&aJ$sW.\U= KOa]?e`5]MM*PY*DnCl6E32BB-7:0ra%\H4"(mN22(EhnjW*?28pfK@J`[[!MH!B8[HQK"!jf o&R]D%nHJm"5FeBE%?@jo3S$g"8jar0l.N@RCY?!>0pJlFiV":, &g1[(4*Jhq4I[qd=t#2]@%_3GZgHMV8%Q>l$=k!K4DE4hF[E))8cGMmOmSJk?qlY!GSG '_ngSBXGW%WF4CmbBfH-3VQK-:?/N?Na1r%YB8a/6fP63Waj9$Pl!n +l7j>8A\fLp2K7U;6T>E8cDG6!4WXc7"?Hb4Wk7fh,^l Gu-2k?3!Y7cm+Skj[`5QE>n)0T9M@!8U^1;abaC7_SidkoJoUefH/9?E m[7^Z+i%f8.H9CJ_lri9)WY8p75:$OAAe5ELDN`>?bUp7P;"RLL(age=oA'T O+^%JPcaC(_^&i&\OMW$?*I^&jCHZ47FAA,!\WBYV+\4^X;sfD#_(f_`)u%D ioZYkE\3NqppFke.Pj4>CKh1_F!5H&-r[]0L18NU;5m^/LH4?c?Q`Oc+.f> e'lc1r:!(0,K&T&5#R9!O*0a;.9*5W'_;b]%M6T=E8Z8c8n+!r1V8tF-R:'I +$4X^F::4AG[id#s#kMi'IFbKBbr[3@`!p_(!L,Yf9&7*"3cmV!eZ2bigph@OdFSrfZ>_)pa+!F0[?c:Jha3e$ Wb9YLH1U1ceu]n+M;lM9Y4]K4f5O5c]&>)%37YT_leK$l5PsfR1M=uAFuG9k S2bN*&eV9`ZAkZR>FRNf$5=o8Vb`p:>IHrQH3h7\I94<8qod?[6Y2su'8LFG A#!QR2/8@+="a7_215o7IMTF;cpp)Z910VdA>cG-X&c)k)<>H!hS%ARq=Ku>CCY/RHP>@o_)Usb^#_d/YQ.l\.UBW-ac[tIp$9)0ldcnS 7'Q`g\Mef2ib4WcY?R`Dh*LdI@Sfe '.EM&=(sh7GC/YXT4glkDrBMHTQ5bpueo<4-Jk7ZJI6i4snO\K1c? oYqhgpuXipp4\#IjiWi=;P_CgDniu2oB(rc?XlqA[q3$bf`Gq?"eh]Y"fM.j l)109b*/G:ZL[;4B'K.OcM)%!,a1qTu2iPK0LQMp$BO&AkR /d?ud!>#gE>IRAG0akrjfr;0hqML2`"qA_A0-B`WJcuO6Y"?Od\T>#Gm\6$d cGr?W:`VT=aI+hsh7@aLN>lMG0*e#)8m"T5H@!.X'&cYVJo?#.k^fU"@(uX: lQ?`MW4E9K-9rP&dNX0:*P9Hb5c^2&>@u-K(!AdN`f,_TFEH?aGskaV*NJ8_ acl#'21JE1amp(+#hr=aABE]AHY^aP8/M(<`0K13r&T_6?b_'DD+tcQ._2#c o!)N7HFV*<4*ID<,IQUdD*b#^J?&%QJHP[iQI+[i9+RQQi,QW!3d'^eXBRT]Uk^G:S0iH o&W5ZLp3V&4To+BADdNcV57$RIJ`_dl`IXBHI-,gm`DtYj)C0""m(6!\CCq3 i@8gGr-=;eL(N$>3.:Y1m#fWIRhrr),tg)R[!1uqfWqG_nl-8MBbrl$iF5@C NZC3iG3rI-+1#t+2O05B^=p>O^Up#Z`Q1X;6G,+9:,YQ j,\EPgj,*AG8$(0Sj%Adh!*:cc^6EhkB;`8:HV=@30E-=bEaa7[r3X3;R5`7 R58(f4aQaf0k3\3(kH$Q1^)QTJ3Rr+[Z,e(h7GW*].20N4aQaFrUndSGOM[u BYh"Q0>-ekW)9=7_;s\Y7VGG1>&==R1G$g9n!4?>eAt*TB,# jN'oV->hJDaXhe7gqRRPVJ16(:s-\.*_MYF;7q-n^;?q#m^_LoAV=2P?_iVp :/O>E_@-qdlLW=ds5Jqi+OjX,MFZGE`PR+IS*G[1THSel[VQhbF8Yh'S)[bU ?b`1!;RQ`=.'j9,3I3Z'hRnge2s.e1kic&gZYpDE2fI9eC4`kuE;9[k[Vboc 1XGPBIYD+#'3"Ji%Yi\`6YP>h3IetT7EVpJR1Lnro[/!OO$uh@C\l>b5[ub)Ft?"Pa)^W6[TA$TKFo,u/Hu&4g%\!A:pA @aL!>i[8[qI)UO2pANF:$>#.)cU3-+Sk@9YE8J?Zru=%>Zu=ini^MrU/8-`) @XApFT'o-$9GJaQZY%HJK*GI;*3BO4ZtZqmKX/#1TiK-n*O,cBRP_iI7$Qa$S X`VMIn3,=hshgs0.:8h45VC=NY[UjX;d Y9?emeEPG[)`26$AA5J[JQ&jK!(([Qi.2,Rk0/Z'5S>9>3Urpn9UINUK*[0Z JQ!QY!+i8H9"8C\;1=fB:]Bh+V.jiWkVW`,>B(2-I^H:gJB0&'oi U-/,7f.U+%&2H_&*V!*/VLpfo',!ZHB.2C%':WAFd1Ff@e#!Qh,&/6=r8(^< 9P_X_W>;T\JH2aS!=Kb7^4oq*G#b_P*?Jqp*F(eL,uXuL0Me3Lc^qghiPK74 c.e+T'5u[9ER^paY&0>IZ?V8%B_An@R4SHeQ!LW877>&l)_bY"TeV$BT).OQ UN1Dj'dJWA&M>N929>m$:pk&g0k855HU^C4TqKE0@DfIiRd9+X6I>p`Ctc71 JH?"J$,JCHi8"nb4S[K3Dn0Y;Bm3kM!=JUZBEe4m5-jMk,c)g-Nh:#!a TBm94\@=MYf]Z&!2Vn9D)K=+oN#7,$L-\-'OA&e*V.""_0]12>](l\nEWS+- !V#iM?@$>Ti5*>kmUcorgDi_D*20=L7ocQgOZu\A;Gb8,4RiQnYeL*mO7gY# Uo(#(QYLA?BXCYS"e3#"]68&.Gu6peHGbIHBQ?`Jg.o7^/,=NGMi\'-Vrg00.2G^[*0]]nqE_tWNNF#2#%!mQAY;hhPea$M1s=X-9,IC)KVG`]rlZUg+VY*tq7"U!Q2&mO*aKaGEocZE ]Cl%L@$"bLo%eNIaktPon)BIib4Tb=1+0:`C7k[:)jL$U\D+`-TjE!&"oQ'& 2/=BKiQZRfWmQ7;7j!0OcpJ?>`^cH?#P]'$2/CbOdBtC_ju54b4oQLU6L*JC [>2LbOlZKjOcD/jjs_l/'qISlRH#Z,5oIkN><%87U<.'bmUKa.I)$K8V'c`s NoN(q4OAK&K^7UQ`8NZ6a&k\fBQ?B^.FQM444Sn2m+ATAqtKDBr/p063-!r5 ++C^MCTmbPM8mpW)-=XmJP_A1I+Enb$ISZrRV[V_Kk CY&:UGkEq!P@Wt!4H#ktE+[Y#hR:C[H0(pTP_,\,hisWP5?b[YE^epm9ZqHjCn:o4n`c3rk#fQt@#VkiF-;9f"(drO> [%^q;)`G@hN]Z[?l`MF#MELR];lC'_N0OdW:QY+nFK&$!SQDVfPZr"3"KL^n=&,J$7"O) nB_rmGCrD03[>6d=;3@+Bi)o3iU=E@omid3JT0lY%NO-9It*oDVt7XfUu7S% g:"$dg@1X`U):lX-\3*Albe/?aU]@N^n$=$D;?o!.@[B=/0BA`Pq,qJG3sOs 2,/%eEG7CWrTpl:@P=>D^^6a\.o861[VXpiW.-oR.SX,"Nq>"L"H&'^:fQLS $A@tXOt;+rVi4c+otUY?'J!4CVmL?tRZJBtOH651Q,7bhKL:J&J_IK%`9EVp >\hroV:n05puA&8L[lY%eEG;T,pD7a@Y=/Hk.C)rRhnBTnOrdp)cInqjb?jr "`="nM_?u%d"!)++sI^&L@cYor.Vmi5F84YAaF#S^sD'ja?9$MIR=TnofuW4 %.fs&*orQ7l9R$QD_u%J'Q0aXKi*[K9_O"2k"WBWOgnU"X']H>1Z!eB5 56lus/g"=c6h`m1 >dD.s:7XFC$-3+XQYNU&X]d"]qLNFXFMnN-;5O]pYB9$WYXo5Z(+N:^@)7GJ =3q;nMfud7RsXhD5gU:R(IlOQ29(9F.C]HXGt4)?6A89e23M;-eWm`X$Y6]a 'IrhH`ujJFl:f.U,I_QJ@nm;W'Urp[PIS`ZjbTYQ0f5h$f1p2<\5@tbLj_=A @N5tuatEt@i7b`$G2ihK.TOaBnZ4@tIt86j0@Z%_No9>).lAj?=XW!gB2N0; =kCaSKM^Vp085dlImFbC`G[`fa?%_+qF@][H0,un8XV;;>i@+&Uja`F.A\B@ +iT:?"&5A9qIp(t]CAb3:1fu3%5CT2Ppl4\/+!NUStNmc[VXV0qXB^b/QuNu ["C8c,:?2J4Se'%>j(>_%8PID:tl*B>)aFXGer[qX)irH'U8lsd8A1(4_TcW -^Jk[6m$qR%soug4o!rf]EK"u^a+A&Fj\R7kf`\thB:"g4NK"PN2P#fU6W/L 5IlenYmLp[/XUJXpBU+Oh9&0CRBf)l58i.;ml r7mfGKeI>\gkHl8%7.[)lJ^jC`qsJk+.SLnW`?)8Q&iLGXbCu%h&rDIa(Z@> QTPMA7_ZH=&[a'HldDV&[VXVn>kn5A01:1#:(pnf9@c]u8nC4 FrOV33A)pZ':c7?l#7V\3lPn*o`"" Fo80CW@o1/fL0R,9d01#gJQqZ!uJ4=K_];(%HnO3EE++`^\DB\NZGH:ab&&t "ZEp,r'O>BF8hnRK4^qG/,MJ7UDW3-,SPr3]ioX^r'c[te#am)QCCt'7:"kb @Zq.;IDPK4GTr0?U)p$YAK)=V$K@;q'g7t%)LEoDXcRhP!VaW#,t@_%+sF'T^p5)iE!d5o.IICs6m$qf &o4/$lk/EjI%9-o@6q+rLje7!KddiG%CM7`#_T-XX_M:2`Dc&]&q,^8Z;rks )#UQ!Ie2"U.h1+!(kX0HeS..?Y['G9R<`[BJ7qt4e5N9.\odU5h+Fmk L$g(a,W;X#^2XiPSHT9NoLEdR`39suS$1>2+MPAEP"pB=0Gi$O."+K.+lmm\ Qrh4Y)p5QHlXgpTG[sc/6?,EG&/_@a\$XQ'*]S^O>l;qNA8tm=BLSc>=s6Wh C460/j0*h``GXkL_:O:KA6rX5il.T@V5!7@ /R*u.c,AIRoFHs%Q)QgBo$u8#Xd!pJj(1j`MFXD(Gtf'ME9+H,l(*%TM.u*b E("_!,NWqQ'>r'&'I`I_hu2u7Hg\^m(T1f5P\Mn-ORh=2:k86)f.1&28)4$6 SbS^9;+Wc2Yts6qS+Ja*Y:#(7M b3$MSbS,Ol/IRW(b-TJ-2?9^tkK^Se80``,cYTb>%sF([PFGrG=upmd"JmI+ rY\*Y@oe3nPQh7)&r.,5;:VR>SK\-;i^#],*.m9#6n%AedVr?KSUaG#nIr%_ 'SPIH]H+gZ-LT/HS^?.K1aZP+?d,65Uth1fOqT6rA`=u'O]e+9!4de.[-ugp hu/SnosAn]3%`_9Kanm;I4(EQ>84rG*mYD;2K)][&SP!BK=_\.]R5 )TM)q<]j6)#'U?FSVU#2(qGLL,`,#,'Bodr&3M$1h07cHXhC]:,s)@%lWKaV B$=G8H?N%(.M]16p$-\ceu:F\)6tlmP]#$XUr7?s=p1mW5k7d\$#6E^M$iDo HXm/A#c50U5NBG=;C%Ypas>)"a[3Od;U>b/+fH)Z]..&WIP-@1HO?5"NWLU9 agjMs=X?gf2#a'YVnNB>9lfsgmr="3pYUHbIn+="$8i5dWd:lLb(^sO*f$R@ D#ChgRj!]7iJ(X0Bfi9Gm^6%u)#1oH^u'q;:K6QVmoQ.!;l 2C;_\=+um5q2nnRgL'sN(H=`=,!Q@2H"@b+=aCVq"W^%ne(i`B]C?i.,g4ni )?MjKEG/=a^=:Y3JkG?4ZI$^d.m+`FL/WZ3Pl1D8J7rNWgn2BSIk=d,J/>Sr XNS]o&/V=6kF[6qpmi'W.:KbNX!k!.![-G0(G8+n+OV#InWg\[e@Wa]-iAZ* _&/kIX&lKb)PL$,=9O8BU)s(=V?GkUBuDGZVe8Z(d&+mal#!5PB&tVUKciH' $Y@cqnTtWZ/4cUCG/JNrK1*gi&G8<(e_1+D.Z2WT@MXtGi>Y2CT$YWc&-d4R A>(D$/g&5qlGDN@V'$7S."mbGP.tYRi^h:Y2/?6Qr)XSrKp(J/S._r#(S"=& e2*OLZUSi1UnjZABK37g/ftOXkFeDjUj[auAc/>aJ`O`Y_\G,X=M,PO_V%<, Cu;sTfT.d'T>4>]]Di/=]B9oJ3#8GPq5U ]Q@Hh*[qoa=t=lBYUOMI]G(@FaIPE%fOWj0W8o;L\Y>#cKj:rr%DaU'JQu@A Uu](\-_71Z5dkL^po#a9AL*45ErQhI!N8^[CtuNTZf[N_51%:f+__]a?0>l] V.9U[;N=(`Ym)YfrA)G&3fUVDm=+`/?h&:RFj$(&(VM!d;W\bib?A'F_RO4) =-c1[n40-oBKO<.mC1uaSt>CX4:[K@0PEl>\QH+G-t+Mh@4W=;j^0B_X%Y1M 7VR:`E.<`BUVjVuTc^:e3lFo)%mdrb"/H2:)+,-8Ec/$pe.55=M5m)=oC'Be ?:t4[5Q;TMV>a>0MM@5^_hSb420a>)Dc'\6,:1j3CW#s-U?&iqKu=ee/%eU3 &tTJHCr:Hoan"VF)T\6u+8Y0$YJ0QR_.9-R,TbD/S-'.i`%55_,P%p:i1A8A BG:M&PWV38>uSt!J5Cbt5URX9GYhm"WdBhi13*D5X8?PUSm<@OmUTX!e0/E& T%J]en2MnZ=3)p#779Ul;/]Xl)G[9@6A1MmOpf#HcFCCX6 0D2!\a1[V1Ab7\nc=S^:DHbA8i!sH4I:r\N8b;8YX`&n8H]"Cc*E"A%O4&LU p"*:N,F$k"=-@hFPUGJOVAI6W$L%dFME;J!;BG.GPKm#P_-K5qYp["LQ8!0q 15hOTKUrf$h#'rtqNEu>@)9-[b;?h0&N!"\'1cjlP4e+o:ik;@c?UG;*4hRh P+8nd1tn;YQCi(/F_rL&:2nO@2\[eI,3/H-rquSj+Cu_?a0X!Bn6c4g?bB-b !X0tn9gG,3Mm+bD]KT!bTqF)ME/1HG9l&@`jW+,1pk0h?QVdG4G9?S*R564J Ab"d!Zp$t%VT,*pB1""j23*n+]2)inDr.!e(5c.Y#=Wa3)4F_/7k7lg"6>sh 62=W*Hq6Rt>pF\%(mX^Ihu4B9`>)@NlC[3k-C?L=d's.\5s[E7cF$8:*V_62 bambCR9f%OW61(]8$ll^g7d:7XF7dtfI56ElCO(HI%F1`93- X2u*`,_Kl/\2baTf3NUZT:j)_*'&U`9C\fs$mL`.O#TEH+;FS"5R7fF;?5ga O&DZZ@0+mg"d%ngkK]V\H1Jb%"'2\i4D`c\N>@XJP!'Gf,!p:$B]6Ut[$-Z9 Ukb.tPI6eRAQ*u6Up(>J&=Y2hGZgsj<'EKu3IB>XCBGi[;pYJ>XnlAA4ZMXNN.5Pd]WHBMMcZJ4>;jLleEV63ra%BLRjFASF=0E%*2n 9Pm1Tgh^7aL1qP-aY1F,dUe3%%uWiK)![6udj!\!s#lOE1q3]WD@EHWA=EqX ^`Eku/73&J>H.rDa'3%;&6(W#_d\&nSd:$2im(LY[hYB3H^5g6Rmm"uf!IUD caY&=o7>2R6YKtkA?aRg9+.JOO[bp[agr3;AFUpV(!)GnN1dqZnjK386(E]d?rY7(m*00&l+s]*, e]WE#l)3fC.9$JY#H_ZW@U9M&PY6OmiuS0[5Q1cRh1gS3#O!Ke?l?h3V*dmP D^d+ane4hQW$@]a>I22>.)7SBe;WZ.h$"12Xp.Hqq5S(fZiZ<8GQSDDPs)DR F`.,o'hX/aV>sd8e[gVh$Xk.Q0t6/_Zjr@O\Zp,^EcKp'"aU_EUE11'>e"qB <\1-=2T?,KKEL>S!Q^lt58DB%1euB\k&s15B9Z)U/6Pg'G`ir*hF+0q!IMOH jtmjT5r);']\refqt2V"C/+V@#SoR;mY6b7+I]aP#:-*^gU:tQ[,Hfq_P?/j Zmdker,C%Q8#RM%VFk?XC=]K.I;nnaj&?iHBh(,0B0&u&'L.TP<82X@6F]f& VeudSOgMWGE/2K]7^Or$BPDN"b/PG>Tf@)ms8CjTV/2AG;\lsB;5dn,P114O E6XU!KS#qdjF0?QotP:RNTM7kOoR1N8u$h3mC.s`:S0h10;i?m0+>*_VF?@V _.6JAq"#CWb!h=Q!Z%hnq24jB9;;FN"Y1^,NX#A_L L+)9+L^,MifP\9\=\KMbh)\tfoi,F7fdJDXd[i"@(DUOTBn-=9d X::cBqk?2ePRM.IaYSKfEpse+qA*dr>VI?S/e2BB;_@W$Z[]i!,u2jIIA.]B'X?[P__CIr_IX,:#)4.]3BaAH"saW:%%R6a.^)AS93 i*!&T1tKrM)8-+!;4d:)k)=7J@]t_IJ)kL7"5&:0F(\1*E^jjA 7e2@'iPSK/(k[q\mUXY8SbhO(%3%3]K5Qa5%$MVPa[:-?,!42.+PCYnSA:Q4 Q!:1>-Q+T7Z&Y'(Wm7(m0%YG`jR6,GR$:I??sZUu.NV_27Lfmkr#1ZZZi WH,Q>k(iF\?bUnU7T9Yr%UfrV)4N0oY,NC;8SN5b,GBB\[ap*9pfVdW-?T1M :Ob^G;>@hOpKeqi"Eu1)4su&^&uZ6g)>!\U39?YGTnIed1V)@r#1F'$JFL?H >)J[NJ_/s`g_+/;bs/hGD;u1<36$WK%(hhE685!e!+YSujL&dTg9`(`Rk8>5 Id-"[06UhOG?g7/"aL]=hu2te8A_ZDb75LOJCeGIDs"e`]carRNYE*H1br=u gO]p,70W\a\%bAa:^EqJ`26t0JtaGO-o#:l1XMGdDB<>`ok`#0%4h`h6km0H @W-$8'4mg^h0!1DGe%'CnVDAb&Z%EPr=#qsM)l08A4%pNq=sao4a-o*Vd"e*?r8"'e/OWt)a:8>=o _UO1Ora01Be&Hft$FD="U9p:eP8:K'1,ku@\N^u`-Z`YtHc,t'#giZg8-@8F #iUmj7kfN5X_g2njhShXRr.,-k.7.U$9#bjXS4sZo07a#b?oM+K*Mo"]\lVS B.M-W\Tm1=-'#9$k.IZs-k)C:lX0Z1O.Dn?Cp#:hj+dA^6K"A'7m-QI)=f;c 1=U7J*P%r+C]G)GL\tO%[qs_A06-[MeJKW-KJ>[IYM& V5[AB)mr)/LhM;P=Y]`!`\0uYbAnb'@[/aBLJ,-%Z@lDhDIIS6HVfpR7>!>ibS7@or+$PWaeC6TK`EYS] CLe:+^0!UdA7!.d:g=Mnn,RiG+E+>63=TV#@W@O2HQX!#+:B8(,=LP5$9D4c/!gs BSGNB_g1IoV+YM..S;/(C*EAb5'PsFXb3Ddb#/mjQ4J"Uo/lERZZ+m?";a!P EPiT6V5C,)pkSDoW"CLICdR)WDq#q1c&38h?5sSlre5G45(dN[S<>8'@C5rp Atl;Lm+@GlSrT815(,K'g'uI^ql5R?*-7;DAoo_)#T/hWV1r,dX]),mBm>Ap <7-]kQ#Xc0)i`ElZi)L6\.q>Nf3NSLRAlTTfN,j;DGJ<5I=h"@HB)5H:2^8* Pc;H4VrVebqA)!oU7$.F8!WBbFc3?L*/'MiBk\GAk^isGW-MU.`Hn:q[9/@t .L8VCiNVQ]G:JeGe1,i&V(HDafnCW4ki;:2d-'d`J-Bq4EC^IKTTsdOacFG4 fRS#hcY]=+Os\poaZURc@JN&M,&[Vl'L97.J)gi;Jifnm%$S8s1g!)D$&fHd S%pOVkiAm+Te#U7Wpprp%';O8K43:_O<9r/> s8)&bjXQXgd[1C;m2Th435p#Weq!0Lj^H]>-a$<6Srj0$AP.&'$ZKVgA::\R8/F/-,A:uDj?NY=,7uXR %hFp`csJt[TFP*tJ.H\9UCh5<,4u3aEYlDa"Hj 4F-Me@p0YJ''A\-V=I#&Rh)?'asIrLC%uLbo5$UTfVF(Gb",o4W,m>i*,jn: Cm*DJ'C4D,#BEq[$2[&i9_opc"BBmTG=1LhbP`LneG+f(H"ql-*q[U:-:AeRbta)]$@/, ?,Ifm^a:+XZI6N`=r)DY.C9D>1<_?m/M>LS3!*;j"MU8HkCu:^ef.W*j4*1$>=$q1$oni%QCPruZ!rEQaIkP,25QcV 3n_A$[bZ\^P8l\%UaSLa:HF&6G`maf(#j3mZ"M@PiCM4'TqG3V!$iF/H$tJ^ A5puQrgng@10_D?[VXW9lF>gCj2X)rg^&`ZNfQeQr+*?OB_7%BkI1#Z)(A\k fYjOB8/OPr%?S,:!ji$Z6?tEV=NodlG]CtBUF)rX'G2'H@!M%jYsX9V+ff:* R_T3*G`',TF]Y"u".?#[R6jme7\OHqY$?fQjd3=mUiQdqR%H9![*g:dM5@!H n%%U&C>drqmmU71?7Lc^Z=V57`O/qe:+dE6s35J2K/u=EXQR[qhTBt+!T%!I TM(S%l)S?Kn9aot?*n8Ws&JR6D)G/.2+El6Q]oP;LjX1beTUlC`fY/mZq8G< C-7,C=1<6gY3A(H-@F$ub:,!AL,%F,@+MNWc47"MY)=#F7WWtOh01=N"pLkP FQsc2k7F;Lndc_fV6W__8FnTQC'K4ZLb#BN[OcPVNj_%1S7/_!fgT%6)8H8X0j3a8c(`s.m*^Md/>: S'1Pi[GoT@numN8.rIOro&NJO4cC=X"/mFmYKT*u<\m6V+-#!=)1fU^8RpdC 5ROM*9u9tX4"6.-+](TU0j$e>:K;0P?;?Sa-jJoMTYX5'5_D)I\&DE>,L+8' rqqoj/%%<>,WioGm #@X9Ar.V"9ltI%?)<*rM-#tn4>sa?Z6`t)L\RYg]W!F6*um ,ndbj]?WFOjBGlC]C3HQ=+M0=Vn^S^HrtkT2HiWPj3qG0GZZBHUeu(I]f>uF Dnd;WIQWn;=7Hd],R]ttfWfDS6bQp]*85ptL/!gKj<'MZeL7t3QACABP)R6q'3^1< D*Bf)e>Z@i<)X$>2*uBF#cR-TnI(o#XtNX:rEZD 6#'(OrfXI)1CI:oW1ieu]]dn?6-0G/8thQ`fc?%Yl"b9od,Q @?Q"`76$!&N97s56E\\cBQujRUqN<$Zn=ZK6(k$.TD@nBI'(3hQ6eb,GQM19P%6bj,gKBkpQe"Ojn#79*6M@WP>` Rl@'BM7bYr_$=:ZqXj#iSQk9_eXj`A#%-&4$EY1@Lh_cChq^+!"N0NZnH9U$ `>;n6-tTl[cGo&%+I:F#68\*js+9gUKJQ5]+qaD(q/@";!KBJ4i.6d&PV6=R 'ELHV\[OG!dSXdtQjQ9I_%_*6NDJCZ$q*:(n/u04S2kZ#8@-`$3"3/%mOMkA l"A;3W>46=$"r_$-efQhJYSfa"_cM+o2tY*UIUC)!epZt]u"VBfR96Di7fhf [Nm.F+eRsT>LuMhI^t9.Vi&?X)-7\(Q+B\,#b:GfqP]3>3?Q=24]=6WOkR73 ^JljMPq>)^NZP`/NU]&C9?]He#SESm7'e=G*2+t921<:>kdrXYLOuhCo$sOJ 2hs1D]O5!\Mt9r\misd#J[IDr"52.HP>nhG8XUM!kAUm2LYgs%1kET_$H\,G Z$Z65bGkrM#[N3iM`u\m[&bTN;c2>9lP+t9L)8SOXQ=6-O4>2@X]o;omu&-8 7.EoL#?M2]GnHXH=[J@(7rr=8`P:qOHbR,6gpepWNlu>3VsD'hKn$c%6f"[3 K#@rKEC5XPEIn6^jD[sOhR%mC[e9,q=Bs/YhP6(S7jh]!0JV9+K.C-@s#MW. ;j1T)2bA#)7sC^/X4ZpV>K)>hr93+FQ$+lU"r*L%Rd?ctPi;X/>hs,)QI\u\ *2(^b$lGZ)'sqjMpha;N^[+$[Z*Z&MTNZ#0g/Kq>H7?MZG%Z"GUO1B9PJ46U 7mee+Z&'-TcCgl76NAmU_iXs?pM)MrBU;d8ARB-T(C,mVNQIa:#bsNuOk08eg`bE2NXcGd+kUO+m$`+>< %5EH5*$J:8$5HaQCl)5`nYi>c;#kS:-XV2hWD]Ps%NK08f)S49]mB@W%UA%V7RTKcY10CIUN#2/\9t>XXnq.&(_:RY @K$&q]mKM)gdW6h4YR$:4m8cg+9DR&FW]Wd:B0KAs(V96GOhF'ft"&\%@ZU& Xo!5F\4o7kUi!s[!6p4Fku+m,hnD@,!c?Yu=h&FE"rd]TkcL.e;_p7h>XpSP *BJ;hEo/*3NkE2"X9!2`*'Sapo&Rp;Rl@g1!o3U=3bd0HR4Y+OnI!D$=Ms6q0iiPUF<-o:'FJ'\U)I!g=mXBAc8C,Kqd]YLhn%e)q'04(09 R&FM:l_M$^@?f&Qe>SKkGAd%Npt2JEd>I#G AF1>7;.jB+Rr[5WA>;VR;D18LZlq[8cpF+bo9cCb@ if!NtgY39'X_4K<=d1ISh7@a3>e+V#XGQ1+FQcPsb8]AOi9].'++3R/(-&^e :3A0NKtGdGH1R1F9;6QcUk5a@5oC!R0%&s'3jCQ&+B3`9HsBo]-E]u]i78.% '/S^p]@Rt<2YF\+n(s<[="[UZ+CD6X^HNJ=.A2Kq2l6:cd#gClJeMr6(5h"B Lk:RRN*tDKD6J<5RS35DCh45J;FK*tb*D;M^V=\"DCj9%^juTL8?"_R)I_rq gQHPfbEa_ZW6hTK^8fSAOY1[)Rt6hTDh+;[/U;*N8.5FL_HGTj ,@A04/R#NK5(.a=1H3OI2c%&dBK9Wi+1:rSX&c?CkK[A8>.(%kLP@=R=>oSE %/c2!,=ZeBg/ZmZ=Qj;K#sPe8h)^&br2AV/$Q!,`(RS;,F;QoP(c>erG*p$W +.n#Ykq#uC1i:rgb*4=mmnXt^G!ri4r5i0$!..+9D2U5c!F)[VWqA7lJ,Ji2 7>l36G+&\uSt8]j6(C]:_UdTH[;4C>Sio/9D!p)hQX)-d5SV"(X*sm=C&FPl le-.f>4n,<=K%)l/!_eng3/p@<69&-*'8>F9:%:!16o9cm^(5'X.:caQS4D2 V](mT?QLVi(r<4PWt5^,$u>0L)m][k'7ms_dA)?I#Gt:[PERS!ZHSn(En%\C b"02Bm^jDsD@@4VN'O][?4K97PI@ta=7?E8jiU"7TN.`h_%;cmP&0;.gB5<[ "Y`gX$PogI[Hc,46[.qO($Y8npncnY"HbRQeD7K&4L,unEF\"fiXhKq`5H'1 OT@n(G=U14@WGs,*M7W>)>q0;N>bN]3&,e:oDha=E8u!4lrcY#/O6>pB=:a+ 3/%T>[r1$W\T?g+X^&F-qUXG[8rOTAJlkSk8\:$'N_ ,7qA^'cNhdLCYIrs/<7qCpK09(.hA;,taEceZ7DfY@F^lNi#aV3D(W/q3,;j5cW92?o_]Ua5Z;X`"1(mRh5,qO2X-aSKNXgYd#g6- p?hSg+Bl$beLI@]4)!AVBnb1`'^%oC(4G8+8,DoE[r^`X8=0'O!O3n>>U_iU )=+k`S=k]/kKf25>.8BT0^'oSnC_HH`Q-$B0H"\"APNdIr&p;3Y[PF#&;XIN AM:c3djA1,Z')C(mZt$nW=g79pu$d4&bt"pi5(%cooY-p6BJf'^aZD4a>"h] +UA2ZoB+:BJ84,;[0,\*MWN$JYB&aI,=ddL[r5WLb8]AOi7tka0>IFj'"g+@ 9bp>Z$\,?\X]egT4MV+.('N*Z%+(eQZY#LT[tM<3R=ch\RUjO'V.%8re##hI k$pkDIL9rV.pXX*,YhKQXhiFsb*4>WY[FqXh3*qa@Q_VBTH8FQm&<.s73_$D [S>q.!K\%mAF?:EQYoB,Go[Hi\b.fr-R,?VU'0qO4- ,pT7*TN)9=$0J3j[;&'`%,&=@GGNE/X'j\jD43mA7:\b1TT[M7(JBu@JM)97 Xg_+p5t3%fOH>RnjHE@`$mlqQO`aS8-KN:4#LZ><4?;&I`@uf@r2*2XWno;G f/s1"Em0k'hkQ5r3cO#m4aZlj]"A&mEQIJ3gUHVb:HT42*tN?B"99&IbYs,u %3SW^G4"G;SSNk`$e;b,j)!DSTrc7o*NQT7K1_&J S3(qt9:%7f3j"IWKiZc[,2#4\W`5rqW)00h??p,Xo&[^S"%3+frRKLBgLN!) 4oY6:EH-!FD8qMP_)/)-!La\>e>Q4h,EuuAA>)V\.TNcbakj^XJ,AWB_31_5 KaS^.FmDMVM*'^ZC/!eg7(@VJE\/,M'I-.@9#<]I:ddl!P[LAg5_0!%.THi, 6Z@&;kYZ_8ji2][^E?M/Z=Sq//(UIcO4C:4#Dsqp+b)[!+e_Ab)FR0ildp(- YT_5*kb56dIE\9G45Wf%1eARA+:nMl2f=kgOZbJ+DVd.m_Q9(S=0>oFITs:! NHBFJr3EQK:jr67Khqp(cprcK]TEHHMEp,!qsT%&\`[SNSfIq8!qhkHQq704 nR+4DFZgH@[Q]3?r3^=l*]7\38kM^OM]CYei;EEBGke[]eWPUf%6PaP10@(< `JPCOjN,`F9:)JJQNe<6_oRrbW@3Zch7us4$;OH:>b='"C+N/"NY0?!*BJ9J imar+LG6jsPkfd,hr;V5UM8V7qe^IM#6*IJYP*d2Pi?aS7p+oD,IRnFFm@H_ >8FW/*'AK8aH7]op?ZMFY+9,l3Q?D2s1gCM>U4VF:nU)JmbLsH=qs_` M@nd+i6aiha$YrdB>G;[JnUZ)5AVcX2bU6G!mcVZNjWihJCoZ)_+"ab%SG&S $JSh-5$e]$oG;^)N6D4W*P88T_&5qhi!!*qb48[f_SB6lMA=SsW*g54fKnE/ I4J9qJ9+Vl?G3pmlZ0r_;a0SLo1$DYWQ'4sT'I=nOMp-&u8NWFlC@hq2_%W\/Lk7U3o! 7:j`4PtF\?8-gs`0`n'X-r[Zsjm!n%G]9&s:-g;=JqBInfAI"4Ngkcr_+QE" >QM8F9dZ1o(akq)nT!#(RZWE$H"EE_l$@78ML"bQD3l+^>CGZe+6D4e4l(#5 \(DrI)9YiKEH-!rGM]uX_3/RgK%6o'=8#IuC=R(LWejP9*W\&mn-J$P\(=<= 6-N5NE4?Q0Qb(4?:>_g[s9OYrj-i"a1mUc07AZ+!9q]DB+82o)fusgpqKMmbBfO.4Np=4[q,RqXcOSb2DI#W@Ar1HgEJSAHo3$ #=VahQ)3'L]7<2"&+'M0$t@f1JhR(#*u1BWGn46^AOaVPEnP)4 \HB]#S`4\7kU+k"f3FApK:Rfs7Oqu7jX]*l.pNdR`3>;SfejF9Y*eSa+06FLqjHR: )5cnZa\@Nb7b#&dTX*Ip*IAeAVF>/q,9PTuVc"$#oB/VH;8Y[h,'M>@CY+=_ H:VA7b`dE==X]YkOfIdL:732;ek0mAjdu@*-?J<1LU'E6V_S0KR)s6ujE%0$gaL:26ZDFTBP%3d$g&5TCo*95[BmT`q<%-C 7JG\h5NgLm9fmL_<2?!E^s0Zg6\hm9\0ZgSO*Z=QYXuPN8$U1;Q0aa)VNC90 H@VNt,;(O='#dP"9.%1dIQ,+0)F$$ajk;A[9lVaX3(GODYrngN6bYh3jgb1D [m*V8ekbJc8hB"`.&`XrF1,l9DS^o._d[4=N,gQ,KZe %[9VQOg8@%(`-F=(![(DO>jAhkNVdHQhkab^4'D?a(p.gCjhXTc(+SDQGX6Z Hi&Q+\i4`[(XG),7CWYFZ\HJ,ISd=\aT;VQ]_^ooX&c?[F?9`;8_CCae&sDZ $mSB2/mYhtd:+/SH[ocU0?&Pb8qg)&KSMmER"'`lR,Oe2~> EI ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1691062243.0 reportlab-4.1.0/docs/images/replogo.gif0000664000175000017500000004030714462707743017457 0ustar00rptlabrptlabGIF87a  !!!"""###$$$%%%&&&'''((()))***+++,,,---...///000111222333444555666777888999:::;;;<<<===>>>???@@@AAABBBCCCDDDEEEFFFGGGHHHIIIJJJKKKLLLMMMNNNOOOPPPQQQRRRSSSTTTUUUVVVWWWXXXYYYZZZ[[[\\\]]]^^^___```aaabbbcccdddeeefffggghhhiiijjjkkklllmmmnnnooopppqqqrrrssstttuuuvvvwwwxxxyyyzzz{{{|||}}}~~~!, H*\ȰÇ#JHŋ3jȱǏ CIɓ(S\ɲ˗0cʜI͛8sɳϟ@ JG&](FJ ԈP^ݪqi?ճW,ٲhC˖۷p㺝Gݻ+/x  aܽ>EK9rƉ ܷo޸mۦt6l׬YFm4iѠ=sƌٲeʒ!Cf1bÄW/^rE֬X\bJSF S'N2Y4IR$G)JTPTɠ>ƦY.W͞y 7iF lL3[o'0w\rB,t *'(%P#<"r!"HxRJ1cߑc9a` HZiجVM5̓ЦCoKq-< tMJuXJ)Ix7I$"h2t3,~NN8E)Vٚ4DlUp - ,̩ʉk)ݞ'$8#(rH!h"T#O:eif)8H6v%k 2L3ޖ[/i*k-J2('&dR%$I$HGsT6XUSi8̀hM6Uce`;Ld.8+fXw)mo,v &} 8 Gxq&tBr|U<㔣PlZ6ڄ5Դ f.,""8u(J(sIxhIy%GAGC>Vuud눣8~e]Z4pG87zp7ݡ-3+rX'v'Tt#M>u1}:!$Csdn6i(mrɄ=rVQ:p'ÉN`"F {D ,aNssCh|8'2h8 VQʍn?3iU؅jCBVauR4R;' vK( Q##fUn{FBZ9@{-@6nxK ڝ61RGo|csB WHp?KѾopK@Q"M7(A{JԢHMRMx塄$%9Up':h:4ӭi$]l Nqxͫ^)CQzMP%C-!l(+Ꭴ:8FNc02ҚMjWֲpc$I@~ !{sZP=)F "q IJ%5HLrAҬ z@iKL.QJdX('}& F@" )asN㞗MұFmۀFvd%Iyx0DQ?L-[8 j(Q~X18Fþf@xAtHȈFp#A{sؠ5x;2_8r@N'TdlM.Y$bD".VY],P:i8,19' = Ov!Ldb%VF`[8;VjhP#@Y@{%6P QB2!k9c(E)!8yo@~aeCBTX?Kġqe TpPᎠP${a#C#Spv`io47 B ` (\?P[1 0Ps0v7wI05k+(` Ұ "*] z`  bEU~Pp;cyyWd0_ +׃0AsDG `1w+ٕ}Eq#T#$UR|E8{st`(d*|Z T Aa .V#d#rI ؇[XSix`. o u%\r A`A]JKJI@JxF@ZPcU%tp:Պ. /T0 3` p P_Ȏ`ЎxKtPf\k,Pm (2 0`_>apD891{ci0[ )q@ p!p4`@Q߰F|UW#F'5E5_pjP &)q" cz8e$e$@ yUG>gR{`uDPr ȠL@ v`zp9ՓEwGe ]_ 07O|Ї[u`=@@y` `P `n P-ɐ;^[=pTP " qc p+`dRqb`e9؀jg@ ě%97 k '3>b 9(p %pra? <zEU5MI B 4t PQ G-IANeƕx;  7 pa 1ϰyf0*Тa sp 9NEy$9!!03f: - P:41yb0j {T p!R3 ; 𘐂XX4~{| 0P " : )0H5 Xz 3JK ` uc b 5а ڇZcu Ap Z ÀuC a n I-WxpppSP rbc*Z 3 } ʡ6Ux`" 0$Q !L@Cj 8wZ |PcIUTq K8'q057  R`H7U(Xwpv>p|D * y%9 P3a Y AP>=8c z 4 @5c?Μ Cb[ Ǽz t~ Y>``3"Iɒ] Ӟi`"8IA@??' &Q Я " )7Ok3+ ` p*Cȡr 1@V 03Xn`kp +X{0Y'M@XC KAP2@  rr\ ?Ȋ P 0 ސ 3XMK0 !9 X,_x@ [v`}2,:& ˈ #` )1 P }2 5# u 0IpC V y #BQm$w8`Nh@=@Q ˱ ` #@1 [|֊|J u@vT3 >40@⿐erO RK]<@a 9/@ ? @#0t\u<,r k0P$ྡK s?c c$  K @@VŰvV θkX"aG۠ A .7pr e~@ P PBѸ5\p ^{! |0 V:D  v S $8P r  p@p ` ` ڮ P!C 6 P@ E塂E_ p6&5[_n0 ݚ paLa P ` pD @ @D`ޚه5 j=P:c 20h@+ 0`D' <)L, t F@ Rlǹ` ` M @H[mH 0'@ `" 7j 3' )K,])I4i4IϡQ5zFF%Bd">NJTQC N9yN˗/]hb'[V(#EI5+]7&G)2d/c8bx:{ś.G<}%jԨRRj$g^5K-[n•+LQ#Fs.ҷtʼ ׭YP wONjj՚+w,X:z媕XOi.m~kIQD](\1#6M̛ӦF4ma$&e>aҤH EF%@Ę#C胏c=hn˧fB 2" 0‹+8 +"(p&bV#( B !n"(ŚxP/+AeJ0+QH1lJTh#yFX&,T؁YڬŖ<ݤZMN@|RYd%WX(e%VTi`ч'!H.;/NO")rIL@Q0IN ą4HdI$ϑlYEAЄAt$8AJA2C0+@*+止)Pb4tg 2" ` |xСnp LpF2/{,I#I(DP=g ]3Yhee]`yhɹ27_ F>8[yR VV9nSQ)wxSN1%lRJ)EPDRa'`.Q$o EG ZC;0;ÍXeˑs(C X7]/0j - *:!:y B<2Du0g!L2WR#\~IUƧ8X^%8Bc]֔g`>g,;I g=l1O8\@VPM Kf}8)Pm )D(DF=MpW.`Mx 7H(* KG$ĵDNpA!"!&L!K=!4t g(C/pa [p/*Da RBb Blc0l30`-4V Dϑh GįS6PHL8*R R|&PA#vQġ,F F1!qpqśH= (STB'qx ٮB; s؃ڸP O\D%(f5bz D.! > -2heZx h(CF%"uGPM! P ir@!*PIB$ x{l 0`\a]#1 0[xJ"eN! ɕE'^ ЁM,!RHcXE1*5Ap:2QQp1 0Lb | 1 Ek3CKFde! IFP̣IxJ ,4p$ J s 5c (B26~mT-aLTERxXFHC$!iR_*B|;łܫLA78TQe#bN~rF42\ L'1➕$ 2q $0/`"-?E7 n d@Q/|a ϵB7Q H^Ua K]U$dx%`@+C Q^LDytLcP"..8ښhA -(E+^֨l-! UXP3XUBEJ EXu6Qp .01CN (4!  NrC xR20TKP1A6A j8>$1 H^\玔 " ~4bLX@1Aě0I%I6ADq 7/CFE0b%*#l!$)a G)0uLH2uK r7jjU 8wm AٴcS 3ݸ# S@X'>1vR;i7Mul0)X vЅ7`q@P#=!<+E( }ڠ3bJzҠ4Aerð Hu/+ϸөP+ @Axj၇/j( g=/R[ EHL'OS90lepf*+R+{ك/`;F 4P/*.+3d6h3.x.,*XhnPh&:JpcJ+j: \H;ZDPㄿ8RX!Pnȉ]*6E8*Z.(W`Upi(d̎QЂ/P,0@.Qx8x/hS#Bw+c]h/sXbd7GFzH? 3?C'BxN ^ZtxHL8 3ر(H&u&P94S8IV8V,$QYLŝ<Ѓ=@( 7ا'T0O`؇X(1\,H A٪- gĐP0ʃu .xn0VЂK< -,+pUY(&p'E4 Dx"[H)o ~`38;CP3H ,wJPh#PeȇX :Vx(y)I_RT+qLȁar! ?xF}hPH)Qx_yJ0ыg14e1(JPP>Clك<=0hBMx'Jq2"N.82wP,$)*%9]ȇH #h.`qE!P` ,Hz2H69 E :8K9H](VxS8THۀ#-*)`U*ȂDH0$) NQPd8 1@h;X( OFmvRQ3͛7G-[eÎEQ8k탞ʉ>=8x7h6X6@1PS4`K9 1x8p2Ȃ>@{%7rI!(PPN4C1B<El9PBh܄HhHKȄApjpzpA/S ASK EMX~T(~E  (,O8+p]]MOx~ЄRxPP8ށNha ZPhfa;1xRO0BH(锉?H<:9ER>"1A;[.zDx%@J=:*$O AV8X]0aC/85x:k7̈8b U*Fқ"l0TU(fA[yHQ'/;/PQL%Վ,I%KHЀ SLxSI1X>x[}(z8D _Fh(jlKF9EZ5h(AH50.R Ä?Px|ȇep=B T6K7Єv jGw  S<_DPxDž{,B"PM I(J"Є*q)2*2%H u??0I=P;`i98p7@ZoZxe50/r23zyi@[X0'z`Z&7{Ň8!36<'//Ih6x_`} L uBSdYB vrRh_zΛ5L@k6r*_K^mIX*8R h$2EB'q \?_涃:Xs:Hk6gi:2(,hf(1>S6 3r+ 0:(Yuj&eo ! 4a!0U DH2@5h7:'AX%'pK=hosJp5͂*0~RoOIͤc!/8m|O4v2IՁXNJ 7}(Z+F0)H`Wh? @@as9wiv}.5oHT/8 2j.=xB}$h'ORԣ"H"e)!X<5dp,.ڊ!i@kD`H(6؄fy`Lh(2 %Ў+KP8h{r\R / rHv{M8EpKL!(ϧbM8b8*Tn%"EP788}Fhx@8anqn;_7076x$P<`v8>⪼s 1t(8#9{Jxw'Q\ 0@!m @#,/Apާ'q؆G KQ#]D5r.sZD(L5mԩLF=z{M'OD IR<]$Qc=oyNb KHVt騦Os.߿r&YԔR%J8I1?ժi"D *DС,,(Ϝ=|g pK,D!41Dqj) LO=%6AbR$oN8?s +AG@#0GNxGx"Zb҆h2'}@xH L2/|"4RH\ Aٲ[t2PD!PVDuBJtʄKF0%qDG1trC(z?X##ltElX4JC;Cl4X9p8԰cp  PAZ+lb6`8XS)zu#C>С qC g;E&/֙Hڱ PR (~ 8)Ha]޲%KhEQN?A _B@F+hUlHEa)JF.D> q"hюEQ;_,6э}s o賟6ґ;#HF/fV4SS!7W 9 05X1 E-FA On=e `bXwqaDȧR!p83|1V"?A~v0G?Ӡ?эe"`,Ʊف?`qDg;XVz=Qsp=rw8iDbm'A H>ށs#MkՏ|#xnq߱Q^'XOҏV,PmQJfCY(9!ݑl0L=;ZjهZ Hl%,[%22|dZp˼xHoP7 pӬ5#G'JvЄbh~.r?>;ԡ3\^ώ~4H@"I X0Xt61qdfԮ~J8]D$W.ºj!kB7f[v">r1;^`ٮn@CↃ rx,;V1 >`ڽ}WeX~k=7y2p-B8قTLzy uDD]r`Av펳/z|Px[{bocP=RFu7LShCn Z& a="d]1s1 A [e3@pМ2A߽EG*QC0~C@Fķxy/· Aԫ@VdyC #-QOxO q3 004PL|"1wcā>@gm{ ID:6 o>2A_ wA HA(i4Aɜ @#DIn? B](BquBI4A 0'0`' `tQM A|+\V"؁` !T B3О "ۛA@B[]!Z9T\FaF쀲؉A 13AAA`Ztɠ"P!V bb$G,^2 _Ap8"J' [.]a-ɌɁc l*3C!HӚI LA 24~d A-:PA܁#`/a>A81@ e%y3A`xȀpŽ!;́| $4J*Z4ƵABmHe$"Ad7 eU?l#D&B7HBI"fe:C dHA 1%NI(e(ЂѥE:I؁ 4d$ ]%ġ1qf1GFS)jBm)HXAT4ܮ;--έm޲C;Lx HTAZlXT^+jhelf1fHRHnHZg벮h֥]*  ՀzfCJ=DL\ktAk`Śkx }СAV*#瓊>)**F縀xFHLXkl/*iZUN&V]&"|ohV0 i$iX/l\A+;Lp4S6lP:hoy(kpd%0h"F"|) ! # H.e 3 |(0kxkZ/w s/j,7ie6|z&VB1PTV2"7)NriwAA A2|_Z, A((7mXf.lp/~/:ij&i&芮n: 1W !@k*%@L@L3x\b WsF} 'rl^%窯A / 9κڏ %o8'0K<DAHwP(;tJи2,;,;qȆrlklFCtMp$'OP111JrZB߳=3zT:,A|t3se.ukdd[:8sq8q 8sJ97(BM$C+H#˕go9w99DBmK30C3439׹9繞99#>?>:7?:GO:W_zK?+aoz ]ᧃ::s@;././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1691062243.0 reportlab-4.1.0/docs/images/testimg.gif0000664000175000017500000000163414462707743017464 0ustar00rptlabrptlabGIF87a ޱٳն̷˷ɹĻÞĜĚŘƕǔȒȐɏʋ̈́΀{szqxnukripgnY^X]V\FK>B;?9<8;48/2)+(*, H*,`# 4HC (İ&p^xP 0/<0 DPA H`1B Ph۷p;././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1691062243.0 reportlab-4.1.0/docs/make.bat0000664000175000017500000000601114462707743015453 0ustar00rptlabrptlab@ECHO OFF REM Command file for Sphinx documentation set SPHINXBUILD=sphinx-build set BUILDDIR=build set ALLSPHINXOPTS=-d %BUILDDIR%/doctrees %SPHINXOPTS% source if NOT "%PAPER%" == "" ( set ALLSPHINXOPTS=-D latex_paper_size=%PAPER% %ALLSPHINXOPTS% ) if "%1" == "" goto help if "%1" == "help" ( :help echo.Please use `make ^` where ^ is one of echo. html to make standalone HTML files echo. dirhtml to make HTML files named index.html in directories echo. pickle to make pickle files echo. json to make JSON files echo. htmlhelp to make HTML files and a HTML help project echo. qthelp to make HTML files and a qthelp project echo. latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter echo. changes to make an overview over all changed/added/deprecated items echo. linkcheck to check all external links for integrity echo. doctest to run all doctests embedded in the documentation if enabled goto end ) if "%1" == "clean" ( for /d %%i in (%BUILDDIR%\*) do rmdir /q /s %%i del /q /s %BUILDDIR%\* goto end ) if "%1" == "html" ( %SPHINXBUILD% -b html %ALLSPHINXOPTS% %BUILDDIR%/html echo. echo.Build finished. The HTML pages are in %BUILDDIR%/html. goto end ) if "%1" == "dirhtml" ( %SPHINXBUILD% -b dirhtml %ALLSPHINXOPTS% %BUILDDIR%/dirhtml echo. echo.Build finished. The HTML pages are in %BUILDDIR%/dirhtml. goto end ) if "%1" == "pickle" ( %SPHINXBUILD% -b pickle %ALLSPHINXOPTS% %BUILDDIR%/pickle echo. echo.Build finished; now you can process the pickle files. goto end ) if "%1" == "json" ( %SPHINXBUILD% -b json %ALLSPHINXOPTS% %BUILDDIR%/json echo. echo.Build finished; now you can process the JSON files. goto end ) if "%1" == "htmlhelp" ( %SPHINXBUILD% -b htmlhelp %ALLSPHINXOPTS% %BUILDDIR%/htmlhelp echo. echo.Build finished; now you can run HTML Help Workshop with the ^ .hhp project file in %BUILDDIR%/htmlhelp. goto end ) if "%1" == "qthelp" ( %SPHINXBUILD% -b qthelp %ALLSPHINXOPTS% %BUILDDIR%/qthelp echo. echo.Build finished; now you can run "qcollectiongenerator" with the ^ .qhcp project file in %BUILDDIR%/qthelp, like this: echo.^> qcollectiongenerator %BUILDDIR%\qthelp\reportlab.qhcp echo.To view the help file: echo.^> assistant -collectionFile %BUILDDIR%\qthelp\reportlab.ghc goto end ) if "%1" == "latex" ( %SPHINXBUILD% -b latex %ALLSPHINXOPTS% %BUILDDIR%/latex echo. echo.Build finished; the LaTeX files are in %BUILDDIR%/latex. goto end ) if "%1" == "changes" ( %SPHINXBUILD% -b changes %ALLSPHINXOPTS% %BUILDDIR%/changes echo. echo.The overview file is in %BUILDDIR%/changes. goto end ) if "%1" == "linkcheck" ( %SPHINXBUILD% -b linkcheck %ALLSPHINXOPTS% %BUILDDIR%/linkcheck echo. echo.Link check complete; look for any errors in the above output ^ or in %BUILDDIR%/linkcheck/output.txt. goto end ) if "%1" == "doctest" ( %SPHINXBUILD% -b doctest %ALLSPHINXOPTS% %BUILDDIR%/doctest echo. echo.Testing of doctests in the sources finished, look at the ^ results in %BUILDDIR%/doctest/output.txt. goto end ) :end ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707393948.3425586 reportlab-4.1.0/docs/reference/0000775000175000017500000000000014561141634015775 5ustar00rptlabrptlab././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1691062243.0 reportlab-4.1.0/docs/reference/build.bat0000775000175000017500000000015614462707743017602 0ustar00rptlabrptlabdel reportlab-reference.pdf python ..\tools\yaml2pdf.py reportlab-reference.yml start reportlab-reference.pdf ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1691062243.0 reportlab-4.1.0/docs/reference/genreference.py0000664000175000017500000000226614462707743021016 0ustar00rptlabrptlab#!/bin/env python #Copyright ReportLab Europe Ltd. 2000-2017 #see license.txt for license details #history https://hg.reportlab.com/hg-public/reportlab/log/tip/docs/reference/genreference.py __version__='3.3.0' __doc__ = """ This module contains the script for building the reference. """ def run(verbose=None, outDir=None): import os, sys, shutil if verbose is None: verbose=('-s' not in sys.argv) cwd = os.getcwd() docsDir=os.path.dirname(os.path.dirname(sys.argv[0]) or cwd) topDir=os.path.dirname(docsDir) sys.path.insert(0,topDir) from tools.docco import yaml2pdf yaml2pdf.run('reference.yml','reportlab-reference.pdf') if verbose: print('Saved reportlab-reference.pdf') if not outDir: outDir = os.path.join(topDir,'docs') destfn = os.path.join(outDir,'reportlab-reference.pdf') shutil.copyfile('reportlab-reference.pdf', destfn) if verbose: print('copied to %s' % destfn) def makeSuite(): "standard test harness support - run self as separate process" from tests.utils import ScriptThatMakesFileTest return ScriptThatMakesFileTest('../docs/reference', 'genreference.py', 'reportlab-reference.pdf') if __name__=='__main__': run() ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1691062243.0 reportlab-4.1.0/docs/reference/reference.yml0000664000175000017500000002330714462707743020474 0ustar00rptlabrptlab.t ReportLab API Reference .nextPageTemplate Normal .h1 Introduction This is the API reference for the ReportLab library. All public classes, functions and methods are documented here. Most of the reference text is built automatically from the documentation strings in each class, method and function. That's why it uses preformatted text and doesn't look very pretty. Please note the following points: .bu ()Items with one leading underscore are considered private to the modules they are defined in; they are not documented here and we make no commitment to their maintenance. .bu ()Items ending in a digit (usually zero) are experimental; they are released to allow widespread testing, but are guaranteed to be broken in future (if only by dropping the zero). By all means play with these and give feedback, but do not use them in production scripts. .h2 Package Architecture The reportlab package is broken into a number of subpackages. These are as follows: .df reportlab.pdfgen - this is the programming interface to the PDF file format. The Canvas (and its co-workers, TextObject and PathObject) provide everything you need to create PDF output working at a low level - individual shapes and lines of text. Internally, it constructs blocks of page marking operators which match your drawing commands, and hand them over to the pdfbase package for drawing. .df reportlab.pdfbase - this is not part of the public interface. It contains code to handle the 'outer structure' of PDF files, and utilities to handle text metrics and compressed streams. .df reportlab.platypus - PLATYPUS stands for "Page Layout and Typography Using Scripts". It provides a higher level of abstraction dealing with paragraphs, frames on the page, and document templates. This is used for multi- page documents such as this reference. .df reportlab.lib - this contains code of interest to application developers which cuts across both of our libraries, such as standard colors, units, and page sizes. It will also contain more drawable and flowable objects in future. There is also a demos directory containing various demonstrations, and a docs directory. These can be accessed with package notation but should not be thought of as packages. Each package is documented in turn. .pageBreak .h1 reportlab.pdfgen subpackage .h2 reportlab.pdfgen.canvas module .getClassDoc reportlab.pdfgen.canvas Canvas .pageBreak .h2 reportlab.pdfgen.pathobject module The method Canvas.beginPath allows users to construct a PDFPathObject, which is defined in reportlab/pdfgen/pathobject.py. .getClassDoc reportlab.pdfgen.pathobject PDFPathObject .pageBreak .h2 reportlab.pdfgen.textobject module The method Canvas.beginText allows users to construct a PDFTextObject, which is defined in reportlab/pdfgen/textobject.py. .getClassDoc reportlab.pdfgen.textobject PDFTextObject .pageBreak .h2 reportlab.pdfgen.pdfgeom module .getModuleDoc reportlab.pdfgen.pdfgeom .h2 reportlab.pdfgen.pdfimages module .getModuleDoc reportlab.pdfgen.pdfimages .h2 reportlab.pdfgen.pycanvas module .getModuleDoc reportlab.pdfgen.pycanvas .pageBreak .h1 reportlab.platypus subpackage The platypus package defines our high-level page layout API. The division into modules is far from final and has been based more on balancing the module lengths than on any particular programming interface. The __init__ module imports the key classes into the top level of the package. .h2 Overall Structure Abstractly Platypus currently can be thought of has having four levels: documents, pages, frames and flowables (things which can fit into frames in some way). In practice there is a fifth level, the canvas, so that if you want you can do anything that pdfgen's canvas allows. .h2 Document Templates .h3 BaseDocTemplate The basic document template class; it provides for initialisation and rendering of documents. A whole bunch of methods handle_XXX handle document rendering events. These event routines all contain some significant semantics so while these may be overridden that may require some detailed knowledge. Some other methods are completely virtual and are designed to be overridden. .h3 BaseDocTemplate .getClassDoc reportlab.platypus.doctemplate BaseDocTemplate .pageBreak A simple document processor can be made using derived class, SimpleDocTemplate. .pageBreak .h3 SimpleDocTemplate .getClassDoc reportlab.platypus.doctemplate SimpleDocTemplate .pageBreak .h2 Flowables .getClassDoc reportlab.platypus.paragraph Paragraph .getClassDoc reportlab.platypus.flowables Flowable .getClassDoc reportlab.platypus.flowables XBox .getClassDoc reportlab.platypus.flowables Preformatted .getClassDoc reportlab.platypus.flowables Image .getClassDoc reportlab.platypus.flowables NullDraw .getClassDoc reportlab.platypus.flowables Spacer .getClassDoc reportlab.platypus.flowables UseUpSpace .getClassDoc reportlab.platypus.flowables PageBreak .getClassDoc reportlab.platypus.flowables SlowPageBreak .getClassDoc reportlab.platypus.flowables CondPageBreak .getClassDoc reportlab.platypus.flowables KeepTogether .getClassDoc reportlab.platypus.flowables Macro .getClassDoc reportlab.platypus.flowables CallerMacro .getClassDoc reportlab.platypus.flowables ParagraphAndImage .getClassDoc reportlab.platypus.flowables KeepInFrame .getClassDoc reportlab.platypus.flowables ImageAndFlowables .getClassDoc reportlab.platypus.flowables AnchorFlowable .getClassDoc reportlab.platypus.flowables FrameSplitter .getClassDoc reportlab.platypus.tableofcontents TableOfContents .getClassDoc reportlab.platypus.tableofcontents SimpleIndex .getClassDoc reportlab.platypus.xpreformatted XPreformatted .getClassDoc reportlab.platypus.xpreformatted PythonPreformatted .pageBreak .h1 reportlab.lib subpackage This package contains a number of modules which either add utility to pdfgen and platypus, or which are of general use in graphics applications. .h2 reportlab.lib.colors module .getModuleDoc reportlab.lib.colors .h2 reportlab.lib.corp module .getModuleDoc reportlab.lib.corp .h2 reportlab.lib.enums module .getModuleDoc reportlab.lib.enums .h2 reportlab.lib.fonts module .getModuleDoc reportlab.lib.fonts .h2 reportlab.lib.pagesizes module .getModuleDoc reportlab.lib.pagesizes .h2 reportlab.lib.sequencer module .getModuleDoc reportlab.lib.sequencer .h2 reportlab.lib.abag module .getModuleDoc reportlab.lib.abag .h2 reportlab.lib.attrmap module .getModuleDoc reportlab.lib.attrmap .h2 reportlab.lib.boxstuff module .getModuleDoc reportlab.lib.boxstuff .h2 reportlab.lib.codecharts module .getModuleDoc reportlab.lib.codecharts .h2 reportlab.lib.extformat module .getModuleDoc reportlab.lib.extformat .h2 reportlab.lib.fontfinder module .getModuleDoc reportlab.lib.fontfinder .h2 reportlab.lib.formatters module .getModuleDoc reportlab.lib.formatters .h2 reportlab.lib.geomutils module .getModuleDoc reportlab.lib.geomutils .h2 reportlab.lib.logger module .getModuleDoc reportlab.lib.logger .h2 reportlab.lib.normalDate module .getModuleDoc reportlab.lib.normalDate .h2 reportlab.lib.pdfencrypt module .getModuleDoc reportlab.lib.pdfencrypt .h2 reportlab.lib.PyFontify module .getModuleDoc reportlab.lib.PyFontify .h2 reportlab.lib.randomtext module .getModuleDoc reportlab.lib.randomtext .h2 reportlab.lib.rltempfile module .getModuleDoc reportlab.lib.rltempfile .h2 reportlab.lib.rparsexml module .getModuleDoc reportlab.lib.rparsexml .h2 reportlab.lib.set_ops module .getModuleDoc reportlab.lib.set_ops .h2 reportlab.lib.styles module .getModuleDoc reportlab.lib.styles .h2 reportlab.lib.testutils module .getModuleDoc reportlab.lib.testutils .h2 reportlab.lib.textsplit module .getModuleDoc reportlab.lib.textsplit .h2 reportlab.lib.units module .getModuleDoc reportlab.lib.units .h2 reportlab.lib.utils module .getModuleDoc reportlab.lib.utils .h2 reportlab.lib.validators module .getModuleDoc reportlab.lib.validators .h2 reportlab.lib.xmllib module .getModuleDoc reportlab.lib.xmllib .h2 reportlab.lib.yaml module .getModuleDoc reportlab.lib.yaml .pageBreak .h1 Appendix A - CVS Revision History .beginPre Code $Log: reference.yml,v $ Revision 1.1 2001/10/05 12:33:33 rgbecker Moved from original project docs, history lost Revision 1.13 2001/08/30 10:32:38 dinu_gherman Added missing flowables. Revision 1.12 2001/07/11 09:21:27 rgbecker Typo fix from Jerome Alet Revision 1.11 2000/07/10 23:56:09 andy_robinson Paragraphs chapter pretty much complete. Fancy cover. Revision 1.10 2000/07/03 15:39:51 rgbecker Documentation fixes Revision 1.9 2000/06/28 14:52:43 rgbecker Documentation changes Revision 1.8 2000/06/19 23:52:31 andy_robinson rltemplate now simple, based on UserDocTemplate Revision 1.7 2000/06/17 07:46:45 andy_robinson Small text changes Revision 1.6 2000/06/14 21:22:52 andy_robinson Added docs for library Revision 1.5 2000/06/12 11:26:34 andy_robinson Numbered list added Revision 1.4 2000/06/12 11:13:09 andy_robinson Added sequencer tags to paragraph parser Revision 1.3 2000/06/09 01:44:24 aaron_watters added automatic generation for pathobject and textobject modules. Revision 1.2 2000/06/07 13:39:22 andy_robinson Added some text to the first page of reference, and a build batch file Revision 1.1.1.1 2000/06/05 16:39:04 andy_robinson initial import .endPre ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707393948.3425586 reportlab-4.1.0/docs/source/0000775000175000017500000000000014561141634015337 5ustar00rptlabrptlab././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707393948.3425586 reportlab-4.1.0/docs/source/_static/0000775000175000017500000000000014561141634016765 5ustar00rptlabrptlab././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1691062243.0 reportlab-4.1.0/docs/source/_static/basic.css0000664000175000017500000000037414462707743020575 0ustar00rptlabrptlab/*this comment is here to alleviate a tool issue in ubuntu document production * see https://bugs.launchpad.net/ubuntu/+source/python-reportlab/+bug/1692123 * apparently zero length files cause a problem because their packager ignores * them :( */ ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1691062243.0 reportlab-4.1.0/docs/source/_static/default.css0000664000175000017500000004004314462707743021135 0ustar00rptlabrptlab/* ReportLab website stylesheet Reorder into 1. reset 2. standard styles, which should appear normally in the main content div 3. named divs for layout, with clear explanation of where they go 4. everything else that's left over. (this will be most of it at first and we can work through seeing where each item is used) */ html, body { margin: 0 0 1px; padding: 0; } body, div, dl, dt, dd, ul, ol, li, h1, h2, h3, h4, h5, h6, pre, form, fieldset, input, p, blockquote, th, td { margin:0; padding:0; font-family:"Trebuchet MS",Verdana,sans-serif; font-weight:normal; font-size: 13px; color: #444444; } body{ background: #43505d; } a { font-weight:bold; /* text-decoration: underline; */ } A:link.menu2{ color:white; text-decoration:none; } A:visited.menu2{ color:white; text-decoration:none; } A:active.menu2{ color:white; } A:hover.menu2{ color:white; } A:link{ color:#00337f; text-decoration:none; /* text-decoration: underline;*/ } A:visited{ color:#00337f; text-decoration:none; } A:active{ color:#ca002a; } A:hover{ color:#ca002a; } a.txt-green { color:#00800d; } a.txt-green:link { color:#00800d; } a.txt-green:active { color:#00800d; } a.txt-green:visited { color:#00800d; } ul{ margin: 5px 0; list-style-type: square; /*#list-style-position: inside;*/ } ol{ list-style-type:decimal; } /*ul.sidemenu {*/ /* padding-top: 0;*/ /*}*/ li.sidemenu { margin-left:15px; padding: 2px 0; /*text-indent: -1em;*/ /*#overflow:hidden;*/ /*#list-style: none; url('http://www.reportlab.com/media/level2/menu_arrow_bg.gif');*/ } li.mlevel1 { width:150px; margin-left:4px; /*#padding: 10px 0;*/ /*#background:url('http://www.reportlab.com/media/level2/menu_bar_bg.gif') repeat-x;*/ /*#list-style: none; url('http://www.reportlab.com/media/level2/menu_arrow_bg.gif');*/ } li.selected { color: #ca002a; font-weight: bold; } pre, .dp-highlighter li { /* Javascript code syntax highlighter */ font-family: monospace; font-size:11px; } .blue{background-color:#00337f} .red{background-color:#ca002a} .lightblue{background-color:#44ADC7} .green{background-color:#9ac083} .purple{background-color:#714893} .pink{background-color:#c04b95} .gray{background-color:#ccc} .txt-blue{color:#00337f} .txt-red{color:#ca002a} .txt-lightblue{color:#44ADC7} .txt-green{color:#00800d} .txt-purple{color:#714893} .txt-pink{color:#c04b95} .txt-gray{color:#ccc} .txt-white{color:#fff} .txt-blue>a, .txt-blue>a:link, .txt-blue>a:visited {color:#00337f} .txt-red>a, .txt-red>a:link, .txt-red>a:visited {color:#ca002a} .txt-lightblue>a, .txt-lightblue>a:link, .txt-lightblue>a:visited {color:#44ADC7} .txt-green>a, .txt-green>a:link, .txt-green>a:visited {color:#00800d} .txt-purple>a, .txt-purple>a:link, .txt-purple>a:visited {color:#714893} .txt-pink>a, .txt-pink>a:link, .txt-pink>a:visited {color:#c04b95} .txt-gray>a, .txt-gray>a:link, .txt-gray>a:visited {color:#ccc} .txt-white>a, .txt-white>a:link, .txt-white>a:visited {color:#fff} a#logo{ display: block; width:182px; height:113px; position:absolute; left:41px; top:23px; } a#logo img{ border: 0 none; } div#logo{ width:182px; height:113px; position:absolute; left:41px; top:23px; background: url('http://www.reportlab.com/media/base/logo_bg.gif') no-repeat; } div#topbar{ width:566px; height:7px; position:absolute; left:241px; top:77px; background: url('http://www.reportlab.com/media/base/topbar_bg.gif') no-repeat; } div#container{ position:relative; /*#border:1px none red;*/ top:0px; width:926px; margin: 17px auto 17px auto; background: #fdfdfd url('http://www.reportlab.com/media/base/page_bg.jpg') no-repeat 797px -1px; } div#content{ margin-left:43px; margin-right:43px; margin-bottom:20px; } div#footer{ margin-left:43px; margin-right:43px; } div#footer_slogan{ width: 838px; height: 19px; background: #fff url('http://www.reportlab.com/media/base/slogan_img.gif') no-repeat; } .footer{ font-size:11px; } img#login_btn{ cursor:pointer; position:absolute; top:10px; right:125px; } div#header{ height: 150px; } #call_us{ position:absolute; text-align:right; top:100px; right:125px; font-size:12pt; line-height:25px; } ul#menu{ padding-top: 0; margin-top: 0; cursor:pointer; position:absolute; top:56px; left:270px; list-style-type:none; } li.menu{ margin-left: 0; padding-top: 0; width: 95px; line-height:18px; text-align:center; font-size:13px; font-weight:bold; float:left; border-right:2px solid #00337f; } li.menu:hover, li.menu:hover>a, li.menu:hover>a:link, li.menu:hover>a:visited, li.menu:hover>a:hover { color: black; } li.menu>a { display: block; } li.highlight_blue:hover{ background: #00337f; } li.highlight_lightblue:hover{ background: #44ADC7; } li.highlight_green:hover{ background: #9ac083; } li.highlight_purple:hover{ background: #714893; } li.highlight_pink:hover{ background: #c04b95; } div#shadow{ position:absolute; top:68px; left:163px; background: url('http://www.reportlab.com/media/base/menu_bg.jpg') no-repeat; width:550px; height:48px; } div#clear{ clear:both; height:10px; } .intro{ padding:20px; padding-top:30px; font-size:10pt; line-height:14pt; font-weight:normal; text-align:justify; } td#slogan{ text-align:center; } table#footer_table{ width:100%; } p.title{ font-size:13pt; line-height:16pt; color: #00337F; } p.teaser{ font-style: italic; font-weight: bold; } /* Added by andy. This is all wrong; the base styles should cover standard text, and the 'home page' or 'menu' styles. should be overridden in each page that needs them, and with selectors like '#menu li'. */ table { /*#border: 1px solid #e5e5e5;*/ border-bottom: 0; border-collapse: collapse; } table th { font-weight: bold; text-align: left; background-color: #e5e5e5; padding: 3px; } table th.left { width: 12em; } table td { /*#border-bottom: 1px solid #e5e5e5;*/ padding: 3px 8px; } table#main_content td { /*#border-bottom: 1px solid #e5e5e5;*/ padding: 0; } hr { border: 0; border-top: 1px solid #e5e5e5; } #main_content_teaser{ font-style:italic; font-weight:bold; font-size:13pt; margin: 15px 0; } #main_content_sub_pages{ width:450px; min-height:700px; margin:10px; float:left; /*font-size:16px;*/ } #main_content_sub_pages_wide{ width:600px; min-height:700px; margin:10px; float:left; /*font-size:16px;*/ } #content h1 { font-size:20px; margin: 0 0 20px 0; color:#264D90; font-weight:bold; line-height:40px; } #content h2 { font-size:18px; margin: 25px 0 10px 0; font-weight: bold; color: #264D90; } #content h3 { font-size:15px; margin: 12px 0 4px 0; font-weight: bold; color: #264D90; } #content h4 { font-size:13px; margin: 5px 0 0 0; font-weight: bold; color: #264D90; } #content p { margin: 10px 0; font-size: 13px; } li { margin-left: 15px; list-style-position: outside; /*#list-style-type:square;*/ } ul { margin-left: 10px; list-style-position: outside; } #breadcrumb{ position: absolute; left: 250px; top: 90px; height: 22px; width: 560px; font-weight:bold; /*background:pink; uncomment to see it*/ margin-top:20px; /*border:1px solid #f2f2f2;*/ font-size:12px; line-height:24px; text-indent:21px; color:#264D90; } #divider{ height:100%; background:white; border-top:1px solid #E5E5E5; margin-top:10px; } #nav_bar{ float:left; margin-left:0px; margin-top:16px; } #nav_bar_top{ width:180px; height:100%; background:url('http://www.reportlab.com/media/level2/menu_bg.gif') repeat-y; color:white; /*#text-indent:10px;*/ color:#264D90; /*#padding-left:10pt;*/ padding: 5px 10px; } #nav_bar_bottom{ height:37px; width:200px; background:url('http://www.reportlab.com/media/level2/menu_footer_bg.gif') no-repeat; line-height:37px; } #nav_bar li { /*#margin-left: 8px;*/ /*#list-style-position: inside;*/ font-size:12px; font-weight:bold; } #nav_bar ul { margin-left: 5px; list-style-position: inside; } #side_div h1 { font-size: 13px; margin: 0 0 12px 25px; color: #000; font-weight:bold; text-align: left; } #side_div a.related_item img { width:100px; height:100px; display:block; margin:0 auto; border: 0; padding-top: 10px; } #side_div li { list-style: none; } table.price_table th { padding-right:10pt; text-align:right; } td.tick { text-align:center; } .notification { border: 2px solid #43505d; padding: 15px; background: #c0c4c9; color: #000; margin: 10px 0; } /* juraj starts here */ #users-navigation { float: right; height: 22px; margin: 10px 120px 10px 10px; background-image: url(status_left.gif); background-repeat: no-repeat; background-position: left; padding-left:2px; } #users-navigation div, #users-navigation a{ color: white; font-size: 90%; line-height: 22px; } #users-navigation div{ float: left; height: 22px; background-image: url(status_middle.gif); padding-left: 3px; } #users-navigation a{ padding-right: 3px; } #users-navigation a:hover{ text-decoration: underline; } #users-navigation div.last{ background-image: url(status_right.gif); background-repeat: no-repeat; } #loggedAs{ float: right; margin: 10px 10px 10px; height: 22px; line-height: 25px; font-size: 10px; } #messages{ margin-left:57px; margin-right:43px; font-size:14px; line-height:24px; text-indent:21px; color:#264D90; } #overlay{ display: block; position: absolute; top: 0pt; left: 0pt; z-index: 2; width: 100%; /* background-image:url('overlay.png'); */ } * html #overlay{ background-color: #333; back\ground-color: transparent; background-image: url(blank.gif); filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src="overlay.png", sizingMethod="scale"); } .overlaydiv{ background-color: #ffffff; position: absolute; width: 550px; left: 50%; top: 100px; margin-left: -275px; padding: 10px; z-index: 102; border: 2px solid #000000; display: none; } .overlaydiv div{ padding: 10px; width: 500px; margin-left: auto; margin-right: auto; z-index: 102; /* border: 2px solid #00337f; */ } .noborder{ border: none; } /* :::::::::::: START accesible forms styles :::::::::::: */ /* color #00337f is reportlab blue */ form.accform li { list-style: none; border: none; } form.accform ul{ margin: 0px 0px 0px 0px; padding: 0px 0px 0px 0px; border: none; } form.accform li{ margin: 0px 0px 5px 0px; padding: 0px 0px 5px 0px; } /* borders */ form.accform textarea, form.accform input[type="text"]{ border: 1px solid #CCCCCC; display: inline-block; } /* labels are used for alignement : overide width if needed */ form.accform label{ display: block; text-align: left; float: left; width: 80px; } /* fieldset with legend */ form.accform fieldset{ border: none; border-top: 2px solid #00337f; padding-top: 10px; } form.accform legend{ font-weight: bold; color: #00337f; } /* highlight elements with errors not working in IE6 */ form.accform ul.errorlist + label + input, form.accform ul.errorlist + label + textarea, form.accform ul.errorlist + label + dl + textarea, form.accform ul.errorlist + label + div + textarea, form.accform ul.errorlist + label + select{ border: 1px solid #800000; } /* this margin should be same as label width */ form.accform ul.errorlist li { margin-left: 80px; } /* some help text dd dt styles */ dl.accform { float: right; } dl.accform > dt:first-child{ padding-bottom: 5px; color: #00337f; } /* :::::::::::: END accesible forms styles :::::::::::: */ /* :::::::::::: START definition list :::::::::::: */ /* inline ; definition type bold */ /* #content #sidebar dl dt, #content #sidebar dl dd { */ /* float: left; */ /* margin-right: 0.5em; */ /* margin-bottom: 0.5em; */ /* } */ /* #content #sidebar dl dt { */ /* clear: left; */ /* font-weight: bold; */ /* } */ dl.inline dt, dl.inline dd { float: left; margin-right: 0.5em; margin-bottom: 0.5em; } dl.inline dd { *float: none; } dl.inline dt{ clear: left; font-weight: bold; } /* :::::::::::: END definition list :::::::::::: */ /* :::::::::::: START snippets form :::::::::::: */ #snippetForm label { width: 130px; } #snippetForm ul.errorlist li { margin-left: 100px; } #snippetForm textarea, #snippetForm input[type="text"]{ width: 410px } .help{ display: none; float: right; width: 270px; } .help textarea{ width: 250px !important; } ul.snippets li{ padding-bottom: 5px; } /* :::::::::::: END snippets form :::::::::::: */ /* :::::::::::: START contact us form :::::::::::: */ #contactusContainer{ display: none; background-color: white; } #contactusContainer fieldset{ border: none; width: 500px; } #contactusContainer textarea, #contactusContainer input[type="text"]{ width: 410px } /* :::::::::::: END contact us form :::::::::::: */ /* :::::::::::: START footer :::::::::::: */ .newFooter{ position: relative; clear: both; } hr#topbar{ width:566px; height:7px; position:absolute; left:241px; top:77px; } .newFooter hr, hr#topbar{ color: #00337f; background-color: #00337f; height: 5px; } .newFooter span{ color: red; } .newFooter div{ position: absolute; left: 500px; top: -13px; background-color: #ffffff; padding: 5px; color: #00337f; font-weight: bold; font-size: 120%; } /* :::::::::::: END footer :::::::::::: */ /* :::::::::::: START columns div :::::::::::: */ div.columns{ overflow: auto; width: 100%; padding: 5px 0px; } div.columns br{ clear: both; } div.columns > div{ float: left; width: 47%; /* padding: 1%; */ /* border: 1px solid red; */ } div.columns div + div{ float: right; clear: right; } div.columns_80_20 > div{ width: 78%; } div.columns_80_20 > div + div{ width: 17% } div.columns_70_30 > div{ width: 68%; } div.columns_70_30 > div + div{ width: 27% } /* :::::::::::: END columns div :::::::::::: */ /* :::::::::::: START general :::::::::::: */ .floatright{ display: block; float: right; } span.contact{ color: #00337f; text-decoration: underline; font-weight: bold; cursor: pointer; } span.contact:hover{ color: #ca002a; } /* :::::::::::: END general :::::::::::: */ .center{ margin-left:auto; margin-right:auto; display:block; } .border{ border: 1px solid #cccccc; padding: 2px; } /* :::::::::::: END general :::::::::::: */ /* :::::::::::: START prifile :::::::::::: */ #accordion{ display: none; } #accordion h3{ margin: 0px; padding: 0px; } #accordion div.notification{ margin: 0px; padding: 5px; } div.gcbutton{ /* height: 48px; */ line-height: 40px; width: 200px; overflow-x: hidden; } div.gcbutton img{ display: inline; } span.expand{ font-weight: normal; font-size: 80%; cursor: pointer; padding-left: 10px; /* display: inline-block; */ } div.profileSection{ border-bottom: 2px solid #00337f; padding: 5px 0px; } /* div.profileSection div.toogle{ */ /* display: nonex; */ /* } */ /* remove important later when css is fixed !!! */ div.profileSection h2{ margin: 0px 0px 0px 0px !important; display: inline } div.profileSection p{ margin: 5px 0px !important; } div.center{ width: 600px; margin-left: auto; margin-right: auto; } div.profileSection div.notification{ margin: 0px 0px 0px 0px !important; } div.profileSection div.notification h3{ margin: 0px 0px 0px 0px !important; } dl.profile dt{ width: 100px; } .tag_icons { float: right; } .tag_icons img { border: 0; } /* Fix for Jquery accordion in IE~6 */ .ui-accordion-content{ zoom: 1; } /* Sphinx docs */ div.related, body>div.sphinxsidebar, body>div.document>div.sphinxsidebar, body>div.footer { display: none; } pre { background:#ECF0F3; border:1px solid #d7e7f3; border-left:0; border-right:0; padding:0.5em; margin:10px 0; } dl { margin-bottom:15px; } tt { background-color:#ECF0F3; font-size:0.95em; padding:0 1px; } tt.descname { font-size:1.2em; font-weight:bold; } dd { margin-bottom:10px; margin-left:30px; margin-top:3px; } div.body p, div.body dd, div.body li { line-height:130%; } a.headerlink { color:#ECF0F3; } a.headerlink:hover{ color:#ca002a; } ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707393948.3425586 reportlab-4.1.0/docs/source/_templates/0000775000175000017500000000000014561141634017474 5ustar00rptlabrptlab././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1691062243.0 reportlab-4.1.0/docs/source/_templates/layout.html0000664000175000017500000000024714462707743021713 0ustar00rptlabrptlab{% extends "!layout.html" %} {% block rootrellink %} {{ super() }} {% endblock %} ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1691062243.0 reportlab-4.1.0/docs/source/_templates/page.html0000664000175000017500000000262714462707743021316 0ustar00rptlabrptlab{% extends "layout.html" %} {% block body %}
{% block relbar1 %}{{ relbar() }}{% endblock %} {{ body }} {% block relbar2 %}{{ relbar() }}{% endblock %}
{% endblock %} ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1691062243.0 reportlab-4.1.0/docs/source/conf.py0000664000175000017500000001443314462707743016654 0ustar00rptlabrptlab# -*- coding: utf-8 -*- # # reportlab documentation build configuration file, created by # sphinx-quickstart on Fri Feb 5 21:41:03 2010. # # This file is execfile()d with the current directory set to its containing dir. # # Note that not all possible configuration values are present in this # autogenerated file. # # All configuration values have a default; values that are commented out # serve to show the default. import sys, os # If extensions (or modules to document with autodoc) are in another directory, # add these directories to sys.path here. If the directory is relative to the # documentation root, use os.path.abspath to make it absolute, like shown here. #sys.path.append(os.path.abspath('.')) # -- General configuration ----------------------------------------------------- # Add any Sphinx extension module names here, as strings. They can be extensions # coming with Sphinx (named 'sphinx.ext.*') or your custom ones. extensions = ['sphinx.ext.autodoc', 'sphinx.ext.doctest', 'sphinx.ext.todo', 'sphinx.ext.coverage'] # Add any paths that contain templates here, relative to this directory. templates_path = ['_templates'] # The suffix of source filenames. source_suffix = '.rst' # The encoding of source files. #source_encoding = 'utf-8' # The master toctree document. master_doc = 'index' # General information about the project. project = 'reportlab' copyright = '2010, Robinson, Becker, Watters and many more' # The version info for the project you're documenting, acts as replacement for # |version| and |release|, also used in various other places throughout the # built documents. # # The short X.Y version. version = '2.4' # The full version, including alpha/beta/rc tags. release = '2.4' # The language for content autogenerated by Sphinx. Refer to documentation # for a list of supported languages. #language = None # There are two options for replacing |today|: either, you set today to some # non-false value, then it is used: #today = '' # Else, today_fmt is used as the format for a strftime call. #today_fmt = '%B %d, %Y' # List of documents that shouldn't be included in the build. #unused_docs = [] # List of directories, relative to source directory, that shouldn't be searched # for source files. exclude_trees = [] # The reST default role (used for this markup: 'text') to use for all documents. #default_role = None # If true, '()' will be appended to :func: etc. cross-reference text. #add_function_parentheses = True # If true, the current module name will be prepended to all description # unit titles (such as .. function::). #add_module_names = True # If true, sectionauthor and moduleauthor directives will be shown in the # output. They are ignored by default. #show_authors = False # The name of the Pygments (syntax highlighting) style to use. pygments_style = 'sphinx' # A list of ignored prefixes for module index sorting. #modindex_common_prefix = [] # -- Options for HTML output --------------------------------------------------- # The theme to use for HTML and HTML Help pages. Major themes that come with # Sphinx are currently 'default' and 'sphinxdoc'. html_theme = 'default' # Theme options are theme-specific and customize the look and feel of a theme # further. For a list of options available for each theme, see the # documentation. #html_theme_options = {} # Add any paths that contain custom themes here, relative to this directory. #html_theme_path = [] # The name for this set of Sphinx documents. If None, it defaults to # " v documentation". #html_title = None # A shorter title for the navigation bar. Default is the same as html_title. #html_short_title = None # The name of an image file (relative to this directory) to place at the top # of the sidebar. #html_logo = None # The name of an image file (within the static path) to use as favicon of the # docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32 # pixels large. #html_favicon = None # Add any paths that contain custom static files (such as style sheets) here, # relative to this directory. They are copied after the builtin static files, # so a file named "default.css" will overwrite the builtin "default.css". html_static_path = ['_static'] # If not '', a 'Last updated on:' timestamp is inserted at every page bottom, # using the given strftime format. #html_last_updated_fmt = '%b %d, %Y' # If true, SmartyPants will be used to convert quotes and dashes to # typographically correct entities. #html_use_smartypants = True # Custom sidebar templates, maps document names to template names. #html_sidebars = {} # Additional templates that should be rendered to pages, maps page names to # template names. #html_additional_pages = {} # If false, no module index is generated. #html_use_modindex = True # If false, no index is generated. #html_use_index = True # If true, the index is split into individual pages for each letter. #html_split_index = False # If true, links to the reST sources are added to the pages. #html_show_sourcelink = True # If true, an OpenSearch description file will be output, and all pages will # contain a tag referring to it. The value of this option must be the # base URL from which the finished HTML is served. #html_use_opensearch = '' # If nonempty, this is the file name suffix for HTML files (e.g. ".xhtml"). #html_file_suffix = '' # Output file base name for HTML help builder. htmlhelp_basename = 'reportlabdoc' # -- Options for LaTeX output -------------------------------------------------- # The paper size ('letter' or 'a4'). #latex_paper_size = 'letter' # The font size ('10pt', '11pt' or '12pt'). #latex_font_size = '10pt' # Grouping the document tree into LaTeX files. List of tuples # (source start file, target name, title, author, documentclass [howto/manual]). latex_documents = [ ('index', 'reportlab.tex', 'reportlab Documentation', 'Robinson, Becker, Watters and many more', 'manual'), ] # The name of an image file (relative to this directory) to place at the top of # the title page. #latex_logo = None # For "manual" documents, if this is true, then toplevel headings are parts, # not chapters. #latex_use_parts = False # Additional stuff for the LaTeX preamble. #latex_preamble = '' # Documents to append as an appendix to all manuals. #latex_appendices = [] # If false, no module index is generated. #latex_use_modindex = True ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1691062243.0 reportlab-4.1.0/docs/source/graphics.rst0000664000175000017500000000250114462707743017700 0ustar00rptlabrptlab=================================== Graphics and Charts =================================== .. rubric:: Graphics and Charts barcode ----------------------- .. automodule:: reportlab.graphics.barcode :members: charts ----------------------- .. automodule:: reportlab.graphics.charts :members: renderPDF ----------------------- .. automodule:: reportlab.graphics.renderPDF :members: renderPM ----------------------- .. automodule:: reportlab.graphics.renderPM :members: renderPS ----------------------- .. automodule:: reportlab.graphics.renderPS :members: renderSVG ----------------------- .. automodule:: reportlab.graphics.renderSVG :members: renderbase ----------------------- .. automodule:: reportlab.graphics.renderbase :members: samples ----------------------- .. automodule:: reportlab.graphics.samples :members: shapes ----------------------- .. automodule:: reportlab.graphics.shapes :members: testdrawings ----------------------- .. automodule:: reportlab.graphics.testdrawings :members: testshapes ----------------------- .. automodule:: reportlab.graphics.testshapes :members: widgetbase ----------------------- .. automodule:: reportlab.graphics.widgetbase :members: widgets ----------------------- .. automodule:: reportlab.graphics.widgets :members: ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1691062243.0 reportlab-4.1.0/docs/source/index.rst0000664000175000017500000000203114462707743017205 0ustar00rptlabrptlab.. reportlab documentation master file, created by sphinx-quickstart on Fri Feb 5 21:41:03 2010. You can adapt this file completely to your liking, but it should at least contain the root `toctree` directive. =================================== ReportLab PDF Toolkit documentation =================================== .. rubric:: API references and more for the ReportLab PDF Toolkit Contents: .. toctree:: :maxdepth: 2 pdfgen package (reportlab.pdfgen) - the basics Platypus (reportlab.platypus) - long flowing documents Graphics and Charts (reportlab.graphics) Library and utilities (reportlab.lib) Sphinx is being used for the automated API references. We have always been able to make our own documents in PDF, without using other peoples' libraries, and don't want to back away from this. So, the main User Guide will remain in PDF format for now. However, programmers need API refs online, and we want to learn Sphinx (and use rst2pdf) in due course. ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1691062243.0 reportlab-4.1.0/docs/source/lib.rst0000664000175000017500000000156514462707743016657 0ustar00rptlabrptlab=================================== ReportLab Library Reference =================================== .. rubric:: API main index This page covers modules within reportlab/lib which may be of use to developers. We have tried only to include things we intend people to use; a lot of code in /lib/ is used by our package itself, and we reserve the right to change it if it's not documented here. Hint: review tests and user guide and see what is actually imported Users definitely need: * units * colors * utils See what else is commonly imported and used in the test scripts! If in doubt, include it and put a comment so Andy can review. units ----------------------- .. automodule:: reportlab.lib.units :members: colors -------------------- .. automodule:: reportlab.lib.colors :members: utils -------------------- .. automodule:: reportlab.lib.utils :members: ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1691062243.0 reportlab-4.1.0/docs/source/pdfgen.rst0000664000175000017500000000035614462707743017351 0ustar00rptlabrptlab=================================== package reportlab.pdfgen =================================== .. rubric:: The basics module reportlab.pdfgen.canvas ------------------------------ .. automodule:: reportlab.pdfgen.canvas :members: ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1691062243.0 reportlab-4.1.0/docs/source/platypus.rst0000664000175000017500000000173014462707743017764 0ustar00rptlabrptlab=================================== Platypus =================================== .. rubric:: long flowing documents doctemplate ----------------------- .. automodule:: reportlab.platypus.doctemplate :members: paragraph ----------------------- .. automodule:: reportlab.platypus.paragraph :members: paraparser ----------------------- .. automodule:: reportlab.platypus.paraparser :members: flowables ----------------------- .. automodule:: reportlab.platypus.flowables :members: frames ----------------------- .. automodule:: reportlab.platypus.frames :members: figures ----------------------- .. automodule:: reportlab.platypus.figures :members: tables ----------------------- .. automodule:: reportlab.platypus.tables :members: tableofcontents ----------------------- .. automodule:: reportlab.platypus.tableofcontents :members: xpreformatted ----------------------- .. automodule:: reportlab.platypus.xpreformatted :members: ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707393948.3945587 reportlab-4.1.0/docs/userguide/0000775000175000017500000000000014561141634016033 5ustar00rptlabrptlab././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1691062243.0 reportlab-4.1.0/docs/userguide/app_demos.py0000664000175000017500000001061614462707743020371 0ustar00rptlabrptlab#Copyright ReportLab Europe Ltd. 2000-2017 #see license.txt for license details #history https://hg.reportlab.com/hg-public/reportlab/log/tip/docs/userguide/app_demos.py from tools.docco.rl_doc_utils import * Appendix1("ReportLab Demos") disc("""In the subdirectories of $reportlab/demos$ there are a number of working examples showing almost all aspects of reportlab in use.""") heading2("""Odyssey""") disc(""" The three scripts odyssey.py, dodyssey.py and fodyssey.py all take the file odyssey.txt and produce PDF documents. The included odyssey.txt is short; a longer and more testing version can be found at ftp://ftp.reportlab.com/odyssey.full.zip. """) eg(""" Windows cd reportlab\\demos\\odyssey python odyssey.py start odyssey.pdf Linux cd reportlab/demos/odyssey python odyssey.py acrord odyssey.pdf """) disc("""Simple formatting is shown by the odyssey.py script. It runs quite fast, but all it does is gather the text and force it onto the canvas pages. It does no paragraph manipulation at all so you get to see the XML < & > tags. """) disc("""The scripts fodyssey.py and dodyssey.py handle paragraph formatting so you get to see colour changes etc. Both scripts use the document template class and the dodyssey.py script shows the ability to do dual column layout and uses multiple page templates. """) heading2("""Standard Fonts and Colors""") disc("""In $reportlab/demos/stdfonts$ the script stdfonts.py can be used to illustrate ReportLab's standard fonts. Run the script using""") eg(""" cd reportlab\\demos\\stdfonts python stdfonts.py """) disc(""" to produce two PDF documents, StandardFonts_MacRoman.pdf & StandardFonts_WinAnsi.pdf which show the two most common built in font encodings. """) disc("""The colortest.py script in $reportlab/demos/colors$ demonstrates the different ways in which reportlab can set up and use colors.""") disc("""Try running the script and viewing the output document, colortest.pdf. This shows different color spaces and a large selection of the colors which are named in the $reportlab.lib.colors$ module. """) heading2("""Py2pdf""") disc("""Dinu Gherman contributed this useful script which uses reportlab to produce nicely colorized PDF documents from Python scripts including bookmarks for classes, methods and functions. To get a nice version of the main script try""") eg(""" cd reportlab/demos/py2pdf python py2pdf.py py2pdf.py acrord py2pdf.pdf """) disc("""i.e. we used py2pdf to produce a nice version of py2pdf.py in the document with the same rootname and a .pdf extension. """) disc(""" The py2pdf.py script has many options which are beyond the scope of this simple introduction; consult the comments at the start of the script. """) heading2("Gadflypaper") disc(""" The Python script, gfe.py, in $reportlab/demos/gadflypaper$ uses an inline style of document preparation. The script almost entirely produced by Aaron Watters produces a document describing Aaron's $gadfly$ in memory database for Python. To generate the document use """) eg(""" cd reportlab\\gadflypaper python gfe.py start gfe.pdf """) disc(""" everything in the PDF document was produced by the script which is why this is an inline style of document production. So, to produce a header followed by some text the script uses functions $header$ and $p$ which take some text and append to a global story list. """) eg(''' header("Conclusion") p("""The revamped query engine design in Gadfly 2 supports .......... and integration.""") ''') heading2("""Pythonpoint""") disc("""Andy Robinson has refined the pythonpoint.py script (in $reportlab\\demos\\pythonpoint$) until it is a really useful script. It takes an input file containing an XML markup and uses an xmllib style parser to map the tags into PDF slides. When run in its own directory pythonpoint.py takes as a default input the file pythonpoint.xml and produces pythonpoint.pdf which is documentation for Pythonpoint! You can also see it in action with an older paper """) eg(""" cd reportlab\\demos\\pythonpoint python pythonpoint.py monterey.xml start monterey.pdf """) disc(""" Not only is pythonpoint self documenting, but it also demonstrates reportlab and PDF. It uses many features of reportlab (document templates, tables etc). Exotic features of PDF such as fadeins and bookmarks are also shown to good effect. The use of an XML document can be contrasted with the inline style of the gadflypaper demo; the content is completely separate from the formatting """) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1691062243.0 reportlab-4.1.0/docs/userguide/ch1_intro.py0000664000175000017500000004243414462707743020313 0ustar00rptlabrptlab#Copyright ReportLab Europe Ltd. 2000-2017 #see license.txt for license details __version__ = '$Id$' from tools.docco.rl_doc_utils import * from reportlab.platypus.tableofcontents import TableOfContents import reportlab from reportlab.lib.utils import TimeStamp title("ReportLab PDF Library") title("User Guide") centred('ReportLab Version ' + reportlab.Version) centred(TimeStamp().datetime.strftime('Document generated on %Y/%m/%d %H:%M:%S %Z')) nextTemplate("TOC") headingTOC() toc = TableOfContents() PS = ParagraphStyle toc.levelStyles = [ PS(fontName='Times-Bold', fontSize=14, name='TOCHeading1', leftIndent=20, firstLineIndent=-20, spaceBefore=5, leading=16), PS(fontSize=12, name='TOCHeading2', leftIndent=40, firstLineIndent=-20, spaceBefore=0, leading=12), PS(fontSize=10, name='TOCHeading3', leftIndent=60, firstLineIndent=-20, spaceBefore=0, leading=12), PS(fontSize=10, name='TOCHeading4', leftIndent=100, firstLineIndent=-20, spaceBefore=0, leading=12), ] getStory().append(toc) nextTemplate("Normal") ######################################################################## # # Chapter 1 # ######################################################################## heading1("Introduction") heading2("About this document") disc("""This document is an introduction to the ReportLab PDF library. Some previous programming experience is presumed and familiarity with the Python Programming language is recommended. If you are new to Python, we tell you in the next section where to go for orientation. """) disc(""" This manual does not cover 100% of the features, but should explain all the main concepts and help you get started, and point you at other learning resources. After working your way through this, you should be ready to begin writing programs to produce sophisticated reports. """) disc("""In this chapter, we will cover the groundwork:""") bullet("What is ReportLab all about, and why should I use it?") bullet("What is Python?") bullet("How do I get everything set up and running?") todo(""" We need your help to make sure this manual is complete and helpful. Please send any feedback to our user mailing list, which is signposted from www.reportlab.com. """) heading2("What is the ReportLab PDF Library?") disc("""This is a software library that lets you directly create documents in Adobe's Portable Document Format (PDF) using the Python programming language. It also creates charts and data graphics in various bitmap and vector formats as well as PDF.""") disc("""PDF is the global standard for electronic documents. It supports high-quality printing yet is totally portable across platforms, thanks to the freely available Acrobat Reader. Any application which previously generated hard copy reports or driving a printer can benefit from making PDF documents instead; these can be archived, emailed, placed on the web, or printed out the old-fashioned way. However, the PDF file format is a complex indexed binary format which is impossible to type directly. The PDF format specification is more than 600 pages long and PDF files must provide precise byte offsets -- a single extra character placed anywhere in a valid PDF document can render it invalid. This makes it harder to generate than HTML.""") disc("""Most of the world's PDF documents have been produced by Adobe's Acrobat tools, or rivals such as JAWS PDF Creator, which act as 'print drivers'. Anyone wanting to automate PDF production would typically use a product like Quark, Word or Framemaker running in a loop with macros or plugins, connected to Acrobat. Pipelines of several languages and products can be slow and somewhat unwieldy. """) disc("""The ReportLab library directly creates PDF based on your graphics commands. There are no intervening steps. Your applications can generate reports extremely fast - sometimes orders of magnitude faster than traditional report-writing tools. This approach is shared by several other libraries - PDFlib for C, iText for Java, iTextSharp for .NET and others. However, The ReportLab library differs in that it can work at much higher levels, with a full featured engine for laying out documents complete with tables and charts. """) disc("""In addition, because you are writing a program in a powerful general purpose language, there are no restrictions at all on where you get your data from, how you transform it, and the kind of output you can create. And you can reuse code across whole families of reports.""") disc("""The ReportLab library is expected to be useful in at least the following contexts:""") bullet("Dynamic PDF generation on the web") bullet("High-volume corporate reporting and database publishing") bullet("""An embeddable print engine for other applications, including a 'report language' so that users can customize their own reports. This is particularly relevant to cross-platform apps which cannot rely on a consistent printing or previewing API on each operating system.""") bullet("""A 'build system' for complex documents with charts, tables and text such as management accounts, statistical reports and scientific papers """) bullet("""Going from XML to PDF in one step""") heading2("ReportLab's commercial software") disc(""" The ReportLab library forms the foundation of our commercial solution for PDF generation, Report Markup Language (RML). This is available for evaluation on our web site with full documentation. We believe that RML is the fastest and easiest way to develop rich PDF workflows. You work in a markup language at a similar level to HTML, using your favorite templating system to populate an RML document; then call our rml2pdf API function to generate a PDF. It's what ReportLab staff use to build all of the solutions you can see on reportlab.com. Key differences: """) bullet("""Fully documented with two manuals, a formal specification (the DTD) and extensive self-documenting tests. (By contrast, we try to make sure the open source documentation isn't wrong, but we don't always keep up with the code)""") bullet("""Work in high-level markup rather than constructing graphs of Python objects """) bullet("""Requires no Python expertise - your colleagues may thank you after you've left!'""") bullet("""Support for vector graphics and inclusion of other PDF documents""") bullet("""Many more useful features expressed with a single tag, which would need a lot of coding in the open source package""") bullet("""Commercial support is included""") disc(""" We ask open source developers to consider trying out RML where it is appropriate. You can register on our site and try out a copy before buying. The costs are reasonable and linked to the volume of the project, and the revenue helps us spend more time developing this software.""") heading2("What is Python?") disc(""" Python is an interpreted, interactive, object-oriented programming language. It is often compared to Tcl, Perl, Scheme or Java. """) disc(""" Python combines remarkable power with very clear syntax. It has modules, classes, exceptions, very high level dynamic data types, and dynamic typing. There are interfaces to many system calls and libraries, as well as to various windowing systems (X11, Motif, Tk, Mac, MFC). New built-in modules are easily written in C or C++. Python is also usable as an extension language for applications that need a programmable interface. """) disc(""" Python is as old as Java and has been growing steadily in popularity for years; since our library first came out it has entered the mainstream. Many ReportLab library users are already Python devotees, but if you are not, we feel that the language is an excellent choice for document-generation apps because of its expressiveness and ability to get data from anywhere. """) disc(""" Python is copyrighted but freely usable and distributable, even for commercial use. """) heading2("Acknowledgements") disc("""Many people have contributed to ReportLab. We would like to thank in particular (in alphabetical order): Albertas Agejevas, Alex Buck, Andre Reitz, Andrew Cutler, Andrew Mercer, Ben Echols, Benjamin Dumke, Benn B, Chad Miller, Chris Buergi, Chris Lee, Christian Jacobs, Dinu Gherman, Edward Greve, Eric Johnson, Felix Labrecque, Fubu @ bitbucket, Gary Poster, Germán M. Bravo, Guillaume Francois, Hans Brand, Henning Vonbargen, Hosam Aly, Ian Stevens, James Martin-Collar, Jeff Bauer, Jerome Alet, Jerry Casiano, Jorge Godoy, Keven D Smith, Kyle MacFarlane, Magnus Lie Hetland, Marcel Tromp, Marius Gedminas, Mark de Wit, Matthew Duggan, Matthias Kirst, Matthias Klose, Max M, Michael Egorov, Michael Spector, Mike Folwell, Mirko Dziadzka, Moshe Wagner, Nate Silva, Paul McNett, Peter Johnson, PJACock, Publio da Costa Melo, Randolph Bentson, Robert Alsina, Robert Hölzl, Robert Kern, Ron Peleg, Ruby Yocum, Simon King, Stephan Richter, Steve Halasz, Stoneleaf @ bitbucket, T Blatter, Tim Roberts, Tomasz Swiderski, Ty Sarna, Volker Haas, Yoann Roman, and many more.""") disc("""Special thanks go to Just van Rossum for his valuable assistance with font technicalities.""") disc("""Moshe Wagner and Hosam Aly deserve a huge thanks for contributing to the RTL patch, which is not yet on the trunk.""") disc("""Marius Gedminas deserves a big hand for contributing the work on TrueType fonts and we are glad to include these in the toolkit. Finally we thank Michal Kosmulski for the DarkGarden font for and Bitstream Inc. for the Vera fonts.""") heading2("Installation and Setup") disc("""To avoid duplication, the installation instructions are kept in the README file in our distribution, which can be viewed online at ^https://hg.reportlab.com/hg-public/reportlab/^""") disc("""This release (%s) of ReportLab requires Python versions %s.%s+ or higher. If you need to use Python 2, please use the latest ReportLab 2.7 package that is suitable for you. """ % ((reportlab.Version,)+reportlab.__min_python_version__)) heading2("Getting Involved") disc("""ReportLab is an Open Source project. Although we are a commercial company we provide the core PDF generation sources freely, even for commercial purposes, and we make no income directly from these modules. We also welcome help from the community as much as any other Open Source project. There are many ways in which you can help:""") bullet("""General feedback on the core API. Does it work for you? Are there any rough edges? Does anything feel clunky and awkward?""") bullet("""New objects to put in reports, or useful utilities for the library. We have an open standard for report objects, so if you have written a nice chart or table class, why not contribute it?""") bullet("""Snippets and Case Studies: If you have produced some nice output, register online on ^http://www.reportlab.com^ and submit a snippet of your output (with or without scripts). If ReportLab solved a problem for you at work, write a little 'case study' and submit it. And if your web site uses our tools to make reports, let us link to it. We will be happy to display your work (and credit it with your name and company) on our site!""") bullet("""Working on the core code: we have a long list of things to refine or to implement. If you are missing some features or just want to help out, let us know!""") disc("""The first step for anyone wanting to learn more or get involved is to join the mailing list. To Subscribe visit $http://two.pairlist.net/mailman/listinfo/reportlab-users$. From there you can also browse through the group's archives and contributions. The mailing list is the place to report bugs and get support. """) disc("""The code now lives on our website ($http://hg.reportlab.com/hg-public/reportlab/$) in a Mercurial repository, along with an issue tracker and wiki. Everyone should feel free to contribute, but if you are working actively on some improvements or want to draw attention to an issue, please use the mailing list to let us know.""") heading2("Site Configuration") disc("""There are a number of options which most likely need to be configured globally for a site. The python script module $reportlab/rl_config.py$ aggregates the various settings files. You may want inspect the file $reportlab/$rl_settings.py$ which contains defaults for the currently used variables. There are several overrides for $rl_settings" modules $reportlab.local_rl_settings$, $reportlab_settings$ (a script file anywhere on the python path) and finally the file $~/.reportlab_settings$ (note no .py). Temporary changes can be made using evironment variables which are the variables from $rl_settings.py" prefixed with $RL_$ eg $RL_verbose=1$. """) heading3("Useful rl_config variables") bullet("""verbose: set to integer values to control diagnostic output.""") bullet("""shapeChecking: set this to zero to turn off a lot of error checking in the graphics modules""") bullet("""defaultEncoding: set this to WinAnsiEncoding or MacRomanEncoding.""") bullet("""defaultPageSize: set this to one of the values defined in reportlab/lib/pagesizes.py; as delivered it is set to pagesizes.A4; other values are pagesizes.letter etc.""") bullet("""defaultImageCaching: set to zero to inhibit the creation of .a85 files on your hard-drive. The default is to create these preprocessed PDF compatible image files for faster loading""") bullet("""T1SearchPath: this is a python list of strings representing directories that may be queried for information on Type 1 fonts""") bullet("""TTFSearchPath: this is a python list of strings representing directories that may be queried for information on TrueType fonts""") bullet("""CMapSearchPath: this is a python list of strings representing directories that may be queried for information on font code maps.""") bullet("""showBoundary: set to non-zero to get boundary lines drawn.""") bullet("""pageCompression: set to non-zero to try and get compressed PDF.""") bullet("""allowtableBoundsErrors: set to 0 to force an error on very large Platypus table elements""") bullet("""emptyTableAction: Controls behaviour for empty tables, can be 'error' (default), 'indicate' or 'ignore'.""") bullet("""trustedHosts: if not $None$ a list of glob patterns of trusted hosts; these may be used in places like <img> tags in paragraph texts.""") bullet("""trustedSchemes: a list of allowed $URL$ schemes used with $trustedHosts$""") disc("""For the full list of variables see the file $reportlab/rl_settings.py$.""") heading3("Other modifications") disc("""More complex modifications to the reportlab toolkit environment may be made using one of the modules $rep[ortlab.local_rl_mods$ (.py script in reportlab folder), $reportlab_mods$ (.py file on the python path) or $~/.reportlab_mods$ (note no .py).""") heading2("Learning More About Python") disc(""" If you are a total beginner to Python, you should check out one or more from the growing number of resources on Python programming. The following are freely available on the web: """) bullet("""Python Documentation. A list of documentation on the Python.org web site. $http://www.python.org/doc/$ """) bullet("""Python Tutorial. The official Python Tutorial , originally written by Guido van Rossum himself. $http://docs.python.org/tutorial/$ """) bullet("""Learning to Program. A tutorial on programming by Alan Gauld. Has a heavy emphasis on Python, but also uses other languages. $http://www.freenetpages.co.uk/hp/alan.gauld/$ """) bullet("""Instant Python. A 6-page minimal crash course by Magnus Lie Hetland. $http://www.hetland.org/python/instant-python.php$ """) bullet("""Dive Into Python. A free Python tutorial for experienced programmers. $http://www.diveintopython.net/$ """) from reportlab.lib.codecharts import SingleByteEncodingChart from tools.docco.stylesheet import getStyleSheet styles = getStyleSheet() indent0_style = styles['Indent0'] indent1_style = styles['Indent1'] heading2("Goals of the 3.x release series") disc("""ReportLab 3.0 has been produced to help in the migration to Python 3.x. Python 3.x will be standard in future Ubuntu releases and is gaining popularity, and a good proportion of major Python packages now run on Python 3. """) bullet("""Python 3.x compatibility. A single line of code should run on 3.6 and higher""") bullet(""" __init__.py restricts to >=3.6""") bullet("""__init__.py allow the import of on optional reportlab.local_rl_mods to allow monkey patching etc.""") bullet("""rl_config now imports rl_settings, optionally local_rl_settings, reportlab_settings.py & finally ~/.reportlab_settings""") bullet("""ReportLab C extensions now live inside reportlab; _rl_accel is no longer required. All _rl_accel imports now pass through reportlab.lib.rl_accel""") bullet("""xmllib is gone, alongside the paraparser stuff that caused issues in favour of HTMLParser.""") bullet("""some obsolete C extensions (sgmlop and pyHnj) are gone""") bullet("""Improved support for multi-threaded systems to the _rl_accel C extension module.""") bullet("""Removed reportlab/lib/ para.py & pycanvas.py. These would better belong in third party packages, which can make use of the monkeypatching feature above.""") bullet("""Add ability to output greyscale and 1-bit PIL images without conversion to RGB. (contributed by Matthew Duggan)""") bullet("""highlight annotation (contributed by Ben Echols)""") bullet("""full compliance with pip, easy_install, wheels etc""") disc("""Detailed release notes are available at $http://www.reportlab.com/software/documentation/relnotes/30/$""") ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1691062243.0 reportlab-4.1.0/docs/userguide/ch2_graphics.py0000664000175000017500000013073314462707743020761 0ustar00rptlabrptlab#Copyright ReportLab Europe Ltd. 2000-2017 #see license.txt for license details #history https://hg.reportlab.com/hg-public/reportlab/log/tip/docs/userguide/ch2_graphics.py from tools.docco.rl_doc_utils import * from reportlab.lib.codecharts import SingleByteEncodingChart heading1("Graphics and Text with $pdfgen$") heading2("Basic Concepts") disc(""" The $pdfgen$ package is the lowest level interface for generating PDF documents. A $pdfgen$ program is essentially a sequence of instructions for "painting" a document onto a sequence of pages. The interface object which provides the painting operations is the $pdfgen canvas$. """) disc(""" The canvas should be thought of as a sheet of white paper with points on the sheet identified using Cartesian ^(X,Y)^ coordinates which by default have the ^(0,0)^ origin point at the lower left corner of the page. Furthermore the first coordinate ^x^ goes to the right and the second coordinate ^y^ goes up, by default.""") disc(""" A simple example program that uses a canvas follows. """) eg(""" from reportlab.pdfgen import canvas def hello(c): c.drawString(100,100,"Hello World") c = canvas.Canvas("hello.pdf") hello(c) c.showPage() c.save() """) disc(""" The above code creates a $canvas$ object which will generate a PDF file named $hello.pdf$ in the current working directory. It then calls the $hello$ function passing the $canvas$ as an argument. Finally the $showPage$ method saves the current page of the canvas and the $save$ method stores the file and closes the canvas.""") disc(""" The $showPage$ method causes the $canvas$ to stop drawing on the current page and any further operations will draw on a subsequent page (if there are any further operations -- if not no new page is created). The $save$ method must be called after the construction of the document is complete -- it generates the PDF document, which is the whole purpose of the $canvas$ object. """) heading2("More about the Canvas") disc(""" Before describing the drawing operations, we will digress to cover some of the things which can be done to configure a canvas. There are many different settings available. If you are new to Python or can't wait to produce some output, you can skip ahead, but come back later and read this!""") disc("""First of all, we will look at the constructor arguments for the canvas:""") eg(""" def __init__(self,filename, pagesize=(595.27,841.89), bottomup = 1, pageCompression=0, encoding=rl_config.defaultEncoding, verbosity=0 encrypt=None): """) disc("""The $filename$ argument controls the name of the final PDF file. You may also pass in any open binary stream (such as $sys.stdout$, the python process standard output with a binary encoding) and the PDF document will be written to that. Since PDF is a binary format, you should take care when writing other stuff before or after it; you can't deliver PDF documents inline in the middle of an HTML page!""") disc("""The $pagesize$ argument is a tuple of two numbers in points (1/72 of an inch). The canvas defaults to $A4$ (an international standard page size which differs from the American standard page size of $letter$), but it is better to explicitly specify it. Most common page sizes are found in the library module $reportlab.lib.pagesizes$, so you can use expressions like""") eg("""from reportlab.lib.pagesizes import letter, A4 myCanvas = Canvas('myfile.pdf', pagesize=letter) width, height = letter #keep for later """) pencilnote() disc("""If you have problems printing your document make sure you are using the right page size (usually either $A4$ or $letter$). Some printers do not work well with pages that are too large or too small.""") disc("""Very often, you will want to calculate things based on the page size. In the example above we extracted the width and height. Later in the program we may use the $width$ variable to define a right margin as $width - inch$ rather than using a constant. By using variables the margin will still make sense even if the page size changes.""") disc("""The $bottomup$ argument switches coordinate systems. Some graphics systems (like PDF and PostScript) place (0,0) at the bottom left of the page others (like many graphical user interfaces [GUI's]) place the origin at the top left. The $bottomup$ argument is deprecated and may be dropped in future""") todo("""Need to see if it really works for all tasks, and if not then get rid of it""") disc("""The $pageCompression$ option determines whether the stream of PDF operations for each page is compressed. By default page streams are not compressed, because the compression slows the file generation process. If output size is important set $pageCompression=1$, but remember that, compressed documents will be smaller, but slower to generate. Note that images are always compressed, and this option will only save space if you have a very large amount of text and vector graphics on each page.""") disc("""The $encoding$ argument is largely obsolete in version 2.0 and can probably be omitted by 99% of users. Its default value is fine unless you very specifically need to use one of the 25 or so characters which are present in MacRoman and not in Winansi. A useful reference to these is here: http://www.alanwood.net/demos/charsetdiffs.html. The parameter determines which font encoding is used for the standard Type 1 fonts; this should correspond to the encoding on your system. Note that this is the encoding used internally by the font; text you pass to the ReportLab toolkit for rendering should always either be a Python unicode string object or a UTF-8 encoded byte string (see the next chapter)! The font encoding has two values at present: $'WinAnsiEncoding'$ or $'MacRomanEncoding'$. The variable $rl_config.defaultEncoding$ above points to the former, which is standard on Windows, Mac OS X and many Unices (including Linux). If you are Mac user and don't have OS X, you may want to make a global change: modify the line at the top of reportlab/pdfbase/pdfdoc.py to switch it over. Otherwise, you can probably just ignore this argument completely and never pass it. For all TTF and the commonly-used CID fonts, the encoding you pass in here is ignored, since the reportlab library itself knows the right encodings in those cases.""") disc("""The demo script $reportlab/demos/stdfonts.py$ will print out two test documents showing all code points in all fonts, so you can look up characters. Special characters can be inserted into string commands with the usual Python escape sequences; for example \\101 = 'A'.""") disc("""The $verbosity$ argument determines how much log information is printed. By default, it is zero to assist applications which want to capture PDF from standard output. With a value of 1, you will get a confirmation message each time a document is generated. Higher numbers may give more output in future.""") disc("""The $encrypt$ argument determines if and how the document is encrypted. By default, the document is not encrypted. If $encrypt$ is a string object, it is used as the user password for the pdf. If $encrypt$ is an instance of $reportlab.lib.pdfencrypt.StandardEncryption$, this object is used to encrypt the pdf. This allows more finegrained control over the encryption settings. Encryption is covered in more detail in Chapter 4.""") todo("to do - all the info functions and other non-drawing stuff") todo("""Cover all constructor arguments, and setAuthor etc.""") heading2("Drawing Operations") disc(""" Suppose the $hello$ function referenced above is implemented as follows (we will not explain each of the operations in detail yet). """) eg(examples.testhello) disc(""" Examining this code notice that there are essentially two types of operations performed using a canvas. The first type draws something on the page such as a text string or a rectangle or a line. The second type changes the state of the canvas such as changing the current fill or stroke color or changing the current font type and size. """) disc(""" If we imagine the program as a painter working on the canvas the "draw" operations apply paint to the canvas using the current set of tools (colors, line styles, fonts, etcetera) and the "state change" operations change one of the current tools (changing the fill color from whatever it was to blue, or changing the current font to $Times-Roman$ in 15 points, for example). """) disc(""" The document generated by the "hello world" program listed above would contain the following graphics. """) illust(examples.hello, '"Hello World" in pdfgen') heading3("About the demos in this document") disc(""" This document contains demonstrations of the code discussed like the one shown in the rectangle above. These demos are drawn on a "tiny page" embedded within the real pages of the guide. The tiny pages are %s inches wide and %s inches tall. The demo displays show the actual output of the demo code. For convenience the size of the output has been reduced slightly. """ % (examplefunctionxinches, examplefunctionyinches)) heading2('The tools: the "draw" operations') disc(""" This section briefly lists the tools available to the program for painting information onto a page using the canvas interface. These will be discussed in detail in later sections. They are listed here for easy reference and for summary purposes. """) heading3("Line methods") eg("""canvas.line(x1,y1,x2,y2)""") eg("""canvas.lines(linelist)""") disc(""" The line methods draw straight line segments on the canvas. """) heading3("Shape methods") eg("""canvas.grid(xlist, ylist) """) eg("""canvas.bezier(x1, y1, x2, y2, x3, y3, x4, y4)""") eg("""canvas.arc(x1,y1,x2,y2) """) eg("""canvas.rect(x, y, width, height, stroke=1, fill=0) """) eg("""canvas.ellipse(x1,y1, x2,y2, stroke=1, fill=0)""") eg("""canvas.wedge(x1,y1, x2,y2, startAng, extent, stroke=1, fill=0) """) eg("""canvas.circle(x_cen, y_cen, r, stroke=1, fill=0)""") eg("""canvas.roundRect(x, y, width, height, radius, stroke=1, fill=0) """) disc(""" The shape methods draw common complex shapes on the canvas. """) heading3("String drawing methods") eg("""canvas.drawString(x, y, text):""") eg("""canvas.drawRightString(x, y, text) """) eg("""canvas.drawCentredString(x, y, text)""") disc(""" The draw string methods draw single lines of text on the canvas. """) heading3("The text object methods") eg("""textobject = canvas.beginText(x, y) """) eg("""canvas.drawText(textobject) """) disc(""" Text objects are used to format text in ways that are not supported directly by the $canvas$ interface. A program creates a text object from the $canvas$ using $beginText$ and then formats text by invoking $textobject$ methods. Finally the $textobject$ is drawn onto the canvas using $drawText$. """) heading3("The path object methods") eg("""path = canvas.beginPath() """) eg("""canvas.drawPath(path, stroke=1, fill=0, fillMode=None) """) eg("""canvas.clipPath(path, stroke=1, fill=0, fillMode=None) """) disc(""" Path objects are similar to text objects: they provide dedicated control for performing complex graphical drawing not directly provided by the canvas interface. A program creates a path object using $beginPath$ populates the path with graphics using the methods of the path object and then draws the path on the canvas using $drawPath$.""") disc("""It is also possible to use a path as a "clipping region" using the $clipPath$ method -- for example a circular path can be used to clip away the outer parts of a rectangular image leaving only a circular part of the image visible on the page. """) disc("""If $fill=1$ is specified then the $fillMode$ argument may be used to set either 0=$even-odd$ or 1=$non-zero$ filling mode. which will alter the way that complex paths are filled. If the default $None$ values is used then the canvas $_fillMode$ attribute value is used (normally $0$ ie $even-odd$).""") heading3("Image methods") pencilnote() disc(""" You need the Python Imaging Library (PIL) to use images with the ReportLab package. Examples of the techniques below can be found by running the script $test_pdfgen_general.py$ in our $tests$ subdirectory and looking at page 7 of the output. """) disc(""" There are two similar-sounding ways to draw images. The preferred one is the $drawImage$ method. This implements a caching system so you can define an image once and draw it many times; it will only be stored once in the PDF file. $drawImage$ also exposes one advanced parameter, a transparency mask, and will expose more in future. The older technique, $drawInlineImage$, stores bitmaps within the page stream and is thus very inefficient if you use the same image more than once in a document; but can result in PDFs which render faster if the images are very small and not repeated. We'll discuss the oldest one first: """) eg("""canvas.drawInlineImage(self, image, x,y, width=None,height=None) """) disc(""" The $drawInlineImage$ method places an image on the canvas. The $image$ parameter may be either a PIL Image object or an image filename. Many common file formats are accepted including GIF and JPEG. It returns the size of the actual image in pixels as a (width, height) tuple. """) eg("""canvas.drawImage(self, image, x,y, width=None,height=None,mask=None) """) disc(""" The arguments and return value work as for $drawInlineImage$. However, we use a caching system; a given image will only be stored the first time it is used, and just referenced on subsequent use. If you supply a filename, it assumes that the same filename means the same image. If you supply a PIL image, it tests if the content has actually changed before re-embedding.""") disc(""" The $mask$ parameter lets you create transparent images. It takes 6 numbers and defines the range of RGB values which will be masked out or treated as transparent. For example with [0,2,40,42,136,139], it will mask out any pixels with a Red value from 0 or 1, Green from 40 or 41 and Blue of 136, 137 or 138 (on a scale of 0-255). It's currently your job to know which color is the 'transparent' or background one.""") disc("""PDF allows for many image features and we will expose more of the over time, probably with extra keyword arguments to $drawImage$.""") heading3("Ending a page") eg("""canvas.showPage()""") disc("""The $showPage$ method finishes the current page. All additional drawing will be done on another page.""") pencilnote() disc("""Warning! All state changes (font changes, color settings, geometry transforms, etcetera) are FORGOTTEN when you advance to a new page in $pdfgen$. Any state settings you wish to preserve must be set up again before the program proceeds with drawing!""") heading2('The toolbox: the "state change" operations') disc(""" This section briefly lists the ways to switch the tools used by the program for painting information onto a page using the $canvas$ interface. These too will be discussed in detail in later sections. """) heading3("Changing Colors") eg("""canvas.setFillColorCMYK(c, m, y, k) """) eg("""canvas.setStrikeColorCMYK(c, m, y, k) """) eg("""canvas.setFillColorRGB(r, g, b) """) eg("""canvas.setStrokeColorRGB(r, g, b) """) eg("""canvas.setFillColor(acolor) """) eg("""canvas.setStrokeColor(acolor) """) eg("""canvas.setFillGray(gray) """) eg("""canvas.setStrokeGray(gray) """) disc(""" PDF supports three different color models: gray level, additive (red/green/blue or RGB), and subtractive with darkness parameter (cyan/magenta/yellow/darkness or CMYK). The ReportLab packages also provide named colors such as $lawngreen$. There are two basic color parameters in the graphics state: the $Fill$ color for the interior of graphic figures and the $Stroke$ color for the boundary of graphic figures. The above methods support setting the fill or stroke color using any of the four color specifications. """) heading3("Changing Fonts") eg("""canvas.setFont(psfontname, size, leading = None) """) disc(""" The $setFont$ method changes the current text font to a given type and size. The $leading$ parameter specifies the distance down to move when advancing from one text line to the next. """) heading3("Changing Graphical Line Styles") eg("""canvas.setLineWidth(width) """) eg("""canvas.setLineCap(mode) """) eg("""canvas.setLineJoin(mode) """) eg("""canvas.setMiterLimit(limit) """) eg("""canvas.setDash(self, array=[], phase=0) """) disc(""" Lines drawn in PDF can be presented in a number of graphical styles. Lines can have different widths, they can end in differing cap styles, they can meet in different join styles, and they can be continuous or they can be dotted or dashed. The above methods adjust these various parameters.""") heading3("Changing Geometry") eg("""canvas.setPageSize(pair) """) eg("""canvas.transform(a,b,c,d,e,f): """) eg("""canvas.translate(dx, dy) """) eg("""canvas.scale(x, y) """) eg("""canvas.rotate(theta) """) eg("""canvas.skew(alpha, beta) """) disc(""" All PDF drawings fit into a specified page size. Elements drawn outside of the specified page size are not visible. Furthermore all drawn elements are passed through an affine transformation which may adjust their location and/or distort their appearence. The $setPageSize$ method adjusts the current page size. The $transform$, $translate$, $scale$, $rotate$, and $skew$ methods add additional transformations to the current transformation. It is important to remember that these transformations are incremental -- a new transform modifies the current transform (but does not replace it). """) heading3("State control") eg("""canvas.saveState() """) eg("""canvas.restoreState() """) disc(""" Very often it is important to save the current font, graphics transform, line styles and other graphics state in order to restore them later. The $saveState$ method marks the current graphics state for later restoration by a matching $restoreState$. Note that the save and restore method invokation must match -- a restore call restores the state to the most recently saved state which hasn't been restored yet. You cannot save the state on one page and restore it on the next, however -- no state is preserved between pages.""") heading2("Other $canvas$ methods.") disc(""" Not all methods of the $canvas$ object fit into the "tool" or "toolbox" categories. Below are some of the misfits, included here for completeness. """) eg(""" canvas.setAuthor() canvas.addOutlineEntry(title, key, level=0, closed=None) canvas.setTitle(title) canvas.setSubject(subj) canvas.pageHasData() canvas.showOutline() canvas.bookmarkPage(name) canvas.bookmarkHorizontalAbsolute(name, yhorizontal) canvas.doForm() canvas.beginForm(name, lowerx=0, lowery=0, upperx=None, uppery=None) canvas.endForm() canvas.linkAbsolute(contents, destinationname, Rect=None, addtopage=1, name=None, **kw) canvas.linkRect(contents, destinationname, Rect=None, addtopage=1, relative=1, name=None, **kw) canvas.getPageNumber() canvas.addLiteral() canvas.getAvailableFonts() canvas.stringWidth(self, text, fontName, fontSize, encoding=None) canvas.setPageCompression(onoff=1) canvas.setPageTransition(self, effectname=None, duration=1, direction=0,dimension='H',motion='I') """) heading2('Coordinates (default user space)') disc(""" By default locations on a page are identified by a pair of numbers. For example the pair $(4.5*inch, 1*inch)$ identifies the location found on the page by starting at the lower left corner and moving to the right 4.5 inches and up one inch. """) disc("""For example, the following function draws a number of elements on a $canvas$.""") eg(examples.testcoords) disc("""In the default user space the "origin" ^(0,0)^ point is at the lower left corner. Executing the $coords$ function in the default user space (for the "demo minipage") we obtain the following.""") illust(examples.coords, 'The Coordinate System') heading3("Moving the origin: the $translate$ method") disc("""Often it is useful to "move the origin" to a new point off the lower left corner. The $canvas.translate(^x,y^)$ method moves the origin for the current page to the point currently identified by ^(x,y)^.""") disc("""For example the following translate function first moves the origin before drawing the same objects as shown above.""") eg(examples.testtranslate) disc("""This produces the following.""") illust(examples.translate, "Moving the origin: the $translate$ method") #illust(NOP) # execute some code pencilnote() disc(""" Note: As illustrated in the example it is perfectly possible to draw objects or parts of objects "off the page". In particular a common confusing bug is a translation operation that translates the entire drawing off the visible area of the page. If a program produces a blank page it is possible that all the drawn objects are off the page. """) heading3("Shrinking and growing: the scale operation") disc("""Another important operation is scaling. The scaling operation $canvas.scale(^dx,dy^)$ stretches or shrinks the ^x^ and ^y^ dimensions by the ^dx^, ^dy^ factors respectively. Often ^dx^ and ^dy^ are the same -- for example to reduce a drawing by half in all dimensions use $dx = dy = 0.5$. However for the purposes of illustration we show an example where $dx$ and $dy$ are different. """) eg(examples.testscale) disc("""This produces a "short and fat" reduced version of the previously displayed operations.""") illust(examples.scale, "Scaling the coordinate system") #illust(NOP) # execute some code pencilnote() disc("""Note: scaling may also move objects or parts of objects off the page, or may cause objects to "shrink to nothing." """) disc("""Scaling and translation can be combined, but the order of the operations are important.""") eg(examples.testscaletranslate) disc("""This example function first saves the current $canvas$ state and then does a $scale$ followed by a $translate$. Afterward the function restores the state (effectively removing the effects of the scaling and translation) and then does the same operations in a different order. Observe the effect below.""") illust(examples.scaletranslate, "Scaling and Translating") #illust(NOP) # execute some code pencilnote() disc("""Note: scaling shrinks or grows everything including line widths so using the canvas.scale method to render a microscopic drawing in scaled microscopic units may produce a blob (because all line widths will get expanded a huge amount). Also rendering an aircraft wing in meters scaled to centimeters may cause the lines to shrink to the point where they disappear. For engineering or scientific purposes such as these scale and translate the units externally before rendering them using the canvas.""") heading3("Saving and restoring the $canvas$ state: $saveState$ and $restoreState$") disc(""" The $scaletranslate$ function used an important feature of the $canvas$ object: the ability to save and restore the current parameters of the $canvas$. By enclosing a sequence of operations in a matching pair of $canvas.saveState()$ an $canvas.restoreState()$ operations all changes of font, color, line style, scaling, translation, or other aspects of the $canvas$ graphics state can be restored to the state at the point of the $saveState()$. Remember that the save/restore calls must match: a stray save or restore operation may cause unexpected and undesirable behavior. Also, remember that no $canvas$ state is preserved across page breaks, and the save/restore mechanism does not work across page breaks. """) heading3("Mirror image") disc(""" It is interesting although perhaps not terribly useful to note that scale factors can be negative. For example the following function """) eg(examples.testmirror) disc(""" creates a mirror image of the elements drawn by the $coord$ function. """) illust(examples.mirror, "Mirror Images") disc(""" Notice that the text strings are painted backwards. """) heading2("Colors") disc(""" There are generally two types of colors used in PDF depending on the media where the PDF will be used. The most commonly known screen colors model RGB can be used in PDF, however in professional printing another color model CMYK is mainly used which gives more control over how inks are applied to paper. More on these color models below. """) heading3("RGB Colors") disc(""" The $RGB$ or additive color representation follows the way a computer screen adds different levels of the red, green, and blue light to make any color in between, where white is formed by turning all three lights on full ($1,1,1$). """) disc(""" There are three ways to specify RGB colors in $pdfgen$: by name (using the $color$ module, by red/green/blue (additive, $RGB$) value, or by gray level. The $colors$ function below exercises each of the four methods. """) eg(examples.testRGBcolors) illust(examples.colorsRGB, "RGB Color Models") heading4("RGB Color Transparency") disc(""" Objects may be painted over other objects to good effect in $pdfgen$. Generally There are two modes of handling objects that overlap in space, the default objects in the top layer will hide any part of other objects that falls underneath it. If you need transparency you got two choices: """) disc(""" 1. If your document is intended to be printed in a professional way and you are working in CMYK color space then you can use overPrint. In overPrinting the colors physically mix in the printer and thus a new color is obtained. By default a knockout will be applied and only top object appears. Read the CMYK section if this is what you intend to use. """) disc(""" 2. If your document is intended for screen output and you are using RGB colors then you can set an alpha value, where alpha is the opacity value of the color. The default alpha value is $1$ (fully opaque) and you can use any real number value in the range 0-1. """) disc(""" Alpha transparency ($alpha$) is similar to overprint but works in RGB color space this example below demonstrates the alpha funtionality. Refer to our website http://www.reportlab.com/snippets/ and look for snippets of overPrint and alpha to see the code that generates the graph below. """) eg(examples.testalpha) illust(examples.alpha, "Alpha example") heading3("CMYK Colors") disc(""" The $CMYK$ or subtractive method follows the way a printer mixes three pigments (cyan, magenta, and yellow) to form colors. Because mixing chemicals is more difficult than combining light there is a fourth parameter for darkness. For example a chemical combination of the $CMY$ pigments generally never makes a perfect black -- instead producing a muddy color -- so, to get black printers don not use the $CMY$ pigments but use a direct black ink. Because $CMYK$ maps more directly to the way printer hardware works it may be the case that colors specified in $CMYK$ will provide better fidelity and better control when printed. """) disc(""" There are two ways of representing CMYK Color: each color can be represented either by a real value between 0 and 1, or integer value between 0 and 100. Depending on your preference you can either use CMYKColor (for real values) or PCMYKColor ( for integer values). 0 means 'no ink', so printing on white papers gives you white. 1 (or 100 if you use PCMYKColor) means 'the maximum amount of ink'. e.g. CMYKColor(0,0,0,1) is black, CMYKColor(0,0,0,0) means 'no ink', and CMYKColor(0.5,0,0,0) means 50 percent cyan color. """) eg(examples.testCMYKcolors) illust(examples.colorsCMYK, "CMYK Color Models") heading2("Color space checking") disc("""The $enforceColorSpace$ argument of the canvas is used to enforce the consistency of the colour model used in a document. It accepts these values: CMYK, RGB, SEP, SEP_BLACK, SEP_CMYK. 'SEP' refers to named color separations such as Pantone spot colors - these can be mixed with CMYK or RGB according to the parameter used. The default is 'MIXED' which allows you to use colors from any color space. An exception is raised if any colors used are not convertible to the specified model, e.g. rgb and cmyk (more information in test_pdfgen_general). This approach doesn't check external images included in document. """) heading2("Color Overprinting") disc(""" When two CMYK colored objects overlap in printing, then either the object 'on top' will knock out the color of the the one underneath it, or the colors of the two objects will mix in the overlapped area. This behaviour can be set using the property $overPrint$. """) disc(""" The $overPrint$ function will cause ovelapping areas of color to mix. In the example below, the colors of the rectangles on the left should appear mixed where they overlap - If you can't see this effect then you may need to enable the 'overprint preview' option in your PDF viewing software. Some PDF viewers such as $evince$ do not support overPrint; however Adobe Acrobat Reader does support it. """) illust(examples.overPrint, "overPrint example") heading3("Other Object Order of Printing Examples") disc(""" The word "SPUMONI" is painted in white over the colored rectangles, with the apparent effect of "removing" the color inside the body of the word. """) eg(examples.testspumoni) illust(examples.spumoni, "Painting over colors") disc(""" The last letters of the word are not visible because the default $canvas$ background is white and painting white letters over a white background leaves no visible effect. """) disc(""" This method of building up complex paintings in layers can be done in very many layers in $pdfgen$ -- there are fewer physical limitations than there are when dealing with physical paints. """) eg(examples.testspumoni2) disc(""" The $spumoni2$ function layers an ice cream cone over the $spumoni$ drawing. Note that different parts of the cone and scoops layer over eachother as well. """) illust(examples.spumoni2, "building up a drawing in layers") heading2('Standard fonts and text objects') disc(""" Text may be drawn in many different colors, fonts, and sizes in $pdfgen$. The $textsize$ function demonstrates how to change the color and font and size of text and how to place text on the page. """) eg(examples.testtextsize) disc(""" The $textsize$ function generates the following page. """) illust(examples.textsize, "text in different fonts and sizes") disc(""" A number of different fonts are always available in $pdfgen$. """) eg(examples.testfonts) disc(""" The $fonts$ function lists the fonts that are always available. These don't need to be stored in a PDF document, since they are guaranteed to be present in Acrobat Reader. """) illust(examples.fonts, "the 14 standard fonts") disc("""The Symbol and ZapfDingbats fonts cannot display properly because the required glyphs are not present in those fonts.""") disc(""" For information on how to use arbitrary fonts, see the next chapter. """) heading2("Text object methods") disc(""" For the dedicated presentation of text in a PDF document, use a text object. The text object interface provides detailed control of text layout parameters not available directly at the $canvas$ level. In addition, it results in smaller PDF that will render faster than many separate calls to the $drawString$ methods. """) eg("""textobject.setTextOrigin(x,y)""") eg("""textobject.setTextTransform(a,b,c,d,e,f)""") eg("""textobject.moveCursor(dx, dy) # from start of current LINE""") eg("""(x,y) = textobject.getCursor()""") eg("""x = textobject.getX(); y = textobject.getY()""") eg("""textobject.setFont(psfontname, size, leading = None)""") eg("""textobject.textOut(text)""") eg("""textobject.textLine(text='')""") eg("""textobject.textLines(stuff, trim=1)""") disc(""" The text object methods shown above relate to basic text geometry. """) disc(""" A text object maintains a text cursor which moves about the page when text is drawn. For example the $setTextOrigin$ places the cursor in a known position and the $textLine$ and $textLines$ methods move the text cursor down past the lines that have been missing. """) eg(examples.testcursormoves1) disc(""" The $cursormoves$ function relies on the automatic movement of the text cursor for placing text after the origin has been set. """) illust(examples.cursormoves1, "How the text cursor moves") disc(""" It is also possible to control the movement of the cursor more explicitly by using the $moveCursor$ method (which moves the cursor as an offset from the start of the current line NOT the current cursor, and which also has positive ^y^ offsets move down (in contrast to the normal geometry where positive ^y^ usually moves up. """) eg(examples.testcursormoves2) disc(""" Here the $textOut$ does not move the down a line in contrast to the $textLine$ function which does move down. """) illust(examples.cursormoves2, "How the text cursor moves again") heading3("Character Spacing") eg("""textobject.setCharSpace(charSpace)""") disc("""The $setCharSpace$ method adjusts one of the parameters of text -- the inter-character spacing.""") eg(examples.testcharspace) disc("""The $charspace$ function exercises various spacing settings. It produces the following page.""") illust(examples.charspace, "Adjusting inter-character spacing") heading3("Word Spacing") eg("""textobject.setWordSpace(wordSpace)""") disc("The $setWordSpace$ method adjusts the space between words.") eg(examples.testwordspace) disc("""The $wordspace$ function shows what various word space settings look like below.""") illust(examples.wordspace, "Adjusting word spacing") heading3("Horizontal Scaling") eg("""textobject.setHorizScale(horizScale)""") disc("""Lines of text can be stretched or shrunken horizontally by the $setHorizScale$ method.""") eg(examples.testhorizontalscale) disc("""The horizontal scaling parameter ^horizScale^ is given in percentages (with 100 as the default), so the 80 setting shown below looks skinny. """) illust(examples.horizontalscale, "adjusting horizontal text scaling") heading3("Interline spacing (Leading)") eg("""textobject.setLeading(leading)""") disc("""The vertical offset between the point at which one line starts and where the next starts is called the leading offset. The $setLeading$ method adjusts the leading offset. """) eg(examples.testleading) disc("""As shown below if the leading offset is set too small characters of one line my write over the bottom parts of characters in the previous line.""") illust(examples.leading, "adjusting the leading") heading3("Other text object methods") eg("""textobject.setTextRenderMode(mode)""") disc("""The $setTextRenderMode$ method allows text to be used as a forground for clipping background drawings, for example.""") eg("""textobject.setRise(rise)""") disc(""" The $setRise$ method raises or lowers text on the line (for creating superscripts or subscripts, for example). """) eg("""textobject.setFillColor(aColor); textobject.setStrokeColor(self, aColor) # and similar""") disc(""" These color change operations change the color of the text and are otherwise similar to the color methods for the $canvas$ object.""") heading2('Paths and Lines') disc("""Just as textobjects are designed for the dedicated presentation of text, path objects are designed for the dedicated construction of graphical figures. When path objects are drawn onto a $canvas$ they are drawn as one figure (like a rectangle) and the mode of drawing for the entire figure can be adjusted: the lines of the figure can be drawn (stroked) or not; the interior of the figure can be filled or not; and so forth.""") disc(""" For example the $star$ function uses a path object to draw a star """) eg(examples.teststar) disc(""" The $star$ function has been designed to be useful in illustrating various line style parameters supported by $pdfgen$. """) illust(examples.star, "line style parameters") heading3("Line join settings") disc(""" The $setLineJoin$ method can adjust whether line segments meet in a point a square or a rounded vertex. """) eg(examples.testjoins) disc(""" The line join setting is only really of interest for thick lines because it cannot be seen clearly for thin lines. """) illust(examples.joins, "different line join styles") heading3("Line cap settings") disc("""The line cap setting, adjusted using the $setLineCap$ method, determines whether a terminating line ends in a square exactly at the vertex, a square over the vertex or a half circle over the vertex. """) eg(examples.testcaps) disc("""The line cap setting, like the line join setting, is only clearly visible when the lines are thick.""") illust(examples.caps, "line cap settings") heading3("Dashes and broken lines") disc(""" The $setDash$ method allows lines to be broken into dots or dashes. """) eg(examples.testdashes) disc(""" The patterns for the dashes or dots can be in a simple on/off repeating pattern or they can be specified in a complex repeating pattern. """) illust(examples.dashes, "some dash patterns") heading3("Creating complex figures with path objects") disc(""" Combinations of lines, curves, arcs and other figures can be combined into a single figure using path objects. For example the function shown below constructs two path objects using lines and curves. This function will be used later on as part of a pencil icon construction. """) eg(examples.testpenciltip) disc(""" Note that the interior of the pencil tip is filled as one object even though it is constructed from several lines and curves. The pencil lead is then drawn over it using a new path object. """) illust(examples.penciltip, "a pencil tip") heading2('Rectangles, circles, ellipses') disc(""" The $pdfgen$ module supports a number of generally useful shapes such as rectangles, rounded rectangles, ellipses, and circles. Each of these figures can be used in path objects or can be drawn directly on a $canvas$. For example the $pencil$ function below draws a pencil icon using rectangles and rounded rectangles with various fill colors and a few other annotations. """) eg(examples.testpencil) pencilnote() disc(""" Note that this function is used to create the "margin pencil" to the left. Also note that the order in which the elements are drawn are important because, for example, the white rectangles "erase" parts of a black rectangle and the "tip" paints over part of the yellow rectangle. """) illust(examples.pencil, "a whole pencil") heading2('Bezier curves') disc(""" Programs that wish to construct figures with curving borders generally use Bezier curves to form the borders. """) eg(examples.testbezier) disc(""" A Bezier curve is specified by four control points $(x1,y1)$, $(x2,y2)$, $(x3,y3)$, $(x4,y4)$. The curve starts at $(x1,y1)$ and ends at $(x4,y4)$ and the line segment from $(x1,y1)$ to $(x2,y2)$ and the line segment from $(x3,y3)$ to $(x4,y4)$ both form tangents to the curve. Furthermore the curve is entirely contained in the convex figure with vertices at the control points. """) illust(examples.bezier, "basic bezier curves") disc(""" The drawing above (the output of $testbezier$) shows a bezier curves, the tangent lines defined by the control points and the convex figure with vertices at the control points. """) heading3("Smoothly joining bezier curve sequences") disc(""" It is often useful to join several bezier curves to form a single smooth curve. To construct a larger smooth curve from several bezier curves make sure that the tangent lines to adjacent bezier curves that join at a control point lie on the same line. """) eg(examples.testbezier2) disc(""" The figure created by $testbezier2$ describes a smooth complex curve because adjacent tangent lines "line up" as illustrated below. """) illust(examples.bezier2, "bezier curves") heading2("Path object methods") disc(""" Path objects build complex graphical figures by setting the "pen" or "brush" at a start point on the canvas and drawing lines or curves to additional points on the canvas. Most operations apply paint on the canvas starting at the end point of the last operation and leave the brush at a new end point. """) eg("""pathobject.moveTo(x,y)""") disc(""" The $moveTo$ method lifts the brush (ending any current sequence of lines or curves if there is one) and replaces the brush at the new ^(x,y)^ location on the canvas to start a new path sequence. """) eg("""pathobject.lineTo(x,y)""") disc(""" The $lineTo$ method paints straight line segment from the current brush location to the new ^(x,y)^ location. """) eg("""pathobject.curveTo(x1, y1, x2, y2, x3, y3) """) disc(""" The $curveTo$ method starts painting a Bezier curve beginning at the current brush location, using ^(x1,y1)^, ^(x2,y2)^, and ^(x3,y3)^ as the other three control points, leaving the brush on ^(x3,y3)^. """) eg("""pathobject.arc(x1,y1, x2,y2, startAng=0, extent=90) """) eg("""pathobject.arcTo(x1,y1, x2,y2, startAng=0, extent=90) """) disc(""" The $arc$ and $arcTo$ methods paint partial ellipses. The $arc$ method first "lifts the brush" and starts a new shape sequence. The $arcTo$ method joins the start of the partial ellipse to the current shape sequence by line segment before drawing the partial ellipse. The points ^(x1,y1)^ and ^(x2,y2)^ define opposite corner points of a rectangle enclosing the ellipse. The $startAng$ is an angle (in degrees) specifying where to begin the partial ellipse where the 0 angle is the midpoint of the right border of the enclosing rectangle (when ^(x1,y1)^ is the lower left corner and ^(x2,y2)^ is the upper right corner). The $extent$ is the angle in degrees to traverse on the ellipse. """) eg(examples.testarcs) disc("""The $arcs$ function above exercises the two partial ellipse methods. It produces the following drawing.""") illust(examples.arcs, "arcs in path objects") eg("""pathobject.rect(x, y, width, height) """) disc("""The $rect$ method draws a rectangle with lower left corner at ^(x,y)^ of the specified ^width^ and ^height^.""") eg("""pathobject.ellipse(x, y, width, height)""") disc("""The $ellipse$ method draws an ellipse enclosed in the rectange with lower left corner at ^(x,y)^ of the specified ^width^ and ^height^. """) eg("""pathobject.circle(x_cen, y_cen, r) """) disc("""The $circle$ method draws a circle centered at ^(x_cen, y_cen)^ with radius ^r^. """) eg(examples.testvariousshapes) disc(""" The $variousshapes$ function above shows a rectangle, circle and ellipse placed in a frame of reference grid. """) illust(examples.variousshapes, "rectangles, circles, ellipses in path objects") eg("""pathobject.close() """) disc(""" The $close$ method closes the current graphical figure by painting a line segment from the last point of the figure to the starting point of the figure (the the most recent point where the brush was placed on the paper by $moveTo$ or $arc$ or other placement operations). """) eg(examples.testclosingfigures) disc(""" The $closingfigures$ function illustrates the effect of closing or not closing figures including a line segment and a partial ellipse. """) illust(examples.closingfigures, "closing and not closing pathobject figures") disc(""" Closing or not closing graphical figures effects only the stroked outline of a figure, not the filling of the figure as illustrated above. """) disc(""" For a more extensive example of drawing using a path object examine the $hand$ function. """) eg(examples.testhand) disc(""" In debug mode (the default) the $hand$ function shows the tangent line segments to the bezier curves used to compose the figure. Note that where the segments line up the curves join smoothly, but where they do not line up the curves show a "sharp edge". """) illust(examples.hand, "an outline of a hand using bezier curves") disc(""" Used in non-debug mode the $hand$ function only shows the Bezier curves. With the $fill$ parameter set the figure is filled using the current fill color. """) eg(examples.testhand2) disc(""" Note that the "stroking" of the border draws over the interior fill where they overlap. """) illust(examples.hand2, "the finished hand, filled") heading2("Further Reading: The ReportLab Graphics Library") disc(""" So far the graphics we have seen were created on a fairly low level. It should be noted, though, that there is another way of creating much more sophisticated graphics using the dedicated high-level ReportLab Graphics Library. """) disc(""" It can be used to produce high-quality, platform-independant, reusable graphics for different output formats (vector and bitmap) like PDF, EPS, SVG, JPG and PNG. """) disc(""" A more thorough description of its philsophy and features is now covered in Chapter 11 of this document, Graphics, which contains information about the existing components and how to create customized ones. """) disc(""" Chapter 11 also contains details of the ReportLab charting package and its components (labels, axes, legends and different types of charts like bar, line and pie charts) that builds directly on the graphics library. """) ##### FILL THEM IN ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1691062243.0 reportlab-4.1.0/docs/userguide/ch2a_fonts.py0000664000175000017500000004673614462707743020464 0ustar00rptlabrptlab#Copyright ReportLab Europe Ltd. 2000-2017 #see license.txt for license details #history https://hg.reportlab.com/hg-public/reportlab/log/tip/docs/userguide/ch2a_fonts.py from tools.docco.rl_doc_utils import * from reportlab.lib.codecharts import SingleByteEncodingChart from reportlab.platypus import Image import reportlab heading1("Fonts and encodings") disc(""" This chapter covers fonts, encodings and Asian language capabilities. If you are purely concerned with generating PDFs for Western European languages, you can just read the "Unicode is the default" section below and skip the rest on a first reading. We expect this section to grow considerably over time. We hope that Open Source will enable us to give better support for more of the world's languages than other tools, and we welcome feedback and help in this area. """) heading2("Unicode and UTF8 are the default input encodings") disc(""" Starting with reportlab Version 2.0 (May 2006), all text input you provide to our APIs should be in UTF8 or as Python Unicode objects. This applies to arguments to canvas.drawString and related APIs, table cell content, drawing object parameters, and paragraph source text. """) disc(""" We considered making the input encoding configurable or even locale-dependent, but decided that "explicit is better than implicit".""") disc(""" This simplifies many things we used to do previously regarding greek letters, symbols and so on. To display any character, find out its unicode code point, and make sure the font you are using is able to display it.""") disc(""" If you are adapting a ReportLab 1.x application, or reading data from another source which contains single-byte data (e.g. latin-1 or WinAnsi), you need to do a conversion into Unicode. The Python codecs package now includes converters for all the common encodings, including Asian ones. """) disc(u""" If your data is not encoded as UTF8, you will get a UnicodeDecodeError as soon as you feed in a non-ASCII character. For example, this snippet below is attempting to read in and print a series of names, including one with a French accent: ^Marc-Andr\u00e9 Lemburg^. The standard error is quite helpful and tells you what character it doesn't like: """) eg(u""" >>> from reportlab.pdfgen.canvas import Canvas >>> c = Canvas('temp.pdf') >>> y = 700 >>> for line in file('latin_python_gurus.txt','r'): ... c.drawString(100, y, line.strip()) ... Traceback (most recent call last): ... UnicodeDecodeError: 'utf8' codec can't decode bytes in position 9-11: invalid data -->\u00e9 L<--emburg >>> """) disc(""" The simplest fix is just to convert your data to unicode, saying which encoding it comes from, like this:""") eg(""" >>> for line in file('latin_input.txt','r'): ... uniLine = unicode(line, 'latin-1') ... c.drawString(100, y, uniLine.strip()) >>> >>> c.save() """) heading2("Automatic output font substitution") disc(""" There are still a number of places in the code, including the rl_config defaultEncoding parameter, and arguments passed to various Font constructors, which refer to encodings. These were useful in the past when people needed to use glyphs in the Symbol and ZapfDingbats fonts which are supported by PDF viewing devices. By default the standard fonts (Helvetica, Courier, Times Roman) will offer the glyphs available in Latin-1. However, if our engine detects a character not in the font, it will attempt to switch to Symbol or ZapfDingbats to display these. For example, if you include the Unicode character for a pair of right-facing scissors, \\u2702, in a call to ^drawString^, you should see them (there is an example in ^test_pdfgen_general.py/pdf^). It is not necessary to switch fonts in your code. """) heading2("Using non-standard Type 1 fonts") disc(""" As discussed in the previous chapter, every copy of Acrobat Reader comes with 14 standard fonts built in. Therefore, the ReportLab PDF Library only needs to refer to these by name. If you want to use other fonts, they must be available to your code and will be embedded in the PDF document.""") disc(""" You can use the mechanism described below to include arbitrary fonts in your documents. We have an open source font named DarkGardenMK which we may use for testing and/or documenting purposes (and which you may use as well). It comes bundled with the ReportLab distribution in the directory $reportlab/fonts$. """) disc(""" Right now font-embedding relies on font description files in the Adobe AFM ('Adobe Font Metrics') and PFB ('Printer Font Binary') format. The former is an ASCII file and contains information about the characters ('glyphs') in the font such as height, width, bounding box info and other 'metrics', while the latter is a binary file that describes the shapes of the font. The $reportlab/fonts$ directory contains the files $'DarkGardenMK.afm'$ and $'DarkGardenMK.pfb'$ that are used as an example font. """) disc(""" In the following example locate the folder containing the test font and register it for future use with the $pdfmetrics$ module, after which we can use it like any other standard font. """) eg(""" import os import reportlab folder = os.path.dirname(reportlab.__file__) + os.sep + 'fonts' afmFile = os.path.join(folder, 'DarkGardenMK.afm') pfbFile = os.path.join(folder, 'DarkGardenMK.pfb') from reportlab.pdfbase import pdfmetrics justFace = pdfmetrics.EmbeddedType1Face(afmFile, pfbFile) faceName = 'DarkGardenMK' # pulled from AFM file pdfmetrics.registerTypeFace(justFace) justFont = pdfmetrics.Font('DarkGardenMK', faceName, 'WinAnsiEncoding') pdfmetrics.registerFont(justFont) canvas.setFont('DarkGardenMK', 32) canvas.drawString(10, 150, 'This should be in') canvas.drawString(10, 100, 'DarkGardenMK') """) disc(""" Note that the argument "WinAnsiEncoding" has nothing to do with the input; it's to say which set of characters within the font file will be active and available. """) illust(examples.customfont1, "Using a very non-standard font") disc(""" The font's facename comes from the AFM file's $FontName$ field. In the example above we knew the name in advance, but quite often the names of font description files are pretty cryptic and then you might want to retrieve the name from an AFM file automatically. When lacking a more sophisticated method you can use some code as simple as this: """) eg(""" class FontNameNotFoundError(Exception): pass def findFontName(path): "Extract a font name from an AFM file." f = open(path) found = 0 while not found: line = f.readline()[:-1] if not found and line[:16] == 'StartCharMetrics': raise FontNameNotFoundError, path if line[:8] == 'FontName': fontName = line[9:] found = 1 return fontName """) disc(""" In the DarkGardenMK example we explicitely specified the place of the font description files to be loaded. In general, you'll prefer to store your fonts in some canonic locations and make the embedding mechanism aware of them. Using the same configuration mechanism we've already seen at the beginning of this section we can indicate a default search path for Type-1 fonts. """) disc(""" Unfortunately, there is no reliable standard yet for such locations (not even on the same platform) and, hence, you might have to edit one of the files $reportlab_settings.py$ or $~/.reportlab_settings$ to modify the value of the $T1SearchPath$ identifier to contain additional directories. Our own recommendation is to use the ^reportlab/fonts^ folder in development; and to have any needed fonts as packaged parts of your application in any kind of controlled server deployment. This insulates you from fonts being installed and uninstalled by other software or system administrator. """) heading3("Warnings about missing glyphs") disc("""If you specify an encoding, it is generally assumed that the font designer has provided all the needed glyphs. However, this is not always true. In the case of our example font, the letters of the alphabet are present, but many symbols and accents are missing. The default behaviour is for the font to print a 'notdef' character - typically a blob, dot or space - when passed a character it cannot draw. However, you can ask the library to warn you instead; the code below (executed before loading a font) will cause warnings to be generated for any glyphs not in the font when you register it.""") eg(""" import reportlab.rl_config reportlab.rl_config.warnOnMissingFontGlyphs = 0 """) heading2("Standard Single-Byte Font Encodings") disc(""" This section shows you the glyphs available in the common encodings. """) disc("""The code chart below shows the characters in the $WinAnsiEncoding$. This is the standard encoding on Windows and many Unix systems in America and Western Europe. It is also knows as Code Page 1252, and is practically identical to ISO-Latin-1 (it contains one or two extra characters). This is the default encoding used by the Reportlab PDF Library. It was generated from a standard routine in $reportlab/lib$, $codecharts.py$, which can be used to display the contents of fonts. The index numbers along the edges are in hex.""") cht1 = SingleByteEncodingChart(encodingName='WinAnsiEncoding',charsPerRow=32, boxSize=12) illust(lambda canv: cht1.drawOn(canv, 0, 0), "WinAnsi Encoding", cht1.width, cht1.height) disc("""The code chart below shows the characters in the $MacRomanEncoding$. as it sounds, this is the standard encoding on Macintosh computers in America and Western Europe. As usual with non-unicode encodings, the first 128 code points (top 4 rows in this case) are the ASCII standard and agree with the WinAnsi code chart above; but the bottom 4 rows differ.""") cht2 = SingleByteEncodingChart(encodingName='MacRomanEncoding',charsPerRow=32, boxSize=12) illust(lambda canv: cht2.drawOn(canv, 0, 0), "MacRoman Encoding", cht2.width, cht2.height) disc("""These two encodings are available for the standard fonts (Helvetica, Times-Roman and Courier and their variants) and will be available for most commercial fonts including those from Adobe. However, some fonts contain non- text glyphs and the concept does not really apply. For example, ZapfDingbats and Symbol can each be treated as having their own encoding.""") cht3 = SingleByteEncodingChart(faceName='ZapfDingbats',encodingName='ZapfDingbatsEncoding',charsPerRow=32, boxSize=12) illust(lambda canv: cht3.drawOn(canv, 0, 0), "ZapfDingbats and its one and only encoding", cht3.width, cht3.height) cht4 = SingleByteEncodingChart(faceName='Symbol',encodingName='SymbolEncoding',charsPerRow=32, boxSize=12) illust(lambda canv: cht4.drawOn(canv, 0, 0), "Symbol and its one and only encoding", cht4.width, cht4.height) CPage(5) heading2("TrueType Font Support") disc(""" Marius Gedminas ($mgedmin@delfi.lt$) with the help of Viktorija Zaksiene ($vika@pov.lt$) have contributed support for embedded TrueType fonts. TrueType fonts work in Unicode/UTF8 and are not limited to 256 characters.""") CPage(3) disc("""We use $reportlab.pdfbase.ttfonts.TTFont$ to create a true type font object and register using $reportlab.pdfbase.pdfmetrics.registerFont$. In pdfgen drawing directly to the canvas we can do""") eg(""" # we know some glyphs are missing, suppress warnings import reportlab.rl_config reportlab.rl_config.warnOnMissingFontGlyphs = 0 from reportlab.pdfbase import pdfmetrics from reportlab.pdfbase.ttfonts import TTFont pdfmetrics.registerFont(TTFont('Vera', 'Vera.ttf')) pdfmetrics.registerFont(TTFont('VeraBd', 'VeraBd.ttf')) pdfmetrics.registerFont(TTFont('VeraIt', 'VeraIt.ttf')) pdfmetrics.registerFont(TTFont('VeraBI', 'VeraBI.ttf')) canvas.setFont('Vera', 32) canvas.drawString(10, 150, "Some text encoded in UTF-8") canvas.drawString(10, 100, "In the Vera TT Font!") """) illust(examples.ttffont1, "Using a the Vera TrueType Font") disc("""In the above example the true type font object is created using""") eg(""" TTFont(name,filename) """) disc("""so that the ReportLab internal name is given by the first argument and the second argument is a string(or file like object) denoting the font's TTF file. In Marius' original patch the filename was supposed to be exactly correct, but we have modified things so that if the filename is relative then a search for the corresponding file is done in the current directory and then in directories specified by $reportlab.rl_config.TTFSearchpath$!""") from reportlab.lib.styles import ParagraphStyle from reportlab.pdfbase.pdfmetrics import registerFontFamily registerFontFamily('Vera',normal='Vera',bold='VeraBd',italic='VeraIt',boldItalic='VeraBI') disc("""Before using the TT Fonts in Platypus we should add a mapping from the family name to the individual font names that describe the behaviour under the $<b>$ and $<i>$ attributes.""") eg(""" from reportlab.pdfbase.pdfmetrics import registerFontFamily registerFontFamily('Vera',normal='Vera',bold='VeraBd',italic='VeraIt',boldItalic='VeraBI') """) disc("""If we only have a Vera regular font, no bold or italic then we must map all to the same internal fontname. ^<b>^ and ^<i>^ tags may now be used safely, but have no effect. After registering and mapping the Vera font as above we can use paragraph text like""") parabox2("""This is in Times-Roman and this is in magenta Vera!""","Using TTF fonts in paragraphs") heading2("Asian Font Support") disc("""The Reportlab PDF Library aims to expose full support for Asian fonts. PDF is the first really portable solution for Asian text handling. There are two main approaches for this: Adobe's Asian Language Packs, or TrueType fonts. """) heading3("Asian Language Packs") disc(""" This approach offers the best performance since nothing needs embedding in the PDF file; as with the standard fonts, everything is on the reader.""") disc(""" Adobe makes available add-ons for each main language. In Adobe Reader 6.0 and 7.0, you will be prompted to download and install these as soon as you try to open a document using them. In earlier versions, you would see an error message on opening an Asian document and had to know what to do. """) disc(""" Japanese, Traditional Chinese (Taiwan/Hong Kong), Simplified Chinese (mainland China) and Korean are all supported and our software knows about the following fonts: """) bullet(""" $chs$ = Chinese Simplified (mainland): '$STSong-Light$' """) bullet(""" $cht$ = Chinese Traditional (Taiwan): '$MSung-Light$', '$MHei-Medium$' """) bullet(""" $kor$ = Korean: '$HYSMyeongJoStd-Medium$','$HYGothic-Medium$' """) bullet(""" $jpn$ = Japanese: '$HeiseiMin-W3$', '$HeiseiKakuGo-W5$' """) disc("""Since many users will not have the font packs installed, we have included a rather grainy ^bitmap^ of some Japanese characters. We will discuss below what is needed to generate them.""") # include a bitmap of some Asian text I=os.path.join(os.path.dirname(reportlab.__file__),'docs','images','jpnchars.jpg') try: getStory().append(Image(I)) except: disc("""An image should have appeared here.""") disc("""Prior to Version 2.0, you had to specify one of many native encodings when registering a CID Font. In version 2.0 you should a new UnicodeCIDFont class.""") eg(""" from reportlab.pdfbase import pdfmetrics from reportlab.pdfbase.cidfonts import UnicodeCIDFont pdfmetrics.registerFont(UnicodeCIDFont('HeiseiMin-W3')) canvas.setFont('HeiseiMin-W3', 16) # the two unicode characters below are "Tokyo" msg = u'\\u6771\\u4EAC : Unicode font, unicode input' canvas.drawString(100, 675, msg) """) #had to double-escape the slashes above to get escapes into the PDF disc("""The old coding style with explicit encodings should still work, but is now only relevant if you need to construct vertical text. We aim to add more readable options for horizontal and vertical text to the UnicodeCIDFont constructor in future. The following four test scripts generate samples in the corresponding languages:""") eg("""tests/test_multibyte_jpn.py tests/test_multibyte_kor.py tests/test_multibyte_chs.py tests/test_multibyte_cht.py""") ## put back in when we have vertical text... ##disc("""The illustration below shows part of the first page ##of the Japanese output sample. It shows both horizontal and vertical ##writing, and illustrates the ability to mix variable-width Latin ##characters in Asian sentences. The choice of horizontal and vertical ##writing is determined by the encoding, which ends in 'H' or 'V'. ##Whether an encoding uses fixed-width or variable-width versions ##of Latin characters also depends on the encoding used; see the definitions ##below.""") ## ##Illustration(image("../images/jpn.gif", width=531*0.50, ##height=435*0.50), 'Output from test_multibyte_jpn.py') ## ##caption(""" ##Output from test_multibyte_jpn.py ##""") disc("""In previous versions of the ReportLab PDF Library, we had to make use of Adobe's CMap files (located near Acrobat Reader if the Asian Language packs were installed). Now that we only have one encoding to deal with, the character width data is embedded in the package, and CMap files are not needed for generation. The CMap search path in ^rl_config.py^ is now deprecated and has no effect if you restrict yourself to UnicodeCIDFont. """) heading3("TrueType fonts with Asian characters") disc(""" This is the easy way to do it. No special handling at all is needed to work with Asian TrueType fonts. Windows users who have installed, for example, Japanese as an option in Control Panel, will have a font "msmincho.ttf" which can be used. However, be aware that it takes time to parse the fonts, and that quite large subsets may need to be embedded in your PDFs. We can also now parse files ending in .ttc, which are a slight variation of .ttf. """) heading3("To Do") disc("""We expect to be developing this area of the package for some time.accept2dyear Here is an outline of the main priorities. We welcome help!""") bullet(""" Ensure that we have accurate character metrics for all encodings in horizontal and vertical writing.""") bullet(""" Add options to ^UnicodeCIDFont^ to allow vertical and proportional variants where the font permits it.""") bullet(""" Improve the word wrapping code in paragraphs and allow vertical writing.""") CPage(5) heading2("RenderPM tests") disc("""This may also be the best place to mention the test function of $reportlab/graphics/renderPM.py$, which can be considered the cannonical place for tests which exercise renderPM (the "PixMap Renderer", as opposed to renderPDF, renderPS or renderSVG).""") disc("""If you run this from the command line, you should see lots of output like the following.""") eg("""C:\\code\\reportlab\\graphics>renderPM.py wrote pmout\\renderPM0.gif wrote pmout\\renderPM0.tif wrote pmout\\renderPM0.png wrote pmout\\renderPM0.jpg wrote pmout\\renderPM0.pct ... wrote pmout\\renderPM12.gif wrote pmout\\renderPM12.tif wrote pmout\\renderPM12.png wrote pmout\\renderPM12.jpg wrote pmout\\renderPM12.pct wrote pmout\\index.html""") disc("""This runs a number of tests progressing from a "Hello World" test, through various tests of Lines; text strings in a number of sizes, fonts, colours and alignments; the basic shapes; translated and rotated groups; scaled coordinates; rotated strings; nested groups; anchoring and non-standard fonts.""") disc("""It creates a subdirectory called $pmout$, writes the image files into it, and writes an $index.html$ page which makes it easy to refer to all the results.""") disc("""The font-related tests which you may wish to look at are test #11 ('Text strings in a non-standard font') and test #12 ('Test Various Fonts').""") ##### FILL THEM IN ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1691062243.0 reportlab-4.1.0/docs/userguide/ch3_pdffeatures.py0000664000175000017500000007352314462707743021475 0ustar00rptlabrptlab#Copyright ReportLab Europe Ltd. 2000-2017 #see license.txt for license details #history https://hg.reportlab.com/hg-public/reportlab/log/tip/docs/userguide/ch3_pdffeatures.py from tools.docco.rl_doc_utils import * heading1("Exposing PDF Special Capabilities") disc("""PDF provides a number of features to make electronic document viewing more efficient and comfortable, and our library exposes a number of these.""") heading2("Forms") disc("""The Form feature lets you create a block of graphics and text once near the start of a PDF file, and then simply refer to it on subsequent pages. If you are dealing with a run of 5000 repetitive business forms - for example, one-page invoices or payslips - you only need to store the backdrop once and simply draw the changing text on each page. Used correctly, forms can dramatically cut file size and production time, and apparently even speed things up on the printer. """) disc("""Forms do not need to refer to a whole page; anything which might be repeated often should be placed in a form.""") disc("""The example below shows the basic sequence used. A real program would probably define the forms up front and refer to them from another location.""") eg(examples.testforms) heading2("Links and Destinations") disc("""PDF supports internal hyperlinks. There is a very wide range of link types, destination types and events which can be triggered by a click. At the moment we just support the basic ability to jump from one part of a document to another, and to control the zoom level of the window after the jump. The bookmarkPage method defines a destination that is the endpoint of a jump.""") #todo("code example here...") eg(""" canvas.bookmarkPage(name, fit="Fit", left=None, top=None, bottom=None, right=None, zoom=None ) """) disc(""" By default the $bookmarkPage$ method defines the page itself as the destination. After jumping to an endpoint defined by bookmarkPage, the PDF browser will display the whole page, scaling it to fit the screen:""") eg("""canvas.bookmarkPage(name)""") disc("""The $bookmarkPage$ method can be instructed to display the page in a number of different ways by providing a $fit$ parameter.""") eg("") t = Table([ ['fit','Parameters Required','Meaning'], ['Fit',None,'Entire page fits in window (the default)'], ['FitH','top','Top coord at top of window, width scaled to fit'], ['FitV','left','Left coord at left of window, height scaled to fit'], ['FitR','left bottom right top','Scale window to fit the specified rectangle'], ['XYZ','left top zoom','Fine grained control. If you omit a parameter\nthe PDF browser interprets it as "leave as is"'] ]) t.setStyle(TableStyle([ ('FONT',(0,0),(-1,1),'Times-Bold',10,12), ('VALIGN',(0,0),(-1,-1),'MIDDLE'), ('INNERGRID', (0,0), (-1,-1), 0.25, colors.black), ('BOX', (0,0), (-1,-1), 0.25, colors.black), ])) getStory().append(t) caption("""Table - Required attributes for different fit types""") disc(""" Note : $fit$ settings are case-sensitive so $fit="FIT"$ is invalid """) disc(""" Sometimes you want the destination of a jump to be some part of a page. The $FitR$ fit allows you to identify a particular rectangle, scaling the area to fit the entire page. """) disc(""" To set the display to a particular x and y coordinate of the page and to control the zoom directly use fit="XYZ". """) eg(""" canvas.bookmarkPage('my_bookmark',fit="XYZ",left=0,top=200) """) disc(""" This destination is at the leftmost of the page with the top of the screen at position 200. Because $zoom$ was not set the zoom remains at whatever the user had it set to. """) eg(""" canvas.bookmarkPage('my_bookmark',fit="XYZ",left=0,top=200,zoom=2) """) disc("""This time zoom is set to expand the page 2X its normal size.""") disc(""" Note : Both $XYZ$ and $FitR$ fit types require that their positional parameters ($top, bottom, left, right$) be specified in terms of the default user space. They ignore any geometric transform in effect in the canvas graphic state. """) pencilnote() disc(""" Note: Two previous bookmark methods are supported but deprecated now that bookmarkPage is so general. These are $bookmarkHorizontalAbsolute$ and $bookmarkHorizontal$. """) heading3("Defining internal links") eg(""" canvas.linkAbsolute(contents, destinationname, Rect=None, addtopage=1, name=None, thickness=0, color=None, dashArray=None, **kw) """) disc(""" The $linkAbsolute$ method defines a starting point for a jump. When the user is browsing the generated document using a dynamic viewer (such as Acrobat Reader) when the mouse is clicked when the pointer is within the rectangle specified by $Rect$ the viewer will jump to the endpoint associated with $destinationname$. As in the case with $bookmarkHorizontalAbsolute$ the rectangle $Rect$ must be specified in terms of the default user space. The $contents$ parameter specifies a chunk of text which displays in the viewer if the user left-clicks on the region. """) disc(""" The rectangle $Rect$ must be specified in terms of a tuple ^(x1,y1,x2,y2)^ identifying the lower left and upper right points of the rectangle in default user space. """) disc(""" For example the code """) eg(""" canvas.bookmarkPage("Meaning_of_life") """) disc(""" defines a location as the whole of the current page with the identifier $Meaning_of_life$. To create a rectangular link to it while drawing a possibly different page, we would use this code: """) eg(""" canvas.linkAbsolute("Find the Meaning of Life", "Meaning_of_life", (inch, inch, 6*inch, 2*inch)) """) disc(""" By default during interactive viewing a rectangle appears around the link. Use the keyword argument $Border='[0 0 0]'$ to suppress the visible rectangle around the during viewing link. For example """) eg(""" canvas.linkAbsolute("Meaning of Life", "Meaning_of_life", (inch, inch, 6*inch, 2*inch), Border='[0 0 0]') """) disc("""The $thickness$, $color$ and $dashArray$ arguments may be used alternately to specify a border if no Border argument is specified. If Border is specified it must be either a string representation of a PDF array or a $PDFArray$ (see the pdfdoc module). The $color$ argument (which should be a $Color$ instance) is equivalent to a keyword argument $C$ which should resolve to a PDF color definition (Normally a three entry PDF array). """) disc("""The $canvas.linkRect$ method is similar in intent to the $linkAbsolute$ method, but has an extra argument $relative=1$ so is intended to obey the local userspace transformation.""") heading2("Outline Trees") disc("""Acrobat Reader has a navigation page which can hold a document outline; it should normally be visible when you open this guide. We provide some simple methods to add outline entries. Typically, a program to make a document (such as this user guide) will call the method $canvas.addOutlineEntry(^self, title, key, level=0, closed=None^)$ as it reaches each heading in the document. """) disc("""^title^ is the caption which will be displayed in the left pane. The ^key^ must be a string which is unique within the document and which names a bookmark, as with the hyperlinks. The ^level^ is zero - the uppermost level - unless otherwise specified, and it is an error to go down more than one level at a time (for example to follow a level 0 heading by a level 2 heading). Finally, the ^closed^ argument specifies whether the node in the outline pane is closed or opened by default.""") disc("""The snippet below is taken from the document template that formats this user guide. A central processor looks at each paragraph in turn, and makes a new outline entry when a new chapter occurs, taking the chapter heading text as the caption text. The key is obtained from the chapter number (not shown here), so Chapter 2 has the key 'ch2'. The bookmark to which the outline entry points aims at the whole page, but it could as easily have been an individual paragraph. """) eg(""" #abridged code from our document template if paragraph.style == 'Heading1': self.chapter = paragraph.getPlainText() key = 'ch%d' % self.chapterNo self.canv.bookmarkPage(key) self.canv.addOutlineEntry(paragraph.getPlainText(), key, 0, 0) """) heading2("Page Transition Effects") eg(""" canvas.setPageTransition(self, effectname=None, duration=1, direction=0,dimension='H',motion='I') """) disc(""" The $setPageTransition$ method specifies how one page will be replaced with the next. By setting the page transition effect to "dissolve" for example the current page will appear to melt away when it is replaced by the next page during interactive viewing. These effects are useful in spicing up slide presentations, among other places. Please see the reference manual for more detail on how to use this method. """) heading2("Internal File Annotations") eg(""" canvas.setAuthor(name) canvas.setTitle(title) canvas.setSubject(subj) """) disc(""" These methods have no automatically seen visible effect on the document. They add internal annotations to the document. These annotations can be viewed using the "Document Info" menu item of the browser and they also can be used as a simple standard way of providing basic information about the document to archiving software which need not parse the entire file. To find the annotations view the $*.pdf$ output file using a standard text editor (such as $notepad$ on MS/Windows or $vi$ or $emacs$ on unix) and look for the string $/Author$ in the file contents. """) eg(examples.testannotations) disc(""" If you want the subject, title, and author to automatically display in the document when viewed and printed you must paint them onto the document like any other text. """) illust(examples.annotations, "Setting document internal annotations") heading2("Encryption") heading3("About encrypting PDF files") disc(""" Adobe's PDF standard allows you to do three related things to a PDF file when you encrypt it: """) bullet("""Apply password protection to it, so a user must supply a valid password before being able to read it, """) bullet("""Encrypt the contents of the file to make it useless until it is decrypted, and """) bullet("""Control whether the user can print, copy and paste or modify the document while viewing it. """) disc(""" The PDF security handler allows two different passwords to be specified for a document: """) bullet("""The 'owner' password (aka the 'security password' or 'master password') """) bullet("""The 'user' password (aka the 'open password') """) disc(""" When a user supplies either one of these passwords, the PDF file will be opened, decrypted and displayed on screen. """) disc(""" If the owner password is supplied, then the file is opened with full control - you can do anything to it, including changing the security settings and passwords, or re-encrypting it with a new password. """) disc(""" If the user password was the one that was supplied, you open it up in a more restricted mode. The restrictions were put in place when the file was encrypted, and will either allow or deny the user permission to do the following: """) bullet(""" Modifying the document's contents """) bullet(""" Copying text and graphics from the document """) bullet(""" Adding or modifying text annotations and interactive form fields """) bullet(""" Printing the document """) disc(""" Note that all password protected PDF files are encrypted, but not all encrypted PDFs are password protected. If a document's user password is an empty string, there will be no prompt for the password when the file is opened. If you only secure a document with the owner password, there will also not be a prompt for the password when you open the file. If the owner and user passwords are set to the same string when encrypting the PDF file, the document will always open with the user access privileges. This means that it is possible to create a file which, for example, is impossible for anyone to print out, even the person who created it. """) t = Table([ ['Owner Password \nset?','User Password \nset?','Result'], ['Y','-','No password required when opening file. \nRestrictions apply to everyone.'], ['-','Y','User password required when opening file. \nRestrictions apply to everyone.'], ['Y','Y','A password required when opening file. \nRestrictions apply only if user password supplied.'], ],[90, 90, 260]) t.setStyle(TableStyle([ ('FONT',(0,0),(-1,0),'Times-Bold',10,12), ('VALIGN',(0,0),(-1,-1),'MIDDLE'), ('INNERGRID', (0,0), (-1,-1), 0.25, colors.black), ('BOX', (0,0), (-1,-1), 0.25, colors.black), ])) getStory().append(t) disc(""" When a PDF file is encrypted, encryption is applied to all the strings and streams in the file. This prevents people who don't have the password from simply removing the password from the PDF file to gain access to it - it renders the file useless unless you actually have the password. """) disc(""" PDF's standard encryption methods use the MD5 message digest algorithm (as described in RFC 1321, The MD5 Message-Digest Algorithm) and an encryption algorithm known as RC4. RC4 is a symmetric stream cipher - the same algorithm is used both for encryption and decryption, and the algorithm does not change the length of the data. """) heading3("How To Use Encryption") disc(""" Documents can be encrypted by passing an argument to the canvas object. """) disc(""" If the argument is a string object, it is used as the User password to the PDF. """) disc(""" The argument can also be an instance of the class $reportlab.lib.pdfencrypt.StandardEncryption$, which allows more finegrained control over encryption settings. """) disc(""" The $StandardEncryption$ constructor takes the following arguments: """) eg(""" def __init__(self, userPassword, ownerPassword=None, canPrint=1, canModify=1, canCopy=1, canAnnotate=1, strength=40): """) disc(""" The $userPassword$ and $ownerPassword$ parameters set the relevant password on the encrypted PDF. """) disc(""" The boolean flags $canPrint$, $canModify$, $canCopy$, $canAnnotate$ determine wether a user can perform the corresponding actions on the PDF when only a user password has been supplied. """) disc(""" If the user supplies the owner password while opening the PDF, all actions can be performed regardless of the flags. """) heading3("Example") disc(""" To create a document named hello.pdf with a user password of 'rptlab' on which printing is not allowed, use the following code: """) eg(""" from reportlab.pdfgen import canvas from reportlab.lib import pdfencrypt enc=pdfencrypt.StandardEncryption("rptlab",canPrint=0) def hello(c): c.drawString(100,100,"Hello World") c = canvas.Canvas("hello.pdf",encrypt=enc) hello(c) c.showPage() c.save() """) heading2("Interactive Forms") heading3("Overview of Interactive Forms") disc("""The PDF standard allows for various kinds of interactive elements, the ReportLab toolkit currently supports only a fraction of the possibilities and should be considered a work in progress. At present we allow choices with checkbox, radio, choice & listbox widgets; text values can be entered with a textfield widget. All the widgets are created by calling methods on the canvas.acroform property.""" ) heading3("Example") disc("This shows the basic mechanism of creating an interactive element on the current page.") eg(""" canvas.acroform.checkbox( name='CB0', tooltip='Field CB0', checked=True, x=72,y=72+4*36, buttonStyle='diamond', borderStyle='bevelled', borderWidth=2, borderColor=red, fillColor=green, textColor=blue, forceBorder=True) """) alStyle=TableStyle([ ('SPAN',(0,0),(-1,0)), ('FONT',(0,0),(-1,0),'Helvetica-Bold',10,12), ('FONT',(0,1),(-1,1),'Helvetica-BoldOblique',8,9.6), ('FONT',(0,2),(0,-1),'Helvetica-Bold',7,8.4), ('FONT',(1,2),(1,-1),'Helvetica',7,8.4), ('FONT',(2,2),(2,-1),'Helvetica-Oblique',7,8.4), ('ALIGN',(0,0),(-1,0),'CENTER'), ('ALIGN',(1,1),(1,1),'CENTER'), ('INNERGRID', (0,0), (-1,-1), 0.25, colors.black), ('BOX', (0,0), (-1,-1), 0.25, colors.black), ]) disc("""NB note that the acroform canvas property is created automatically on demand and that there is only one form allowd in a document.""") heading3("Checkbox Usage") disc("""The canvas.acroform.checkbox method creates a checkbox widget on the current page. The value of the checkbox is either YES or OFF. The arguments are""") t = Table([ ['canvas.acroform.checkbox parameters','',''], ['Parameter','Meaning','Default'], ["name","the parameter's name","None"], ["x","the horizontal position on the page (absolute coordinates)","0"], ["y","the vertical position on the page (absolute coordinates)","0"], ["size","The outline dimensions size x size","20"], ["checked","if True the checkbox is initially checked","False"], ["buttonStyle","the checkbox style (see below)","'check'"], ["shape","The outline of the widget (see below)","'square'"], ["fillColor","colour to be used to fill the widget","None"], ["textColor","the colour of the symbol or text","None"], ["borderWidth","as it says","1"], ["borderColor","the widget's border colour","None"], ["borderStyle","The border style name","'solid'"], ["tooltip","The text to display when hovering over the widget","None"], ["annotationFlags","blank separated string of annotation flags","'print'"], ["fieldFlags","Blank separated field flags (see below)","'required'"], ["forceBorder","when true a border force a border to be drawn","False"], ["relative","if true obey the current canvas transform","False"], ["dashLen ","the dashline to be used if the borderStyle=='dashed'","3"], ],[90, 260, 90],style=alStyle,repeatRows=2) getStory().append(t) heading3("Radio Usage") disc("""The canvas.acroform.radio method creates a radio widget on the current page. The value of the radio is the value of the radio group's selected value or OFF if none are selected. The arguments are""") t = Table([ ['canvas.acroform.radio parameters','',''], ['Parameter','Meaning','Default'], ["name","the radio's group (ie parameter) name","None"], ["value","the radio's group name","None"], ["x","the horizontal position on the page (absolute coordinates)","0"], ["y","the vertical position on the page (absolute coordinates)","0"], ["size","The outline dimensions size x size","20"], ["selected","if True this radio is the selected one in its group","False"], ["buttonStyle","the checkbox style (see below)","'check'"], ["shape","The outline of the widget (see below)","'square'"], ["fillColor","colour to be used to fill the widget","None"], ["textColor","the colour of the symbol or text","None"], ["borderWidth","as it says","1"], ["borderColor","the widget's border colour","None"], ["borderStyle","The border style name","'solid'"], ["tooltip","The text to display when hovering over the widget","None"], ["annotationFlags","blank separated string of annotation flags","'print'"], ["fieldFlags","Blank separated field flags (see below)","'noToggleToOff required radio'"], ["forceBorder","when true a border force a border to be drawn","False"], ["relative","if true obey the current canvas transform","False"], ["dashLen ","the dashline to be used if the borderStyle=='dashed'","3"], ],[90, 260, 90],style=alStyle,repeatRows=2) getStory().append(t) heading3("Listbox Usage") disc("""The canvas.acroform.listbox method creates a listbox widget on the current page. The listbox contains a list of options one or more of which (depending on fieldFlags) may be selected. """) t = Table([ ['canvas.acroform.listbox parameters','',''], ['Parameter','Meaning','Default'], ["name","the radio's group (ie parameter) name","None"], ["options","List or tuple of avaiable options","[]"], ["value","Singleton or list of strings of selected options","[]"], ["x","the horizontal position on the page (absolute coordinates)","0"], ["y","the vertical position on the page (absolute coordinates)","0"], ["width","The widget width","120"], ["height","The widget height","36"], ["fontName","The name of the type 1 font to be used","'Helvetica'"], ["fontSize","The size of font to be used","12"], ["fillColor","colour to be used to fill the widget","None"], ["textColor","the colour of the symbol or text","None"], ["borderWidth","as it says","1"], ["borderColor","the widget's border colour","None"], ["borderStyle","The border style name","'solid'"], ["tooltip","The text to display when hovering over the widget","None"], ["annotationFlags","blank separated string of annotation flags","'print'"], ["fieldFlags","Blank separated field flags (see below)","''"], ["forceBorder","when true a border force a border to be drawn","False"], ["relative","if true obey the current canvas transform","False"], ["dashLen ","the dashline to be used if the borderStyle=='dashed'","3"], ],[90, 260, 90],style=alStyle,repeatRows=2) getStory().append(t) heading3("Choice Usage") disc("""The canvas.acroform.choice method creates a dropdown widget on the current page. The dropdown contains a list of options one or more of which (depending on fieldFlags) may be selected. If you add edit to the fieldFlags then the result may be edited. """) t = Table([ ['canvas.acroform.choice parameters','',''], ['Parameter','Meaning','Default'], ["name","the radio's group (ie parameter) name","None"], ["options","List or tuple of avaiable options","[]"], ["value","Singleton or list of strings of selected options","[]"], ["x","the horizontal position on the page (absolute coordinates)","0"], ["y","the vertical position on the page (absolute coordinates)","0"], ["width","The widget width","120"], ["height","The widget height","36"], ["fontName","The name of the type 1 font to be used","'Helvetica'"], ["fontSize","The size of font to be used","12"], ["fillColor","colour to be used to fill the widget","None"], ["textColor","the colour of the symbol or text","None"], ["borderWidth","as it says","1"], ["borderColor","the widget's border colour","None"], ["borderStyle","The border style name","'solid'"], ["tooltip","The text to display when hovering over the widget","None"], ["annotationFlags","blank separated string of annotation flags","'print'"], ["fieldFlags","Blank separated field flags (see below)","'combo'"], ["forceBorder","when true a border force a border to be drawn","False"], ["relative","if true obey the current canvas transform","False"], ["dashLen ","the dashline to be used if the borderStyle=='dashed'","3"], ["maxlen ","None or maximum length of the widget value","None"], ],[90, 260, 90],style=alStyle,repeatRows=2) getStory().append(t) heading3("Textfield Usage") disc("""The canvas.acroform.textfield method creates a textfield entry widget on the current page. The textfield may be edited to change tha value of the widget """) t = Table([ ['canvas.acroform.textfield parameters','',''], ['Parameter','Meaning','Default'], ["name","the radio's group (ie parameter) name","None"], ["value","Value of the text field","''"], ["maxlen ","None or maximum length of the widget value","100"], ["x","the horizontal position on the page (absolute coordinates)","0"], ["y","the vertical position on the page (absolute coordinates)","0"], ["width","The widget width","120"], ["height","The widget height","36"], ["fontName","The name of the type 1 font to be used","'Helvetica'"], ["fontSize","The size of font to be used","12"], ["fillColor","colour to be used to fill the widget","None"], ["textColor","the colour of the symbol or text","None"], ["borderWidth","as it says","1"], ["borderColor","the widget's border colour","None"], ["borderStyle","The border style name","'solid'"], ["tooltip","The text to display when hovering over the widget","None"], ["annotationFlags","blank separated string of annotation flags","'print'"], ["fieldFlags","Blank separated field flags (see below)","''"], ["forceBorder","when true a border force a border to be drawn","False"], ["relative","if true obey the current canvas transform","False"], ["dashLen ","the dashline to be used if the borderStyle=='dashed'","3"], ],[90, 260, 90],style=alStyle,repeatRows=2) getStory().append(t) heading3("Button styles") disc("""The button style argument indicates what style of symbol should appear in the button when it is selected. There are several choices""") eg(""" check cross circle star diamond """) disc("""note that the document renderer can make some of these symbols wrong for their intended application. Acrobat reader prefers to use its own rendering on top of what the specification says should be shown (especially when the forms hihlighting features are used""") heading3("Widget shape") disc("""The shape argument describes how the outline of the checkbox or radio widget should appear you can use""") eg(""" circle square """) disc("""The renderer may make its own decisions about how the widget should look; so Acrobat Reader prefers circular outlines for radios.""") heading3("Border style") disc("""The borderStyle argument changes the 3D appearance of the widget on the page alternatives are""") eg(""" solid dashed inset bevelled underlined """) heading3("fieldFlags Argument") disc("""The fieldFlags arguments can be an integer or a string containing blank separate tokens the values are shown in the table below. For more information consult the PDF specification.""") t = Table([ ['Field Flag Tokens and values','',''], ['Token','Meaning','Value'], ["readOnly","The widget is read only","1<<0"], ["required","the widget is required","1<<1"], ["noExport","don't export the widget value","1<<2"], ["noToggleToOff","radios one only must be on","1<<14"], ["radio","added by the radio method","1<<15"], ["pushButton","if the button is a push button","1<<16"], ["radiosInUnison","radios with the same value toggle together","1<<25"], ["multiline","for multiline text widget","1<<12"], ["password","password textfield","1<<13"], ["fileSelect","file selection widget","1<<20"], #1.4 ["doNotSpellCheck","as it says","1<<22"], #1.4 ["doNotScroll","text fields do not scroll","1<<23"], #1.4 ["comb","make a comb style text based on the maxlen value","1<<24"], #1.5 ["richText","if rich text is used","1<<25"], #1.5 ["combo","for choice fields","1<<17"], ["edit","if the choice is editable","1<<18"], ["sort","if the values should be sorted","1<<19"], ["multiSelect","if the choice allows multi-select","1<<21"], #1.4 ["commitOnSelChange","not used by reportlab","1<<26"], #1.5 ],[90, 260, 90],style=alStyle,repeatRows=2) getStory().append(t) heading3("annotationFlags Argument") disc("""PDF widgets are annotations and have annotation properties these are shown in the table below""") t = Table([ ['Annotation Flag Tokens and values','',''], ['Token','Meaning','Value'], ["invisible","The widget is not shown","1<<0"], ["hidden","The widget is hidden","1<<1"], ["print","The widget will print","1<<2"], ["nozoom","The annotation will notscale with the rendered page","1<<3"], ["norotate","The widget won't rotate with the page","1<<4"], ["noview","Don't render the widget","1<<5"], ["readonly","Widget cannot be interacted with","1<<6"], ["locked","The widget cannot be changed","1<<7"], #1.4 ["togglenoview","Teh widget may be viewed after some events","1<<8"], #1.9 ["lockedcontents","The contents of the widget are fixed","1<<9"], #1.7 ],[90, 260, 90],style=alStyle) getStory().append(t) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1691062243.0 reportlab-4.1.0/docs/userguide/ch4_platypus_concepts.py0000664000175000017500000004556214462707743022747 0ustar00rptlabrptlab#Copyright ReportLab Europe Ltd. 2000-2017 #see license.txt for license details #history https://hg.reportlab.com/hg-public/reportlab/log/tip/docs/userguide/ch4_platypus_concepts.py from tools.docco.rl_doc_utils import * #####################################################################################################3 heading1("PLATYPUS - Page Layout and Typography Using Scripts") heading2("Design Goals") disc(""" Platypus stands for "Page Layout and Typography Using Scripts". It is a high level page layout library which lets you programmatically create complex documents with a minimum of effort. """) disc(""" The design of Platypus seeks to separate "high level" layout decisions from the document content as much as possible. Thus, for example, paragraphs are constructed using paragraph styles and pages are constructed using page templates with the intention that hundreds of documents with thousands of pages can be reformatted to different style specifications with the modifications of a few lines in a single shared file which contains the paragraph styles and page layout specifications. """) disc(""" The overall design of Platypus can be thought of has having several layers, top down, these are""") disc("$DocTemplates$ the outermost container for the document;") disc("$PageTemplates$ specifications for layouts of pages of various kinds;") disc("$Frames$ specifications of regions in pages that can contain flowing text or graphics.") disc("""$Flowables$ text or graphic elements that should be "flowed into the document (i.e. things like images, paragraphs and tables, but not things like page footers or fixed page graphics).""") disc("""$pdfgen.Canvas$ the lowest level which ultimately receives the painting of the document from the other layers.""") illust(examples.doctemplateillustration, "Illustration of DocTemplate structure") disc(""" The illustration above graphically illustrates the concepts of $DocTemplates$, $PageTemplates$ and $Flowables$. It is deceptive, however, because each of the $PageTemplates$ actually may specify the format for any number of pages (not just one as might be inferred from the diagram). """) disc(""" $DocTemplates$ contain one or more $PageTemplates$ each of which contain one or more $Frames$. $Flowables$ are things which can be flowed into a $Frame$ e.g. a $Paragraph$ or a $Table$. """) disc(""" To use platypus you create a document from a $DocTemplate$ class and pass a list of $Flowable$s to its $build$ method. The document $build$ method knows how to process the list of flowables into something reasonable. """) disc(""" Internally the $DocTemplate$ class implements page layout and formatting using various events. Each of the events has a corresponding handler method called $handle_XXX$ where $XXX$ is the event name. A typical event is $frameBegin$ which occurs when the machinery begins to use a frame for the first time. """) disc(""" A Platypus story consists of a sequence of basic elements called $Flowables$ and these elements drive the data driven Platypus formatting engine. To modify the behavior of the engine a special kind of flowable, $ActionFlowables$, tell the layout engine to, for example, skip to the next column or change to another $PageTemplate$. """) heading2("""Getting started""") disc("""Consider the following code sequence which provides a very simple "hello world" example for Platypus.""") eg(examples.platypussetup) disc("""First we import some constructors, some paragraph styles and other conveniences from other modules.""") eg(examples.platypusfirstpage) disc("""We define the fixed features of the first page of the document with the function above.""") eg(examples.platypusnextpage) disc("""Since we want pages after the first to look different from the first we define an alternate layout for the fixed features of the other pages. Note that the two functions above use the $pdfgen$ level canvas operations to paint the annotations for the pages. """) eg(examples.platypusgo) disc(""" Finally, we create a story and build the document. Note that we are using a "canned" document template here which comes pre-built with page templates. We are also using a pre-built paragraph style. We are only using two types of flowables here -- $Spacers$ and $Paragraphs$. The first $Spacer$ ensures that the Paragraphs skip past the title string. """) disc(""" To see the output of this example program run the module $tools/docco/examples.py$ (from the ReportLab $source$ distribution) as a "top level script". The script interpretation $python examples.py$ will generate the Platypus output $phello.pdf$. """) heading2("$Flowables$") disc(""" $Flowables$ are things which can be drawn and which have $wrap$, $draw$ and perhaps $split$ methods. $Flowable$ is an abstract base class for things to be drawn and an instance knows its size and draws in its own coordinate system (this requires the base API to provide an absolute coordinate system when the $Flowable.draw$ method is called). To get an instance use $f=Flowable()$. """) disc(""" It should be noted that the $Flowable$ class is an abstract class and is normally only used as a base class. """) k=startKeep() disc(""" To illustrate the general way in which $Flowables$ are used we show how a derived class $Paragraph$ is used and drawn on a canvas. $Paragraphs$ are so important they will get a whole chapter to themselves. """) eg(""" from reportlab.lib.styles import getSampleStyleSheet from reportlab.platypus import Paragraph from reportlab.pdfgen.canvas import Canvas styleSheet = getSampleStyleSheet() style = styleSheet['BodyText'] P=Paragraph('This is a very silly example',style) canv = Canvas('doc.pdf') aW = 460 # available width and height aH = 800 w,h = P.wrap(aW, aH) # find required space if w<=aW and h<=aH: P.drawOn(canv,0,aH) aH = aH - h # reduce the available height canv.save() else: raise ValueError, "Not enough room" """) endKeep(k) heading3("$Flowable$ User Methods") eg(""" Flowable.draw() """) disc("""This will be called to ask the flowable to actually render itself. The $Flowable$ class does not implement $draw$. The calling code should ensure that the flowable has an attribute $canv$ which is the $pdfgen.Canvas$ which should be drawn to an that the $Canvas$ is in an appropriate state (as regards translations rotations, etc). Normally this method will only be called internally by the $drawOn$ method. Derived classes must implement this method. """) eg(""" Flowable.drawOn(canvas,x,y) """) disc(""" This is the method which controlling programs use to render the flowable to a particular canvas. It handles the translation to the canvas coordinate (x,y) and ensuring that the flowable has a $canv$ attribute so that the $draw$ method (which is not implemented in the base class) can render in an absolute coordinate frame. """) eg(""" Flowable.wrap(availWidth, availHeight) """) disc("""This will be called by the enclosing frame before objects are asked their size, drawn or whatever. It returns the size actually used.""") eg(""" Flowable.split(self, availWidth, availheight): """) disc("""This will be called by more sophisticated frames when wrap fails. Stupid flowables should return [] meaning that they are unable to split. Clever flowables should split themselves and return a list of flowables. It is up to the client code to ensure that repeated attempts to split are avoided. If the space is sufficient the split method should return [self]. Otherwise the flowable should rearrange itself and return a list $[f0,...]$ of flowables which will be considered in order. The implemented split method should avoid changing $self$ as this will allow sophisticated layout mechanisms to do multiple passes over a list of flowables. """) heading2("Guidelines for flowable positioning") disc("""Two methods, which by default return zero, provide guidance on vertical spacing of flowables: """) eg(""" Flowable.getSpaceAfter(self): Flowable.getSpaceBefore(self): """) disc("""These methods return how much space should follow or precede the flowable. The space doesn't belong to the flowable itself i.e. the flowable's $draw$ method shouldn't consider it when rendering. Controlling programs will use the values returned in determining how much space is required by a particular flowable in context. """) disc("""All flowables have an $hAlign$ property: $('LEFT', 'RIGHT', 'CENTER' or 'CENTRE')$. For paragraphs, which fill the full width of the frame, this has no effect. For tables, images or other objects which are less than the width of the frame, this determines their horizontal placement. """) disc("""The chapters which follow will cover the most important specific types of flowables: Paragraphs and Tables.""") heading2("Frames") disc(""" $Frames$ are active containers which are themselves contained in $PageTemplates$. $Frames$ have a location and size and maintain a concept of remaining drawable space. The command """) eg(""" Frame(x1, y1, width,height, leftPadding=6, bottomPadding=6, rightPadding=6, topPadding=6, id=None, showBoundary=0) """) disc("""creates a $Frame$ instance with lower left hand corner at coordinate $(x1,y1)$ (relative to the canvas at use time) and with dimensions $width$ x $height$. The $Padding$ arguments are positive quantities used to reduce the space available for drawing. The $id$ argument is an identifier for use at runtime e.g. 'LeftColumn' or 'RightColumn' etc. If the $showBoundary$ argument is non-zero then the boundary of the frame will get drawn at run time (this is useful sometimes). """) heading3("$Frame$ User Methods") eg(""" Frame.addFromList(drawlist, canvas) """) disc("""consumes $Flowables$ from the front of $drawlist$ until the frame is full. If it cannot fit one object, raises an exception.""") eg(""" Frame.split(flowable,canv) """) disc('''Asks the flowable to split using up the available space and return the list of flowables. ''') eg(""" Frame.drawBoundary(canvas) """) disc("draws the frame boundary as a rectangle (primarily for debugging).") heading3("Using $Frames$") disc(""" $Frames$ can be used directly with canvases and flowables to create documents. The $Frame.addFromList$ method handles the $wrap$ & $drawOn$ calls for you. You don't need all of the Platypus machinery to get something useful into PDF. """) eg(""" from reportlab.pdfgen.canvas import Canvas from reportlab.lib.styles import getSampleStyleSheet from reportlab.lib.units import inch from reportlab.platypus import Paragraph, Frame styles = getSampleStyleSheet() styleN = styles['Normal'] styleH = styles['Heading1'] story = [] #add some flowables story.append(Paragraph("This is a Heading",styleH)) story.append(Paragraph("This is a paragraph in Normal style.", styleN)) c = Canvas('mydoc.pdf') f = Frame(inch, inch, 6*inch, 9*inch, showBoundary=1) f.addFromList(story,c) c.save() """) heading2("Documents and Templates") disc(""" The $BaseDocTemplate$ class implements the basic machinery for document formatting. An instance of the class contains a list of one or more $PageTemplates$ that can be used to describe the layout of information on a single page. The $build$ method can be used to process a list of $Flowables$ to produce a PDF document. """) CPage(3.0) heading3("The $BaseDocTemplate$ class") eg(""" BaseDocTemplate(self, filename, pagesize=defaultPageSize, pageTemplates=[], showBoundary=0, leftMargin=inch, rightMargin=inch, topMargin=inch, bottomMargin=inch, allowSplitting=1, title=None, author=None, _pageBreakQuick=1, encrypt=None) """) disc(""" creates a document template suitable for creating a basic document. It comes with quite a lot of internal machinery, but no default page templates. The required $filename$ can be a string, the name of a file to receive the created PDF document; alternatively it can be an object which has a $write$ method such as a $BytesIO$ or $file$ or $socket$. """) disc(""" The allowed arguments should be self explanatory, but $showBoundary$ controls whether or not $Frame$ boundaries are drawn which can be useful for debugging purposes. The $allowSplitting$ argument determines whether the builtin methods should try to split individual $Flowables$ across $Frames$. The $_pageBreakQuick$ argument determines whether an attempt to do a page break should try to end all the frames on the page or not, before ending the page. The encrypt argument determines wether or not and how the document is encrypted. By default, the document is not encrypted. If $encrypt$ is a string object, it is used as the user password for the pdf. If $encrypt$ is an instance of $reportlab.lib.pdfencrypt.StandardEncryption$, this object is used to encrypt the pdf. This allows more finegrained control over the encryption settings. """) heading4("User $BaseDocTemplate$ Methods") disc("""These are of direct interest to client programmers in that they are normally expected to be used. """) eg(""" BaseDocTemplate.addPageTemplates(self,pageTemplates) """) disc(""" This method is used to add one or a list of $PageTemplates$ to an existing documents. """) eg(""" BaseDocTemplate.build(self, flowables, filename=None, canvasmaker=canvas.Canvas) """) disc(""" This is the main method which is of interest to the application programmer. Assuming that the document instance is correctly set up the $build$ method takes the story in the shape of the list of flowables (the $flowables$ argument) and loops through the list forcing the flowables one at a time through the formatting machinery. Effectively this causes the $BaseDocTemplate$ instance to issue calls to the instance $handle_XXX$ methods to process the various events. """) heading4("User Virtual $BaseDocTemplate$ Methods") disc(""" These have no semantics at all in the base class. They are intended as pure virtual hooks into the layout machinery. Creators of immediately derived classes can override these without worrying about affecting the properties of the layout engine. """) eg(""" BaseDocTemplate.afterInit(self) """) disc(""" This is called after initialisation of the base class; a derived class could overide the method to add default $PageTemplates$. """) eg(""" BaseDocTemplate.afterPage(self) """) disc("""This is called after page processing, and immediately after the afterDrawPage method of the current page template. A derived class could use this to do things which are dependent on information in the page such as the first and last word on the page of a dictionary. """) eg(""" BaseDocTemplate.beforeDocument(self) """) disc("""This is called before any processing is done on the document, but after the processing machinery is ready. It can therefore be used to do things to the instance\'s $pdfgen.canvas$ and the like. """) eg(""" BaseDocTemplate.beforePage(self) """) disc("""This is called at the beginning of page processing, and immediately before the beforeDrawPage method of the current page template. It could be used to reset page specific information holders.""") eg(""" BaseDocTemplate.filterFlowables(self,flowables) """) disc("""This is called to filter flowables at the start of the main handle_flowable method. Upon return if flowables[0] has been set to None it is discarded and the main method returns immediately. """) eg(""" BaseDocTemplate.afterFlowable(self, flowable) """) disc("""Called after a flowable has been rendered. An interested class could use this hook to gather information about what information is present on a particular page or frame.""") heading4("$BaseDocTemplate$ Event handler Methods") disc(""" These methods constitute the greater part of the layout engine. Programmers shouldn't have to call or override these methods directly unless they are trying to modify the layout engine. Of course, the experienced programmer who wants to intervene at a particular event, $XXX$, which does not correspond to one of the virtual methods can always override and call the base method from the drived class version. We make this easy by providing a base class synonym for each of the handler methods with the same name prefixed by an underscore '_'. """) eg(""" def handle_pageBegin(self): doStuff() BaseDocTemplate.handle_pageBegin(self) doMoreStuff() #using the synonym def handle_pageEnd(self): doStuff() self._handle_pageEnd() doMoreStuff() """) disc(""" Here we list the methods only as an indication of the events that are being handled. Interested programmers can take a look at the source. """) eg(""" handle_currentFrame(self,fx) handle_documentBegin(self) handle_flowable(self,flowables) handle_frameBegin(self,*args) handle_frameEnd(self) handle_nextFrame(self,fx) handle_nextPageTemplate(self,pt) handle_pageBegin(self) handle_pageBreak(self) handle_pageEnd(self) """) disc(""" Using document templates can be very easy; $SimpleDoctemplate$ is a class derived from $BaseDocTemplate$ which provides its own $PageTemplate$ and $Frame$ setup. """) eg(""" from reportlab.lib.styles import getSampleStyleSheet from reportlab.lib.pagesizes import letter from reportlab.platypus import Paragraph, SimpleDocTemplate styles = getSampleStyleSheet() styleN = styles['Normal'] styleH = styles['Heading1'] story = [] #add some flowables story.append(Paragraph("This is a Heading",styleH)) story.append(Paragraph("This is a paragraph in Normal style.", styleN)) doc = SimpleDocTemplate('mydoc.pdf',pagesize = letter) doc.build(story) """) heading3("$PageTemplates$") disc(""" The $PageTemplate$ class is a container class with fairly minimal semantics. Each instance contains a list of $Frames$ and has methods which should be called at the start and end of each page. """) eg("PageTemplate(id=None,frames=[],onPage=_doNothing,onPageEnd=_doNothing)") disc(""" is used to initialize an instance, the $frames$ argument should be a list of $Frames$ whilst the optional $onPage$ and $onPageEnd$ arguments are callables which should have signature $def XXX(canvas,document)$ where $canvas$ and $document$ are the canvas and document being drawn. These routines are intended to be used to paint non-flowing (i.e. standard) parts of pages. These attribute functions are exactly parallel to the pure virtual methods $PageTemplate.beforPage$ and $PageTemplate.afterPage$ which have signature $beforPage(self,canvas,document)$. The methods allow class derivation to be used to define standard behaviour, whilst the attributes allow instance changes. The $id$ argument is used at run time to perform $PageTemplate$ switching so $id='FirstPage'$ or $id='TwoColumns'$ are typical. """) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1691062243.0 reportlab-4.1.0/docs/userguide/ch5_paragraphs.py0000664000175000017500000005500414462707743021311 0ustar00rptlabrptlab#Copyright ReportLab Europe Ltd. 2000-2017 #see license.txt for license details #history https://hg.reportlab.com/hg-public/reportlab/log/tip/docs/userguide/ch5_paragraphs.py from tools.docco.rl_doc_utils import * #begin chapter oon paragraphs heading1("Paragraphs") disc(""" The $reportlab.platypus.Paragraph$ class is one of the most useful of the Platypus $Flowables$; it can format fairly arbitrary text and provides for inline font style and colour changes using an XML style markup. The overall shape of the formatted text can be justified, right or left ragged or centered. The XML markup can even be used to insert greek characters or to do subscripts. """) disc("""The following text creates an instance of the $Paragraph$ class:""") eg("""Paragraph(text, style, bulletText=None)""") disc("""The $text$ argument contains the text of the paragraph; excess white space is removed from the text at the ends and internally after linefeeds. This allows easy use of indented triple quoted text in Python scripts. The $bulletText$ argument provides the text of a default bullet for the paragraph. The font and other properties for the paragraph text and bullet are set using the style argument. """) disc(""" The $style$ argument should be an instance of class $ParagraphStyle$ obtained typically using""") eg(""" from reportlab.lib.styles import ParagraphStyle """) disc(""" this container class provides for the setting of multiple default paragraph attributes in a structured way. The styles are arranged in a dictionary style object called a $stylesheet$ which allows for the styles to be accessed as $stylesheet['BodyText']$. A sample style sheet is provided. """) eg(""" from reportlab.lib.styles import getSampleStyleSheet stylesheet=getSampleStyleSheet() normalStyle = stylesheet['Normal'] """) disc(""" The options which can be set for a $Paragraph$ can be seen from the $ParagraphStyle$ defaults. The values with leading underscore ('_') are derived from the defaults in module $reportlab.rl_config$ which are derived from module $reportlab.rl_settings$. """) heading4("$class ParagraphStyle$") eg(""" class ParagraphStyle(PropertySet): defaults = { 'fontName':_baseFontName, 'fontSize':10, 'leading':12, 'leftIndent':0, 'rightIndent':0, 'firstLineIndent':0, 'alignment':TA_LEFT, 'spaceBefore':0, 'spaceAfter':0, 'bulletFontName':_baseFontName, 'bulletFontSize':10, 'bulletIndent':0, 'textColor': black, 'backColor':None, 'wordWrap':None, 'borderWidth': 0, 'borderPadding': 0, 'borderColor': None, 'borderRadius': None, 'allowWidows': 1, 'allowOrphans': 0, 'textTransform':None, 'endDots':None, 'splitLongWords':1, 'underlineWidth': _baseUnderlineWidth, 'bulletAnchor': 'start', 'justifyLastLine': 0, 'justifyBreaks': 0, 'spaceShrinkage': _spaceShrinkage, 'strikeWidth': _baseStrikeWidth, #stroke width 'underlineOffset': _baseUnderlineOffset, #fraction of fontsize to offset underlines 'underlineGap': _baseUnderlineGap, #gap for double/triple underline 'strikeOffset': _baseStrikeOffset, #fraction of fontsize to offset strikethrough 'strikeGap': _baseStrikeGap, #gap for double/triple strike 'linkUnderline': _platypus_link_underline, #'underlineColor': None, #'strikeColor': None, 'hyphenationLang': _hyphenationLang, 'uriWasteReduce': _uriWasteReduce, 'embeddedHyphenation': _embeddedHyphenation, } """) heading2("Using Paragraph Styles") #this will be used in the ParaBox demos. sample = """You are hereby charged that on the 28th day of May, 1970, you did willfully, unlawfully, and with malice of forethought, publish an alleged English-Hungarian phrase book with intent to cause a breach of the peace. How do you plead?""" disc("""The $Paragraph$ and $ParagraphStyle$ classes together handle most common formatting needs. The following examples draw paragraphs in various styles, and add a bounding box so that you can see exactly what space is taken up.""") s1 = ParagraphStyle('Normal') parabox(sample, s1, 'The default $ParagraphStyle$') disc("""The two attributes $spaceBefore$ and $spaceAfter$ do what they say, except at the top or bottom of a frame. At the top of a frame, $spaceBefore$ is ignored, and at the bottom, $spaceAfter$ is ignored. This means that you could specify that a 'Heading2' style had two inches of space before when it occurs in mid-page, but will not get acres of whitespace at the top of a page. These two attributes should be thought of as 'requests' to the Frame and are not part of the space occupied by the Paragraph itself.""") disc("""The $fontSize$ and $fontName$ tags are obvious, but it is important to set the $leading$. This is the spacing between adjacent lines of text; a good rule of thumb is to make this 20% larger than the point size. To get double-spaced text, use a high $leading$. If you set $autoLeading$(default $"off"$) to $"min"$(use observed leading even if smaller than specified) or $"max"$(use the larger of observed and specified) then an attempt is made to determine the leading on a line by line basis. This may be useful if the lines contain different font sizes etc.""") disc("""The figure below shows space before and after and an increased leading:""") parabox(sample, ParagraphStyle('Spaced', spaceBefore=6, spaceAfter=6, leading=16), 'Space before and after and increased leading' ) disc("""The attribute $borderPadding$ adjusts the padding between the paragraph and the border of its background. This can either be a single value or a tuple containing 2 to 4 values. These values are applied the same way as in Cascading Style Sheets (CSS). If a single value is given, that value is applied to all four sides. If more than one value is given, they are applied in clockwise order to the sides starting at the top. If two or three values are given, the missing values are taken from the opposite side(s). Note that in the following example the yellow box is drawn by the paragraph itself.""") parabox(sample, ParagraphStyle('padded', borderPadding=(7, 2, 20), borderColor='#000000', borderWidth=1, backColor='#FFFF00'), 'Variable padding' ) disc("""The $leftIndent$ and $rightIndent$ attributes do exactly what you would expect; $firstLineIndent$ is added to the $leftIndent$ of the first line. If you want a straight left edge, remember to set $firstLineIndent$ equal to 0.""") parabox(sample, ParagraphStyle('indented', firstLineIndent=+24, leftIndent=24, rightIndent=24), 'one third inch indents at left and right, two thirds on first line' ) disc("""Setting $firstLineIndent$ equal to a negative number, $leftIndent$ much higher, and using a different font (we'll show you how later!) can give you a definition list:.""") parabox('Judge Pickles: ' + sample, ParagraphStyle('dl', leftIndent=36), 'Definition Lists' ) disc("""There are four possible values of $alignment$, defined as constants in the module reportlab.lib.enums. These are TA_LEFT, TA_CENTER or TA_CENTRE, TA_RIGHT and TA_JUSTIFY, with values of 0, 1, 2 and 4 respectively. These do exactly what you would expect.""") disc("""Set $wordWrap$ to $'CJK'$ to get Asian language linewrapping. For normal western text you can change the way the line breaking algorithm handles widows and orphans with the $allowWidows$ and $allowOrphans$ values. Both should normally be set to $0$, but for historical reasons we have allowed widows. The default color of the text can be set with $textColor$ and the paragraph background colour can be set with $backColor$. The paragraph's border properties may be changed using $borderWidth$, $borderPadding$, $borderColor$ and $borderRadius$.""") disc("""The $textTransform$ attribute can be None, 'uppercase' or 'lowercase' to get the obvious result and 'capitalize' to get initial letter capitalization.""") disc("""Attribute $endDots$ can be None, a string, or an object with attributes text and optional fontName, fontSize, textColor, backColor and dy(y offset) to specify trailing matter on the last line of left/right justified paragraphs.""") disc("""The $splitLongWords$ attribute can be set to a false value to avoid splitting very long words.""") disc("""Attribute $bulletAnchor$ can be 'start', 'middle', 'end' or 'numeric' to control where the bullet is anchored.""") disc("""The $justifyBreaks$ attribute controls whether lines deliberately broken with a $<br/>$ tag should be justified""") disc("""Attribute $spaceShrinkage$ is a fractional number specifiying by how much the space of a paragraph line may be shrunk in order to make it fit; typically it is something like 0.05""") disc("""The $underlineWidth$, $underlineOffset$, $underlineGap$ & $underlineColor$ attributes control the underline behaviour when the $<u>$ or a linking tag is used. Those tags can have override values of these attributes. The attribute value for width & offset is a $fraction * Letter$ where letter can be one of $P$, $L$, $f$ or $F$ representing fontSize proportions. $P$ uses the fontsize at the tag, $F$ is the maximum fontSize in the tag, $f$ is the initial fontsize inside the tag. $L$ means the global (paragrpah style) font size. $strikeWidth$, $strikeOffset$, $strikeGap$ & $strikeColor$ attributes do the same for strikethrough lines. """) disc("""Attribute $linkUnderline$ controls whether link tags are automatically underlined.""") disc("""If the $pyphen$ python module is installed attribute $hyphenationLang$ controls which language will be used to hyphenate words without explicit embedded hyphens.""") disc("""If $embeddedHyphenation$ is set then attempts will be made to split words with embedded hyphens.""") disc("""Attribute $uriWasteReduce$ controls how we attempt to split long uri's. It is the fraction of a line that we regard as too much waste. The default in module $reportlab.rl_settings$ is 0.5 which means that we will try and split a word that looks like a uri if we would waste at least half of the line.""") disc("""Currently the hyphenation and uri splitting are turned off by default. You need to modify the default settings by using the file $~/.rl_settings$ or adding a module $reportlab_settings.py$ to the python path. Suitable values are""") eg(""" hyphenationLanguage='en_GB' embeddedHyphenation=1 uriWasteReduce=0.3 """) heading2("Paragraph XML Markup Tags") disc("""XML markup can be used to modify or specify the overall paragraph style, and also to specify intra- paragraph markup.""") heading3("The outermost < para > tag") disc(""" The paragraph text may optionally be surrounded by <para attributes....> </para> tags. The attributes if any of the opening <para> tag affect the style that is used with the $Paragraph$ $text$ and/or $bulletText$. """) disc(" ") from reportlab.platypus.paraparser import _addAttributeNames, _paraAttrMap, _bulletAttrMap def getAttrs(A): _addAttributeNames(A) S={} for k, v in A.items(): a = v[0] if a not in S: S[a] = [k] else: S[a].append(k) K = list(sorted(S.keys())) K.sort() D=[('Attribute','Synonyms')] for k in K: D.append((k,", ".join(list(sorted(S[k]))))) cols=2*[None] rows=len(D)*[None] return D,cols,rows t=Table(*getAttrs(_paraAttrMap)) t.setStyle(TableStyle([ ('FONT',(0,0),(-1,1),'Times-Bold',10,12), ('FONT',(0,1),(-1,-1),'Courier',8,8), ('VALIGN',(0,0),(-1,-1),'MIDDLE'), ('INNERGRID', (0,0), (-1,-1), 0.25, colors.black), ('BOX', (0,0), (-1,-1), 0.25, colors.black), ])) getStory().append(t) caption("""Table - Synonyms for style attributes""") disc("""Some useful synonyms have been provided for our Python attribute names, including lowercase versions, and the equivalent properties from the HTML standard where they exist. These additions make it much easier to build XML-printing applications, since much intra-paragraph markup may not need translating. The table below shows the allowed attributes and synonyms in the outermost paragraph tag.""") CPage(1) heading2("Intra-paragraph markup") disc("""...), italic (...) and underline (...). Other tags which are allowed are strong (...), and strike through (...). The and tags may be used to refer to URIs, documents or bookmarks in the current document. The a variant of the tag can be used to mark a position in a document. A break (
) tag is also allowed.]]> """) parabox2("""You are hereby charged that on the 28th day of May, 1970, you did willfully, unlawfully, and with malice of forethought, publish an alleged English-Hungarian phrase book with intent to cause a breach of the peace. How do you plead?""", "Simple bold and italic tags") parabox2("""This
is a link to an anchor tag ie here. This is another link to the same anchor tag.""", "anchors and links") disc("""The link tag can be used as a reference, but not as an anchor. The a and link hyperlink tags have additional attributes fontName, fontSize, color & backColor attributes. The hyperlink reference can have a scheme of http:(external webpage), pdf:(different pdf document) or document:(same pdf document); a missing scheme is treated as document as is the case when the reference starts with # (in which case the anchor should omit it). Any other scheme is treated as some kind of URI. """) parabox2("""You are hereby charged that on the 28th day of May, 1970, you did willfully, unlawfully, and with malice of forethought,
publish an alleged English-Hungarian phrase book with intent to cause a breach of the peace. How do you plead?""", "Strong, strike, and break tags") heading3("The $<font>$ tag") disc("""The $<font>$ tag can be used to change the font name, size and text color for any substring within the paragraph. Legal attributes are $size$, $face$, $name$ (which is the same as $face$), $color$, and $fg$ (which is the same as $color$). The $name$ is the font family name, without any 'bold' or 'italic' suffixes. Colors may be HTML color names or a hex string encoded in a variety of ways; see ^reportlab.lib.colors^ for the formats allowed.""") parabox2("""You are hereby charged that on the 28th day of May, 1970, you did willfully, unlawfully, and with malice of forethought, publish an alleged English-Hungarian phrase book with intent to cause a breach of the peace. How do you plead?""", "The $font$ tag") heading3("Superscripts and Subscripts") disc("""Superscripts and subscripts are supported with the / and tags, which work exactly as you might expect. Additionally these three tags have attributes rise and size to optionally set the rise/descent and font size for the superscript/subscript text. In addition, most greek letters can be accessed by using the tag, or with mathML entity names.]]>""") ##parabox2("""epsiloniota ##pi = -1""", "Greek letters and subscripts") parabox2("""Equation (α): e ip = -1""", "Greek letters and superscripts") heading3("Inline Images") disc("""We can embed images in a paragraph with the <img/> tag which has attributes $src$, $width$, $height$ whose meanings are obvious. The $valign$ attribute may be set to a css like value from "baseline", "sub", "super", "top", "text-top", "middle", "bottom", "text-bottom"; the value may also be a numeric percentage or an absolute value. """) parabox2("""This <img/> is aligned top.

This <img/> is aligned bottom.

This <img/> is aligned middle.

This <img/> is aligned -4.

This <img/> is aligned +4.

This <img/> has width 10.

""","Inline images") disc("""The $src$ attribute can refer to a remote location eg $src="https://www.reportlab.com/images/logo.gif"$. By default we set $rl_config.trustedShemes$ to $['https','http', 'file', 'data', 'ftp']$ and $rl_config.trustedHosts=None$ the latter meaning no-restriction. You can modify these variables using one of the override files eg $reportlab_settings.py$ or $~/.reportlab_settings$. Or as comma separated strings in the environment variables $RL_trustedSchemes$ & $RL_trustedHosts$. Note that the $trustedHosts$ values may contain glob wild cars so *.reportlab.com will match the obvious domains.
*NB* use of trustedHosts and or trustedSchemes may not control behaviour & actions when $URI$ patterns are detected by the viewer application.""") heading3("The $<u>$ & $<strike>$ tags") disc("""These tags can be used to carry out explicit underlineing or strikethroughs. These tags have attributes $width$, $offset$, $color$, $gap$ & $kind$. The $kind$ attribute controls how many lines will be drawn (default $kind=1$) and when $kind>1$ the $gap$ attribute controls the disatnce between lines.""") heading3("The $<nobr>$ tag") disc("""If hyphenation is in operation the $<nobr>$ tag suppresses it so $<nobr>averylongwordthatwontbebroken</nobr>$ won't be broken.""") heading3("Numbering Paragraphs and Lists") disc("""The $<seq>$ tag provides comprehensive support for numbering lists, chapter headings and so on. It acts as an interface to the $Sequencer$ class in ^reportlab.lib.sequencer^. These are used to number headings and figures throughout this document. You may create as many separate 'counters' as you wish, accessed with the $id$ attribute; these will be incremented by one each time they are accessed. The $seqreset$ tag resets a counter. If you want it to resume from a number other than 1, use the syntax <seqreset id="mycounter" base="42">. Let's have a go:""") parabox2(""", , . Reset. , , .""", "Basic sequences") disc("""You can save specifying an ID by designating a counter ID as the default using the <seqdefault id="Counter"> tag; it will then be used whenever a counter ID is not specified. This saves some typing, especially when doing multi-level lists; you just change counter ID when stepping in or out a level.""") parabox2("""Continued... , , , , , , .""", "The default sequence") disc("""Finally, one can access multi-level sequences using a variation of Python string formatting and the $template$ attribute in a <seq> tags. This is used to do the captions in all of the figures, as well as the level two headings. The substring $%(counter)s$ extracts the current value of a counter without incrementing it; appending a plus sign as in $%(counter)s$ increments the counter. The figure captions use a pattern like the one below:""") parabox2("""Figure - Multi-level templates""", "Multi-level templates") disc("""We cheated a little - the real document used 'Figure', but the text above uses 'FigureNo' - otherwise we would have messed up our numbering!""") heading2("Bullets and Paragraph Numbering") disc("""In addition to the three indent properties, some other parameters are needed to correctly handle bulleted and numbered lists. We discuss this here because you have now seen how to handle numbering. A paragraph may have an optional ^bulletText^ argument passed to its constructor; alternatively, bullet text may be placed in a $..]]>$ tag at its head. This text will be drawn on the first line of the paragraph, with its x origin determined by the $bulletIndent$ attribute of the style, and in the font given in the $bulletFontName$ attribute. The "bullet" may be a single character such as (doh!) a bullet, or a fragment of text such as a number in some numbering sequence, or even a short title as used in a definition list. Fonts may offer various bullet characters but we suggest first trying the Unicode bullet ($•$), which may be written as $&bull;$, $&#x2022;$ or (in utf8) $\\xe2\\x80\\xa2$):""") t=Table(*getAttrs(_bulletAttrMap)) t.setStyle([ ('FONT',(0,0),(-1,1),'Times-Bold',10,12), ('FONT',(0,1),(-1,-1),'Courier',8,8), ('VALIGN',(0,0),(-1,-1),'MIDDLE'), ('INNERGRID', (0,0), (-1,-1), 0.25, colors.black), ('BOX', (0,0), (-1,-1), 0.25, colors.black), ]) getStory().append(t) caption("""Table - <bullet> attributes & synonyms""") disc("""The <bullet> tag is only allowed once in a given paragraph and its use overrides the implied bullet style and ^bulletText^ specified in the ^Paragraph^ creation. """) parabox("""this is a bullet point. Spam spam spam spam spam spam spam spam spam spam spam spam spam spam spam spam spam spam spam spam spam spam """, styleSheet['Bullet'], 'Basic use of bullet points') disc("""Exactly the same technique is used for numbers, except that a sequence tag is used. It is also possible to put a multi-character string in the bullet; with a deep indent and bold bullet font, you can make a compact definition list.""") ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1691062243.0 reportlab-4.1.0/docs/userguide/ch6_tables.py0000664000175000017500000010337314462707743020437 0ustar00rptlabrptlab#Copyright ReportLab Europe Ltd. 2000-2017 #see license.txt for license details #history https://hg.reportlab.com/hg-public/reportlab/log/tip/docs/userguide/ch6_tables.py from tools.docco.rl_doc_utils import * from reportlab.platypus import Image,ListFlowable, ListItem import reportlab heading1("Tables and TableStyles") disc(""" The $Table$ and $LongTable$ classes derive from the $Flowable$ class and are intended as a simple textual gridding mechanisms. The $longTable$ class uses a greedy algorithm when calculating column widths and is intended for long tables where speed counts. $Table$ cells can hold anything which can be converted to a Python $string$ or $Flowables$ (or lists of $Flowables$). """) disc(""" Our present tables are a trade-off between efficient drawing and specification and functionality. We assume the reader has some familiarity with HTML tables. In brief, they have the following characteristics: """) bullet("""They can contain anything convertible to a string; flowable objects such as other tables; or entire sub-stories""") bullet("""They can work out the row heights to fit the data if you don't supply the row height. (They can also work out the widths, but generally it is better for a designer to set the width manually, and it draws faster).""") bullet("""They can split across pages if needed (see the canSplit attribute). You can specify that a number of rows at the top and bottom should be repeated after the split (e.g. show the headers again on page 2,3,4...)""") bullet("""They have a simple and powerful notation for specifying shading and gridlines which works well with financial or database tables, where you don't know the number of rows up front. You can easily say 'make the last row bold and put a line above it'""") bullet("""The style and data are separated, so you can declare a handful of table styles and use them for a family of reports. Styes can also 'inherit', as with paragraphs.""") disc("""There is however one main limitation compared to an HTML table. They define a simple rectangular grid. There is no simple row or column spanning; if you need to span cells, you must nest tables inside table cells instead or use a more complex scheme in which the lead cell of a span contains the actual contents.""") disc(""" $Tables$ are created by passing the constructor an optional sequence of column widths, an optional sequence of row heights, and the data in row order. Drawing of the table can be controlled by using a $TableStyle$ instance. This allows control of the color and weight of the lines (if any), and the font, alignment and padding of the text. A primitive automatic row height and or column width calculation mechanism is provided for. """) heading2('$Table$ User Methods') disc("""These are the main methods which are of interest to the client programmer.""") heading4("""$Table(data, colWidths=None, rowHeights=None, style=None, splitByRow=1, repeatRows=0, repeatCols=0, rowSplitRange=None, spaceBefore=None, spaceAfter=None, cornerRadii=None)$""") disc("""The $data$ argument is a sequence of sequences of cell values each of which should be convertible to a string value using the $str$ function or should be a Flowable instance (such as a $Paragraph$) or a list (or tuple) of such instances. If a cell value is a $Flowable$ or list of $Flowables$ these must either have a determined width or the containing column must have a fixed width. The first row of cell values is in $data[0]$ i.e. the values are in row order. The $i$, $j$th. cell value is in $data[i][j]$. Newline characters $'\\n'$ in cell values are treated as line split characters and are used at draw time to format the cell into lines. """) disc("""The other arguments are fairly obvious, the $colWidths$ argument is a sequence of numbers or possibly $None$, representing the widths of the columns. The number of elements in $colWidths$ determines the number of columns in the table. A value of $None$ means that the corresponding column width should be calculated automatically.""") disc("""The $rowHeights$ argument is a sequence of numbers or possibly $None$, representing the heights of the rows. The number of elements in $rowHeights$ determines the number of rows in the table. A value of $None$ means that the corresponding row height should be calculated automatically.""") disc("""The $style$ argument can be an initial style for the table.""") disc("""The $splitByRow$ argument is only needed for tables both too tall and too wide to fit in the current context. In this case you must decide whether to 'tile' down and across, or across and then down. This parameter is a Boolean indicating that the $Table$ should split itself by row before attempting to split itself by column when too little space is available in the current drawing area and the caller wants the $Table$ to split. Splitting a $Table$ by column is currently not implemented, so setting $splitByRow$ to $False$ will result in a $NotImplementedError$.""") disc("""The $repeatRows$ argument specifies the number or a tuple of leading rows that should be repeated when the $Table$ is asked to split itself. If it is a tuple it should specify which of the leading rows should be repeated; this allows for cases where the first appearance of the table hsa more leading rows than later split parts. The $repeatCols$ argument is currently ignored as a $Table$ cannot be split by column.""") disc("""The $rowSplitRange$ argument may be used to control the splitting of the table to a subset of its rows; that can be to prevent splitting too close to the beginning or end of the table.""") disc("""The $spaceBefore$ & $spaceAfter$ arguments may be used to put extra space before or after the table when renedered in a $platypus$ story.""") disc("""The $style$ argument can be an initial style for the table.""") disc("""The $cornerRadii$ argument can be a list of the top left, top right, bottom left and bottom right radii. A positive non-zero radius indicates that the corner should be rounded. This argument will override any $ROUNDEDCORNERS$ command in the argument $style$ list (ie it has pririty).""") heading4('$Table.setStyle(tblStyle)$') disc(""" This method applies a particular instance of class $TableStyle$ (discussed below) to the $Table$ instance. This is the only way to get $tables$ to appear in a nicely formatted way. """) disc(""" Successive uses of the $setStyle$ method apply the styles in an additive fashion. That is, later applications override earlier ones where they overlap. """) heading2('$TableStyle$') disc(""" This class is created by passing it a sequence of commands, each command is a tuple identified by its first element which is a string; the remaining elements of the command tuple represent the start and stop cell coordinates of the command and possibly thickness and colors, etc. """) heading2("$TableStyle$ User Methods") heading3("$TableStyle(commandSequence)$") disc("""The creation method initializes the $TableStyle$ with the argument command sequence as an example:""") eg(""" LIST_STYLE = TableStyle( [('LINEABOVE', (0,0), (-1,0), 2, colors.green), ('LINEABOVE', (0,1), (-1,-1), 0.25, colors.black), ('LINEBELOW', (0,-1), (-1,-1), 2, colors.green), ('ALIGN', (1,1), (-1,-1), 'RIGHT')] ) """) heading3("$TableStyle.add(commandSequence)$") disc("""This method allows you to add commands to an existing $TableStyle$, i.e. you can build up $TableStyles$ in multiple statements. """) eg(""" LIST_STYLE.add('BACKGROUND', (0,0), (-1,0), colors.Color(0,0.7,0.7)) """) heading3("$TableStyle.getCommands()$") disc("""This method returns the sequence of commands of the instance.""") eg(""" cmds = LIST_STYLE.getCommands() """) heading2("$TableStyle$ Commands") disc("""The commands passed to $TableStyles$ come in three main groups which affect the table background, draw lines, or set cell styles. """) disc("""The first element of each command is its identifier, the second and third arguments determine the cell coordinates of the box of cells which are affected with negative coordinates counting backwards from the limit values as in Python indexing. The coordinates are given as (column, row) which follows the spreadsheet 'A1' model, but not the more natural (for mathematicians) 'RC' ordering. The top left cell is (0, 0) the bottom right is (-1, -1). Depending on the command various extra (???) occur at indices beginning at 3 on. """) heading3("""$TableStyle$ Cell Formatting Commands""") disc("""The cell formatting commands all begin with an identifier, followed by the start and stop cell definitions and the perhaps other arguments. the cell formatting commands are:""") npeg(""" FONT - takes fontname, optional fontsize and optional leading. FONTNAME (or FACE) - takes fontname. FONTSIZE (or SIZE) - takes fontsize in points; leading may get out of sync. LEADING - takes leading in points. TEXTCOLOR - takes a color name or (R,G,B) tuple. ALIGNMENT (or ALIGN) - takes one of LEFT, RIGHT and CENTRE (or CENTER) or DECIMAL. LEFTPADDING - takes an integer, defaults to 6. RIGHTPADDING - takes an integer, defaults to 6. BOTTOMPADDING - takes an integer, defaults to 3. TOPPADDING - takes an integer, defaults to 3. BACKGROUND - takes a color defined by an object, string name or numeric tuple/list, or takes a list/tuple describing a desired gradient fill which should contain three elements of the form [DIRECTION, startColor, endColor] where DIRECTION is either VERTICAL or HORIZONTAL. ROWBACKGROUNDS - takes a list of colors to be used cyclically. COLBACKGROUNDS - takes a list of colors to be used cyclically. VALIGN - takes one of TOP, MIDDLE or the default BOTTOM """) disc("""This sets the background cell color in the relevant cells. The following example shows the $BACKGROUND$, and $TEXTCOLOR$ commands in action:""") EmbeddedCode(""" data= [['00', '01', '02', '03', '04'], ['10', '11', '12', '13', '14'], ['20', '21', '22', '23', '24'], ['30', '31', '32', '33', '34']] t=Table(data) t.setStyle(TableStyle([('BACKGROUND',(1,1),(-2,-2),colors.green), ('TEXTCOLOR',(0,0),(1,-1),colors.red)])) """) disc("""To see the effects of the alignment styles we need some widths and a grid, but it should be easy to see where the styles come from.""") EmbeddedCode(""" data= [['00', '01', '02', '03', '04'], ['10', '11', '12', '13', '14'], ['20', '21', '22', '23', '24'], ['30', '31', '32', '33', '34']] t=Table(data,5*[0.4*inch], 4*[0.4*inch]) t.setStyle(TableStyle([('ALIGN',(1,1),(-2,-2),'RIGHT'), ('TEXTCOLOR',(1,1),(-2,-2),colors.red), ('VALIGN',(0,0),(0,-1),'TOP'), ('TEXTCOLOR',(0,0),(0,-1),colors.blue), ('ALIGN',(0,-1),(-1,-1),'CENTER'), ('VALIGN',(0,-1),(-1,-1),'MIDDLE'), ('TEXTCOLOR',(0,-1),(-1,-1),colors.green), ('INNERGRID', (0,0), (-1,-1), 0.25, colors.black), ('BOX', (0,0), (-1,-1), 0.25, colors.black), ])) """) heading3("""$TableStyle$ Line Commands""") disc(""" Line commands begin with the identifier, the start and stop cell coordinates and always follow this with the thickness (in points) and color of the desired lines. Colors can be names, or they can be specified as a (R, G, B) tuple, where R, G and B are floats and (0, 0, 0) is black. The line command names are: GRID, BOX, OUTLINE, INNERGRID, LINEBELOW, LINEABOVE, LINEBEFORE and LINEAFTER. BOX and OUTLINE are equivalent, and GRID is the equivalent of applying both BOX and INNERGRID. """) CPage(4.0) disc("""We can see some line commands in action with the following example. """) EmbeddedCode(""" data= [['00', '01', '02', '03', '04'], ['10', '11', '12', '13', '14'], ['20', '21', '22', '23', '24'], ['30', '31', '32', '33', '34']] t=Table(data,style=[('GRID',(1,1),(-2,-2),1,colors.green), ('BOX',(0,0),(1,-1),2,colors.red), ('LINEABOVE',(1,2),(-2,2),1,colors.blue), ('LINEBEFORE',(2,1),(2,-2),1,colors.pink), ]) """) disc("""Line commands cause problems for tables when they split; the following example shows a table being split in various positions""") EmbeddedCode(""" data= [['00', '01', '02', '03', '04'], ['10', '11', '12', '13', '14'], ['20', '21', '22', '23', '24'], ['30', '31', '32', '33', '34']] t=Table(data,style=[ ('GRID',(0,0),(-1,-1),0.5,colors.grey), ('GRID',(1,1),(-2,-2),1,colors.green), ('BOX',(0,0),(1,-1),2,colors.red), ('BOX',(0,0),(-1,-1),2,colors.black), ('LINEABOVE',(1,2),(-2,2),1,colors.blue), ('LINEBEFORE',(2,1),(2,-2),1,colors.pink), ('BACKGROUND', (0, 0), (0, 1), colors.pink), ('BACKGROUND', (1, 1), (1, 2), colors.lavender), ('BACKGROUND', (2, 2), (2, 3), colors.orange), ]) """) t=getStory()[-1] getStory().append(Spacer(0,6)) for s in t.split(4*inch,30): getStory().append(s) getStory().append(Spacer(0,6)) getStory().append(Spacer(0,6)) for s in t.split(4*inch,36): getStory().append(s) getStory().append(Spacer(0,6)) disc("""When unsplit and split at the first or second row.""") CPage(4.0) heading3("""Complex Cell Values""") disc(""" As mentioned above we can have complicated cell values including $Paragraphs$, $Images$ and other $Flowables$ or lists of the same. To see this in operation consider the following code and the table it produces. Note that the $Image$ has a white background which will obscure any background you choose for the cell. To get better results you should use a transparent background. """) import os, reportlab.platypus I = '../images/replogo.gif' EmbeddedCode(""" I = Image('%s') I.drawHeight = 1.25*inch*I.drawHeight / I.drawWidth I.drawWidth = 1.25*inch P0 = Paragraph(''' A paragraph 1''', styleSheet["BodyText"]) P = Paragraph(''' The ReportLab Left Logo Image''', styleSheet["BodyText"]) data= [['A', 'B', 'C', P0, 'D'], ['00', '01', '02', [I,P], '04'], ['10', '11', '12', [P,I], '14'], ['20', '21', '22', '23', '24'], ['30', '31', '32', '33', '34']] t=Table(data,style=[('GRID',(1,1),(-2,-2),1,colors.green), ('BOX',(0,0),(1,-1),2,colors.red), ('LINEABOVE',(1,2),(-2,2),1,colors.blue), ('LINEBEFORE',(2,1),(2,-2),1,colors.pink), ('BACKGROUND', (0, 0), (0, 1), colors.pink), ('BACKGROUND', (1, 1), (1, 2), colors.lavender), ('BACKGROUND', (2, 2), (2, 3), colors.orange), ('BOX',(0,0),(-1,-1),2,colors.black), ('GRID',(0,0),(-1,-1),0.5,colors.black), ('VALIGN',(3,0),(3,0),'BOTTOM'), ('BACKGROUND',(3,0),(3,0),colors.limegreen), ('BACKGROUND',(3,1),(3,1),colors.khaki), ('ALIGN',(3,1),(3,1),'CENTER'), ('BACKGROUND',(3,2),(3,2),colors.beige), ('ALIGN',(3,2),(3,2),'LEFT'), ]) t._argW[3]=1.5*inch """%I) heading3("""$TableStyle$ Span Commands""") disc("""Our $Table$ classes support the concept of spanning, but it isn't specified in the same way as html. The style specification """) eg(""" SPAN, (sc,sr), (ec,er) """) disc("""indicates that the cells in columns $sc$ - $ec$ and rows $sr$ - $er$ should be combined into a super cell with contents determined by the cell $(sc, sr)$. The other cells should be present, but should contain empty strings or you may get unexpected results. """) EmbeddedCode(""" data= [['Top\\nLeft', '', '02', '03', '04'], ['', '', '12', '13', '14'], ['20', '21', '22', 'Bottom\\nRight', ''], ['30', '31', '32', '', '']] t=Table(data,style=[ ('GRID',(0,0),(-1,-1),0.5,colors.grey), ('BACKGROUND',(0,0),(1,1),colors.palegreen), ('SPAN',(0,0),(1,1)), ('BACKGROUND',(-2,-2),(-1,-1), colors.pink), ('SPAN',(-2,-2),(-1,-1)), ]) """) disc("""notice that we don't need to be conservative with our $GRID$ command. The spanned cells are not drawn through. """) heading3("""$TableStyle$ Miscellaneous Commands""") disc("""To control $Table$ splitting the $NOSPLIT$ command may be used The style specification """) eg(""" NOSPLIT, (sc,sr), (ec,er) """) disc("""demands that the cells in columns $sc$ - $ec$ and rows $sr$ - $er$ may not be split.""") eg("") eg("") disc("""To control $Table$ corner rounding the $ROUNDEDCORNERS$ command may be used The style specification """) eg(""" ROUNDEDCORNERS, [tl, tr, bl, br] """) disc("""specifies the radii of the top left, top right, bottom left and bottom right. A value of $0$ indicates a square corner. replace the whole array by $None$ to turn off all rounding.
Borders at a rounded corner are curved by an octant.""") heading3("""Special $TableStyle$ Indeces""") disc("""In any style command the first row index may be set to one of the special strings $'splitlast'$ or $'splitfirst'$ to indicate that the style should be used only for the last row of a split table, or the first row of a continuation. This allows splitting tables with nicer effects around the split.""") heading1("""Programming $Flowables$""") disc("""The following flowables let you conditionally evaluate and execute expressions and statements at wrap time:""") heading2("""$DocAssign(self, var, expr, life='forever')$""") disc("""Assigns a variable of name $var$ to the expression $expr$. E.g.:""") eg(""" DocAssign('i',3) """) heading2("""$DocExec(self, stmt, lifetime='forever')$""") disc("""Executes the statement $stmt$. E.g.:""") eg(""" DocExec('i-=1') """) heading2("""$DocPara(self, expr, format=None, style=None, klass=None, escape=True)$""") disc("""Creates a paragraph with the value of expr as text. If format is specified it should use %(__expr__)s for string interpolation of the expression expr (if any). It may also use %(name)s interpolations for other variables in the namespace. E.g.:""") eg(""" DocPara('i',format='The value of i is %(__expr__)d',style=normal) """) heading2("""$DocAssert(self, cond, format=None)$""") disc("""Raises an $AssertionError$ containing the $format$ string if $cond$ evaluates as $False$.""") eg(""" DocAssert(val, 'val is False') """) heading2("""$DocIf(self, cond, thenBlock, elseBlock=[])$""") disc("""If $cond$ evaluates as $True$, this flowable is replaced by the $thenBlock$ elsethe $elseBlock$.""") eg(""" DocIf('i>3',Paragraph('The value of i is larger than 3',normal),\\ Paragraph('The value of i is not larger than 3',normal)) """) heading2("""$DocWhile(self, cond, whileBlock)$""") disc("""Runs the $whileBlock$ while $cond$ evaluates to $True$. E.g.:""") eg(""" DocAssign('i',5) DocWhile('i',[DocPara('i',format='The value of i is %(__expr__)d',style=normal),DocExec('i-=1')]) """) disc("""This example produces a set of paragraphs of the form:""") eg(""" The value of i is 5 The value of i is 4 The value of i is 3 The value of i is 2 The value of i is 1 """) heading1("""Other Useful $Flowables$""") heading2("""$Preformatted(text, style, bulletText=None, dedent=0, maxLineLength=None, splitChars=None, newLineChars=None)$""") disc(""" Creates a preformatted paragraph which does no wrapping, line splitting or other manipulations. No $XML$ style tags are taken account of in the text. If dedent is non zero $dedent$ common leading spaces will be removed from the front of each line. """) heading3("Defining a maximum line length") disc(""" You can use the property $maxLineLength$ to define a maximum line length. If a line length exceeds this maximum value, the line will be automatically splitted. """) disc(""" The line will be split on any single character defined in $splitChars$. If no value is provided for this property, the line will be split on any of the following standard characters: space, colon, full stop, semi-colon, coma, hyphen, forward slash, back slash, left parenthesis, left square bracket and left curly brace """) disc(""" Characters can be automatically inserted at the beginning of each line that has been created. You can set the property $newLineChars$ to the characters you want to use. """) EmbeddedCode(""" from reportlab.lib.styles import getSampleStyleSheet stylesheet=getSampleStyleSheet() normalStyle = stylesheet['Code'] text=''' class XPreformatted(Paragraph): def __init__(self, text, style, bulletText = None, frags=None, caseSensitive=1): self.caseSensitive = caseSensitive if maximumLineLength and text: text = self.stopLine(text, maximumLineLength, splitCharacters) cleaner = lambda text, dedent=dedent: ''.join(_dedenter(text or '',dedent)) self._setup(text, style, bulletText, frags, cleaner) ''' t=Preformatted(text,normalStyle,maxLineLength=60, newLineChars='> ') """) heading2("""$XPreformatted(text, style, bulletText=None, dedent=0, frags=None)$""") disc(""" This is a non rearranging form of the $Paragraph$ class; XML tags are allowed in $text$ and have the same meanings as for the $Paragraph$ class. As for $Preformatted$, if dedent is non zero $dedent$ common leading spaces will be removed from the front of each line. """) EmbeddedCode(""" from reportlab.lib.styles import getSampleStyleSheet stylesheet=getSampleStyleSheet() normalStyle = stylesheet['Code'] text=''' This is a non rearranging form of the Paragraph class; XML tags are allowed in text and have the same meanings as for the Paragraph class. As for Preformatted, if dedent is non zero dedent common leading spaces will be removed from the front of each line. You can have &amp; style entities as well for & < > and ". ''' t=XPreformatted(text,normalStyle,dedent=3) """) heading2("""$Image(filename, width=None, height=None)$""") disc("""Create a flowable which will contain the image defined by the data in file $filename$ which can be filepath, file like object or an instance of a $reportlab.graphics.shapes.Drawing$. The default PDF image type jpeg is supported and if the PIL extension to Python is installed the other image types can also be handled. If $width$ and or $height$ are specified then they determine the dimension of the displayed image in points. If either dimension is not specified (or specified as $None$) then the corresponding pixel dimension of the image is assumed to be in points and used. """) I="../images/lj8100.jpg" eg(""" Image("lj8100.jpg") """,after=0.1) disc("""will display as""") try: getStory().append(Image(I)) except: disc("""An image should have appeared here.""") disc("""whereas""") eg(""" im = Image("lj8100.jpg", width=2*inch, height=2*inch) im.hAlign = 'CENTER' """, after=0.1) disc('produces') try: im = Image(I, width=2*inch, height=2*inch) im.hAlign = 'CENTER' getStory().append(Image(I, width=2*inch, height=2*inch)) except: disc("""An image should have appeared here.""") heading2("""$Spacer(width, height)$""") disc("""This does exactly as would be expected; it adds a certain amount of space into the story. At present this only works for vertical space. """) CPage(1) heading2("""$PageBreak()$""") disc("""This $Flowable$ represents a page break. It works by effectively consuming all vertical space given to it. This is sufficient for a single $Frame$ document, but would only be a frame break for multiple frames so the $BaseDocTemplate$ mechanism detects $pageBreaks$ internally and handles them specially. """) CPage(1) heading2("""$CondPageBreak(height)$""") disc("""This $Flowable$ attempts to force a $Frame$ break if insufficient vertical space remains in the current $Frame$. It is thus probably wrongly named and should probably be renamed as $CondFrameBreak$. """) CPage(1) heading2("""$KeepTogether(flowables)$""") disc(""" This compound $Flowable$ takes a list of $Flowables$ and attempts to keep them in the same $Frame$. If the total height of the $Flowables$ in the list $flowables$ exceeds the current frame's available space then all the space is used and a frame break is forced. """) CPage(1) heading2("""$TableOfContents()$""") disc(""" A table of contents can be generated by using the $TableOfContents$ flowable. The following steps are needed to add a table of contents to your document: """) disc("""Create an instance of $TableOfContents$. Override the level styles (optional) and add the object to the story:""") eg(""" toc = TableOfContents() PS = ParagraphStyle toc.levelStyles = [ PS(fontName='Times-Bold', fontSize=14, name='TOCHeading1', leftIndent=20, firstLineIndent=-20, spaceBefore=5, leading=16), PS(fontSize=12, name='TOCHeading2', leftIndent=40, firstLineIndent=-20, spaceBefore=0, leading=12), PS(fontSize=10, name='TOCHeading3', leftIndent=60, firstLineIndent=-20, spaceBefore=0, leading=12), PS(fontSize=10, name='TOCHeading4', leftIndent=100, firstLineIndent=-20, spaceBefore=0, leading=12), ] story.append(toc) """) disc("""Entries to the table of contents can be done either manually by calling the $addEntry$ method on the $TableOfContents$ object or automatically by sending a $'TOCEntry'$ notification in the $afterFlowable$ method of the $DocTemplate$ you are using. The data to be passed to $notify$ is a list of three or four items countaining a level number, the entry text, the page number and an optional destination key which the entry should point to. This list will usually be created in a document template's method like afterFlowable(), making notification calls using the notify() method with appropriate data like this: """) eg(''' def afterFlowable(self, flowable): """Detect Level 1 and 2 headings, build outline, and track chapter title.""" if isinstance(flowable, Paragraph): txt = flowable.getPlainText() if style == 'Heading1': # ... self.notify('TOCEntry', (0, txt, self.page)) elif style == 'Heading2': # ... key = 'h2-%s' % self.seq.nextf('heading2') self.canv.bookmarkPage(key) self.notify('TOCEntry', (1, txt, self.page, key)) # ... ''') disc("""This way, whenever a paragraph of style $'Heading1'$ or $'Heading2'$ is added to the story, it will appear in the table of contents. $Heading2$ entries will be clickable because a bookmarked key has been supplied. """) disc("""Finally you need to use the $multiBuild$ method of the DocTemplate because tables of contents need several passes to be generated:""") eg(""" doc.multiBuild(story) """) disc("""Below is a simple but working example of a document with a table of contents:""") eg(''' from reportlab.lib.styles import ParagraphStyle as PS from reportlab.platypus import PageBreak from reportlab.platypus.paragraph import Paragraph from reportlab.platypus.doctemplate import PageTemplate, BaseDocTemplate from reportlab.platypus.tableofcontents import TableOfContents from reportlab.platypus.frames import Frame from reportlab.lib.units import cm class MyDocTemplate(BaseDocTemplate): def __init__(self, filename, **kw): self.allowSplitting = 0 BaseDocTemplate.__init__(self, filename, **kw) template = PageTemplate('normal', [Frame(2.5*cm, 2.5*cm, 15*cm, 25*cm, id='F1')]) self.addPageTemplates(template) def afterFlowable(self, flowable): "Registers TOC entries." if flowable.__class__.__name__ == 'Paragraph': text = flowable.getPlainText() style = flowable.style.name if style == 'Heading1': self.notify('TOCEntry', (0, text, self.page)) if style == 'Heading2': self.notify('TOCEntry', (1, text, self.page)) h1 = PS(name = 'Heading1', fontSize = 14, leading = 16) h2 = PS(name = 'Heading2', fontSize = 12, leading = 14, leftIndent = delta) # Build story. story = [] toc = TableOfContents() # For conciseness we use the same styles for headings and TOC entries toc.levelStyles = [h1, h2] story.append(toc) story.append(PageBreak()) story.append(Paragraph('First heading', h1)) story.append(Paragraph('Text in first heading', PS('body'))) story.append(Paragraph('First sub heading', h2)) story.append(Paragraph('Text in first sub heading', PS('body'))) story.append(PageBreak()) story.append(Paragraph('Second sub heading', h2)) story.append(Paragraph('Text in second sub heading', PS('body'))) story.append(Paragraph('Last heading', h1)) doc = MyDocTemplate('mintoc.pdf') doc.multiBuild(story) ''') CPage(1) heading2("""$SimpleIndex()$""") disc(""" An index can be generated by using the $SimpleIndex$ flowable. The following steps are needed to add an index to your document: """) disc("""Use the index tag in paragraphs to index terms:""") eg(''' story = [] ... story.append('The third word of this paragraph is indexed.') ''') disc("""Create an instance of $SimpleIndex$ and add it to the story where you want it to appear:""") eg(''' index = SimpleIndex(dot=' . ', headers=headers) story.append(index) ''') disc("""The parameters which you can pass into the SimpleIndex constructor are explained in the reportlab reference. Now, build the document by using the canvas maker returned by SimpleIndex.getCanvasMaker():""") eg(""" doc.build(story, canvasmaker=index.getCanvasMaker()) """) disc("""To build an index with multiple levels, pass a comma-separated list of items to the item attribute of an index tag:""") eg(""" """) disc("""terma will respresent the top-most level and termc the most specific term. termd and termb will appear in the same level inside terma.""") disc("""If you need to index a term containing a comma, you will need to escape it by doubling it. To avoid the ambiguity of three consecutive commas (an escaped comma followed by a list separator or a list separator followed by an escaped comma?) introduce a space in the right position. Spaces at the beginning or end of terms will be removed.""") eg(""" """) disc(""" This indexes the terms "comma (,)", "," and "...". """) heading2("""$ListFlowable(),ListItem()$""") disc(""" Use these classes to make ordered and unordered lists. Lists can be nested. """) disc(""" $ListFlowable()$ will create an ordered list, which can contain any flowable. The class has a number of parameters to change font, colour, size, style and position of list numbers, or of bullets in unordered lists. The type of numbering can also be set to use lower or upper case letters ('A,B,C' etc.) or Roman numerals (capitals or lowercase) using the bulletType property. To change the list to an unordered type, set bulletType='bullet'. """) disc(""" Items within a $ListFlowable()$ list can be changed from their default appearance by wrapping them in a $ListItem()$ class and setting its properties. """) disc(""" The following will create an ordered list, and set the third item to an unordered sublist. """) EmbeddedCode(""" from reportlab.platypus import ListFlowable, ListItem from reportlab.lib.styles import getSampleStyleSheet styles = getSampleStyleSheet() style = styles["Normal"] t = ListFlowable( [ Paragraph("Item no.1", style), ListItem(Paragraph("Item no. 2", style),bulletColor="green",value=7), ListFlowable( [ Paragraph("sublist item 1", style), ListItem(Paragraph('sublist item 2', style),bulletColor='red',value='square') ], bulletType='bullet', start='square', ), Paragraph("Item no.4", style), ], bulletType='i' ) """) disc("""To cope with nesting the $start$ parameter can be set to a list of possible starts; for $ul$ acceptable starts are any unicode character or specific names known to flowables.py eg $bulletchar$, $circle$, $square$, $disc$, $diamond$, $diamondwx$, $rarrowhead$, $sparkle$, $squarelrs$ or $blackstar$. For $ol$ the $start$ can be any character from $'1iaAI'$ to indicate different number styles. """) heading2("""$BalancedColumns()$""") disc("""Use the $BalancedColumns$ class to make a flowable that splits its content flowables into two or more roughly equal sized columns. Effectively $n$ frames are synthesized to take the content and the flowable tries to balance the content between them. The created frames will be split when the total height is too large and the split will maintain the balance. """) eg(""" from reportlab.platypus.flowables import BalancedColumns from reportlab.platypus.frames import ShowBoundaryValue F = [ list of flowables........ ] story.append( Balanced( F, #the flowables we are balancing nCols = 2, #the number of columns needed = 72,#the minimum space needed by the flowable spacBefore = 0, spaceAfter = 0, showBoundary = None, #optional boundary showing leftPadding=None, #these override the created frame rightPadding=None, #paddings if specified else the topPadding=None, #default frame paddings bottomPadding=None, #are used innerPadding=None, #the gap between frames if specified else #use max(leftPadding,rightPadding) name='', #for identification purposes when stuff goes awry endSlack=0.1, #height disparity allowance ie 10% of available height ) ) """) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1691062243.0 reportlab-4.1.0/docs/userguide/ch7_custom.py0000664000175000017500000000512314462707743020472 0ustar00rptlabrptlab#Copyright ReportLab Europe Ltd. 2000-2017 #see license.txt for license details #history https://hg.reportlab.com/hg-public/reportlab/log/tip/docs/userguide/ch7_custom.py from tools.docco.rl_doc_utils import * heading1("Writing your own $Flowable$ Objects") disc(""" Flowables are intended to be an open standard for creating reusable report content, and you can easily create your own objects. We hope that over time we will build up a library of contributions, giving reportlab users a rich selection of charts, graphics and other "report widgets" they can use in their own reports. This section shows you how to create your own flowables.""") todo("""we should put the Figure class in the standard library, as it is a very useful base.""") heading2("A very simple $Flowable$") disc(""" Recall the $hand$ function from the $pdfgen$ section of this user guide which generated a drawing of a hand as a closed figure composed from Bezier curves. """) illust(examples.hand, "a hand") disc(""" To embed this or any other drawing in a Platypus flowable we must define a subclass of $Flowable$ with at least a $wrap$ method and a $draw$ method. """) eg(examples.testhandannotation) disc(""" The $wrap$ method must provide the size of the drawing -- it is used by the Platypus mainloop to decide whether this element fits in the space remaining on the current frame. The $draw$ method performs the drawing of the object after the Platypus mainloop has translated the $(0,0)$ origin to an appropriate location in an appropriate frame. """) disc(""" Below are some example uses of the $HandAnnotation$ flowable. """) from reportlab.lib.colors import blue, pink, yellow, cyan, brown from reportlab.lib.units import inch handnote() disc("""The default.""") handnote(size=inch) disc("""Just one inch high.""") handnote(xoffset=3*inch, size=inch, strokecolor=blue, fillcolor=cyan) disc("""One inch high and shifted to the left with blue and cyan.""") heading2("Modifying a Built in $Flowable$") disc("""To modify an existing flowable, you should create a derived class and override the methods you need to change to get the desired behaviour""") disc("""As an example to create a rotated image you need to override the wrap and draw methods of the existing Image class""") import os from reportlab.platypus import * I = '../images/replogo.gif' EmbeddedCode(""" class RotatedImage(Image): def wrap(self,availWidth,availHeight): h, w = Image.wrap(self,availHeight,availWidth) return w, h def draw(self): self.canv.rotate(90) Image.draw(self) I = RotatedImage('%s') I.hAlign = 'CENTER' """ % I,'I') ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1691062243.0 reportlab-4.1.0/docs/userguide/genuserguide.py0000664000175000017500000000676714462707743021124 0ustar00rptlabrptlab#!/bin/env python #Copyright ReportLab Europe Ltd. 2000-2017 #see license.txt for license details #history https://hg.reportlab.com/hg-public/reportlab/log/tip/docs/userguide/genuserguide.py __version__='3.3.0' __doc__ = """ This module contains the script for building the user guide. """ def run(pagesize=None, verbose=0, outDir=None): import sys,os from reportlab.lib.utils import open_and_read cwd = os.getcwd() docsDir=os.path.dirname(os.path.dirname(sys.argv[0]) or cwd) topDir=os.path.dirname(docsDir) if not outDir: outDir=docsDir G = {} sys.path.insert(0,topDir) from reportlab.pdfbase.pdfmetrics import registerFontFamily from reportlab.pdfbase import pdfmetrics from reportlab.pdfbase.ttfonts import TTFont pdfmetrics.registerFont(TTFont('Vera', 'Vera.ttf')) pdfmetrics.registerFont(TTFont('VeraBd', 'VeraBd.ttf')) pdfmetrics.registerFont(TTFont('VeraIt', 'VeraIt.ttf')) pdfmetrics.registerFont(TTFont('VeraBI', 'VeraBI.ttf')) registerFontFamily('Vera',normal='Vera',bold='VeraBd',italic='VeraIt',boldItalic='VeraBI') from reportlab.rl_config import defaultPageSize from tools.docco.rl_doc_utils import setStory, getStory, H1, H2, H3, H4 from tools.docco.rltemplate import RLDocTemplate from tools.docco import rl_doc_utils exec('from tools.docco.rl_doc_utils import *', G, G) destfn = os.path.join(outDir,'reportlab-userguide.pdf') doc = RLDocTemplate(destfn,pagesize = pagesize or defaultPageSize) #this builds the story setStory() for f in ( 'ch1_intro', 'ch2_graphics', 'ch2a_fonts', 'ch3_pdffeatures', 'ch4_platypus_concepts', 'ch5_paragraphs', 'ch6_tables', 'ch7_custom', 'graph_intro', 'graph_concepts', 'graph_charts', 'graph_shapes', 'graph_widgets', 'app_demos', ): #python source is supposed to be utf8 these days exec(open_and_read(f+'.py', mode='r'), G, G) del G story = getStory() if verbose: print('Built story contains %d flowables...' % len(story)) doc.multiBuild(story) if verbose: print('Saved "%s"' % destfn) def makeSuite(): "standard test harness support - run self as separate process" from tests.utils import ScriptThatMakesFileTest return ScriptThatMakesFileTest('../docs/userguide', 'genuserguide.py', 'reportlab-userguide.pdf') def main(): import sys outDir = [x for x in sys.argv if x[:9]=='--outdir='] if outDir: outDir = outDir[0] sys.argv.remove(outDir) outDir = outDir[9:] else: outDir = None verbose = '-s' not in sys.argv if not verbose: sys.argv.remove('-s') timing = '-timing' in sys.argv if timing: sys.argv.remove('-timing') prof = '-prof' in sys.argv if prof: sys.argv.remove('-prof') if len(sys.argv) > 1: try: pagesize = (w,h) = eval(sys.argv[1]) except: print('Expected page size in argument 1', sys.argv[1]) raise if verbose: print('set page size to',sys.argv[1]) else: pagesize = None if timing: from time import time t0 = time() run(pagesize, verbose,outDir) if verbose: print('Generation of userguide took %.2f seconds' % (time()-t0)) elif prof: import profile profile.run('run(pagesize,verbose,outDir)','genuserguide.stats') else: run(pagesize, verbose,outDir) if __name__=="__main__": main() ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1691062243.0 reportlab-4.1.0/docs/userguide/graph_charts.py0000664000175000017500000014704114462707743021072 0ustar00rptlabrptlab#Copyright ReportLab Europe Ltd. 2000-2017 #see license.txt for license details __version__='3.3.0' from tools.docco.rl_doc_utils import * from reportlab.graphics.shapes import * heading2("Charts") disc(""" The motivation for much of this is to create a flexible chart package. This section presents a treatment of the ideas behind our charting model, what the design goals are and what components of the chart package already exist. """) heading3("Design Goals") disc("Here are some of the design goals: ") disc("Make simple top-level use really simple ") disc("""It should be possible to create a simple chart with minimum lines of code, yet have it 'do the right things' with sensible automatic settings. The pie chart snippets above do this. If a real chart has many subcomponents, you still should not need to interact with them unless you want to customize what they do.""") disc("Allow precise positioning ") disc("""An absolute requirement in publishing and graphic design is to control the placing and style of every element. We will try to have properties that specify things in fixed sizes and proportions of the drawing, rather than having automatic resizing. Thus, the 'inner plot rectangle' will not magically change when you make the font size of the y labels bigger, even if this means your labels can spill out of the left edge of the chart rectangle. It is your job to preview the chart and choose sizes and spaces which will work.""") disc("""Some things do need to be automatic. For example, if you want to fit N bars into a 200 point space and don't know N in advance, we specify bar separation as a percentage of the width of a bar rather than a point size, and let the chart work it out. This is still deterministic and controllable.""") disc("Control child elements individually or as a group") disc("""We use smart collection classes that let you customize a group of things, or just one of them. For example you can do this in our experimental pie chart:""") eg(""" d = Drawing(400,200) pc = Pie() pc.x = 150 pc.y = 50 pc.data = [10,20,30,40,50,60] pc.labels = ['a','b','c','d','e','f'] pc.slices.strokeWidth=0.5 pc.slices[3].popout = 20 pc.slices[3].strokeWidth = 2 pc.slices[3].strokeDashArray = [2,2] pc.slices[3].labelRadius = 1.75 pc.slices[3].fontColor = colors.red d.add(pc, '') """) disc("""pc.slices[3] actually lazily creates a little object which holds information about the slice in question; this will be used to format a fourth slice at draw-time if there is one.""") disc("Only expose things you should change ") disc("""It would be wrong from a statistical viewpoint to let you directly adjust the angle of one of the pie slices in the above example, since that is determined by the data. So not everything will be exposed through the public properties. There may be 'back doors' to let you violate this when you really need to, or methods to provide advanced functionality, but in general properties will be orthogonal.""") disc("Composition and component based ") disc("""Charts are built out of reusable child widgets. A Legend is an easy-to-grasp example. If you need a specialized type of legend (e.g. circular colour swatches), you should subclass the standard Legend widget. Then you could either do something like...""") eg(""" c = MyChartWithLegend() c.legend = MyNewLegendClass() # just change it c.legend.swatchRadius = 5 # set a property only relevant to the new one c.data = [10,20,30] # and then configure as usual... """) disc("""...or create/modify your own chart or drawing class which creates one of these by default. This is also very relevant for time series charts, where there can be many styles of x axis.""") disc("""Top level chart classes will create a number of such components, and then either call methods or set private properties to tell them their height and position - all the stuff which should be done for you and which you cannot customise. We are working on modelling what the components should be and will publish their APIs here as a consensus emerges.""") disc("Multiples ") disc("""A corollary of the component approach is that you can create diagrams with multiple charts, or custom data graphics. Our favourite example of what we are aiming for is the weather report in our gallery contributed by a user; we'd like to make it easy to create such drawings, hook the building blocks up to their legends, and feed that data in a consistent way.""") disc("""(If you want to see the image, it is available on our website
here)""") ##heading3("Key Concepts and Components") heading3("Overview") disc("""A chart or plot is an object which is placed on a drawing; it is not itself a drawing. You can thus control where it goes, put several on the same drawing, or add annotations.""") disc("""Charts have two axes; axes may be Value or Category axes. Axes in turn have a Labels property which lets you configure all text labels or each one individually. Most of the configuration details which vary from chart to chart relate to axis properties, or axis labels.""") disc("""Objects expose properties through the interfaces discussed in the previous section; these are all optional and are there to let the end user configure the appearance. Things which must be set for a chart to work, and essential communication between a chart and its components, are handled through methods.""") disc("""You can subclass any chart component and use your replacement instead of the original provided you implement the essential methods and properties.""") heading2("Labels") disc(""" A label is a string of text attached to some chart element. They are used on axes, for titles or alongside axes, or attached to individual data points. Labels may contain newline characters, but only one font. """) disc("""The text and 'origin' of a label are typically set by its parent object. They are accessed by methods rather than properties. Thus, the X axis decides the 'reference point' for each tickmark label and the numeric or date text for each label. However, the end user can set properties of the label (or collection of labels) directly to affect its position relative to this origin and all of its formatting.""") eg(""" from reportlab.graphics import shapes from reportlab.graphics.charts.textlabels import Label d = Drawing(200, 100) # mark the origin of the label d.add(Circle(100,90, 5, fillColor=colors.green)) lab = Label() lab.setOrigin(100,90) lab.boxAnchor = 'ne' lab.angle = 45 lab.dx = 0 lab.dy = -20 lab.boxStrokeColor = colors.green lab.setText('Some\nMulti-Line\nLabel') d.add(lab) """) from reportlab.graphics import shapes from reportlab.graphics.charts.textlabels import Label d = Drawing(200, 100) # mark the origin of the label d.add(Circle(100,90, 5, fillColor=colors.green)) lab = Label() lab.setOrigin(100,90) lab.boxAnchor = 'ne' lab.angle = 45 lab.dx = 0 lab.dy = -20 lab.boxStrokeColor = colors.green lab.setText('Some\nMulti-Line\nLabel') d.add(lab) draw(d, 'Label example') disc(""" In the drawing above, the label is defined relative to the green blob. The text box should have its north-east corner ten points down from the origin, and be rotated by 45 degrees about that corner. """) disc(""" At present labels have the following properties, which we believe are sufficient for all charts we have seen to date: """) disc("") data=[["Property", "Meaning"], ["dx", """The label's x displacement."""], ["dy", """The label's y displacement."""], ["angle", """The angle of rotation (counterclockwise) applied to the label."""], ["boxAnchor", "The label's box anchor, one of 'n', 'e', 'w', 's', 'ne', 'nw', 'se', 'sw'."], ["textAnchor", """The place where to anchor the label's text, one of 'start', 'middle', 'end'."""], ["boxFillColor", """The fill color used in the label's box."""], ["boxStrokeColor", "The stroke color used in the label's box."], ["boxStrokeWidth", """The line width of the label's box."""], ["fontName", """The label's font name."""], ["fontSize", """The label's font size."""], ["leading", """The leading value of the label's text lines."""], ["x", """The X-coordinate of the reference point."""], ["y", """The Y-coordinate of the reference point."""], ["width", """The label's width."""], ["height", """The label's height."""] ] t=Table(data, colWidths=(100,330)) t.setStyle(TableStyle([ ('FONT',(0,0),(-1,0),'Times-Bold',10,12), ('FONT',(0,1),(0,-1),'Courier',8,8), ('FONT',(1,1),(1,-1),'Times-Roman',10,12), ('VALIGN',(0,0),(-1,-1),'MIDDLE'), ('INNERGRID', (0,0), (-1,-1), 0.25, colors.black), ('BOX', (0,0), (-1,-1), 0.25, colors.black), ])) getStory().append(t) caption("""Table - Label properties""") disc(""" To see many more examples of $Label$ objects with different combinations of properties, please have a look into the ReportLab test suite in the folder $tests$, run the script $test_charts_textlabels.py$ and look at the PDF document it generates! """) heading2("Axes") disc(""" We identify two basic kinds of axes - Value and Category ones. Both come in horizontal and vertical flavors. Both can be subclassed to make very specific kinds of axis. For example, if you have complex rules for which dates to display in a time series application, or want irregular scaling, you override the axis and make a new one. """) disc(""" Axes are responsible for determining the mapping from data to image coordinates; transforming points on request from the chart; drawing themselves and their tickmarks, gridlines and axis labels. """) disc(""" This drawing shows two axes, one of each kind, which have been created directly without reference to any chart: """) from reportlab.graphics import shapes from reportlab.graphics.charts.axes import XCategoryAxis,YValueAxis drawing = Drawing(400, 200) data = [(10, 20, 30, 40), (15, 22, 37, 42)] xAxis = XCategoryAxis() xAxis.setPosition(75, 75, 300) xAxis.configure(data) xAxis.categoryNames = ['Beer', 'Wine', 'Meat', 'Cannelloni'] xAxis.labels.boxAnchor = 'n' xAxis.labels[3].dy = -15 xAxis.labels[3].angle = 30 xAxis.labels[3].fontName = 'Times-Bold' yAxis = YValueAxis() yAxis.setPosition(50, 50, 125) yAxis.configure(data) drawing.add(xAxis) drawing.add(yAxis) draw(drawing, 'Two isolated axes') disc("Here is the code that created them: ") eg(""" from reportlab.graphics import shapes from reportlab.graphics.charts.axes import XCategoryAxis,YValueAxis drawing = Drawing(400, 200) data = [(10, 20, 30, 40), (15, 22, 37, 42)] xAxis = XCategoryAxis() xAxis.setPosition(75, 75, 300) xAxis.configure(data) xAxis.categoryNames = ['Beer', 'Wine', 'Meat', 'Cannelloni'] xAxis.labels.boxAnchor = 'n' xAxis.labels[3].dy = -15 xAxis.labels[3].angle = 30 xAxis.labels[3].fontName = 'Times-Bold' yAxis = YValueAxis() yAxis.setPosition(50, 50, 125) yAxis.configure(data) drawing.add(xAxis) drawing.add(yAxis) """) disc(""" Remember that, usually, you won't have to create axes directly; when using a standard chart, it comes with ready-made axes. The methods are what the chart uses to configure it and take care of the geometry. However, we will talk through them in detail below. The orthogonally dual axes to those we describe have essentially the same properties, except for those refering to ticks. """) heading3("XCategoryAxis class") disc(""" A Category Axis doesn't really have a scale; it just divides itself into equal-sized buckets. It is simpler than a value axis. The chart (or programmer) sets its location with the method $setPosition(x, y, length)$. The next stage is to show it the data so that it can configure itself. This is easy for a category axis - it just counts the number of data points in one of the data series. The $reversed$ attribute (if 1) indicates that the categories should be reversed. When the drawing is drawn, the axis can provide some help to the chart with its $scale()$ method, which tells the chart where a given category begins and ends on the page. We have not yet seen any need to let people override the widths or positions of categories. """) disc("An XCategoryAxis has the following editable properties:") disc("") data=[["Property", "Meaning"], ["visible", """Should the axis be drawn at all? Sometimes you don't want to display one or both axes, but they still need to be there as they manage the scaling of points."""], ["strokeColor", "Color of the axis"], ["strokeDashArray", """Whether to draw axis with a dash and, if so, what kind. Defaults to None"""], ["strokeWidth", "Width of axis in points"], ["tickUp", """How far above the axis should the tick marks protrude? (Note that making this equal to chart height gives you a gridline)"""], ["tickDown", """How far below the axis should the tick mark protrude?"""], ["categoryNames", """Either None, or a list of strings. This should have the same length as each data series."""], ["labels", """A collection of labels for the tick marks. By default the 'north' of each text label (i.e top centre) is positioned 5 points down from the centre of each category on the axis. You may redefine any property of the whole label group or of any one label. If categoryNames=None, no labels are drawn."""], ["title", """Not Implemented Yet. This needs to be like a label, but also lets you set the text directly. It would have a default location below the axis."""]] t=Table(data, colWidths=(100,330)) t.setStyle(TableStyle([ ('FONT',(0,0),(-1,0),'Times-Bold',10,12), ('FONT',(0,1),(0,-1),'Courier',8,8), ('FONT',(1,1),(1,-1),'Times-Roman',10,12), ('VALIGN',(0,0),(-1,-1),'MIDDLE'), ('INNERGRID', (0,0), (-1,-1), 0.25, colors.black), ('BOX', (0,0), (-1,-1), 0.25, colors.black), ])) getStory().append(t) caption("""Table - XCategoryAxis properties""") heading3("YValueAxis") disc(""" The left axis in the diagram is a YValueAxis. A Value Axis differs from a Category Axis in that each point along its length corresponds to a y value in chart space. It is the job of the axis to configure itself, and to convert Y values from chart space to points on demand to assist the parent chart in plotting. """) disc(""" $setPosition(x, y, length)$ and $configure(data)$ work exactly as for a category axis. If you have not fully specified the maximum, minimum and tick interval, then $configure()$ results in the axis choosing suitable values. Once configured, the value axis can convert y data values to drawing space with the $scale()$ method. Thus: """) eg(""" >>> yAxis = YValueAxis() >>> yAxis.setPosition(50, 50, 125) >>> data = [(10, 20, 30, 40),(15, 22, 37, 42)] >>> yAxis.configure(data) >>> yAxis.scale(10) # should be bottom of chart 50.0 >>> yAxis.scale(40) # should be near the top 167.1875 >>> """) disc("""By default, the highest data point is aligned with the top of the axis, the lowest with the bottom of the axis, and the axis choose 'nice round numbers' for its tickmark points. You may override these settings with the properties below. """) disc("") data=[["Property", "Meaning"], ["visible", """Should the axis be drawn at all? Sometimes you don't want to display one or both axes, but they still need to be there as they manage the scaling of points."""], ["strokeColor", "Color of the axis"], ["strokeDashArray", """Whether to draw axis with a dash and, if so, what kind. Defaults to None"""], ["strokeWidth", "Width of axis in points"], ["tickLeft", """How far to the left of the axis should the tick marks protrude? (Note that making this equal to chart height gives you a gridline)"""], ["tickRight", """How far to the right of the axis should the tick mark protrude?"""], ["valueMin", """The y value to which the bottom of the axis should correspond. Default value is None in which case the axis sets it to the lowest actual data point (e.g. 10 in the example above). It is common to set this to zero to avoid misleading the eye."""], ["valueMax", """The y value to which the top of the axis should correspond. Default value is None in which case the axis sets it to the highest actual data point (e.g. 42 in the example above). It is common to set this to a 'round number' so data bars do not quite reach the top."""], ["valueStep", """The y change between tick intervals. By default this is None, and the chart tries to pick 'nice round numbers' which are just wider than the minimumTickSpacing below."""], ["valueSteps", """A list of numbers at which to place ticks."""], ["minimumTickSpacing", """This is used when valueStep is set to None, and ignored otherwise. The designer specified that tick marks should be no closer than X points apart (based, presumably, on considerations of the label font size and angle). The chart tries values of the type 1,2,5,10,20,50,100... (going down below 1 if necessary) until it finds an interval which is greater than the desired spacing, and uses this for the step."""], ["labelTextFormat", """This determines what goes in the labels. Unlike a category axis which accepts fixed strings, the labels on a ValueAxis are supposed to be numbers. You may provide either a 'format string' like '%0.2f' (show two decimal places), or an arbitrary function which accepts a number and returns a string. One use for the latter is to convert a timestamp to a readable year-month-day format."""], ["title", """Not Implemented Yet. This needs to be like a label, but also lets you set the text directly. It would have a default location below the axis."""]] t=Table(data, colWidths=(100,330)) t.setStyle(TableStyle([ ('FONT',(0,0),(-1,0),'Times-Bold',10,12), ('FONT',(0,1),(0,-1),'Courier',8,8), ('FONT',(1,1),(1,-1),'Times-Roman',10,12), ('VALIGN',(0,0),(-1,-1),'MIDDLE'), ('INNERGRID', (0,0), (-1,-1), 0.25, colors.black), ('BOX', (0,0), (-1,-1), 0.25, colors.black), ])) getStory().append(t) caption("""Table - YValueAxis properties""") disc(""" The $valueSteps$ property lets you explicitly specify the tick mark locations, so you don't have to follow regular intervals. Hence, you can plot month ends and month end dates with a couple of helper functions, and without needing special time series chart classes. The following code show how to create a simple $XValueAxis$ with special tick intervals. Make sure to set the $valueSteps$ attribute before calling the configure method! """) eg(""" from reportlab.graphics.shapes import Drawing from reportlab.graphics.charts.axes import XValueAxis drawing = Drawing(400, 100) data = [(10, 20, 30, 40)] xAxis = XValueAxis() xAxis.setPosition(75, 50, 300) xAxis.valueSteps = [10, 15, 20, 30, 35, 40] xAxis.configure(data) xAxis.labels.boxAnchor = 'n' drawing.add(xAxis) """) from reportlab.graphics import shapes from reportlab.graphics.charts.axes import XValueAxis drawing = Drawing(400, 100) data = [(10, 20, 30, 40)] xAxis = XValueAxis() xAxis.setPosition(75, 50, 300) xAxis.valueSteps = [10, 15, 20, 30, 35, 40] xAxis.configure(data) xAxis.labels.boxAnchor = 'n' drawing.add(xAxis) draw(drawing, 'An axis with non-equidistant tick marks') disc(""" In addition to these properties, all axes classes have three properties describing how to join two of them to each other. Again, this is interesting only if you define your own charts or want to modify the appearance of an existing chart using such axes. These properties are listed here only very briefly for now, but you can find a host of sample functions in the module $reportlab/graphics/axes.py$ which you can examine... """) disc(""" One axis is joined to another, by calling the method $joinToAxis(otherAxis, mode, pos)$ on the first axis, with $mode$ and $pos$ being the properties described by $joinAxisMode$ and $joinAxisPos$, respectively. $'points'$ means to use an absolute value, and $'value'$ to use a relative value (both indicated by the the $joinAxisPos$ property) along the axis. """) disc("") data=[["Property", "Meaning"], ["joinAxis", """Join both axes if true."""], ["joinAxisMode", """Mode used for connecting axis ('bottom', 'top', 'left', 'right', 'value', 'points', None)."""], ["joinAxisPos", """Position at which to join with other axis."""], ] t=Table(data, colWidths=(100,330)) t.setStyle(TableStyle([ ('FONT',(0,0),(-1,0),'Times-Bold',10,12), ('FONT',(0,1),(0,-1),'Courier',8,8), ('FONT',(1,1),(1,-1),'Times-Roman',10,12), ('VALIGN',(0,0),(-1,-1),'MIDDLE'), ('INNERGRID', (0,0), (-1,-1), 0.25, colors.black), ('BOX', (0,0), (-1,-1), 0.25, colors.black), ])) getStory().append(t) caption("""Table - Axes joining properties""") heading2("Bar Charts") disc(""" This describes our current $VerticalBarChart$ class, which uses the axes and labels above. We think it is step in the right direction but is is far from final. Note that people we speak to are divided about 50/50 on whether to call this a 'Vertical' or 'Horizontal' bar chart. We chose this name because 'Vertical' appears next to 'Bar', so we take it to mean that the bars rather than the category axis are vertical. """) disc(""" As usual, we will start with an example: """) from reportlab.graphics.shapes import Drawing from reportlab.graphics.charts.barcharts import VerticalBarChart drawing = Drawing(400, 200) data = [ (13, 5, 20, 22, 37, 45, 19, 4), (14, 6, 21, 23, 38, 46, 20, 5) ] bc = VerticalBarChart() bc.x = 50 bc.y = 50 bc.height = 125 bc.width = 300 bc.data = data bc.strokeColor = colors.black bc.valueAxis.valueMin = 0 bc.valueAxis.valueMax = 50 bc.valueAxis.valueStep = 10 bc.categoryAxis.labels.boxAnchor = 'ne' bc.categoryAxis.labels.dx = 8 bc.categoryAxis.labels.dy = -2 bc.categoryAxis.labels.angle = 30 bc.categoryAxis.categoryNames = ['Jan-99','Feb-99','Mar-99', 'Apr-99','May-99','Jun-99','Jul-99','Aug-99'] drawing.add(bc) draw(drawing, 'Simple bar chart with two data series') eg(""" # code to produce the above chart from reportlab.graphics.shapes import Drawing from reportlab.graphics.charts.barcharts import VerticalBarChart drawing = Drawing(400, 200) data = [ (13, 5, 20, 22, 37, 45, 19, 4), (14, 6, 21, 23, 38, 46, 20, 5) ] bc = VerticalBarChart() bc.x = 50 bc.y = 50 bc.height = 125 bc.width = 300 bc.data = data bc.strokeColor = colors.black bc.valueAxis.valueMin = 0 bc.valueAxis.valueMax = 50 bc.valueAxis.valueStep = 10 bc.categoryAxis.labels.boxAnchor = 'ne' bc.categoryAxis.labels.dx = 8 bc.categoryAxis.labels.dy = -2 bc.categoryAxis.labels.angle = 30 bc.categoryAxis.categoryNames = ['Jan-99','Feb-99','Mar-99', 'Apr-99','May-99','Jun-99','Jul-99','Aug-99'] drawing.add(bc) """) disc(""" Most of this code is concerned with setting up the axes and labels, which we have already covered. Here are the top-level properties of the $VerticalBarChart$ class: """) disc("") data=[["Property", "Meaning"], ["data", """This should be a "list of lists of numbers" or "list of tuples of numbers". If you have just one series, write it as data = [(10,20,30,42),]"""], ["x, y, width, height", """These define the inner 'plot rectangle'. We highlighted this with a yellow border above. Note that it is your job to place the chart on the drawing in a way which leaves room for all the axis labels and tickmarks. We specify this 'inner rectangle' because it makes it very easy to lay out multiple charts in a consistent manner."""], ["strokeColor", """Defaults to None. This will draw a border around the plot rectangle, which may be useful in debugging. Axes will overwrite this."""], ["fillColor", """Defaults to None. This will fill the plot rectangle with a solid color. (Note that we could implement dashArray etc. as for any other solid shape)"""], ["useAbsolute", """Defaults to 0. If 1, the three properties below are absolute values in points (which means you can make a chart where the bars stick out from the plot rectangle); if 0, they are relative quantities and indicate the proportional widths of the elements involved."""], ["barWidth", """As it says. Defaults to 10."""], ["groupSpacing", """Defaults to 5. This is the space between each group of bars. If you have only one series, use groupSpacing and not barSpacing to split them up. Half of the groupSpacing is used before the first bar in the chart, and another half at the end."""], ["barSpacing", """Defaults to 0. This is the spacing between bars in each group. If you wanted a little gap between green and red bars in the example above, you would make this non-zero."""], ["barLabelFormat", """Defaults to None. As with the YValueAxis, if you supply a function or format string then labels will be drawn next to each bar showing the numeric value. They are positioned automatically above the bar for positive values and below for negative ones."""], ["barLabels", """A collection of labels used to format all bar labels. Since this is a two-dimensional array, you may explicitly format the third label of the second series using this syntax: chart.barLabels[(1,2)].fontSize = 12"""], ["valueAxis", """The value axis, which may be formatted as described previously."""], ["categoryAxis", """The category axis, which may be formatted as described previously."""], ["title", """Not Implemented Yet. This needs to be like a label, but also lets you set the text directly. It would have a default location below the axis."""]] t=Table(data, colWidths=(100,330)) t.setStyle(TableStyle([ ('FONT',(0,0),(-1,0),'Times-Bold',10,12), ('FONT',(0,1),(0,-1),'Courier',8,8), ('FONT',(1,1),(1,-1),'Times-Roman',10,12), ('VALIGN',(0,0),(-1,-1),'MIDDLE'), ('INNERGRID', (0,0), (-1,-1), 0.25, colors.black), ('BOX', (0,0), (-1,-1), 0.25, colors.black), ])) getStory().append(t) caption("""Table - VerticalBarChart properties""") disc(""" From this table we deduce that adding the following lines to our code above should double the spacing between bar groups (the $groupSpacing$ attribute has a default value of five points) and we should also see some tiny space between bars of the same group ($barSpacing$). """) eg(""" bc.groupSpacing = 10 bc.barSpacing = 2.5 """) disc(""" And, in fact, this is exactly what we can see after adding these lines to the code above. Notice how the width of the individual bars has changed as well. This is because the space added between the bars has to be 'taken' from somewhere as the total chart width stays unchanged. """) from reportlab.graphics.shapes import Drawing from reportlab.graphics.charts.barcharts import VerticalBarChart drawing = Drawing(400, 200) data = [ (13, 5, 20, 22, 37, 45, 19, 4), (14, 6, 21, 23, 38, 46, 20, 5) ] bc = VerticalBarChart() bc.x = 50 bc.y = 50 bc.height = 125 bc.width = 300 bc.data = data bc.strokeColor = colors.black bc.groupSpacing = 10 bc.barSpacing = 2.5 bc.valueAxis.valueMin = 0 bc.valueAxis.valueMax = 50 bc.valueAxis.valueStep = 10 bc.categoryAxis.labels.boxAnchor = 'ne' bc.categoryAxis.labels.dx = 8 bc.categoryAxis.labels.dy = -2 bc.categoryAxis.labels.angle = 30 bc.categoryAxis.categoryNames = ['Jan-99','Feb-99','Mar-99', 'Apr-99','May-99','Jun-99','Jul-99','Aug-99'] drawing.add(bc) draw(drawing, 'Like before, but with modified spacing') disc(""" Bars labels are automatically displayed for negative values below the lower end of the bar for positive values above the upper end of the other ones. """) disc(""" Stacked bars are also supported for vertical bar graphs. You enable this layout for your chart by setting the $style$ attribute to $'stacked'$ on the $categoryAxis$. """) eg(""" bc.categoryAxis.style = 'stacked' """) disc(""" Here is an example of the previous chart values arranged in the stacked style. """) drawing = Drawing(400, 200) data = [ (13, 5, 20, 22, 37, 45, 19, 4), (14, 6, 21, 23, 38, 46, 20, 5) ] bc = VerticalBarChart() bc.x = 50 bc.y = 50 bc.height = 125 bc.width = 300 bc.data = data bc.strokeColor = colors.black bc.groupSpacing = 10 bc.barSpacing = 2.5 bc.valueAxis.valueMin = 0 bc.valueAxis.valueMax = 100 bc.valueAxis.valueStep = 20 bc.categoryAxis.labels.boxAnchor = 'ne' bc.categoryAxis.labels.dx = 8 bc.categoryAxis.labels.dy = -2 bc.categoryAxis.labels.angle = 30 bc.categoryAxis.categoryNames = ['Jan-99','Feb-99','Mar-99', 'Apr-99','May-99','Jun-99','Jul-99','Aug-99'] bc.categoryAxis.style = 'stacked' drawing.add(bc) draw(drawing, 'Stacking bars on top of each other.') ##Property Value ##data This should be a "list of lists of numbers" or "list of tuples of numbers". If you have just one series, write it as ##data = [(10,20,30,42),] ## ##x, y, width, height These define the inner 'plot rectangle'. We highlighted this with a yellow border above. Note that it is your job to place the chart on the drawing in a way which leaves room for all the axis labels and tickmarks. We specify this 'inner rectangle' because it makes it very easy to lay out multiple charts in a consistent manner. ##strokeColor Defaults to None. This will draw a border around the plot rectangle, which may be useful in debugging. Axes will overwrite this. ##fillColor Defaults to None. This will fill the plot rectangle with a solid color. (Note that we could implement dashArray etc. as for any other solid shape) ##barLabelFormat This is a format string or function used for displaying labels above each bar. We're working on ways to position these labels so that they work for positive and negative bars. ##useAbsolute Defaults to 0. If 1, the three properties below are absolute values in points (which means you can make a chart where the bars stick out from the plot rectangle); if 0, they are relative quantities and indicate the proportional widths of the elements involved. ##barWidth As it says. Defaults to 10. ##groupSpacing Defaults to 5. This is the space between each group of bars. If you have only one series, use groupSpacing and not barSpacing to split them up. Half of the groupSpacing is used before the first bar in the chart, and another half at the end. ##barSpacing Defaults to 0. This is the spacing between bars in each group. If you wanted a little gap between green and red bars in the example above, you would make this non-zero. ##barLabelFormat Defaults to None. As with the YValueAxis, if you supply a function or format string then labels will be drawn next to each bar showing the numeric value. ##barLabels A collection of labels used to format all bar labels. Since this is a two-dimensional array, you may explicitly format the third label of the second series using this syntax: ## chart.barLabels[(1,2)].fontSize = 12 ## ##valueAxis The value axis, which may be formatted as described previously ##categoryAxis The categoryAxis, which may be formatted as described previously ##title, subTitle Not implemented yet. These would be label-like objects whose text could be set directly and which would appear in sensible locations. For now, you can just place extra strings on the drawing. heading2("Line Charts") disc(""" We consider "Line Charts" to be essentially the same as "Bar Charts", but with lines instead of bars. Both share the same pair of Category/Value axes pairs. This is in contrast to "Line Plots", where both axes are Value axes. """) disc(""" The following code and its output shall serve as a simple example. More explanation will follow. For the time being you can also study the output of running the tool $reportlab/lib/graphdocpy.py$ withough any arguments and search the generated PDF document for examples of Line Charts. """) eg(""" from reportlab.graphics.charts.linecharts import HorizontalLineChart drawing = Drawing(400, 200) data = [ (13, 5, 20, 22, 37, 45, 19, 4), (5, 20, 46, 38, 23, 21, 6, 14) ] lc = HorizontalLineChart() lc.x = 50 lc.y = 50 lc.height = 125 lc.width = 300 lc.data = data lc.joinedLines = 1 catNames = 'Jan Feb Mar Apr May Jun Jul Aug'.split(' ') lc.categoryAxis.categoryNames = catNames lc.categoryAxis.labels.boxAnchor = 'n' lc.valueAxis.valueMin = 0 lc.valueAxis.valueMax = 60 lc.valueAxis.valueStep = 15 lc.lines[0].strokeWidth = 2 lc.lines[1].strokeWidth = 1.5 drawing.add(lc) """) from reportlab.graphics.charts.linecharts import HorizontalLineChart drawing = Drawing(400, 200) data = [ (13, 5, 20, 22, 37, 45, 19, 4), (5, 20, 46, 38, 23, 21, 6, 14) ] lc = HorizontalLineChart() lc.x = 50 lc.y = 50 lc.height = 125 lc.width = 300 lc.data = data lc.joinedLines = 1 catNames = 'Jan Feb Mar Apr May Jun Jul Aug'.split(' ') lc.categoryAxis.categoryNames = catNames lc.categoryAxis.labels.boxAnchor = 'n' lc.valueAxis.valueMin = 0 lc.valueAxis.valueMax = 60 lc.valueAxis.valueStep = 15 lc.lines[0].strokeWidth = 2 lc.lines[1].strokeWidth = 1.5 drawing.add(lc) draw(drawing, 'HorizontalLineChart sample') disc("") data=[["Property","Meaning"], ["data", "Data to be plotted, list of (lists of) numbers."], ["x, y, width, height", """Bounding box of the line chart. Note that x and y do NOT specify the centre but the bottom left corner"""], ["valueAxis", """The value axis, which may be formatted as described previously."""], ["categoryAxis", """The category axis, which may be formatted as described previously."""], ["strokeColor", """Defaults to None. This will draw a border around the plot rectangle, which may be useful in debugging. Axes will overwrite this."""], ["fillColor", """Defaults to None. This will fill the plot rectangle with a solid color."""], ["lines.strokeColor", """Color of the line."""], ["lines.strokeWidth", """Width of the line."""], ["lineLabels", """A collection of labels used to format all line labels. Since this is a two-dimensional array, you may explicitly format the third label of the second line using this syntax: chart.lineLabels[(1,2)].fontSize = 12"""], ["lineLabelFormat", """Defaults to None. As with the YValueAxis, if you supply a function or format string then labels will be drawn next to each line showing the numeric value. You can also set it to 'values' to display the values explicity defined in lineLabelArray."""], ["lineLabelArray", """Explicit array of line label values, must match size of data if present. These labels values will be displayed only if the property lineLabelFormat above is set to 'values'."""]] t=Table(data, colWidths=(100,330)) t.setStyle(TableStyle([ ('FONT',(0,0),(-1,0),'Times-Bold',10,12), ('FONT',(0,1),(0,-1),'Courier',8,8), ('FONT',(1,1),(1,-1),'Times-Roman',10,12), ('VALIGN',(0,0),(-1,-1),'MIDDLE'), ('INNERGRID', (0,0), (-1,-1), 0.25, colors.black), ('BOX', (0,0), (-1,-1), 0.25, colors.black), ])) getStory().append(t) caption("""Table - HorizontalLineChart properties""") heading2("Line Plots") disc(""" Below we show a more complex example of a Line Plot that also uses some experimental features like line markers placed at each data point. """) eg(""" from reportlab.graphics.charts.lineplots import LinePlot from reportlab.graphics.widgets.markers import makeMarker drawing = Drawing(400, 200) data = [ ((1,1), (2,2), (2.5,1), (3,3), (4,5)), ((1,2), (2,3), (2.5,2), (3.5,5), (4,6)) ] lp = LinePlot() lp.x = 50 lp.y = 50 lp.height = 125 lp.width = 300 lp.data = data lp.joinedLines = 1 lp.lines[0].symbol = makeMarker('FilledCircle') lp.lines[1].symbol = makeMarker('Circle') lp.lineLabelFormat = '%2.0f' lp.strokeColor = colors.black lp.xValueAxis.valueMin = 0 lp.xValueAxis.valueMax = 5 lp.xValueAxis.valueSteps = [1, 2, 2.5, 3, 4, 5] lp.xValueAxis.labelTextFormat = '%2.1f' lp.yValueAxis.valueMin = 0 lp.yValueAxis.valueMax = 7 lp.yValueAxis.valueSteps = [1, 2, 3, 5, 6] drawing.add(lp) """) from reportlab.graphics.charts.lineplots import LinePlot from reportlab.graphics.widgets.markers import makeMarker drawing = Drawing(400, 200) data = [ ((1,1), (2,2), (2.5,1), (3,3), (4,5)), ((1,2), (2,3), (2.5,2), (3.5,5), (4,6)) ] lp = LinePlot() lp.x = 50 lp.y = 50 lp.height = 125 lp.width = 300 lp.data = data lp.joinedLines = 1 lp.lines[0].symbol = makeMarker('FilledCircle') lp.lines[1].symbol = makeMarker('Circle') lp.lineLabelFormat = '%2.0f' lp.strokeColor = colors.black lp.xValueAxis.valueMin = 0 lp.xValueAxis.valueMax = 5 lp.xValueAxis.valueSteps = [1, 2, 2.5, 3, 4, 5] lp.xValueAxis.labelTextFormat = '%2.1f' lp.yValueAxis.valueMin = 0 lp.yValueAxis.valueMax = 7 lp.yValueAxis.valueSteps = [1, 2, 3, 5, 6] drawing.add(lp) draw(drawing, 'LinePlot sample') disc("") data=[["Property","Meaning"], ["data", "Data to be plotted, list of (lists of) numbers."], ["x, y, width, height", """Bounding box of the line chart. Note that x and y do NOT specify the centre but the bottom left corner"""], ["xValueAxis", """The vertical value axis, which may be formatted as described previously."""], ["yValueAxis", """The horizontal value axis, which may be formatted as described previously."""], ["strokeColor", """Defaults to None. This will draw a border around the plot rectangle, which may be useful in debugging. Axes will overwrite this."""], ["strokeWidth", """Defaults to None. Width of the border around the plot rectangle."""], ["fillColor", """Defaults to None. This will fill the plot rectangle with a solid color."""], ["lines.strokeColor", """Color of the line."""], ["lines.strokeWidth", """Width of the line."""], ["lines.symbol", """Marker used for each point. You can create a new marker using the function makeMarker(). For example to use a circle, the function call would be makeMarker('Circle')"""], ["lineLabels", """A collection of labels used to format all line labels. Since this is a two-dimensional array, you may explicitly format the third label of the second line using this syntax: chart.lineLabels[(1,2)].fontSize = 12"""], ["lineLabelFormat", """Defaults to None. As with the YValueAxis, if you supply a function or format string then labels will be drawn next to each line showing the numeric value. You can also set it to 'values' to display the values explicity defined in lineLabelArray."""], ["lineLabelArray", """Explicit array of line label values, must match size of data if present. These labels values will be displayed only if the property lineLabelFormat above is set to 'values'."""]] t=Table(data, colWidths=(100,330)) t.setStyle(TableStyle([ ('FONT',(0,0),(-1,0),'Times-Bold',10,12), ('FONT',(0,1),(0,-1),'Courier',8,8), ('FONT',(1,1),(1,-1),'Times-Roman',10,12), ('VALIGN',(0,0),(-1,-1),'MIDDLE'), ('INNERGRID', (0,0), (-1,-1), 0.25, colors.black), ('BOX', (0,0), (-1,-1), 0.25, colors.black), ])) getStory().append(t) caption("""Table - LinePlot properties""") heading2("Pie Charts") disc(""" As usual, we will start with an example: """) eg(""" from reportlab.graphics.charts.piecharts import Pie d = Drawing(200, 100) pc = Pie() pc.x = 65 pc.y = 15 pc.width = 70 pc.height = 70 pc.data = [10,20,30,40,50,60] pc.labels = ['a','b','c','d','e','f'] pc.slices.strokeWidth=0.5 pc.slices[3].popout = 10 pc.slices[3].strokeWidth = 2 pc.slices[3].strokeDashArray = [2,2] pc.slices[3].labelRadius = 1.75 pc.slices[3].fontColor = colors.red d.add(pc) """) from reportlab.graphics.charts.piecharts import Pie d = Drawing(400, 200) pc = Pie() pc.x = 125 pc.y = 25 pc.width = 150 pc.height = 150 pc.data = [10,20,30,40,50,60] pc.labels = ['a','b','c','d','e','f'] pc.slices.strokeWidth=0.5 pc.slices[3].popout = 10 pc.slices[3].strokeWidth = 2 pc.slices[3].strokeDashArray = [2,2] pc.slices[3].labelRadius = 1.25 pc.slices[3].fontColor = colors.red d.add(pc) draw(d, 'A bare bones pie chart') disc(""" Properties are covered below. The pie has a 'slices' collection and we document wedge properties in the same table. """) disc("") data=[["Property", "Meaning"], ["data", "A list or tuple of numbers"], ["x, y, width, height", """Bounding box of the pie. Note that x and y do NOT specify the centre but the bottom left corner, and that width and height do not have to be equal; pies may be elliptical and slices will be drawn correctly."""], ["labels", """None, or a list of strings. Make it None if you don't want labels around the edge of the pie. Since it is impossible to know the size of slices, we generally discourage placing labels in or around pies; it is much better to put them in a legend alongside."""], ["startAngle", """Where is the start angle of the first pie slice? The default is '90' which is twelve o'clock."""], ["direction", """Which direction do slices progress in? The default is 'clockwise'."""], ["sideLabels", """This creates a chart with the labels in two columns, one on either side."""], ["sideLabelsOffset", """This is a fraction of the width of the pie that defines the horizontal distance between the pie and the columns of labels."""], ["simpleLabels", """Default is 1. Set to 0 to enable the use of customizable labels and of properties prefixed by label_ in the collection slices."""], ["slices", """Collection of slices. This lets you customise each wedge, or individual ones. See below"""], ["slices.strokeWidth", "Border width for wedge"], ["slices.strokeColor", "Border color"], ["slices.strokeDashArray", "Solid or dashed line configuration"], ["slices.popout", """How far out should the slice(s) stick from the centre of the pie? Default is zero."""], ["slices.fontName", "Name of the label font"], ["slices.fontSize", "Size of the label font"], ["slices.fontColor", "Color of the label text"], ["slices.labelRadius", """This controls the anchor point for a text label. It is a fraction of the radius; 0.7 will place the text inside the pie, 1.2 will place it slightly outside. (note that if we add labels, we will keep this to specify their anchor point)"""]] t=Table(data, colWidths=(130,300)) t.setStyle(TableStyle([ ('FONT',(0,0),(-1,0),'Times-Bold',10,12), ('FONT',(0,1),(0,-1),'Courier',8,8), ('FONT',(1,1),(1,-1),'Times-Roman',10,12), ('VALIGN',(0,0),(-1,-1),'MIDDLE'), ('INNERGRID', (0,0), (-1,-1), 0.25, colors.black), ('BOX', (0,0), (-1,-1), 0.25, colors.black), ])) getStory().append(t) caption("""Table - Pie properties""") heading3("Customizing Labels") disc(""" Each slide label can be customized individually by changing the properties prefixed by $label_$ in the collection $slices$. For example $pc.slices[2].label_angle = 10$ changes the angle of the third label. """) disc(""" Before being able to use these customization properties, you need to disable simple labels with: $pc.simplesLabels = 0$ """) disc("") data=[["Property", "Meaning"], ["label_dx", """X Offset of the label"""], ["label_dy", """Y Offset of the label"""], ["label_angle", """Angle of the label, default (0) is horizontal, 90 is vertical, 180 is upside down"""], ["label_boxAnchor", """Anchoring point of the label"""], ["label_boxStrokeColor", """Border color for the label box"""], ["label_boxStrokeWidth", """Border width for the label box"""], ["label_boxFillColor", """Filling color of the label box"""], ["label_strokeColor", """Border color for the label text"""], ["label_strokeWidth", """Border width for the label text"""], ["label_text", """Text of the label"""], ["label_width", """Width of the label"""], ["label_maxWidth", """Maximum width the label can grow to"""], ["label_height", """Height of the label"""], ["label_textAnchor", """Maximum height the label can grow to"""], ["label_visible", """True if the label is to be drawn"""], ["label_topPadding", """Padding at top of box"""], ["label_leftPadding", """Padding at left of box"""], ["label_rightPadding", """Padding at right of box"""], ["label_bottomPadding", """Padding at bottom of box"""], ["label_simple_pointer", """Set to 1 for simple pointers"""], ["label_pointer_strokeColor", """Color of indicator line"""], ["label_pointer_strokeWidth", """Width of indicator line"""]] t=Table(data, colWidths=(130,300)) t.setStyle(TableStyle([ ('FONT',(0,0),(-1,0),'Times-Bold',10,12), ('FONT',(0,1),(0,-1),'Courier',8,8), ('FONT',(1,1),(1,-1),'Times-Roman',10,12), ('VALIGN',(0,0),(-1,-1),'MIDDLE'), ('INNERGRID', (0,0), (-1,-1), 0.25, colors.black), ('BOX', (0,0), (-1,-1), 0.25, colors.black), ])) getStory().append(t) caption("""Table - Pie.slices label customization properties""") heading3("Side Labels") disc(""" If the sideLabels attribute is set to true, then the labels of the slices are placed in two columns, one on either side of the pie and the start angle of the pie will be set automatically. The anchor of the right hand column is set to 'start' and the anchor of the left hand column is set to 'end'. The distance from the edge of the pie from the edge of either column is decided by the sideLabelsOffset attribute, which is a fraction of the width of the pie. If xradius is changed, the pie can overlap the labels, and so we advise leaving xradius as None. There is an example below. """) from reportlab.graphics.charts.piecharts import sample5, sample7, sample8 drawing5 = sample5() draw(drawing5, 'An example of a piechart with sideLabels =1') disc(""" If you have sideLabels set to True, then some of the attributes become redundant, such as pointerLabelMode. Also sideLabelsOffset only changes the piechart if sideLabels is set to true. """) heading4("Some issues") disc(""" The pointers can cross if there are too many slices. """) drawing7 = sample7() draw(drawing7, 'An example of pointers crossing') disc(""" Also the labels can overlap despite checkLabelOverlap if they correspond to slices that are not adjacent. """) drawing8 = sample8() draw(drawing8, 'An example of labels overlapping') heading2("Legends") disc(""" Various preliminary legend classes can be found but need a cleanup to be consistent with the rest of the charting model. Legends are the natural place to specify the colors and line styles of charts; we propose that each chart is created with a $legend$ attribute which is invisible. One would then do the following to specify colors: """) eg(""" myChart.legend.defaultColors = [red, green, blue] """) disc(""" One could also define a group of charts sharing the same legend: """) eg(""" myLegend = Legend() myLegend.defaultColor = [red, green.....] #yuck! myLegend.columns = 2 # etc. chart1.legend = myLegend chart2.legend = myLegend chart3.legend = myLegend """) # Hack to force a new paragraph before the todo() :-( disc("") todo("""Does this work? Is it an acceptable complication over specifying chart colors directly?""") heading3("Remaining Issues") disc(""" There are several issues that are almost solved, but for which is is a bit too early to start making them really public. Nevertheless, here is a list of things that are under way: """) bullet(""" Color specification - right now the chart has an undocumented property $defaultColors$, which provides a list of colors to cycle through, such that each data series gets its own color. Right now, if you introduce a legend, you need to make sure it shares the same list of colors. Most likely, this will be replaced with a scheme to specify a kind of legend containing attributes with different values for each data series. This legend can then also be shared by several charts, but need not be visible itself. """) bullet(""" Additional chart types - when the current design will have become more stable, we expect to add variants of bar charts to deal with percentile bars as well as the side-by-side variant seen here. """) heading3("Outlook") disc(""" It will take some time to deal with the full range of chart types. We expect to finalize bars and pies first and to produce trial implementations of more general plots, thereafter. """) heading3("X-Y Plots") disc(""" Most other plots involve two value axes and directly plotting x-y data in some form. The series can be plotted as lines, marker symbols, both, or custom graphics such as open-high-low-close graphics. All share the concepts of scaling and axis/title formatting. At a certain point, a routine will loop over the data series and 'do something' with the data points at given x-y locations. Given a basic line plot, it should be very easy to derive a custom chart type just by overriding a single method - say, $drawSeries()$. """) heading3("Marker customisation and custom shapes") disc(""" Well known plotting packages such as excel, Mathematica and Excel offer ranges of marker types to add to charts. We can do better - you can write any kind of chart widget you want and just tell the chart to use it as an example. """) heading4("Combination plots") disc(""" Combining multiple plot types is really easy. You can just draw several charts (bar, line or whatever) in the same rectangle, suppressing axes as needed. So a chart could correlate a line with Scottish typhoid cases over a 15 year period on the left axis with a set of bars showing inflation rates on the right axis. If anyone can remind us where this example came from we'll attribute it, and happily show the well-known graph as an example. """) heading3("Interactive editors") disc(""" One principle of the Graphics package is to make all 'interesting' properties of its graphic components accessible and changeable by setting apropriate values of corresponding public attributes. This makes it very tempting to build a tool like a GUI editor that that helps you with doing that interactively. """) disc(""" ReportLab has built such a tool using the Tkinter toolkit that loads pure Python code describing a drawing and records your property editing operations. This "change history" is then used to create code for a subclass of that chart, say, that can be saved and used instantly just like any other chart or as a new starting point for another interactive editing session. """) disc(""" This is still work in progress, though, and the conditions for releasing this need to be further elaborated. """) heading3("Misc.") disc(""" This has not been an exhaustive look at all the chart classes. Those classes are constantly being worked on. To see exactly what is in the current distribution, use the $graphdocpy.py$ utility. By default, it will run on reportlab/graphics, and produce a full report. (If you want to run it on other modules or packages, $graphdocpy.py -h$ prints a help message that will tell you how.) """) disc(""" This is the tool that was mentioned in the section on 'Documenting Widgets'. """) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1691062243.0 reportlab-4.1.0/docs/userguide/graph_concepts.py0000664000175000017500000002701414462707743021421 0ustar00rptlabrptlab#Copyright ReportLab Europe Ltd. 2000-2017 #see license.txt for license details __version__='3.3.0' from tools.docco.rl_doc_utils import * heading2("General Concepts") disc(""" In this section we will present some of the more fundamental principles of the graphics library, which will show-up later in various places. """) heading3("Drawings and Renderers") disc(""" A Drawing is a platform-independent description of a collection of shapes. It is not directly associated with PDF, Postscript or any other output format. Fortunately, most vector graphics systems have followed the Postscript model and it is possible to describe shapes unambiguously. """) disc(""" A drawing contains a number of primitive Shapes. Normal shapes are those widely known as rectangles, circles, lines, etc. One special (logic) shape is a Group, which can hold other shapes and apply a transformation to them. Groups represent composites of shapes and allow to treat the composite as if it were a single shape. Just about anything can be built up from a small number of basic shapes. """) disc(""" The package provides several Renderers which know how to draw a drawing into different formats. These include PDF (renderPDF), Postscript (renderPS), and bitmap output (renderPM). The bitmap renderer uses Raph Levien's libart rasterizer and Fredrik Lundh's Python Imaging Library (PIL). The SVG renderer makes use of Python's standard library XML modules, so you don't need to install the XML-SIG's additional package named PyXML. If you have the right extensions installed, you can generate drawings in bitmap form for the web as well as vector form for PDF documents, and get "identical output". """) disc(""" The PDF renderer has special "privileges" - a Drawing object is also a Flowable and, hence, can be placed directly in the story of any Platypus document, or drawn directly on a Canvas with one line of code. In addition, the PDF renderer has a utility function to make a one-page PDF document quickly. """) disc(""" The SVG renderer is special as it is still pretty experimental. The SVG code it generates is not really optimised in any way and maps only the features available in ReportLab Graphics (RLG) to SVG. This means there is no support for SVG animation, interactivity, scripting or more sophisticated clipping, masking or graduation shapes. So, be careful, and please report any bugs you find! """) heading3("Coordinate System") disc(""" The Y-direction in our X-Y coordinate system points from the bottom up. This is consistent with PDF, Postscript and mathematical notation. It also appears to be more natural for people, especially when working with charts. Note that in other graphics models (such as SVG) the Y-coordinate points down. For the SVG renderer this is actually no problem as it will take your drawings and flip things as needed, so your SVG output looks just as expected. """) disc(""" The X-coordinate points, as usual, from left to right. So far there doesn't seem to be any model advocating the opposite direction - at least not yet (with interesting exceptions, as it seems, for Arabs looking at time series charts...). """) heading3("Getting Started") disc(""" Let's create a simple drawing containing the string "Hello World" and some special characters, displayed on top of a coloured rectangle. After creating it we will save the drawing to a standalone PDF file. """) eg(""" from reportlab.lib import colors from reportlab.graphics.shapes import * d = Drawing(400, 200) d.add(Rect(50, 50, 300, 100, fillColor=colors.yellow)) d.add(String(150,100, 'Hello World', fontSize=18, fillColor=colors.red)) d.add(String(180,86, 'Special characters \\ \\xc2\\xa2\\xc2\\xa9\\xc2\\xae\\xc2\\xa3\\xce\\xb1\\xce\\xb2', fillColor=colors.red)) from reportlab.graphics import renderPDF renderPDF.drawToFile(d, 'example1.pdf', 'My First Drawing') """) disc("This will produce a PDF file containing the following graphic:") from reportlab.graphics.shapes import * from reportlab.graphics import testshapes t = testshapes.getDrawing01() draw(t, "'Hello World'") disc(""" Each renderer is allowed to do whatever is appropriate for its format, and may have whatever API is needed. If it refers to a file format, it usually has a $drawToFile$ function, and that's all you need to know about the renderer. Let's save the same drawing in Encapsulated Postscript format: """) ##eg(""" ## from reportlab.graphics import renderPS ## renderPS.drawToFile(D, 'example1.eps', 'My First Drawing') ##""") eg(""" from reportlab.graphics import renderPS renderPS.drawToFile(d, 'example1.eps') """) disc(""" This will produce an EPS file with the identical drawing, which may be imported into publishing tools such as Quark Express. If we wanted to generate the same drawing as a bitmap file for a website, say, all we need to do is write code like this: """) eg(""" from reportlab.graphics import renderPM renderPM.drawToFile(d, 'example1.png', 'PNG') """) disc(""" Many other bitmap formats, like GIF, JPG, TIFF, BMP and PPN are genuinely available, making it unlikely you'll need to add external postprocessing steps to convert to the final format you need. """) disc(""" To produce an SVG file containing the identical drawing, which may be imported into graphical editing tools such as Illustrator all we need to do is write code like this: """) eg(""" from reportlab.graphics import renderSVG renderSVG.drawToFile(d, 'example1.svg') """) heading3("Attribute Verification") disc(""" Python is very dynamic and lets us execute statements at run time that can easily be the source for unexpected behaviour. One subtle 'error' is when assigning to an attribute that the framework doesn't know about because the used attribute's name contains a typo. Python lets you get away with it (adding a new attribute to an object, say), but the graphics framework will not detect this 'typo' without taking special counter-measures. """) disc(""" There are two verification techniques to avoid this situation. The default is for every object to check every assignment at run time, such that you can only assign to 'legal' attributes. This is what happens by default. As this imposes a small performance penalty, this behaviour can be turned off when you need it to be. """) eg(""" >>> r = Rect(10,10,200,100, fillColor=colors.red) >>> >>> r.fullColor = colors.green # note the typo >>> r.x = 'not a number' # illegal argument type >>> del r.width # that should confuse it """) disc(""" These statements would be caught by the compiler in a statically typed language, but Python lets you get away with it. The first error could leave you staring at the picture trying to figure out why the colors were wrong. The second error would probably become clear only later, when some back-end tries to draw the rectangle. The third, though less likely, results in an invalid object that would not know how to draw itself. """) eg(""" >>> r = shapes.Rect(10,10,200,80) >>> r.fullColor = colors.green Traceback (most recent call last): File "", line 1, in ? File "C:\\code\\users\\andy\\graphics\\shapes.py", line 254, in __setattr__ validateSetattr(self,attr,value) #from reportlab.lib.attrmap File "C:\\code\\users\\andy\\lib\\attrmap.py", line 74, in validateSetattr raise AttributeError, "Illegal attribute '%s' in class %s" % (name, obj.__class__.__name__) AttributeError: Illegal attribute 'fullColor' in class Rect >>> """) disc(""" This imposes a performance penalty, so this behaviour can be turned off when you need it to be. To do this, you should use the following lines of code before you first import reportlab.graphics.shapes: """) eg(""" >>> import reportlab.rl_config >>> reportlab.rl_config.shapeChecking = 0 >>> from reportlab.graphics import shapes >>> """) disc(""" Once you turn off $shapeChecking$, the classes are actually built without the verification hook; code should get faster, then. Currently the penalty seems to be about 25% on batches of charts, so it is hardly worth disabling. However, if we move the renderers to C in future (which is eminently possible), the remaining 75% would shrink to almost nothing and the saving from verification would be significant. """) disc(""" Each object, including the drawing itself, has a $verify()$ method. This either succeeds, or raises an exception. If you turn off automatic verification, then you should explicitly call $verify()$ in testing when developing the code, or perhaps once in a batch process. """) heading3("Property Editing") disc(""" A cornerstone of the reportlab/graphics which we will cover below is that you can automatically document widgets. This means getting hold of all of their editable properties, including those of their subcomponents. """) disc(""" Another goal is to be able to create GUIs and config files for drawings. A generic GUI can be built to show all editable properties of a drawing, and let you modify them and see the results. The Visual Basic or Delphi development environment are good examples of this kind of thing. In a batch charting application, a file could list all the properties of all the components in a chart, and be merged with a database query to make a batch of charts. """) disc(""" To support these applications we have two interfaces, $getProperties$ and $setProperties$, as well as a convenience method $dumpProperties$. The first returns a dictionary of the editable properties of an object; the second sets them en masse. If an object has publicly exposed 'children' then one can recursively set and get their properties too. This will make much more sense when we look at Widgets later on, but we need to put the support into the base of the framework. """) eg(""" >>> r = shapes.Rect(0,0,200,100) >>> import pprint >>> pprint.pprint(r.getProperties()) {'fillColor': Color(0.00,0.00,0.00), 'height': 100, 'rx': 0, 'ry': 0, 'strokeColor': Color(0.00,0.00,0.00), 'strokeDashArray': None, 'strokeLineCap': 0, 'strokeLineJoin': 0, 'strokeMiterLimit': 0, 'strokeWidth': 1, 'width': 200, 'x': 0, 'y': 0} >>> r.setProperties({'x':20, 'y':30, 'strokeColor': colors.red}) >>> r.dumpProperties() fillColor = Color(0.00,0.00,0.00) height = 100 rx = 0 ry = 0 strokeColor = Color(1.00,0.00,0.00) strokeDashArray = None strokeLineCap = 0 strokeLineJoin = 0 strokeMiterLimit = 0 strokeWidth = 1 width = 200 x = 20 y = 30 >>> """) disc(""" Note: $pprint$ is the standard Python library module that allows you to 'pretty print' output over multiple lines rather than having one very long line. """) disc(""" These three methods don't seem to do much here, but as we will see they make our widgets framework much more powerful when dealing with non-primitive objects. """) heading3("Naming Children") disc(""" You can add objects to the $Drawing$ and $Group$ objects. These normally go into a list of contents. However, you may also give objects a name when adding them. This allows you to refer to and possibly change any element of a drawing after constructing it. """) eg(""" >>> d = shapes.Drawing(400, 200) >>> s = shapes.String(10, 10, 'Hello World') >>> d.add(s, 'caption') >>> s.caption.text 'Hello World' >>> """) disc(""" Note that you can use the same shape instance in several contexts in a drawing; if you choose to use the same $Circle$ object in many locations (e.g. a scatter plot) and use different names to access it, it will still be a shared object and the changes will be global. """) disc(""" This provides one paradigm for creating and modifying interactive drawings. """) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1691062243.0 reportlab-4.1.0/docs/userguide/graph_intro.py0000664000175000017500000000075214462707743020736 0ustar00rptlabrptlab#Copyright ReportLab Europe Ltd. 2000-2017 #see license.txt for license details __version__='3.3.0' from tools.docco.rl_doc_utils import * heading1("Graphics") heading2("Introduction") disc(""" ReportLab Graphics is one of the sub-packages to the ReportLab library. It started off as a stand-alone set of programs, but is now a fully integrated part of the ReportLab toolkit that allows you to use its powerful charting and graphics features to improve your PDF forms and reports. """) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1691062243.0 reportlab-4.1.0/docs/userguide/graph_shapes.py0000664000175000017500000003016314462707743021065 0ustar00rptlabrptlab#Copyright ReportLab Europe Ltd. 2000-2017 #see license.txt for license details __version__='3.3.0' from tools.docco.rl_doc_utils import * from reportlab.graphics.shapes import * heading2("Shapes") disc(""" This section describes the concept of shapes and their importance as building blocks for all output generated by the graphics library. Some properties of existing shapes and their relationship to diagrams are presented and the notion of having different renderers for different output formats is briefly introduced. """) heading3("Available Shapes") disc(""" Drawings are made up of Shapes. Absolutely anything can be built up by combining the same set of primitive shapes. The module $shapes.py$ supplies a number of primitive shapes and constructs which can be added to a drawing. They are: """) bullet("Rect") bullet("Circle") bullet("Ellipse") bullet("Wedge (a pie slice)") bullet("Polygon") bullet("Line") bullet("PolyLine") bullet("String") bullet("Group") bullet("Path (not implemented yet, but will be added in the future)") disc(""" The following drawing, taken from our test suite, shows most of the basic shapes (except for groups). Those with a filled green surface are also called solid shapes (these are $Rect$, $Circle$, $Ellipse$, $Wedge$ and $Polygon$). """) from reportlab.graphics import testshapes t = testshapes.getDrawing06() draw(t, "Basic shapes") heading3("Shape Properties") disc(""" Shapes have two kinds of properties - some to define their geometry and some to define their style. Let's create a red rectangle with 3-point thick green borders: """) eg(""" >>> from reportlab.graphics.shapes import Rect >>> from reportlab.lib.colors import red, green >>> r = Rect(5, 5, 200, 100) >>> r.fillColor = red >>> r.strokeColor = green >>> r.strokeWidth = 3 >>> """) from reportlab.graphics.shapes import Rect from reportlab.lib.colors import red, green d = Drawing(220, 120) r = Rect(5, 5, 200, 100) r.fillColor = red r.strokeColor = green r.strokeWidth = 3 d.add(r) draw(d, "red rectangle with green border") disc(""" Note: In future examples we will omit the import statements. """) disc(""" All shapes have a number of properties which can be set. At an interactive prompt, we can use their dumpProperties() method to list these. Here's what you can use to configure a Rect: """) eg(""" >>> r.dumpProperties() fillColor = Color(1.00,0.00,0.00) height = 100 rx = 0 ry = 0 strokeColor = Color(0.00,0.50,0.00) strokeDashArray = None strokeLineCap = 0 strokeLineJoin = 0 strokeMiterLimit = 0 strokeWidth = 3 width = 200 x = 5 y = 5 >>> """) disc(""" Shapes generally have style properties and geometry properties. $x$, $y$, $width$ and $height$ are part of the geometry and must be provided when creating the rectangle, since it does not make much sense without those properties. The others are optional and come with sensible defaults. """) disc(""" You may set other properties on subsequent lines, or by passing them as optional arguments to the constructor. We could also have created our rectangle this way: """) eg(""" >>> r = Rect(5, 5, 200, 100, fillColor=red, strokeColor=green, strokeWidth=3) """) disc(""" Let's run through the style properties. $fillColor$ is obvious. $stroke$ is publishing terminology for the edge of a shape; the stroke has a color, width, possibly a dash pattern, and some (rarely used) features for what happens when a line turns a corner. $rx$ and $ry$ are optional geometric properties and are used to define the corner radius for a rounded rectangle. """) disc("All the other solid shapes share the same style properties.") heading3("Lines") disc(""" We provide single straight lines, PolyLines and curves. Lines have all the $stroke*$ properties, but no $fillColor$. Here are a few Line and PolyLine examples and the corresponding graphics output: """) eg(""" Line(50,50, 300,100, strokeColor=colors.blue, strokeWidth=5) Line(50,100, 300,50, strokeColor=colors.red, strokeWidth=10, strokeDashArray=[10, 20]) PolyLine([120,110, 130,150, 140,110, 150,150, 160,110, 170,150, 180,110, 190,150, 200,110], strokeWidth=2, strokeColor=colors.purple) """) d = Drawing(400, 200) d.add(Line(50,50, 300,100,strokeColor=colors.blue, strokeWidth=5)) d.add(Line(50,100, 300,50, strokeColor=colors.red, strokeWidth=10, strokeDashArray=[10, 20])) d.add(PolyLine([120,110, 130,150, 140,110, 150,150, 160,110, 170,150, 180,110, 190,150, 200,110], strokeWidth=2, strokeColor=colors.purple)) draw(d, "Line and PolyLine examples") heading3("Strings") disc(""" The ReportLab Graphics package is not designed for fancy text layout, but it can place strings at desired locations and with left/right/center alignment. Let's specify a $String$ object and look at its properties: """) eg(""" >>> s = String(10, 50, 'Hello World') >>> s.dumpProperties() fillColor = Color(0.00,0.00,0.00) fontName = Times-Roman fontSize = 10 text = Hello World textAnchor = start x = 10 y = 50 >>> """) disc(""" Strings have a textAnchor property, which may have one of the values 'start', 'middle', 'end'. If this is set to 'start', x and y relate to the start of the string, and so on. This provides an easy way to align text. """) disc(""" Strings use a common font standard: the Type 1 Postscript fonts present in Acrobat Reader. We can thus use the basic 14 fonts in ReportLab and get accurate metrics for them. We have recently also added support for extra Type 1 fonts and the renderers all know how to render Type 1 fonts. """) ##Until now we have worked with bitmap renderers which have to use ##TrueType fonts and which make some substitutions; this could lead ##to differences in text wrapping or even the number of labels on ##a chart between renderers. disc(""" Here is a more fancy example using the code snippet below. Please consult the ReportLab User Guide to see how non-standard like 'DarkGardenMK' fonts are being registered! """) eg(""" d = Drawing(400, 200) for size in range(12, 36, 4): d.add(String(10+size*2, 10+size*2, 'Hello World', fontName='Times-Roman', fontSize=size)) d.add(String(130, 120, 'Hello World', fontName='Courier', fontSize=36)) d.add(String(150, 160, 'Hello World', fontName='DarkGardenMK', fontSize=36)) """) from reportlab.pdfbase import pdfmetrics from reportlab import rl_config rl_config.warnOnMissingFontGlyphs = 0 afmFile, pfbFile = getJustFontPaths() T1face = pdfmetrics.EmbeddedType1Face(afmFile, pfbFile) T1faceName = 'DarkGardenMK' pdfmetrics.registerTypeFace(T1face) T1font = pdfmetrics.Font(T1faceName, T1faceName, 'WinAnsiEncoding') pdfmetrics.registerFont(T1font) d = Drawing(400, 200) for size in range(12, 36, 4): d.add(String(10+size*2, 10+size*2, 'Hello World', fontName='Times-Roman', fontSize=size)) d.add(String(130, 120, 'Hello World', fontName='Courier', fontSize=36)) d.add(String(150, 160, 'Hello World', fontName='DarkGardenMK', fontSize=36)) draw(d, 'fancy font example') heading3("""Paths""") disc(""" Postscript paths are a widely understood concept in graphics. They are not implemented in $reportlab/graphics$ as yet, but they will be, soon. """) # NB This commented out section is for 'future compatibility' - paths haven't # been implemented yet, but when they are we can uncomment this back in. ##disc("""Postscript paths are a widely understood concept in graphics. A Path ## is a way of defining a region in space. You put an imaginary pen down, ## draw straight and curved segments, and even pick the pen up and move ## it. At the end of this you have described a region, which may consist ## of several distinct close shapes or unclosed lines. At the end, this ## 'path' is 'stroked and filled' according to its properties. A Path has ## the same style properties as a solid shape. It can be used to create ## any irregular shape.""") ## ##disc("""In Postscript-based imaging models such as PDF, Postscript and SVG, ## everything is done with paths. All the specific shapes covered above ## are instances of paths; even text strings (which are shapes in which ## each character is an outline to be filled). Here we begin creating a ## path with a straight line and a bezier curve:""") ## ##eg(""" ##>>> P = Path(0,0, strokeWidth=3, strokeColor=red) ##>>> P.lineTo(0, 50) ##>>> P.curveTo(10,50,80,80,100,30) ##>>> ##""") ##disc("""As well as being the only way to draw complex shapes, paths offer some ## performance advantages in renderers which support them. If you want to ## create a scatter plot with 5000 blue circles of different sizes, you ## can create 5000 circles, or one path object. With the latter, you only ## need to set the color and line width once. PINGO just remembers the ## drawing sequence, and writes it out into the file. In renderers which ## do not support paths, the renderer will still have to decompose it ## into 5000 circles so you won't save anything.""") ## ##disc("""Note that our current path implementation is an approximation; it ## should be finished off accurately for PDF and PS.""") heading3("Groups") disc(""" Finally, we have Group objects. A group has a list of contents, which are other nodes. It can also apply a transformation - its contents can be rotated, scaled or shifted. If you know the math, you can set the transform directly. Otherwise it provides methods to rotate, scale and so on. Here we make a group which is rotated and translated: """) eg(""" >>> g =Group(shape1, shape2, shape3) >>> g.rotate(30) >>> g.translate(50, 200) """) disc(""" Groups provide a tool for reuse. You can make a bunch of shapes to represent some component - say, a coordinate system - and put them in one group called "Axis". You can then put that group into other groups, each with a different translation and rotation, and you get a bunch of axis. It is still the same group, being drawn in different places. """) disc("""Let's do this with some only slightly more code:""") eg(""" d = Drawing(400, 200) Axis = Group( Line(0,0,100,0), # x axis Line(0,0,0,50), # y axis Line(0,10,10,10), # ticks on y axis Line(0,20,10,20), Line(0,30,10,30), Line(0,40,10,40), Line(10,0,10,10), # ticks on x axis Line(20,0,20,10), Line(30,0,30,10), Line(40,0,40,10), Line(50,0,50,10), Line(60,0,60,10), Line(70,0,70,10), Line(80,0,80,10), Line(90,0,90,10), String(20, 35, 'Axes', fill=colors.black) ) firstAxisGroup = Group(Axis) firstAxisGroup.translate(10,10) d.add(firstAxisGroup) secondAxisGroup = Group(Axis) secondAxisGroup.translate(150,10) secondAxisGroup.rotate(15) d.add(secondAxisGroup) thirdAxisGroup = Group(Axis, transform=mmult(translate(300,10), rotate(30))) d.add(thirdAxisGroup) """) d = Drawing(400, 200) Axis = Group( Line(0,0,100,0), # x axis Line(0,0,0,50), # y axis Line(0,10,10,10), # ticks on y axis Line(0,20,10,20), Line(0,30,10,30), Line(0,40,10,40), Line(10,0,10,10), # ticks on x axis Line(20,0,20,10), Line(30,0,30,10), Line(40,0,40,10), Line(50,0,50,10), Line(60,0,60,10), Line(70,0,70,10), Line(80,0,80,10), Line(90,0,90,10), String(20, 35, 'Axes', fill=colors.black) ) firstAxisGroup = Group(Axis) firstAxisGroup.translate(10,10) d.add(firstAxisGroup) secondAxisGroup = Group(Axis) secondAxisGroup.translate(150,10) secondAxisGroup.rotate(15) d.add(secondAxisGroup) thirdAxisGroup = Group(Axis, transform=mmult(translate(300,10), rotate(30))) d.add(thirdAxisGroup) draw(d, "Groups examples") ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1691062243.0 reportlab-4.1.0/docs/userguide/graph_widgets.py0000664000175000017500000003232214462707743021247 0ustar00rptlabrptlab#Copyright ReportLab Europe Ltd. 2000-2017 #see license.txt for license details __version__='3.3.0' from tools.docco.rl_doc_utils import * from reportlab.graphics.shapes import * from reportlab.graphics.widgets import signsandsymbols heading2("Widgets") disc(""" We now describe widgets and how they relate to shapes. Using many examples it is shown how widgets make reusable graphics components. """) heading3("Shapes vs. Widgets") disc("""Up until now, Drawings have been 'pure data'. There is no code in them to actually do anything, except assist the programmer in checking and inspecting the drawing. In fact, that's the cornerstone of the whole concept and is what lets us achieve portability - a renderer only needs to implement the primitive shapes.""") disc("""We want to build reusable graphic objects, including a powerful chart library. To do this we need to reuse more tangible things than rectangles and circles. We should be able to write objects for other to reuse - arrows, gears, text boxes, UML diagram nodes, even fully fledged charts.""") disc(""" The Widget standard is a standard built on top of the shapes module. Anyone can write new widgets, and we can build up libraries of them. Widgets support the $getProperties()$ and $setProperties()$ methods, so you can inspect and modify as well as document them in a uniform way. """) bullet("A widget is a reusable shape ") bullet("""it can be initialized with no arguments when its $draw()$ method is called it creates a primitive Shape or a Group to represent itself""") bullet("""It can have any parameters you want, and they can drive the way it is drawn""") bullet("""it has a $demo()$ method which should return an attractively drawn example of itself in a 200x100 rectangle. This is the cornerstone of the automatic documentation tools. The $demo()$ method should also have a well written docstring, since that is printed too!""") disc("""Widgets run contrary to the idea that a drawing is just a bundle of shapes; surely they have their own code? The way they work is that a widget can convert itself to a group of primitive shapes. If some of its components are themselves widgets, they will get converted too. This happens automatically during rendering; the renderer will not see your chart widget, but just a collection of rectangles, lines and strings. You can also explicitly 'flatten out' a drawing, causing all widgets to be converted to primitives.""") heading3("Using a Widget") disc(""" Let's imagine a simple new widget. We will use a widget to draw a face, then show how it was implemented.""") eg(""" >>> from reportlab.lib import colors >>> from reportlab.graphics import shapes >>> from reportlab.graphics import widgetbase >>> from reportlab.graphics import renderPDF >>> d = shapes.Drawing(200, 100) >>> f = widgetbase.Face() >>> f.skinColor = colors.yellow >>> f.mood = "sad" >>> d.add(f) >>> renderPDF.drawToFile(d, 'face.pdf', 'A Face') """) from reportlab.graphics import widgetbase d = Drawing(200, 120) f = widgetbase.Face() f.x = 50 f.y = 10 f.skinColor = colors.yellow f.mood = "sad" d.add(f) draw(d, 'A sample widget') disc(""" Let's see what properties it has available, using the $setProperties()$ method we have seen earlier: """) eg(""" >>> f.dumpProperties() eyeColor = Color(0.00,0.00,1.00) mood = sad size = 80 skinColor = Color(1.00,1.00,0.00) x = 10 y = 10 >>> """) disc(""" One thing which seems strange about the above code is that we did not set the size or position when we made the face. This is a necessary trade-off to allow a uniform interface for constructing widgets and documenting them - they cannot require arguments in their $__init__()$ method. Instead, they are generally designed to fit in a 200 x 100 window, and you move or resize them by setting properties such as x, y, width and so on after creation. """) disc(""" In addition, a widget always provides a $demo()$ method. Simple ones like this always do something sensible before setting properties, but more complex ones like a chart would not have any data to plot. The documentation tool calls $demo()$ so that your fancy new chart class can create a drawing showing what it can do. """) disc(""" Here are a handful of simple widgets available in the module signsandsymbols.py: """) from reportlab.graphics.shapes import Drawing from reportlab.graphics.widgets import signsandsymbols d = Drawing(230, 230) ne = signsandsymbols.NoEntry() ds = signsandsymbols.DangerSign() fd = signsandsymbols.FloppyDisk() ns = signsandsymbols.NoSmoking() ne.x, ne.y = 10, 10 ds.x, ds.y = 120, 10 fd.x, fd.y = 10, 120 ns.x, ns.y = 120, 120 d.add(ne) d.add(ds) d.add(fd) d.add(ns) draw(d, 'A few samples from signsandsymbols.py') disc(""" And this is the code needed to generate them as seen in the drawing above: """) eg(""" from reportlab.graphics.shapes import Drawing from reportlab.graphics.widgets import signsandsymbols d = Drawing(230, 230) ne = signsandsymbols.NoEntry() ds = signsandsymbols.DangerSign() fd = signsandsymbols.FloppyDisk() ns = signsandsymbols.NoSmoking() ne.x, ne.y = 10, 10 ds.x, ds.y = 120, 10 fd.x, fd.y = 10, 120 ns.x, ns.y = 120, 120 d.add(ne) d.add(ds) d.add(fd) d.add(ns) """) heading3("Compound Widgets") disc("""Let's imagine a compound widget which draws two faces side by side. This is easy to build when you have the Face widget.""") eg(""" >>> tf = widgetbase.TwoFaces() >>> tf.faceOne.mood 'happy' >>> tf.faceTwo.mood 'sad' >>> tf.dumpProperties() faceOne.eyeColor = Color(0.00,0.00,1.00) faceOne.mood = happy faceOne.size = 80 faceOne.skinColor = None faceOne.x = 10 faceOne.y = 10 faceTwo.eyeColor = Color(0.00,0.00,1.00) faceTwo.mood = sad faceTwo.size = 80 faceTwo.skinColor = None faceTwo.x = 100 faceTwo.y = 10 >>> """) disc("""The attributes 'faceOne' and 'faceTwo' are deliberately exposed so you can get at them directly. There could also be top-level attributes, but there aren't in this case.""") heading3("Verifying Widgets") disc("""The widget designer decides the policy on verification, but by default they work like shapes - checking every assignment - if the designer has provided the checking information.""") heading3("Implementing Widgets") disc("""We tried to make it as easy to implement widgets as possible. Here's the code for a Face widget which does not do any type checking:""") eg(""" class Face(Widget): \"\"\"This draws a face with two eyes, mouth and nose.\"\"\" def __init__(self): self.x = 10 self.y = 10 self.size = 80 self.skinColor = None self.eyeColor = colors.blue self.mood = 'happy' def draw(self): s = self.size # abbreviate as we will use this a lot g = shapes.Group() g.transform = [1,0,0,1,self.x, self.y] # background g.add(shapes.Circle(s * 0.5, s * 0.5, s * 0.5, fillColor=self.skinColor)) # CODE OMITTED TO MAKE MORE SHAPES return g """) disc("""We left out all the code to draw the shapes in this document, but you can find it in the distribution in $widgetbase.py$.""") disc("""By default, any attribute without a leading underscore is returned by setProperties. This is a deliberate policy to encourage consistent coding conventions.""") disc("""Once your widget works, you probably want to add support for verification. This involves adding a dictionary to the class called $_verifyMap$, which map from attribute names to 'checking functions'. The $widgetbase.py$ module defines a bunch of checking functions with names like $isNumber$, $isListOfShapes$ and so on. You can also simply use $None$, which means that the attribute must be present but can have any type. And you can and should write your own checking functions. We want to restrict the "mood" custom attribute to the values "happy", "sad" or "ok". So we do this:""") eg(""" class Face(Widget): \"\"\"This draws a face with two eyes. It exposes a couple of properties to configure itself and hides all other details\"\"\" def checkMood(moodName): return (moodName in ('happy','sad','ok')) _verifyMap = { 'x': shapes.isNumber, 'y': shapes.isNumber, 'size': shapes.isNumber, 'skinColor':shapes.isColorOrNone, 'eyeColor': shapes.isColorOrNone, 'mood': checkMood } """) disc("""This checking will be performed on every attribute assignment; or, if $config.shapeChecking$ is off, whenever you call $myFace.verify()$.""") heading3("Documenting Widgets") disc(""" We are working on a generic tool to document any Python package or module; this is already checked into ReportLab and will be used to generate a reference for the ReportLab package. When it encounters widgets, it adds extra sections to the manual including:""") bullet("the doc string for your widget class ") bullet("the code snippet from your demo() method, so people can see how to use it") bullet("the drawing produced by the demo() method ") bullet("the property dump for the widget in the drawing. ") disc(""" This tool will mean that we can have guaranteed up-to-date documentation on our widgets and charts, both on the web site and in print; and that you can do the same for your own widgets, too! """) heading3("Widget Design Strategies") disc("""We could not come up with a consistent architecture for designing widgets, so we are leaving that problem to the authors! If you do not like the default verification strategy, or the way $setProperties/getProperties$ works, you can override them yourself.""") disc("""For simple widgets it is recommended that you do what we did above: select non-overlapping properties, initialize every property on $__init__$ and construct everything when $draw()$ is called. You can instead have $__setattr__$ hooks and have things updated when certain attributes are set. Consider a pie chart. If you want to expose the individual slices, you might write code like this:""") eg(""" from reportlab.graphics.charts import piecharts pc = piecharts.Pie() pc.defaultColors = [navy, blue, skyblue] #used in rotation pc.data = [10,30,50,25] pc.slices[7].strokeWidth = 5 """) #removed 'pc.backColor = yellow' from above code example disc("""The last line is problematic as we have only created four slices - in fact we might not have created them yet. Does $pc.slices[7]$ raise an error? Is it a prescription for what should happen if a seventh wedge is defined, used to override the default settings? We dump this problem squarely on the widget author for now, and recommend that you get a simple one working before exposing 'child objects' whose existence depends on other properties' values :-)""") disc("""We also discussed rules by which parent widgets could pass properties to their children. There seems to be a general desire for a global way to say that 'all slices get their lineWidth from the lineWidth of their parent' without a lot of repetitive coding. We do not have a universal solution, so again leave that to widget authors. We hope people will experiment with push-down, pull-down and pattern-matching approaches and come up with something nice. In the meantime, we certainly can write monolithic chart widgets which work like the ones in, say, Visual Basic and Delphi.""") disc("""For now have a look at the following sample code using an early version of a pie chart widget and the output it generates:""") eg(""" from reportlab.lib.colors import * from reportlab.graphics import shapes,renderPDF from reportlab.graphics.charts.piecharts import Pie d = Drawing(400,200) d.add(String(100,175,"Without labels", textAnchor="middle")) d.add(String(300,175,"With labels", textAnchor="middle")) pc = Pie() pc.x = 25 pc.y = 50 pc.data = [10,20,30,40,50,60] pc.slices[0].popout = 5 d.add(pc, 'pie1') pc2 = Pie() pc2.x = 150 pc2.y = 50 pc2.data = [10,20,30,40,50,60] pc2.labels = ['a','b','c','d','e','f'] d.add(pc2, 'pie2') pc3 = Pie() pc3.x = 275 pc3.y = 50 pc3.data = [10,20,30,40,50,60] pc3.labels = ['a','b','c','d','e','f'] pc3.slices.labelRadius = 0.65 pc3.slices.fontName = "Helvetica-Bold" pc3.slices.fontSize = 16 pc3.slices.fontColor = colors.yellow d.add(pc3, 'pie3') """) # Hack to force a new paragraph before the todo() :-( disc("") from reportlab.lib.colors import * from reportlab.graphics import shapes,renderPDF from reportlab.graphics.charts.piecharts import Pie d = Drawing(400,200) d.add(String(100,175,"Without labels", textAnchor="middle")) d.add(String(300,175,"With labels", textAnchor="middle")) pc = Pie() pc.x = 25 pc.y = 50 pc.data = [10,20,30,40,50,60] pc.slices[0].popout = 5 d.add(pc, 'pie1') pc2 = Pie() pc2.x = 150 pc2.y = 50 pc2.data = [10,20,30,40,50,60] pc2.labels = ['a','b','c','d','e','f'] d.add(pc2, 'pie2') pc3 = Pie() pc3.x = 275 pc3.y = 50 pc3.data = [10,20,30,40,50,60] pc3.labels = ['a','b','c','d','e','f'] pc3.slices.labelRadius = 0.65 pc3.slices.fontName = "Helvetica-Bold" pc3.slices.fontSize = 16 pc3.slices.fontColor = colors.yellow d.add(pc3, 'pie3') draw(d, 'Some sample Pies') ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1691062243.0 reportlab-4.1.0/docs/userguide/testfile.txt0000664000175000017500000000016014462707743020421 0ustar00rptlabrptlabTest of ability to create new files in sourceforge CVS, which seems not to be working. Can be removed any time.././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1691062243.0 reportlab-4.1.0/pyproject.toml0000664000175000017500000000013114462707743016027 0ustar00rptlabrptlab[build-system] requires = ["setuptools","wheel"] build-backend = "setuptools.build_meta" ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707393948.6585588 reportlab-4.1.0/setup.cfg0000664000175000017500000000004614561141635014731 0ustar00rptlabrptlab[egg_info] tag_build = tag_date = 0 ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1707393478.0 reportlab-4.1.0/setup.py0000664000175000017500000002734414561140706014632 0ustar00rptlabrptlab#Copyright ReportLab Europe Ltd. 2000-2023 #see LICENSE for license details __version__='4.1.0' import os, sys, glob, shutil, re, sysconfig, traceback, io, subprocess from urllib.parse import quote as urlquote platform = sys.platform pjoin = os.path.join abspath = os.path.abspath isfile = os.path.isfile isdir = os.path.isdir dirname = os.path.dirname basename = os.path.basename splitext = os.path.splitext addrSize = 64 if sys.maxsize > 2**32 else 32 sysconfig_platform = sysconfig.get_platform() INFOLINES=[] def infoline(t, pfx='#####', add=True, ): bn = splitext(basename(sys.argv[0]))[0] ver = '.'.join(map(str,sys.version_info[:3])) s = '%s %s-python-%s-%s: %s' % (pfx, bn, ver, sysconfig_platform, t) print(s) if add: INFOLINES.append(s) def showTraceback(s): buf = io.StringIO() print(s,file=buf) if verbose>2: traceback.print_exc(file=buf) for l in buf.getvalue().split('\n'): infoline(l,pfx='!!!!!',add=False) def spCall(cmd,*args,**kwds): r = subprocess.call( cmd, stderr = subprocess.STDOUT, stdout = subprocess.DEVNULL if kwds.pop('dropOutput',False) else None, timeout = kwds.pop('timeout',3600), ) if verbose>=3: infoline('%r --> %s' % (' '.join(cmd),r), pfx='!!!!!' if r else '#####', add=False) return r def specialOption(n,ceq=False): v = 0 while n in sys.argv: v += 1 sys.argv.remove(n) if ceq: n += '=' V = [_ for _ in sys.argv if _.startswith(n)] for _ in V: sys.argv.remove(_) if V: n = len(n) v = V[-1][n:] return v dlt1 = not specialOption('--no-download-t1-files') verbose = specialOption('--verbose',ceq=True) nullDivert = not verbose pkgDir=dirname(__file__) if not pkgDir: pkgDir=os.getcwd() elif not os.path.isabs(pkgDir): pkgDir=abspath(pkgDir) try: os.chdir(pkgDir) except: showTraceback('warning could not change directory to %r' % pkgDir) from setuptools import setup def get_version(): #determine Version #first try source FN = pjoin(pkgDir,'src','reportlab','__init__') try: for l in open(pjoin(FN+'.py'),'r').readlines(): if l.startswith('Version'): D = {} exec(l.strip(),D) return D['Version'] except: pass #don't have source, try import import imp for desc in ('.pyc', 'rb', 2), ('.pyo', 'rb', 2): try: fn = FN+desc[0] f = open(fn,desc[1]) m = imp.load_module('reportlab',f,fn,desc) return m.Version except: pass raise ValueError('Cannot determine ReportLab Version') #this code from /FBot's PIL setup.py def aDir(P, d, x=None): if d and isdir(d) and d not in P: if x is None: P.append(d) else: P.insert(x, d) # protection against loops needed. reported by # Michał Górny < mgorny at gentoo dot org > # see https://stackoverflow.com/questions/36977259 def findFile(root, wanted, followlinks=True): visited = set() for p, D, F in os.walk(root,followlinks=followlinks): #scan directories to check for prior visits #use dev/inode to make unique key SD = [].append for d in D: dk = os.stat(pjoin(p,d)) dk = dk.st_dev, dk.st_ino if dk not in visited: visited.add(dk) SD(d) D[:] = SD.__self__ #set the dirs to be scanned for fn in F: if fn==wanted: return abspath(pjoin(p,fn)) def listFiles(root,followlinks=True,strJoin=None): visited = set() R = [].append for p, D, F in os.walk(root,followlinks=followlinks): #scan directories to check for prior visits #use dev/inode to make unique key SD = [].append for d in D: dk = os.stat(pjoin(p,d)) dk = dk.st_dev, dk.st_ino if dk not in visited: visited.add(dk) SD(d) D[:] = SD.__self__ #set the dirs to be scanned for fn in F: R(abspath(pjoin(p,fn))) R = R.__self__ return strJoin.join(R) if strJoin else R reportlab_files= [ 'fonts/00readme.txt', 'fonts/bitstream-vera-license.txt', 'fonts/DarkGarden-changelog.txt', 'fonts/DarkGarden-copying-gpl.txt', 'fonts/DarkGarden-copying.txt', 'fonts/DarkGarden-readme.txt', 'fonts/DarkGarden.sfd', 'fonts/DarkGardenMK.afm', 'fonts/DarkGardenMK.pfb', 'fonts/Vera.ttf', 'fonts/VeraBd.ttf', 'fonts/VeraBI.ttf', 'fonts/VeraIt.ttf', 'fonts/_abi____.pfb', 'fonts/_ab_____.pfb', 'fonts/_ai_____.pfb', 'fonts/_a______.pfb', 'fonts/cobo____.pfb', 'fonts/cob_____.pfb', 'fonts/com_____.pfb', 'fonts/coo_____.pfb', 'fonts/_ebi____.pfb', 'fonts/_eb_____.pfb', 'fonts/_ei_____.pfb', 'fonts/_er_____.pfb', 'fonts/sy______.pfb', 'fonts/zd______.pfb', 'fonts/zx______.pfb', 'fonts/zy______.pfb', 'fonts/callig15.pfb', 'fonts/callig15.afm', 'reportlab/graphics/barcode/README' 'reportlab/graphics/barcode/TODO' 'license.txt', ] def url2data(url,returnRaw=False): import urllib.request as ureq remotehandle = ureq.urlopen(url) try: raw = remotehandle.read() return raw if returnRaw else io.BytesIO(raw) finally: remotehandle.close() def get_fonts(PACKAGE_DIR, reportlab_files): import zipfile rl_dir = PACKAGE_DIR['reportlab'] if not [x for x in reportlab_files if not isfile(pjoin(rl_dir,x))]: xitmsg = "Standard T1 font curves already downloaded" elif not dlt1: xitmsg = "not downloading T1 font curve files" else: try: infoline("Downloading standard T1 font curves") zipdata = url2data("https://www.reportlab.com/ftp/pfbfer-20180109.zip") archive = zipfile.ZipFile(zipdata) dst = pjoin(rl_dir, 'fonts') for name in archive.namelist(): if not name.endswith('/'): with open(pjoin(dst, name), 'wb') as outfile: outfile.write(archive.read(name)) xitmsg = "Finished download of standard T1 font curves" except: xitmsg = "Failed to download standard T1 font curves" infoline(xitmsg) def get_glyphlist_module(PACKAGE_DIR): try: lfn = pjoin("pdfbase","_glyphlist.py") fn = pjoin(PACKAGE_DIR['reportlab'],lfn) if isfile(fn): xitmsg = "The _glyphlist module already exists" else: text = url2data("https://raw.githubusercontent.com/adobe-type-tools/agl-aglfn/master/glyphlist.txt",True) comments = ['#see https://github.com/adobe-type-tools/agl-aglfn\n'].append G2U = [].append G2Us = [].append if not isinstance(text,str): text = text.decode('latin1') for line in text.split('\n'): line = line.strip() if not line: continue if line.startswith('#'): comments(line+'\n') else: gu = line.split(';') if len(gu)==2: v = gu[1].split() if len(v)==1: G2U('\t%r: 0x%s,\n' % (gu[0],gu[1])) else: G2Us('\t%r: (%s),\n' % (gu[0],','.join('0x%s'%u for u in v))) else: infoline('bad glyphlist line %r' % line, '!!!!!') with open(fn,'w') as f: f.write(''.join(comments.__self__)) f.write('_glyphname2unicode = {\n') f.write(''.join(G2U.__self__)) f.write('\t}\n') f.write('_glyphname2unicodes = {\n') f.write(''.join(G2Us.__self__)) f.write('\t}\n') xitmsg = "Finished creation of _glyphlist.py" except: xitmsg = "Failed to download glyphlist.txt" infoline(xitmsg) def main(): if 'test' in sys.argv \ or 'tests' in sys.argv \ or 'tests-postinstall' in sys.argv \ or 'tests-preinstall' in sys.argv: failfast = specialOption('--failfast') verboseTests = specialOption('--verbose-tests') excludes = [_ for _ in sys.argv if _.startswith('--exclude=')] for _ in excludes: sys.argv.remove(_) if len(sys.argv)!=2: raise ValueError('tests commands may only be used alone sys.argv[1:]=%s' % repr(sys.argv[1:])) cmd = sys.argv[-1] PYTHONPATH = [pkgDir] if cmd!='test' else [] if cmd=='tests-preinstall': PYTHONPATH.insert(0,pjoin(pkgDir,'src')) if PYTHONPATH: os.environ['PYTHONPATH']=os.pathsep.join(PYTHONPATH) os.chdir(pjoin(pkgDir,'tests')) cli = [sys.executable, 'runAll.py']+excludes if cmd=='tests-postinstall': cli.append('--post-install') if verboseTests: cli.append('--verbosity=2') if failfast: cli.append('--failfast') r = spCall(cli) sys.exit(('!!!!! runAll.py --> %s should exit with error !!!!!' % r) if r else r) #copy some special case files into place so package_data will treat them properly PACKAGE_DIR = {'':'src','reportlab': pjoin('src','reportlab')} get_fonts(PACKAGE_DIR, reportlab_files) get_glyphlist_module(PACKAGE_DIR) setup( name="reportlab", version=get_version(), license="BSD license (see license.txt for details), Copyright (c) 2000-2022, ReportLab Inc.", description="The Reportlab Toolkit", long_description="""The ReportLab Toolkit. An Open Source Python library for generating PDFs and graphics.""", author="Andy Robinson, Robin Becker, the ReportLab team and the community", author_email="reportlab-users@lists2.reportlab.com", url="https://www.reportlab.com/", packages=[ 'reportlab', 'reportlab.graphics.charts', 'reportlab.graphics.samples', 'reportlab.graphics.widgets', 'reportlab.graphics.barcode', 'reportlab.graphics', 'reportlab.lib', 'reportlab.pdfbase', 'reportlab.pdfgen', 'reportlab.platypus', ], package_dir = PACKAGE_DIR, package_data = {'reportlab': reportlab_files}, classifiers = [ 'Development Status :: 5 - Production/Stable', 'Intended Audience :: Developers', 'License :: OSI Approved :: BSD License', 'Topic :: Printing', 'Topic :: Text Processing :: Markup', 'Programming Language :: Python :: 3', 'Programming Language :: Python :: 3.7', 'Programming Language :: Python :: 3.8', 'Programming Language :: Python :: 3.9', 'Programming Language :: Python :: 3.10', 'Programming Language :: Python :: 3.11', ], # this probably only works for setuptools, but distutils seems to ignore it install_requires=['pillow>=9.0.0','chardet'], # moved to pyproject.toml python_requires='>=3.7,<4', extras_require={ 'accel': ['rl_accel>=0.9.0,<1.1'], 'renderpm': ['rl_renderPM>=4.0.3,<4.1'], 'pycairo': ['rlPyCairo>=0.2.0,<1', 'freetype-py>=2.3.0,<2.4'] }, ) print() print('########## SUMMARY INFO #########') print('\n'.join(INFOLINES)) if __name__=='__main__': main() ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707393948.3345587 reportlab-4.1.0/src/0000775000175000017500000000000014561141634013676 5ustar00rptlabrptlab././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707393948.3945587 reportlab-4.1.0/src/reportlab/0000775000175000017500000000000014561141634015670 5ustar00rptlabrptlab././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1691062243.0 reportlab-4.1.0/src/reportlab/MANIFEST.in0000664000175000017500000000027114462707743017437 0ustar00rptlabrptlabglobal-include *.dtd *.txt *.xml *.yml global-include *.c *.h *.in *.mashed global-include *.gif *.png *.jpg .a85 global-include *.AFM *.PFB *.ttf global-include README include changes ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1707393443.0 reportlab-4.1.0/src/reportlab/__init__.py0000664000175000017500000000271114561140643020001 0ustar00rptlabrptlab#Copyright ReportLab Europe Ltd. 2000-2023 #see license.txt for license details __doc__="""The Reportlab PDF generation library.""" Version = "4.1.0" __version__=Version __date__='20240208' import sys, os __min_python_version__ = (3,7) if sys.version_info< __min_python_version__: raise ImportError("""reportlab requires %s.%s+; other versions are unsupported. If you want to try with other python versions edit line 10 of reportlab/__init__ to remove this error.""" % (__min_python_version__)) #define these early in reportlab's life def cmp(a,b): return -1 if ab else 0) def _fake_import(fn,name): from importlib.util import spec_from_loader, module_from_spec from importlib.machinery import SourceFileLoader spec = spec_from_loader(name, SourceFileLoader(name, fn)) module = module_from_spec(spec) try: spec.loader.exec_module(module) except FileNotFoundError: raise ImportError('file %s not found' % ascii(fn)) sys.modules[name] = module #try to use dynamic modifications from #reportlab.local_rl_mods.py #reportlab_mods.py or ~/.reportlab_mods try: import reportlab.local_rl_mods except ImportError: pass try: import reportlab_mods #application specific modifications can be anywhere on python path except ImportError: try: _fake_import(os.path.expanduser(os.path.join('~','.reportlab_mods')),'reportlab_mods') except (ImportError,KeyError,PermissionError): pass ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707393948.3985586 reportlab-4.1.0/src/reportlab/fonts/0000775000175000017500000000000014561141634017021 5ustar00rptlabrptlab././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1691062243.0 reportlab-4.1.0/src/reportlab/fonts/00readme.txt0000664000175000017500000000047614462707743021177 0ustar00rptlabrptlabThis directory is a convenient place to put fonts where Reportlab will find them. If running in a server environment, this is a good place to put Type 1 fonts needed by your application. If in a desktop environment, you might prefer to add your font directories to the T1SearchPath in reportlab/rl_config.py instead. ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1691062243.0 reportlab-4.1.0/src/reportlab/fonts/DarkGarden-changelog.txt0000664000175000017500000000077014462707743023526 0ustar00rptlabrptlab2004-05-18 Michal Kosmulski * Version 1.1 * Changed license to GNU GPL with Font Exception * Added Zacute character * Added basic hinting * Added kerning information 2000 Michal Kosmulski * Version 1.0 * Added Polish and German diacritic characters except for Zacute 1999 Michal Kosmulski * Version 0.9 * Includes only the 26 letters of the English alphabet * Distributed under a freeware license ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1691062243.0 reportlab-4.1.0/src/reportlab/fonts/DarkGarden-copying-gpl.txt0000664000175000017500000004307014462707743024027 0ustar00rptlabrptlab GNU GENERAL PUBLIC LICENSE Version 2, June 1991 Copyright (C) 1989, 1991 Free Software Foundation, Inc. 675 Mass Ave, Cambridge, MA 02139, USA Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. Preamble The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change free software--to make sure the software is free for all its users. This General Public License applies to most of the Free Software Foundation's software and to any other program whose authors commit to using it. (Some other Free Software Foundation software is covered by the GNU Library General Public License instead.) You can apply it to your programs, too. When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for this service if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs; and that you know you can do these things. To protect your rights, we need to make restrictions that forbid anyone to deny you these rights or to ask you to surrender the rights. These restrictions translate to certain responsibilities for you if you distribute copies of the software, or if you modify it. For example, if you distribute copies of such a program, whether gratis or for a fee, you must give the recipients all the rights that you have. You must make sure that they, too, receive or can get the source code. And you must show them these terms so they know their rights. We protect your rights with two steps: (1) copyright the software, and (2) offer you this license which gives you legal permission to copy, distribute and/or modify the software. Also, for each author's protection and ours, we want to make certain that everyone understands that there is no warranty for this free software. If the software is modified by someone else and passed on, we want its recipients to know that what they have is not the original, so that any problems introduced by others will not reflect on the original authors' reputations. Finally, any free program is threatened constantly by software patents. We wish to avoid the danger that redistributors of a free program will individually obtain patent licenses, in effect making the program proprietary. To prevent this, we have made it clear that any patent must be licensed for everyone's free use or not licensed at all. The precise terms and conditions for copying, distribution and modification follow. GNU GENERAL PUBLIC LICENSE TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 0. This License applies to any program or other work which contains a notice placed by the copyright holder saying it may be distributed under the terms of this General Public License. The "Program", below, refers to any such program or work, and a "work based on the Program" means either the Program or any derivative work under copyright law: that is to say, a work containing the Program or a portion of it, either verbatim or with modifications and/or translated into another language. (Hereinafter, translation is included without limitation in the term "modification".) Each licensee is addressed as "you". Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running the Program is not restricted, and the output from the Program is covered only if its contents constitute a work based on the Program (independent of having been made by running the Program). Whether that is true depends on what the Program does. 1. You may copy and distribute verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice and disclaimer of warranty; keep intact all the notices that refer to this License and to the absence of any warranty; and give any other recipients of the Program a copy of this License along with the Program. You may charge a fee for the physical act of transferring a copy, and you may at your option offer warranty protection in exchange for a fee. 2. You may modify your copy or copies of the Program or any portion of it, thus forming a work based on the Program, and copy and distribute such modifications or work under the terms of Section 1 above, provided that you also meet all of these conditions: a) You must cause the modified files to carry prominent notices stating that you changed the files and the date of any change. b) You must cause any work that you distribute or publish, that in whole or in part contains or is derived from the Program or any part thereof, to be licensed as a whole at no charge to all third parties under the terms of this License. c) If the modified program normally reads commands interactively when run, you must cause it, when started running for such interactive use in the most ordinary way, to print or display an announcement including an appropriate copyright notice and a notice that there is no warranty (or else, saying that you provide a warranty) and that users may redistribute the program under these conditions, and telling the user how to view a copy of this License. (Exception: if the Program itself is interactive but does not normally print such an announcement, your work based on the Program is not required to print an announcement.) These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Program, and can be reasonably considered independent and separate works in themselves, then this License, and its terms, do not apply to those sections when you distribute them as separate works. But when you distribute the same sections as part of a whole which is a work based on the Program, the distribution of the whole must be on the terms of this License, whose permissions for other licensees extend to the entire whole, and thus to each and every part regardless of who wrote it. Thus, it is not the intent of this section to claim rights or contest your rights to work written entirely by you; rather, the intent is to exercise the right to control the distribution of derivative or collective works based on the Program. In addition, mere aggregation of another work not based on the Program with the Program (or with a work based on the Program) on a volume of a storage or distribution medium does not bring the other work under the scope of this License. 3. You may copy and distribute the Program (or a work based on it, under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you also do one of the following: a) Accompany it with the complete corresponding machine-readable source code, which must be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, b) Accompany it with a written offer, valid for at least three years, to give any third party, for a charge no more than your cost of physically performing source distribution, a complete machine-readable copy of the corresponding source code, to be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, c) Accompany it with the information you received as to the offer to distribute corresponding source code. (This alternative is allowed only for noncommercial distribution and only if you received the program in object code or executable form with such an offer, in accord with Subsection b above.) The source code for a work means the preferred form of the work for making modifications to it. For an executable work, complete source code means all the source code for all modules it contains, plus any associated interface definition files, plus the scripts used to control compilation and installation of the executable. However, as a special exception, the source code distributed need not include anything that is normally distributed (in either source or binary form) with the major components (compiler, kernel, and so on) of the operating system on which the executable runs, unless that component itself accompanies the executable. If distribution of executable or object code is made by offering access to copy from a designated place, then offering equivalent access to copy the source code from the same place counts as distribution of the source code, even though third parties are not compelled to copy the source along with the object code. 4. You may not copy, modify, sublicense, or distribute the Program except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense or distribute the Program is void, and will automatically terminate your rights under this License. However, parties who have received copies, or rights, from you under this License will not have their licenses terminated so long as such parties remain in full compliance. 5. You are not required to accept this License, since you have not signed it. However, nothing else grants you permission to modify or distribute the Program or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Program (or any work based on the Program), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Program or works based on it. 6. Each time you redistribute the Program (or any work based on the Program), the recipient automatically receives a license from the original licensor to copy, distribute or modify the Program subject to these terms and conditions. You may not impose any further restrictions on the recipients' exercise of the rights granted herein. You are not responsible for enforcing compliance by third parties to this License. 7. If, as a consequence of a court judgment or allegation of patent infringement or for any other reason (not limited to patent issues), conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot distribute so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not distribute the Program at all. For example, if a patent license would not permit royalty-free redistribution of the Program by all those who receive copies directly or indirectly through you, then the only way you could satisfy both it and this License would be to refrain entirely from distribution of the Program. If any portion of this section is held invalid or unenforceable under any particular circumstance, the balance of the section is intended to apply and the section as a whole is intended to apply in other circumstances. It is not the purpose of this section to induce you to infringe any patents or other property right claims or to contest validity of any such claims; this section has the sole purpose of protecting the integrity of the free software distribution system, which is implemented by public license practices. Many people have made generous contributions to the wide range of software distributed through that system in reliance on consistent application of that system; it is up to the author/donor to decide if he or she is willing to distribute software through any other system and a licensee cannot impose that choice. This section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License. 8. If the distribution and/or use of the Program is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Program under this License may add an explicit geographical distribution limitation excluding those countries, so that distribution is permitted only in or among countries not thus excluded. In such case, this License incorporates the limitation as if written in the body of this License. 9. The Free Software Foundation may publish revised and/or new versions of the General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Program specifies a version number of this License which applies to it and "any later version", you have the option of following the terms and conditions either of that version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of this License, you may choose any version ever published by the Free Software Foundation. 10. If you wish to incorporate parts of the Program into other free programs whose distribution conditions are different, write to the author to ask for permission. For software which is copyrighted by the Free Software Foundation, write to the Free Software Foundation; we sometimes make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally. NO WARRANTY 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. END OF TERMS AND CONDITIONS How to Apply These Terms to Your New Programs If you develop a new program, and you want it to be of the greatest possible use to the public, the best way to achieve this is to make it free software which everyone can redistribute and change under these terms. To do so, attach the following notices to the program. It is safest to attach them to the start of each source file to most effectively convey the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. Copyright (C) 19yy This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program 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 General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. Also add information on how to contact you by electronic and paper mail. If the program is interactive, make it output a short notice like this when it starts in an interactive mode: Gnomovision version 69, Copyright (C) 19yy name of author Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. This is free software, and you are welcome to redistribute it under certain conditions; type `show c' for details. The hypothetical commands `show w' and `show c' should show the appropriate parts of the General Public License. Of course, the commands you use may be called something other than `show w' and `show c'; they could even be mouse-clicks or menu items--whatever suits your program. You should also get your employer (if you work as a programmer) or your school, if any, to sign a "copyright disclaimer" for the program, if necessary. Here is a sample; alter the names: Yoyodyne, Inc., hereby disclaims all copyright interest in the program `Gnomovision' (which makes passes at compilers) written by James Hacker. , 1 April 1989 Ty Coon, President of Vice This General Public License does not permit incorporating your program into proprietary programs. If your program is a subroutine library, you may consider it more useful to permit linking proprietary applications with the library. If this is what you want to do, use the GNU Library General Public License instead of this License. ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1691062243.0 reportlab-4.1.0/src/reportlab/fonts/DarkGarden-copying.txt0000664000175000017500000000244614462707743023251 0ustar00rptlabrptlabCopyright (C) 1999, 2000, 2004 Michal Kosmulski This font is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This font 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 General Public License for more details. You should have received a copy of the GNU General Public License along with this font; if not, write to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. As a special exception, if you create a document which uses this font, and embed this font or unaltered portions of this font into the document, this font does not by itself cause the resulting document to be covered by the GNU General Public License. This exception does not however invalidate any other reasons why the document might be covered by the GNU General Public License. If you modify this font, you may extend this exception to your version of the font, but you are not obligated to do so. If you do not wish to do so, delete this exception statement from your version. ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1691062243.0 reportlab-4.1.0/src/reportlab/fonts/DarkGarden-readme.txt0000664000175000017500000001003214462707743023024 0ustar00rptlabrptlabDark Garden =========== GENERAL Dark Garden is a decorative outline font of unusual shape. The typeface is based on author's original hand drawings. The letterform is complex, with all characters decorated with spikes resembling thorns or flames, character spacing is very dense. Such a theme makes it a great font for titles, banners, logos etc. As of version 1.1, Dark Garden includes letters of the English alphabet, Polish and German diacritic characters and some punctuation. Unicode encoding is used. The font is equipped with hinting information to allow high quality rendering at small point sizes. Only horizontal and vertical hints are currently used, future versions might take advantage of truetype hinting instructions some day. There are also a lot of kerning pairs defined in the font - they were chosen after looking at a choice of Polish and English texts and selecting the character pairs that needed manual kerning. The font was created with PfaEdit / FontForge (http://fontforge.sourceforge.net/) - an opensource font editing tool. Pfaedit uses its own text-based file format which can then be exported to truetype, postscript, opentype and many other font formats. This makes it possible to generate font files for Dark Garden in any of the many supported formats, so it can be used on almost any platform. So far, the truetype version has been tested on X11 (Linux) and Windows, the opentype version worked on Windows but not X11. Truetype should also work on Mac OS. INSTALLATION Installation is described for the truetype version of the font (which is what most users will need). On Windows: * Extract .ttf files from the archive into a temporary directory * In the Control Panel choose Fonts * From the File menu choose Install New Font * Browse to the temporary directory you chose * "Dark Garden" should appear in the font list - click OK (this may require Administrator privileges) On Linux / UNIX (using KDE): * Extract .ttf files from the archive into a temporary directory * In the Control Center choose Font Installer in the System Administration tree * Click on "Administrator Mode" and enter root's password * Click on "Add Fonts" icon * Select the .ttf file extracted from the archive and click OK On Linux / UNIX (using commandline) unzip darkgarden-*.ttf.zip su ginstall -o root -m 644 DarkGardenMK.ttf /usr/X11R6/lib/fonts/TTF fc-cache -f COPYRIGHT AND LICENSE Copyright (C) 1999, 2000, 2004 Michal Kosmulski This font is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This font 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 General Public License for more details. You should have received a copy of the GNU General Public License along with this font; if not, write to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. As a special exception, if you create a document which uses this font, and embed this font or unaltered portions of this font into the document, this font does not by itself cause the resulting document to be covered by the GNU General Public License. This exception does not however invalidate any other reasons why the document might be covered by the GNU General Public License. If you modify this font, you may extend this exception to your version of the font, but you are not obligated to do so. If you do not wish to do so, delete this exception statement from your version. The text of this license can be found in file COPYING.txt in the distribution archives. The GNU General Public License text can be found in file COPYING-GPL.txt. CONTACTING THE AUTHOR Send e-mail with questions, bug reports and patches to Michal Kosmulski, mkosmul@users.sourceforge.net The homepage of Dark Garden Font is located at http://darkgarden.sourceforge.net/. ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1691062243.0 reportlab-4.1.0/src/reportlab/fonts/DarkGarden.sfd0000664000175000017500000176672214462707743021557 0ustar00rptlabrptlabSplineFontDB: 1.0 FontName: DarkGardenMK FullName: Dark Garden FamilyName: Dark Garden Weight: Medium Copyright: Copyright (C) 1999, 2000, 2004 Michal Kosmulski \n\n\nThis font is free software; you can redistribute it and/or modify\nit under the terms of the GNU General Public License as published by\nthe Free Software Foundation; either version 2 of the License, or\n(at your option) any later version.\n\nThis font is distributed in the hope that it will be useful,\nbut WITHOUT ANY WARRANTY; without even the implied warranty of\nMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\nGNU General Public License for more details.\n\nYou should have received a copy of the GNU General Public License\nalong with this font; if not, write to the Free Software\nFoundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.\n\nAs a special exception, if you create a document which uses\nthis font, and embed this font or unaltered portions of this font into\nthe document, this font does not by itself cause the resulting\ndocument to be covered by the GNU General Public License. This\nexception does not however invalidate any other reasons why the\ndocument might be covered by the GNU General Public License. If you\nmodify this font, you may extend this exception to your version of the\nfont, but you are not obligated to do so. If you do not wish to do so,\ndelete this exception statement from your version.\n Version: 1.1 ItalicAngle: 0 UnderlinePosition: -420 UnderlineWidth: 80 Ascent: 1638 Descent: 410 Order2: 1 NeedsXUIDChange: 1 FSType: 0 PfmFamily: 81 TTFWeight: 500 TTFWidth: 5 Panose: 2 11 6 3 5 6 0 0 2 4 LineGap: 0 VLineGap: 0 OS2TypoAscent: 2311 OS2TypoDescent: -708 OS2WinAscent: 2311 OS2WinDescent: 708 ScriptLang: 1 1 latn 1 dflt LangName: 1033 "" "" "Regular" "DarkGarden (Michal Kosmulski)" "" "" "" "" "Micha+AUIA Kosmulski" "Micha+AUIA Kosmulski" Encoding: unicode UnicodeInterp: none DisplaySize: -48 AntiAlias: 1 FitToEm: 1 WinInfo: 64 16 4 TeXData: 1 10485760 0 524288 262144 174762 810240 -1048576 174762 783286 444596 497025 792723 393216 433062 380633 303038 157286 324010 404750 52429 2506097 1059062 262144 BeginChars: 65538 86 StartChar: .notdef Encoding: 0 -1 0 Width: 2048 Flags: MW VStem: 2 1085<0 1821> Fore 2 0 m 1,0,-1 2 1821 l 0,1,-1 1087 1821 l 0,2,-1 1087 0 l 0,3,-1 2 0 l 1,0,-1 EndSplineSet EndChar StartChar: glyph1 Encoding: 1 -1 1 Width: 0 Flags: W EndChar StartChar: glyph2 Encoding: 2 -1 2 Width: 2048 Flags: W EndChar StartChar: space Encoding: 32 32 3 Width: 1024 Flags: W EndChar StartChar: comma Encoding: 44 44 6 Width: 267 Flags: HMW HStem: -1.6875 173.812<6.75 231.188> VStem: 120.938 110.25<-133.875 -1.6875> Fore 40.5 -154.125 m 1,0,1 96.75 -106.875 96.75 -106.875 106.875 -77.625 c 0,2,3 117 -48.375 117 -48.375 117 -37.125 c 0,4,5 123.75 -4.5 123.75 -4.5 91.125 -4.5 c 0,6,7 58.5 -4.5 58.5 -4.5 54 -2.25 c 0,8,9 4.5 11.25 4.5 11.25 2.25 81 c 0,10,11 -1.125 133.875 -1.125 133.875 6.75 172.125 c 0,12,13 24.75 208.125 24.75 208.125 48.375 208.125 c 0,14,15 116.999 208.125 116.999 208.125 158.062 214.875 c 0,16,17 179.095 214.82 l 0,18,19 205.824 209.75 205.824 209.75 223.875 177.75 c 0,20,-1 248.062 129.938 l 0,21,22 251.423 123.475 251.423 123.475 251.338 108.103 c 0,23,24 251.239 90.0244 251.239 90.0244 246.375 59.625 c 0,25,-1 231.188 -1.6875 l 0,26,27 219.376 -49.4989 219.376 -49.4989 191.25 -88.875 c 0,28,29 164.25 -119.25 164.25 -119.25 120.938 -133.875 c 0,30,31 77.625 -148.5 77.625 -148.5 40.5 -154.125 c 1,0,1 EndSplineSet EndChar StartChar: hyphen Encoding: 45 45 7 Width: 1252 Flags: HMW HStem: 843.75 163.5<206.75 1005.5> Fore 379.25 809.25 m 1,0,1 319.25 789.75 319.25 789.75 266 800.25 c 0,2,3 212.75 810.75 212.75 810.75 212.75 866.25 c 0,4,-1 261.5 836.25 l 0,5,6 310.25 806.25 310.25 806.25 323.75 890.25 c 0,7,8 326.75 932.25 326.75 932.25 268.25 938.25 c 0,9,10 209.75 944.25 209.75 944.25 155.75 932.25 c 0,11,12 122.75 911.25 122.75 911.25 120.5 863.25 c 0,13,14 118.25 815.25 118.25 815.25 118.25 807.75 c 0,15,16 74.75 891.75 74.75 891.75 111.5 943.5 c 0,17,18 148.25 995.25 148.25 995.25 206.75 1007.25 c 0,19,20 344.75 1016.25 344.75 1016.25 464 972 c 0,21,22 583.25 927.75 583.25 927.75 718.25 927.75 c 0,23,24 764.75 932.25 764.75 932.25 821.75 932.25 c 0,25,26 878.75 932.25 878.75 932.25 889.25 966.75 c 0,27,28 884.75 1011.75 884.75 1011.75 844.25 1002.75 c 0,29,30 803.75 993.75 803.75 993.75 782.75 972.75 c 0,31,32 794.75 1005.75 794.75 1005.75 812.75 1033.5 c 0,33,34 830.75 1061.25 830.75 1061.25 878.75 1062.75 c 0,35,36 934.25 1047.75 934.25 1047.75 950.75 1032.75 c 0,37,38 967.25 1017.75 967.25 1017.75 982.25 969.75 c 0,39,40 982.25 936.75 982.25 936.75 998.75 915 c 0,41,42 1015.25 893.25 1015.25 893.25 1082.75 906.75 c 0,43,44 1121.75 921.75 1121.75 921.75 1145.75 947.25 c 0,45,46 1139.75 927.75 1139.75 927.75 1123.25 897.75 c 0,47,48 1106.75 867.75 1106.75 867.75 1079.75 854.25 c 0,49,-1 1079.75 854.25 l 0,50,-1 1079.75 854.25 l 0,51,52 1066.25 840.75 1066.25 840.75 1005.5 843.75 c 0,53,54 944.75 846.75 944.75 846.75 929.75 846.75 c 0,55,56 872.75 855.75 872.75 855.75 831.5 858 c 0,57,58 790.25 860.25 790.25 860.25 736.25 842.25 c 0,59,60 668.75 824.25 668.75 824.25 693.5 791.25 c 0,61,62 718.25 758.25 718.25 758.25 784.25 815.25 c 0,63,64 772.25 789.75 772.25 789.75 747.5 762 c 0,65,66 722.75 734.25 722.75 734.25 613.25 755.25 c 0,67,68 523.25 777.75 523.25 777.75 497.75 791.25 c 0,69,70 472.25 804.75 472.25 804.75 379.25 809.25 c 1,0,1 EndSplineSet KernsSLIF: 90 -260 0 0 122 -208 0 0 88 -182 0 0 120 -156 0 0 89 -130 0 0 121 -104 0 0 87 -182 0 0 119 -182 0 0 84 -286 0 0 116 -273 0 0 83 -234 0 0 115 -156 0 0 65 -234 0 0 97 -234 0 0 EndChar StartChar: period Encoding: 46 46 5 Width: 270 Flags: HMW HStem: 57.9375 152.438<9 235.688> Fore 142.875 2.25 m 0,0,1 103.5 -1.125 103.5 -1.125 92.25 14.625 c 0,2,3 81 29.25 81 29.25 63 34.875 c 0,4,5 6.75 51.75 6.75 51.75 4.5 120.375 c 0,6,7 0 172.125 0 172.125 9 210.375 c 0,8,9 27 246.375 27 246.375 50.625 246.375 c 0,10,11 119.249 246.375 119.249 246.375 160.312 253.125 c 0,12,13 181.345 253.07 l 0,14,15 208.074 248 208.074 248 226.125 216 c 0,16,-1 250.312 168.188 l 0,17,18 253.673 161.725 253.673 161.725 253.588 146.353 c 0,19,20 253.489 128.274 253.489 128.274 248.625 97.875 c 0,21,22 245.249 84.3705 245.249 84.3705 235.688 57.9375 c 0,23,24 226.126 31.5004 226.126 31.5004 214.875 24.75 c 0,25,26 180 4.5 180 4.5 142.875 2.25 c 0,0,1 EndSplineSet EndChar StartChar: colon Encoding: 58 58 34 Width: 384 Flags: HMW HStem: 23.625 211.5<86.625 239.062> 678.75 191.25<108.75 288.75> Fore 108.75 870 m 1,0,1 166.125 930.75 166.125 930.75 202.125 909.938 c 0,2,3 238.125 889.125 238.125 889.125 295.5 832.875 c 0,4,5 325.875 802.5 325.875 802.5 325.312 754.125 c 0,6,7 324.75 705.75 324.75 705.75 288.75 678.75 c 0,8,9 211.125 621.375 211.125 621.375 189.75 618 c 0,10,11 168.375 614.625 168.375 614.625 131.25 636 c 0,12,13 80.625 663 80.625 663 75 680.438 c 0,14,15 69.375 697.875 69.375 697.875 68.25 731.625 c 0,16,17 64.875 775.5 64.875 775.5 67.6875 803.062 c 0,18,19 70.5 830.625 70.5 830.625 108.75 870 c 0,20,-1 108.75 870 l 1,0,1 86.625 235.125 m 0,16,17 95.625 275.625 95.625 275.625 164.25 279 c 0,18,19 232.875 282.375 232.875 282.375 252 271.125 c 0,20,21 273.375 257.625 273.375 257.625 289.688 189.562 c 0,22,23 301.323 141.017 301.323 141.017 301.225 117.366 c 0,24,25 301.185 107.859 301.185 107.859 299.25 102.375 c 0,26,27 273.375 34.875 273.375 34.875 239.062 23.625 c 0,28,29 204.749 12.375 204.749 12.375 160.875 12.375 c 0,30,31 145.124 12.375 145.124 12.375 128.812 39.9375 c 0,32,33 112.499 67.5003 112.499 67.5003 95.625 75.375 c 0,34,35 68.625 86.625 68.625 86.625 73.125 142.875 c 0,36,37 77.625 199.125 77.625 199.125 86.625 235.125 c 0,16,17 EndSplineSet EndChar StartChar: semicolon Encoding: 59 59 35 Width: 384 Flags: HMW HStem: 45 132.75<91.125 303.75> 738 180<118.875 291> VStem: 154.125 149.625<-200.25 45> Fore 118.875 918 m 1,0,1 177.375 977.625 177.375 977.625 212.25 957.375 c 0,2,3 247.125 937.125 247.125 937.125 305.625 880.875 c 0,4,5 366.375 821.25 366.375 821.25 291 738 c 0,6,7 238.125 679.5 238.125 679.5 230.25 678.938 c 0,8,9 222.375 678.375 222.375 678.375 141.375 682.875 c 0,10,11 82.875 686.25 82.875 686.25 81.1875 716.062 c 0,12,13 79.5 745.875 79.5 745.875 77.25 779.625 c 0,14,15 73.875 823.5 73.875 823.5 77.25 850.5 c 0,16,17 80.625 877.5 80.625 877.5 118.875 918 c 0,18,-1 118.875 918 l 1,0,1 91.125 177.75 m 0,15,16 100.125 218.251 100.125 218.251 169.312 222.188 c 0,17,18 225.136 222.126 l 0,19,20 247.88 220.056 247.88 220.056 257.625 213.75 c 0,21,22 278.999 200.25 278.999 200.25 293.062 133.312 c 0,23,24 307.125 66.375 307.125 66.375 303.75 45 c 0,25,26 292.5 -19.125 292.5 -19.125 246.938 -110.25 c 0,27,28 202.357 -199.411 202.357 -199.411 154.125 -200.25 c 0,29,30 201.375 -173.25 201.375 -173.25 201.375 -86.625 c 0,31,32 201.375 0 201.375 0 174.375 6.75 c 0,33,34 140.074 9.61226 l 0,35,36 138.95 9.59327 138.95 9.59327 137.812 9.5625 c 0,37,38 113.206 12.6329 l 0,39,40 106.394 14.6566 106.394 14.6566 100.125 18 c 0,41,42 73.125 30.375 73.125 30.375 77.625 85.5 c 0,43,44 82.125 140.625 82.125 140.625 91.125 177.75 c 0,15,16 EndSplineSet EndChar StartChar: A Encoding: 65 65 55 Width: 1447 Flags: W Fore 1268 -330 m 1,0,1 1304.01 -261.985 1304.01 -261.985 1321 -184 c 0,2,3 1324.46 -150.427 l 0,4,5 1323.49 -92.1465 1323.49 -92.1465 1272 -43 c 0,6,7 1221.01 4.9888 1221.01 4.9888 1171 38 c 0,8,9 1121.01 71 1121.01 71 1066 52 c 0,10,11 1028.99 38 1028.99 38 1019.5 -17 c 0,12,13 1010.01 -72 1010.01 -72 1006 -72 c 0,14,15 965 9 965 9 1013.5 102 c 0,16,17 1059.21 189.663 1059.21 189.663 1059.17 266.65 c 0,18,19 1059.17 271.346 1059.17 271.346 1059 276 c 0,20,21 1053 434.993 1053 434.993 1006 491.5 c 0,22,23 959.002 547.999 959.002 547.999 895 573 c 0,24,25 861.093 585.849 861.093 585.849 831.581 585.768 c 0,26,27 778.406 585.622 778.406 585.622 739.5 543.5 c 0,28,29 679.002 478.002 679.002 478.002 616 450 c 0,30,31 577 432 577 432 533.5 448.5 c 0,32,33 490 465 490 465 487 510 c 0,34,35 532 492 532 492 543.5 499.5 c 0,36,37 555 507 555 507 558 514 c 0,38,39 579 558 579 558 530 570 c 0,40,41 424 595 424 595 383 514 c 0,42,43 347 446 347 446 318.5 347 c 0,44,45 290 248 290 248 328 164 c 0,46,47 336.295 144.644 336.295 144.644 336.228 116.448 c 0,48,49 336.198 103.856 336.198 103.856 334.5 89.5 c 0,50,51 328.999 42.9997 328.999 42.9997 283 27 c 0,52,53 302 105 302 105 245 98 c 0,54,55 188 91 188 91 157 57 c 0,56,57 89.0005 -17 89.0005 -17 55 -80 c 0,58,59 21 -143 21 -143 33 -233 c 0,60,61 7.11917 -206.16 7.11917 -206.16 6.9652 -142.109 c 0,62,63 6.95854 -139.339 6.95854 -139.339 7 -136.5 c 0,64,65 8 -67.9999 8 -67.9999 27 -36 c 0,66,67 60 22 60 22 93.5 73.5 c 0,68,69 126.999 124.999 126.999 124.999 128 188 c 0,70,71 128 227 128 227 100 243 c 0,72,73 89.0676 246.192 l 0,74,75 81.8899 245.118 81.8899 245.118 81.7695 231.241 c 0,76,77 87 197 l 0,78,79 60.9999 218 60.9999 218 60.5 237 c 0,80,81 63 272 l 0,82,83 105 461 105 461 237.5 625 c 0,84,85 370.001 789.001 370.001 789.001 396 894 c 0,86,87 431.998 1045.99 431.998 1045.99 450 1180 c 0,88,89 458 1246.01 458 1246.01 501 1303.5 c 0,90,91 526.01 1336.94 526.01 1336.94 555.08 1337.06 c 0,92,93 575.989 1337.15 575.989 1337.15 599 1320 c 0,94,95 545 1309.01 545 1309.01 543 1280.5 c 0,96,97 541 1252 541 1252 552 1240 c 0,98,99 570.499 1217.04 570.499 1217.04 589 1216.86 c 0,100,101 599.5 1216.76 599.5 1216.76 610 1224 c 0,102,103 666.003 1261.01 666.003 1261.01 702.5 1381 c 0,104,105 739 1501 739 1501 737 1567 c 0,106,107 734 1633 734 1633 690 1672 c 0,108,109 669.348 1690.31 669.348 1690.31 646.491 1690.32 c 0,110,111 620.654 1690.35 620.654 1690.35 592 1667 c 0,112,113 628 1758.99 628 1758.99 682.5 1745 c 0,114,115 737 1731.01 737 1731.01 792.5 1671.5 c 0,116,117 848.023 1611.97 848.023 1611.97 896 1539 c 0,118,119 944 1465.99 944 1465.99 966 1440 c 0,120,121 1000.99 1397.01 1000.99 1397.01 1047 1369 c 0,122,123 1092.99 1341 1092.99 1341 1112 1302 c 0,124,125 1127.05 1269.26 1127.05 1269.26 1127.11 1243.37 c 0,126,127 1127.19 1210.74 1127.19 1210.74 1103.5 1189 c 0,128,129 1081.08 1168.42 1081.08 1168.42 1054.61 1168.45 c 0,130,131 1030.93 1168.47 1030.93 1168.47 1004 1185 c 0,132,133 1024.39 1186.95 l 0,134,135 1038.73 1191.67 1038.73 1191.67 1040 1207 c 0,136,137 1040 1232 1040 1232 1000.5 1252 c 0,138,139 992.466 1256.07 992.466 1256.07 986.066 1256.04 c 0,140,141 961 1255.93 961 1255.93 961 1193 c 0,142,143 961 1164.99 961 1164.99 974 1131.5 c 0,144,145 987 1098.01 987 1098.01 995 1082 c 0,146,147 1018.3 1023.02 1018.3 1023.02 1032.59 1022.63 c 0,148,149 1036.22 1022.53 1036.22 1022.53 1039.27 1026.22 c 0,150,151 1040.7 1027.94 1040.7 1027.94 1042 1030.5 c 0,152,153 1057 1060.01 1057 1060.01 1039 1080 c 0,154,155 1077.99 1080 1077.99 1080 1091 1030.5 c 0,156,157 1104 981.019 1104 981.019 1104 968 c 0,158,159 1104 893.057 1104 893.057 1094.5 786.5 c 0,160,161 1092.76 724.816 l 0,162,163 1095.42 659.144 1095.42 659.144 1119 612 c 0,164,165 1129.97 589.052 1129.97 589.052 1171 527.5 c 0,166,167 1211.99 466.005 1211.99 466.005 1230 456 c 0,168,169 1251.99 443.008 1251.99 443.008 1272.5 399.5 c 0,170,171 1278.45 386.871 1278.45 386.871 1278.38 375.043 c 0,172,173 1278.2 346.131 1278.2 346.131 1242 322 c 0,174,175 1248.76 340.824 1248.76 340.824 1248.69 354.457 c 0,176,177 1248.53 387.176 1248.53 387.176 1209 390 c 0,178,179 1180.02 387.742 l 0,180,181 1171.73 385.453 1171.73 385.453 1169 380 c 0,182,183 1166.86 361.224 l 0,184,185 1167.14 356.858 1167.14 356.858 1168 352 c 0,186,187 1183 234.001 1183 234.001 1270 167 c 0,188,189 1357.01 99.9952 1357.01 99.9952 1368 -1 c 0,190,191 1372.17 -39.7089 1372.17 -39.7089 1372.1 -75.0335 c 0,192,193 1371.98 -132.791 1371.98 -132.791 1360.5 -181.5 c 0,194,195 1342.01 -259.987 1342.01 -259.987 1268 -330 c 1,0,1 701 705 m 0,116,117 736.5 753 l 0,118,119 755 778 755 778 776 793 c 0,120,121 839 831 839 831 860 763 c 0,122,123 831.214 778.397 831.214 778.397 813.857 778.333 c 0,124,125 805.285 778.302 805.285 778.302 799.5 774.5 c 0,126,127 790.855 768.819 790.855 768.819 790.629 758.624 c 0,128,129 794.49 742.017 l 0,130,131 796.315 737.74 796.315 737.74 799 733 c 0,132,133 827 679 827 679 877 735 c 0,134,135 927 791 927 791 912 878 c 0,136,137 904.001 918.996 904.001 918.996 851 1051 c 0,138,139 798 1183 798 1183 759 1150 c 0,140,141 734.385 1130 734.385 1130 734.326 1102.31 c 0,142,143 734.308 1094 734.308 1094 736.5 1085 c 0,144,145 746 1046 746 1046 750 1010 c 0,146,147 756 938 756 938 726 869.5 c 0,148,149 696 801 696 801 585 843 c 0,150,151 616 840 616 840 661 864.5 c 0,152,153 706 889 706 889 654 934 c 0,154,155 635 949 635 949 610.5 934.5 c 0,156,157 585.998 919.998 585.998 919.998 571 901 c 0,158,159 531.263 848.664 531.263 848.664 530.978 805.134 c 0,160,161 530.881 790.211 530.881 790.211 535.419 776.324 c 0,162,163 544.962 747.125 544.962 747.125 575 722.5 c 0,164,165 661 652 661 652 701 705 c 0,116,117 EndSplineSet KernsSLIF: 67 -52 0 0 99 -130 0 0 77 -104 0 0 109 -78 0 0 104 -130 0 0 72 -104 0 0 45 -169 0 0 115 -286 0 0 83 -247 0 0 121 -299 0 0 89 -257 0 0 116 -299 0 0 84 -299 0 0 118 -65 0 0 119 -230 0 0 86 -50 0 0 87 -193 0 0 EndChar StartChar: B Encoding: 66 66 16 Width: 1278 Flags: HMW HStem: 48 189<429.6 747.3> 726 257<422.4 754.5> 1447 200<399 696> 1549 111<30 212.7> VStem: 246 153<-28 1647> Fore 502 218 m 1,0,1 561.4 216.556 l 0,2,3 622.601 219 622.601 219 691 237 c 0,4,5 793.6 264 793.6 264 865.6 297 c 0,6,7 926.8 324 926.8 324 994 397 c 0,8,9 1036 442.625 1036 442.625 1036.28 481.219 c 0,10,11 1036.38 494.855 1036.38 494.855 1031.27 507.613 c 0,12,13 1027.71 516.52 1027.71 516.52 1021.6 525 c 0,14,15 1007.2 544 1007.2 544 977.2 551.5 c 0,16,17 947.2 559 947.2 559 923.2 535 c 0,18,19 907.6 519 907.6 519 914.2 492 c 0,20,21 920.8 465 920.8 465 962.8 448 c 0,22,23 930.4 424 930.4 424 872.8 455.5 c 0,24,25 815.2 487 815.2 487 824.8 540 c 0,26,27 834.4 599 834.4 599 892 634.5 c 0,28,29 949.6 670 949.6 670 930.4 721 c 0,30,31 914.8 760 914.8 760 828.4 789 c 0,32,33 742 818 742 818 659.2 824 c 0,34,35 583.6 829 583.6 829 518.2 821 c 0,36,37 452.8 813 452.8 813 422.8 749 c 0,38,39 397.6 699 397.6 699 394 644 c 0,40,41 392.642 563.434 l 0,42,43 393.092 550.121 393.092 550.121 394 537 c 0,44,45 394 505 394 505 425.8 479 c 0,46,47 441.204 466.405 441.204 466.405 461.255 466.482 c 0,48,49 482.596 466.563 482.596 466.563 509.2 481 c 0,50,51 563.2 511 563.2 511 547 549.5 c 0,52,53 530.8 588 530.8 588 487.6 600 c 0,54,55 535.6 628 535.6 628 587.2 607 c 0,56,57 641.417 584.409 641.417 584.409 641.743 534.874 c 0,58,59 641.778 529.59 641.778 529.59 641.2 524 c 0,60,61 635.2 466 635.2 466 600.4 434 c 0,62,63 568 404 568 404 494.8 354.5 c 0,64,65 421.6 305 421.6 305 432.4 260 c 0,66,67 439.6 222.999 439.6 222.999 502 218 c 0,68,-1 502 218 l 1,0,1 407.399 1024 m 1,44,45 440.211 988.385 440.211 988.385 494.485 988.133 c 0,46,47 515.008 988.038 515.008 988.038 538.6 993 c 0,48,49 710.352 1029.12 710.352 1029.12 715 1040 c 0,50,-1 855 1160 l 0,51,52 892.587 1216.39 892.587 1216.39 895 1340 c 0,53,54 891.78 1368.18 l 0,55,56 877.492 1424.08 877.492 1424.08 800.199 1467 c 0,57,58 718.469 1511.32 718.469 1511.32 663.365 1511.34 c 0,59,60 653.779 1511.34 653.779 1511.34 645 1510 c 0,61,62 624.821 1506.71 624.821 1506.71 624.832 1481.94 c 0,63,64 624.843 1459.52 624.843 1459.52 641.399 1419.5 c 0,65,66 656.36 1382.55 656.36 1382.55 656.399 1347.14 c 0,67,68 656.445 1304.45 656.445 1304.45 634.8 1264 c 0,69,70 577.198 1157.99 577.198 1157.99 480 1165 c 0,71,72 542.913 1179.56 542.913 1179.56 543.048 1262.94 c 0,73,74 543.052 1265.44 543.052 1265.44 543 1268 c 0,75,76 541.199 1356 541.199 1356 471.6 1356 c 0,77,78 412.814 1356 412.814 1356 390 1175 c 0,79,80 385.232 1137.17 385.232 1137.17 385.253 1108.14 c 0,81,82 385.299 1045.82 385.299 1045.82 407.399 1024 c 0,83,-1 407.399 1024 l 1,44,45 329 42.5 m 145,-1,-1 217.398 -13.5 l 0,45,46 189.653 -11.4947 l 0,47,48 152.289 -3.04026 152.289 -3.04026 148.549 38.5 c 0,49,50 143.6 93.5001 143.6 93.5001 170.6 138.5 c 0,51,52 171.034 92.1899 l 0,53,54 175.03 55.9341 175.03 55.9341 193.049 55.9206 c 0,55,56 196.817 55.9177 196.817 55.9177 201.199 57.5 c 0,57,58 237.199 70.5001 237.199 70.5001 243.049 146 c 0,59,60 245.057 225.875 l 0,61,62 244.13 266.908 244.13 266.908 239.449 311.5 c 0,63,64 230 401.5 230 401.5 212.449 482.5 c 0,65,66 194.897 563.5 194.897 563.5 185.898 586.5 c 0,67,68 148.1 672.5 148.1 672.5 131 707 c 0,69,70 109.776 749.815 109.776 749.815 62.5996 814.5 c 0,71,72 25.0875 865.935 25.0875 865.935 25.0878 930.344 c 0,73,74 25.0878 938.566 25.0878 938.566 25.6992 947 c 0,75,76 31.099 1021.51 31.099 1021.51 84.1992 1062.5 c 0,77,78 105.439 1078.95 105.439 1078.95 132.197 1079.03 c 0,79,80 142.86 1079.06 142.86 1079.06 154.398 1076.5 c 0,81,82 194.898 1067.5 194.898 1067.5 199.398 984.5 c 0,83,84 181.495 1010.2 181.495 1010.2 153.067 1010.13 c 0,85,86 147.206 1010.11 147.206 1010.11 140.898 1009 c 0,87,88 108.919 1003.37 108.919 1003.37 108.71 956.798 c 0,89,90 108.678 949.633 108.678 949.633 109.398 941.5 c 0,91,92 113.898 888.5 113.898 888.5 153.5 887 c 0,93,94 177.527 889.565 l 0,95,96 198.558 895.607 198.558 895.607 209.299 915.5 c 0,97,98 244.941 978.864 244.941 978.864 244.85 1117 c 0,99,100 244.398 1254.51 244.398 1254.51 239 1337.5 c 0,101,102 234.5 1398.51 234.5 1398.51 214.699 1474 c 0,103,104 197.487 1539.63 197.487 1539.63 136.544 1539.54 c 0,105,106 125.889 1539.52 125.889 1539.52 113.898 1537.5 c 0,107,108 53.5987 1527.32 53.5987 1527.32 53.5019 1477.59 c 0,109,110 53.4845 1468.68 53.4845 1468.68 55.3984 1458.5 c 0,111,112 67.9981 1391.51 67.9981 1391.51 95 1387.5 c 0,113,114 71.1185 1384.55 l 0,115,116 33.5813 1386.31 33.5813 1386.31 9.04883 1432 c 0,117,118 -9.05229 1465.71 -9.05229 1465.71 -9.0989 1503.43 c 0,119,120 -9.13456 1532.29 -9.13456 1532.29 1.39844 1563.5 c 0,121,122 48.8936 1701.35 48.8936 1701.35 184.1 1674.5 c 0,123,-1 277.25 1656 l 0,124,125 288.387 1652.52 288.387 1652.52 303.567 1652.53 c 0,126,127 337.485 1652.56 337.485 1652.56 391.6 1670 c 0,128,129 439.6 1686.01 439.6 1686.01 478.6 1730 c 0,130,131 517.645 1774.05 517.645 1774.05 550 1807 c 0,132,133 571.608 1830 571.608 1830 616.6 1849.5 c 0,134,135 661.6 1869 661.6 1869 701.2 1863 c 0,136,137 757.593 1855.01 757.593 1855.01 810.4 1807 c 0,138,139 844.491 1776.01 844.491 1776.01 844.565 1732.09 c 0,140,141 844.604 1708.46 844.604 1708.46 834.4 1680 c 0,142,143 826.002 1712.99 826.002 1712.99 757 1759 c 0,144,145 732.891 1775.07 732.891 1775.07 713.659 1775.14 c 0,146,147 686.315 1775.24 686.315 1775.24 668.833 1742.98 c 0,148,149 664.282 1734.59 664.282 1734.59 660.4 1724 c 0,150,151 659.954 1711.82 l 0,152,153 668.693 1677.46 668.693 1677.46 782.8 1621.5 c 0,154,155 918.4 1555.01 918.4 1555.01 954.4 1515 c 0,156,157 1044.4 1411.99 1044.4 1411.99 1061.8 1300 c 0,158,159 1069.05 1253.31 1069.05 1253.31 1068.98 1209.14 c 0,160,161 1068.86 1141.63 1068.86 1141.63 1051.6 1080 c 0,162,163 1043.2 1049.99 1043.2 1049.99 997 1004.5 c 0,164,165 964.388 972.382 964.388 972.382 932.075 972.403 c 0,166,167 918.612 972.412 918.612 972.412 905.2 978 c 0,168,169 938.8 1012.99 938.8 1012.99 905.2 1026 c 0,170,171 886.612 1029.18 l 0,172,173 869.691 1027.82 869.691 1027.82 865.6 1006 c 0,174,175 857.2 961 857.2 961 951.4 850 c 0,176,177 1046.91 737.47 1046.91 737.47 1080.4 784 c 0,178,179 1098.4 809 1098.4 809 1080.4 844 c 0,180,181 1062.4 879 1062.4 879 1025.2 906 c 0,182,183 1133.2 903 1133.2 903 1181.2 815.5 c 0,184,185 1229.2 728 1229.2 728 1231.6 695 c 0,186,187 1235.2 629 1235.2 629 1196.2 526 c 0,188,189 1157.2 423 1157.2 423 1157.2 339 c 0,190,191 1157.2 237.999 1157.2 237.999 1142.8 158 c 0,192,193 1128.4 78.0005 1128.4 78.0005 1085.2 27 c 0,194,195 1033.6 -33 1033.6 -33 947.2 -50 c 0,196,197 904 -59 904 -59 830.2 -52 c 0,198,199 756.4 -45 756.4 -45 725.2 -20 c 0,200,201 780.4 -32 780.4 -32 833.2 -4.5 c 0,202,203 887.95 24.0156 887.95 24.0156 856 71 c 0,204,205 835.6 101 835.6 101 731.2 97 c 0,206,207 626.8 92.9999 626.8 92.9999 584.8 90 c 0,208,-1 450.4 79.5 l 0,209,210 396.73 69.5341 396.73 69.5341 329 42.5 c 145,-1,-1 EndSplineSet EndChar StartChar: C Encoding: 67 67 9 Width: 1268 Flags: W Fore 47 1225 m 0,0,1 49.4717 1250.42 l 0,2,3 59.182 1290.3 59.182 1290.3 105 1339.5 c 0,4,5 139.698 1376.76 139.698 1376.76 170.189 1376.97 c 0,6,7 184.334 1377.07 184.334 1377.07 197.574 1369.19 c 0,8,9 205.969 1364.2 205.969 1364.2 214 1356 c 0,10,11 161.521 1347.64 161.521 1347.64 161.103 1310.92 c 0,12,13 165.255 1287.2 l 0,14,15 165.612 1286.11 165.612 1286.11 166 1285 c 0,16,17 173.846 1261.46 173.846 1261.46 188.296 1261.14 c 0,18,19 201.91 1265.14 l 0,20,21 214.659 1272.25 214.659 1272.25 231 1292 c 0,22,23 279.011 1350.02 279.011 1350.02 288 1369 c 0,24,25 316.999 1432 316.999 1432 325.5 1494 c 0,26,27 334.002 1556.01 334.002 1556.01 375 1609 c 0,28,29 407.609 1651.5 407.609 1651.5 461 1651.5 c 0,30,31 513.998 1651.01 513.998 1651.01 527 1612 c 0,32,33 477.134 1610.54 477.134 1610.54 476.205 1594.01 c 0,34,35 479.67 1583.33 l 0,36,37 480.687 1581.71 480.687 1581.71 482 1580 c 0,38,39 503 1550 503 1550 539 1571 c 0,40,41 575.016 1592.01 575.016 1592.01 592 1608 c 0,42,43 625.211 1639.88 625.211 1639.88 625.553 1659.63 c 0,44,45 622.289 1671.21 l 0,46,47 620.426 1674.05 620.426 1674.05 617.5 1676.5 c 0,48,49 605.555 1686.5 605.555 1686.5 590.873 1686.63 c 0,50,51 579.546 1686.73 579.546 1686.73 566.589 1680.95 c 0,52,53 561.901 1678.86 561.901 1678.86 557 1676 c 0,54,55 561.001 1724.01 561.001 1724.01 599 1730.5 c 0,56,57 631.988 1732.53 l 0,58,59 649.19 1731.37 649.19 1731.37 663 1725 c 0,60,61 774.955 1671.02 774.955 1671.02 848.5 1627 c 0,62,63 922.028 1582.99 922.028 1582.99 944 1574 c 0,64,65 980.724 1556.52 980.724 1556.52 1013.99 1556.61 c 0,66,67 1018.78 1556.62 1018.78 1556.62 1023.5 1557 c 0,68,69 1065.63 1556.28 l 0,70,71 1085.75 1554.21 1085.75 1554.21 1108 1549 c 0,72,73 1133.01 1543 1133.01 1543 1141 1509 c 0,74,75 1144.76 1476.5 l 0,76,77 1144.64 1459.48 1144.64 1459.48 1140 1443 c 0,78,79 1100.54 1480.38 1100.54 1480.38 1075.21 1480.38 c 0,80,81 1063.96 1480.38 1063.96 1480.38 1055.5 1473 c 0,82,83 1028 1449 1028 1449 1027 1379 c 0,84,85 1025.99 1342.76 1025.99 1342.76 1023.5 1308 c 0,86,87 1024.8 1274.25 l 0,88,89 1027.4 1257.24 1027.4 1257.24 1034 1241 c 0,90,91 1056.99 1187 1056.99 1187 1104 1173.5 c 0,92,93 1150.99 1160 1150.99 1160 1208 1157 c 0,94,95 1193.22 1128.26 1193.22 1128.26 1142.36 1128.18 c 0,96,97 1131.28 1128.16 1131.28 1128.16 1118.5 1129.5 c 0,98,99 1046.99 1137 1046.99 1137 1024 1155 c 0,100,101 960.474 1201.53 960.474 1201.53 960.191 1248.45 c 0,102,103 960.158 1253.97 960.158 1253.97 961 1259.5 c 0,104,105 961.658 1293.31 l 0,106,107 957.59 1340.52 957.59 1340.52 929 1412 c 0,108,109 904.002 1471.99 904.002 1471.99 828.5 1485 c 0,110,111 753 1498.01 753 1498.01 702 1440 c 0,112,113 663 1395 663 1395 633 1335 c 0,114,115 603.007 1275.01 603.007 1275.01 567 1229 c 0,116,117 553 1211 553 1211 495 1212.5 c 0,118,119 442.472 1213.86 442.472 1213.86 441.617 1243.51 c 0,120,121 441.528 1246.6 441.528 1246.6 442 1250 c 0,122,123 476 1233.01 476 1233.01 508 1254.5 c 0,124,125 538.826 1275.21 538.826 1275.21 539 1309 c 0,126,127 538.026 1346.98 538.026 1346.98 516 1347.5 c 0,128,129 494.008 1347.01 494.008 1347.01 476 1335 c 0,130,131 422.998 1299 422.998 1299 400 1269 c 0,132,133 376.997 1239 376.997 1239 363 1178 c 0,134,135 350.291 1125.16 350.291 1125.16 350.334 1075.45 c 0,136,137 350.354 1050.84 350.354 1050.84 353.5 1027 c 0,138,-1 373 875 l 0,139,140 377 833 377 833 392.5 790.5 c 0,141,142 408 748 408 748 402 708 c 0,143,144 384 597 384 597 276 601 c 0,145,146 297 615 297 615 321 643.5 c 0,147,148 345 672 345 672 327 704 c 0,149,150 317.431 720.586 317.431 720.586 296.467 720.691 c 0,151,152 284.569 720.75 284.569 720.75 269 715.5 c 0,153,154 226 701 226 701 222 674 c 0,155,156 203.999 574.997 203.999 574.997 203.5 494 c 0,157,158 207.196 446.84 l 0,159,160 216.755 387.21 216.755 387.21 251 323 c 0,161,162 274 279 274 279 310 272.5 c 0,163,164 325.021 273.259 l 0,165,166 349.347 280.951 349.347 280.951 361 333 c 0,167,168 367 358 367 358 360.5 370.5 c 0,169,170 354.013 382.975 354.013 382.975 340 408 c 0,171,172 364 402 364 402 386 395.5 c 0,173,174 408 389 408 389 420 365 c 0,175,176 444 317 444 317 448 270 c 0,177,178 452.001 223 452.001 223 469 172 c 0,179,180 485.999 112 485.999 112 527 100 c 0,181,182 549.843 92.7319 549.843 92.7319 568.743 92.6397 c 0,183,184 589.209 92.5398 589.209 92.5398 605.053 100.853 c 0,185,186 630.948 114.44 630.948 114.44 644.5 150.5 c 0,187,188 674 228.999 674 228.999 713 284 c 0,189,190 728 306 728 306 758.5 303 c 0,191,192 789 300 789 300 807 272 c 0,193,194 822.48 247.06 822.48 247.06 822.428 228.037 c 0,195,196 822.42 224.94 822.42 224.94 822 222 c 0,197,198 806.151 230.453 806.151 230.453 792.255 230.533 c 0,199,200 779.849 230.604 779.849 230.604 769 224 c 0,201,202 756.895 216.632 756.895 216.632 756.701 206.493 c 0,203,204 760.654 193.505 l 0,205,206 762.764 189.883 762.764 189.883 766 186 c 0,207,208 778.697 169.395 778.697 169.395 794.376 169.248 c 0,209,210 804.891 169.149 804.891 169.149 816.746 176.451 c 0,211,212 823.411 180.556 823.411 180.556 830.5 187 c 0,213,214 869 221.999 869 221.999 872 275 c 0,215,216 875 343 875 343 864 401 c 0,217,218 853.002 458.994 853.002 458.994 830 527 c 0,219,220 819 558 819 558 829.5 632 c 0,221,222 840 706 840 706 877 760 c 0,223,224 871 705 871 705 863.5 649.5 c 0,225,226 856 594 856 594 874 540 c 0,227,228 887.006 500.985 887.006 500.985 903 460.5 c 0,229,230 919 420 919 420 937 388 c 0,231,232 967.999 333.002 967.999 333.002 997 302 c 0,233,234 1020.46 276.921 1020.46 276.921 1064.21 276.712 c 0,235,236 1074.54 276.663 1074.54 276.663 1086 278 c 0,237,238 1110.37 280.089 1110.37 280.089 1110.5 306.429 c 0,239,240 1110.55 317.912 1110.55 317.912 1106 334 c 0,241,242 1118.66 334.754 l 0,243,244 1131.52 331.594 1131.52 331.594 1143 312 c 0,245,246 1157.23 287.716 1157.23 287.716 1157.45 273.956 c 0,247,248 1157.49 271.279 1157.49 271.279 1157 269 c 0,249,250 1148 226.995 1148 226.995 1130.5 212 c 0,251,252 1112.99 197 1112.99 197 1075 185 c 0,253,254 1046.42 174.52 1046.42 174.52 1011.5 174.5 c 0,255,256 978 174.999 978 174.999 951 161 c 0,257,258 914 141.001 914 141.001 909.5 67 c 0,259,260 905 -6.99995 905 -6.99995 884 -48 c 0,261,262 861 -91.0001 861 -91.0001 795 -104 c 0,263,264 769 -108.999 769 -108.999 721.5 -100 c 0,265,266 674 -91 674 -91 675 -49 c 0,267,268 706 -76 706 -76 748 -55 c 0,269,270 771 -41 771 -41 760.5 -12 c 0,271,272 750 17 750 17 728 23 c 0,273,274 701 27 701 27 672 20 c 0,275,276 643 12.9999 643 12.9999 618 4 c 0,277,278 510.997 -35.0014 510.997 -35.0014 450.5 -65 c 0,279,280 390 -95 390 -95 288 -50 c 0,281,282 255.001 -35.0002 255.001 -35.0002 248 19 c 0,283,284 240.999 73 240.999 73 266 90 c 0,285,286 268.764 57.7708 l 0,287,288 273.271 37.2823 273.271 37.2823 285 23.5 c 0,289,290 305 -3.8147e-06 305 -3.8147e-06 326 18 c 0,291,292 351 42 351 42 330 84.5 c 0,293,294 309 126.999 309 126.999 270 170 c 0,295,296 231.004 212.997 231.004 212.997 189 247 c 0,297,298 147 281 147 281 132 287 c 0,299,300 90.8733 273.479 90.8733 273.479 90.2146 252.658 c 0,301,302 93.6925 239.052 l 0,303,304 99.219 228.316 99.219 228.316 113.5 216 c 0,305,306 168.001 168.999 168.001 168.999 208 167 c 0,307,308 164.966 164.347 l 0,309,310 113.852 166.12 113.852 166.12 87.5 195 c 0,311,312 51 235.001 51 235.001 27 291 c 0,313,314 -18 394 -18 394 7 532 c 0,315,316 21 601 21 601 58.5 666.5 c 0,317,318 96 732 96 732 100 804 c 0,319,320 104.001 909 104.001 909 77.5 1014 c 0,321,322 50.9998 1119 50.9998 1119 47 1225 c 0,0,1 EndSplineSet KernsSLIF: 83 -143 0 0 115 -130 0 0 65 -65 0 0 97 -91 0 0 EndChar StartChar: D Encoding: 68 68 59 Width: 1497 Flags: HMW VStem: 205 177.5<-118.5 1622> Fore 365 -163 m 1,0,1 416.469 -202.888 416.469 -202.888 460.901 -203.041 c 0,2,3 485.532 -203.126 485.532 -203.126 508 -191 c 0,4,5 571 -156.999 571 -156.999 570 -140 c 0,6,7 568.069 -103.299 568.069 -103.299 511.5 -103 c 0,8,9 454.994 -104.001 454.994 -104.001 382.5 -118.5 c 0,10,11 309.985 -133.004 309.985 -133.004 241 -149.5 c 0,12,13 187.813 -162.219 187.813 -162.219 159.581 -162.162 c 0,14,15 151.188 -162.146 151.188 -162.146 145 -161 c 0,16,17 87.0002 -150.001 87.0002 -150.001 36.5 -93.5 c 0,18,19 -14 -37 -14 -37 31 65 c 0,20,21 32 -35 32 -35 80 -60.5 c 0,22,23 106.871 -74.7751 106.871 -74.7751 136.405 -74.7912 c 0,24,25 159.629 -74.8038 159.629 -74.8038 184.5 -66 c 0,26,27 241 -46.0003 241 -46.0003 287.5 5 c 0,28,29 334 56 334 56 334 110 c 0,30,31 334 134.001 334 134.001 303 181 c 0,32,33 272 227.999 272 227.999 240 223 c 0,34,35 200.921 216.053 200.921 216.053 200.681 163.856 c 0,36,37 200.645 155.947 200.645 155.947 201.5 147 c 0,38,39 207.999 79.0005 207.999 79.0005 242 55 c 0,40,41 198 57 198 57 186 69.5 c 0,42,43 173.999 82.0008 173.999 82.0008 166 102 c 0,44,45 146.175 148.259 146.175 148.259 146.18 200.646 c 0,46,47 146.186 259.24 146.186 259.24 171 325.5 c 0,48,49 217.997 450.995 217.997 450.995 255 533 c 0,50,51 281 592 281 592 288.5 644.5 c 0,52,53 296 697 296 697 284 804 c 0,54,55 272 905.001 272 905.001 200.5 994 c 0,56,57 129.006 1082.99 129.006 1082.99 113 1136 c 0,58,59 105.918 1159.37 105.918 1159.37 105.92 1182.3 c 0,60,61 105.924 1224.13 105.924 1224.13 129.5 1264.5 c 0,62,63 159.568 1315.99 159.568 1315.99 217.121 1316.24 c 0,64,65 229.432 1316.29 229.432 1316.29 243 1314 c 0,66,67 217.999 1303.01 217.999 1303.01 202.5 1270.5 c 0,68,69 197.239 1259.47 197.239 1259.47 197.22 1249.64 c 0,70,71 197.184 1230.54 197.184 1230.54 217 1216 c 0,72,73 229.554 1206.32 229.554 1206.32 239.508 1206.15 c 0,74,75 250.481 1209.35 l 0,76,77 269.179 1221.62 269.179 1221.62 275 1281 c 0,78,79 280.343 1335.49 280.343 1335.49 280.262 1373.43 c 0,80,81 280.192 1406.51 280.192 1406.51 276 1427 c 0,82,83 265.002 1483.99 265.002 1483.99 241 1527 c 0,84,85 216.996 1570.01 216.996 1570.01 205 1622 c 0,86,87 198.585 1647.66 198.585 1647.66 198.623 1675.88 c 0,88,89 198.661 1704.84 198.661 1704.84 205.5 1736.5 c 0,90,91 218.999 1799 218.999 1799 263 1838 c 0,92,93 292.994 1866 292.994 1866 351 1867.5 c 0,94,95 385.17 1864.86 l 0,96,97 415.91 1858.47 415.91 1858.47 430 1837 c 0,98,99 440 1820.01 440 1820.01 448 1802.5 c 0,100,101 451.449 1794.95 451.449 1794.95 451.366 1783.78 c 0,102,103 451.257 1769.05 451.257 1769.05 445 1748 c 0,104,105 439 1775 439 1775 383 1796 c 0,106,107 370.726 1800.6 370.726 1800.6 360.326 1800.69 c 0,108,109 348.764 1800.79 348.764 1800.79 339.517 1795.3 c 0,110,111 319.131 1783.21 319.131 1783.21 310 1744 c 0,112,113 296 1690 296 1690 342.5 1657 c 0,114,115 389.022 1623.98 389.022 1623.98 438 1601 c 0,116,117 481.975 1580.01 481.975 1580.01 619 1544.5 c 0,118,119 667.085 1532.04 667.085 1532.04 700.019 1532.08 c 0,120,121 760.914 1532.16 760.914 1532.16 770 1575 c 0,122,123 774.3 1598.65 774.3 1598.65 774.32 1618.05 c 0,124,125 774.385 1679.86 774.385 1679.86 731 1698.5 c 0,126,127 703.091 1710.49 703.091 1710.49 679.502 1710.62 c 0,128,129 662.09 1710.72 662.09 1710.72 647.03 1704.36 c 0,130,131 635 1698 l 0,132,133 635 1743 635 1743 670 1758.5 c 0,134,135 704.999 1773.99 704.999 1773.99 713 1775 c 0,136,137 760 1774.5 l 0,138,139 802.004 1770.17 802.004 1770.17 824 1750.5 c 0,140,141 857.006 1720.99 857.006 1720.99 872 1694 c 0,142,143 896.002 1649 896.002 1649 913.5 1585 c 0,144,145 930.999 1521 930.999 1521 973 1494 c 0,146,147 1042 1450.01 1042 1450.01 1072 1440 c 0,148,149 1102 1429.99 1102 1429.99 1177 1419 c 0,150,151 1282.99 1403 1282.99 1403 1308 1317 c 0,152,153 1313.32 1295.3 1313.32 1295.3 1313.3 1276.45 c 0,154,155 1313.22 1206.7 1313.22 1206.7 1240 1176 c 0,156,157 1260.26 1204.06 1260.26 1204.06 1260.48 1235.14 c 0,158,159 1260.55 1243.95 1260.55 1243.95 1259 1253 c 0,160,161 1252.76 1289.51 1252.76 1289.51 1206.87 1289.54 c 0,162,163 1201.23 1289.55 1201.23 1289.55 1195 1289 c 0,164,165 1174.85 1287.11 1174.85 1287.11 1174.92 1260.84 c 0,166,167 1174.96 1245.39 1174.96 1245.39 1182 1221.5 c 0,168,169 1201.02 1156.95 1201.02 1156.95 1214 1130 c 0,170,171 1274.01 1003.97 1274.01 1003.97 1353 887 c 0,172,173 1432 770.008 1432 770.008 1438 703 c 0,174,175 1437.29 667.063 l 0,176,177 1429.48 607.261 1429.48 607.261 1377 554 c 0,178,179 1359 536 1359 536 1318.5 532.5 c 0,180,181 1285.16 533.1 l 0,182,183 1266.74 535.756 1266.74 535.756 1253 544 c 0,184,185 1292 544 1292 544 1311.5 575 c 0,186,187 1320.25 588.918 1320.25 588.918 1320.44 600.216 c 0,188,189 1317.5 612.987 l 0,190,191 1314.39 618.996 1314.39 618.996 1308 624 c 0,192,193 1266 653 1266 653 1237.5 607.5 c 0,194,195 1209 562 1209 562 1200 535 c 0,196,197 1198.96 531.908 1198.96 531.908 1180 489.5 c 0,198,199 1161.01 447.043 1161.01 447.043 1144.5 396.5 c 0,200,201 1128 346 1128 346 1123.5 303.5 c 0,202,203 1124.19 278.807 l 0,204,205 1128.4 260.303 1128.4 260.303 1146 259 c 0,206,207 1188 255 1188 255 1203 276 c 0,208,209 1218.01 297.013 1218.01 297.013 1232 339 c 0,210,211 1252.93 293.919 1252.93 293.919 1253.12 259.927 c 0,212,213 1253.22 242.802 1253.22 242.802 1248.05 228.491 c 0,214,215 1244.37 218.279 1244.37 218.279 1238 209.5 c 0,216,217 1205 164 1205 164 1175 152 c 0,218,219 1085 115.002 1085 115.002 1029.5 103.5 c 0,220,221 974 91.9999 974 91.9999 930.5 75.5 c 0,222,223 887 59 887 59 844.5 22.5 c 0,224,225 801.998 -14.0021 801.998 -14.0021 740 -103 c 0,226,227 619.211 -271.373 619.211 -271.373 522.285 -271.438 c 0,228,229 513.29 -271.444 513.29 -271.444 504.5 -270 c 0,230,231 401 -253 401 -253 365 -163 c 1,0,1 725 192 m 0,122,123 749 216 749 216 794.5 272 c 0,124,125 840 328 840 328 855 355 c 0,126,127 879.999 397.998 879.999 397.998 888.5 438.5 c 0,128,129 897 479 897 479 906 529 c 0,130,131 922 613 922 613 979 629.5 c 0,132,133 1000.57 635.743 1000.57 635.743 1016.41 635.759 c 0,134,135 1042.44 635.784 1042.44 635.784 1053 619 c 0,136,137 1002 619 1002 619 984 586 c 0,138,139 966 553 966 553 977 538 c 0,140,141 989.486 518.904 989.486 518.904 1004.74 518.755 c 0,142,143 1015.01 518.656 1015.01 518.656 1026.55 527.159 c 0,144,145 1044.5 540.4 1044.5 540.4 1065.5 574.5 c 0,146,147 1120 663.009 1120 663.009 1126 744 c 0,148,149 1130.99 817 1130.99 817 1094.5 950.5 c 0,150,151 1066.07 1054.48 1066.07 1054.48 1021.56 1054.42 c 0,152,153 1008.93 1054.4 1008.93 1054.4 995 1046 c 0,154,155 975.667 1034 975.667 1034 975.667 1018 c 0,156,157 975.667 1010 975.667 1010 980.5 1001 c 0,158,159 995.002 973.998 995.002 973.998 1038 962 c 0,160,161 954 929 954 929 929.5 1003.5 c 0,162,163 904.996 1078.02 904.996 1078.02 894 1138 c 0,164,165 876.999 1227 876.999 1227 805.5 1282.5 c 0,166,167 734 1338 734 1338 651.5 1350 c 0,168,169 605.665 1352.79 l 0,170,171 548.883 1351.23 548.883 1351.23 498 1324 c 0,172,173 427.002 1286.01 427.002 1286.01 412 1188 c 0,174,175 405 1146 405 1146 419.5 1117.5 c 0,176,177 434 1089 434 1089 470 1098 c 0,178,179 485 1101.75 485 1101.75 485.375 1115.63 c 0,180,181 484 1126 l 0,182,183 477.997 1149.01 477.997 1149.01 454 1166 c 0,184,185 479.875 1167.62 l 0,186,187 516.252 1164.25 516.252 1164.25 538 1126 c 0,188,189 546.998 1108 546.998 1108 553 1077.5 c 0,190,191 553.751 1052.78 l 0,192,193 551.262 1032.3 551.262 1032.3 539 1009 c 0,194,195 458.999 855.998 458.999 855.998 437.5 671.5 c 0,196,197 416 487 416 487 428 407 c 0,198,199 445 284 445 284 488.5 279.5 c 0,200,201 532 275 532 275 539 318 c 0,202,203 538.454 335.091 l 0,204,205 531.345 359 531.345 359 484 359 c 0,206,207 490 374 490 374 509.5 376 c 0,208,209 529 378 529 378 541 381 c 0,210,211 567.678 382.442 l 0,212,213 608.823 378.097 608.823 378.097 618.5 327 c 0,214,215 630.999 261.003 630.999 261.003 643 220 c 0,216,217 652 181 652 181 678 176.5 c 0,218,219 697.181 176.647 l 0,220,221 712.042 179.66 712.042 179.66 725 192 c 0,122,123 EndSplineSet KernsSLIF: 90 -182 0 0 122 -143 0 0 97 -207 0 0 65 -150 0 0 EndChar StartChar: E Encoding: 69 69 53 Width: 1257 Flags: HMW HStem: 47 32.5<30 142.5> 89 202.5<224.5 921.5> 729 161<354 767> 1357 203<404 858> VStem: 117.5 176.5<365 1523> Fore 702 114 m 1,0,1 611.006 112.001 611.006 112.001 515.5 93.5 c 0,2,3 420 75.0001 420 75.0001 339 36 c 0,4,5 268 1.99995 268 1.99995 178.5 -13.5 c 0,6,7 88.9995 -29 88.9995 -29 30 47 c 0,8,9 -15 107 -15 107 15 159.5 c 0,10,11 40.0002 203.25 40.0002 203.25 98.3333 203.597 c 0,12,13 110 203.667 110 203.667 123 202 c 0,14,-1 82.5 186.5 l 0,15,16 64.901 179.851 64.901 179.851 64.7384 152.708 c 0,17,18 64.6931 145.149 64.6931 145.149 66 136 c 0,19,20 75 70 75 70 142.5 79.5 c 0,21,22 210 88.9999 210 88.9999 225 162 c 0,23,24 229.413 184.556 229.413 184.556 229.378 216.128 c 0,25,26 229.341 248.943 229.341 248.943 224.5 291.5 c 0,27,28 215.001 375 215.001 375 152 384 c 0,29,30 129.001 387 129.001 387 117.5 365 c 0,31,32 105.999 343 105.999 343 110 322 c 0,33,34 117.001 279 117.001 279 152 244 c 0,35,36 84.0005 262 84.0005 262 60 326 c 0,37,38 14 446 14 446 47.5 574 c 0,39,40 80.9999 702 80.9999 702 102 820 c 0,41,42 121.001 932.001 121.001 932.001 124.5 984 c 0,43,44 124.02 1053.51 l 0,45,46 121.855 1094.37 121.855 1094.37 116 1150 c 0,47,48 103.999 1246.01 103.999 1246.01 60.5 1348.5 c 0,49,50 17 1450.99 17 1450.99 22 1545 c 0,51,52 24 1585.01 24 1585.01 32 1606.5 c 0,53,54 40 1627.99 40 1627.99 71 1653 c 0,55,56 106.829 1682.31 106.829 1682.31 136.69 1682.29 c 0,57,58 180.171 1682.25 180.171 1682.25 211 1620 c 0,59,60 188.421 1640.26 188.421 1640.26 166.513 1640.58 c 0,61,62 147.914 1637.21 l 0,63,64 141.427 1634.75 141.427 1634.75 135 1630.5 c 0,65,66 110.758 1614.45 110.758 1614.45 110.555 1588.31 c 0,67,68 110.455 1575.46 110.455 1575.46 117 1558 c 0,69,70 135.515 1508.3 135.515 1508.3 195 1508 c 0,71,72 253.999 1509.01 253.999 1509.01 294 1523 c 0,73,74 395.012 1556 395.012 1556 501.5 1639.5 c 0,75,76 591.424 1710.01 591.424 1710.01 685.277 1710.28 c 0,77,78 702.572 1710.33 702.572 1710.33 720 1708 c 0,79,80 764 1702 764 1702 787.5 1661.5 c 0,81,82 811 1621 811 1621 787 1582 c 0,83,84 776.899 1645.98 776.899 1645.98 721.089 1646.53 c 0,85,86 698.5 1644.5 l 0,87,88 623.013 1631.18 623.013 1631.18 623 1584 c 0,89,90 623 1526.01 623 1526.01 680.99 1525.71 c 0,91,92 698 1525.62 698 1525.62 720 1530.5 c 0,93,94 817.381 1552.08 817.381 1552.08 858 1560 c 0,95,96 911.778 1569.96 911.778 1569.96 983.5 1580 c 0,97,98 1036.93 1583.69 l 0,99,100 1076.51 1583.35 1076.51 1583.35 1110 1573 c 0,101,102 1244.01 1531 1244.01 1531 1255 1399 c 0,103,104 1249 1432 1249 1432 1232 1452 c 0,105,106 1215.02 1471.98 1215.02 1471.98 1200 1485 c 0,107,108 1153.97 1523.47 1153.97 1523.47 1089.78 1523.48 c 0,109,110 1060.52 1523.48 1060.52 1523.48 1027.5 1515.5 c 0,111,112 921.99 1490 921.99 1490 863 1441 c 0,113,114 833.001 1415.01 833.001 1415.01 827.5 1379 c 0,115,116 828.033 1360.63 l 0,117,118 833.454 1337.82 833.454 1337.82 864 1324 c 0,119,120 869.974 1321.01 869.974 1321.01 888.5 1315.5 c 0,121,122 900.641 1311.89 900.641 1311.89 918.181 1311.94 c 0,123,124 927.351 1311.97 927.351 1311.97 938 1313 c 0,125,126 875 1259 875 1259 740 1322 c 0,127,128 605 1385 605 1385 514 1385 c 0,129,130 441.992 1383.99 441.992 1383.99 404 1357 c 0,131,132 378.16 1338.64 378.16 1338.64 378.214 1299.01 c 0,133,134 378.239 1280.81 378.239 1280.81 384 1257 c 0,135,136 393 1218 393 1218 423.5 1164 c 0,137,138 454 1110 454 1110 434 1071 c 0,139,140 409 1021.01 409 1021.01 358 1023 c 0,141,142 408 1083 408 1083 370 1108.5 c 0,143,144 353.553 1119.54 353.553 1119.54 338.791 1119.8 c 0,145,146 322.286 1116.51 l 0,147,148 312.191 1112.14 312.191 1112.14 303 1102 c 0,149,150 273.134 1069.54 273.134 1069.54 273.197 1022.74 c 0,151,152 273.231 997.463 273.231 997.463 282 968 c 0,153,154 307 884 307 884 385 891 c 0,155,156 455 897 455 897 507.5 911 c 0,157,158 559.99 924.997 559.99 924.997 623 948 c 0,159,160 702 976 702 976 804 940 c 0,161,162 906 904 906 904 884 793 c 0,163,164 876 837 876 837 846 869.5 c 0,165,166 816 902 816 902 767 890 c 0,167,168 726.999 879.999 726.999 879.999 705.5 844.5 c 0,169,170 684 809 684 809 677 773 c 0,171,172 658 674 658 674 626 610.5 c 0,173,174 604.458 567.752 604.458 567.752 542.58 567.831 c 0,175,176 512.542 567.869 512.542 567.869 473 578 c 0,177,178 561 602 561 602 561 645 c 0,179,180 561 720 561 720 485.5 729 c 0,181,182 447.32 733.551 447.32 733.551 414.125 733.499 c 0,183,184 381.68 733.449 381.68 733.449 354 729 c 0,185,186 284 717 284 717 283 654 c 0,187,188 280 600 280 600 315 596.5 c 0,189,190 328.846 598.578 l 0,191,192 344.765 606.4 344.765 606.4 344.877 641.401 c 0,193,194 344.905 649.899 344.905 649.899 344 660 c 0,195,196 392 607 392 607 391 573 c 0,197,198 389.999 514.999 389.999 514.999 357.5 484.5 c 0,199,200 325 454.001 325 454.001 325 410 c 0,201,202 325 332 325 332 369 336.5 c 0,203,204 413 341 413 341 471 370 c 0,205,206 529.005 399.002 529.005 399.002 585.5 422.5 c 0,207,208 606.644 431.295 606.644 431.295 623.377 431.196 c 0,209,210 651.356 431.031 651.356 431.031 667 406 c 0,211,212 677.588 389.235 677.588 389.235 677.666 368.967 c 0,213,214 677.676 366.265 677.676 366.265 677.5 363.5 c 0,215,216 676 340 676 340 652 333 c 0,217,218 652.989 347.212 l 0,219,220 650.646 358.106 650.646 358.106 635.616 358.287 c 0,221,222 630.147 358.352 630.147 358.352 623 357 c 0,223,224 563 343 563 343 603 291 c 0,225,226 630 254 630 254 697.5 254 c 0,227,228 765 254 765 254 800 275 c 0,229,230 851 305 851 305 888 352 c 0,231,232 925 399 925 399 976 426 c 0,233,234 993.321 434.66 993.321 434.66 1010.43 434.679 c 0,235,236 1046.68 434.717 1046.68 434.717 1082 396 c 0,237,238 1134.01 339 1134.01 339 1076 291 c 0,239,240 1101.99 369 1101.99 369 1025 361 c 0,241,242 967.999 353.999 967.999 353.999 961.5 300.5 c 0,243,244 960.341 260.536 l 0,245,246 962.497 231.61 962.497 231.61 974 208 c 0,247,248 998 157 998 157 1055 116.5 c 0,249,250 1112 76 1112 76 1148 34 c 0,251,252 1185 -7.99286 1185 -7.99286 1197 -81.5 c 0,253,254 1199.64 -120.957 l 0,255,256 1197.74 -168.802 1197.74 -168.802 1169 -204 c 0,257,258 1173.43 -171.487 1173.43 -171.487 1173.38 -146.126 c 0,259,260 1173.32 -120.019 1173.32 -120.019 1168.5 -101.5 c 0,261,262 1159.01 -65.0068 1159.01 -65.0068 1111 -17 c 0,263,264 1028.99 64.0016 1028.99 64.0016 921.5 89 c 0,265,266 814.002 114 814.002 114 702 114 c 1,0,1 EndSplineSet KernsSLIF: 83 -130 0 0 115 -130 0 0 EndChar StartChar: F Encoding: 70 70 8 Width: 1352 Flags: MW HStem: 705 181<397 741> 1396 225<414 1092> VStem: 110 217<38 1678> Fore 642 839 m 1,0,1 644 729 644 729 741 705 c 0,2,3 769.434 702.509 l 0,4,5 803.088 704.294 803.088 704.294 834.5 729 c 0,6,7 879 763 l 0,8,9 873 739 873 739 845.5 693 c 0,10,11 818 647 818 647 773 627 c 0,12,13 719 607 719 607 685.5 614.5 c 0,14,15 652 622 652 622 613 634 c 0,16,17 562 653 562 653 505.5 704 c 0,18,19 466.31 739.375 466.31 739.375 424.956 739.628 c 0,20,21 408.667 739.728 408.667 739.728 392.041 734.379 c 0,22,23 390.023 733.73 390.023 733.73 388 733 c 0,24,25 340 708 340 708 329.5 679.5 c 0,26,27 319 651 319 651 312 621 c 0,28,29 306 585 306 585 292 478 c 0,30,31 278 371 278 371 370 376 c 0,32,33 424 427 424 427 347 473 c 0,34,35 419 467 419 467 446 407 c 0,36,37 446 353 446 353 433.5 330 c 0,38,39 420.995 306.989 420.995 306.989 401 265 c 0,40,41 375.999 232 375.999 232 362 187.5 c 0,42,-1 346 137 l 0,43,44 324 87.0005 324 87.0005 327 38 c 0,45,46 327 -20 327 -20 350.5 -86.5 c 0,47,48 374.001 -153.001 374.001 -153.001 428 -195 c 0,49,50 365.001 -195 365.001 -195 323.5 -122.5 c 0,51,52 282.002 -50.0044 282.002 -50.0044 266 -3 c 0,53,54 256 75 256 75 228.5 101.5 c 0,55,56 201.001 128.001 201.001 128.001 170 137 c 0,57,58 165.999 137 165.999 137 132.5 129.5 c 0,59,60 99.0005 122 99.0005 122 101 62 c 0,61,-1 115.5 33.5 l 0,62,63 130.001 5 130.001 5 178 -5 c 0,64,65 150.278 -14.0397 150.278 -14.0397 128.549 -13.9998 c 0,66,67 114.222 -13.9735 114.222 -13.9735 102.5 -10 c 0,68,69 72.9999 4.76837e-06 72.9999 4.76837e-06 61 3 c 0,70,71 32 18 32 18 20 48.5 c 0,72,73 8 78.9999 8 78.9999 8 97 c 0,74,75 15.0001 179.999 15.0001 179.999 77 241 c 0,76,77 93.9998 251.999 93.9998 251.999 105 282 c 0,78,79 115.999 312 115.999 312 123 336 c 0,80,81 128.001 354.007 128.001 354.007 140.5 444.5 c 0,82,83 149 506.041 149 506.041 148.946 535.905 c 0,84,85 148.92 549.96 148.92 549.96 147 557 c 0,86,87 146.947 572.694 l 0,88,89 142.652 589.782 142.652 589.782 119 603 c 0,90,91 78.9999 606 78.9999 606 86.5 552.5 c 0,92,93 93.9998 499.001 93.9998 499.001 108 486 c 0,94,95 69 486 69 486 44 527 c 0,96,97 20 554 20 554 23 583 c 0,98,99 26 612 26 612 35 640 c 0,100,101 53 689 53 689 86 731.5 c 0,102,103 119 774 119 774 143 820 c 0,104,105 145.997 843.974 145.997 843.974 152.5 889 c 0,106,107 152.986 918.716 l 0,108,109 149.654 945.423 149.654 945.423 132 967 c 0,110,111 129 973 129 973 83 1040.5 c 0,112,113 38 1106.99 38 1106.99 37 1108 c 0,114,115 30.0021 1120 30.0021 1120 17 1176 c 0,116,117 9.22428 1209.49 9.22428 1209.49 9.31933 1241.2 c 0,118,119 9.38319 1262.5 9.38319 1262.5 13 1283 c 0,120,121 13 1311.99 13 1311.99 42.5 1349 c 0,122,123 70.2188 1383.77 70.2188 1383.77 104.576 1384.1 c 0,124,125 106.774 1384.12 106.774 1384.12 109 1384 c 0,126,127 82 1339 82 1339 95.5 1289.5 c 0,128,129 109 1240 109 1240 161 1252 c 0,130,131 176.009 1255 176.009 1255 193.5 1268 c 0,132,133 211.001 1281.01 211.001 1281.01 227 1329 c 0,134,135 236 1369.99 236 1369.99 233 1411.5 c 0,136,137 230.001 1452.99 230.001 1452.99 224 1495 c 0,138,139 215 1547.99 215 1547.99 149 1537 c 0,140,141 113 1516.15 113 1516.15 113 1499 c 0,142,143 114.998 1483 114.998 1483 130 1444 c 0,144,145 68.9998 1495 68.9998 1495 66 1559 c 0,146,147 66.2889 1594.43 l 0,148,149 72.286 1642.5 72.286 1642.5 110 1678 c 0,150,151 159.023 1705.71 159.023 1705.71 195.936 1705.91 c 0,152,153 210.973 1705.99 210.973 1705.99 224 1701.5 c 0,154,155 269 1686.01 269 1686.01 328 1658 c 0,156,-1 414 1621 l 0,157,158 452.534 1610.88 452.534 1610.88 492.001 1610.98 c 0,159,160 534.461 1611.08 534.461 1611.08 578 1623 c 0,161,162 662 1645.99 662 1645.99 743 1662 c 0,163,164 815 1672.01 815 1672.01 877.5 1668 c 0,165,166 940.046 1663.99 940.046 1663.99 1010 1652 c 0,167,168 1102.99 1608.01 1102.99 1608.01 1115 1592.5 c 0,169,-1 1148 1551 l 0,170,171 1128.02 1558.99 1128.02 1558.99 1114 1568.5 c 0,172,173 1099.99 1578.01 1099.99 1578.01 1070 1583 c 0,174,175 991 1583 991 1583 986 1543.5 c 0,176,177 981 1504 981 1504 972 1504 c 0,178,179 987.996 1452.01 987.996 1452.01 1008 1434.5 c 0,180,181 1027.99 1417 1027.99 1417 1092 1396 c 0,182,183 1224 1402 1224 1402 1237.5 1459.5 c 0,184,185 1251.02 1517.06 1251.02 1517.06 1288 1628 c 0,186,-1 1272.5 1524 l 0,187,188 1257.99 1426.99 1257.99 1426.99 1240 1409 c 0,189,190 1215.99 1375.99 1215.99 1375.99 1174.5 1356 c 0,191,192 1132.97 1335.99 1132.97 1335.99 1112 1334 c 0,193,194 1075.74 1331.76 l 0,195,196 1068.75 1331.8 1068.75 1331.8 1060.5 1332 c 0,197,198 1017.99 1333.01 1017.99 1333.01 1006 1345 c 0,199,200 979 1355.01 979 1355.01 957.5 1369 c 0,201,-1 913 1398 l 0,202,203 764 1482 764 1482 702.5 1477.5 c 0,204,205 640.987 1473 640.987 1473 496 1409 c 0,206,207 460 1383.99 460 1383.99 473.5 1352 c 0,208,209 487.002 1320 487.002 1320 518 1320 c 0,210,211 543.105 1321.01 543.105 1321.01 572.5 1325 c 0,212,213 602.002 1329.01 602.002 1329.01 626 1383 c 0,214,215 623 1369.01 623 1369.01 623.5 1336.5 c 0,216,217 620.162 1310.39 l 0,218,219 615.024 1291.76 615.024 1291.76 602 1274 c 0,220,221 521.986 1225.99 521.986 1225.99 436.5 1203 c 0,222,223 351.002 1180.01 351.002 1180.01 333 1058 c 0,224,225 329.412 1045.28 329.412 1045.28 329.388 1030.91 c 0,226,227 329.34 1001.22 329.34 1001.22 344.5 964.5 c 0,228,229 367 910 367 910 397 886 c 0,230,231 406.248 868.824 406.248 868.824 439.281 868.668 c 0,232,233 456.251 868.588 456.251 868.588 479.5 873 c 0,234,235 548 886 548 886 557 934 c 0,236,237 560 994 560 994 526 1001.5 c 0,238,239 492 1009 492 1009 457 991 c 0,240,241 475.004 1027.01 475.004 1027.01 505 1044 c 0,242,243 600 1080 600 1080 630 996 c 0,244,245 635 961 635 961 637.5 918 c 0,246,-1 642 839 l 1,0,1 EndSplineSet KernsSLIF: 116 -286 0 0 84 -169 0 0 45 -208 0 0 46 -234 0 0 44 -273 0 0 65 -491 0 0 97 -470 0 0 EndChar StartChar: G Encoding: 71 71 12 Width: 1278 Flags: W Fore 586 -123 m 0,0,1 512 -115.001 512 -115.001 398.5 -55.5 c 0,2,3 285.001 3.99925 285.001 3.99925 251 54 c 0,4,5 140.158 218.532 140.158 218.532 139.923 377.813 c 0,6,7 139.886 402.469 139.886 402.469 142.5 427 c 0,8,9 162 610 162 610 93 791 c 0,10,11 70.9999 847 70.9999 847 40 906.5 c 0,12,13 8.99995 966 8.99995 966 12 1002 c 0,14,15 17 1065 17 1065 57 1086 c 0,16,17 97.0001 1107 97.0001 1107 130 1095 c 0,18,19 112.083 1092.92 l 0,20,21 89.0771 1084.96 89.0771 1084.96 75.5 1049 c 0,22,23 70.7155 1036.33 70.7155 1036.33 70.5795 1026.33 c 0,24,25 73.8997 1010.88 l 0,26,27 81.7288 995.636 81.7288 995.636 108 991 c 0,28,29 192 975 192 975 163.5 1093.5 c 0,30,31 135.001 1212 135.001 1212 134 1245 c 0,32,33 127.998 1329.02 127.998 1329.02 125 1379.5 c 0,34,35 122 1430.01 122 1430.01 161 1516 c 0,36,37 180.003 1560 180.003 1560 240 1560 c 0,38,39 300.012 1560 300.012 1560 330 1547 c 0,40,41 279 1544 279 1544 259.5 1515.5 c 0,42,43 250.674 1502.6 250.674 1502.6 250.759 1491.65 c 0,44,45 250.863 1478.4 250.863 1478.4 264 1468 c 0,46,47 279.59 1455.3 279.59 1455.3 296.138 1455.14 c 0,48,49 306.108 1455.04 306.108 1455.04 316.425 1459.5 c 0,50,51 348.303 1473.27 348.303 1473.27 383.5 1530.5 c 0,52,53 430.286 1606.57 430.286 1606.57 430.388 1650.76 c 0,54,55 430.429 1668.43 430.429 1668.43 423 1681 c 0,56,57 405 1709.99 405 1709.99 376 1709.5 c 0,58,59 347.026 1709.01 347.026 1709.01 320 1698 c 0,60,61 293.003 1686 293.003 1686 277.5 1657 c 0,62,63 262 1628.01 262 1628.01 244 1600 c 0,64,65 242.736 1626.39 l 0,66,67 245.946 1664.86 245.946 1664.86 274.5 1724.5 c 0,68,69 314 1807 314 1807 381 1810 c 0,70,71 436.151 1813.01 436.151 1813.01 515.5 1820 c 0,72,73 595.113 1827.01 595.113 1827.01 640 1833 c 0,74,75 754 1848 754 1848 911 1809 c 0,76,77 1067.95 1770.01 1067.95 1770.01 1167 1743 c 0,78,79 1216.13 1728.55 1216.13 1728.55 1216.08 1665.83 c 0,80,81 1216.07 1663.45 1216.07 1663.45 1216 1661 c 0,82,83 1214.01 1594.01 1214.01 1594.01 1170 1566 c 0,84,85 1173.89 1576.83 1173.89 1576.83 1173.84 1587.2 c 0,86,87 1173.72 1614.17 1173.72 1614.17 1147 1638 c 0,88,89 1131.29 1652.01 1131.29 1652.01 1115.75 1652.32 c 0,90,91 1099.92 1649.06 l 0,92,93 1086.9 1643.41 1086.9 1643.41 1074 1628 c 0,94,95 1061.39 1613.19 1061.39 1613.19 1061.26 1591.32 c 0,96,97 1061.16 1575.07 1061.16 1575.07 1067.94 1554.92 c 0,98,99 1068.68 1552.73 1068.68 1552.73 1069.5 1550.5 c 0,100,-1 1100 1467 l 0,101,102 1130.03 1374.92 1130.03 1374.92 1152 1321 c 0,103,104 1160.8 1299.4 1160.8 1299.4 1160.8 1271.08 c 0,105,106 1160.8 1229.03 1160.8 1229.03 1141 1171 c 0,107,108 1119 1108.01 1119 1108.01 1067.5 1054.5 c 0,109,110 1016.01 1001 1016.01 1001 901 976 c 0,111,112 945.016 1009.01 945.016 1009.01 1008.5 1039.5 c 0,113,114 1068.86 1068.49 1068.86 1068.49 1069.13 1152.16 c 0,115,116 1069.15 1156.51 1069.15 1156.51 1069 1161 c 0,117,118 1066 1201 1066 1201 1016.5 1247.5 c 0,119,120 967 1294 967 1294 918 1273 c 0,121,122 867.288 1251.94 867.288 1251.94 866.93 1207.55 c 0,123,124 867 1203.5 l 0,125,126 868.999 1156 868.999 1156 887 1111 c 0,127,128 830 1150 830 1150 838.5 1231 c 0,129,130 847 1311.99 847 1311.99 876 1343 c 0,131,132 889.997 1358 889.997 1358 904 1387 c 0,133,134 914.347 1408.43 914.347 1408.43 914.315 1423.31 c 0,135,136 914.304 1428.57 914.304 1428.57 913 1433 c 0,137,138 901.003 1475.99 901.003 1475.99 839 1511.5 c 0,139,140 809.887 1528.17 809.887 1528.17 782.758 1528.19 c 0,141,142 752.113 1528.22 752.113 1528.22 724 1507 c 0,143,144 697 1486 697 1486 708 1436.5 c 0,145,146 718.999 1387 718.999 1387 720 1355 c 0,147,148 721 1269.01 721 1269.01 625 1256 c 0,149,150 604.735 1257.19 l 0,151,152 590.855 1260.5 590.855 1260.5 576 1270.5 c 0,153,154 549.997 1288.01 549.997 1288.01 542 1325 c 0,155,156 563.197 1315.63 563.197 1315.63 580.749 1315.5 c 0,157,158 593.765 1315.4 593.765 1315.4 604.776 1320.38 c 0,159,160 609.038 1322.31 609.038 1322.31 613 1325 c 0,161,162 641 1344.01 641 1344.01 623 1391 c 0,163,164 614 1412 614 1412 563.5 1424 c 0,165,166 540.067 1429.57 540.067 1429.57 521.906 1429.54 c 0,167,168 500.936 1429.5 500.936 1429.5 487 1422 c 0,169,170 421 1386 421 1386 401 1249 c 0,171,172 394.695 1205.81 394.695 1205.81 394.751 1169.67 c 0,173,174 394.872 1091.19 394.872 1091.19 425 1046 c 0,175,176 484.994 954.01 484.994 954.01 527 883 c 0,177,178 548.851 846.061 548.851 846.061 548.778 807.498 c 0,179,180 548.71 771.939 548.71 771.939 530 735 c 0,181,182 518 711 518 711 463 699 c 0,183,184 408 687 408 687 387 707 c 0,185,186 440 716 440 716 450 752 c 0,187,188 465 819 465 819 386 842 c 0,189,190 358.249 844.514 l 0,191,192 341.329 844.06 341.329 844.06 319 840 c 0,193,194 275 832 275 832 254 795 c 0,195,196 241.999 773.999 241.999 773.999 241.5 703 c 0,197,198 245.037 633.868 l 0,199,200 249.259 594.007 249.259 594.007 258.5 551.5 c 0,201,202 276 471 276 471 315 401 c 0,203,204 354 331 354 331 422 313 c 0,205,206 493 294 493 294 551.5 330 c 0,207,208 610 366 610 366 663 385 c 0,209,210 725.305 407.252 725.305 407.252 765.019 407.222 c 0,211,212 796.695 407.198 796.695 407.198 814 393 c 0,213,214 835.408 374.111 835.408 374.111 835.407 352.249 c 0,215,216 835.407 339.389 835.407 339.389 828 325.5 c 0,217,218 808 288 808 288 772 291 c 0,219,220 791.412 305.236 791.412 305.236 791.564 318.842 c 0,221,222 791.647 326.265 791.647 326.265 786 333.5 c 0,223,224 772.461 350.846 772.461 350.846 760 351 c 0,225,226 709 337 709 337 715.5 305.5 c 0,227,228 722 274 722 274 746 262 c 0,229,230 761.411 253.594 761.411 253.594 778.11 253.469 c 0,231,232 791.358 253.369 791.358 253.369 805.415 258.481 c 0,233,234 824.232 265.322 824.232 265.322 844.5 281.5 c 0,235,236 899 325 899 325 918 361 c 0,237,238 930 383 930 383 921 437 c 0,239,240 912 491 912 491 885 502 c 0,241,242 809.779 529.799 809.779 529.799 747.592 529.855 c 0,243,244 733.722 529.868 733.722 529.868 720.5 528.5 c 0,245,246 648 521 648 521 548 528 c 0,247,248 409 537 409 537 353 577 c 0,249,250 297 617 297 617 297 668 c 0,251,252 297 691 297 691 315.5 722 c 0,253,254 334 753 334 753 392 761 c 0,255,256 341 742 341 742 334 692.5 c 0,257,258 334.029 667.297 l 0,259,260 339.17 637.192 339.17 637.192 371 622 c 0,261,262 467 573 467 573 574 628 c 0,263,264 681 683 681 683 717 734 c 0,265,266 757 791 757 791 829 799.5 c 0,267,268 880.389 802.174 l 0,269,270 911.309 800.99 911.309 800.99 926 791 c 0,271,272 944 778 944 778 955 748 c 0,273,274 966 718 966 718 942 693 c 0,275,276 943 744 943 744 896.5 738.5 c 0,277,278 850 733 850 733 849 715 c 0,279,280 846 677 846 677 881 642.5 c 0,281,282 916 608 916 608 985 612 c 0,283,284 1048 615 1048 615 1120 580 c 0,285,286 1192 545 1192 545 1198 506 c 0,287,288 1198.65 470.761 l 0,289,290 1196.72 451.59 1196.72 451.59 1189.5 435 c 0,291,292 1176 404.001 1176 404.001 1138 403 c 0,293,294 1151.85 417.478 1151.85 417.478 1152.03 429.782 c 0,295,296 1152.12 436.49 1152.12 436.49 1147.5 443.5 c 0,297,298 1139.48 454.732 1139.48 454.732 1127.95 455.048 c 0,299,300 1114 452 l 0,301,302 1085.01 439 1085.01 439 1096 405.5 c 0,303,304 1107.01 371.953 1107.01 371.953 1113 345 c 0,305,306 1134 242.792 1134 242.792 1133.93 166.08 c 0,307,308 1133.9 133.199 1133.9 133.199 1130 105 c 0,309,310 1116.99 10.9955 1116.99 10.9955 1090 -10 c 0,311,312 1051 -40.0026 1051 -40.0026 994.5 -57 c 0,313,314 938 -73.9999 938 -73.9999 869 -34 c 0,315,316 845.649 -21.9218 845.649 -21.9218 845.639 20.6278 c 0,317,318 845.636 30.9221 845.636 30.9221 847 43 c 0,319,320 852 15 852 15 888 9 c 0,321,322 924 3 924 3 940 59 c 0,323,324 949 90.9999 949 90.9999 903.5 101 c 0,325,326 858 111.001 858 111.001 798.5 108.5 c 0,327,328 739 105.999 739 105.999 685 95.5 c 0,329,330 631 85 631 85 624 78 c 0,331,332 597 47 597 47 595.5 32 c 0,333,334 594 17 594 17 608 -31 c 0,335,336 623 -82 623 -82 686 -82 c 0,337,338 749 -82 749 -82 791 -47 c 0,339,340 761 -124 761 -124 677.5 -123.5 c 0,341,342 594 -123.001 594 -123.001 586 -123 c 0,0,1 EndSplineSet EndChar StartChar: H Encoding: 72 72 10 Width: 1352 Flags: HMW HStem: 699 320<465.5 883.5> VStem: 115.5 242.5<36.5 1488> 928 212<-51 1523> Fore 105.5 816.5 m 132,-1,0 36 880 36 880 19 967 c 0,1,2 14.9504 986.091 14.9504 986.091 15.0006 1004.26 c 0,3,4 15.124 1048.91 15.124 1048.91 40 1088 c 0,5,6 73.0086 1139.88 73.0086 1139.88 122.035 1140.15 c 0,7,8 124.99 1140.17 124.99 1140.17 128 1140 c 0,9,10 170 1137 170 1137 170 1095 c 0,11,12 156.052 1106.77 156.052 1106.77 143.148 1106.76 c 0,13,14 126.45 1106.74 126.45 1106.74 111.5 1087 c 0,15,16 97.7055 1068.78 97.7055 1068.78 97.5949 1049.75 c 0,17,18 97.496 1032.71 97.496 1032.71 109 1014 c 0,19,20 115.998 1001 115.998 1001 160.5 996.5 c 0,21,22 178.23 997.922 l 0,23,24 206.536 1006.49 206.536 1006.49 212 1058 c 0,25,26 222.998 1168.99 222.998 1168.99 239 1270.5 c 0,27,28 244.978 1308.42 244.978 1308.42 244.954 1336.5 c 0,29,30 244.913 1383.58 244.913 1383.58 228 1403 c 0,31,32 220.944 1410.45 220.944 1410.45 209.816 1410.6 c 0,33,34 189.949 1406.38 l 0,35,36 178.932 1402.1 178.932 1402.1 165.5 1393.5 c 0,37,38 142.118 1378.53 142.118 1378.53 141.789 1354.85 c 0,39,40 145.468 1333.76 l 0,41,42 149.976 1320.42 149.976 1320.42 160 1305 c 0,43,44 110.509 1338.17 110.509 1338.17 110.36 1375.64 c 0,45,46 110.26 1400.77 110.26 1400.77 132.369 1427.84 c 0,47,48 139.897 1437.06 139.897 1437.06 150 1446.5 c 0,49,50 233.996 1524.99 233.996 1524.99 267 1597 c 0,51,52 299.996 1670 299.996 1670 353.5 1734.5 c 0,53,54 407 1799 407 1799 500 1793 c 0,55,56 537.011 1779.99 537.011 1779.99 559.5 1762 c 0,57,58 582 1744 582 1744 597 1693 c 0,59,60 593.998 1713.01 593.998 1713.01 517.5 1749.5 c 0,61,62 500.595 1757.56 500.595 1757.56 484.643 1757.69 c 0,63,64 472.549 1757.79 472.549 1757.79 461.003 1753.33 c 0,65,66 418.855 1737.05 418.855 1737.05 384 1660 c 0,67,68 356.523 1601.82 356.523 1601.82 356.476 1525.34 c 0,69,70 356.465 1507.19 356.465 1507.19 358 1488 c 0,71,72 364 1398 364 1398 429 1310.5 c 0,73,74 477.324 1245.45 477.324 1245.45 477.562 1182.33 c 0,75,76 477.644 1160.55 477.644 1160.55 472 1139 c 0,77,78 464.998 1111.99 464.998 1111.99 417.5 1102.5 c 0,79,80 377.156 1097.63 l 0,81,82 363.646 1097.77 363.646 1097.77 358 1102 c 0,83,84 394 1106.99 394 1106.99 407 1129 c 0,85,86 420 1151 420 1151 420 1152 c 0,87,88 416.971 1176.71 l 0,89,90 409.979 1201.86 409.979 1201.86 387 1224.5 c 0,91,92 371.888 1239.39 371.888 1239.39 359.543 1239.36 c 0,93,94 344.11 1239.33 344.11 1239.33 333 1216 c 0,95,96 320 1189 320 1189 317 1122 c 0,97,98 314 1056 314 1056 314 1055 c 0,99,100 322.999 994.003 322.999 994.003 347.5 955.5 c 0,101,102 371.999 917.001 371.999 917.001 375 916 c 0,103,104 399 895 399 895 428 897.5 c 0,105,106 457 900 457 900 472 906 c 0,107,108 580 955.999 580 955.999 618 1003 c 0,109,110 649.772 1042.29 649.772 1042.29 713.695 1042.45 c 0,111,112 726.23 1042.48 726.23 1042.48 740 1041 c 0,113,114 769.004 1029 769.004 1029 783.5 1008.5 c 0,115,116 798 988 798 988 786 934 c 0,117,118 772 898 772 898 735 893 c 0,119,120 753 911 753 911 744.5 933.5 c 0,121,122 736 956 736 956 712 938 c 0,123,124 682.31 915.493 682.31 915.493 681.858 898.26 c 0,125,126 685.012 887.021 l 0,127,128 692.164 875.551 692.164 875.551 715.5 867 c 0,129,130 781 843 781 843 823 846 c 0,131,132 838 846 838 846 893 863 c 0,133,134 948 880 948 880 923 962 c 0,135,136 912.999 995.001 912.999 995.001 883.5 1019 c 0,137,138 854 1043 854 1043 851 1083 c 0,139,140 851.18 1119.3 l 0,141,142 855.8 1158.5 855.8 1158.5 881 1183 c 0,143,144 899.015 1200.01 899.015 1200.01 940.5 1211 c 0,145,146 964.418 1213.55 l 0,147,148 991.024 1211.78 991.024 1211.78 1012 1188 c 0,149,150 982.048 1185.47 l 0,151,152 938.654 1175.69 938.654 1175.69 931 1129 c 0,153,154 921 1067.99 921 1067.99 999 1051 c 0,155,156 1015.67 1050.34 l 0,157,158 1049.51 1057.23 1049.51 1057.23 1060.5 1137 c 0,159,160 1071.56 1217.31 1071.56 1217.31 1071.55 1255.32 c 0,161,162 1071.54 1263.69 1071.54 1263.69 1071 1270 c 0,163,164 1065 1317.02 1065 1317.02 1002.5 1406 c 0,165,166 940 1494.99 940 1494.99 928 1523 c 0,167,168 913.999 1551.01 913.999 1551.01 901.5 1616 c 0,169,170 899.156 1647.62 l 0,171,172 901.5 1693.75 901.5 1693.75 939 1732 c 0,173,174 965.005 1758 965.005 1758 1000.5 1759.5 c 0,175,176 1054.31 1757.68 l 0,177,178 1064.53 1756.61 1064.53 1756.61 1075 1755 c 0,179,180 1138 1744.99 1138 1744.99 1193 1697 c 0,181,182 1183.01 1697 1183.01 1697 1154 1711 c 0,183,184 1124.99 1725 1124.99 1725 1102 1725 c 0,185,186 1042.01 1725 1042.01 1725 1002 1697.5 c 0,187,188 972.596 1677.29 972.596 1677.29 972.372 1645.99 c 0,189,190 972.292 1634.72 972.292 1634.72 976 1622 c 0,191,192 1011 1494.87 1011 1494.87 1077.42 1494.19 c 0,193,194 1083.09 1494.13 1083.09 1494.13 1089 1495 c 0,195,196 1164 1505.99 1164 1505.99 1170 1527 c 0,197,198 1175.83 1549.08 1175.83 1549.08 1175.85 1567.34 c 0,199,200 1175.87 1592.92 1175.87 1592.92 1164.5 1611 c 0,201,202 1145.03 1641.96 1145.03 1641.96 1119 1672 c 0,203,204 1155 1672 1155 1672 1198.5 1617.5 c 0,205,206 1242 1563.01 1242 1563.01 1242 1530 c 0,207,208 1242 1458.02 1242 1458.02 1226.5 1372 c 0,209,210 1221.92 1346.59 1221.92 1346.59 1222.01 1316.99 c 0,211,212 1222.23 1246.41 1222.23 1246.41 1249 1152 c 0,213,214 1263.99 1099.03 1263.99 1099.03 1276 1049.5 c 0,215,216 1288 1000 1288 1000 1288 951 c 0,217,218 1288 925.992 1288 925.992 1263 891 c 0,219,220 1237.99 856 1237.99 856 1181 853 c 0,221,222 1181 854 1181 854 1215.5 880.5 c 0,223,224 1250 907 1250 907 1235 955 c 0,225,226 1223 970 1223 970 1200.5 959.5 c 0,227,228 1178.01 949.003 1178.01 949.003 1165 925 c 0,229,230 1153 903 1153 903 1142.5 844.5 c 0,231,232 1134.87 801.972 1134.87 801.972 1134.9 772.936 c 0,233,234 1134.91 762.016 1134.91 762.016 1136 753 c 0,235,236 1142 687.014 1142 687.014 1166.5 635 c 0,237,238 1191 582.981 1191 582.981 1200 539 c 0,239,240 1216.99 446 1216.99 446 1204.5 409 c 0,241,242 1192.01 372.012 1192.01 372.012 1177 353 c 0,243,244 1165 346.001 1165 346.001 1137.5 341 c 0,245,246 1115.12 340.89 l 0,247,248 1098.65 343.703 1098.65 343.703 1082 355 c 0,249,250 1129 359.001 1129 359.001 1142 378 c 0,251,-1 1149.5 410.5 l 0,252,253 1149.4 425.528 l 0,254,255 1143.56 444.551 1143.56 444.551 1105 449 c 0,256,257 1090.45 446.644 l 0,258,259 1076.15 440.772 1076.15 440.772 1061 421 c 0,260,261 1042.72 397.15 1042.72 397.15 1042.76 337.294 c 0,262,263 1042.77 321.845 1042.77 321.845 1044 304 c 0,264,265 1051.99 195 1051.99 195 1084.5 123 c 0,266,267 1117.01 51 1117.01 51 1140 -51 c 0,268,269 1152.45 -109.993 1152.45 -109.993 1152.38 -156.242 c 0,270,271 1152.21 -266.008 1152.21 -266.008 1081.5 -304 c 0,272,273 982.005 -358 982.005 -358 981 -358 c 0,274,275 948 -362 948 -362 901.5 -360.5 c 0,276,277 855 -359 855 -359 819 -330 c 0,278,279 852 -343 852 -343 896.5 -345 c 0,280,281 935.359 -343.042 l 0,282,283 957.07 -339.654 957.07 -339.654 976 -331 c 0,284,285 1035 -300.996 1035 -300.996 1071 -255.5 c 0,286,287 1086.62 -235.762 1086.62 -235.762 1086.8 -212.544 c 0,288,289 1086.9 -200.455 1086.9 -200.455 1082.82 -187.422 c 0,290,291 1076.66 -167.782 1076.66 -167.782 1061 -146 c 0,292,293 992 -51.0001 992 -51.0001 903 -31 c 0,294,295 814 -11 814 -11 793 6 c 0,296,297 732.585 56.9527 732.585 56.9527 732.57 111.614 c 0,298,299 732.564 132.048 732.564 132.048 741 153 c 0,300,301 770.744 226.878 770.744 226.878 814 227 c 0,302,303 846 224 846 224 876 185 c 0,304,305 857.344 193.955 857.344 193.955 843.281 194.139 c 0,306,307 828.019 191.183 l 0,308,309 815.839 185.689 815.839 185.689 809 170 c 0,310,311 785 113 785 113 838 98.5 c 0,312,313 891 83.9999 891 83.9999 891 106 c 0,314,315 903.199 124.977 903.199 124.977 903.227 166.688 c 0,316,317 903.239 186.524 903.239 186.524 900.5 211.5 c 0,318,319 891.999 289.006 891.999 289.006 886 323 c 0,320,321 831 412 831 412 787.5 416.5 c 0,322,323 744 421 744 421 716 452 c 0,324,325 672 498.001 672 498.001 669 527.5 c 0,326,327 666 557 666 557 678 593 c 0,328,329 700 659 700 659 766 632 c 0,330,331 746 620 746 620 739 595.5 c 0,332,333 732 571 732 571 765 574 c 0,334,335 798 577 798 577 825 590.5 c 0,336,337 852 604 852 604 844 646 c 0,338,339 825 745 825 745 684 751.5 c 0,340,341 543 758 543 758 498 734 c 0,342,343 481.002 713.002 481.002 713.002 465.5 699 c 0,344,345 459.145 693.26 459.145 693.26 459.094 675.417 c 0,346,347 459.02 649.739 459.02 649.739 472 599 c 0,348,349 478 574 478 574 486.5 528.5 c 0,350,351 487.651 503.031 l 0,352,353 484.37 476.319 484.37 476.319 460 461 c 0,354,355 434.294 445.021 434.294 445.021 398.454 444.97 c 0,356,357 382.705 444.947 382.705 444.947 365 448 c 0,358,359 401 454 401 454 423 491 c 0,360,361 445 528 445 528 391 537 c 0,362,363 375.319 535.564 l 0,364,365 361.023 530.93 361.023 530.93 348 514 c 0,366,367 328 488 328 488 328 458 c 0,368,369 330.048 395.957 l 0,370,371 337.072 324.887 337.072 324.887 366 269.5 c 0,372,373 407 191.001 407 191.001 398 127 c 0,374,375 391 82 391 82 375.5 71 c 0,376,377 360.001 60.0004 360.001 60.0004 328 53 c 0,378,379 336 77 336 77 343.5 92.5 c 0,380,381 351 107.999 351 107.999 330 127 c 0,382,383 321.857 133.786 321.857 133.786 311.873 133.895 c 0,384,385 307.143 133.946 307.143 133.946 302 132.5 c 0,386,387 286 128 286 128 277 125 c 0,388,389 231.23 107.948 231.23 107.948 230.966 58.6818 c 0,390,391 230.936 53.0513 230.936 53.0513 231.5 47 c 0,392,393 236.927 -11.2137 236.927 -11.2137 258 -28 c 0,394,395 281 -45 281 -45 318.5 -59.5 c 0,396,397 356 -74.0001 356 -74.0001 443 -45 c 0,398,-1 492.5 -13.5 l 0,399,400 542 18 542 18 587 123 c 0,401,402 552.999 9.99854 552.999 9.99854 486 -60 c 0,403,404 463 -82.9999 463 -82.9999 363 -111.5 c 0,405,406 333.213 -119.989 333.213 -119.989 304.491 -119.916 c 0,407,408 236.788 -119.745 236.788 -119.745 175 -72 c 0,409,410 117 -27.0004 117 -27.0004 115.5 36.5 c 0,411,412 114 99.9999 114 99.9999 117 118 c 0,413,414 121.001 160.001 121.001 160.001 167.5 263 c 0,415,416 214 366.001 214 366.001 214 376 c 0,417,418 214 397.991 214 397.991 220.5 508.5 c 0,419,420 221.507 585.118 l 0,421,422 219.117 635.948 219.117 635.948 207 662 c 0,423,424 175.001 752.999 175.001 752.999 105.5 816.5 c 132,-1,0 EndSplineSet KernsSLIF: 65 -91 0 0 EndChar StartChar: I Encoding: 73 73 51 Width: 582 Flags: HMW VStem: 256 244.5<240.5 1423> Fore 232 519 m 0,0,1 224.001 624.998 224.001 624.998 126 719 c 0,2,3 45.602 796.117 45.602 796.117 45.2953 885.347 c 0,4,5 45.2282 904.883 45.2282 904.883 49 925 c 0,6,7 63.999 1002.99 63.999 1002.99 117.5 1022 c 0,8,9 128.072 1025.76 128.072 1025.76 137.726 1025.68 c 0,10,11 176.928 1025.39 176.928 1025.39 201 962 c 0,12,-1 190 978 l 0,13,14 171.382 993.709 171.382 993.709 155.81 994.016 c 0,15,16 141.649 990.804 l 0,17,18 138.235 989.102 138.235 989.102 135 986.5 c 0,19,20 112.001 968 112.001 968 108 936.5 c 0,21,22 108.64 911.78 l 0,23,24 112 893.601 112 893.601 124 876.5 c 0,25,26 143.999 848 143.999 848 199 857 c 0,27,28 226 861 226 861 232 911 c 0,29,30 235.1 972.442 l 0,31,32 234.847 996.834 234.847 996.834 232.5 1023.5 c 0,33,34 227 1086 227 1086 213.5 1143 c 0,35,36 200 1200 200 1200 189 1218 c 0,37,38 124.986 1314.02 124.986 1314.02 83.5 1358 c 0,39,40 49.5783 1393.96 49.5783 1393.96 49.397 1447.97 c 0,41,42 49.3565 1460.04 49.3565 1460.04 51 1473 c 0,43,44 69.0007 1610 69.0007 1610 219 1646 c 0,45,46 145.001 1608.01 145.001 1608.01 126 1542.5 c 0,47,48 114.33 1502.27 114.33 1502.27 114.355 1474.3 c 0,49,50 114.371 1456.73 114.371 1456.73 119 1444 c 0,51,52 138.175 1413.96 138.175 1413.96 172.467 1413.74 c 0,53,54 187.822 1413.65 187.822 1413.65 206.21 1419.53 c 0,55,56 211.002 1421.06 211.002 1421.06 216 1423 c 0,57,58 282.992 1448.99 282.992 1448.99 296 1464 c 0,59,60 403 1587 403 1587 365 1725 c 0,61,62 327 1863 327 1863 152 1908 c 0,63,64 259 1908 259 1908 351 1815 c 0,65,66 443.001 1722 443.001 1722 455 1619 c 0,67,68 461 1534.99 461 1534.99 483.5 1458 c 0,69,70 505.993 1381.03 505.993 1381.03 524 1292 c 0,71,72 532 1247 532 1247 544 1211 c 0,73,74 554.285 1180.14 554.285 1180.14 554.286 1161.04 c 0,75,76 554.286 1157.86 554.286 1157.86 554 1155 c 0,77,78 546.001 1064 546.001 1064 450 1064 c 0,79,80 492.002 1097 492.002 1097 501.5 1152 c 0,81,82 501.656 1171.25 l 0,83,84 495.027 1204.71 495.027 1204.71 434.075 1205.07 c 0,85,86 430.622 1205.09 430.622 1205.09 427 1205 c 0,87,88 392 1206.99 392 1206.99 380.5 1160 c 0,89,90 369 1113.01 369 1113.01 369 1052.5 c 0,91,92 369 992.005 369 992.005 375.5 935.5 c 0,93,94 381.993 879.057 381.993 879.057 384 864 c 0,95,96 390 795 390 795 443 801 c 0,97,98 478.903 805.065 478.903 805.065 479.013 846.3 c 0,99,100 479.065 865.936 479.065 865.936 471 894 c 0,101,102 463 918 463 918 426 958 c 0,103,104 441 949 441 949 456 938.5 c 0,105,106 471 928 471 928 496 897 c 0,107,108 528.83 854.008 528.83 854.008 528.971 808.268 c 0,109,110 529.011 795.491 529.011 795.491 526.5 782.5 c 0,111,112 515 723 515 723 485 660 c 0,113,-1 425 532.5 l 0,114,115 395 468 395 468 400 404 c 0,116,117 407.001 308.999 407.001 308.999 460.5 240.5 c 0,118,119 514 172 514 172 517 82 c 0,120,121 519 10 519 10 455.5 -13 c 0,122,123 392 -36 392 -36 331 -34 c 0,124,125 409 -20 409 -20 407 52.5 c 0,126,127 405 124.999 405 124.999 321 131 c 0,128,129 291.816 129.369 l 0,130,131 231.611 117.594 231.611 117.594 231.312 32.2265 c 0,132,133 231.26 17.4636 231.26 17.4636 233 0.5 c 0,134,135 246.999 -135.998 246.999 -135.998 280 -188 c 0,136,137 328 -263 328 -263 391 -299.5 c 0,138,139 454 -336 454 -336 487 -366 c 0,140,141 427.995 -346.998 427.995 -346.998 394 -329.5 c 0,142,143 360.005 -312.002 360.005 -312.002 314 -283 c 0,144,145 314 -282 314 -282 276.5 -245 c 0,146,147 238.998 -207.997 238.998 -207.997 219 -168 c 0,148,149 174.999 -79.9963 174.999 -79.9963 161 11 c 0,150,151 157.704 57.9995 l 0,152,153 158.567 121.5 158.567 121.5 188.158 185 c 0,154,155 190.022 189 190.022 189 192 193 c 0,156,157 228 266.001 228 266.001 232.5 352.5 c 0,158,159 234.331 462.476 l 0,160,161 233.742 491.132 233.742 491.132 232 519 c 0,0,1 EndSplineSet EndChar StartChar: J Encoding: 74 74 63 Width: 1235 Flags: MW HStem: -181.5 278.5<390.5 1080> 1374 216<210.5 730> VStem: 262 128.5<-181.5 574> 753 279.5<121 1629> Fore 266 -186 m 0,0,1 224.001 -180 224.001 -180 177.5 -136 c 0,2,3 131 -92.0005 131 -92.0005 119 -17 c 0,4,5 153.477 -76.1043 153.477 -76.1043 181 -84 c 0,6,7 209.646 -85.7528 l 0,8,9 237.766 -83.402 237.766 -83.402 252.5 -62.5 c 0,10,11 274 -32 274 -32 274 11 c 0,12,13 274 74.0005 274 74.0005 219 127 c 0,14,15 194.8 150.32 194.8 150.32 182.216 150.408 c 0,16,17 168.769 150.502 168.769 150.502 168.586 124.068 c 0,18,19 168.551 119.018 168.551 119.018 169 113 c 0,20,21 171.948 59.931 171.948 59.931 224 55 c 0,22,23 206.644 34.5454 206.644 34.5454 187.56 34.4533 c 0,24,25 176.342 34.3991 176.342 34.3991 163.5 42 c 0,26,27 131.001 61.999 131.001 61.999 121 82 c 0,28,29 86.9999 146.001 86.9999 146.001 115 239 c 0,30,31 140.998 329.994 140.998 329.994 180.5 414 c 0,32,33 219.995 497.991 219.995 497.991 262 574 c 0,34,35 319 680 319 680 419 771.5 c 0,36,37 519 863 519 863 639 891 c 0,38,39 497 834 497 834 403.5 649 c 0,40,41 310 464 310 464 340 317 c 0,42,43 350 268 350 268 386.5 238 c 0,44,45 402.291 225.021 402.291 225.021 417.613 224.77 c 0,46,47 434.195 228.284 l 0,48,49 445.735 233.41 445.735 233.41 457 246 c 0,50,51 481 273 481 273 479.5 310.5 c 0,52,53 478 348 478 348 469 369 c 0,54,55 455 396 455 396 417 413 c 0,56,57 468 425 468 425 503.5 388.5 c 0,58,59 538.999 352.002 538.999 352.002 546 319 c 0,60,61 550 297 550 297 546 262 c 0,62,63 542 227.005 542 227.005 542 215 c 0,64,65 541.282 157.714 l 0,66,67 543.818 120.228 543.818 120.228 556 105 c 0,68,69 576 79.9999 576 79.9999 613 70 c 0,70,71 646 60 646 60 689 75.5 c 0,72,73 732 90.9999 732 90.9999 753 121 c 0,74,75 789 170.999 789 170.999 805.5 237.5 c 0,76,77 822 304 822 304 831 368 c 0,78,79 833.059 429.818 l 0,80,81 833.031 430.907 833.031 430.907 833 432 c 0,82,83 832 467 832 467 796 467 c 0,84,85 762 467 762 467 761 439.5 c 0,86,87 760 412 760 412 769 394 c 0,88,89 748 394 748 394 725.5 408.5 c 0,90,91 703 423 703 423 702 480 c 0,92,93 701 516 701 516 723.5 545 c 0,94,95 746 574 746 574 761 607 c 0,96,97 801 694 801 694 807.5 724 c 0,98,99 811.571 742.789 811.571 742.789 811.523 776.872 c 0,100,101 811.495 797.214 811.495 797.214 810 823 c 0,102,103 804 898 804 898 711 1003 c 0,104,105 664.04 1056.02 664.04 1056.02 663.74 1107 c 0,106,107 663.641 1123.83 663.641 1123.83 668.627 1140.44 c 0,108,109 678.449 1173.15 678.449 1173.15 708 1205 c 0,110,111 723 1221.99 723 1221.99 764.5 1218.5 c 0,112,113 806 1215.01 806 1215.01 815 1166 c 0,114,115 800.85 1174.76 800.85 1174.76 784.879 1174.89 c 0,116,117 777.153 1174.96 777.153 1174.96 769 1173 c 0,118,119 744 1167 744 1167 744 1149 c 0,120,121 744 1087.99 744 1087.99 782.5 1101 c 0,122,123 821.009 1114.01 821.009 1114.01 844 1135 c 0,124,125 871 1160.99 871 1160.99 876 1273 c 0,126,127 875.964 1349.1 l 0,128,129 872.849 1400.52 872.849 1400.52 860 1425 c 0,130,131 849.326 1445.59 849.326 1445.59 825.576 1445.54 c 0,132,133 818.173 1445.52 818.173 1445.52 809.5 1443.5 c 0,134,135 773 1434.99 773 1434.99 772 1417 c 0,136,137 768 1373.01 768 1373.01 798 1373.5 c 0,138,139 828 1373.99 828 1373.99 840 1384 c 0,140,141 838.397 1364.37 l 0,142,143 833.435 1347.78 833.435 1347.78 815.5 1338 c 0,144,145 793.685 1326.1 793.685 1326.1 779.113 1326.16 c 0,146,147 775.31 1326.17 775.31 1326.17 772 1327 c 0,148,149 715 1339 715 1339 678.5 1375 c 0,150,151 642.016 1410.98 642.016 1410.98 603 1436 c 0,152,153 556.039 1464.7 556.039 1464.7 506.748 1464.68 c 0,154,155 480.455 1464.68 480.455 1464.68 453.5 1456.5 c 0,156,157 375.96 1432.98 375.96 1432.98 334 1415 c 0,158,159 280.973 1391.99 280.973 1391.99 210.5 1374 c 0,160,161 146.8 1357.74 146.8 1357.74 121.868 1357.8 c 0,162,163 119.215 1357.81 119.215 1357.81 117 1358 c 0,164,165 18.9988 1365.01 18.9988 1365.01 8 1466.5 c 0,166,167 -3 1568.01 -3 1568.01 89 1594 c 0,168,169 66.0001 1576 66.0001 1576 44 1532.5 c 0,170,171 22 1489 22 1489 63 1447 c 0,172,173 85.4007 1423 85.4007 1423 118.04 1422.75 c 0,174,175 147.044 1426.67 l 0,176,177 163.949 1431.1 163.949 1431.1 183 1440.5 c 0,178,179 261 1479.01 261 1479.01 285 1517 c 0,180,181 327.531 1585.52 327.531 1585.52 327.879 1616.21 c 0,182,183 327.973 1624.48 327.973 1624.48 325 1630 c 0,184,185 311 1655.99 311 1655.99 281 1648 c 0,186,187 273.001 1646.01 273.001 1646.01 270 1629.5 c 0,188,189 270.92 1617.45 l 0,190,191 274.131 1609.04 274.131 1609.04 285 1603 c 0,192,193 268.51 1595.15 268.51 1595.15 254.565 1595 c 0,194,195 245.213 1594.91 245.213 1594.91 237.005 1598.27 c 0,196,197 226.275 1602.68 226.275 1602.68 217.5 1613 c 0,198,199 199.327 1634.38 199.327 1634.38 199.184 1669.47 c 0,200,201 199.126 1683.62 199.126 1683.62 202 1700 c 0,202,203 208 1739 208 1739 249.5 1751 c 0,204,205 291 1763 291 1763 311 1757 c 0,206,207 421.988 1725.01 421.988 1725.01 511.5 1660.5 c 0,208,209 601 1596 601 1596 730 1590 c 0,210,211 805.281 1589.97 l 0,212,213 827.921 1590.97 827.921 1590.97 854 1593 c 0,214,215 931 1599 931 1599 931 1659 c 0,216,217 931 1679.99 931 1679.99 896.5 1697.5 c 0,218,219 870.907 1710.49 870.907 1710.49 857.692 1710.53 c 0,220,221 853.097 1710.55 853.097 1710.55 850 1709 c 0,222,223 822.999 1692.99 822.999 1692.99 822.5 1675.5 c 0,224,225 822 1657.99 822 1657.99 824 1632 c 0,226,227 797.428 1640.59 797.428 1640.59 797.12 1672.1 c 0,228,229 797.034 1680.9 797.034 1680.9 799 1691.5 c 0,230,231 808.001 1740 808.001 1740 838 1755 c 0,232,233 861.517 1766.1 861.517 1766.1 891.215 1766.11 c 0,234,235 906.986 1766.12 906.986 1766.12 924.5 1763 c 0,236,237 974.999 1754 974.999 1754 991 1730 c 0,238,239 1028 1673.01 1028 1673.01 1032.5 1629 c 0,240,241 1036.27 1592.18 1036.27 1592.18 1036.18 1540.01 c 0,242,243 1036 1519 l 0,244,-1 1022.5 1335.5 l 0,245,246 1020.56 1260.23 l 0,247,248 1022.51 1199.19 1022.51 1199.19 1038 1165 c 0,249,250 1058 1119.98 1058 1119.98 1081.5 1083.5 c 0,251,-1 1125 1013 l 0,252,253 1149.01 966.986 1149.01 966.986 1163 858 c 0,254,255 1166.9 800.919 l 0,256,257 1166.23 743.613 1166.23 743.613 1141 731 c 0,258,259 1139.08 769.983 l 0,260,261 1132.48 813.66 1132.48 813.66 1105.5 848 c 0,262,263 1086.38 872.329 1086.38 872.329 1068.62 872.499 c 0,264,265 1058.42 872.597 1058.42 872.597 1048.66 864.714 c 0,266,267 1041.2 858.688 1041.2 858.688 1034 848 c 0,268,269 1013.01 817.011 1013.01 817.011 994 741 c 0,270,271 988.449 718.797 988.449 718.797 988.361 701.972 c 0,272,273 988.262 683.23 988.262 683.23 994.94 671.159 c 0,274,275 1002.79 656.972 1002.79 656.972 1020 652 c 0,276,277 1041.52 648.472 l 0,278,279 1063.24 649.314 1063.24 649.314 1068.5 673.5 c 0,280,281 1076 708 1076 708 1052 744 c 0,282,283 1084 744 1084 744 1102 704 c 0,284,285 1115.59 674.668 1115.59 674.668 1115.69 641.818 c 0,286,287 1115.78 607.006 1115.78 607.006 1100.73 568.244 c 0,288,289 1090.27 541.324 1090.27 541.324 1072.5 512.5 c 0,290,291 1005 403 1005 403 975 328 c 0,292,293 957 285 957 285 952 227.5 c 0,294,295 947 169.995 947 169.995 947 128 c 0,296,297 947 113 947 113 956.5 94 c 0,298,299 966 74.9999 966 74.9999 988 84 c 0,300,301 1020.91 98.9589 1020.91 98.9589 1020.81 124.823 c 0,302,303 1020.78 133.542 1020.78 133.542 1017 143.5 c 0,304,305 1002 183 1002 183 981 201 c 0,306,307 993.355 202.547 l 0,308,309 1012.86 199.6 1012.86 199.6 1041.5 166.5 c 0,310,311 1080 122.005 1080 122.005 1080 97 c 0,312,313 1080 56.9999 1080 56.9999 1066.5 -3 c 0,314,315 1053 -63 1053 -63 1008 -77 c 0,316,317 967 -89 967 -89 923.5 -86 c 0,318,319 880 -83 880 -83 838 -86 c 0,320,321 754 -96.0001 754 -96.0001 667.5 -104.5 c 0,322,323 580.997 -113.001 580.997 -113.001 506 -144 c 0,324,325 444 -168 444 -168 390.5 -181.5 c 0,326,327 337 -195 337 -195 266 -186 c 0,0,1 EndSplineSet EndChar StartChar: K Encoding: 75 75 13 Width: 1310 Flags: HMW VStem: 48 294<-13 1634> Fore 638 316 m 0,0,1 591 315 591 315 620 274 c 0,2,3 644.538 239.308 644.538 239.308 683.396 238.982 c 0,4,5 690.462 238.923 690.462 238.923 698 240 c 0,6,7 679.098 223.619 679.098 223.619 649.677 223.513 c 0,8,9 632.402 223.451 632.402 223.451 611.5 229 c 0,10,11 555.001 244 555.001 244 536 277 c 0,12,13 501 334 501 334 480 444 c 0,14,15 459 554 459 554 376 588 c 0,16,17 361 594 361 594 328.5 585.5 c 0,18,19 296.001 577 296.001 577 286 551 c 0,20,21 271 514 271 514 294.5 482 c 0,22,-1 342 415 l 0,23,24 369 370 369 370 374 303 c 0,25,26 373.24 263.147 l 0,27,28 368.196 223.29 368.196 223.29 345 196 c 0,29,30 344 200.001 344 200.001 342 245.5 c 0,31,32 340.55 278.486 340.55 278.486 312.624 278.424 c 0,33,34 300.363 278.397 300.363 278.397 283 272 c 0,35,36 264.001 265 264.001 265 255.5 165.5 c 0,37,38 246.999 66.0001 246.999 66.0001 290 66 c 0,39,40 329 66 329 66 323.5 89 c 0,41,42 318 111.999 318 111.999 304 127 c 0,43,44 361 109 361 109 366.5 63 c 0,45,46 372 17 372 17 342 -13 c 0,47,48 289.002 -63.9983 289.002 -63.9983 222.5 -104 c 0,49,50 156 -144.001 156 -144.001 156 -222 c 0,51,52 156 -296.001 156 -296.001 230.5 -329.5 c 0,53,54 300.803 -361.112 300.803 -361.112 396.485 -361.113 c 0,55,56 402.198 -361.113 402.198 -361.113 408 -361 c 0,57,58 348.507 -372.092 348.507 -372.092 301.95 -371.999 c 0,59,60 209.993 -371.816 209.993 -371.816 168.5 -328 c 0,61,62 107.913 -264.02 107.913 -264.02 98 -181 c 0,63,64 97.2541 -142.611 l 0,65,66 101.102 -94.0729 101.102 -94.0729 129 -44 c 0,67,68 167.999 25.9991 167.999 25.9991 169 95 c 0,69,70 169 157.001 169 157.001 144 198 c 0,71,72 135.64 212.08 135.64 212.08 124.957 213.576 c 0,73,74 111.932 211.149 l 0,75,76 103.533 207.148 103.533 207.148 94 197 c 0,77,78 62.9999 164 62.9999 164 112 113 c 0,79,80 73 102.001 73 102.001 47.5 132 c 0,81,82 38.9939 142.007 38.9939 142.007 21 180 c 0,83,84 4.00904 215.876 4.00904 215.876 35 283.5 c 0,85,86 54.7141 326.518 54.7141 326.518 77 381 c 0,87,88 109.344 460.071 109.344 460.071 111.5 491.5 c 0,89,90 119.119 602.598 119.119 602.598 121 605 c 0,91,92 123.409 606.637 123.409 606.637 123.374 613.538 c 0,93,94 123.309 626.595 123.309 626.595 114.5 658.5 c 0,95,96 93.5096 731.735 93.5096 731.735 48 800 c 0,97,98 36 818 36 818 32 867 c 0,99,100 28 916 28 916 67 942 c 0,101,102 58.6356 921.335 58.6356 921.335 58.6489 907.841 c 0,103,104 58.6678 888.725 58.6678 888.725 75.5 884 c 0,105,106 106 876 106 876 130 924 c 0,107,108 154.741 970.912 154.741 970.912 154.837 1000.58 c 0,109,110 154.848 1004.17 154.848 1004.17 154.5 1007.5 c 0,111,112 145.981 1070.48 145.981 1070.48 127 1074 c 0,113,114 105.667 1074.72 l 0,115,116 91.2499 1071.94 91.2499 1071.94 90.8002 1057.34 c 0,117,118 90.73 1055.06 90.73 1055.06 91 1052.5 c 0,119,120 94 1024 94 1024 106 1012 c 0,121,122 73.004 1012 73.004 1012 53.5 1036.5 c 0,123,124 34 1060.99 34 1060.99 34 1076 c 0,125,126 31 1122.99 31 1122.99 53 1185.5 c 0,127,128 75.0055 1248.02 75.0055 1248.02 88 1296 c 0,129,130 97.938 1333.68 97.938 1333.68 97.9311 1370.59 c 0,131,132 97.9214 1422.82 97.9214 1422.82 78 1473.5 c 0,133,134 44 1560.01 44 1560.01 48 1634 c 0,135,136 49.9995 1682.99 49.9995 1682.99 79.5 1717 c 0,137,138 99.8632 1740.47 99.8632 1740.47 129.045 1740.59 c 0,139,140 142.135 1740.65 142.135 1740.65 157 1736 c 0,141,142 110.002 1719.01 110.002 1719.01 102 1688.5 c 0,143,144 98.2452 1661.63 l 0,145,146 98.4527 1649.59 98.4527 1649.59 103 1641 c 0,147,148 122.999 1599 122.999 1599 169 1605 c 0,149,150 215.001 1611 215.001 1611 229 1641 c 0,151,152 244.674 1677.15 244.674 1677.15 244.693 1707.92 c 0,153,154 244.732 1773.36 244.732 1773.36 174 1814.5 c 0,155,156 69.9617 1875.02 69.9617 1875.02 36 1886 c 0,157,158 165.006 1859 165.006 1859 219 1802.5 c 0,159,160 273.003 1745.99 273.003 1745.99 287 1698 c 0,161,162 298.866 1655.73 298.866 1655.73 298.907 1618.68 c 0,163,164 298.921 1605.77 298.921 1605.77 297.5 1593.5 c 0,165,166 292.001 1546.01 292.001 1546.01 277 1488 c 0,167,168 266.593 1447.11 266.593 1447.11 266.685 1393.79 c 0,169,170 266.717 1375.39 266.717 1375.39 268 1355.5 c 0,171,172 272.58 1284.5 272.58 1284.5 328.353 1283.58 c 0,173,174 333.462 1283.5 333.462 1283.5 339 1284 c 0,175,176 402 1290 402 1290 393 1344 c 0,177,178 384 1398 384 1398 334 1410 c 0,179,180 359.97 1413.09 l 0,181,182 381.98 1412.55 381.98 1412.55 406.5 1402 c 0,183,184 445.998 1385.01 445.998 1385.01 455 1355 c 0,185,186 475 1280 475 1280 435.5 1215.5 c 0,187,188 398.21 1154.61 398.21 1154.61 394 1076 c 0,189,190 391.08 1021.49 391.08 1021.49 447 1046 c 0,191,192 520 1077.99 520 1077.99 595 1205 c 0,193,194 622 1250 622 1250 650 1371.5 c 0,195,196 677.466 1490.68 677.466 1490.68 718 1522 c 0,197,198 740 1538.99 740 1538.99 774.5 1547.5 c 0,199,200 799.731 1550.51 l 0,201,202 815.211 1549.79 815.211 1549.79 824 1541 c 0,203,204 755 1536.01 755 1536.01 755 1490 c 0,205,206 755 1458.99 755 1458.99 785 1466 c 0,207,208 875 1482.01 875 1482.01 883.5 1543.5 c 0,209,210 892.001 1605.01 892.001 1605.01 931 1655 c 0,211,212 958 1689.99 958 1689.99 1005.5 1685 c 0,213,214 1052.99 1680.01 1052.99 1680.01 1066 1658 c 0,215,216 1046.78 1662.27 1046.78 1662.27 1031.01 1662.3 c 0,217,218 987.727 1662.39 987.727 1662.39 970.5 1630.5 c 0,219,220 961.129 1613.15 961.129 1613.15 961.06 1596.68 c 0,221,222 960.961 1572.89 960.961 1572.89 982 1549 c 0,223,224 1006.17 1522.41 1006.17 1522.41 1048.2 1522.44 c 0,225,226 1058.33 1522.45 1058.33 1522.45 1069.5 1524 c 0,227,228 1126.99 1531.99 1126.99 1531.99 1174.5 1568 c 0,229,230 1222.01 1604 1222.01 1604 1242 1662.5 c 0,231,232 1248.19 1680.62 1248.19 1680.62 1248.15 1699.75 c 0,233,234 1248.06 1742.38 1248.06 1742.38 1217 1790 c 0,235,236 1275 1744 1275 1744 1278 1669 c 0,237,238 1275.94 1627.18 l 0,239,240 1268.9 1580.13 1268.9 1580.13 1240 1547 c 0,241,242 1216 1519 1216 1519 1155 1484.5 c 0,243,244 1093.98 1449.99 1093.98 1449.99 1031 1426 c 0,245,246 936.739 1390.05 936.739 1390.05 861 1257 c 0,247,248 824.002 1192.01 824.002 1192.01 803.5 1131 c 0,249,250 783.002 1070 783.002 1070 718 989 c 0,251,252 674.001 934.001 674.001 934.001 603 927 c 0,253,254 639 942 639 942 662 975.5 c 0,255,256 670.036 987.205 670.036 987.205 670.015 995.797 c 0,257,258 669.976 1011.8 669.976 1011.8 642 1017 c 0,259,260 621.612 1016.71 l 0,261,262 601.663 1012.85 601.663 1012.85 581.5 995 c 0,263,264 552.458 969.292 552.458 969.292 545 932 c 0,265,266 533 872 533 872 565.5 844.5 c 0,267,268 599.679 815.578 599.679 815.578 619 851 c 0,269,270 620.942 860.69 l 0,271,272 618.273 876.636 618.273 876.636 575 889 c 0,273,274 597.521 905.746 597.521 905.746 617.708 905.986 c 0,275,276 636.286 902.519 l 0,277,278 641.221 900.562 641.221 900.562 646 897.5 c 0,279,280 678 877 678 877 687 847 c 0,281,282 711 767 711 767 672 722 c 0,283,284 634.562 678.803 634.562 678.803 645 604 c 0,285,286 657 518 657 518 757.5 474.5 c 0,287,288 858 431 858 431 945 402 c 0,289,290 1041.01 369.999 1041.01 369.999 1070 311 c 0,291,292 1092.11 266.008 1092.11 266.008 1092.13 243.118 c 0,293,294 1092.14 235.987 1092.14 235.987 1090 231 c 0,295,296 1064.99 311.001 1064.99 311.001 991 328 c 0,297,298 956.966 331.206 l 0,299,300 912.173 329.667 912.173 329.667 900 291 c 0,301,302 897.698 271.598 l 0,303,304 900.902 224.978 900.902 224.978 985 168.5 c 0,305,306 1087 99.9995 1087 99.9995 1132 65 c 0,307,308 1174.01 30.9915 1174.01 30.9915 1210.5 -27.5 c 0,309,310 1239.73 -74.3571 1239.73 -74.3571 1239.78 -117.036 c 0,311,312 1239.79 -127.648 1239.79 -127.648 1238 -138 c 0,313,314 1209.34 -300.784 1209.34 -300.784 1045 -336 c 0,315,316 1025 -340.286 1025 -340.286 992.499 -340.235 c 0,317,318 979.5 -340.214 979.5 -340.214 964.5 -339.5 c 0,319,320 912 -337 912 -337 868 -322 c 0,321,322 880.727 -325.182 880.727 -325.182 912.893 -325.124 c 0,323,324 931.273 -325.091 931.273 -325.091 956 -324 c 0,325,326 1024 -321 1024 -321 1051 -309 c 0,327,328 1115 -279.003 1115 -279.003 1154 -208 c 0,329,330 1171.45 -176.237 1171.45 -176.237 1171.48 -142.472 c 0,331,332 1171.53 -100.763 1171.53 -100.763 1145 -56 c 0,333,334 1131.01 -32.0164 1131.01 -32.0164 1093 -0.5 c 0,335,336 1055.01 31 1055.01 31 1012 44 c 0,337,338 903 75.0001 903 75.0001 906 29 c 0,339,340 906 6.00005 906 6.00005 933.5 6 c 0,341,342 961 6 961 6 979 -1 c 0,343,344 937 -25 937 -25 890.5 -12.5 c 0,345,346 844 -4.76837e-06 844 -4.76837e-06 838 15 c 0,347,348 822.002 44.9949 822.002 44.9949 806 92 c 0,349,-1 782 172 l 0,350,351 772.999 202.002 772.999 202.002 725.5 259.5 c 0,352,353 679.085 315.686 679.085 315.686 638 316 c 0,0,1 EndSplineSet KernsSLIF: 111 -104 0 0 79 -52 0 0 115 -221 0 0 83 -208 0 0 103 -182 0 0 71 -78 0 0 99 -234 0 0 67 -143 0 0 EndChar StartChar: L Encoding: 76 76 65 Width: 1349 Flags: MW HStem: 5.5 212.5<394 867> VStem: 77 263<33 1557> Fore 81 187 m 1,0,1 95.8849 195.931 95.8849 195.931 113.845 196 c 0,2,3 138.115 196.092 138.115 196.092 168 180 c 0,4,5 135.47 181.975 l 0,6,7 106.046 179.89 106.046 179.89 86.5 162 c 0,8,9 56.9999 135 56.9999 135 75 99 c 0,10,11 87.3838 72.0972 87.3838 72.0972 106.059 71.9092 c 0,12,13 115.619 71.8129 115.619 71.8129 126.827 78.7173 c 0,14,15 144.998 89.91 144.998 89.91 167.5 119.5 c 0,16,17 205.326 169.241 205.326 169.241 205.362 225.545 c 0,18,19 205.386 263.76 205.386 263.76 188 305 c 0,20,21 168.819 348.157 168.819 348.157 146.118 348.141 c 0,22,23 135.681 348.134 135.681 348.134 124.5 339 c 0,24,25 110.569 327.62 110.569 327.62 110.42 313.007 c 0,26,27 110.325 303.613 110.325 303.613 115.924 292.882 c 0,28,29 123.812 277.767 123.812 277.767 143 260 c 0,30,31 66.9999 285 66.9999 285 64 377 c 0,32,33 61 446 61 446 93.5 520.5 c 0,34,35 125.999 594.997 125.999 594.997 142 665 c 0,36,37 158.584 741.182 158.584 741.182 158.516 811.993 c 0,38,39 158.453 877.817 158.453 877.817 144 939 c 0,40,41 129 1001 129 1001 109 1061 c 0,42,43 89.0001 1121 89.0001 1121 83 1190 c 0,44,45 85.4002 1207.77 l 0,46,47 89.192 1219.98 89.192 1219.98 98.5 1237 c 0,48,49 113.063 1263.62 113.063 1263.62 148.738 1263.94 c 0,50,51 155.94 1264.01 155.94 1264.01 164 1263 c 0,52,53 151.987 1262.88 l 0,54,55 137.206 1258.28 137.206 1258.28 125 1231 c 0,56,57 121 1222.06 121 1222.06 120.765 1215.44 c 0,58,59 123.205 1205.69 l 0,60,61 129.228 1196.59 129.228 1196.59 150.025 1196.62 c 0,62,63 154.213 1196.62 154.213 1196.62 159 1197 c 0,64,65 193.073 1199.62 193.073 1199.62 193.561 1233.92 c 0,66,67 193.632 1238.88 193.632 1238.88 193 1244.5 c 0,68,69 188.004 1288.98 188.004 1288.98 180 1342 c 0,70,71 168.003 1405.99 168.003 1405.99 142.5 1462.5 c 0,72,73 116.992 1519.02 116.992 1519.02 96 1579 c 0,74,75 90.8969 1591.93 90.8969 1591.93 90.9442 1607.29 c 0,76,77 91.0361 1637.08 91.0361 1637.08 110.5 1676 c 0,78,79 127.596 1710.19 127.596 1710.19 157.618 1710.13 c 0,80,81 179.407 1710.08 179.407 1710.08 208 1692 c 0,82,83 184.001 1692 184.001 1692 154.5 1675.5 c 0,84,85 133.787 1663.92 133.787 1663.92 133.533 1633.84 c 0,86,87 137 1605 l 0,88,89 148.796 1548.97 148.796 1548.97 196 1548.5 c 0,90,91 242.998 1548.99 242.998 1548.99 264 1609 c 0,92,93 272.991 1635.97 272.991 1635.97 273.066 1660.18 c 0,94,95 273.164 1691.87 273.164 1691.87 257.991 1718.82 c 0,96,97 240.916 1749.16 240.916 1749.16 204.5 1773.5 c 0,98,99 111.01 1836 111.01 1836 31 1848 c 0,100,101 98.7863 1845.34 l 0,102,103 181.869 1836.9 181.869 1836.9 234 1802.5 c 0,104,105 306.003 1754.99 306.003 1754.99 324 1710 c 0,106,107 354 1632 354 1632 340 1557 c 0,108,109 326 1482 326 1482 326 1409 c 0,110,111 329.503 1348.47 l 0,112,113 338.221 1276.68 338.221 1276.68 368.5 1193.5 c 0,114,115 412 1073.99 412 1073.99 345 1027 c 0,116,117 355.31 1043.14 355.31 1043.14 355.372 1059.38 c 0,118,119 355.448 1079.36 355.448 1079.36 340 1099.5 c 0,120,121 328.21 1114.87 328.21 1114.87 316.244 1115.25 c 0,122,123 304.078 1111.81 l 0,124,125 293.606 1105.55 293.606 1105.55 283 1088 c 0,126,127 268.001 1064 268.001 1064 262.5 975 c 0,128,129 263.074 928.003 l 0,130,131 268.216 880.218 268.216 880.218 295 864 c 0,132,133 304.791 858.066 304.791 858.066 312.778 857.81 c 0,134,135 323.721 860.607 l 0,136,137 334.485 867.085 334.485 867.085 340.5 888.5 c 0,138,139 353 933 353 933 317 972 c 0,140,141 358 972 358 972 376.5 918 c 0,142,143 395 864 395 864 374 823 c 0,144,145 363 801 363 801 348.5 704.5 c 0,146,147 334.001 608.009 334.001 608.009 330 500 c 0,148,149 330.05 399.127 l 0,150,151 332.138 349.53 332.138 349.53 338.5 305.5 c 0,152,153 350.999 219.001 350.999 219.001 394 218 c 0,154,155 419.375 220.375 l 0,156,157 455.75 229.75 455.75 229.75 482 274 c 0,158,159 514.832 329.345 514.832 329.345 585.501 329.254 c 0,160,161 590.168 329.248 590.168 329.248 595 329 c 0,162,163 628 326 628 326 647 296.5 c 0,164,165 662.048 273.136 662.048 273.136 662.042 247.577 c 0,166,167 662.04 240.864 662.04 240.864 661 234 c 0,168,169 640 285 640 285 592 281.5 c 0,170,171 544 278 544 278 559 218 c 0,172,173 562 200 562 200 599 188 c 0,174,175 609.533 184.584 609.533 184.584 625.171 184.652 c 0,176,177 664.468 184.825 664.468 184.825 736 207 c 0,178,179 792.993 224.998 792.993 224.998 906 266 c 0,180,181 1019 307 1019 307 1004 187 c 0,182,183 985.478 232.409 985.478 232.409 960.708 233.016 c 0,184,185 945.201 229.307 l 0,186,187 935.283 224.505 935.283 224.505 924.5 213.5 c 0,188,189 876 164 876 164 920 146 c 0,190,191 1049 93.0005 1049 93.0005 1151 165.5 c 0,192,193 1239.19 228.186 1239.19 228.186 1239.17 375.713 c 0,194,195 1239.17 398.817 1239.17 398.817 1237 424 c 0,196,197 1285 262 1285 262 1235.5 175 c 0,198,199 1186 87.9974 1186 87.9974 1087.5 49 c 0,200,201 988.995 9.99982 988.995 9.99982 867 5.5 c 0,202,203 745 1 745 1 648 5 c 0,204,205 588 8 588 8 517 22 c 0,206,207 446 36 446 36 341 8 c 0,208,209 291.986 -4.7862 291.986 -4.7862 239.44 -4.70537 c 0,210,211 218.014 -4.67242 218.014 -4.67242 196 -2.5 c 0,212,213 120.001 4.99989 120.001 4.99989 77 33 c 0,214,215 44 54 44 54 38 104 c 0,216,217 38.6834 129.312 l 0,218,219 44.988 162.747 44.988 162.747 81 187 c 1,0,1 EndSplineSet KernsSLIF: 116 -417 0 0 84 -417 0 0 89 -234 0 0 121 -234 0 0 105 -130 0 0 73 -143 0 0 45 -221 0 0 83 -234 0 0 119 -273 0 0 87 -286 0 0 EndChar StartChar: M Encoding: 77 77 14 Width: 1706 Flags: HMW VStem: 94 134<-53 110> 103 219.5<176.5 1679> 352.5 105.5<62.5 376> 1204 234<80 1735> 1320.5 117.5<-254 80> Fore 1191 -391 m 1,0,1 1254.99 -348.011 1254.99 -348.011 1320.5 -254 c 0,2,3 1378.85 -170.264 1378.85 -170.264 1378.87 -61.11 c 0,4,5 1378.87 -47.7462 1378.87 -47.7462 1378 -34 c 0,6,7 1375 5.9856 1375 5.9856 1352 60.5 c 0,8,9 1329.01 115 1329.01 115 1271 121 c 0,10,11 1236.18 118.355 l 0,12,13 1233.88 117.956 1233.88 117.956 1231.5 117.5 c 0,14,15 1208 113.001 1208 113.001 1202 95 c 0,16,17 1190.15 63.5722 1190.15 63.5722 1190.25 38.2553 c 0,18,19 1190.33 14.4222 1190.33 14.4222 1201 -4 c 0,20,21 1217.66 -32.7714 1217.66 -32.7714 1249.22 -32.8796 c 0,22,23 1259.34 -32.9143 1259.34 -32.9143 1271 -30 c 0,24,25 1254.04 -59.2158 1254.04 -59.2158 1207.32 -59.1209 c 0,26,27 1204.46 -59.1151 1204.46 -59.1151 1201.5 -59 c 0,28,29 1150.01 -57 1150.01 -57 1122 -27 c 0,30,31 1082.65 11.5429 1082.65 11.5429 1082.64 73.3058 c 0,32,33 1082.64 88.4541 1082.64 88.4541 1085 105 c 0,34,35 1098.01 201.049 1098.01 201.049 1129 292 c 0,36,37 1159.99 382.965 1159.99 382.965 1178 473 c 0,38,39 1190.02 533.081 1190.02 533.081 1210 677.5 c 0,40,41 1230 822.036 1230 822.036 1230 885 c 0,42,43 1230 933.068 1230 933.068 1224.5 1007.5 c 0,44,45 1219 1082 1219 1082 1165 1107 c 0,46,47 1145.79 1115.87 1145.79 1115.87 1125.63 1115.79 c 0,48,49 1091.2 1115.67 1091.2 1115.67 1054 1089.5 c 0,50,51 1014.77 1061.9 1014.77 1061.9 1014.45 1027.45 c 0,52,53 1018.33 1004.4 l 0,54,55 1020.54 997.811 1020.54 997.811 1024 991 c 0,56,57 1037.79 964.081 1037.79 964.081 1054.81 963.673 c 0,58,59 1068.33 967.252 l 0,60,61 1070.88 968.617 1070.88 968.617 1073.5 970.5 c 0,62,63 1101.99 990.995 1101.99 990.995 1112 1029 c 0,64,65 1134.99 955 1134.99 955 1094 895 c 0,66,67 1058 843.999 1058 843.999 976 836 c 0,68,69 893.995 828 893.995 828 830 828 c 0,70,71 769 828 769 828 740 797.5 c 0,72,73 710.999 766.999 710.999 766.999 709 736 c 0,74,75 706 698 706 698 723.5 653.5 c 0,76,77 741 609 741 609 768 595 c 0,78,79 855 548 855 548 890 574 c 0,80,81 925.001 600 925.001 600 936 631 c 0,82,83 943 595 943 595 916.5 562 c 0,84,85 890 529 890 529 869 526 c 0,86,87 790 509 790 509 758.5 527 c 0,88,89 727 545 727 545 700 574 c 0,90,91 640.999 634.001 640.999 634.001 622.5 739 c 0,92,93 604 844 604 844 603 915 c 0,94,95 601 959 601 959 577.5 1002.5 c 0,96,97 554 1046 554 1046 503 1049 c 0,98,99 469 1050.01 469 1050.01 470 1014.5 c 0,100,101 470.546 995.136 470.546 995.136 486.86 994.963 c 0,102,103 496.177 994.864 496.177 994.864 510.639 1001.02 c 0,104,105 517.277 1003.85 517.277 1003.85 525 1008 c 0,106,107 515 966 515 966 484 963.5 c 0,108,109 455.502 964.925 l 0,110,111 440.947 967.75 440.947 967.75 428 975 c 0,112,113 397.999 990 397.999 990 397.5 1036 c 0,114,115 400.858 1097.86 l 0,116,117 402.845 1115.12 402.845 1115.12 406 1133 c 0,118,119 408.23 1168.25 l 0,120,121 406.474 1196.11 406.474 1196.11 391 1209 c 0,122,123 377 1220.38 377 1220.38 365.042 1220.31 c 0,124,125 336 1220.15 336 1220.15 319 1152.5 c 0,126,127 295 1056.99 295 1056.99 295 999 c 0,128,129 295 826.001 295 826.001 348 638 c 0,130,131 364 575 364 575 402 506.5 c 0,132,133 440 438 440 438 458 376 c 0,134,135 480.369 294.514 480.369 294.514 480.4 228.983 c 0,136,137 480.408 212.486 480.408 212.486 479 197 c 0,138,139 467 54.9995 467 54.9995 376 26 c 0,140,141 292 -2 292 -2 265 54 c 0,142,143 303 41 303 41 352.5 62.5 c 0,144,145 399.923 83.0977 399.923 83.0977 400.077 129.854 c 0,146,147 400.084 131.902 400.084 131.902 400 134 c 0,148,149 396.484 183.929 396.484 183.929 359.587 184.653 c 0,150,151 334.74 180.746 l 0,152,153 328.882 179.009 328.882 179.009 322.5 176.5 c 0,154,155 250.001 148 250.001 148 228 110 c 0,156,157 192.001 48.0011 192.001 48.0011 185 -25 c 0,158,159 182.436 -88.491 l 0,160,161 183.31 -118.758 183.31 -118.758 189 -141 c 0,162,163 223.999 -293.999 223.999 -293.999 290 -361 c 0,164,165 356 -428 356 -428 425 -482 c 0,166,167 285 -455 285 -455 187.5 -325 c 0,168,169 93.943 -200.257 93.943 -200.257 93.8425 -64.4657 c 0,170,171 93.8382 -58.7428 93.8382 -58.7428 94 -53 c 0,172,173 97 43 97 43 146 140 c 0,174,175 195.001 237.001 195.001 237.001 209 333 c 0,176,177 214.998 371.988 214.998 371.988 227.5 438.5 c 0,178,179 230.901 474.219 l 0,180,181 230.041 510.432 230.041 510.432 207 523 c 0,182,183 191.903 530.839 191.903 530.839 180.346 530.839 c 0,184,185 152.097 530.839 152.097 530.839 145 484 c 0,186,187 143.091 450.184 l 0,188,189 145.56 415.36 145.56 415.36 171 409 c 0,190,191 97.0005 409 97.0005 409 90 474 c 0,192,193 82.9999 539 82.9999 539 90 588 c 0,194,195 96 634 96 634 127 686 c 0,196,197 158 738 158 738 164 783 c 0,198,199 168.088 814.428 168.088 814.428 167.998 844.615 c 0,200,201 167.736 932.573 167.736 932.573 132 1010 c 0,202,203 84.004 1113.99 84.004 1113.99 53 1222 c 0,204,205 22.9998 1322.01 22.9998 1322.01 20.5 1382 c 0,206,207 18 1442 18 1442 70 1544 c 0,208,209 89.997 1582.99 89.997 1582.99 126.5 1590 c 0,210,211 154.046 1592.08 l 0,212,213 168.318 1590.79 168.318 1590.79 175 1583 c 0,214,215 124.999 1578.99 124.999 1578.99 114.5 1508.5 c 0,216,217 112.6 1474.11 l 0,218,219 115.168 1439.36 115.168 1439.36 144 1436 c 0,220,221 173.178 1437.94 l 0,222,223 208.051 1445.24 208.051 1445.24 224 1477.5 c 0,224,225 246 1522 246 1522 252 1575 c 0,226,227 256.999 1620 256.999 1620 246 1672.5 c 0,228,229 236.506 1717.81 236.506 1717.81 172.622 1718.06 c 0,230,231 162.495 1718.09 162.495 1718.09 151 1717 c 0,232,233 128.007 1715.01 128.007 1715.01 115.5 1696.5 c 0,234,235 103.708 1679.05 103.708 1679.05 103 1679 c 0,236,237 105.806 1714.01 l 0,238,239 117.15 1769.34 117.15 1769.34 173.5 1784.5 c 0,240,241 189.642 1788.84 189.642 1788.84 205.164 1788.8 c 0,242,243 259.359 1788.64 259.359 1788.64 306 1735 c 0,244,245 363.005 1667.99 363.005 1667.99 396.5 1582.5 c 0,246,247 430 1497 430 1497 473 1428 c 0,248,-1 530 1343.5 l 0,249,250 566.99 1288.67 566.99 1288.67 595.556 1288.37 c 0,251,252 605.034 1288.27 605.034 1288.27 613.585 1294.17 c 0,253,254 618.977 1297.89 618.977 1297.89 624 1304 c 0,255,256 634.821 1316.98 634.821 1316.98 634.87 1331.28 c 0,257,258 634.933 1350.01 634.933 1350.01 616.5 1371 c 0,259,260 588.485 1402.9 588.485 1402.9 554.892 1402.84 c 0,261,262 549.517 1402.83 549.517 1402.83 544 1402 c 0,263,264 562.993 1424.95 562.993 1424.95 587.931 1425.04 c 0,265,266 594.509 1425.07 594.509 1425.07 601.5 1423.5 c 0,267,268 634.987 1416 634.987 1416 653 1405 c 0,269,270 689.001 1379.99 689.001 1379.99 694 1326 c 0,271,272 695.999 1271.01 695.999 1271.01 723.5 1217.5 c 0,273,274 742.767 1180.01 742.767 1180.01 771.12 1180.09 c 0,275,276 783.231 1180.12 783.231 1180.12 797 1187 c 0,277,278 839.999 1208 839.999 1208 857.5 1263.5 c 0,279,280 874.99 1318.97 874.99 1318.97 901 1389 c 0,281,282 937 1485 937 1485 1034.5 1600.5 c 0,283,284 1131.99 1715.99 1131.99 1715.99 1204 1735 c 0,285,286 1299.18 1758.55 1299.18 1758.55 1414.62 1758.51 c 0,287,288 1416.82 1758.51 1416.82 1758.51 1419 1758.5 c 0,289,290 1536.99 1758.01 1536.99 1758.01 1624 1696 c 0,291,292 1668.01 1662.99 1668.01 1662.99 1715 1607 c 0,293,294 1762 1551 1762 1551 1762 1486 c 0,295,296 1762 1451.98 1762 1451.98 1753.5 1420.5 c 0,297,298 1745 1389 1745 1389 1706 1367 c 0,299,300 1732.07 1398.62 1732.07 1398.62 1732.14 1440.1 c 0,301,302 1732.19 1473.38 1732.19 1473.38 1715.5 1513 c 0,303,304 1678 1602 1678 1602 1606 1635 c 0,305,306 1531.03 1668.99 1531.03 1668.99 1449.5 1673 c 0,307,308 1424.97 1670.67 l 0,309,310 1367.02 1655.35 1367.02 1655.35 1362 1544 c 0,311,312 1364.34 1517.8 l 0,313,314 1372.6 1483.53 1372.6 1483.53 1408 1448.5 c 0,315,316 1438.06 1418.76 1438.06 1418.76 1459.46 1418.54 c 0,317,318 1468.94 1418.44 1468.94 1418.44 1476.72 1424.14 c 0,319,320 1480.01 1426.55 1480.01 1426.55 1483 1430 c 0,321,322 1503.71 1453.3 1503.71 1453.3 1503.69 1471.35 c 0,323,324 1503.68 1481.2 1503.68 1481.2 1497.5 1489.5 c 0,325,326 1480.01 1512.99 1480.01 1512.99 1451 1523 c 0,327,328 1462.95 1538.93 1462.95 1538.93 1480.07 1538.84 c 0,329,330 1493.05 1538.77 1493.05 1538.77 1509 1529.5 c 0,331,332 1545.99 1508.01 1545.99 1508.01 1552 1497 c 0,333,334 1562.18 1474.09 1562.18 1474.09 1562.51 1446 c 0,335,336 1558.74 1407.05 l 0,337,338 1554 1387 l 0,339,340 1536 1321.99 1536 1321.99 1500 1278 c 0,341,342 1416.04 1176.16 1416.04 1176.16 1416.08 1061.63 c 0,343,344 1416.1 1028.84 1416.1 1028.84 1423 995 c 0,345,346 1444 887.992 1444 887.992 1476.5 845 c 0,347,348 1508.97 802.053 1508.97 802.053 1539 757 c 0,349,350 1602.07 662.786 1602.07 662.786 1602.09 561.896 c 0,351,352 1602.09 533.218 1602.09 533.218 1597 504 c 0,353,354 1589.99 464.981 1589.99 464.981 1573.5 427.5 c 0,355,356 1557 389.995 1557 389.995 1514 360 c 0,357,358 1503.02 353.01 1503.02 353.01 1475.5 342.5 c 0,359,360 1455.47 338.636 l 0,361,362 1439.99 338.866 1439.99 338.866 1427 350 c 0,363,364 1484 377 1484 377 1494.5 417.5 c 0,365,366 1501.7 445.258 1501.7 445.258 1501.61 472.323 c 0,367,368 1501.57 484.735 1501.57 484.735 1500 497 c 0,369,370 1497 524 1497 524 1451 525.5 c 0,371,372 1429 522.813 l 0,373,374 1401.07 514.148 1401.07 514.148 1390 478 c 0,375,376 1374.99 431.982 1374.99 431.982 1373 369.5 c 0,377,378 1371.01 307 1371.01 307 1379 259 c 0,379,380 1389.99 190.017 1389.99 190.017 1406.5 154 c 0,381,382 1423 118 1423 118 1438 80 c 0,383,384 1469.99 -7 1469.99 -7 1453 -101 c 0,385,386 1436.99 -185.011 1436.99 -185.011 1383 -266 c 0,387,388 1329 -347 1329 -347 1191 -391 c 1,0,1 EndSplineSet KernsSLIF: 65 -104 0 0 97 -104 0 0 105 78 0 0 EndChar StartChar: N Encoding: 78 78 49 Width: 1258 Flags: MW VStem: 112 207<77 1354> 762 258<69 1428.5> Fore 74 -62 m 1,0,1 41 43 41 43 64.5 150 c 0,2,3 87.9992 256.995 87.9992 256.995 108 359 c 0,4,5 138 521 138 521 61 677 c 0,6,7 -16 833 -16 833 17 954 c 0,8,9 20 965 20 965 44 986 c 0,10,11 68 1007 68 1007 101 992 c 0,12,13 9.00005 947 9.00005 947 77.5 905.5 c 0,14,15 146.001 864 146.001 864 146 964 c 0,16,17 146 1059 146 1059 129 1160 c 0,18,19 112 1261 112 1261 112 1354 c 0,20,21 114.761 1469.81 l 0,22,23 116.564 1501.21 116.564 1501.21 119.5 1533.5 c 0,24,25 128.001 1627 128.001 1627 184 1684 c 0,26,27 203.611 1704.22 203.611 1704.22 228.297 1704.54 c 0,28,29 251.074 1700.94 l 0,30,31 256.195 1699.33 256.195 1699.33 261.5 1697 c 0,32,33 307 1677 307 1677 307 1650 c 0,34,35 268.794 1682.55 268.794 1682.55 241.845 1682.8 c 0,36,37 231.258 1682.9 231.258 1682.9 221.5 1677.5 c 0,38,39 189.999 1659 189.999 1659 180.5 1611.5 c 0,40,41 176.467 1591.33 176.467 1591.33 176.489 1569.19 c 0,42,43 176.519 1539.16 176.519 1539.16 184 1505.5 c 0,44,45 196.999 1447.01 196.999 1447.01 233 1413 c 0,46,47 295.992 1350.01 295.992 1350.01 386 1314.5 c 0,48,49 476.011 1278.99 476.011 1278.99 519 1224 c 0,50,51 545.623 1187.93 545.623 1187.93 545.694 1151.12 c 0,52,53 545.706 1145.07 545.706 1145.07 545 1139 c 0,54,55 540.001 1096 540.001 1096 480 1066 c 0,56,-1 502 1105 l 0,57,58 514 1126 514 1126 506 1153 c 0,59,60 497 1178.99 497 1178.99 477.5 1184.5 c 0,61,62 464.262 1184.99 l 0,63,64 453.62 1182.33 453.62 1182.33 446 1169 c 0,65,66 437.906 1155.92 437.906 1155.92 437.953 1128.31 c 0,67,68 437.981 1111.58 437.981 1111.58 441 1089.5 c 0,69,70 449 1031 449 1031 469.5 969.5 c 0,71,72 490 908 490 908 517.5 862 c 0,73,74 541.915 821.159 541.915 821.159 565.149 820.52 c 0,75,76 568.084 820.439 568.084 820.439 571 821 c 0,77,78 643 833 643 833 617 883.5 c 0,79,80 591.001 933.999 591.001 933.999 559 960 c 0,81,82 673 931 673 931 681 835.5 c 0,83,84 689 740 689 740 689 645 c 0,85,86 689 567.999 689 567.999 744 530 c 0,87,88 757.572 520.623 757.572 520.623 768.89 520.563 c 0,89,90 787.453 520.463 787.453 520.463 799.956 545.418 c 0,91,92 810.726 566.914 810.726 566.914 817 607 c 0,93,94 826.998 675.985 826.998 675.985 832.5 743.5 c 0,95,96 838 811 838 811 819 882 c 0,97,98 808 921 808 921 781.5 974.5 c 0,99,100 755 1028.01 755 1028.01 755 1075 c 0,101,102 755 1120 755 1120 773 1156 c 0,103,104 789.176 1188.35 789.176 1188.35 831.992 1188.4 c 0,105,106 836.826 1188.41 836.826 1188.41 842 1188 c 0,107,108 822 1170 822 1170 807 1140 c 0,109,110 792 1110 792 1110 813 1092 c 0,111,112 823 1082.67 823 1082.67 831.5 1082.67 c 0,113,114 848.499 1082.67 848.499 1082.67 859.5 1120 c 0,115,116 876 1175.99 876 1175.99 876 1188 c 0,117,118 876 1262 876 1262 839 1314.5 c 0,119,120 802 1367 802 1367 794 1439 c 0,121,122 794.095 1471.9 l 0,123,124 800.447 1521.51 800.447 1521.51 845.5 1560.5 c 0,125,126 905 1611.99 905 1611.99 953 1535 c 0,127,128 919.238 1535.44 l 0,129,130 871.273 1529.7 871.273 1529.7 870.734 1481.68 c 0,131,132 870.688 1477.5 870.688 1477.5 871 1473 c 0,133,134 876 1401 876 1401 936 1401 c 0,135,136 989.994 1401 989.994 1401 1020 1428.5 c 0,137,138 1050 1455.99 1050 1455.99 1071 1499 c 0,139,140 1093.96 1545.56 1093.96 1545.56 1093.94 1612.45 c 0,141,142 1093.93 1650.44 1093.93 1650.44 1086.5 1695 c 0,143,144 1065.99 1818.01 1065.99 1818.01 1006 1877 c 0,145,146 1102.01 1814 1102.01 1814 1125 1699 c 0,147,148 1148 1583.97 1148 1583.97 1148 1560 c 0,149,150 1148 1485.01 1148 1485.01 1116 1422.5 c 0,151,152 1083.99 1359.96 1083.99 1359.96 1070 1297 c 0,153,154 1062.93 1266.38 1062.93 1266.38 1062.96 1238.99 c 0,155,156 1062.99 1196.62 1062.99 1196.62 1080 1162 c 0,157,158 1107.99 1105.03 1107.99 1105.03 1134 1043 c 0,159,160 1168.01 955 1168.01 955 1183.5 886 c 0,161,162 1198.99 817 1198.99 817 1083 760 c 0,163,-1 1113 802.5 l 0,164,165 1130 827.007 1130 827.007 1130 852 c 0,166,167 1130 892 1130 892 1104 892 c 0,168,169 1077.42 889.157 l 0,170,171 1028.81 876.802 1028.81 876.802 1024 811 c 0,172,173 1015 687 1015 687 1003 556.5 c 0,174,175 991 426 991 426 966 305 c 0,176,177 948 222.001 948 222.001 863 62 c 0,178,179 778 -98 778 -98 670 -79 c 0,180,181 720 -55 720 -55 736.5 -18.5 c 0,182,183 753 18 753 18 762 69 c 0,184,185 775 138 775 138 725.5 292.5 c 0,186,187 676 447 676 447 593 435 c 0,188,189 565 431 565 431 569 395 c 0,190,191 572.22 366.025 572.22 366.025 596.817 365.553 c 0,192,193 610 367 l 0,194,195 596.188 350 596.188 350 578.988 349.934 c 0,196,197 563.812 349.875 563.812 349.875 546 363 c 0,198,199 508 391 508 391 502 411 c 0,200,201 467 518.001 467 518.001 461 595 c 0,202,203 455 671.999 455 671.999 423 770 c 0,204,205 400 839 400 839 373 847 c 0,206,207 364.788 846.446 l 0,208,209 359.164 842.844 359.164 842.844 359.247 828.26 c 0,210,211 359.369 806.668 359.369 806.668 372 761 c 0,212,213 381.671 725.158 381.671 725.158 381.633 684.301 c 0,214,215 381.604 653.34 381.604 653.34 376 619.5 c 0,216,217 363 541 363 541 267 579 c 0,218,219 351 576 351 576 313.5 641.5 c 0,220,221 276 707 276 707 249 644 c 0,222,223 234.53 609.272 234.53 609.272 234.5 559 c 0,224,225 234.999 510.002 234.999 510.002 247 479 c 0,226,227 294.999 346.002 294.999 346.002 326.5 289.5 c 0,228,229 340.656 264.108 340.656 264.108 340.574 218.621 c 0,230,231 340.473 162.892 340.473 162.892 319 77 c 0,232,233 309 36 309 36 268 13 c 0,234,235 227.001 -9.99947 227.001 -9.99947 186 -20 c 0,236,237 230.999 2.99969 230.999 2.99969 250 78.5 c 0,238,239 253.611 106.897 l 0,240,241 252.175 152.133 252.175 152.133 189 152 c 0,242,243 144.001 150.001 144.001 150.001 131 95.5 c 0,244,245 117.999 41 117.999 41 118 -7 c 0,246,247 118 -142 118 -142 217.5 -203.5 c 0,248,249 317 -265 317 -265 431 -271 c 0,250,251 395.576 -276.239 395.576 -276.239 363.232 -276.188 c 0,252,253 265.925 -276.034 265.925 -276.034 196.5 -228 c 0,254,255 104 -164 104 -164 74 -62 c 1,0,1 EndSplineSet KernsSLIF: 65 -234 0 0 97 -208 0 0 EndChar StartChar: O Encoding: 79 79 47 Width: 1417 Flags: HW Fore 263 27 m 1,0,1 233 13.5 233 13.5 202 13.5 c 0,2,3 171 13.5 171 13.5 139 27 c 0,4,5 22 76.0001 22 76.0001 22 185 c 0,6,7 22 261.001 22 261.001 75 455 c 0,8,-1 147 721 l 0,9,10 153.999 750.993 153.999 750.993 158 796 c 0,11,12 156.573 817.294 l 0,13,14 149.813 841.812 149.813 841.812 117 844 c 0,15,16 89.2061 842.225 l 0,17,18 46.2343 832.476 46.2343 832.476 46.0801 776.017 c 0,19,20 46.0569 767.536 46.0569 767.536 47 758 c 0,21,22 19.3514 778.513 19.3514 778.513 19.1465 836.017 c 0,23,24 19.1216 842.987 19.1216 842.987 19.5 850.5 c 0,25,26 23 920 23 920 41.5 1005.5 c 0,27,28 60 1091 60 1091 83.5 1178 c 0,29,30 106.998 1264.99 106.998 1264.99 116 1324 c 0,31,32 128.001 1411.01 128.001 1411.01 174 1492.5 c 0,33,34 201.989 1542.09 201.989 1542.09 257.37 1542.25 c 0,35,36 289.993 1542.35 289.993 1542.35 332.12 1525.3 c 0,37,38 336.018 1523.72 336.018 1523.72 340 1522 c 0,39,40 232.57 1519.34 232.57 1519.34 231.558 1459.92 c 0,41,42 233 1444 l 0,43,44 246.622 1371.02 246.622 1371.02 295 1370 c 0,45,46 373.997 1370 373.997 1370 454 1495 c 0,47,48 502.516 1570.8 502.516 1570.8 502.485 1611.67 c 0,49,50 502.465 1638.19 502.465 1638.19 482 1650 c 0,51,52 451.482 1667.25 451.482 1667.25 427.613 1667.38 c 0,53,54 409.651 1667.48 409.651 1667.48 395.456 1657.88 c 0,55,56 385.869 1651.4 385.869 1651.4 378 1640.5 c 0,57,58 343 1592.01 343 1592.01 330 1567 c 0,59,60 325.922 1585.8 325.922 1585.8 325.899 1602.66 c 0,61,62 325.82 1660.2 325.82 1660.2 373 1695 c 0,63,64 427.818 1735.44 427.818 1735.44 511.724 1735.5 c 0,65,66 521.177 1735.51 521.177 1735.51 531 1735 c 0,67,68 630.999 1729 630.999 1729 758 1669 c 0,69,70 885.004 1609 885.004 1609 924 1539 c 0,71,-1 949.5 1479.5 l 0,72,73 970.969 1429.07 970.969 1429.07 999.5 1372.5 c 0,74,75 1027.99 1316.02 1027.99 1316.02 1060 1270.5 c 0,76,77 1089.79 1228.14 1089.79 1228.14 1118 1228 c 0,78,79 1188.94 1234.16 1188.94 1234.16 1189.13 1280.17 c 0,80,81 1189.18 1293.83 1189.18 1293.83 1183 1311 c 0,82,83 1156 1386.01 1156 1386.01 1090 1388 c 0,84,85 1116.63 1392.13 1116.63 1392.13 1138.87 1392.1 c 0,86,87 1224.37 1392 1224.37 1392 1245 1330.5 c 0,88,89 1260.02 1285.72 1260.02 1285.72 1260.02 1250.8 c 0,90,91 1260.03 1225.27 1260.03 1225.27 1252 1205 c 0,92,93 1227.01 1143.05 1227.01 1143.05 1162 963 c 0,94,95 1114.5 831.456 1114.5 831.456 1114.53 767.21 c 0,96,97 1114.54 743.538 1114.54 743.538 1121 729 c 0,98,99 1134.99 694 1134.99 694 1190 694.5 c 0,100,101 1245 695 1245 695 1257 742 c 0,102,103 1261.16 756.544 1261.16 756.544 1261.24 768.805 c 0,104,105 1261.34 782.452 1261.34 782.452 1256.4 793.271 c 0,106,107 1242.28 824.188 1242.28 824.188 1187 832 c 0,108,109 1197.02 844.659 1197.02 844.659 1221.79 844.798 c 0,110,111 1239.24 844.897 1239.24 844.897 1264.01 838.779 c 0,112,113 1270.74 837.119 1270.74 837.119 1278 835 c 0,114,115 1347.81 814.638 1347.81 814.638 1348.05 740.675 c 0,116,117 1348.06 738.365 1348.06 738.365 1348 736 c 0,118,119 1343.01 576.009 1343.01 576.009 1216.5 460.5 c 0,120,121 1090 344.992 1090 344.992 1030 216 c 0,122,123 1024.6 204.557 1024.6 204.557 1024.65 193.874 c 0,124,125 1024.76 170.939 1024.76 170.939 1050 151.5 c 0,126,127 1063.03 141.468 1063.03 141.468 1082.37 141.534 c 0,128,129 1117.97 141.656 1117.97 141.656 1175 176 c 0,130,131 1155.01 125 1155.01 125 1091 97 c 0,132,133 1026.98 68.9955 1026.98 68.9955 952.5 52.5 c 0,134,135 878 36 878 36 810.5 25.5 c 0,136,137 743 15 743 15 718 1 c 0,138,139 658 -32 658 -32 567 -58 c 0,140,141 522.468 -70.7233 522.468 -70.7233 476.5 -70.7546 c 0,142,143 428.532 -70.7873 428.532 -70.7873 379 -57 c 0,144,145 367 -53 367 -53 343.5 -37 c 0,146,147 320 -21 320 -21 315 11 c 0,148,149 368 -31 368 -31 410 -27 c 0,150,151 452 -23 452 -23 473 -1 c 0,152,153 497 25 497 25 456 54.5 c 0,154,155 415 84.0001 415 84.0001 353.5 106.5 c 0,156,157 292 129 292 129 233.5 138 c 0,158,159 189.68 141.609 l 0,160,161 170.8 140.934 170.8 140.934 166 134 c 0,162,163 152.476 114.369 152.476 114.369 152.56 97.6881 c 0,164,165 152.668 76.131 152.668 76.131 175.5 59.5 c 0,166,167 216 30 216 30 263 27 c 1,0,1 887 310 m 1,85,86 899 334 899 334 890.5 373 c 0,87,88 882 412 882 412 832 394 c 0,89,90 781 376 781 376 788 333 c 0,91,92 795 290 795 290 818 288 c 0,93,94 749 286 749 286 745 349 c 0,95,96 739 418 739 418 790 450.5 c 0,97,98 841 483 841 483 889 534 c 0,99,100 904 551 904 551 945 692.5 c 0,101,102 986 834 986 834 968 910 c 0,103,104 946 999 946 999 872.5 1038 c 0,105,106 799 1077 799 1077 799 1186 c 0,107,108 799 1200.99 799 1200.99 817 1212.5 c 0,109,110 826.229 1218.4 826.229 1218.4 836.25 1218.38 c 0,111,112 845.767 1218.36 845.767 1218.36 856 1213 c 0,113,114 840.205 1210.37 840.205 1210.37 839.81 1193.49 c 0,115,116 839.755 1191.13 839.755 1191.13 840 1188.5 c 0,117,118 842 1167.01 842 1167.01 860 1166 c 0,119,120 872.806 1168.21 l 0,121,122 884.747 1174.44 884.747 1174.44 884.653 1197.6 c 0,123,124 884.553 1222.09 884.553 1222.09 871 1265.5 c 0,125,126 839 1367.99 839 1367.99 736 1390 c 0,127,128 628 1412.99 628 1412.99 550.5 1369 c 0,129,130 473 1325.01 473 1325.01 473 1256 c 0,131,132 473 1230.99 473 1230.99 505 1214 c 0,133,134 525.872 1202.91 525.872 1202.91 548.866 1202.89 c 0,135,136 561.131 1202.87 561.131 1202.87 574 1206 c 0,137,138 603.86 1213.31 603.86 1213.31 604.012 1235.48 c 0,139,140 604.11 1249.69 604.11 1249.69 592 1270 c 0,141,142 628.292 1265.05 628.292 1265.05 628.527 1221.67 c 0,143,144 628.577 1212.45 628.577 1212.45 627 1201.5 c 0,145,146 618.002 1139.01 618.002 1139.01 585 1126 c 0,147,148 547.001 1111 547.001 1111 491 1102 c 0,149,150 435.018 1093 435.018 1093 388 1073 c 0,151,152 356.003 1059.01 356.003 1059.01 331 996 c 0,153,154 306 933 306 933 289.5 859 c 0,155,156 273 785 273 785 264.5 719 c 0,157,158 256 653 256 653 257 632 c 0,159,160 260 542 260 542 312.5 522.5 c 0,161,162 365 503 365 503 416 449 c 0,163,164 443 420 443 420 441 370.5 c 0,165,166 439 321 439 321 402 316 c 0,167,168 411.192 332.085 411.192 332.085 411.143 345.2 c 0,169,170 411.106 354.915 411.106 354.915 406 363 c 0,171,172 394 382 394 382 360 373 c 0,173,174 322 363 322 363 328.5 317.5 c 0,175,176 335 272 335 272 371 252 c 0,177,178 468.098 195.621 468.098 195.621 594.015 195.652 c 0,179,180 628.902 195.661 628.902 195.661 666 200 c 0,181,182 837 220 837 220 887 310 c 1,85,86 EndSplineSet KernsSLIF: 121 -78 0 0 89 -91 0 0 97 -156 0 0 65 -156 0 0 120 -156 0 0 88 -156 0 0 87 -234 0 0 116 -286 0 0 84 -365 0 0 EndChar StartChar: P Encoding: 80 80 61 Width: 1329 Flags: MW VStem: 197 325<73 1477> Fore 518 874 m 0,0,1 606 816 606 816 627 886 c 0,2,3 650 964 650 964 611 956.5 c 0,4,5 572 949 572 949 555 928 c 0,6,7 543 943 543 943 554.5 971.5 c 0,8,9 566 1000 566 1000 578 1012 c 0,10,11 627 1061.01 627 1061.01 677 1025.5 c 0,12,13 726.986 990.005 726.986 990.005 783 974 c 0,14,15 852 953 852 953 878.5 1050 c 0,16,17 905.001 1147.01 905.001 1147.01 910 1231 c 0,18,19 908.901 1282.34 l 0,20,21 904.241 1331.41 904.241 1331.41 886 1384.5 c 0,22,23 857.997 1466 857.997 1466 788 1505 c 0,24,25 746.02 1526.99 746.02 1526.99 701 1528 c 0,26,27 656 1529.01 656 1529.01 661 1453 c 0,28,29 663 1415 663 1415 696.5 1410.5 c 0,30,31 726.891 1410.32 l 0,32,33 746.742 1412.61 746.742 1412.61 768 1421 c 0,34,35 761.001 1388.01 761.001 1388.01 727 1373.5 c 0,36,37 705.194 1364.2 705.194 1364.2 689.55 1364.16 c 0,38,39 680.813 1364.13 680.813 1364.13 674 1367 c 0,40,41 603.995 1394 603.995 1394 569.5 1438.5 c 0,42,43 535.012 1482.99 535.012 1482.99 511 1493 c 0,44,45 487.022 1501.95 487.022 1501.95 468.037 1502.06 c 0,46,47 451.651 1502.15 451.651 1502.15 438.986 1495.66 c 0,48,49 425.329 1488.66 425.329 1488.66 416 1474 c 0,50,51 393 1439 393 1439 391.5 1350.5 c 0,52,53 394.035 1261.13 l 0,54,55 397.399 1214.16 397.399 1214.16 405 1165 c 0,56,57 419.999 1068 419.999 1068 449.5 984 c 0,58,59 479 900 479 900 518 874 c 0,0,1 235 -68 m 0,36,37 233.325 25.6653 l 0,38,39 237.033 178.49 237.033 178.49 283 327.5 c 0,40,41 319.793 446.772 319.793 446.772 319.734 573.376 c 0,42,43 319.697 653.229 319.697 653.229 305 736 c 0,44,45 288.001 824.999 288.001 824.999 232 888 c 0,46,47 176 951.001 176 951.001 164 1029 c 0,48,49 162.356 1058.78 l 0,50,51 163.651 1078.43 163.651 1078.43 170.5 1102 c 0,52,53 182.999 1145.01 182.999 1145.01 222 1150 c 0,54,55 205.412 1107.34 205.412 1107.34 205.203 1079.82 c 0,56,57 205.105 1067.02 205.105 1067.02 208.55 1057.49 c 0,58,59 216.453 1035.63 216.453 1035.63 243 1031 c 0,60,61 265.996 1030.34 l 0,62,63 303.391 1035.78 303.391 1035.78 312 1089 c 0,64,65 310.993 1137.94 l 0,66,67 308.867 1164.38 308.867 1164.38 304 1202 c 0,68,69 293.002 1286.99 293.002 1286.99 266 1363.5 c 0,70,71 239.003 1439.99 239.003 1439.99 197 1477 c 0,72,73 181.88 1490.32 181.88 1490.32 164.686 1490.29 c 0,74,75 134.121 1490.24 134.121 1490.24 97 1448 c 0,76,77 59.3301 1404.67 59.3301 1404.67 59.3529 1351.6 c 0,78,79 59.3544 1348.32 59.3544 1348.32 59.5 1345 c 0,80,81 62 1288 62 1288 83 1261 c 0,82,83 101 1237 101 1237 109 1222 c 0,84,85 117.003 1206.99 117.003 1206.99 141 1199 c 0,86,87 78 1208 78 1208 67.5 1221.5 c 0,88,89 56.9847 1235.02 56.9847 1235.02 33 1258 c 0,90,91 10.9999 1303 10.9999 1303 10 1340 c 0,92,93 12.5953 1401.58 l 0,94,95 13.6097 1411.57 13.6097 1411.57 15 1422 c 0,96,97 27.0018 1502.01 27.0018 1502.01 71 1555 c 0,98,99 176 1676.01 176 1676.01 269 1705 c 0,100,101 353.428 1731.32 353.428 1731.32 498.8 1731.28 c 0,102,103 513.581 1731.28 513.581 1731.28 529 1731 c 0,104,105 694.016 1728 694.016 1728 811 1689.5 c 0,106,107 928.032 1650.98 928.032 1650.98 1071 1557 c 0,108,109 1142.03 1508.98 1142.03 1508.98 1204 1436 c 0,110,111 1238.68 1395.16 1238.68 1395.16 1238.63 1344.64 c 0,112,113 1238.59 1304.83 1238.59 1304.83 1217 1259 c 0,114,115 1201 1225 1201 1225 1177.5 1206 c 0,116,117 1154.01 1187.01 1154.01 1187.01 1103 1183 c 0,118,119 1122 1215.99 1122 1215.99 1129.5 1250 c 0,120,121 1130.62 1272.67 l 0,122,123 1127.86 1294.49 1127.86 1294.49 1110 1315 c 0,124,125 1098.99 1326.01 1098.99 1326.01 1065.5 1334 c 0,126,127 1032.01 1341.99 1032.01 1341.99 1031 1289 c 0,128,129 1032.07 1159.01 l 0,130,131 1033.01 1135.15 1033.01 1135.15 1034.5 1111.5 c 0,132,133 1035.52 1032.62 l 0,134,135 1033.73 983.704 1033.73 983.704 1026 934 c 0,136,137 1017 876.978 1017 876.978 968 749.5 c 0,138,139 919 622 919 622 836 589 c 0,140,141 782 568 782 568 699.5 588 c 0,142,143 617 608 617 608 596 671 c 0,144,145 653 642 653 642 708 645 c 0,146,147 773 648 773 648 777 682 c 0,148,149 774.961 695.917 l 0,150,151 764.158 721.263 764.158 721.263 701 741 c 0,152,153 651 756 651 756 596 745.5 c 0,154,155 541 735 541 735 509 694 c 0,156,157 485.999 663.998 485.999 663.998 466 566 c 0,158,159 454.824 511.235 454.824 511.235 454.889 464.59 c 0,160,161 454.941 427.764 454.941 427.764 462 396 c 0,162,163 481.006 309.979 481.006 309.979 500.5 233 c 0,164,165 520.001 155.999 520.001 155.999 522 73 c 0,166,167 525 -94 525 -94 450 -233 c 0,168,169 423 -283 423 -283 341.5 -349 c 0,170,171 260.001 -415 260.001 -415 201 -415 c 0,172,173 287 -373 287 -373 379 -249.5 c 0,174,175 442.033 -164.885 442.033 -164.885 442.164 -90.362 c 0,176,177 442.224 -56.1152 442.224 -56.1152 429 -24 c 0,178,179 405 31 405 31 363 27.5 c 0,180,181 321 24 321 24 289 -18 c 0,182,183 268 -46 268 -46 275.5 -98.5 c 0,184,185 283 -151 283 -151 294 -175 c 0,186,187 239.001 -134.001 239.001 -134.001 235 -68 c 0,36,37 EndSplineSet KernsSLIF: 45 -208 0 0 46 -260 0 0 44 -286 0 0 116 -91 0 0 84 -195 0 0 321 -363 0 0 322 -363 0 0 65 -342 0 0 97 -363 0 0 EndChar StartChar: Q Encoding: 81 81 32 Width: 1255 Flags: W Fore 946 1665 m 1,0,1 972.261 1677.88 972.261 1677.88 999.749 1678 c 0,2,3 1023.34 1678.1 1023.34 1678.1 1047.83 1668.8 c 0,4,5 1052.4 1667.06 1052.4 1667.06 1057 1665 c 0,6,7 1162 1612.99 1162 1612.99 1162 1503 c 0,8,9 1162 1424.01 1162 1424.01 1114 1225 c 0,10,11 1066.03 1026.12 1066.03 1026.12 1050 953 c 0,12,13 1042.99 921 1042.99 921 1039.5 875 c 0,14,15 1036.01 829 1036.01 829 1077 826 c 0,16,17 1100.59 827.702 l 0,18,19 1139.62 837.667 1139.62 837.667 1139.65 898.428 c 0,20,21 1139.65 906.288 1139.65 906.288 1139 915 c 0,22,23 1170.9 877.5 1170.9 877.5 1171.01 822.931 c 0,24,25 1171.1 779.997 1171.1 779.997 1151.5 726.5 c 0,26,27 1107 605.014 1107 605.014 1107 504 c 0,28,29 1107 402.008 1107 402.008 1139 350.5 c 0,30,31 1170.99 299 1170.99 299 1163 239 c 0,32,33 1152.01 149.012 1152.01 149.012 1110 77.5 c 0,34,35 1086.04 36.7115 1086.04 36.7115 1040.93 36.4396 c 0,36,37 1024.38 36.3399 1024.38 36.3399 1005 41.6884 c 0,38,39 984.575 47.3221 984.575 47.3221 961 59 c 0,40,41 1067.99 61 1067.99 61 1055.5 138 c 0,42,43 1043.33 212.974 1043.33 212.974 1001 214 c 0,44,45 983 214 983 214 942 177.5 c 0,46,47 901 141.001 901 141.001 901 95 c 0,48,49 899 34 899 34 925 15 c 0,50,51 951 -4.00001 951 -4.00001 985 -23 c 0,52,53 1018.99 -41.9901 1018.99 -41.9901 1050 -81.5 c 0,54,55 1080.99 -120.985 1080.99 -120.985 1091 -223 c 0,56,57 1055 -129.996 1055 -129.996 979 -79.5 c 0,58,59 903 -29 903 -29 877 -98 c 0,60,61 859 -144.999 859 -144.999 956.5 -251 c 0,62,63 1054 -357 1054 -357 1183 -365 c 0,64,65 1121.24 -362.563 l 0,66,67 1028.23 -352.747 1028.23 -352.747 951.5 -305.5 c 0,68,69 850 -243 850 -243 782 -175 c 0,70,71 723.983 -116.983 723.983 -116.983 724 -55 c 0,72,73 725 6.00005 725 6.00005 698 16 c 0,74,75 684.054 21.1892 684.054 21.1892 671.37 21.1191 c 0,76,77 644.946 20.973 644.946 20.973 624 -2 c 0,78,79 593 -36 593 -36 522 -50 c 0,80,81 244 -101 244 -101 220 54 c 0,82,83 286 0 286 0 337 21 c 0,84,85 388 42 388 42 355 114 c 0,86,87 351.005 121.989 351.005 121.989 332 173.5 c 0,88,89 313 224.999 313 224.999 287 283 c 0,90,91 261 341 261 341 232.5 387.5 c 0,92,93 204.564 433.08 204.564 433.08 182 433 c 0,94,95 99.0005 424 99.0005 424 123 346.5 c 0,96,97 147 269 147 269 207 269 c 0,98,99 187.571 253.572 187.571 253.572 167.49 253.49 c 0,100,101 152.429 253.429 152.429 253.429 137 262 c 0,102,103 101 282 101 282 95 291 c 0,104,105 42 354 42 354 65 457 c 0,106,107 71 489 71 489 93.5 559 c 0,108,-1 138.5 705 l 0,109,110 160.999 780.995 160.999 780.995 175.5 848.5 c 0,111,112 190.001 916 190.001 916 180 944 c 0,113,114 166.999 979 166.999 979 117.5 979 c 0,115,116 68 979 68 979 58 932 c 0,117,118 39 851 39 851 120 839 c 0,119,120 102 815 102 815 39.5 836 c 0,121,122 -23 857 -23 857 -22 937 c 0,123,124 -17.9997 1101.01 -17.9997 1101.01 94.5 1220 c 0,125,126 206.996 1338.99 206.996 1338.99 261 1471 c 0,127,128 276 1507 276 1507 241 1522 c 0,129,130 206.001 1537 206.001 1537 154 1459 c 0,131,132 158.999 1543 158.999 1543 213.5 1582 c 0,133,134 268.01 1621.01 268.01 1621.01 335 1638 c 0,135,136 402.083 1655.02 402.083 1655.02 462.5 1663 c 0,137,138 522.996 1670.99 522.996 1670.99 540 1692 c 0,139,140 572 1732.01 572 1732.01 504 1761 c 0,141,142 482.218 1770.29 482.218 1770.29 461.258 1770.34 c 0,143,144 423.561 1770.44 423.561 1770.44 388.522 1740.68 c 0,145,146 382.218 1735.32 382.218 1735.32 376 1729 c 0,147,148 382.001 1806.01 382.001 1806.01 465.5 1821.5 c 0,149,150 549 1836.99 549 1836.99 587 1820 c 0,151,152 656 1787 656 1787 697 1740.5 c 0,153,154 738.065 1693.93 738.065 1693.93 756 1672 c 0,155,156 819.012 1591.99 819.012 1591.99 912.5 1554 c 0,157,158 958.669 1535.24 958.669 1535.24 988.622 1535.25 c 0,159,160 1019.33 1535.26 1019.33 1535.26 1033 1555 c 0,161,162 1046.31 1574.97 1046.31 1574.97 1046.33 1592.08 c 0,163,164 1046.36 1613.54 1046.36 1613.54 1025.5 1630.5 c 0,165,166 988 1660.99 988 1660.99 946 1665 c 0,167,-1 946 1665 l 1,0,1 735 1510 m 0,105,106 636 1511.01 636 1511.01 529.5 1478.5 c 0,107,108 422.998 1445.99 422.998 1445.99 389 1374 c 0,109,110 377 1350 377 1350 384.5 1309.5 c 0,111,112 389.617 1281.87 389.617 1281.87 412.654 1281.93 c 0,113,114 423.383 1281.96 423.383 1281.96 438 1288 c 0,115,116 476.322 1303.68 476.322 1303.68 476.716 1339.08 c 0,117,118 476.774 1344.32 476.774 1344.32 476 1350 c 0,119,120 469.999 1394 469.999 1394 451 1397 c 0,121,122 475.763 1394.05 l 0,123,124 512.154 1383.46 512.154 1383.46 516 1335 c 0,125,126 514.434 1298.61 l 0,127,128 507.433 1254.61 507.433 1254.61 474.5 1230 c 0,129,130 428.988 1195.99 428.988 1195.99 387 1145 c 0,131,132 371.997 1127 371.997 1127 332.5 980.5 c 0,133,134 304.311 875.949 304.311 875.949 304.388 806.797 c 0,135,136 304.418 779.049 304.418 779.049 309 757 c 0,137,138 328.001 664.999 328.001 664.999 402.5 593 c 0,139,140 477 521 477 521 477 410 c 0,141,142 477 395 477 395 460.5 382.5 c 0,143,144 444 370 444 370 426 382 c 0,145,146 441 385 441 385 439 407 c 0,147,148 437 429 437 429 422 431 c 0,149,150 383 434 383 434 376 361.5 c 0,151,152 369 289 369 289 435 243 c 0,153,154 476 213 476 213 527 201 c 0,155,156 578 189 578 189 608 204 c 0,157,158 667 229.999 667 229.999 656 285 c 0,159,160 645 340 645 340 582 376 c 0,161,162 678 371 678 371 691.5 318.5 c 0,163,164 705 266 705 266 768 262 c 0,165,166 807 259 807 259 826.5 295 c 0,167,168 846 331 846 331 846 349 c 0,169,170 846 373.999 846 373.999 817 391.5 c 0,171,172 797.184 403.458 797.184 403.458 776.433 403.509 c 0,173,174 766.817 403.533 766.817 403.533 757 401 c 0,175,176 729.121 393.121 729.121 393.121 728.791 370.55 c 0,177,178 732.807 350.482 l 0,179,180 735.501 343.222 735.501 343.222 740 335 c 0,181,182 706.857 339.971 706.857 339.971 706.668 384.761 c 0,183,184 706.629 394.028 706.629 394.028 708 405 c 0,185,186 716 469 716 469 746 483 c 0,187,188 779 498 779 498 846 517.5 c 0,189,190 913 537 913 537 937 598 c 0,191,192 961 661 961 661 940 875.5 c 0,193,194 919 1089.99 919 1089.99 810 1232 c 0,195,196 787.5 1260.13 787.5 1260.13 787.412 1305.83 c 0,197,198 787.406 1308.88 787.406 1308.88 787.5 1312 c 0,199,200 789 1362 789 1362 822 1368 c 0,201,202 813.495 1350.99 813.495 1350.99 813.349 1337.68 c 0,203,204 813.25 1328.63 813.25 1328.63 818 1319.5 c 0,205,206 825.334 1307.17 825.334 1307.17 841.555 1307.06 c 0,207,208 849.667 1307 849.667 1307 860 1310 c 0,209,210 893 1320.01 893 1320.01 893 1371 c 0,211,212 893 1421.99 893 1421.99 869 1450 c 0,213,214 845.986 1476.01 845.986 1476.01 805.5 1493 c 0,215,216 764.988 1510 764.988 1510 735 1510 c 0,105,106 EndSplineSet EndChar StartChar: R Encoding: 82 82 57 Width: 1327 Flags: MW VStem: 112 318<-13 1619> Fore 1128 -43 m 0,0,1 1125 20.0058 1125 20.0058 1077.5 71.5 c 0,2,3 1029.99 123.002 1029.99 123.002 969 136 c 0,4,5 942.51 137.844 l 0,6,7 911.739 135.321 911.739 135.321 893.5 108.5 c 0,8,9 868 71 868 71 903 37 c 0,10,11 933 7 933 7 951 20 c 0,12,13 969 33 969 33 987 57 c 0,14,15 1005 -25 1005 -25 930 -45 c 0,16,17 855 -65 855 -65 813 -4 c 0,18,19 780 44 780 44 770.5 108.5 c 0,20,21 761 173 761 173 745 227 c 0,22,23 716.999 318.002 716.999 318.002 642.5 454 c 0,24,25 568 590 568 590 472 611 c 0,26,27 436 617 436 617 386 598.5 c 0,28,29 337.069 580.396 337.069 580.396 337 505 c 0,30,31 337 368 337 368 381 245 c 0,32,33 425 122 425 122 416 -26 c 0,34,35 411.001 -102.999 411.001 -102.999 341.5 -186 c 0,36,37 272 -269.001 272 -269.001 200 -295 c 0,38,39 147.999 -313 147.999 -313 102 -320.5 c 0,40,41 55.9999 -328 55.9999 -328 -1 -319 c 0,42,43 64 -309 64 -309 138 -277 c 0,44,45 181.001 -256 181.001 -256 248.5 -196.5 c 0,46,47 316.001 -136.999 316.001 -136.999 321 -47 c 0,48,49 324 14 324 14 310 68 c 0,50,51 296 122 296 122 220 121 c 0,52,53 161.371 119.046 161.371 119.046 161 33.5 c 0,54,55 162.001 -52.0001 162.001 -52.0001 222 -74 c 0,56,57 185.921 -72.0319 l 0,58,59 160.223 -67.6052 160.223 -67.6052 146 -54 c 0,60,61 122.998 -31.9977 122.998 -31.9977 112 -13 c 0,62,63 87.1224 30.6532 87.1224 30.6532 87.0314 92.7034 c 0,64,65 86.9318 160.706 86.9318 160.706 116.602 250.804 c 0,66,67 117.536 253.642 117.536 253.642 118.5 256.5 c 0,68,69 177.998 432.992 177.998 432.992 200 529 c 0,70,71 213.298 586.794 213.298 586.794 213.255 619.738 c 0,72,73 213.214 651.206 213.214 651.206 201 660 c 0,74,75 189.636 668.182 189.636 668.182 179.512 668.306 c 0,76,77 171.681 668.402 171.681 668.402 164.591 663.676 c 0,78,79 160.683 661.07 160.683 661.07 157 657 c 0,80,81 138.001 636.001 138.001 636.001 135.5 602 c 0,82,83 136.939 576.347 l 0,84,85 140.286 561.572 140.286 561.572 150 553 c 0,86,87 81 556 81 556 73.5 615.5 c 0,88,89 66 675 66 675 75 710 c 0,90,91 88.9999 771 88.9999 771 129 837.5 c 0,92,93 168.998 903.996 168.998 903.996 185 966 c 0,94,95 209 1063.01 209 1063.01 200 1164 c 0,96,97 187.999 1302.01 187.999 1302.01 165.5 1448 c 0,98,99 161.539 1473.7 161.539 1473.7 161.56 1498.62 c 0,100,101 161.659 1615.3 161.659 1615.3 249 1715 c 0,102,103 332.004 1811.01 332.004 1811.01 498.5 1823.5 c 0,104,105 542.128 1823.16 l 0,106,107 666.124 1810.3 666.124 1810.3 673 1653 c 0,108,109 633 1746 633 1746 526 1740 c 0,110,111 429.612 1734.6 429.612 1734.6 428.979 1640.74 c 0,112,113 428.909 1630.41 428.909 1630.41 430 1619 c 0,114,115 433 1582 433 1582 480 1559.5 c 0,116,117 527.013 1536.99 527.013 1536.99 583 1530.5 c 0,118,119 634.872 1528.19 l 0,120,121 661.46 1529.07 661.46 1529.07 685.5 1534.5 c 0,122,123 732 1545 732 1545 734 1575 c 0,124,125 730.88 1592.46 l 0,126,127 720.662 1615.48 720.662 1615.48 677.121 1615.69 c 0,128,129 669.123 1615.73 669.123 1615.73 660 1615 c 0,130,131 696.965 1635.92 696.965 1635.92 737.127 1635.89 c 0,132,133 779.53 1635.87 779.53 1635.87 825.5 1612.5 c 0,134,135 914.997 1567.01 914.997 1567.01 949 1468 c 0,136,137 974.001 1390 974.001 1390 1011 1367.5 c 0,138,139 1047.99 1345.01 1047.99 1345.01 1111 1288 c 0,140,141 1137.99 1262.01 1137.99 1262.01 1149.5 1203.5 c 0,142,143 1150.82 1178.98 l 0,144,145 1146.53 1137.32 1146.53 1137.32 1095 1110 c 0,146,147 1121.6 1139.56 1121.6 1139.56 1121.65 1165.79 c 0,148,149 1121.68 1183.94 1121.68 1183.94 1109 1200.5 c 0,150,151 1088.51 1227.26 1088.51 1227.26 1070.66 1227.17 c 0,152,153 1061.48 1227.12 1061.48 1227.12 1053 1220 c 0,154,155 1037.03 1206.94 1037.03 1206.94 1036.99 1173.85 c 0,156,157 1036.94 1138.57 1036.94 1138.57 1055 1080.5 c 0,158,159 1089.99 968 1089.99 968 1064 859 c 0,160,161 1038.99 757 1038.99 757 945.5 742.5 c 0,162,163 852 728 852 728 813 764 c 0,164,165 854.001 765 854.001 765 885 788.5 c 0,166,167 916 812 916 812 907 857 c 0,168,169 892 927 892 927 809 855.5 c 0,170,171 726 784 726 784 738 710 c 0,172,173 744 666 744 666 803.5 620 c 0,174,175 863 574 863 574 887 593 c 0,176,177 897.886 601.165 897.886 601.165 898.107 612.144 c 0,178,179 894.131 627.135 l 0,180,181 892.791 629.758 892.791 629.758 891 632.5 c 0,182,183 875 657 875 657 833 657 c 0,184,185 837 687 837 687 889 687 c 0,186,187 941 687 941 687 967 659 c 0,188,189 1000 620 1000 620 991 539 c 0,190,191 982 458 982 458 982 408 c 0,192,193 982 300.001 982 300.001 1059 269.5 c 0,194,195 1135.99 239.001 1135.99 239.001 1191 158 c 0,196,197 1234 94.0096 1234 94.0096 1249 7.5 c 0,198,199 1257.42 -41.0666 1257.42 -41.0666 1257.33 -82.5396 c 0,200,201 1257.26 -114.933 1257.26 -114.933 1252 -143 c 0,202,203 1196.01 -418.993 1196.01 -418.993 985.5 -531 c 0,204,205 775.003 -642.999 775.003 -642.999 531 -677 c 0,206,207 771.001 -609.999 771.001 -609.999 956.5 -466.5 c 0,208,209 1128.86 -333.171 1128.86 -333.171 1128.98 -81.9849 c 0,210,211 1128.99 -62.8342 1128.99 -62.8342 1128 -43 c 0,0,1 596 909 m 0,125,126 622 881 622 881 659.5 894.5 c 0,127,128 697 908 697 908 739 937 c 0,129,130 788 971 788 971 817.5 1042.5 c 0,131,132 846.999 1114 846.999 1114 852.5 1183.5 c 0,133,134 853.032 1236.31 l 0,135,136 850.538 1272.97 850.538 1272.97 839.5 1302.5 c 0,137,138 824.154 1343.56 824.154 1343.56 789.89 1343.68 c 0,139,140 782.845 1343.71 782.845 1343.71 775 1342 c 0,141,142 736 1333 736 1333 732.5 1301.5 c 0,143,144 734.396 1286.82 l 0,145,146 743.097 1264.03 743.097 1264.03 788 1245 c 0,147,148 704 1231.99 704 1231.99 664.5 1276.5 c 0,149,150 625.002 1321 625.002 1321 584 1347 c 0,151,152 543.637 1371.84 543.637 1371.84 506.754 1372.04 c 0,153,154 488.577 1372.14 488.577 1372.14 471.246 1366.26 c 0,155,156 455.786 1361.01 455.786 1361.01 441 1351 c 0,157,158 376.004 1307.01 376.004 1307.01 346 1215 c 0,159,160 331 1171.01 331 1171.01 322 1032 c 0,161,162 313 893 313 893 394 878 c 0,163,164 420.822 875.578 l 0,165,166 464.908 878.309 464.908 878.309 465.305 934.977 c 0,167,168 465.342 940.254 465.342 940.254 465 946 c 0,169,170 461.845 983.859 461.845 983.859 419.498 984.392 c 0,171,172 394 982 l 0,173,174 395.633 992.939 l 0,175,176 401.858 1006 401.858 1006 429 1016 c 0,177,178 449.668 1023.61 449.668 1023.61 464.713 1023.54 c 0,179,180 477.334 1023.47 477.334 1023.47 486 1018 c 0,181,182 561 967 561 967 552.5 965.5 c 0,183,184 544 964 544 964 596 909 c 0,125,126 EndSplineSet KernsSLIF: 89 -143 0 0 121 -130 0 0 83 -208 0 0 71 -104 0 0 116 -286 0 0 84 -313 0 0 86 -22 0 0 87 -150 0 0 EndChar StartChar: S Encoding: 83 83 15 Width: 1364 Flags: HW Fore 598 -86 m 0,0,1 580 -78.0001 580 -78.0001 553.5 -52 c 0,2,3 531.24 -30.1606 531.24 -30.1606 531.206 -9.7312 c 0,4,5 531.2 -5.8401 531.2 -5.8401 532 -2 c 0,6,7 556.993 -17.9955 556.993 -17.9955 582 -36.5 c 0,8,9 594 -45.38 594 -45.38 606 -45.62 c 0,10,11 622 -42.1 l 0,12,13 627 -39.8 627 -39.8 632 -36 c 0,14,15 649.627 -22.339 649.627 -22.339 649.777 -9.26058 c 0,16,17 649.872 -0.893791 649.872 -0.893791 642.815 7.23458 c 0,18,19 635.87 15.2327 635.87 15.2327 622 23 c 0,20,21 572 51 572 51 493 79 c 0,22,-1 335.5 134 l 0,23,24 256.999 161 256.999 161 240 188 c 0,25,26 211.999 230 211.999 230 219 294.5 c 0,27,28 226 359 226 359 283 372 c 0,29,30 283.268 329.648 l 0,31,32 286.957 296.146 286.957 296.146 303 278.5 c 0,33,34 328 251 328 251 403 274 c 0,35,36 445 286 445 286 436.5 339 c 0,37,38 427.999 392.001 427.999 392.001 414 421 c 0,39,40 384 481 384 481 302.5 515.5 c 0,41,42 221.001 550 221.001 550 157 560 c 0,43,44 122.001 565 122.001 565 83.5 557.5 c 0,45,46 45 550 45 550 8 542 c 0,47,48 79 596 79 596 130.5 595.5 c 0,49,50 182.001 595 182.001 595 200 594 c 0,51,52 248 591 248 591 326.5 558 c 0,53,54 405 525 405 525 438 494 c 0,55,56 492.001 441.998 492.001 441.998 546 351 c 0,57,58 599.621 260.638 599.621 260.638 666 208 c 0,59,60 704 176.999 704 176.999 783 160 c 0,61,62 809.78 154.237 809.78 154.237 831.963 154.22 c 0,63,64 875.22 154.187 875.22 154.187 901 176 c 0,65,66 998 261.999 998 261.999 1013 374.5 c 0,67,68 1028 487 1028 487 992 570 c 0,69,70 974 612 974 612 893.5 669 c 0,71,72 813 726 813 726 754 729 c 0,73,74 721.157 727.957 l 0,75,76 684 721.514 684 721.514 684 688 c 0,77,78 684 637 684 637 705 625.5 c 0,79,-1 764 593 l 0,80,81 740.845 584.699 740.845 584.699 718.262 584.796 c 0,82,83 689.155 584.922 689.155 584.922 661 599 c 0,84,85 611 624 611 624 592 672 c 0,86,-1 546.5 782 l 0,87,88 510 870 510 870 460.5 963 c 0,89,90 411.009 1055.98 411.009 1055.98 356.5 1124.5 c 0,91,92 311.764 1180.73 311.764 1180.73 272.75 1180.69 c 0,93,94 264.239 1180.69 264.239 1180.69 256 1178 c 0,95,96 220.5 1166.49 220.5 1166.49 220.442 1108.94 c 0,97,98 220.439 1106.51 220.439 1106.51 220.5 1104 c 0,99,100 222 1041.99 222 1041.99 256 1034 c 0,101,102 231.657 1031.21 l 0,103,104 199.094 1032.81 199.094 1032.81 182 1067 c 0,105,106 159 1113.01 159 1113.01 159 1134 c 0,107,108 159 1199 159 1199 174 1247 c 0,109,110 189 1295 189 1295 213 1343 c 0,111,112 270.997 1462.99 270.997 1462.99 412.5 1566 c 0,113,114 554 1669.01 554 1669.01 611 1704 c 0,115,116 689.946 1749.97 689.946 1749.97 763 1779.5 c 0,117,118 836 1809.01 836 1809.01 1021 1775 c 0,119,120 1123.01 1755.99 1123.01 1755.99 1179 1697 c 0,121,122 1235 1638 1235 1638 1241 1590 c 0,123,124 1170.01 1684.01 1170.01 1684.01 1043 1644 c 0,125,126 1000.99 1630.99 1000.99 1630.99 980 1586.5 c 0,127,128 959 1541.99 959 1541.99 963 1495 c 0,129,130 972.959 1370.96 972.959 1370.96 1086.21 1370.29 c 0,131,132 1098.04 1370.22 1098.04 1370.22 1111 1371.5 c 0,133,134 1247.98 1385 1247.98 1385 1338 1414 c 0,135,136 1283 1338 1283 1338 1180 1315.5 c 0,137,138 1110.41 1300.3 1110.41 1300.3 1067.29 1300.39 c 0,139,140 1046.6 1300.43 1046.6 1300.43 1032 1304 c 0,141,142 943.012 1323.99 943.012 1323.99 902 1366.5 c 0,143,144 861 1408.99 861 1408.99 803 1461 c 0,145,146 761.569 1497.43 761.569 1497.43 707.898 1497.38 c 0,147,148 686.428 1497.36 686.428 1497.36 663 1491.5 c 0,149,150 580.997 1470.99 580.997 1470.99 545 1396 c 0,151,152 519 1340 519 1340 509.5 1233.5 c 0,153,154 508.766 1185.28 l 0,155,156 513.672 1116.51 513.672 1116.51 556 1084 c 0,157,158 651.097 1007.76 651.097 1007.76 701.05 1007.84 c 0,159,160 709.406 1007.85 709.406 1007.85 716.5 1010 c 0,161,162 766 1025 766 1025 839 1016 c 0,163,164 880 1010 880 1010 922 975 c 0,165,166 964 940 964 940 941 883 c 0,167,168 914 952 914 952 883 955.5 c 0,169,170 861.719 954.539 l 0,171,172 845.625 950.75 845.625 950.75 835 937 c 0,173,174 802 895 802 895 901.5 820 c 0,175,176 1001 745 1001 745 1040 733 c 0,177,178 1057.62 726.748 1057.62 726.748 1077.66 726.795 c 0,179,180 1092.88 726.831 1092.88 726.831 1109.5 730.5 c 0,181,182 1124.23 733.752 1124.23 733.752 1124.54 745.418 c 0,183,184 1120.41 761.043 l 0,185,186 1112.25 778.324 1112.25 778.324 1088 805 c 0,187,188 1169.99 797.002 1169.99 797.002 1178.5 720 c 0,189,190 1187.01 643 1187.01 643 1177 597 c 0,191,192 1168 559 1168 559 1154.5 451 c 0,193,194 1150.46 418.662 1150.46 418.662 1150.5 389.819 c 0,195,196 1150.58 322.343 1150.58 322.343 1173 274 c 0,197,198 1198 217.001 1198 217.001 1222.5 204 c 0,199,200 1247.01 190.994 1247.01 190.994 1261 104 c 0,201,202 1265.01 72.0001 1265.01 72.0001 1243 6.5 c 0,203,204 1220.99 -59.0006 1220.99 -59.0006 1146 -68 c 0,205,206 1159.01 -44 1159.01 -44 1198.5 14 c 0,207,208 1211.67 33.3338 1211.67 33.3338 1211.67 47.4445 c 0,209,210 1211.67 75.6671 1211.67 75.6671 1159 83 c 0,211,212 1127.99 86 1127.99 86 1099 43 c 0,213,214 1067 -5 l 0,215,216 1002.99 -102.001 1002.99 -102.001 853 -118.5 c 0,217,218 703 -135 703 -135 598 -86 c 0,0,1 EndSplineSet KernsSLIF: 69 52 0 0 101 39 0 0 83 -117 0 0 116 -182 0 0 84 -65 0 0 EndChar StartChar: T Encoding: 84 84 83 Width: 1699 Flags: MW HStem: 1371 258<399 1229> VStem: 705 217.5<139 1333> Fore 705 139 m 0,0,1 725.954 259.212 725.954 259.212 725.928 369.54 c 0,2,3 725.906 459.29 725.906 459.29 712 542.5 c 0,4,5 681 728 681 728 631 926 c 0,6,7 620 965 620 965 632 1042.5 c 0,8,9 643.026 1113.72 643.026 1113.72 696.275 1114.42 c 0,10,11 700.974 1114.49 700.974 1114.49 706 1114 c 0,12,13 697 1114 697 1114 684.5 1091.5 c 0,14,15 673.19 1071.14 673.19 1071.14 673 1060 c 0,16,17 675.939 1014.92 675.939 1014.92 711.5 1010 c 0,18,19 725.288 1011.93 l 0,20,21 744.108 1020.83 744.108 1020.83 744.233 1066.63 c 0,22,23 744.248 1072.06 744.248 1072.06 744 1078 c 0,24,25 743.001 1100.95 743.001 1100.95 742 1158.5 c 0,26,27 740.999 1216.01 740.999 1216.01 731.5 1272 c 0,28,29 722.001 1327.99 722.001 1327.99 700.5 1366.5 c 0,30,31 679 1405.01 679 1405.01 637 1392 c 0,32,33 622 1387.01 622 1387.01 530 1380 c 0,34,35 438 1372.99 438 1372.99 399 1371 c 0,36,37 356.557 1372.66 l 0,38,39 304.306 1379.74 304.306 1379.74 259.5 1412 c 0,40,41 218.599 1441.45 218.599 1441.45 218.597 1490.6 c 0,42,43 218.596 1516.55 218.596 1516.55 230 1548 c 0,44,45 230 1463.01 230 1463.01 275 1459 c 0,46,47 301.917 1458.98 l 0,48,49 336.366 1464.11 336.366 1464.11 336.475 1500.02 c 0,50,51 336.498 1507.58 336.498 1507.58 335 1516.5 c 0,52,53 324.001 1582 324.001 1582 287 1594 c 0,54,55 194 1622 194 1622 138 1627 c 0,56,57 106.672 1625.72 l 0,58,59 60.8195 1618.5 60.8195 1618.5 2 1581 c 0,60,61 24.9947 1632.99 24.9947 1632.99 83 1653.5 c 0,62,63 133.741 1671.44 133.741 1671.44 175.312 1671.38 c 0,64,65 181.25 1671.37 181.25 1671.37 187 1671 c 0,66,67 392.272 1652.98 392.272 1652.98 641 1626.5 c 0,68,69 817.488 1607.71 817.488 1607.71 957.858 1607.77 c 0,70,71 1015.48 1607.8 1015.48 1607.8 1067 1611 c 0,72,73 1160 1615.99 1160 1615.99 1229 1629 c 0,74,75 1270.13 1636.75 1270.13 1636.75 1317.67 1636.68 c 0,76,77 1349.86 1636.64 1349.86 1636.64 1385 1633 c 0,78,79 1485.29 1621 1485.29 1621 1485.65 1571.16 c 0,80,81 1485.72 1562.86 1485.72 1562.86 1483 1553.5 c 0,82,83 1467.25 1499.22 1467.25 1499.22 1464 1501 c 0,84,85 1459.01 1586.99 1459.01 1586.99 1387.5 1573 c 0,86,87 1316 1559.01 1316 1559.01 1307 1530 c 0,88,89 1302.26 1515.52 1302.26 1515.52 1302.17 1502.75 c 0,90,91 1302.07 1489.7 1302.07 1489.7 1306.81 1478.42 c 0,92,93 1315.06 1458.77 1315.06 1458.77 1338 1444.5 c 0,94,95 1387.01 1414.01 1387.01 1414.01 1450.5 1414.5 c 0,96,97 1513.99 1414.99 1513.99 1414.99 1566 1449.5 c 0,98,99 1608.59 1477.75 1608.59 1477.75 1608.92 1533.85 c 0,100,101 1608.99 1546.24 1608.99 1546.24 1607 1560 c 0,102,103 1611.51 1543.45 1611.51 1543.45 1611.5 1523.93 c 0,104,105 1611.47 1491.55 1611.47 1491.55 1599 1451 c 0,106,107 1579.01 1386.01 1579.01 1386.01 1484 1358 c 0,108,109 1393.64 1330.95 1393.64 1330.95 1315.57 1330.98 c 0,110,111 1249.36 1331 1249.36 1331 1192 1350.5 c 0,112,113 1067.01 1392.99 1067.01 1392.99 968 1394 c 0,114,115 923 1394 923 1394 922.5 1333 c 0,116,117 925.664 1227.25 l 0,118,119 926.274 1218.14 926.274 1218.14 927 1209 c 0,120,121 927 1208.01 927 1208.01 936 1130.5 c 0,122,123 944.999 1053.01 944.999 1053.01 1029 941 c 0,124,125 1068 889 1068 889 1047 764.5 c 0,126,127 1026 640 1026 640 928 653 c 0,128,129 992.426 653 992.426 653 992.628 741.926 c 0,130,131 992.648 751 992.648 751 992 761 c 0,132,133 985 869 985 869 935 827 c 0,134,135 899 797 899 797 892.5 771.5 c 0,136,137 886 746 886 746 891 671 c 0,138,139 901.999 494.004 901.999 494.004 941.5 392.5 c 0,140,141 975.036 306.325 975.036 306.325 975.054 132.577 c 0,142,143 975.057 101.673 975.057 101.673 974 68 c 0,144,145 968 -93.9994 968 -93.9994 861 -122 c 0,146,147 913.644 -62.4528 913.644 -62.4528 913.78 -24.1307 c 0,148,149 913.801 -18.048 913.801 -18.048 912.5 -12.5 c 0,150,151 903.001 27.9999 903.001 27.9999 869.5 34.5 c 0,152,153 836 41 836 41 801.5 11 c 0,154,155 767 -19 767 -19 779 -94 c 0,156,157 806 -273 806 -273 858.5 -319.5 c 0,158,159 911 -366 911 -366 944 -399 c 0,160,161 801 -369 801 -369 740.5 -184 c 0,162,163 697.607 -52.8381 697.607 -52.8381 697.69 54.6971 c 0,164,165 697.724 98.8389 697.724 98.8389 705 139 c 0,0,1 EndSplineSet KernsSLIF: 322 -391 0 0 321 -469 0 0 85 -117 0 0 117 -143 0 0 104 -234 0 0 72 -156 0 0 45 -300 0 0 46 -260 0 0 44 -260 0 0 243 -300 0 0 211 -208 0 0 115 -286 0 0 83 -260 0 0 111 -208 0 0 79 -143 0 0 65 -512 0 0 97 -512 0 0 EndChar StartChar: U Encoding: 85 85 68 Width: 1411 Flags: W Fore 46 241 m 0,0,1 -23 339 -23 339 50.5 416.5 c 0,2,3 124 494 124 494 164 494 c 0,4,5 118.001 458.001 118.001 458.001 103.5 368.5 c 0,6,7 88.9999 279 88.9999 279 192 310 c 0,8,9 222 319 222 319 232 422 c 0,10,11 237.34 477.005 237.34 477.005 237.262 527.732 c 0,12,13 237.194 571.994 237.194 571.994 233 613 c 0,14,15 224 705 224 705 177.5 757 c 0,16,17 164.022 772.073 164.022 772.073 155.879 772.61 c 0,18,19 149.279 769.765 l 0,20,21 143.401 762.964 143.401 762.964 143.449 740.018 c 0,22,23 148 688 l 0,24,25 64 754 64 754 96 903 c 0,26,27 119.323 1011.6 119.323 1011.6 119.273 1144.11 c 0,28,29 119.254 1193.4 119.254 1193.4 116 1246 c 0,30,31 113.225 1341.01 l 0,32,33 115.265 1478.14 115.265 1478.14 156 1561.5 c 0,34,35 209.993 1671.99 209.993 1671.99 280 1722.5 c 0,36,37 350 1773.01 350 1773.01 410 1781 c 0,38,39 469.016 1789 l 0,40,41 469 1789 l 0,42,43 388 1774 388 1774 314.5 1694.5 c 0,44,45 240.996 1615 240.996 1615 209 1527 c 0,46,47 191.706 1479.44 191.706 1479.44 191.644 1438.16 c 0,48,49 191.592 1403.06 191.592 1403.06 204 1372.5 c 0,50,51 226.472 1317.16 226.472 1317.16 314.735 1316.87 c 0,52,53 332.531 1316.82 332.531 1316.82 353 1319 c 0,54,55 435 1328 435 1328 409.5 1419.5 c 0,56,57 386.796 1500.97 386.796 1500.97 317.708 1501.18 c 0,58,59 309.205 1501.2 309.205 1501.2 300 1500 c 0,60,61 328.11 1504.8 328.11 1504.8 351.378 1504.8 c 0,62,63 458.89 1504.76 458.89 1504.76 463 1402 c 0,64,65 468 1277.01 468 1277.01 444 1246 c 0,66,67 350.001 1126 350.001 1126 344.5 922 c 0,68,69 339 718 339 718 348 571 c 0,70,71 354 470.999 354 470.999 395.5 365 c 0,72,73 437 259 437 259 527 295 c 0,74,75 563 309.063 563 309.063 562.93 332.617 c 0,76,77 562.875 350.937 562.875 350.937 541 375 c 0,78,79 491 430 491 430 466 364 c 0,80,81 451 427 451 427 493.5 441.5 c 0,82,83 536 456 536 456 560 449 c 0,84,85 659 416 659 416 654 337 c 0,86,87 649.001 258.004 649.001 258.004 643 233 c 0,88,89 640.623 210.278 l 0,90,91 643.022 170.739 643.022 170.739 693.5 141 c 0,92,93 710.928 130.733 710.928 130.733 732.042 130.759 c 0,94,95 789.073 130.83 789.073 130.83 873 206 c 0,96,97 891 222.001 891 222.001 931 287.5 c 0,98,99 970.999 352.998 970.999 352.998 997.5 431 c 0,100,101 1024.01 509 1024.01 509 1017 580 c 0,102,103 1009.99 651.002 1009.99 651.002 934 679 c 0,104,105 883 697 883 697 885.5 635.5 c 0,106,107 888 574 888 574 932 546 c 0,108,109 829 595 829 595 823 689 c 0,110,111 817 783 817 783 850.5 898.5 c 0,112,113 884.003 1014.01 884.003 1014.01 929.5 1137.5 c 0,114,115 975 1261 975 1261 975 1369 c 0,116,117 975 1384.99 975 1384.99 996.5 1507.5 c 0,118,119 1014.74 1611.48 1014.74 1611.48 1106.84 1612.07 c 0,120,121 1142 1609 l 0,122,123 1114 1609 1114 1609 1084 1578 c 0,124,125 1065.83 1559.22 1065.83 1559.22 1065.63 1537.15 c 0,126,127 1065.54 1526.11 1065.54 1526.11 1069.93 1514.25 c 0,128,129 1071.26 1510.66 1071.26 1510.66 1073 1507 c 0,130,131 1097.08 1458.24 1097.08 1458.24 1127.69 1458.04 c 0,132,133 1143.25 1457.94 1143.25 1457.94 1160.49 1470.39 c 0,134,135 1165.67 1474.13 1165.67 1474.13 1171 1479 c 0,136,137 1199.69 1504.1 1199.69 1504.1 1199.8 1560.46 c 0,138,139 1199.87 1598.4 1199.87 1598.4 1187 1650.5 c 0,140,141 1160.61 1757.3 1160.61 1757.3 1045.79 1757.66 c 0,142,143 1021.39 1757.73 1021.39 1757.73 993 1753 c 0,144,145 1034.65 1774 1034.65 1774 1074.09 1774.11 c 0,146,147 1108.32 1774.21 1108.32 1774.21 1140.89 1758.58 c 0,148,149 1178.03 1740.77 1178.03 1740.77 1213 1702.5 c 0,150,151 1266.02 1644.49 1266.02 1644.49 1266.13 1556.31 c 0,152,153 1266.23 1476.51 1266.23 1476.51 1223 1372 c 0,154,155 1187.02 1285.05 1187.02 1285.05 1145.5 1165.5 c 0,156,157 1104 1046.01 1104 1046.01 1101 977 c 0,158,159 1102.08 933.908 l 0,160,161 1108.46 884.297 1108.46 884.297 1140.5 864.5 c 0,162,163 1185.01 837 1185.01 837 1224.5 853.5 c 0,164,165 1264.01 870.005 1264.01 870.005 1270.5 923 c 0,166,167 1269.24 946.944 l 0,168,169 1259.55 992.592 1259.55 992.592 1196 1053 c 0,170,171 1338.99 1039.01 1338.99 1039.01 1341.5 918 c 0,172,173 1338.83 854.387 l 0,174,175 1329.25 760.063 1329.25 760.063 1286.5 653 c 0,176,177 1229.01 509 1229.01 509 1151.5 384.5 c 0,178,179 1073.98 259.972 1073.98 259.972 1059 241 c 0,180,181 1020.99 192.985 1020.99 192.985 991 128 c 0,182,183 961 63.0001 961 63.0001 1048 81 c 0,184,185 1093 90 1093 90 1088.5 126 c 0,186,187 1084 161.999 1084 161.999 1069 208 c 0,188,189 1143.1 168.331 1143.1 168.331 1143.53 96.7311 c 0,190,191 1139.54 60.7425 l 0,192,193 1137.87 53.0215 1137.87 53.0215 1135.5 45 c 0,194,195 1102.99 -65.0001 1102.99 -65.0001 1012 -66 c 0,196,197 578 -72 578 -72 336.5 49.5 c 0,198,199 94.9995 171 94.9995 171 46 241 c 0,0,1 EndSplineSet KernsSLIF: 116 -78 0 0 84 -65 0 0 88 -130 0 0 EndChar StartChar: V Encoding: 86 86 69 Width: 1266 Flags: W Fore 346 1049 m 1,0,1 445 1021 445 1021 449 940.5 c 0,2,3 450.299 842.065 l 0,4,5 449.624 820.845 449.624 820.845 448 802 c 0,6,7 442 735 442 735 432.5 682.5 c 0,8,9 431.139 654.738 l 0,10,11 434.544 623.651 434.544 623.651 463 608 c 0,12,13 498 588 498 588 514.5 635 c 0,14,15 531 682 531 682 536 749 c 0,16,17 540.231 805.7 540.231 805.7 540.166 859.521 c 0,18,19 540.154 869.308 540.154 869.308 540 879 c 0,20,21 539 942 539 942 539 954 c 0,22,23 539 1034.01 539 1034.01 544.5 1098.5 c 0,24,25 550 1163 550 1163 574 1239 c 0,26,27 590.997 1292.99 590.997 1292.99 629.5 1337.5 c 0,28,29 667.985 1381.99 667.985 1381.99 699 1398 c 0,30,31 713.755 1401.18 l 0,32,33 723.716 1400.86 723.716 1400.86 734 1394 c 0,34,35 752 1382 752 1382 752 1369 c 0,36,37 698 1397.99 698 1397.99 700 1322.5 c 0,38,39 702 1247 702 1247 733 1247 c 0,40,41 765.998 1247 765.998 1247 779.5 1279 c 0,42,43 793 1310.99 793 1310.99 793 1337 c 0,44,45 793 1433 793 1433 808.5 1505 c 0,46,47 823.997 1576.99 823.997 1576.99 850 1667 c 0,48,49 857.997 1696.99 857.997 1696.99 884.5 1729.5 c 0,50,51 911.003 1762.01 911.003 1762.01 927 1776 c 0,52,53 956 1801.01 956 1801.01 1012.5 1800 c 0,54,55 1069 1798.99 1069 1798.99 1076 1765 c 0,56,57 1057.04 1782.69 1057.04 1782.69 1033.2 1782.91 c 0,58,59 1009.58 1779.2 l 0,60,61 986.018 1771.95 986.018 1771.95 958.5 1750.5 c 0,62,63 915 1716.6 915 1716.6 914.88 1673.88 c 0,64,65 914.8 1645.4 914.8 1645.4 934 1613 c 0,66,67 951.778 1582.33 951.778 1582.33 978.643 1582.38 c 0,68,69 1012.23 1582.44 1012.23 1582.44 1060 1630.5 c 0,70,71 1146 1717.01 1146 1717.01 1158 1756 c 0,72,73 1179.24 1823.78 1179.24 1823.78 1179.24 1871.65 c 0,74,75 1179.24 1929.72 1179.24 1929.72 1148 1958.5 c 0,76,77 1091 2011 1091 2011 1074 2028 c 0,78,79 1142.02 1994.99 1142.02 1994.99 1174 1955 c 0,80,81 1206 1914.99 1206 1914.99 1206 1828 c 0,82,83 1206 1746.01 1206 1746.01 1164 1676 c 0,84,85 1122 1605.99 1122 1605.99 1076 1552 c 0,86,87 964.997 1423 964.997 1423 911 1267.5 c 0,88,89 857 1111.99 857 1111.99 854 945 c 0,90,91 853 915 853 915 856 832 c 0,92,93 859 749 859 749 852.5 655 c 0,94,95 846.001 561.005 846.001 561.005 824.5 478 c 0,96,97 803 395 803 395 754 365 c 0,98,99 793 446 793 446 792.5 514 c 0,100,101 792 582 792 582 750 613 c 0,102,103 675 665 675 665 637 563 c 0,104,105 599 461 599 461 589 409 c 0,106,107 571 325 571 325 559 244.5 c 0,108,109 547 163.999 547 163.999 642 168 c 0,110,111 651 168 651 168 666 188.5 c 0,112,113 681 209.001 681 209.001 675 238 c 0,114,115 666 281 666 281 604 292 c 0,116,117 629.82 313.633 629.82 313.633 653.449 313.839 c 0,118,119 663.68 313.928 663.68 313.928 673.5 310 c 0,120,121 706.001 296.999 706.001 296.999 724 266 c 0,122,123 744.16 227.514 744.16 227.514 744.167 188.094 c 0,124,125 744.171 162.987 744.171 162.987 736 137.5 c 0,126,127 715 71.9999 715 71.9999 681 52 c 0,128,-1 575 -7.5 l 0,129,130 530 -32 530 -32 530 -128 c 0,131,132 530 -264.001 530 -264.001 624.5 -318.5 c 0,133,134 719 -373 719 -373 839 -367 c 0,135,136 744 -397 744 -397 654.5 -374.5 c 0,137,138 565 -352 565 -352 530 -313 c 0,139,140 412 -179.999 412 -179.999 410.5 -4 c 0,141,142 409 171.999 409 171.999 320 295 c 0,143,144 304 316 304 316 265 333 c 0,145,146 226 350 226 350 211 297 c 0,147,148 185.001 208.001 185.001 208.001 274 186 c 0,149,150 239.736 185.285 l 0,151,152 218.405 187.152 218.405 187.152 195 194.5 c 0,153,154 152.001 208 152.001 208 124 277 c 0,155,156 106.733 319 106.733 319 106.78 364.267 c 0,157,158 106.834 416 106.834 416 129.5 472 c 0,159,160 172 577.001 172 577.001 172 669 c 0,161,162 172 813.002 172 813.002 124.5 942.5 c 0,163,164 76.9999 1071.99 76.9999 1071.99 48 1208 c 0,165,166 39 1248.01 39 1248.01 22.5 1335.5 c 0,167,168 8.49056 1409.79 8.49056 1409.79 8.53863 1491.66 c 0,169,170 8.54717 1506.21 8.54717 1506.21 9 1521 c 0,171,172 10.9999 1588.01 10.9999 1588.01 45 1680 c 0,173,174 79.004 1772.01 79.004 1772.01 133 1780 c 0,175,176 110.001 1747 110.001 1747 92.5 1700.5 c 0,177,178 78.865 1664.27 78.865 1664.27 78.8889 1635.02 c 0,179,180 78.8957 1626.73 78.8957 1626.73 80 1619 c 0,181,182 92.9678 1535.64 92.9678 1535.64 186.577 1535.49 c 0,183,184 194.034 1535.48 194.034 1535.48 202 1536 c 0,185,186 257 1539 257 1539 266 1632.5 c 0,187,188 270.261 1713.86 l 0,189,190 270.153 1752.18 270.153 1752.18 265 1780 c 0,191,192 258 1814.01 258 1814.01 223 1843 c 0,193,194 187.993 1872 187.993 1872 152 1878 c 0,195,196 193.862 1879.28 l 0,197,198 284.127 1872.85 284.127 1872.85 312.5 1779.5 c 0,199,200 347 1665.99 347 1665.99 338 1592 c 0,201,202 329.999 1541.99 329.999 1541.99 303.5 1446 c 0,203,204 277.002 1350.01 277.002 1350.01 267 1293 c 0,205,206 263.07 1274.13 263.07 1274.13 263.156 1218.51 c 0,207,208 263.179 1203.37 263.179 1203.37 263.5 1185.5 c 0,209,210 265 1102.01 265 1102.01 276 1018.5 c 0,211,212 286.999 935.003 286.999 935.003 310 881 c 0,213,214 333 827 333 827 372 863 c 0,215,216 415 902 415 902 399 960.5 c 0,217,218 382.999 1019 382.999 1019 346 1049 c 1,0,1 EndSplineSet KernsSLIF: 214 -193 0 0 246 -224 0 0 111 -195 0 0 79 -156 0 0 45 -208 0 0 46 -247 0 0 44 -247 0 0 73 -104 0 0 105 -182 0 0 97 -321 0 0 65 -270 0 0 EndChar StartChar: W Encoding: 87 87 11 Width: 2018 Flags: HW Fore 1198 -258 m 0,0,1 1141 -241.001 1141 -241.001 1105 -191 c 0,2,3 1068.99 -140.988 1068.99 -140.988 1055 -100 c 0,4,5 1028 -25 1028 -25 1011.5 75 c 0,6,7 995 175 995 175 962 235 c 0,8,9 914 318 914 318 882 324 c 0,10,11 850 330 850 330 808 271 c 0,12,13 777.835 228.58 777.835 228.58 777.883 126.621 c 0,14,15 777.885 120.42 777.885 120.42 778 114 c 0,16,17 780 1.99995 780 1.99995 814 -37 c 0,18,19 839 -67 839 -67 899 -79 c 0,20,21 848.175 -107.756 848.175 -107.756 793.772 -107.666 c 0,22,23 766.825 -107.622 766.825 -107.622 739 -100.5 c 0,24,25 655 -79.0001 655 -79.0001 620 -45 c 0,26,27 586 -12 586 -12 561.5 25.5 c 0,28,29 537 63 537 63 513 105 c 0,30,31 485.998 152.002 485.998 152.002 472.5 171.5 c 0,32,33 459 190.999 459 190.999 402 210 c 0,34,35 384.54 209.64 l 0,36,37 369.5 205 l 0,38,39 349.001 197.001 349.001 197.001 345 185 c 0,40,41 321 119 321 119 383 104 c 0,42,43 344 84.9999 344 84.9999 314 110 c 0,44,45 284 135.001 284 135.001 281 163 c 0,46,47 273.557 211.38 273.557 211.38 273.604 252.976 c 0,48,49 273.646 289.62 273.646 289.62 279.5 321 c 0,50,51 292 388 292 388 314 462 c 0,52,53 357.094 610.435 357.094 610.435 357.085 756.122 c 0,54,55 357.085 762.561 357.085 762.561 357 769 c 0,56,57 355 920.999 355 920.999 289 1064 c 0,58,59 254.025 1136.95 254.025 1136.95 214 1204 c 0,60,61 174 1271 174 1271 171 1359 c 0,62,63 171.789 1419.71 l 0,64,65 181.716 1538.68 181.716 1538.68 263 1546 c 0,66,67 291.179 1544.62 l 0,68,69 330 1536.43 330 1536.43 330 1490 c 0,70,71 306 1512.01 306 1512.01 271.5 1497.5 c 0,72,73 249.617 1488.3 249.617 1488.3 249.661 1455.57 c 0,74,75 249.686 1436.7 249.686 1436.7 257 1410 c 0,76,77 266.64 1374.41 266.64 1374.41 302.395 1374 c 0,78,79 330.5 1378 l 0,80,81 391 1394.01 391 1394.01 391 1442 c 0,82,83 389.999 1546 389.999 1546 327 1586.5 c 0,84,85 264 1627 264 1627 190 1627 c 0,86,87 89.9968 1627 89.9968 1627 57 1575 c 0,88,89 24 1522.99 24 1522.99 9 1497 c 0,90,91 19 1585.99 19 1585.99 67 1623 c 0,92,93 114.993 1660 114.993 1660 196 1666 c 0,94,95 240.049 1665.23 l 0,96,97 302.45 1658.55 302.45 1658.55 356 1619.5 c 0,98,99 428 1567 428 1567 456 1513 c 0,100,101 534 1360 534 1360 502 1271.5 c 0,102,103 470 1183 470 1183 460 1017 c 0,104,105 457 966 457 966 456 896.5 c 0,106,107 455 827 455 827 489 788 c 0,108,109 521 752 521 752 541.5 763.5 c 0,110,111 560.877 774.37 560.877 774.37 561 800 c 0,112,113 559.001 821.999 559.001 821.999 553.5 841 c 0,114,115 548 860 548 860 494 864 c 0,116,117 527.206 880.794 527.206 880.794 554.148 880.98 c 0,118,119 568.225 881.078 568.225 881.078 580.592 876.641 c 0,120,121 606.569 867.323 606.569 867.323 625 838 c 0,122,123 648.561 798.453 648.561 798.453 648.756 767.399 c 0,124,125 648.793 761.549 648.793 761.549 648 756 c 0,126,127 643 721 643 721 637 688 c 0,128,129 618 590 618 590 617.5 538 c 0,130,131 617 486 617 486 659 456 c 0,132,133 686 435 686 435 741 542.5 c 0,134,135 796 650 796 650 820 704 c 0,136,137 846 761 846 761 873 797.5 c 0,138,139 900 834 900 834 984 873 c 0,140,141 934 801 934 801 920.5 759 c 0,142,143 907 717 907 717 919 639 c 0,144,145 925 592.001 925 592.001 942 552.5 c 0,146,147 959 513 959 513 999 509 c 0,148,149 1027.6 508.97 l 0,150,151 1090.09 517.856 1090.09 517.856 1127 608.5 c 0,152,153 1172 719 1172 719 1178 779 c 0,154,155 1179.01 791 1179.01 791 1199 889 c 0,156,157 1218.99 987 1218.99 987 1175 987 c 0,158,159 1148 987 1148 987 1139 958.5 c 0,160,161 1130 930 1130 930 1151 911 c 0,162,163 1104.99 919 1104.99 919 1104.5 966 c 0,164,165 1104.01 1013 1104.01 1013 1115 1031 c 0,166,167 1151 1088 1151 1088 1203 1129.5 c 0,168,169 1255.02 1171.01 1255.02 1171.01 1287 1210 c 0,170,171 1335 1270 1335 1270 1348.5 1294 c 0,172,173 1362 1318 1362 1318 1383 1381 c 0,174,175 1399.89 1431.69 1399.89 1431.69 1439.5 1540 c 0,176,177 1478.99 1647.99 1478.99 1647.99 1529 1698 c 0,178,179 1572.99 1741.99 1572.99 1741.99 1607 1759.5 c 0,180,181 1627.24 1769.92 1627.24 1769.92 1653.15 1769.88 c 0,182,183 1670.76 1769.86 1670.76 1769.86 1691 1765 c 0,184,-1 1607 1716.5 l 0,185,186 1567 1694 1567 1694 1543 1631 c 0,187,188 1528.58 1595.35 1528.58 1595.35 1528.56 1547.03 c 0,189,190 1528.55 1531.66 1528.55 1531.66 1530 1515 c 0,191,192 1536 1446 1536 1446 1594 1440 c 0,193,194 1663 1432.01 1663 1432.01 1721.5 1474.5 c 0,195,196 1779.99 1516.99 1779.99 1516.99 1808 1580 c 0,197,198 1825.98 1621.95 1825.98 1621.95 1847.5 1662.5 c 0,199,200 1868.99 1703 1868.99 1703 1864 1805 c 0,201,202 1858 1913 1858 1913 1703 1994 c 0,203,204 1884.99 1955 1884.99 1955 1910 1785 c 0,205,206 1914.52 1754.1 1914.52 1754.1 1914.43 1721.43 c 0,207,208 1914.28 1667.39 1914.28 1667.39 1901.5 1608.5 c 0,209,210 1881 1514.01 1881 1514.01 1819 1444 c 0,211,212 1731 1344 1731 1344 1622 1262 c 0,213,214 1579.99 1230 1579.99 1230 1512 1140.5 c 0,215,216 1444.01 1050.99 1444.01 1050.99 1491 995 c 0,217,218 1503 980 1503 980 1533 987 c 0,219,220 1562.99 993.999 1562.99 993.999 1570 1021 c 0,221,222 1575.85 1043.49 1575.85 1043.49 1575.93 1057.9 c 0,223,224 1576.02 1075.5 1576.02 1075.5 1567.5 1081 c 0,225,-1 1530 1106 l 0,226,227 1561.81 1109.98 l 0,228,229 1606.38 1109.6 1606.38 1109.6 1617 1067.5 c 0,230,231 1624.51 1037.74 1624.51 1037.74 1624.54 1010.13 c 0,232,233 1624.56 986.259 1624.56 986.259 1619 964 c 0,234,235 1601 892 1601 892 1535 861 c 0,236,237 1469.01 830.005 1469.01 830.005 1417 786 c 0,238,239 1355.99 735 1355.99 735 1307.5 681 c 0,240,241 1259 626.993 1259 626.993 1247 548 c 0,242,243 1240.43 507.416 1240.43 507.416 1240.43 473.856 c 0,244,245 1240.44 420.581 1240.44 420.581 1257 385 c 0,246,-1 1322 239 l 0,247,248 1349.01 173.984 1349.01 173.984 1357 99.5 c 0,249,250 1356.76 63.9884 l 0,251,252 1349.8 2.65468 1349.8 2.65468 1299 -72 c 0,253,254 1299 -39.0261 1299 -39.0261 1313 33 c 0,255,256 1326.99 105 1326.99 105 1259 147 c 0,257,258 1243.74 155.902 1243.74 155.902 1229.44 156.01 c 0,259,260 1217.62 156.1 1217.62 156.1 1206.45 150.18 c 0,261,262 1188.64 140.736 1188.64 140.736 1172.5 116 c 0,263,264 1134 57.0082 1134 57.0082 1131 -57 c 0,265,266 1133.57 -92.4594 l 0,267,268 1139.35 -124.071 1139.35 -124.071 1157.5 -157.5 c 0,269,270 1186 -210.003 1186 -210.003 1232 -232 c 0,271,272 1277 -253.001 1277 -253.001 1373 -255 c 0,273,274 1341.01 -271 1341.01 -271 1289 -270 c 0,275,276 1237 -269 1237 -269 1198 -258 c 0,0,1 EndSplineSet KernsSLIF: 214 -180 0 0 246 -212 0 0 322 -469 0 0 321 -508 0 0 72 -260 0 0 104 -300 0 0 45 -234 0 0 46 -326 0 0 44 -364 0 0 115 -326 0 0 83 -260 0 0 105 -182 0 0 73 -91 0 0 243 -313 0 0 211 -365 0 0 111 -273 0 0 79 -221 0 0 196 -313 0 0 228 -270 0 0 261 -342 0 0 260 -342 0 0 97 -449 0 0 65 -398 0 0 EndChar StartChar: X Encoding: 88 88 29 Width: 1415 Flags: HW Fore 760 1490 m 0,0,1 714 1479.88 714 1479.88 713.706 1446.06 c 0,2,3 714 1440 l 0,4,5 718 1402.01 718 1402.01 718 1401 c 0,6,7 668 1425 668 1425 677 1494 c 0,8,9 684.998 1557.99 684.998 1557.99 760 1577 c 0,10,11 801.957 1587.98 801.957 1587.98 857.5 1609 c 0,12,13 913 1630 913 1630 949 1654 c 0,14,15 964.003 1663 964.003 1663 980 1697 c 0,16,17 995.999 1731 995.999 1731 1000 1751 c 0,18,19 1004.07 1771.56 1004.07 1771.56 1004.04 1788.43 c 0,20,21 1003.92 1854.44 1003.92 1854.44 941 1864 c 0,22,23 966.36 1866.94 l 0,24,25 988.032 1865.85 988.032 1865.85 1004.5 1851 c 0,26,27 1030 1828.01 1030 1828.01 1030 1798 c 0,28,29 1030 1772.94 1030 1772.94 1023 1683.5 c 0,30,31 1021.96 1629.04 l 0,32,33 1024.61 1594 1024.61 1594 1039 1594 c 0,34,35 1071 1594 1071 1594 1092 1637 c 0,36,37 1115.99 1692.98 1115.99 1692.98 1117 1744.5 c 0,38,39 1118.01 1796.02 1118.01 1796.02 1140 1845 c 0,40,41 1161.01 1890.01 1161.01 1890.01 1202.5 1920.5 c 0,42,43 1237.05 1945.88 1237.05 1945.88 1267.77 1945.99 c 0,44,45 1273.96 1946.01 1273.96 1946.01 1280 1945 c 0,46,47 1246.99 1934 1246.99 1934 1221 1903 c 0,48,49 1195 1871.99 1195 1871.99 1195 1851 c 0,50,51 1195 1802 1195 1802 1249 1802 c 0,52,53 1272 1802 1272 1802 1280.5 1824 c 0,54,55 1285.39 1836.65 1285.39 1836.65 1285.48 1847.98 c 0,56,57 1285.55 1856.35 1285.55 1856.35 1283 1864 c 0,58,59 1322 1859.99 1322 1859.99 1322 1811.5 c 0,60,61 1322 1762.99 1322 1762.99 1310 1743 c 0,62,63 1292 1713 1292 1713 1253 1672.5 c 0,64,65 1213.92 1631.92 1213.92 1631.92 1189 1609 c 0,66,-1 1070 1500 l 0,67,68 975.004 1414 975.004 1414 945 1346 c 0,69,70 928.994 1309.99 928.994 1309.99 891 1189 c 0,71,72 874.988 1138.01 874.988 1138.01 874.956 1101.76 c 0,73,74 874.912 1051.98 874.912 1051.98 905 1030 c 0,75,76 919.654 1018.16 919.654 1018.16 935.262 1018.24 c 0,77,78 947.346 1018.3 947.346 1018.3 960 1025.5 c 0,79,80 989.007 1042 989.007 1042 1001 1058 c 0,81,82 1029.99 1095.99 1029.99 1095.99 999.5 1122.5 c 0,83,84 969 1149.01 969 1149.01 947 1151 c 0,85,86 966.65 1157.25 966.65 1157.25 984.599 1157.22 c 0,87,88 1006.85 1157.19 1006.85 1157.19 1026.5 1147.5 c 0,89,90 1062 1130 1062 1130 1068 1110 c 0,91,92 1076.18 1081.05 1076.18 1081.05 1076.24 1057.88 c 0,93,94 1076.34 1019.14 1076.34 1019.14 1053.71 996.609 c 0,95,96 1046.89 989.817 1046.89 989.817 1038 984.5 c 0,97,98 981.995 950.994 981.995 950.994 928 898 c 0,99,100 874 844 874 844 871.5 803 c 0,101,102 869 762 869 762 875 720 c 0,103,104 884 659 884 659 935 574.5 c 0,105,106 986.02 489.967 986.02 489.967 1051.5 404.5 c 0,107,-1 1181 243 l 0,108,-1 1280 125 l 0,109,110 1306.99 91.0083 1306.99 91.0083 1326 11.5 c 0,111,112 1345.01 -68 1345.01 -68 1302 -109 c 0,113,114 1315.29 -83.1647 1315.29 -83.1647 1315.22 -54.808 c 0,115,116 1315.11 -6.33775 1315.11 -6.33775 1276 49.5 c 0,117,118 1214.01 137.998 1214.01 137.998 1155 149 c 0,119,120 1125.06 150.232 l 0,121,122 1088.17 146.304 1088.17 146.304 1077.5 111 c 0,123,124 1070.42 87.5735 1070.42 87.5735 1070.37 67.0018 c 0,125,126 1070.32 45.43 1070.32 45.43 1078 27 c 0,127,128 1121.01 -73 1121.01 -73 1192 -106.5 c 0,129,130 1263 -140 1263 -140 1331 -140.5 c 0,131,132 1395.74 -137.331 l 0,133,134 1424.13 -134.077 1424.13 -134.077 1448 -127.5 c 0,135,136 1479 -118.959 1479 -118.959 1490.39 -119.024 c 0,137,138 1497 -119.061 1497 -119.061 1497 -122 c 0,139,140 1387.98 -157.22 1387.98 -157.22 1301.63 -157.28 c 0,141,142 1233.52 -157.327 1233.52 -157.327 1179.5 -135.5 c 0,143,144 1057 -86.0024 1057 -86.0024 1009 38 c 0,145,146 980.998 110.003 980.998 110.003 940 229.5 c 0,147,148 899 349 899 349 868 352 c 0,149,150 804 358 804 358 804 299 c 0,151,152 804 263 804 263 821.5 256.5 c 0,153,154 833.616 252 833.616 252 844.533 252.053 c 0,155,156 849.385 252.077 849.385 252.077 854 253 c 0,157,158 835.564 229.6 835.564 229.6 815.619 229.581 c 0,159,160 807.436 229.573 807.436 229.573 799 233.5 c 0,161,162 770 247.001 770 247.001 758 272 c 0,163,164 731.999 325.002 731.999 325.002 727 386 c 0,165,166 722 447 722 447 722 518 c 0,167,168 722 542 722 542 711 588.5 c 0,169,170 700 635 700 635 667 639 c 0,171,172 590 648 590 648 536.5 513 c 0,173,174 499.347 419.251 499.347 419.251 499.087 386.264 c 0,175,176 498.992 374.272 498.992 374.272 506 369 c 0,177,178 527 361 527 361 548 384 c 0,179,180 572 408 572 408 537 446 c 0,181,182 558 446 558 446 574.5 422.5 c 0,183,184 591 399 591 399 591 378 c 0,185,186 591 338 591 338 558.5 289 c 0,187,188 526 240 526 240 485 229 c 0,189,190 431 215.001 431 215.001 385 185.5 c 0,191,192 339 155.999 339 155.999 327 100 c 0,193,194 313.005 37.0199 313.005 37.0199 297.5 -20 c 0,195,196 282 -77 282 -77 255 -114 c 0,197,198 243 -129 243 -129 201.5 -141 c 0,199,200 179.007 -147.504 179.007 -147.504 161.656 -147.545 c 0,201,202 146.992 -147.58 146.992 -147.58 136 -143 c 0,203,204 195 -134 195 -134 224 -81 c 0,205,206 242.001 -46.999 242.001 -46.999 242.5 20 c 0,207,208 242.999 87.0001 242.999 87.0001 187 87 c 0,209,210 124 87 124 87 90 12.5 c 0,211,212 55.9999 -62 55.9999 -62 56 -116 c 0,213,214 56 -207.001 56 -207.001 149 -254 c 0,215,216 80 -254 80 -254 48.5 -209 c 0,217,218 17 -164 17 -164 14 -116 c 0,219,220 3 2.00005 3 2.00005 77 106 c 0,221,222 112.997 157.997 112.997 157.997 232 284 c 0,223,224 351 410 351 410 349 463 c 0,225,226 347 495 347 495 306 495 c 0,227,228 284.978 495 284.978 495 284.5 472.5 c 0,229,230 284.999 450.002 284.999 450.002 293 440 c 0,231,232 269 433 269 433 245.5 460 c 0,233,234 221.999 487 221.999 487 247 535 c 0,235,236 267 574 267 574 325.5 608 c 0,237,238 384.003 642.002 384.003 642.002 417 673 c 0,239,240 450.002 704.002 450.002 704.002 490.5 765 c 0,241,242 531 826 531 826 531 877 c 0,243,244 531 910 531 910 503 924 c 0,245,246 475 938 475 938 448 938 c 0,247,248 379.456 935.397 379.456 935.397 378.665 895.53 c 0,249,250 380 882.5 l 0,251,252 391 830 391 830 421 830 c 0,253,254 369 821 369 821 328 845 c 0,255,256 287 869 287 869 287 926 c 0,257,258 287 970 287 970 312 1017.5 c 0,259,260 337.001 1065.01 337.001 1065.01 347 1104 c 0,261,262 355 1140 355 1140 355.5 1190 c 0,263,264 356 1239.99 356 1239.99 344 1274 c 0,265,266 319.003 1339.99 319.003 1339.99 266 1395 c 0,267,268 213 1450.01 213 1450.01 213 1535 c 0,269,270 213 1557.99 213 1557.99 237.5 1602.5 c 0,271,272 261.997 1647 261.997 1647 302 1647 c 0,273,274 263 1609.99 263 1609.99 263 1559 c 0,275,276 263 1544.99 263 1544.99 276 1522 c 0,277,278 289.003 1499 289.003 1499 310 1499 c 0,279,280 374 1499 374 1499 374 1562 c 0,281,282 374 1752.53 374 1752.53 219.724 1752.48 c 0,283,284 212.053 1752.47 212.053 1752.47 204 1752 c 0,285,286 247.833 1765.11 247.833 1765.11 282.611 1765.1 c 0,287,288 340.669 1765.08 340.669 1765.08 373.5 1728.5 c 0,289,290 426.001 1670 426.001 1670 448 1582 c 0,291,292 466 1505.99 466 1505.99 475.5 1424.5 c 0,293,294 485.001 1342.99 485.001 1342.99 506 1269 c 0,295,296 515.003 1235.99 515.003 1235.99 552 1178.5 c 0,297,298 581.04 1133.37 581.04 1133.37 613.156 1132.9 c 0,299,300 631 1136 l 0,301,302 680.005 1152.01 680.005 1152.01 722.5 1212 c 0,303,304 765 1272 765 1272 783 1320 c 0,305,306 789 1336.01 789 1336.01 801.5 1419 c 0,307,308 803.564 1454.98 l 0,309,310 800.907 1490.88 800.907 1490.88 773.555 1491.5 c 0,311,312 760 1490 l 0,0,1 EndSplineSet KernsSLIF: 45 -208 0 0 EndChar StartChar: Y Encoding: 89 89 17 Width: 1321 Flags: MW VStem: 406 327<-12 893> Fore 587 -427 m 1,0,1 650 -373 650 -373 691.5 -193 c 0,2,3 733 -13 733 -13 673 39 c 0,4,5 647 61 647 61 574 65.5 c 0,6,7 501 70 501 70 520 10 c 0,8,9 531 -25 531 -25 563.5 -31 c 0,10,11 591.368 -32.2583 l 0,12,13 609.425 -30.504 609.425 -30.504 627 -22 c 0,14,15 627 -68 627 -68 526 -76 c 0,16,17 425 -83.9999 425 -83.9999 406 -12 c 0,18,19 398.427 14.7027 398.427 14.7027 398.479 42.0412 c 0,20,21 398.558 83.2966 398.558 83.2966 416 126 c 0,22,23 445 197.002 445 197.002 469 265 c 0,24,25 474.004 280.013 474.004 280.013 489.5 337.5 c 0,26,27 505 395.003 505 395.003 515.5 458.5 c 0,28,29 525.179 517.032 525.179 517.032 525.086 565.366 c 0,30,31 525.078 569.468 525.078 569.468 525 573.5 c 0,32,33 524 625.001 524 625.001 496 630 c 0,34,35 473.874 629.028 l 0,36,37 461.395 626.368 461.395 626.368 448.5 619 c 0,38,39 425.042 605.596 425.042 605.596 425 572 c 0,40,41 425 548 425 548 473 539 c 0,42,43 435 526 435 526 387.5 534.5 c 0,44,45 340 543 340 543 324 580 c 0,46,47 317.399 594.852 317.399 594.852 317.497 610.957 c 0,48,49 317.697 643.648 317.697 643.648 345.5 681.5 c 0,50,51 387 738 387 738 398 783 c 0,52,53 404.119 810.154 404.119 810.154 404.095 837.382 c 0,54,55 404.056 881.345 404.056 881.345 388 925.5 c 0,56,57 362 997 362 997 319 1042 c 0,58,59 310.857 1049.71 310.857 1049.71 301.979 1049.9 c 0,60,61 289.326 1046.54 l 0,62,63 283.314 1043.31 283.314 1043.31 277 1037 c 0,64,65 263.787 1023.79 263.787 1023.79 263.445 1010.25 c 0,66,67 267.068 995.034 l 0,68,69 268.318 992.522 268.318 992.522 270 990 c 0,70,71 282 972 282 972 290.5 967 c 0,72,73 299 962 299 962 341 962 c 0,74,75 333.001 943 333.001 943 281.5 940 c 0,76,77 245.179 941.292 l 0,78,79 219.509 945.159 219.509 945.159 203 958 c 0,80,81 158 992 158 992 173 1067 c 0,82,83 188 1142 188 1142 188 1190 c 0,84,85 188 1298 188 1298 111 1360 c 0,86,87 34.0009 1421.99 34.0009 1421.99 19 1521 c 0,88,89 14.7895 1547.84 14.7895 1547.84 14.8726 1575.69 c 0,90,91 15.1051 1653.65 15.1051 1653.65 49 1739.5 c 0,92,93 94.9978 1856 94.9978 1856 234 1913 c 0,94,95 139.993 1851.99 139.993 1851.99 89.5 1755 c 0,96,97 39 1657.99 39 1657.99 84 1557 c 0,98,99 113.309 1491.05 113.309 1491.05 188.767 1490.96 c 0,100,101 195.689 1490.95 195.689 1490.95 203 1491.5 c 0,102,103 289.995 1497.99 289.995 1497.99 332 1546 c 0,104,105 346.769 1562.25 346.769 1562.25 346.875 1578.25 c 0,106,107 346.974 1593.24 346.974 1593.24 334.206 1608.02 c 0,108,109 332.918 1609.51 332.918 1609.51 331.5 1611 c 0,110,111 310.872 1632.64 310.872 1632.64 278.582 1632.79 c 0,112,113 263.126 1632.86 263.126 1632.86 245 1628 c 0,114,115 281 1653.99 281 1653.99 325.5 1653.5 c 0,116,117 369.993 1653.01 369.993 1653.01 392 1635 c 0,118,119 421.654 1608.64 421.654 1608.64 421.779 1569.91 c 0,120,121 421.843 1549.86 421.843 1549.86 414 1526.5 c 0,122,123 391.987 1460.93 391.987 1460.93 391.958 1414.16 c 0,124,125 391.957 1412.06 391.957 1412.06 392 1410 c 0,126,127 393 1358.01 393 1358.01 402.5 1279 c 0,128,129 411.998 1200.01 411.998 1200.01 433.5 1129.5 c 0,130,131 455.002 1058.99 455.002 1058.99 490.5 1016.5 c 0,132,133 526 974 526 974 580 997 c 0,134,135 623.004 1015 623.004 1015 668 1086.5 c 0,136,137 713.005 1158.01 713.005 1158.01 722 1192 c 0,138,139 722.967 1213.49 l 0,140,141 720.821 1232.68 720.821 1232.68 709.5 1259 c 0,142,143 697.668 1286.51 697.668 1286.51 678.264 1287.01 c 0,144,145 662.531 1283.53 l 0,146,147 658.396 1281.73 658.396 1281.73 654 1279 c 0,148,149 623 1259.99 623 1259.99 644 1238.5 c 0,150,151 665.005 1217 665.005 1217 689 1217 c 0,152,153 668.538 1203.36 668.538 1203.36 648.887 1203.12 c 0,154,155 628.401 1206.6 l 0,156,157 623.929 1208.19 623.929 1208.19 619.5 1210.5 c 0,158,159 586 1228.01 586 1228.01 580 1254 c 0,160,161 577.345 1283.47 l 0,162,163 580.493 1350.79 580.493 1350.79 672.5 1397 c 0,164,165 783.992 1452.99 783.992 1452.99 842 1519 c 0,166,167 883.993 1565.99 883.993 1565.99 911.5 1631 c 0,168,169 939.004 1696.01 939.004 1696.01 975 1747 c 0,170,-1 1009 1799 l 0,171,172 1034.59 1838.13 1034.59 1838.13 1076.6 1838.19 c 0,173,174 1090.41 1838.21 1090.41 1838.21 1106 1834 c 0,175,176 1048 1818 1048 1818 1029 1767.5 c 0,177,178 1023.79 1753.67 1023.79 1753.67 1023.77 1741.52 c 0,179,180 1023.69 1709.34 1023.69 1709.34 1060 1689 c 0,181,182 1070.52 1682.59 1070.52 1682.59 1083.77 1682.47 c 0,183,184 1107.18 1686.44 l 0,185,186 1112.9 1688.29 1112.9 1688.29 1119 1691 c 0,187,188 1155.02 1707.01 1155.02 1707.01 1164 1717 c 0,189,190 1211.36 1773.83 1211.36 1773.83 1211.75 1816.12 c 0,191,192 1208.36 1838.44 l 0,193,194 1199.16 1866.33 1199.16 1866.33 1165 1886.5 c 0,195,196 1070.99 1942.01 1070.99 1942.01 1047 1951 c 0,197,198 1137.99 1935 1137.99 1935 1181 1897 c 0,199,200 1223.99 1859.02 1223.99 1859.02 1227 1853 c 0,201,202 1246.97 1809.61 1246.97 1809.61 1247.02 1775.71 c 0,203,204 1247.05 1760.39 1247.05 1760.39 1243 1747 c 0,205,206 1229.99 1703.99 1229.99 1703.99 1186 1636 c 0,207,208 1142.01 1570.01 1142.01 1570.01 1043 1495 c 0,209,210 944 1420 944 1420 935 1345 c 0,211,212 926 1282 926 1282 945.5 1214.5 c 0,213,214 965 1147 965 1147 967 1084 c 0,215,216 967 1054 967 1054 943.5 963 c 0,217,218 920 872 920 872 815 866 c 0,219,220 857 879 857 879 883.5 956.5 c 0,221,222 889.484 974.001 889.484 974.001 889.681 987.55 c 0,223,224 886.68 1005.75 l 0,225,226 875.526 1034 875.526 1034 823 1034 c 0,227,228 771 1034 771 1034 752 980 c 0,229,230 733 926 733 926 733 893 c 0,231,232 733 811.001 733 811.001 801 798 c 0,233,234 834.18 791.758 834.18 791.758 860.508 791.83 c 0,235,236 914.319 791.977 914.319 791.977 939.5 818.5 c 0,237,238 960.695 840.826 960.695 840.826 960.646 863.631 c 0,239,240 960.608 881.174 960.608 881.174 948 899 c 0,241,242 978 896 978 896 989.5 866 c 0,243,244 1001 836 1001 836 997 821 c 0,245,246 961 701 961 701 866.5 644.5 c 0,247,248 772 588 772 588 736 460 c 0,249,250 723.002 415.009 723.002 415.009 713 360 c 0,251,252 703 305 703 305 703 257 c 0,253,254 703 207.999 703 207.999 723.5 154.5 c 0,255,256 744.007 100.984 744.007 100.984 763 57 c 0,257,258 807 -46.0001 807 -46.0001 731.5 -214 c 0,259,260 656 -382 656 -382 587 -427 c 1,0,1 EndSplineSet KernsSLIF: 79 -91 0 0 111 -182 0 0 321 -313 0 0 83 -260 0 0 45 -195 0 0 46 -234 0 0 44 -234 0 0 97 -427 0 0 65 -385 0 0 EndChar StartChar: Z Encoding: 90 90 30 Width: 1724 Flags: HMW HStem: 39.5 156<312 1458.5> 1435 135<408 1265> Fore 237 -220 m 0,0,1 177 -220 177 -220 153.5 -186 c 0,2,3 130.001 -152.001 130.001 -152.001 126 -106 c 0,4,5 124.999 -98.9995 124.999 -98.9995 130.5 -45 c 0,6,7 136.001 9.00019 136.001 9.00019 178 20 c 0,8,9 160 3.8147e-06 160 3.8147e-06 154 -37 c 0,10,11 153.534 -61.664 l 0,12,13 156.519 -80.2962 156.519 -80.2962 171 -91 c 0,14,15 195.849 -108.749 195.849 -108.749 220.619 -108.763 c 0,16,17 258.651 -108.785 258.651 -108.785 296.5 -67 c 0,18,19 359 2 359 2 350 74 c 0,20,21 341 140 341 140 312 195.5 c 0,22,23 284.062 248.969 284.062 248.969 283.967 326.1 c 0,24,25 283.963 329.032 283.963 329.032 284 332 c 0,26,27 284 367 284 367 308.5 416 c 0,28,29 332.999 464.999 332.999 464.999 375 475 c 0,30,31 386 478 386 478 412.5 479 c 0,32,33 439 480 439 480 445 464 c 0,34,35 421 479 421 479 380 457.5 c 0,36,37 339 436 339 436 336 411 c 0,38,39 333 384 333 384 340 349 c 0,40,41 347 314 347 314 386 314 c 0,42,43 433 314 433 314 491 438 c 0,44,45 549 562 549 562 561 604 c 0,46,47 588.999 708.994 588.999 708.994 597.5 802.5 c 0,48,49 606.002 896.013 606.002 896.013 622 989 c 0,50,51 626.002 1016.01 626.002 1016.01 642 1055.5 c 0,52,53 658 1094.99 658 1094.99 679 1114 c 0,54,55 732.993 1163 732.993 1163 790 1170.5 c 0,56,57 847 1178 847 1178 861 1157 c 0,58,59 839.005 1159.27 l 0,60,61 804.088 1157.18 804.088 1157.18 761.5 1121 c 0,62,63 729.029 1093.41 729.029 1093.41 728.761 1068.8 c 0,64,65 728.666 1060.01 728.666 1060.01 732.68 1051.59 c 0,66,67 736.981 1042.58 736.981 1042.58 746 1034 c 0,68,69 758.751 1021.72 758.751 1021.72 775.514 1021.82 c 0,70,71 794.252 1021.93 794.252 1021.93 818 1037.5 c 0,72,73 863 1067.01 863 1067.01 878 1087 c 0,74,-1 938.5 1169.5 l 0,75,76 971.986 1215.98 971.986 1215.98 996 1257 c 0,77,78 1019.99 1299.98 1019.99 1299.98 1034.5 1347 c 0,79,80 1037.69 1368.81 l 0,81,82 1036.86 1402.8 1036.86 1402.8 998 1431 c 0,83,84 953.018 1461.99 953.018 1461.99 882 1470.5 c 0,85,86 811.043 1479 811.043 1479 758 1479 c 0,87,88 637.993 1479 637.993 1479 585 1440.5 c 0,89,-1 461 1347 l 0,90,91 452 1341 452 1341 431.5 1324.5 c 0,92,93 411 1308 411 1308 399 1308 c 0,94,95 373 1306.01 373 1306.01 328.5 1318.5 c 0,96,97 284 1330.99 284 1330.99 273 1377 c 0,98,99 281.997 1358 281.997 1358 348.5 1347.5 c 0,100,101 370.966 1347.4 l 0,102,103 408.317 1354.47 408.317 1354.47 408.663 1416.16 c 0,104,105 408.713 1425.02 408.713 1425.02 408 1435 c 0,106,107 402.001 1507.99 402.001 1507.99 309.5 1513.5 c 0,108,109 225.463 1515.21 l 0,110,111 196.474 1514.14 196.474 1514.14 179 1510 c 0,112,113 52.0235 1476.53 52.0235 1476.53 51.5 1402.5 c 0,114,115 52 1292 l 0,116,117 29.2774 1353.48 29.2774 1353.48 29.1846 1400.28 c 0,118,119 29.0851 1450.43 29.0851 1450.43 54.9838 1483.72 c 0,120,121 59.1549 1489.08 59.1549 1489.08 64 1494 c 0,122,123 126.992 1558 126.992 1558 183 1576 c 0,124,125 251.935 1596.94 251.935 1596.94 326.223 1596.94 c 0,126,127 337.056 1596.94 337.056 1596.94 348 1596.5 c 0,128,129 433.929 1593.01 433.929 1593.01 515 1584 c 0,130,131 572 1578 572 1578 630.5 1582.5 c 0,132,133 673.739 1585.83 673.739 1585.83 674.092 1615.65 c 0,134,135 669.821 1637.75 l 0,136,137 669.427 1638.86 669.427 1638.86 669 1640 c 0,138,139 656.558 1671.11 656.558 1671.11 625.717 1671.15 c 0,140,141 611.944 1671.17 611.944 1671.17 594.5 1665 c 0,142,143 538.001 1645.01 538.001 1645.01 534 1629 c 0,144,145 532.47 1656.34 l 0,146,147 534.846 1679.14 534.846 1679.14 551 1694 c 0,148,149 576.009 1717 576.009 1717 597 1723 c 0,150,151 636 1732 636 1732 696 1727.5 c 0,152,153 755.989 1723 755.989 1723 794 1703 c 0,154,-1 917 1635.5 l 0,155,156 983.989 1598.01 983.989 1598.01 1039 1585 c 0,157,158 1102 1570 1102 1570 1150.5 1568.5 c 0,159,160 1260.41 1569.8 l 0,161,162 1262.69 1569.9 1262.69 1569.9 1265 1570 c 0,163,164 1349.93 1567.33 l 0,165,166 1365.77 1566.16 1365.77 1566.16 1382.5 1564.5 c 0,167,168 1447.99 1558.01 1447.99 1558.01 1490 1519 c 0,169,170 1518.99 1492 1518.99 1492 1521.5 1422.5 c 0,171,172 1519.34 1385.52 l 0,173,174 1512.2 1343.51 1512.2 1343.51 1483 1320 c 0,175,176 1461.18 1301.94 1461.18 1301.94 1419.52 1302 c 0,177,178 1405.83 1302.02 1405.83 1302.02 1390 1304 c 0,179,180 1421.01 1305.01 1421.01 1305.01 1454.5 1361.5 c 0,181,182 1468.24 1384.68 1468.24 1384.68 1468.27 1407.09 c 0,183,184 1468.31 1439.33 1468.31 1439.33 1440 1470 c 0,185,186 1427.39 1482.61 1427.39 1482.61 1405.3 1482.6 c 0,187,188 1387.11 1482.58 1387.11 1482.58 1362.5 1474 c 0,189,190 1308 1454.99 1308 1454.99 1290 1435 c 0,191,192 1215 1352.01 1215 1352.01 1139.5 1219.5 c 0,193,194 1064.02 1087.02 1064.02 1087.02 1018 985 c 0,195,196 988.999 918.996 988.999 918.996 972 828 c 0,197,198 955 737 955 737 946 665 c 0,199,200 935.001 593.002 935.001 593.002 894 557.5 c 0,201,202 853 522 853 522 760 561 c 0,203,204 793 555 793 555 837.5 579 c 0,205,206 882 603 882 603 864 663 c 0,207,208 853.377 695.377 853.377 695.377 831.749 695.891 c 0,209,210 814.459 692.007 l 0,211,212 798.784 685.202 798.784 685.202 779 666.5 c 0,213,214 715 606.001 715 606.001 712 568 c 0,215,216 706.001 503.007 706.001 503.007 703.5 387 c 0,217,218 706.084 344.04 l 0,219,220 718.324 266.367 718.324 266.367 787 248 c 0,221,222 835.997 235 835.997 235 897.5 226 c 0,223,224 959 217 959 217 1018 217 c 0,225,226 1110.99 217 1110.99 217 1154 286 c 0,227,228 1197.03 355.037 1197.03 355.037 1245 418 c 0,229,230 1311.58 504.619 1311.58 504.619 1367.71 504.744 c 0,231,232 1398.42 504.812 1398.42 504.812 1426 479 c 0,233,234 1498.75 410.917 1498.75 410.917 1499.3 379.363 c 0,235,236 1499.34 377.087 1499.34 377.087 1499 375 c 0,237,238 1482.01 402 1482.01 402 1418 425.5 c 0,239,240 1397.57 433 1397.57 433 1380.61 432.912 c 0,241,242 1344.43 432.724 1344.43 432.724 1324 398 c 0,243,244 1304 362.992 1304 362.992 1304 298 c 0,245,246 1304 260.996 1304 260.996 1348.5 222 c 0,247,248 1393.01 183 1393.01 183 1419 174 c 0,249,250 1456.01 159 1456.01 159 1509 141 c 0,251,252 1562.02 122.991 1562.02 122.991 1598 108 c 0,253,254 1669.01 77.9939 1669.01 77.9939 1713 17.5 c 0,255,256 1745.17 -26.7446 1745.17 -26.7446 1745.27 -73.9191 c 0,257,258 1745.3 -91.2615 1745.3 -91.2615 1741 -109 c 0,259,260 1722.99 -65.9799 1722.99 -65.9799 1692 -19.5 c 0,261,262 1660.99 27.0011 1660.99 27.0011 1582 35 c 0,263,264 1536.43 39.8826 1536.43 39.8826 1483.24 39.7986 c 0,265,266 1471.07 39.7794 1471.07 39.7794 1458.5 39.5 c 0,267,268 1390.99 37.9999 1390.99 37.9999 1335 24 c 0,269,270 1287 10.9999 1287 10.9999 1240.5 -17.5 c 0,271,272 1194 -46 1194 -46 1152 -63 c 0,273,274 1090.99 -86.0012 1090.99 -86.0012 1044.5 -92.5 c 0,275,276 998 -98.9999 998 -98.9999 964 -63 c 0,277,278 949 -48 949 -48 951.5 -26 c 0,279,280 954 -3.99995 954 -3.99995 962 1 c 0,281,282 969.999 -44 969.999 -44 999 -44 c 0,283,284 1042.99 -44 1042.99 -44 1050 -2 c 0,285,286 1048.42 12.7096 l 0,287,288 1038.21 37.5233 1038.21 37.5233 973.184 37.7045 c 0,289,290 961.698 37.7366 961.698 37.7366 948.5 37 c 0,291,292 841.002 31.0001 841.002 31.0001 828 29 c 0,293,294 699 6.99995 699 6.99995 604 -48.5 c 0,295,296 509 -104 509 -104 397 -161 c 0,297,-1 320 -198 l 0,298,299 274.001 -220 274.001 -220 237 -220 c 0,0,1 EndSplineSet KernsSLIF: 121 -117 0 0 89 -104 0 0 322 -182 0 0 321 -169 0 0 105 -52 0 0 73 -65 0 0 101 -65 0 0 98 -78 0 0 66 -78 0 0 45 -208 0 0 EndChar StartChar: a Encoding: 97 97 56 Width: 1254 Flags: W Fore 1101 -190 m 1,0,1 1130.99 -133.017 1130.99 -133.017 1145.5 -66.5 c 0,2,3 1160.01 -5.34058e-05 1160.01 -5.34058e-05 1105 52 c 0,4,5 1061.98 94.0183 1061.98 94.0183 1019 122 c 0,6,7 976 150.001 976 150.001 929 134 c 0,8,9 898.001 122 898.001 122 889.5 75 c 0,10,11 881 28 881 28 878 28 c 0,12,13 843 97 843 97 885 176 c 0,14,15 924.162 249.663 924.162 249.663 924.2 314.63 c 0,16,17 924.203 319.338 924.203 319.338 924 324 c 0,18,19 918 460 918 460 878 508 c 0,20,21 838 556 838 556 784 577 c 0,22,23 755.159 588.038 755.159 588.038 730.121 588.046 c 0,24,25 684.841 588.061 684.841 588.061 652 552 c 0,26,27 601 496 601 496 547 472 c 0,28,29 514 457 514 457 477.5 471 c 0,30,31 441 485 441 485 438 524 c 0,32,33 464.8 513.421 464.8 513.421 477.424 513.287 c 0,34,35 482.7 513.232 482.7 513.232 485.5 515 c 0,36,37 495 521 495 521 498 527 c 0,38,39 515 563 515 563 474 575 c 0,40,41 385 595 385 595 349 527 c 0,42,43 319 469 319 469 294.5 385 c 0,44,45 270 301 270 301 302 230 c 0,46,47 308.851 213.559 308.851 213.559 308.896 189.844 c 0,48,49 308.917 178.941 308.917 178.941 307.5 166.5 c 0,50,51 303 126.999 303 126.999 264 113 c 0,52,53 267.965 142.506 l 0,54,55 267.628 173.422 267.628 173.422 240.722 174.061 c 0,56,57 231.5 173.5 l 0,58,59 183 167 183 167 157 138 c 0,60,61 98.9995 73.9999 98.9995 73.9999 70 21 c 0,62,63 41 -32 41 -32 51 -108 c 0,64,65 27 -84 27 -84 28.5 -26.5 c 0,66,67 30 31 30 31 46 58 c 0,68,69 74.9999 109 74.9999 109 103 152.5 c 0,70,71 131.001 196 131.001 196 133 250 c 0,72,73 133 283 133 283 109 296.5 c 0,74,75 85 310 85 310 97 257 c 0,76,77 68.0001 282 68.0001 282 77 321 c 0,78,79 111.999 481 111.999 481 225.5 621 c 0,80,81 338.999 760.998 338.999 760.998 360 850 c 0,82,83 374.002 908.012 374.002 908.012 386 973.5 c 0,84,85 398.006 1039.04 398.006 1039.04 406 1093 c 0,86,87 412.001 1150.01 412.001 1150.01 448.5 1198.5 c 0,88,89 469.7 1226.67 469.7 1226.67 494.444 1226.67 c 0,90,91 512.299 1226.67 512.299 1226.67 532 1212 c 0,92,93 487 1203 487 1203 485.5 1178.5 c 0,94,95 484 1154.01 484 1154.01 493 1144 c 0,96,97 508.183 1124.39 508.183 1124.39 523.767 1124.39 c 0,98,99 532.816 1124.39 532.816 1124.39 542 1131 c 0,100,101 590 1162.99 590 1162.99 620.5 1264.5 c 0,102,103 650.032 1362.79 650.032 1362.79 650 1422 c 0,104,105 647 1478 647 1478 609.5 1511 c 0,106,107 591.999 1526.4 591.999 1526.4 572.867 1526.56 c 0,108,109 561.011 1526.65 561.011 1526.65 548.53 1520.9 c 0,110,111 537.988 1516.04 537.988 1516.04 527 1507 c 0,112,113 557 1585 557 1585 603.5 1573 c 0,114,115 650.006 1561 650.006 1561 697.5 1510.5 c 0,116,117 745 1459.99 745 1459.99 785.5 1398 c 0,118,119 826 1336.01 826 1336.01 844 1314 c 0,120,121 873.983 1277.02 873.983 1277.02 913.5 1253.5 c 0,122,123 953.003 1229.99 953.003 1229.99 969 1197 c 0,124,125 981.772 1169.25 981.772 1169.25 981.839 1147.23 c 0,126,127 981.924 1119.24 981.924 1119.24 961.5 1100.5 c 0,128,129 942.278 1082.86 942.278 1082.86 919.867 1082.83 c 0,130,131 899.721 1082.8 899.721 1082.8 877 1097 c 0,132,133 907 1097 907 1097 907 1116 c 0,134,135 907 1136.99 907 1136.99 873.5 1154.5 c 0,136,137 859.98 1158.04 l 0,138,139 840.37 1156.54 840.37 1156.54 840 1104 c 0,140,141 840 1080 840 1080 851.5 1052 c 0,142,-1 869 1010 l 0,143,144 896 941 896 941 908.5 966 c 0,145,146 921 991 921 991 906 1008 c 0,147,148 939 1008 939 1008 950.5 966 c 0,149,150 962 924 962 924 962 913 c 0,151,152 962 849 962 849 953.5 758.5 c 0,153,154 945 668 945 668 975 611 c 0,155,156 984 591 984 591 1019 539 c 0,157,158 1053.42 487.858 1053.42 487.858 1069 478 c 0,159,160 1087.99 466.009 1087.99 466.009 1105.5 429.5 c 0,161,162 1110.37 419.346 1110.37 419.346 1110.48 409.695 c 0,163,164 1110.57 401.279 1110.57 401.279 1107.05 393.244 c 0,165,166 1100.08 377.377 1100.08 377.377 1079 363 c 0,167,168 1084.24 378.447 1084.24 378.447 1084.46 389.787 c 0,169,170 1081.44 405.63 l 0,171,172 1074.39 420.005 1074.39 420.005 1051 421 c 0,173,174 1032.22 419.204 l 0,175,176 1015.67 414.069 1015.67 414.069 1015.63 395.11 c 0,177,178 1015.62 392.216 1015.62 392.216 1016 389 c 0,179,180 1028 288.996 1028 288.996 1102.5 232 c 0,181,182 1177 175.004 1177 175.004 1186 88 c 0,183,184 1189.26 21.1694 l 0,185,186 1188.68 -24.9163 1188.68 -24.9163 1179.5 -64 c 0,187,188 1164.01 -129.994 1164.01 -129.994 1101 -190 c 1,0,1 619 690 m 1,115,116 634 708 634 708 649.5 729.5 c 0,117,118 665 751 665 751 683 764 c 0,119,120 703.141 776.451 703.141 776.451 718.052 776.43 c 0,121,122 743.859 776.394 743.859 776.394 754 739 c 0,123,124 718 758 718 758 703 748 c 0,125,126 695.286 742.857 695.286 742.857 695.242 733.747 c 0,127,128 695.2 725.143 695.2 725.143 702 713 c 0,129,130 726 668 726 668 768.5 715 c 0,131,132 801.516 751.512 801.516 751.512 801.642 804.32 c 0,133,134 801.678 819.488 801.678 819.488 799 836 c 0,135,136 793 871 793 871 747 983 c 0,137,138 710.201 1072.6 710.201 1072.6 681.72 1073.24 c 0,139,140 670.911 1070.1 l 0,141,142 669.443 1069.18 669.443 1069.18 668 1068 c 0,143,144 641 1045.99 641 1045.99 649.5 1012.5 c 0,145,146 658 979 658 979 661 948 c 0,147,148 660.631 904.308 l 0,149,150 656.786 866.042 656.786 866.042 640.5 829 c 0,151,152 615 771 615 771 521 807 c 0,153,154 548 804 548 804 586 824.5 c 0,155,156 624 845 624 845 579 884 c 0,157,158 570.784 890.676 570.784 890.676 561.249 890.627 c 0,159,160 552.216 890.581 552.216 890.581 542 884.5 c 0,161,162 521 872 521 872 509 856 c 0,163,164 440 763 440 763 512.5 704 c 0,165,166 585 645 585 645 619 690 c 1,115,116 EndSplineSet KernsSLIF: 99 -130 0 0 109 -78 0 0 104 -117 0 0 45 -182 0 0 115 -208 0 0 121 -299 0 0 116 -342 0 0 118 -43 0 0 119 -221 0 0 EndChar StartChar: b Encoding: 98 98 18 Width: 1083 Flags: HMW HStem: 40.8 160.65<365.16 635.205> 617.1 218.45<359.04 641.325> 1229.95 170<339.15 591.6> 1316.65 94.35<25.5 180.795> VStem: 209.1 130.05<-23.8 1399.95> Fore 426.7 185.3 m 1,0,1 482.159 184.3 l 0,2,3 531.98 186.879 531.98 186.879 587.35 201.45 c 0,4,5 674.56 224.4 674.56 224.4 735.76 252.45 c 0,6,7 787.78 275.4 787.78 275.4 844.9 337.45 c 0,8,9 880.496 376.117 880.496 376.117 880.837 408.843 c 0,10,11 877.226 429.789 l 0,12,13 874.124 438.244 874.124 438.244 868.359 446.25 c 0,14,15 856.121 462.4 856.121 462.4 830.62 468.775 c 0,16,17 805.12 475.15 805.12 475.15 784.721 454.75 c 0,18,19 775.451 445.243 775.451 445.243 775.402 431.167 c 0,20,21 775.382 425.107 775.382 425.107 777.07 418.2 c 0,22,23 782.68 395.25 782.68 395.25 818.38 380.8 c 0,24,25 790.84 360.4 790.84 360.4 741.88 387.175 c 0,26,27 700.418 409.849 700.418 409.849 699.92 445.63 c 0,28,29 699.83 452.101 699.83 452.101 701.08 459 c 0,30,31 709.24 509.15 709.24 509.15 758.2 539.325 c 0,32,33 807.16 569.5 807.16 569.5 790.84 612.85 c 0,34,35 777.58 646 777.58 646 704.141 670.65 c 0,36,37 630.699 695.299 630.699 695.299 560.32 700.4 c 0,38,39 496.06 704.649 496.06 704.649 440.47 697.85 c 0,40,41 384.88 691.051 384.88 691.051 359.38 636.65 c 0,42,43 337.96 594.151 337.96 594.151 334.9 547.4 c 0,44,45 333.928 474.045 l 0,46,47 334.294 465.198 334.294 465.198 334.9 456.45 c 0,48,49 334.9 429.25 334.9 429.25 361.93 407.15 c 0,50,51 374.852 396.585 374.852 396.585 391.621 396.51 c 0,52,53 409.928 396.428 409.928 396.428 432.82 408.85 c 0,54,55 467.684 428.219 467.684 428.219 468.122 451.755 c 0,56,57 464.95 467.075 l 0,58,59 451.18 499.8 451.18 499.8 414.46 510 c 0,60,61 437.91 523.68 437.91 523.68 462.372 523.6 c 0,62,63 480.469 523.54 480.469 523.54 499.12 515.95 c 0,64,65 545.059 496.808 545.059 496.808 545.48 454.907 c 0,66,67 545.527 450.291 545.527 450.291 545.021 445.4 c 0,68,69 539.919 396.099 539.919 396.099 510.34 368.9 c 0,70,71 482.8 343.4 482.8 343.4 420.58 301.325 c 0,72,73 358.359 259.25 358.359 259.25 367.54 221 c 0,74,75 373.66 189.549 373.66 189.549 426.7 185.3 c 0,76,-1 426.7 185.3 l 1,0,1 346.289 870.4 m 1,44,45 374.387 839.903 374.387 839.903 420.997 839.912 c 0,46,47 438.15 839.915 438.15 839.915 457.81 844.05 c 0,48,49 603.802 874.755 603.802 874.755 607.75 884 c 0,50,-1 726.75 986 l 0,51,52 758.7 1033.93 758.7 1033.93 760.75 1139 c 0,53,54 757.517 1164.82 l 0,55,56 744.581 1211.19 744.581 1211.19 680.169 1246.95 c 0,57,58 610.978 1284.48 610.978 1284.48 564.236 1284.64 c 0,59,60 555.885 1284.66 555.885 1284.66 548.25 1283.5 c 0,61,62 515.57 1278.17 515.57 1278.17 545.189 1206.58 c 0,63,64 573.239 1137.3 573.239 1137.3 539.58 1074.4 c 0,65,66 493.969 990.462 493.969 990.462 419.145 989.885 c 0,67,68 413.651 989.843 413.651 989.843 408 990.25 c 0,69,70 461.193 1002.56 461.193 1002.56 461.588 1072.75 c 0,71,72 461.602 1075.24 461.602 1075.24 461.55 1077.8 c 0,73,74 460.02 1152.6 460.02 1152.6 400.859 1152.6 c 0,75,76 350.893 1152.6 350.893 1152.6 331.5 998.75 c 0,77,78 327.473 940.051 l 0,79,80 327.837 888.625 327.837 888.625 346.289 870.4 c 0,81,-1 346.289 870.4 l 1,44,45 279.65 36.125 m 145,-1,-1 184.789 -11.4746 l 0,45,46 159.502 -9.35944 l 0,47,48 129.359 -1.62558 129.359 -1.62558 126.267 32.7246 c 0,49,50 126.948 66.7202 l 0,51,52 130.7 93.8745 130.7 93.8745 145.01 117.725 c 0,53,54 140.419 37.8253 140.419 37.8253 171.02 48.875 c 0,55,56 201.62 59.9251 201.62 59.9251 206.592 124.1 c 0,57,58 211.563 188.275 211.563 188.275 203.532 264.775 c 0,59,60 195.5 341.275 195.5 341.275 180.582 410.125 c 0,61,62 165.665 478.973 165.665 478.973 158.014 498.525 c 0,63,64 125.887 571.621 125.887 571.621 111.35 600.95 c 0,65,66 93.3115 637.34 93.3115 637.34 53.21 692.325 c 0,67,68 21.4043 735.935 21.4043 735.935 21.3251 790.518 c 0,69,70 21.3148 797.641 21.3148 797.641 21.8447 804.95 c 0,71,72 26.4336 868.276 26.4336 868.276 71.5693 903.125 c 0,73,74 89.6215 917.105 89.6215 917.105 112.368 917.176 c 0,75,76 121.43 917.204 121.43 917.204 131.238 915.025 c 0,77,78 165.664 907.375 165.664 907.375 169.488 836.825 c 0,79,80 154.453 858.406 154.453 858.406 130.692 858.606 c 0,81,82 125.441 858.65 125.441 858.65 119.764 857.65 c 0,83,84 88.4003 852.125 88.4003 852.125 92.9883 800.275 c 0,85,86 96.8135 755.225 96.8135 755.225 130.475 753.95 c 0,87,88 152.528 756.629 l 0,89,90 169.195 762.046 169.195 762.046 177.904 778.175 c 0,91,92 208.147 831.941 208.147 831.941 208.122 949.45 c 0,93,94 207.738 1066.34 207.738 1066.34 203.15 1136.88 c 0,95,96 199.325 1188.72 199.325 1188.72 182.494 1252.9 c 0,97,98 167.916 1308.49 167.916 1308.49 116.417 1308.61 c 0,99,100 107.206 1308.63 107.206 1308.63 96.8135 1306.88 c 0,101,102 45.3775 1298.19 45.3775 1298.19 45.4768 1255.64 c 0,103,104 45.4942 1248.2 45.4942 1248.2 47.0889 1239.72 c 0,105,106 57.7988 1182.79 57.7988 1182.79 80.75 1179.38 c 0,107,108 59.2039 1176.94 l 0,109,110 28.1379 1179.12 28.1379 1179.12 7.69141 1217.2 c 0,111,112 -7.80302 1246.06 -7.80302 1246.06 -7.73372 1278.37 c 0,113,114 -7.68156 1302.69 -7.68156 1302.69 1.18848 1328.97 c 0,115,116 34.7996 1426.53 34.7996 1426.53 120.092 1427.05 c 0,117,118 156.484 1423.33 l 0,119,-1 235.662 1407.6 l 0,120,121 259.896 1404.67 l 0,122,123 288.348 1405.15 288.348 1405.15 332.859 1419.5 c 0,124,125 373.66 1433.1 373.66 1433.1 406.81 1470.5 c 0,126,127 440.005 1507.95 440.005 1507.95 467.5 1535.95 c 0,128,129 485.874 1555.51 485.874 1555.51 524.109 1572.08 c 0,130,131 553.312 1584.73 553.312 1584.73 579.849 1584.75 c 0,132,133 588.062 1584.76 588.062 1584.76 596.021 1583.55 c 0,134,135 643.954 1576.76 643.954 1576.76 688.84 1535.95 c 0,136,137 717.922 1509.51 717.922 1509.51 717.881 1472.01 c 0,138,139 717.858 1452.1 717.858 1452.1 709.24 1428 c 0,140,141 702.102 1456.04 702.102 1456.04 643.45 1495.15 c 0,142,143 623.166 1508.67 623.166 1508.67 606.944 1508.87 c 0,144,145 598.781 1508.97 598.781 1508.97 591.647 1505.69 c 0,146,147 572.968 1497.11 572.968 1497.11 561.34 1465.4 c 0,148,149 550.12 1434.8 550.12 1434.8 665.38 1378.28 c 0,150,151 780.658 1321.74 780.658 1321.74 811.24 1287.75 c 0,152,153 887.742 1200.19 887.742 1200.19 902.53 1105 c 0,154,155 908.699 1065.29 908.699 1065.29 908.628 1027.72 c 0,156,157 908.519 970.361 908.519 970.361 893.859 918 c 0,158,159 886.72 892.498 886.72 892.498 847.45 853.825 c 0,160,161 819.755 826.55 819.755 826.55 792.314 826.543 c 0,162,163 780.845 826.539 780.845 826.539 769.42 831.3 c 0,164,165 797.979 861.049 797.979 861.049 769.42 872.1 c 0,166,167 753.683 874.809 l 0,168,169 739.244 873.686 739.244 873.686 735.76 855.1 c 0,170,171 728.62 816.85 728.62 816.85 808.69 722.5 c 0,172,173 889.862 626.849 889.862 626.849 918.34 666.4 c 0,174,175 933.641 687.651 933.641 687.651 918.34 717.4 c 0,176,177 903.04 747.15 903.04 747.15 871.42 770.1 c 0,178,179 963.221 767.55 963.221 767.55 1004.02 693.175 c 0,180,181 1044.82 618.8 1044.82 618.8 1046.86 590.75 c 0,182,183 1044.78 549.144 l 0,184,185 1038.75 505.432 1038.75 505.432 1016.77 447.1 c 0,186,187 983.62 359.55 983.62 359.55 983.62 288.15 c 0,188,189 983.62 202.3 983.62 202.3 971.38 134.3 c 0,190,191 959.141 66.2997 959.141 66.2997 922.42 22.9502 c 0,192,193 878.56 -28.0498 878.56 -28.0498 805.12 -42.5 c 0,194,195 768.4 -50.1505 768.4 -50.1505 705.67 -44.2002 c 0,196,197 642.94 -38.25 642.94 -38.25 616.42 -17 c 0,198,199 647.676 -20.065 l 0,200,201 678.398 -19.3574 678.398 -19.3574 708.221 -3.8252 c 0,202,203 737.354 11.3484 737.354 11.3484 737.606 32.6744 c 0,204,205 737.702 40.8109 737.702 40.8109 733.594 49.8429 c 0,206,207 731.27 54.953 731.27 54.953 727.6 60.3496 c 0,208,209 710.26 85.8496 710.26 85.8496 621.521 82.4502 c 0,210,211 532.781 79.0499 532.781 79.0499 497.08 76.5 c 0,212,-1 382.84 67.5752 l 0,213,214 337.222 59.1049 337.222 59.1049 279.65 36.125 c 145,-1,-1 EndSplineSet EndChar StartChar: c Encoding: 99 99 19 Width: 1171 Flags: W Fore 130 1163 m 1,0,1 132.395 1186.83 l 0,2,3 140.998 1220.08 140.998 1220.08 178.5 1260.5 c 0,4,5 207.417 1291.66 207.417 1291.66 233.339 1292.09 c 0,6,7 251.453 1288.48 l 0,8,9 261.996 1284 261.996 1284 272 1274 c 0,10,11 226.25 1267.25 226.25 1267.25 226.063 1236.88 c 0,12,13 226 1226.75 226 1226.75 231 1214 c 0,14,15 238.091 1193.2 238.091 1193.2 250.769 1193.3 c 0,16,17 264.909 1193.4 264.909 1193.4 286 1219.5 c 0,18,19 325.995 1268.99 325.995 1268.99 334 1286 c 0,20,21 358.997 1338.99 358.997 1338.99 366 1392 c 0,22,23 373.001 1445 373.001 1445 409 1490 c 0,24,25 436.611 1525.5 436.611 1525.5 481.5 1525.5 c 0,26,27 525.998 1525.01 525.998 1525.01 538 1492 c 0,28,29 480 1492 480 1492 499 1465 c 0,30,31 509.578 1449.72 509.578 1449.72 524.471 1449.64 c 0,32,33 534.923 1449.58 534.923 1449.58 547.5 1457 c 0,34,35 577.986 1474.99 577.986 1474.99 593 1489 c 0,36,37 621.242 1516.57 621.242 1516.57 621.224 1533.29 c 0,38,39 621.216 1541.43 621.216 1541.43 614.5 1547 c 0,40,41 594 1563.99 594 1563.99 564 1547 c 0,42,43 567.001 1588.01 567.001 1588.01 599.5 1593 c 0,44,45 630.619 1594.13 l 0,46,47 643.508 1592.77 643.508 1592.77 654 1588 c 0,48,49 749.093 1541.95 749.093 1541.95 811.5 1505 c 0,50,51 874 1467.99 874 1467.99 892 1460 c 0,52,53 923.249 1445.25 923.249 1445.25 951.459 1445.18 c 0,54,55 955.764 1445.17 955.764 1445.17 960 1445.5 c 0,56,57 1000.05 1444.5 l 0,58,59 1015.33 1442.75 1015.33 1442.75 1032 1439 c 0,60,61 1053.01 1433 1053.01 1433 1059.5 1404.5 c 0,62,63 1065.99 1376 1065.99 1376 1058 1349 c 0,64,65 1024.88 1380.05 1024.88 1380.05 1003.65 1380.15 c 0,66,67 994.125 1380.2 994.125 1380.2 987 1374 c 0,68,69 964 1354.01 964 1354.01 963 1294 c 0,70,71 961.999 1263.98 961.999 1263.98 959.5 1234 c 0,72,73 957 1204 957 1204 969 1177 c 0,74,75 988.003 1130 988.003 1130 1028 1119.5 c 0,76,77 1068.01 1109 1068.01 1109 1116 1106 c 0,78,79 1103.78 1081.57 1103.78 1081.57 1061.37 1081.35 c 0,80,81 1051.72 1081.3 1051.72 1081.3 1040.5 1082.5 c 0,82,83 980.007 1088.99 980.007 1088.99 961 1104 c 0,84,85 906.204 1143.52 906.204 1143.52 905.876 1183.45 c 0,86,87 905.839 1187.97 905.839 1187.97 906.5 1192.5 c 0,88,89 906.604 1224.3 l 0,90,91 902.367 1263.58 902.367 1263.58 879 1322 c 0,92,93 857.998 1373.01 857.998 1373.01 794 1384 c 0,94,95 762.159 1385.67 l 0,96,97 718.588 1382.3 718.588 1382.3 686 1346 c 0,98,99 653.006 1308.01 653.006 1308.01 627.5 1257 c 0,100,101 602 1206 602 1206 572 1167 c 0,102,103 560.987 1152.31 560.987 1152.31 518.784 1152.37 c 0,104,105 515.018 1152.38 515.018 1152.38 511 1152.5 c 0,106,107 466.355 1153.87 466.355 1153.87 465.708 1179.72 c 0,108,109 465.644 1182.24 465.644 1182.24 466 1185 c 0,110,111 495 1170 495 1170 522 1188 c 0,112,113 547.852 1205.23 547.852 1205.23 548 1235 c 0,114,115 547.031 1266.97 547.031 1266.97 528.5 1267 c 0,116,117 509.991 1265.99 509.991 1265.99 495 1257 c 0,118,119 450.683 1226.47 450.683 1226.47 430 1200.5 c 0,120,121 409.998 1175 409.998 1175 398 1123 c 0,122,123 387.25 1077.98 387.25 1077.98 387.334 1035.68 c 0,124,125 387.375 1015.02 387.375 1015.02 390 995 c 0,126,-1 407 865 l 0,127,128 410 830 410 830 423.5 794 c 0,129,130 437 758 437 758 432 724 c 0,131,132 415.795 633.439 415.795 633.439 333.252 632.842 c 0,133,134 329.206 632.813 329.206 632.813 325 633 c 0,135,136 342 645 342 645 362.5 669 c 0,137,138 383 693 383 693 368 720 c 0,139,140 355 742 355 742 318.5 730 c 0,141,142 282 718 282 718 279 695 c 0,143,144 264 611 264 611 263 541.5 c 0,145,146 266.367 498.172 l 0,147,148 274.626 448.904 274.626 448.904 303 397 c 0,149,150 322.999 359.001 322.999 359.001 353.5 353.5 c 0,151,152 384 348 384 348 397 405 c 0,153,154 399.148 427.344 l 0,155,156 398.563 432.875 398.563 432.875 396.5 437 c 0,157,158 391 448 391 448 379 469 c 0,159,160 399.007 462.998 399.007 462.998 417.5 458 c 0,161,162 436 453 436 453 447 433 c 0,163,164 468 391 468 391 471 351 c 0,165,166 474 311.003 474 311.003 488 268 c 0,167,168 504 216 504 216 538 207 c 0,169,170 557.5 200.76 557.5 200.76 573.62 200.638 c 0,171,172 586.718 200.539 586.718 200.539 597.585 204.479 c 0,173,174 624.781 214.339 624.781 214.339 638 249.5 c 0,175,176 663 316 663 316 696 364 c 0,177,178 709 382 709 382 735 379.5 c 0,179,180 761 377 761 377 776 353 c 0,181,182 791 329 791 329 788 311 c 0,183,184 763 325 763 325 743.5 313 c 0,185,186 724 301 724 301 741 281 c 0,187,188 751.698 266.413 751.698 266.413 764.877 266.011 c 0,189,190 779.807 269.701 l 0,191,192 787.321 273.45 787.321 273.45 795.5 281 c 0,193,194 828 311 828 311 831 356 c 0,195,196 829.957 415.261 l 0,197,198 823.929 488.15 823.929 488.15 795 570 c 0,199,200 790.425 583.218 790.425 583.218 790.501 606.128 c 0,201,202 790.575 628.283 790.575 628.283 795 659.5 c 0,203,204 804 723 804 723 835 768 c 0,205,206 830.002 721.017 830.002 721.017 824 674 c 0,207,208 818 627 818 627 833 581 c 0,209,210 844 548 844 548 857.5 513.5 c 0,211,212 871 479 871 479 886 452 c 0,213,214 913 405 913 405 937.5 378.5 c 0,215,216 962 352 962 352 1013 358 c 0,217,218 1033.63 360.063 1033.63 360.063 1033.93 381.977 c 0,219,220 1030 406 l 0,221,222 1046.99 412 1046.99 412 1061.5 387.5 c 0,223,224 1073.22 367.704 1073.22 367.704 1073.51 356.063 c 0,225,226 1073.58 353.302 1073.58 353.302 1073 351 c 0,227,228 1062.99 299 1062.99 299 1004 279 c 0,229,230 978 270 978 270 949.5 270.5 c 0,231,232 921 271 921 271 898 259 c 0,233,234 867 242.001 867 242.001 863.5 178.5 c 0,235,236 860 115.001 860 115.001 842 81 c 0,237,238 821 43 821 43 766 33 c 0,239,240 744 28 744 28 703.5 36 c 0,241,242 663 44 663 44 664 80 c 0,243,244 691 55 691 55 725 75 c 0,245,246 745 85.9999 745 85.9999 736 111.5 c 0,247,248 727 137 727 137 708 141 c 0,249,250 679.592 141.611 l 0,251,252 652.565 138.87 652.565 138.87 616 125 c 0,253,254 525 90.9996 525 90.9996 473 65 c 0,255,256 421 39 421 39 335 79 c 0,257,258 306 91 306 91 300.5 137.5 c 0,259,260 300.225 168.721 l 0,261,262 303.157 189.438 303.157 189.438 316 198 c 0,263,264 316 161.999 316 161.999 332.5 142 c 0,265,266 341.348 131.275 341.348 131.275 350.627 130.902 c 0,267,268 361.932 134.19 l 0,269,270 364.451 135.734 364.451 135.734 367 138 c 0,271,272 381.21 150.918 381.21 150.918 381.339 168.895 c 0,273,274 381.439 182.643 381.439 182.643 373.303 199.348 c 0,275,276 359.136 228.439 359.136 228.439 320 266.5 c 0,277,278 229 355 229 355 202 366 c 0,279,280 166.426 353.951 166.426 353.951 166.407 335.647 c 0,281,282 166.393 322.049 166.393 322.049 186 305 c 0,283,284 231.999 265.001 231.999 265.001 267 264 c 0,285,286 196.001 254 196.001 254 165 288 c 0,287,288 134.001 321.999 134.001 321.999 113 369 c 0,289,290 87.6341 423.536 87.6341 423.536 87.6032 491.344 c 0,291,292 87.5854 530.464 87.5854 530.464 96 574 c 0,293,294 108 633 108 633 140 689 c 0,295,296 172 745 172 745 175 806 c 0,297,298 178 896 178 896 155.5 984.5 c 0,299,300 133 1073 133 1073 130 1163 c 1,0,1 EndSplineSet KernsSLIF: 115 -117 0 0 97 -104 0 0 EndChar StartChar: d Encoding: 100 100 60 Width: 1313 Flags: MW VStem: 197 151.5<8.5 1487> Fore 334 -30 m 1,0,1 377.834 -63.5206 377.834 -63.5206 415.436 -63.5899 c 0,2,3 436.165 -63.6281 436.165 -63.6281 455 -53.5 c 0,4,5 508 -25 508 -25 508 -10 c 0,6,7 506 21 506 21 458 20.5 c 0,8,9 410 20 410 20 348.5 8.5 c 0,10,11 287 -3 287 -3 228 -17.5 c 0,12,13 181.952 -28.8171 181.952 -28.8171 157.832 -28.8647 c 0,14,15 151.049 -28.8781 151.049 -28.8781 146 -28 c 0,16,17 98 -19 98 -19 54.5 29 c 0,18,19 11 77 11 77 50 164 c 0,20,21 51.0001 77.9999 51.0001 77.9999 91.5 56.5 c 0,22,23 132 35 132 35 180 52 c 0,24,25 227.999 68.9997 227.999 68.9997 268 112.5 c 0,26,27 308 155.999 308 155.999 308 203 c 0,28,29 308 222.999 308 222.999 281.5 263 c 0,30,31 257.972 298.514 257.972 298.514 234.05 298.555 c 0,32,33 231.028 298.561 231.028 298.561 228 298 c 0,34,35 193.875 292.75 193.875 292.75 193.82 247.688 c 0,36,37 193.812 241.25 193.812 241.25 194.5 234 c 0,38,39 200.001 175.999 200.001 175.999 229 156 c 0,40,41 191.999 157.001 191.999 157.001 181 168 c 0,42,43 170 179 170 179 164 196 c 0,44,45 147.605 234.879 147.605 234.879 147.667 279.024 c 0,46,47 147.737 329.122 147.737 329.122 169 386 c 0,48,49 209.007 493.016 209.007 493.016 240 562 c 0,50,51 262.001 612 262.001 612 268.5 657 c 0,52,53 270.99 707.825 l 0,54,55 270.407 743.335 270.407 743.335 265 792 c 0,56,57 254.001 877.999 254.001 877.999 193.5 953.5 c 0,58,59 133.003 1028.99 133.003 1028.99 120 1074 c 0,60,61 113.455 1094.73 113.455 1094.73 113.455 1114.93 c 0,62,63 113.455 1150.28 113.455 1150.28 133.5 1184 c 0,64,65 159.451 1227.66 159.451 1227.66 208.138 1227.89 c 0,66,67 218.549 1227.94 218.549 1227.94 230 1226 c 0,68,69 208.997 1217 208.997 1217 195.5 1189 c 0,70,71 190.804 1179.26 190.804 1179.26 190.888 1170.73 c 0,72,73 191.044 1154.74 191.044 1154.74 208 1143 c 0,74,75 219.174 1134.49 219.174 1134.49 227.907 1134.36 c 0,76,77 234.827 1134.26 234.827 1134.26 240.213 1139.43 c 0,78,79 253.577 1152.25 253.577 1152.25 257.5 1197.5 c 0,80,81 265 1284.01 265 1284.01 258 1322 c 0,82,83 248.999 1370.01 248.999 1370.01 228 1406.5 c 0,84,85 207.005 1442.99 207.005 1442.99 197 1487 c 0,86,87 191.696 1508.7 191.696 1508.7 191.74 1532.38 c 0,88,89 191.787 1557.8 191.787 1557.8 198 1585.5 c 0,90,91 209.999 1639 209.999 1639 247 1672 c 0,92,93 272.994 1695.99 272.994 1695.99 322 1697 c 0,94,95 353.127 1694.13 l 0,96,97 377.447 1688.33 377.447 1688.33 389 1671 c 0,98,99 398 1656 398 1656 404.5 1641 c 0,100,101 407.204 1623.97 l 0,102,103 406.891 1611.85 406.891 1611.85 402 1595 c 0,104,105 396 1617.99 396 1617.99 349 1635.5 c 0,106,107 302 1653.01 302 1653.01 287 1592 c 0,108,109 275 1545.01 275 1545.01 314.5 1517 c 0,110,111 353.959 1489.02 353.959 1489.02 396 1470 c 0,112,113 433.024 1451.99 433.024 1451.99 549.5 1421.5 c 0,114,115 589.846 1410.94 589.846 1410.94 617.657 1410.87 c 0,116,117 657.976 1410.77 657.976 1410.77 671.957 1432.72 c 0,118,119 676.18 1439.36 676.18 1439.36 678 1448 c 0,120,121 681.935 1486.52 l 0,122,123 681.575 1537.19 681.575 1537.19 645 1552.5 c 0,124,125 621.099 1562.5 621.099 1562.5 601.002 1562.63 c 0,126,127 584.9 1562.73 584.9 1562.73 571.241 1556.48 c 0,128,129 567.003 1554.55 567.003 1554.55 563 1552 c 0,130,131 563 1590.99 563 1590.99 593 1604 c 0,132,133 622.962 1616.99 622.962 1616.99 629 1618 c 0,134,135 695 1621 695 1621 723.5 1597 c 0,136,137 752 1573 752 1573 765 1549 c 0,138,139 785.996 1510.01 785.996 1510.01 800.5 1455.5 c 0,140,141 815 1401.01 815 1401.01 851 1379 c 0,142,143 908.983 1342.01 908.983 1342.01 934.5 1333 c 0,144,145 960 1324 960 1324 1024 1315 c 0,146,147 1112.99 1301.99 1112.99 1301.99 1135 1228 c 0,148,149 1140.22 1208.71 1140.22 1208.71 1140.13 1192.05 c 0,150,151 1139.85 1135.97 1139.85 1135.97 1078 1109 c 0,152,153 1094.92 1132.07 1094.92 1132.07 1094.98 1158.11 c 0,154,155 1095 1165.92 1095 1165.92 1093.5 1174 c 0,156,157 1087.84 1204.5 1087.84 1204.5 1050.65 1204.62 c 0,158,159 1045.17 1204.64 1045.17 1204.64 1039 1204 c 0,160,161 1022.33 1202.15 1022.33 1202.15 1022.05 1180.66 c 0,162,163 1026.65 1151.28 l 0,164,165 1027.28 1148.94 1027.28 1148.94 1028 1146.5 c 0,166,167 1044.01 1091.99 1044.01 1091.99 1056 1070 c 0,168,169 1105.98 963.021 1105.98 963.021 1173.5 863.5 c 0,170,171 1241.01 763.992 1241.01 763.992 1246 707 c 0,172,173 1244.58 673.304 l 0,174,175 1236.64 624.131 1236.64 624.131 1194 580 c 0,176,177 1179 565 1179 565 1144.5 562 c 0,178,179 1110 559 1110 559 1089 571 c 0,180,181 1122 571 1122 571 1138.5 597.5 c 0,182,183 1145.85 609.313 1145.85 609.313 1145.96 618.841 c 0,184,185 1146.05 627.748 1146.05 627.748 1139.81 634.659 c 0,186,187 1137.75 636.938 1137.75 636.938 1135 639 c 0,188,189 1121.36 648.356 1121.36 648.356 1109.39 648.29 c 0,190,191 1090.64 648.186 1090.64 648.186 1076 625 c 0,192,193 1052 587.002 1052 587.002 1043 564 c 0,194,195 1041.99 559.967 1041.99 559.967 997 446.5 c 0,196,197 974.979 390.957 974.979 390.957 974.75 361.637 c 0,198,199 974.65 348.854 974.65 348.854 978.693 341.055 c 0,200,201 984.326 330.189 984.326 330.189 998 329 c 0,202,203 1023.15 329.34 l 0,204,205 1039.03 332.237 1039.03 332.237 1046.5 343 c 0,206,207 1059 361.014 1059 361.014 1071 397 c 0,208,209 1088.77 358.229 1088.77 358.229 1088.85 329.175 c 0,210,211 1088.93 304.269 1088.93 304.269 1076 286.5 c 0,212,213 1048 248.001 1048 248.001 1022 238 c 0,214,215 869.999 176 869.999 176 814.5 173 c 0,216,217 759 170 759 170 652 20 c 0,218,219 541 -136 541 -136 452.5 -121 c 0,220,221 364 -106 364 -106 334 -30 c 1,0,1 640 273 m 0,118,119 660 292 660 292 698.5 340 c 0,120,121 737 388 737 388 751 411 c 0,122,123 772 447 772 447 779 481.5 c 0,124,-1 794 558 l 0,125,126 807 630 807 630 855.5 644 c 0,127,128 904 658 904 658 919 635 c 0,129,130 875 635 875 635 860 607 c 0,131,132 850.854 589.926 850.854 589.926 850.631 578.431 c 0,133,134 853.459 566.831 l 0,135,136 854 566 l 0,137,138 884 522 884 522 929.5 597.5 c 0,139,140 975 673 975 673 981 742 c 0,141,142 979.57 790.509 l 0,143,144 974.2 842.742 974.2 842.742 953.5 917 c 0,145,146 929.084 1004.59 929.084 1004.59 891.747 1005.06 c 0,147,148 875.211 1001.29 l 0,149,150 872.143 999.898 872.143 999.898 869 998 c 0,151,152 845 983 845 983 857 959.5 c 0,153,154 869 936 869 936 905 927 c 0,155,156 883.461 918.384 883.461 918.384 866.562 918.432 c 0,157,158 828.539 918.538 828.539 918.538 814 962.5 c 0,159,160 793.002 1025.99 793.002 1025.99 784 1077 c 0,161,162 769.001 1151.99 769.001 1151.99 708.5 1199.5 c 0,163,164 648 1247.01 648 1247.01 578 1256.5 c 0,165,166 508 1265.99 508 1265.99 447.5 1234 c 0,167,168 387.002 1202.01 387.002 1202.01 374 1119 c 0,169,170 372.342 1087.63 l 0,171,172 373.653 1071.46 373.653 1071.46 380 1058.5 c 0,173,174 392 1034.01 392 1034.01 423 1042 c 0,175,176 440 1046.01 440 1046.01 435.5 1066 c 0,177,178 430.999 1086 430.999 1086 410 1101 c 0,179,180 433.116 1101.63 l 0,181,182 462.692 1097.49 462.692 1097.49 481 1066 c 0,183,184 489 1051 489 1051 494 1025 c 0,185,186 494.287 1001.71 l 0,187,188 491.796 985.017 491.796 985.017 482 966 c 0,189,190 413.999 836.997 413.999 836.997 395.5 680 c 0,191,192 383.413 577.424 383.413 577.424 383.492 512.842 c 0,193,194 383.533 478.573 383.533 478.573 387 455 c 0,195,196 402 350 402 350 439 346.5 c 0,197,198 476 343 476 343 482 379 c 0,199,200 486 415 486 415 435 415 c 0,201,202 439 427 439 427 456 428.5 c 0,203,204 473.001 430 473.001 430 484 433 c 0,205,206 538 442 538 442 549 386.5 c 0,207,208 560 331 560 331 570 296 c 0,209,210 578 263 578 263 600 259 c 0,211,212 622 255 622 255 640 273 c 0,118,119 EndSplineSet KernsSLIF: 122 -91 0 0 97 -150 0 0 EndChar StartChar: e Encoding: 101 101 54 Width: 1080 Flags: HMW HStem: 142 27<40 136.5> 177.5 172<205.5 798> 722 137<316 666> 1260.15 167.854<365 744> VStem: 114.5 149.5<412 1397> Fore 611 199 m 0,0,1 532.994 197.999 532.994 197.999 452 182 c 0,2,3 370.998 165.999 370.998 165.999 302 133 c 0,4,5 242 103 242 103 166 89.5 c 0,6,7 89.9995 76 89.9995 76 40 142 c 0,8,9 16.5184 172.707 16.5184 172.707 16.6003 201.057 c 0,10,11 16.6544 219.793 16.6544 219.793 27 237.5 c 0,12,13 49.0431 275.228 49.0431 275.228 99.8393 275.219 c 0,14,15 108.956 275.217 108.956 275.217 119 274 c 0,16,-1 84 260.5 l 0,17,18 68.7059 254.765 68.7059 254.765 68.6159 232.948 c 0,19,20 68.5882 226.235 68.5882 226.235 70 218 c 0,21,22 77.7819 168.715 77.7819 168.715 121.824 168.025 c 0,23,24 136.5 169 l 0,25,26 194 177 194 177 206 240 c 0,27,28 209.42 259.054 209.42 259.054 209.379 285.629 c 0,29,30 209.336 313.444 209.336 313.444 205.5 349.5 c 0,31,32 198 420 198 420 144 428 c 0,33,34 130.002 426.996 l 0,35,36 120.296 423.593 120.296 423.593 114.5 412 c 0,37,38 105.001 393 105.001 393 108 376 c 0,39,40 114 339 114 339 144 310 c 0,41,42 85.9995 325 85.9995 325 65 379 c 0,43,44 26 481 26 481 54.5 590 c 0,45,46 83.0006 699.003 83.0006 699.003 101 799 c 0,47,48 117.001 895 117.001 895 120 939.5 c 0,49,50 123 984 123 984 113 1080 c 0,51,52 102.999 1161 102.999 1161 66 1248 c 0,53,54 32.5449 1326.66 32.5449 1326.66 32.6099 1399.61 c 0,55,56 32.6168 1407.34 32.6168 1407.34 33 1415 c 0,57,58 35.9995 1475.99 35.9995 1475.99 75 1507 c 0,59,60 104.849 1532.01 104.849 1532.01 129.979 1532.28 c 0,61,62 149.015 1528.68 l 0,63,64 174.29 1518.42 174.29 1518.42 194 1479 c 0,65,66 174.301 1496.91 174.301 1496.91 155.139 1496.82 c 0,67,68 142.197 1496.77 142.197 1496.77 129.5 1488.5 c 0,69,70 98 1467.99 98 1467.99 114 1427 c 0,71,72 129.519 1384.33 129.519 1384.33 180 1384 c 0,73,74 230.015 1385.01 230.015 1385.01 264 1397 c 0,75,76 349.99 1424 349.99 1424 440.5 1495 c 0,77,78 517.902 1555.72 517.902 1555.72 599.319 1555.73 c 0,79,80 613.102 1555.74 613.102 1555.74 627 1554 c 0,81,82 663.003 1548 663.003 1548 683.5 1514 c 0,83,84 693.597 1497.25 693.597 1497.25 693.627 1480.75 c 0,85,86 693.657 1463.75 693.657 1463.75 683 1447 c 0,87,88 675.449 1501.53 675.449 1501.53 628.135 1501.87 c 0,89,90 619.051 1501.93 619.051 1501.93 608.5 1500 c 0,91,92 543 1488 543 1488 544 1449 c 0,93,94 544 1398.96 544 1398.96 594.427 1399.05 c 0,95,96 608.5 1399.07 608.5 1399.07 626.5 1403 c 0,97,98 708.714 1420.94 708.714 1420.94 744 1428 c 0,99,100 789.909 1436.98 789.909 1436.98 850.5 1445.5 c 0,101,102 898.275 1448.51 l 0,103,104 930.453 1447.79 930.453 1447.79 958 1439 c 0,105,106 1070.99 1404.01 1070.99 1404.01 1081 1291 c 0,107,108 1073.99 1330 1073.99 1330 1034 1364 c 0,109,110 994.899 1396.93 994.899 1396.93 940.501 1397.15 c 0,111,112 916.073 1397.25 916.073 1397.25 887.5 1390.5 c 0,113,114 798.009 1369.01 798.009 1369.01 749 1327 c 0,115,116 721.998 1304.99 721.998 1304.99 717.5 1274 c 0,117,118 718.413 1256.86 l 0,119,120 723.722 1238.24 723.722 1238.24 749 1227 c 0,121,122 777 1215 777 1215 812 1218 c 0,123,124 787.164 1197.3 787.164 1197.3 749.528 1197.34 c 0,125,126 705.755 1197.38 705.755 1197.38 643.5 1226 c 0,127,128 528.99 1279 528.99 1279 452 1279 c 0,129,130 393.915 1279 393.915 1279 365 1260.15 c 0,131,132 336.453 1241.55 336.453 1241.55 336.306 1204.56 c 0,133,134 336.246 1189.34 336.246 1189.34 341 1171 c 0,135,136 348.997 1138.01 348.997 1138.01 374.5 1092 c 0,137,138 389.671 1064.63 389.671 1064.63 389.799 1041.87 c 0,139,140 389.886 1026.37 389.886 1026.37 383 1013 c 0,141,142 362.985 972.016 362.985 972.016 319 972 c 0,143,144 342.462 1000.49 342.462 1000.49 342.676 1019.78 c 0,145,146 342.77 1028.23 342.77 1028.23 338.391 1034.92 c 0,147,148 334.882 1040.28 334.882 1040.28 328.5 1044.5 c 0,149,150 314.406 1053.82 314.406 1053.82 301.912 1054.03 c 0,151,152 287.322 1050.91 l 0,153,154 279.271 1047.18 279.271 1047.18 272 1039 c 0,155,156 233 997 233 997 254 925.5 c 0,157,158 275 854 275 854 342 860 c 0,159,160 401 865 401 865 445.5 876.5 c 0,161,162 490 888 490 888 544 908 c 0,163,164 611 932 611 932 698 901.5 c 0,165,166 769.056 876.59 769.056 876.59 769.404 808.654 c 0,167,168 769.482 793.41 769.482 793.41 766 776 c 0,169,170 758.999 814.001 758.999 814.001 733.5 841.5 c 0,171,172 714.8 861.667 714.8 861.667 687.227 861.667 c 0,173,174 677.2 861.667 677.2 861.667 666 859 c 0,175,176 633 850 633 850 614.5 819.5 c 0,177,178 596 789 596 789 590 759 c 0,179,180 573 675 573 675 546.5 621 c 0,181,182 520 567 520 567 416 594 c 0,183,184 492 614 492 614 492 650 c 0,185,186 492 714 492 714 427.5 721.5 c 0,187,188 363 729 363 729 316 722 c 0,189,190 256.001 712 256.001 712 255 658 c 0,191,192 252 612 252 612 282 609 c 0,193,194 312 606 312 606 307 663 c 0,195,196 347 619 347 619 347 589 c 0,197,198 345.999 539.999 345.999 539.999 318 514 c 0,199,200 290 488 290 488 290 451 c 0,201,202 290 385 290 385 327.5 389 c 0,203,204 365 393 365 393 414.5 417 c 0,205,206 464 441 464 441 512 461 c 0,207,208 529.829 468.428 529.829 468.428 544.07 468.407 c 0,209,210 568.171 468.371 568.171 468.371 582 447 c 0,211,212 611 399 611 399 569 385 c 0,213,214 574 412 574 412 544 406 c 0,215,216 494 394 494 394 527 349 c 0,217,218 550 318 550 318 607 318 c 0,219,220 664 318 664 318 694 336 c 0,221,222 738 361 738 361 769 401.5 c 0,223,224 800 442 800 442 845 464 c 0,225,226 890 487 890 487 934 439 c 0,227,228 954.533 416.6 954.533 416.6 954.813 395.507 c 0,229,230 951.306 377.599 l 0,231,232 945.296 362.968 945.296 362.968 929 349 c 0,233,234 934.5 365.5 934.5 365.5 934.563 377.5 c 0,235,236 934.661 396.45 934.661 396.45 921.2 404.178 c 0,237,238 911.841 409.551 911.841 409.551 895.928 409.5 c 0,239,240 891.247 409.484 891.247 409.484 886 409 c 0,241,242 837.001 403 837.001 403 831.5 357.5 c 0,243,244 830.802 321.967 l 0,245,246 833.038 298.338 833.038 298.338 843 279 c 0,247,248 862.999 236.001 862.999 236.001 911 201.5 c 0,249,250 959 167 959 167 990 131 c 0,251,252 1021.99 93.9995 1021.99 93.9995 1032 32.5 c 0,253,254 1042.01 -29 1042.01 -29 1008 -71 c 0,255,256 1011.87 -21.0033 l 0,257,258 1011.65 -0.13516 1011.65 -0.13516 1007.5 15 c 0,259,260 998.993 46.0079 998.993 46.0079 959 87 c 0,261,262 888.999 156.001 888.999 156.001 798 177.5 c 0,263,264 706.997 199 706.997 199 611 199 c 0,0,1 EndSplineSet KernsSLIF: 115 -78 0 0 EndChar StartChar: f Encoding: 102 102 20 Width: 1155 Flags: HMW HStem: 714 154<374 666> 1301 192<389 965> VStem: 130 185<147 1541> Fore 582 828 m 1,0,1 584 733 584 733 666 714 c 0,2,3 708 705 708 705 746 735 c 0,4,5 784 765 784 765 784 764 c 0,6,7 778 743 778 743 755 704 c 0,8,9 732 665 732 665 694 648 c 0,10,11 647 631 647 631 619 637 c 0,12,13 591 643 591 643 558 654 c 0,14,15 515 670 515 670 466.5 713.5 c 0,16,17 418 757 418 757 366 739 c 0,18,19 325 717 325 717 316.5 692.5 c 0,20,21 308 668 308 668 302 643 c 0,22,23 297 613 297 613 285 522 c 0,24,25 273 431 273 431 351 435 c 0,26,27 369.915 452.305 369.915 452.305 370.366 468.962 c 0,28,29 367.282 483.295 l 0,30,31 359.337 500.505 359.337 500.505 331 517 c 0,32,33 391 513 391 513 416 461 c 0,34,35 416 416 416 416 405 396.5 c 0,36,37 393.995 376.989 393.995 376.989 377 341 c 0,38,39 356 312 356 312 344.5 274.5 c 0,40,41 332.999 236.998 332.999 236.998 331 232 c 0,42,43 314.682 193.354 314.682 193.354 314.591 158.394 c 0,44,45 314.576 152.647 314.576 152.647 315 147 c 0,46,47 315 96 315 96 334.5 40.5 c 0,48,49 354 -15 354 -15 400 -50 c 0,50,51 347 -50 347 -50 312 10.5 c 0,52,53 276.998 71.004 276.998 71.004 263 112 c 0,54,55 254 179 254 179 231 202 c 0,56,57 208.001 224.999 208.001 224.999 181 232 c 0,58,59 178.002 232 178.002 232 149.5 225.5 c 0,60,61 121.991 219.226 121.991 219.226 122 168 c 0,62,-1 135 143.5 l 0,63,64 148.001 119 148.001 119 188 110 c 0,65,66 149 96.0005 149 96.0005 123.5 105 c 0,67,68 98 114 98 114 89 118 c 0,69,70 64.9997 130 64.9997 130 54.5 156.5 c 0,71,72 44 183.001 44 183.001 44 198 c 0,73,74 49 267 49 267 102 320 c 0,75,76 117 329 117 329 126 354.5 c 0,77,78 135 380 135 380 141 401 c 0,79,80 145.001 416 145.001 416 156 493 c 0,81,82 166.999 570 166.999 570 162 588 c 0,83,84 166.001 613 166.001 613 138 628 c 0,85,86 103.999 631 103.999 631 110 585.5 c 0,87,88 116 540 116 540 128 528 c 0,89,90 95 528 95 528 74 563 c 0,91,92 54 587 54 587 56.5 611 c 0,93,94 59 635 59 635 66 659 c 0,95,96 81 701 81 701 109.5 737 c 0,97,98 138.001 773.002 138.001 773.002 158 812 c 0,99,-1 166 870.5 l 0,100,101 165.864 898.01 l 0,102,103 162.564 919.121 162.564 919.121 149 937 c 0,104,105 146 943 146 943 107 1000 c 0,106,107 69.0001 1055.99 69.0001 1055.99 68 1057 c 0,108,109 61.9965 1067.01 61.9965 1067.01 51.5 1114.5 c 0,110,111 45.1768 1143.11 45.1768 1143.11 45.2001 1170.08 c 0,112,113 45.2154 1187.89 45.2154 1187.89 48 1205 c 0,114,115 48 1230 48 1230 73 1261.5 c 0,116,117 97.1265 1291.9 97.1265 1291.9 130 1292 c 0,118,119 113.751 1265.6 113.751 1265.6 113.775 1238.05 c 0,120,121 113.786 1224.91 113.786 1224.91 117.5 1211.5 c 0,122,123 126.928 1177.48 126.928 1177.48 158.199 1177.4 c 0,124,125 165.072 1177.38 165.072 1177.38 173 1179 c 0,126,127 185.001 1181 185.001 1181 200.5 1192.5 c 0,128,129 215.999 1204.01 215.999 1204.01 229 1245 c 0,130,131 235.158 1271.18 235.158 1271.18 235.095 1298.23 c 0,132,133 235.076 1306.33 235.076 1306.33 234.5 1314.5 c 0,134,135 231.999 1350.02 231.999 1350.02 228 1386 c 0,136,137 221.477 1421.88 221.477 1421.88 182.376 1422.52 c 0,138,139 163 1421 l 0,140,141 133 1404.12 133 1404.12 132.5 1389 c 0,142,143 134.001 1375 134.001 1375 147 1342 c 0,144,145 95.9994 1385.01 95.9994 1385.01 93 1440 c 0,146,147 93.4391 1473.01 l 0,148,149 98.921 1513.54 98.921 1513.54 130 1541 c 0,150,151 171.776 1564.77 171.776 1564.77 203.429 1564.68 c 0,152,153 215.728 1564.64 215.728 1564.64 226.5 1561 c 0,154,155 264.999 1548 264.999 1548 316 1525 c 0,156,-1 389 1493 l 0,157,158 421.777 1484.32 421.777 1484.32 455.251 1484.36 c 0,159,160 491.223 1484.4 491.223 1484.4 528 1494.5 c 0,161,162 599.07 1514.02 599.07 1514.02 668 1528 c 0,163,164 710.819 1534.32 710.819 1534.32 749.674 1534.23 c 0,165,166 766.196 1534.19 766.196 1534.19 782 1533 c 0,167,168 835.112 1528.99 835.112 1528.99 895 1519 c 0,169,170 974.006 1481.99 974.006 1481.99 984.5 1468.5 c 0,171,-1 1013 1433 l 0,172,173 995 1439 995 1439 983.5 1448 c 0,174,175 972.008 1456.99 972.008 1456.99 946 1461 c 0,176,177 879.001 1461 879.001 1461 874.5 1427.5 c 0,178,179 869.999 1394 869.999 1394 863 1394 c 0,180,181 876.001 1349 876.001 1349 893.5 1334 c 0,182,183 911 1319 911 1319 965 1301 c 0,184,185 1077 1307 1077 1307 1088.5 1356 c 0,186,187 1100.02 1405.08 1100.02 1405.08 1131 1499 c 0,188,189 1130.03 1493.23 1130.03 1493.23 1118 1410.5 c 0,190,191 1106 1327.99 1106 1327.99 1090 1313 c 0,192,193 1070.01 1284.99 1070.01 1284.99 1034.5 1268 c 0,194,195 998.966 1250.99 998.966 1250.99 982 1249 c 0,196,197 975 1247.01 975 1247.01 938.5 1247.5 c 0,198,199 902 1247.99 902 1247.99 892 1258 c 0,200,201 868.998 1267 868.998 1267 850.5 1279 c 0,202,-1 813 1303 l 0,203,204 687 1373.99 687 1373.99 634 1370.5 c 0,205,206 581.013 1367.01 581.013 1367.01 458 1313 c 0,207,208 436.041 1297.63 436.041 1297.63 436.049 1278.77 c 0,209,210 436.052 1271.87 436.052 1271.87 439 1264.5 c 0,211,212 450.002 1237 450.002 1237 477 1237 c 0,213,214 498 1238.01 498 1238.01 523 1241.5 c 0,215,216 547.997 1244.99 547.997 1244.99 569 1290 c 0,217,218 566 1278 566 1278 566.5 1251 c 0,219,220 563.262 1227.75 l 0,221,222 558.754 1212.71 558.754 1212.71 548 1198 c 0,223,224 480.001 1158 480.001 1158 407.5 1138 c 0,225,226 335.001 1118.01 335.001 1118.01 320 1014 c 0,227,228 311 981 311 981 330 935 c 0,229,230 349.001 888.999 349.001 888.999 374 868 c 0,231,232 386 846 386 846 444 856.5 c 0,233,234 502 867 502 867 510 909 c 0,235,236 513 960 513 960 484 966.5 c 0,237,238 455 973 455 973 425 958 c 0,239,240 442 990 442 990 466 1003 c 0,241,242 489.104 1011.77 489.104 1011.77 507.76 1011.91 c 0,243,244 521.278 1012.01 521.278 1012.01 532.462 1007.57 c 0,245,246 558.618 997.189 558.618 997.189 572 962 c 0,247,248 576 932 576 932 578 895.5 c 0,249,250 579.994 859.099 579.994 859.099 582 828 c 1,0,1 EndSplineSet KernsSLIF: 116 -130 0 0 45 -156 0 0 46 -247 0 0 44 -260 0 0 97 -427 0 0 EndChar StartChar: g Encoding: 103 103 21 Width: 1125 Flags: HW Fore 531 22 m 0,0,1 468 28 468 28 371.5 79 c 0,2,3 275.001 130 275.001 130 247 174 c 0,4,5 152.809 313.125 152.809 313.125 152.707 448.145 c 0,6,7 152.69 469.373 152.69 469.373 155 490.5 c 0,8,9 158.749 561.265 l 0,10,11 158.332 681.08 158.332 681.08 112 800 c 0,12,13 92.9999 848 92.9999 848 67 898.5 c 0,14,15 41 949 41 949 44 979 c 0,16,17 48 1033 48 1033 82 1051 c 0,18,19 102.837 1062.03 102.837 1062.03 121.423 1062.17 c 0,20,21 133.16 1062.26 133.16 1062.26 144 1058 c 0,22,23 112.999 1059.99 112.999 1059.99 98 1019 c 0,24,25 94.0204 1008.12 94.0204 1008.12 94.0529 999.568 c 0,26,27 94.1429 975.877 94.1429 975.877 125 970 c 0,28,29 148.219 968.74 l 0,30,31 178.448 972.724 178.448 972.724 178.718 1012.41 c 0,32,33 174.332 1048.98 l 0,34,35 173.496 1052.89 173.496 1052.89 172.5 1057 c 0,36,37 148.001 1157.99 148.001 1157.99 147 1186 c 0,38,39 142.997 1257.03 142.997 1257.03 140 1300 c 0,40,41 142.052 1332.31 l 0,42,43 148.094 1367.54 148.094 1367.54 170 1416 c 0,44,45 186.001 1453.01 186.001 1453.01 237 1453.5 c 0,46,47 288 1453.99 288 1453.99 314 1443 c 0,48,49 270 1440 270 1440 253.5 1416 c 0,50,51 246.487 1405.8 246.487 1405.8 246.248 1397.05 c 0,52,53 249.324 1385.34 l 0,54,55 252.262 1380.37 252.262 1380.37 258 1376 c 0,56,57 303 1338.01 303 1338.01 359 1428.5 c 0,58,59 398.875 1492.94 398.875 1492.94 399.203 1530.76 c 0,60,61 399.299 1541.98 399.299 1541.98 395.92 1550.85 c 0,62,63 394.69 1554.08 394.69 1554.08 393 1557 c 0,64,65 377.944 1581.09 377.944 1581.09 349.102 1581.24 c 0,66,67 330.49 1581.34 330.49 1581.34 305 1571 c 0,68,69 281.994 1560.99 281.994 1560.99 269 1536 c 0,70,71 256.013 1511.02 256.013 1511.02 241 1487 c 0,72,73 239.456 1510.96 l 0,74,75 242.089 1543.47 242.089 1543.47 266.5 1593 c 0,76,77 300.997 1663 300.997 1663 358 1666 c 0,78,79 404.325 1669.02 404.325 1669.02 472 1674.5 c 0,80,81 540.002 1680.01 540.002 1680.01 578 1685 c 0,82,83 636.783 1688.22 l 0,84,85 712.691 1687.58 712.691 1687.58 807.5 1664.5 c 0,86,87 941 1631.99 941 1631.99 1025 1609 c 0,88,89 1068.99 1597 1068.99 1597 1067 1540 c 0,90,91 1065.01 1483.01 1065.01 1483.01 1027 1459 c 0,92,93 1030.32 1478.67 l 0,94,95 1029.52 1500.41 1029.52 1500.41 1008 1519.5 c 0,96,97 994.786 1531.22 994.786 1531.22 981.755 1531.41 c 0,98,99 966.92 1527.85 l 0,100,101 956.905 1522.89 956.905 1522.89 947 1511 c 0,102,103 935.923 1498.81 935.923 1498.81 935.889 1480.19 c 0,104,105 935.861 1465.19 935.861 1465.19 943 1446 c 0,106,107 959 1402.99 959 1402.99 968 1374 c 0,108,109 993.985 1296.05 993.985 1296.05 1012.5 1250.5 c 0,110,111 1019.83 1232.48 1019.83 1232.48 1019.86 1208.73 c 0,112,113 1019.91 1172.52 1019.91 1172.52 1003 1123 c 0,114,115 984.998 1068.99 984.998 1068.99 941 1023.5 c 0,116,117 897 978 897 978 799 957 c 0,118,119 836 986 836 986 890.5 1011.5 c 0,120,121 941.81 1035.51 941.81 1035.51 942.154 1105.16 c 0,122,123 942.176 1109.49 942.176 1109.49 942 1114 c 0,124,125 939.001 1147.99 939.001 1147.99 897 1188 c 0,126,127 868.002 1215.62 868.002 1215.62 839 1215.59 c 0,128,129 826 1215.57 826 1215.57 813 1210 c 0,130,131 770.269 1191.95 770.269 1191.95 769.918 1154.53 c 0,132,133 769.899 1152.54 769.899 1152.54 770 1150.5 c 0,134,135 772 1110 772 1110 787 1072 c 0,136,137 745.147 1100.77 745.147 1100.77 745.109 1156.53 c 0,138,139 745.103 1164.73 745.103 1164.73 746 1173.5 c 0,140,141 753 1242 753 1242 778 1269 c 0,142,143 790 1282.01 790 1282.01 801.5 1306.5 c 0,144,145 810.671 1326.03 810.671 1326.03 810.62 1339.53 c 0,146,147 810.608 1342.96 810.608 1342.96 810 1346 c 0,148,149 797.998 1382.01 797.998 1382.01 746 1412.5 c 0,150,151 694 1442.99 694 1442.99 649 1408 c 0,152,153 626 1390 626 1390 635 1348 c 0,154,155 644 1306 644 1306 645 1279 c 0,156,157 642.621 1251.41 l 0,158,159 630.999 1203.16 630.999 1203.16 565 1196 c 0,160,161 541.843 1195.8 l 0,162,163 505.619 1202.1 505.619 1202.1 494 1254 c 0,164,165 530 1237.99 530 1237.99 554 1254 c 0,166,167 568.571 1263.72 568.571 1263.72 568.767 1282.28 c 0,168,169 564.575 1305.54 l 0,170,171 563.85 1307.73 563.85 1307.73 563 1310 c 0,172,173 556.002 1327.99 556.002 1327.99 512.5 1338 c 0,174,175 492.91 1342.51 492.91 1342.51 477.678 1342.55 c 0,176,177 459.093 1342.6 459.093 1342.6 447 1336 c 0,178,179 390.999 1306 390.999 1306 374 1189.5 c 0,180,181 368.629 1152.69 368.629 1152.69 368.648 1121.92 c 0,182,183 368.69 1055.3 368.69 1055.3 394 1017 c 0,184,185 445 939 445 939 481 878.5 c 0,186,187 517 818 517 818 484 752 c 0,188,189 474 732 474 732 427 722 c 0,190,191 394.04 718.32 l 0,192,193 373.463 718.785 373.463 718.785 362 729 c 0,194,195 408 737 408 737 416 767 c 0,196,197 418.16 790.251 l 0,198,199 414.789 827.474 414.789 827.474 362 843 c 0,200,201 342 849 342 849 308 846.5 c 0,202,203 274.001 844 274.001 844 249 803 c 0,204,205 235.692 781.805 235.692 781.805 235.746 730.244 c 0,206,207 235.801 677.194 235.801 677.194 250 592 c 0,208,209 278 424 278 424 392 394 c 0,210,211 452 377 452 377 502 407.5 c 0,212,213 552.003 438.002 552.003 438.002 597 455 c 0,214,215 692 489 692 489 726 461 c 0,216,217 743.193 445.649 743.193 445.649 743.419 427.659 c 0,218,219 739.897 410.197 l 0,220,221 738.664 407.132 738.664 407.132 737 404 c 0,222,223 720 372 720 372 689 374 c 0,224,225 706.383 386.233 706.383 386.233 706.771 397.844 c 0,226,227 703.446 408.525 l 0,228,229 702 410.5 l 0,230,231 689.827 425.717 689.827 425.717 679 426 c 0,232,233 636 414 636 414 641.5 387.5 c 0,234,235 647 361 647 361 668 350 c 0,236,237 682.869 341.783 682.869 341.783 698.428 341.834 c 0,238,239 722.631 341.913 722.631 341.913 748.5 362 c 0,240,241 791.001 395.001 791.001 395.001 814 434 c 0,242,243 822.957 450.72 822.957 450.72 823 472.252 c 0,244,245 823.029 486.78 823.029 486.78 819 503.5 c 0,246,247 809 545 809 545 785 554 c 0,248,249 707 584 707 584 645.5 577 c 0,250,251 584 570 584 570 500 576 c 0,252,253 381.002 583.999 381.002 583.999 333 617.5 c 0,254,255 286.238 650.135 286.238 650.135 286 695 c 0,256,257 286 715 286 715 301.5 741.5 c 0,258,259 316.999 767.999 316.999 767.999 367 775 c 0,260,261 324 758 324 758 317.5 716 c 0,262,263 311 674 311 674 349 656 c 0,264,265 431 614 431 614 521.5 661 c 0,266,267 612 708 612 708 643 751 c 0,268,269 677 800 677 800 738 807 c 0,270,271 784.905 809.042 l 0,272,273 808.475 807.683 808.475 807.683 820 800 c 0,274,275 834.999 789.001 834.999 789.001 845 763 c 0,276,277 848.309 744.846 l 0,278,279 847.766 729.405 847.766 729.405 835 716 c 0,280,281 835 760 835 760 795.5 755 c 0,282,283 756 750 756 750 755 735 c 0,284,285 756.786 713.323 l 0,286,287 762.156 693.016 762.156 693.016 781.5 674 c 0,288,289 811 645 811 645 871 648 c 0,290,291 910.248 645.529 l 0,292,293 947.216 639.656 947.216 639.656 986.5 620.5 c 0,294,295 1047.01 590.994 1047.01 590.994 1052 558 c 0,296,297 1062.99 471 1062.99 471 1001 471 c 0,298,299 1019 489 1019 489 1008.5 504 c 0,300,301 998 519 998 519 980 512 c 0,302,303 956 500 956 500 964.5 472.5 c 0,304,305 973 445 973 445 979 421 c 0,306,307 1007 296 1007 296 995 216.5 c 0,308,309 983 137 983 137 959 119 c 0,310,311 926 92 926 92 878 77.5 c 0,312,313 830 62.9999 830 62.9999 772 97 c 0,314,315 752.299 108.492 752.299 108.492 752.139 146.266 c 0,316,317 752.105 154.507 752.105 154.507 753 164 c 0,318,319 757.001 139.999 757.001 139.999 788 135 c 0,320,321 803.325 136.102 l 0,322,323 822.734 142.8 822.734 142.8 833 178 c 0,324,325 833.161 192.353 l 0,326,327 828.613 207.514 828.613 207.514 801.5 213.5 c 0,328,329 763 222.001 763 222.001 712 219.5 c 0,330,331 660.992 216.999 660.992 216.999 615.5 208.5 c 0,332,333 569.999 199.999 569.999 199.999 564 194 c 0,334,335 540 166.999 540 166.999 539.5 154 c 0,336,337 545.209 121.479 l 0,338,339 547.604 112.321 547.604 112.321 551 101 c 0,340,341 563 56 563 56 616.5 56.5 c 0,342,343 670 57 670 57 706 87 c 0,344,345 679 21 679 21 608.5 21 c 0,346,347 538 21 538 21 531 22 c 0,0,1 EndSplineSet EndChar StartChar: h Encoding: 104 104 22 Width: 1191 Flags: HMW HStem: 703 272.5<432 788> VStem: 135 206<140 1374> 826 179<65 1404> Fore 127 803.5 m 128,-1,0 68.0001 857 68.0001 857 53 931 c 0,1,2 49.5493 964.928 l 0,3,4 50.165 1001.61 50.165 1001.61 70.5 1034 c 0,5,6 98.0227 1077.85 98.0227 1077.85 139.03 1078.18 c 0,7,8 141.981 1078.2 141.981 1078.2 145 1078 c 0,9,10 181 1075 181 1075 181 1040 c 0,11,12 169.272 1049.99 169.272 1049.99 158.394 1049.98 c 0,13,14 144.227 1049.97 144.227 1049.97 131.5 1033 c 0,15,16 109 1003 109 1003 130 971 c 0,17,18 136.001 959.999 136.001 959.999 173.5 956.5 c 0,19,20 189.848 958.247 l 0,21,22 212.456 966.35 212.456 966.35 217 1008 c 0,23,24 225.997 1101.98 225.997 1101.98 239.5 1188.5 c 0,25,26 244.674 1221.65 244.674 1221.65 244.634 1246.07 c 0,27,28 244.568 1285.35 244.568 1285.35 231 1302 c 0,29,30 225.057 1308.34 225.057 1308.34 215.502 1308.4 c 0,31,32 200.945 1308.49 200.945 1308.49 178 1294 c 0,33,34 157.734 1281.2 157.734 1281.2 157.662 1260.72 c 0,35,36 157.6 1242.8 157.6 1242.8 173 1219 c 0,37,38 130.636 1246.72 130.636 1246.72 130.124 1278.13 c 0,39,40 133.771 1297.81 l 0,41,42 141.244 1317.48 141.244 1317.48 164 1338.5 c 0,43,44 235.991 1404.99 235.991 1404.99 264 1467 c 0,45,46 292.005 1530.01 292.005 1530.01 337.5 1584.5 c 0,47,48 378.252 1633.31 378.252 1633.31 445.867 1633.59 c 0,49,50 453.751 1633.63 453.751 1633.63 462 1633 c 0,51,52 492.977 1622.01 492.977 1622.01 512.5 1606.5 c 0,53,54 532 1591.01 532 1591.01 544 1548 c 0,55,56 540.999 1565 540.999 1565 476 1596.5 c 0,57,58 461.045 1603.75 461.045 1603.75 446.989 1603.66 c 0,59,60 399.957 1603.38 399.957 1603.38 363 1521 c 0,61,62 335 1458 335 1458 341 1374 c 0,63,64 345.999 1298.01 345.999 1298.01 401 1223.5 c 0,65,66 456 1148.99 456 1148.99 438 1078 c 0,67,68 432 1055.01 432 1055.01 392 1046.5 c 0,69,70 356.819 1042.14 l 0,71,72 345.962 1042.39 345.962 1042.39 341 1046 c 0,73,74 372 1050.01 372 1050.01 383 1068.5 c 0,75,76 394 1087 394 1087 394 1089 c 0,77,78 391.033 1111.52 l 0,79,80 384.862 1131.96 384.862 1131.96 366 1150.5 c 0,81,82 337 1179 337 1179 319 1143 c 0,83,84 308 1120 308 1120 306 1063 c 0,85,86 304 1007.01 304 1007.01 304 1006 c 0,87,88 311.001 954.998 311.001 954.998 331.5 922 c 0,89,90 352 889 352 889 355 888 c 0,91,92 376 870 376 870 401 872 c 0,93,94 426 874 426 874 438 880 c 0,95,96 530 922 530 922 561.5 962 c 0,97,98 593 1002 593 1002 665 995 c 0,99,100 690 984 690 984 702.5 966.5 c 0,101,102 709.4 956.839 709.4 956.839 709.444 938.8 c 0,103,104 709.48 924.16 709.48 924.16 705 904 c 0,105,106 693 873 693 873 662 868 c 0,107,108 677 883 677 883 670 902.5 c 0,109,110 663 922 663 922 642 907 c 0,111,112 616.157 887.496 616.157 887.496 616.111 872.628 c 0,113,114 616.062 857.004 616.062 857.004 644.5 846.5 c 0,115,116 700 826 700 826 736 829 c 0,117,118 749 829 749 829 796 843 c 0,119,120 828.07 852.553 828.07 852.553 828.48 888.646 c 0,121,122 824.428 919.069 l 0,123,124 823.356 923.414 823.356 923.414 822 928 c 0,125,126 813 955 813 955 788 975.5 c 0,127,128 763 996 763 996 760 1030 c 0,129,130 761.054 1063.96 l 0,131,132 765.883 1095.56 765.883 1095.56 786 1115 c 0,133,134 801 1130 801 1130 836 1139 c 0,135,136 856.93 1140.92 l 0,137,138 879.097 1138.97 879.097 1138.97 897 1119 c 0,139,140 870.531 1116.71 l 0,141,142 834.782 1108.19 834.782 1108.19 828 1069 c 0,143,144 819 1016.99 819 1016.99 886 1003 c 0,145,146 901.604 1002.82 l 0,147,148 929.362 1010.06 929.362 1010.06 938.5 1076 c 0,149,150 947.659 1142.1 947.659 1142.1 947.621 1174.59 c 0,151,152 947.611 1182.89 947.611 1182.89 947 1189 c 0,153,154 941 1229.01 941 1229.01 888.5 1304.5 c 0,155,156 836.007 1379.99 836.007 1379.99 826 1404 c 0,157,158 814 1428 814 1428 803.5 1483.5 c 0,159,160 801.65 1512.46 l 0,161,162 804.299 1550.56 804.299 1550.56 835 1582 c 0,163,164 857.909 1604.91 857.909 1604.91 909.781 1604.88 c 0,165,166 928.085 1604.87 928.085 1604.87 950 1602 c 0,167,168 1004 1593 1004 1593 1051 1552 c 0,169,170 1042.01 1552 1042.01 1552 1017 1564 c 0,171,172 991.995 1576 991.995 1576 974 1576 c 0,173,174 922.993 1576 922.993 1576 888.5 1552.5 c 0,175,176 854 1528.99 854 1528.99 866 1488 c 0,177,178 895.617 1379.71 895.617 1379.71 952.652 1379.79 c 0,179,180 957.237 1379.79 957.237 1379.79 962 1380.5 c 0,181,182 1026 1389.99 1026 1389.99 1031 1408 c 0,183,184 1035.9 1426.38 1035.9 1426.38 1035.96 1441.59 c 0,185,186 1036.05 1463.62 1036.05 1463.62 1026 1479 c 0,187,188 1008.99 1505.02 1008.99 1505.02 988 1531 c 0,189,190 1019.01 1531 1019.01 1531 1055.5 1484.5 c 0,191,192 1092 1437.99 1092 1437.99 1092 1410 c 0,193,194 1092 1347.98 1092 1347.98 1079 1275 c 0,195,196 1075.15 1253.41 1075.15 1253.41 1075.25 1228.33 c 0,197,198 1075.46 1168.59 1075.46 1168.59 1098 1089 c 0,199,-1 1121 1002 l 0,200,201 1132 959.981 1132 959.981 1132 918 c 0,202,203 1132 897.007 1132 897.007 1110.5 867 c 0,204,205 1089.01 837 1089.01 837 1041 834 c 0,206,207 1041 835.996 1041 835.996 1070 858 c 0,208,209 1089.94 873.128 1089.94 873.128 1090.02 897.703 c 0,210,211 1090.06 908.876 1090.06 908.876 1086 922 c 0,212,213 1080.13 929.035 1080.13 929.035 1071.18 929.025 c 0,214,215 1064.86 929.017 1064.86 929.017 1057 925.5 c 0,216,217 1037.99 917 1037.99 917 1027 896 c 0,218,219 1017 877.014 1017 877.014 1008 827 c 0,220,221 999 777 999 777 1002 750 c 0,222,223 1008 693 1008 693 1029 649 c 0,224,225 1049.99 605.018 1049.99 605.018 1057 568 c 0,226,227 1065.62 522.606 1065.62 522.606 1065.65 492.89 c 0,228,229 1065.68 470.899 1065.68 470.899 1061 457.5 c 0,230,231 1050.01 426 1050.01 426 1037 410 c 0,232,233 1026.99 403.997 1026.99 403.997 1003.5 399.5 c 0,234,235 980 395 980 395 956 412 c 0,236,237 996 414 996 414 1007 431 c 0,238,-1 1013.5 458.5 l 0,239,240 1019.99 486 1019.99 486 976 492 c 0,241,242 958 493 958 493 938 468 c 0,243,244 918 443 918 443 924 368 c 0,245,246 930 275 930 275 958.5 213.5 c 0,247,248 987 152 987 152 1005 65 c 0,249,250 1015.71 15.0325 1015.71 15.0325 1015.71 -24.0976 c 0,251,252 1015.72 -116.534 1015.72 -116.534 956 -148.5 c 0,253,254 871.999 -194 871.999 -194 871 -194 c 0,255,256 807.664 -196.104 l 0,257,258 805.354 -196.059 805.354 -196.059 803 -196 c 0,259,260 762.999 -194.999 762.999 -194.999 733 -171 c 0,261,262 769.5 -185 769.5 -185 803 -185 c 0,263,264 836.5 -185 836.5 -185 867 -171 c 0,265,266 916 -147 916 -147 946.5 -108 c 0,267,268 977 -69 977 -69 938 -15 c 0,269,270 880 65 880 65 804.5 82 c 0,271,272 729 98.9999 729 98.9999 711 115 c 0,273,274 659.39 157.887 659.39 157.887 659.297 204.209 c 0,275,276 659.263 221.612 659.263 221.612 666.5 239.5 c 0,277,278 692.165 302.937 692.165 302.937 729 303 c 0,279,280 755 301 755 301 782 267 c 0,281,282 765.311 274.586 765.311 274.586 752.937 274.547 c 0,283,284 732.689 274.483 732.689 274.483 724 254 c 0,285,286 717.578 239.322 717.578 239.322 717.375 227.964 c 0,287,288 720.614 212.702 l 0,289,290 727.42 199.291 727.42 199.291 748.5 193.5 c 0,291,292 777.978 188.543 l 0,293,294 794 188.725 794 188.725 794 200 c 0,295,296 804.307 216.492 804.307 216.492 804.227 252.578 c 0,297,298 804.19 269.008 804.19 269.008 802 289.5 c 0,299,300 795 355 795 355 790 384 c 0,301,302 743 459 743 459 706 463 c 0,303,304 669 467 669 467 646 494 c 0,305,306 608 533 608 533 605 558 c 0,307,308 605.804 586.508 l 0,309,310 607.893 599.607 607.893 599.607 613 614 c 0,311,312 633 671 633 671 688 646 c 0,313,314 671 636.999 671 636.999 664.5 615.5 c 0,315,316 658 594 658 594 687 597 c 0,317,318 715 600 715 600 738 611.5 c 0,319,320 755.674 620.337 755.674 620.337 755.633 643.64 c 0,321,322 755.621 650.663 755.621 650.663 754 659 c 0,323,324 738 743 738 743 618 748.5 c 0,325,326 536.449 748.89 l 0,327,328 483.089 746.152 483.089 746.152 460 734 c 0,329,330 445 715 445 715 432 703 c 0,331,332 419 691 419 691 438 619 c 0,333,334 443 598 443 598 450 559 c 0,335,336 450.723 535.595 l 0,337,338 447.5 513.776 447.5 513.776 428 501 c 0,339,340 405.482 487.63 405.482 487.63 374.545 487.63 c 0,341,342 361.519 487.63 361.519 487.63 347 490 c 0,343,344 377 495 377 495 395.5 526.5 c 0,345,346 414 558 414 558 369 566 c 0,347,348 349 569 349 569 332.5 547 c 0,349,350 316 525 316 525 316 498 c 0,351,352 313 405 313 405 348 338.5 c 0,353,354 383 272 383 272 375 218 c 0,355,356 369 179 369 179 356 170 c 0,357,358 343 161.001 343 161.001 316 154 c 0,359,360 321.999 174.997 321.999 174.997 328.5 188 c 0,361,362 335 201.001 335 201.001 317 218 c 0,363,364 311.667 222.445 311.667 222.445 302.185 222.543 c 0,365,366 277.896 218.022 l 0,367,368 275.037 217.104 275.037 217.104 272 216 c 0,369,370 233.492 201.671 233.492 201.671 233.078 159.275 c 0,371,372 233.03 154.328 233.03 154.328 233.5 149 c 0,373,374 238 98 238 98 256 85 c 0,375,376 275.001 69.9993 275.001 69.9993 307.5 58 c 0,377,378 318.436 53.9621 318.436 53.9621 333.958 54.0004 c 0,379,380 364.564 54.0758 364.564 54.0758 413 70 c 0,381,-1 455 97 l 0,382,383 497 124 497 124 536 214 c 0,384,385 507.999 117.999 507.999 117.999 450 58 c 0,386,387 431 37 431 37 345.5 14 c 0,388,389 260 -8.99999 260 -8.99999 185 48 c 0,390,391 136.001 84.9993 136.001 84.9993 135 140 c 0,392,393 136 210 l 0,394,395 139 246.001 139 246.001 179 333 c 0,396,397 219 419.999 219 419.999 219 429 c 0,398,399 219 448.008 219 448.008 224.5 542 c 0,400,401 225.127 611.157 l 0,402,403 222.808 651.23 222.808 651.23 213 672 c 0,404,405 186 749.999 186 749.999 127 803.5 c 128,-1,0 EndSplineSet KernsSLIF: 97 -104 0 0 EndChar StartChar: i Encoding: 105 105 52 Width: 526 Flags: HMW VStem: 191.5 208.5<315 1320> Fore 205 552 m 0,0,1 199 642 199 642 115 721.5 c 0,2,3 31 801 31 801 50 897 c 0,4,5 62 963 62 963 107.5 979 c 0,6,7 126.311 982.037 l 0,8,9 158.637 980.476 158.637 980.476 179 928 c 0,10,-1 170 941 l 0,11,12 150.714 957.786 150.714 957.786 136.276 958.117 c 0,13,14 124.188 955.041 l 0,15,16 107.697 945.447 107.697 945.447 100 906 c 0,17,18 83.9999 824 83.9999 824 177 839 c 0,19,20 211.046 843.346 211.046 843.346 211.247 915.645 c 0,21,22 211.323 943.154 211.323 943.154 206.5 980.5 c 0,23,24 188.999 1116 188.999 1116 169 1146 c 0,25,26 113.997 1227 113.997 1227 78.5 1264.5 c 0,27,28 43 1302 43 1302 52 1362 c 0,29,30 65.9993 1475.99 65.9993 1475.99 194 1510 c 0,31,32 131 1477 131 1477 115 1421.5 c 0,33,34 105.515 1388.6 105.515 1388.6 105.519 1365.36 c 0,35,36 105.521 1349.4 105.521 1349.4 110 1338 c 0,37,38 126.105 1312.23 126.105 1312.23 155.28 1312.19 c 0,39,40 171.396 1312.17 171.396 1312.17 191.5 1320 c 0,41,42 248.008 1342.01 248.008 1342.01 260 1354 c 0,43,44 351 1459 351 1459 318.5 1576 c 0,45,46 285.999 1693 285.999 1693 138 1732 c 0,47,48 229.001 1732 229.001 1732 307.5 1652.5 c 0,49,50 386 1573 386 1573 395 1486 c 0,51,52 399.999 1414.01 399.999 1414.01 419.5 1348.5 c 0,53,54 439.003 1282.98 439.003 1282.98 454 1208 c 0,55,56 460.003 1169.99 460.003 1169.99 470.5 1139.5 c 0,57,58 480.116 1111.57 480.116 1111.57 480 1092 c 0,59,60 472 1015 472 1015 391 1015 c 0,61,62 426 1042 426 1042 434 1089 c 0,63,64 433.926 1106.55 l 0,65,66 427.642 1134.17 427.642 1134.17 377.246 1134.08 c 0,67,68 374.678 1134.08 374.678 1134.08 372 1134 c 0,69,70 313 1138.99 313 1138.99 322.5 1005 c 0,71,72 331.999 871.009 331.999 871.009 335 845 c 0,73,74 340 786 340 786 385 790.5 c 0,75,76 430 795 430 795 409 870 c 0,77,78 403 889 403 889 371 925 c 0,79,80 383 918 383 918 396 908.5 c 0,81,82 409 899 409 899 430 872 c 0,83,84 502 780 502 780 421 671 c 0,85,86 340 562 340 562 349 454 c 0,87,88 355 373 355 373 400 315 c 0,89,90 445 257 445 257 448 179 c 0,91,92 450 117.999 450 117.999 396 98 c 0,93,94 342 78.0001 342 78.0001 290 81 c 0,95,96 354.192 91.6986 354.192 91.6986 354.5 154 c 0,97,98 353 216 353 216 282 222 c 0,99,100 255.63 220.575 l 0,101,102 205.536 210.268 205.536 210.268 205.16 138.129 c 0,103,104 205.095 125.728 205.095 125.728 206.5 111.5 c 0,105,106 218.001 -5.00005 218.001 -5.00005 247 -50 c 0,107,108 286 -113 286 -113 340.5 -144.5 c 0,109,110 395.002 -176.002 395.002 -176.002 422 -201 c 0,111,112 371.997 -183.999 371.997 -183.999 343 -169.5 c 0,113,114 313.991 -154.995 313.991 -154.995 275 -130 c 0,115,116 275 -129 275 -129 243 -97.5 c 0,117,118 210.998 -65.998 210.998 -65.998 194 -32 c 0,119,120 157 40.9986 157 40.9986 145 119 c 0,121,122 142.267 162.201 l 0,123,124 143.819 218.362 143.819 218.362 172 274 c 0,125,126 202.001 337.001 202.001 337.001 205.5 410.5 c 0,127,128 206.608 515.08 l 0,129,130 206.074 533.739 206.074 533.739 205 552 c 0,0,1 EndSplineSet EndChar StartChar: j Encoding: 106 106 64 Width: 1080 Flags: MW HStem: -47.5 237.5<360.5 947> 1275.5 183.5<208 649> VStem: 252 108.5<-47.5 596> 669 237.5<211 1492.5> Fore 255 -50 m 0,0,1 219 -44 219 -44 180 -8 c 0,2,3 140.999 28.0006 140.999 28.0006 130 92 c 0,4,5 161.001 39 161.001 39 184 36 c 0,6,7 226 27 226 27 244 53 c 0,8,9 262 78.9999 262 78.9999 262 117 c 0,10,11 262 170.001 262 170.001 215.5 215.5 c 0,12,13 195.259 235.306 195.259 235.306 184.586 235.69 c 0,14,15 177.625 232.939 l 0,16,17 172.716 227.713 172.716 227.713 172.683 212.589 c 0,18,19 172.675 208.633 172.675 208.633 173 204 c 0,20,21 175.94 158.921 175.94 158.921 220 154 c 0,22,23 205.32 137.485 205.32 137.485 189.331 137.245 c 0,24,25 173.596 140.802 l 0,26,27 171.063 141.962 171.063 141.962 168.5 143.5 c 0,28,29 141 160 141 160 132 177 c 0,30,31 116.083 207.737 116.083 207.737 116.132 244.8 c 0,32,33 116.173 275.264 116.173 275.264 127 310 c 0,34,35 149.002 388.004 149.002 388.004 183 459.5 c 0,36,37 217.001 531 217.001 531 252 596 c 0,38,39 300 686 300 686 385 763.5 c 0,40,41 470 841 470 841 572 865 c 0,42,43 452 817 452 817 372 659 c 0,44,45 292 501 292 501 319 377 c 0,46,47 327 335 327 335 358 309.5 c 0,48,49 389 284 389 284 418 317 c 0,50,51 439 340 439 340 437 371.5 c 0,52,53 435 403 435 403 428 421 c 0,54,55 415 445 415 445 383 459 c 0,56,57 427 468 427 468 457 437.5 c 0,58,59 487 407 487 407 493 379 c 0,60,61 493.982 342.219 l 0,62,63 493.618 336.582 493.618 336.582 493 330.5 c 0,64,65 490 301 490 301 490 290 c 0,66,67 485 218 485 218 501.5 197 c 0,68,69 518 176 518 176 550 167 c 0,70,71 568.655 161.454 568.655 161.454 585.468 161.5 c 0,72,73 635.344 161.638 635.344 161.638 669 211 c 0,74,75 699 253 699 253 713.5 309.5 c 0,76,77 727.999 365.993 727.999 365.993 735 420 c 0,78,79 737.068 472.341 l 0,80,81 737.037 473.416 737.037 473.416 737 474.5 c 0,82,83 736 504 736 504 706 504 c 0,84,85 677 504 677 504 676 481 c 0,86,87 678.327 455.139 l 0,88,89 680.053 448.527 680.053 448.527 683 443 c 0,90,91 665 443 665 443 646 455 c 0,92,93 627 466.999 627 466.999 626 516 c 0,94,95 625 546 625 546 644 570.5 c 0,96,97 662.998 594.996 662.998 594.996 676 623 c 0,98,99 709.998 696.995 709.998 696.995 715.5 722.5 c 0,100,101 721 748 721 748 717 807 c 0,102,103 712 871 712 871 633 960 c 0,104,105 593.041 1005.01 593.041 1005.01 592.994 1048.5 c 0,106,107 592.948 1090.98 592.948 1090.98 631 1132 c 0,108,109 641.561 1144.18 641.561 1144.18 666.649 1144.16 c 0,110,111 672.436 1144.16 672.436 1144.16 679 1143.5 c 0,112,113 714 1140.01 714 1140.01 722 1098 c 0,114,115 704 1108.99 704 1108.99 683 1104 c 0,116,117 662 1099.01 662 1099.01 662 1084 c 0,118,119 662 1042.15 662 1042.15 683.378 1041.11 c 0,120,121 695 1043 l 0,122,123 727.992 1053.99 727.992 1053.99 746 1072 c 0,124,125 770 1094.01 770 1094.01 774 1189 c 0,126,127 773.549 1259.71 l 0,128,129 770.677 1299.08 770.677 1299.08 761 1319 c 0,130,131 752.033 1336.18 752.033 1336.18 732.184 1336.34 c 0,132,133 725.465 1336.4 725.465 1336.4 717.5 1334.5 c 0,134,135 686 1327 686 1327 685 1312 c 0,136,137 686.41 1290.57 l 0,138,139 690.959 1275 690.959 1275 707.5 1275 c 0,140,141 733 1275 733 1275 744 1284 c 0,142,143 742.032 1266.13 l 0,144,145 737.373 1252.41 737.373 1252.41 722.5 1244.5 c 0,146,147 704.631 1235 704.631 1235 692.267 1235.03 c 0,148,149 688.359 1235.04 688.359 1235.04 685 1236 c 0,150,151 637 1246.01 637 1246.01 605.5 1276.5 c 0,152,153 573.985 1307.01 573.985 1307.01 541 1328 c 0,154,155 501.957 1352.08 501.957 1352.08 460.364 1352.02 c 0,156,157 438.049 1351.98 438.049 1351.98 415 1345 c 0,158,159 349.045 1325.02 349.045 1325.02 313 1310 c 0,160,161 268 1290.99 268 1290.99 208 1275.5 c 0,162,163 154.836 1261.77 154.836 1261.77 133.861 1261.77 c 0,164,165 131.164 1261.77 131.164 1261.77 129 1262 c 0,166,167 44.9994 1268 44.9994 1268 35.5 1354.5 c 0,168,169 35.3657 1387.6 l 0,170,171 42.3818 1445.56 42.3818 1445.56 105 1463 c 0,172,173 85.0001 1448 85.0001 1448 66.5 1410.5 c 0,174,175 48 1373 48 1373 83 1337 c 0,176,177 101.794 1316.6 101.794 1316.6 129.668 1316.66 c 0,178,179 153.708 1316.72 153.708 1316.72 184.5 1332 c 0,180,181 250.996 1365 250.996 1365 271 1397 c 0,182,183 317 1470.99 317 1470.99 305.5 1493 c 0,184,185 296.454 1510.31 296.454 1510.31 278.433 1510.29 c 0,186,187 273.547 1510.28 273.547 1510.28 268 1509 c 0,188,189 262.002 1507.01 262.002 1507.01 259 1493 c 0,190,191 259.794 1481.77 l 0,192,193 262.522 1475.09 262.522 1475.09 271 1470 c 0,194,195 256.877 1463.14 256.877 1463.14 244.871 1463.2 c 0,196,197 227.122 1463.29 227.122 1463.29 214 1478.5 c 0,198,199 198.496 1496.47 198.496 1496.47 198.388 1526.11 c 0,200,201 198.342 1538.53 198.342 1538.53 201 1553 c 0,202,203 207.001 1586.01 207.001 1586.01 242 1595.5 c 0,204,205 266.917 1602.26 266.917 1602.26 282.695 1602.19 c 0,206,207 289.097 1602.16 289.097 1602.16 294 1601 c 0,208,209 387 1574 387 1574 463.5 1518.5 c 0,210,211 539.993 1463.01 539.993 1463.01 649 1459 c 0,212,213 689 1457.01 689 1457.01 755 1462 c 0,214,215 821 1466.99 821 1466.99 821 1518 c 0,216,217 821 1536 821 1536 791.5 1551 c 0,218,219 770.962 1561.44 770.962 1561.44 759.876 1561.71 c 0,220,221 752 1560 l 0,222,223 728.999 1546.99 728.999 1546.99 728.5 1532 c 0,224,225 730 1495 l 0,226,227 707.38 1502.02 707.38 1502.02 706.967 1528.51 c 0,228,229 708.5 1545 l 0,230,231 716 1585.99 716 1585.99 742 1599 c 0,232,233 772 1614 772 1614 815 1606.5 c 0,234,235 858 1599 858 1599 872 1578 c 0,236,237 903 1528.99 903 1528.99 906.5 1492.5 c 0,238,239 910 1456 910 1456 910 1399 c 0,240,-1 898.5 1243 l 0,241,242 896.911 1175.05 l 0,243,244 898.939 1126.57 898.939 1126.57 912 1098 c 0,245,246 927.997 1059.01 927.997 1059.01 948.5 1028 c 0,247,248 969.009 996.982 969.009 996.982 985 968 c 0,249,250 1005.99 929.012 1005.99 929.012 1017.5 836.5 c 0,251,252 1020.61 785.11 l 0,253,254 1019.37 739.187 1019.37 739.187 999 729 c 0,255,256 996.499 765.333 l 0,257,258 990.165 800.003 990.165 800.003 968.5 828 c 0,259,260 952.652 848.479 952.652 848.479 937.876 848.987 c 0,261,262 925.717 845.927 l 0,263,264 916.644 840.966 916.644 840.966 908 828 c 0,265,266 890 801 890 801 874 737 c 0,267,268 869.307 718.227 869.307 718.227 869.26 704.013 c 0,269,270 869.16 673.848 869.16 673.848 889.99 664.225 c 0,271,272 892.805 662.925 892.805 662.925 896 662 c 0,273,274 915.755 658.584 l 0,275,276 933.115 659.596 933.115 659.596 937.5 679.5 c 0,277,278 938.669 701.65 l 0,279,280 936.562 720.529 936.562 720.529 924 740 c 0,281,282 950 740 950 740 966 706 c 0,283,284 998 636 998 636 940.5 543 c 0,285,286 883 450 883 450 858 387 c 0,287,288 843 349.999 843 349.999 838.5 301 c 0,289,290 834 252 834 252 834 216 c 0,291,292 834 203.999 834 203.999 842.5 187 c 0,293,294 847.793 176.415 847.793 176.415 856.768 175.91 c 0,295,296 869 179 l 0,297,298 896.475 191.623 896.475 191.623 896.655 213.346 c 0,299,300 896.718 220.876 896.718 220.876 893.5 229.5 c 0,301,302 881 262.999 881 262.999 863 279 c 0,303,304 874.769 279.858 l 0,305,306 891.15 276.301 891.15 276.301 914.5 249 c 0,307,308 947 211.001 947 211.001 947 190 c 0,309,310 947 156.003 947 156.003 936 104 c 0,311,312 925 51.9999 925 51.9999 886 41 c 0,313,314 856.875 32.6783 856.875 32.6783 826.709 32.6667 c 0,315,316 820.626 32.6643 820.626 32.6643 814.5 33 c 0,317,318 778 35 778 35 742 34 c 0,319,320 670 25 670 25 596.5 17.5 c 0,321,322 523 10 523 10 459 -15 c 0,323,324 406.003 -35.9992 406.003 -35.9992 360.5 -47.5 c 0,325,326 315 -59 315 -59 255 -50 c 0,0,1 EndSplineSet EndChar StartChar: k Encoding: 107 107 23 Width: 1113 Flags: HMW VStem: 40.7998 249.9<-11.0498 1388.9> Fore 542.3 268.6 m 0,0,1 502.35 267.749 502.35 267.749 527 232.9 c 0,2,3 547.932 203.306 547.932 203.306 581.122 203.133 c 0,4,5 587.018 203.102 587.018 203.102 593.3 204 c 0,6,7 577.164 190.016 577.164 190.016 552.009 189.986 c 0,8,9 537.411 189.968 537.411 189.968 519.775 194.65 c 0,10,11 471.751 207.4 471.751 207.4 455.6 235.45 c 0,12,13 425.85 283.901 425.85 283.901 408 377.4 c 0,14,15 390.15 470.899 390.15 470.899 319.6 499.8 c 0,16,17 306.85 504.9 306.85 504.9 279.225 497.675 c 0,18,19 251.601 490.45 251.601 490.45 243.1 468.35 c 0,20,21 238.176 456.204 238.176 456.204 238.133 444.692 c 0,22,23 238.064 426.395 238.064 426.395 250.325 409.7 c 0,24,-1 290.7 352.75 l 0,25,26 313.651 314.499 313.651 314.499 317.9 257.55 c 0,27,28 316.954 221.448 l 0,29,30 312.315 189.03 312.315 189.03 293.25 166.6 c 0,31,32 292.4 170.001 292.4 170.001 290.7 208.675 c 0,33,34 289.493 236.149 289.493 236.149 266.675 236.651 c 0,35,36 244.032 232.428 l 0,37,38 242.322 231.853 242.322 231.853 240.55 231.2 c 0,39,40 224.401 225.25 224.401 225.25 217.175 140.675 c 0,41,42 209.949 56.0996 209.949 56.0996 246.5 56.0996 c 0,43,44 274.994 56.0996 274.994 56.0996 275.542 70.5434 c 0,45,46 275.632 72.904 275.632 72.904 274.975 75.6504 c 0,47,48 270.299 95.2002 270.299 95.2002 258.4 107.95 c 0,49,50 306.849 92.6506 306.849 92.6506 311.525 53.5498 c 0,51,52 316.201 14.4502 316.201 14.4502 290.7 -11.0498 c 0,53,54 245.652 -54.3987 245.652 -54.3987 189.125 -88.4004 c 0,55,56 132.6 -122.4 132.6 -122.4 132.6 -188.7 c 0,57,58 132.6 -251.601 132.6 -251.601 195.925 -280.075 c 0,59,60 255.893 -307.04 255.893 -307.04 337.584 -306.945 c 0,61,62 342.157 -306.94 342.157 -306.94 346.8 -306.85 c 0,63,64 196.35 -334.9 196.35 -334.9 143.225 -278.8 c 0,65,66 91.7255 -224.418 91.7255 -224.418 83.2998 -153.85 c 0,67,68 82.957 -117.949 l 0,69,70 86.8762 -78.2765 86.8762 -78.2765 109.65 -37.4004 c 0,71,72 142.799 22.0987 142.799 22.0987 143.65 80.75 c 0,73,74 143.65 133.451 143.65 133.451 122.4 168.3 c 0,75,76 106.25 195.499 106.25 195.499 79.9004 167.45 c 0,77,78 53.5498 139.4 53.5498 139.4 95.2002 96.0498 c 0,79,80 62.0497 86.7002 62.0497 86.7002 40.375 112.2 c 0,81,82 33.1445 120.707 33.1445 120.707 17.8496 153 c 0,83,84 3.40722 183.493 3.40722 183.493 29.75 240.975 c 0,85,86 46.5068 277.54 46.5068 277.54 65.4502 323.85 c 0,87,88 92.9434 391.062 92.9434 391.062 94.7754 417.775 c 0,89,90 101.251 512.209 101.251 512.209 102.85 514.25 c 0,91,92 104.836 522.868 l 0,93,94 104.373 534.203 104.373 534.203 97.3252 559.725 c 0,95,96 79.4824 621.977 79.4824 621.977 40.7998 680 c 0,97,98 30.5996 695.3 30.5996 695.3 27.2002 736.95 c 0,99,100 23.7999 778.6 23.7999 778.6 56.9502 800.7 c 0,101,102 49.8754 783.221 49.8754 783.221 49.8519 771.778 c 0,103,104 49.8182 755.43 49.8182 755.43 64.1748 751.4 c 0,105,106 90.0996 744.6 90.0996 744.6 110.5 785.4 c 0,107,108 131.413 825.057 131.413 825.057 131.609 850.216 c 0,109,110 131.634 853.413 131.634 853.413 131.325 856.375 c 0,111,112 124.084 909.899 124.084 909.899 107.95 912.9 c 0,113,114 74.7999 918.85 74.7999 918.85 77.3496 894.625 c 0,115,116 79.9004 870.4 79.9004 870.4 90.0996 860.2 c 0,117,118 62.0502 860.2 62.0502 860.2 45.4746 881.025 c 0,119,120 28.9003 901.849 28.9003 901.849 28.9004 914.6 c 0,121,122 30.6431 951.441 l 0,123,124 34.4008 977.421 34.4008 977.421 45.0498 1007.67 c 0,125,126 63.75 1060.8 63.75 1060.8 74.7998 1101.6 c 0,127,128 95.2003 1178.96 95.2003 1178.96 66.2998 1252.47 c 0,129,130 40.3659 1318.45 40.3659 1318.45 40.4422 1375.88 c 0,131,132 40.451 1382.45 40.451 1382.45 40.7998 1388.9 c 0,133,134 42.4996 1430.54 42.4996 1430.54 67.5752 1459.45 c 0,135,136 85.036 1479.58 85.036 1479.58 110.125 1479.5 c 0,137,138 121.062 1479.47 121.062 1479.47 133.45 1475.6 c 0,139,140 93.4999 1461.15 93.4999 1461.15 86.7002 1435.22 c 0,141,142 83.601 1410.01 l 0,143,144 84.1391 1401.29 84.1391 1401.29 87.5498 1394.85 c 0,145,146 102.429 1363.6 102.429 1363.6 134.236 1363.61 c 0,147,148 138.771 1363.61 138.771 1363.61 143.65 1364.25 c 0,149,150 182.75 1369.35 182.75 1369.35 194.65 1394.85 c 0,151,152 208.059 1425.77 208.059 1425.77 207.989 1452.07 c 0,153,154 207.84 1507.45 207.84 1507.45 147.9 1542.33 c 0,155,156 59.481 1593.76 59.481 1593.76 30.5996 1603.1 c 0,157,158 140.25 1580.15 140.25 1580.15 186.15 1532.12 c 0,159,160 232.049 1484.11 232.049 1484.11 243.95 1443.3 c 0,161,162 257.551 1394.85 257.551 1394.85 252.875 1354.47 c 0,163,164 248.199 1314.1 248.199 1314.1 235.45 1264.8 c 0,165,166 226.614 1230.08 226.614 1230.08 226.682 1184.83 c 0,167,168 226.706 1169.13 226.706 1169.13 227.8 1152.17 c 0,169,170 231.7 1091.72 231.7 1091.72 279.269 1091.04 c 0,171,172 283.534 1090.98 283.534 1090.98 288.15 1091.4 c 0,173,174 341.7 1096.5 341.7 1096.5 334.05 1142.4 c 0,175,176 326.4 1188.3 326.4 1188.3 283.9 1198.5 c 0,177,178 308.183 1201.04 l 0,179,180 325.909 1200.14 325.909 1200.14 345.525 1191.7 c 0,181,182 379.098 1177.26 379.098 1177.26 386.75 1151.75 c 0,183,184 392.424 1130.47 392.424 1130.47 392.464 1110.19 c 0,185,186 392.543 1069.7 392.543 1069.7 370.175 1033.17 c 0,187,188 338.479 981.419 338.479 981.419 334.9 914.6 c 0,189,190 332.417 868.263 332.417 868.263 379.95 889.1 c 0,191,192 442 916.299 442 916.299 505.75 1024.25 c 0,193,194 528.697 1062.5 528.697 1062.5 552.5 1165.78 c 0,195,196 575.844 1267.07 575.844 1267.07 610.3 1293.7 c 0,197,198 629.01 1308.15 629.01 1308.15 658.325 1315.38 c 0,199,200 681.508 1317.82 l 0,201,202 693.431 1316.82 693.431 1316.82 700.4 1309.85 c 0,203,204 641.75 1305.6 641.75 1305.6 641.75 1266.5 c 0,205,206 641.75 1240.15 641.75 1240.15 667.25 1246.1 c 0,207,208 743.751 1259.71 743.751 1259.71 750.975 1311.97 c 0,209,210 758.202 1364.26 758.202 1364.26 791.35 1406.75 c 0,211,212 811.401 1432.74 811.401 1432.74 844.752 1432.78 c 0,213,214 849.575 1432.79 849.575 1432.79 854.675 1432.25 c 0,215,216 895.049 1428.01 895.049 1428.01 906.1 1409.3 c 0,217,218 874.516 1412.94 l 0,219,220 839.2 1412.34 839.2 1412.34 824.925 1385.92 c 0,221,222 817.061 1371.36 817.061 1371.36 816.904 1357.53 c 0,223,224 820.58 1338.22 l 0,225,226 824.994 1327.19 824.994 1327.19 834.7 1316.65 c 0,227,228 855.055 1294.26 855.055 1294.26 890.312 1294.08 c 0,229,230 899.217 1294.03 899.217 1294.03 909.075 1295.4 c 0,231,232 957.942 1302.19 957.942 1302.19 998.325 1332.8 c 0,233,234 1038.71 1363.41 1038.71 1363.41 1055.7 1413.12 c 0,235,236 1060.93 1428.44 1060.93 1428.44 1060.93 1444.6 c 0,237,238 1060.92 1480.92 1060.92 1480.92 1034.45 1521.5 c 0,239,240 1083.75 1482.4 1083.75 1482.4 1086.3 1418.65 c 0,241,242 1084.19 1380.81 l 0,243,244 1077.86 1342.3 1077.86 1342.3 1054 1314.95 c 0,245,246 1033.61 1291.16 1033.61 1291.16 981.75 1261.83 c 0,247,248 929.871 1232.49 929.871 1232.49 876.35 1212.1 c 0,249,250 796.23 1181.55 796.23 1181.55 731.85 1068.45 c 0,251,252 700.406 1013.22 700.406 1013.22 682.975 961.35 c 0,253,254 665.549 909.5 665.549 909.5 610.3 840.65 c 0,255,256 572.901 793.901 572.901 793.901 512.55 787.95 c 0,257,258 543.15 800.7 543.15 800.7 562.7 829.175 c 0,259,260 569.503 839.084 569.503 839.084 569.513 846.368 c 0,261,262 569.531 860.017 569.531 860.017 545.7 864.45 c 0,263,264 520.2 868.7 520.2 868.7 494.275 845.75 c 0,265,266 469.591 823.898 469.591 823.898 463.25 792.2 c 0,267,268 460.627 761.739 l 0,269,270 462.103 733.539 462.103 733.539 480.675 717.825 c 0,271,272 493.756 706.756 493.756 706.756 504.277 706.775 c 0,273,274 517.122 706.798 517.122 706.798 526.15 723.35 c 0,275,276 527.626 732.428 l 0,277,278 524.386 745.468 524.386 745.468 488.75 755.65 c 0,279,280 508.168 770.089 508.168 770.089 525.544 770.091 c 0,281,282 537.833 770.093 537.833 770.093 549.1 762.875 c 0,283,284 576.3 745.449 576.3 745.449 583.95 719.95 c 0,285,286 604.35 651.951 604.35 651.951 571.2 613.7 c 0,287,288 546.358 585.035 546.358 585.035 546.316 540 c 0,289,290 546.304 527.346 546.304 527.346 548.25 513.4 c 0,291,292 558.45 440.3 558.45 440.3 643.875 403.325 c 0,293,294 729.3 366.35 729.3 366.35 803.25 341.7 c 0,295,296 884.85 314.5 884.85 314.5 909.5 264.35 c 0,297,298 928.35 226 928.35 226 928.312 206.538 c 0,299,300 928.3 200.55 928.3 200.55 926.5 196.35 c 0,301,302 905.249 264.351 905.249 264.351 842.35 278.8 c 0,303,304 811.077 281.413 l 0,305,306 775.025 279.194 775.025 279.194 765 247.35 c 0,307,308 763.193 229.147 l 0,309,310 767.307 190.197 767.307 190.197 837.25 143.225 c 0,311,312 923.95 84.9995 923.95 84.9995 962.2 55.25 c 0,313,314 997.9 26.3497 997.9 26.3497 1028.92 -23.375 c 0,315,316 1053.67 -63.0368 1053.67 -63.0368 1053.81 -99.1914 c 0,317,318 1053.85 -108.358 1053.85 -108.358 1052.3 -117.3 c 0,319,320 1027.92 -255.669 1027.92 -255.669 888.25 -285.6 c 0,321,322 871.057 -289.284 871.057 -289.284 843.002 -289.198 c 0,323,324 832.216 -289.165 832.216 -289.165 819.825 -288.575 c 0,325,326 775.198 -286.449 775.198 -286.449 737.8 -273.7 c 0,327,328 748.664 -276.416 748.664 -276.416 776.189 -276.355 c 0,329,330 791.737 -276.32 791.737 -276.32 812.6 -275.4 c 0,331,332 870.4 -272.85 870.4 -272.85 893.35 -262.65 c 0,333,334 947.749 -237.15 947.749 -237.15 980.9 -176.8 c 0,335,336 1014.05 -116.451 1014.05 -116.451 973.25 -47.5996 c 0,337,338 961.351 -27.202 961.351 -27.202 929.05 -0.424805 c 0,339,340 896.751 26.3496 896.751 26.3496 860.2 37.4004 c 0,341,342 823.078 47.9578 823.078 47.9578 801.239 48.0084 c 0,343,344 770.67 48.0793 770.67 48.0793 770.1 24.6504 c 0,345,346 770.1 5.09961 770.1 5.09961 793.475 5.09961 c 0,347,348 816.85 5.09961 816.85 5.09961 832.15 -0.849609 c 0,349,350 796.45 -21.25 796.45 -21.25 756.925 -10.625 c 0,351,352 717.4 -4.76837e-06 717.4 -4.76837e-06 712.3 12.75 c 0,353,354 698.702 38.2446 698.702 38.2446 685.1 78.2002 c 0,355,-1 664.7 146.2 l 0,356,357 657.049 171.702 657.049 171.702 616.675 220.575 c 0,358,359 577.384 268.136 577.384 268.136 542.3 268.6 c 0,0,1 EndSplineSet KernsSLIF: 111 -65 0 0 115 -104 0 0 103 -65 0 0 99 -156 0 0 EndChar StartChar: l Encoding: 108 108 66 Width: 1076 Flags: HMW HStem: 136.5 181.5<307 709> VStem: 37 223.5<161 1456.5> Fore 41 292 m 0,0,1 70 310 70 310 114 285 c 0,2,3 70.0001 294 70.0001 294 45 270.5 c 0,4,5 29.3458 255.785 29.3458 255.785 29.375 238.521 c 0,6,7 29.3925 228.215 29.3925 228.215 35 217 c 0,8,9 45.7595 193.759 45.7595 193.759 61.8905 193.765 c 0,10,11 83.2405 193.772 83.2405 193.772 114 234.5 c 0,12,13 146.057 276.946 146.057 276.946 146.044 324.502 c 0,14,15 146.035 357.054 146.035 357.054 131 392 c 0,16,17 107 446 107 446 77 421 c 0,18,19 47 396 47 396 93 354 c 0,20,21 27 375 27 375 26 453 c 0,22,23 27.8452 496.459 l 0,24,25 32.9898 535.068 32.9898 535.068 50.5 575.5 c 0,26,27 77.9997 638.999 77.9997 638.999 92 698 c 0,28,29 119 824 119 824 94 931 c 0,30,31 81.9967 983.015 81.9967 983.015 64.5 1034.5 c 0,32,33 47.0011 1085.99 47.0011 1085.99 42 1145 c 0,34,35 45.7278 1163.7 l 0,36,37 48.9752 1172.67 48.9752 1172.67 55 1184.5 c 0,38,39 68.9999 1211.99 68.9999 1211.99 111 1207 c 0,40,41 100.366 1206.12 l 0,42,43 88.4565 1201.3 88.4565 1201.3 78 1179 c 0,44,45 74.1633 1163.65 l 0,46,47 75.1096 1150.58 75.1096 1150.58 97.0824 1150.55 c 0,48,49 101.177 1150.55 101.177 1150.55 106 1151 c 0,50,51 134.875 1152.75 134.875 1152.75 135.422 1182.06 c 0,52,53 135.5 1186.25 135.5 1186.25 135 1191 c 0,54,55 130.996 1229.03 130.996 1229.03 124 1274 c 0,56,57 113.999 1328 113.999 1328 92.5 1376 c 0,58,59 71.0001 1424 71.0001 1424 53 1475 c 0,60,61 49.0488 1485.54 49.0488 1485.54 49.109 1498.02 c 0,62,63 49.2317 1523.47 49.2317 1523.47 66 1557 c 0,64,65 80.4583 1585.91 80.4583 1585.91 105.952 1586.07 c 0,66,67 122.383 1586.17 122.383 1586.17 143.398 1574.32 c 0,68,69 146.159 1572.76 146.159 1572.76 149 1571 c 0,70,71 128.01 1571 128.01 1571 103 1557 c 0,72,73 77.9999 1543.01 77.9999 1543.01 88 1497 c 0,74,75 96.8173 1449.97 96.8173 1449.97 137.5 1449.5 c 0,76,77 177.998 1449.99 177.998 1449.99 196 1501 c 0,78,79 203.796 1524.39 203.796 1524.39 203.751 1545.28 c 0,80,81 203.629 1602.11 203.629 1602.11 145.5 1640.5 c 0,82,83 66.01 1692.99 66.01 1692.99 -2 1703 c 0,84,85 59.4295 1700.45 l 0,86,87 127.09 1692.99 127.09 1692.99 170 1664.5 c 0,88,89 230.996 1624 230.996 1624 247 1586 c 0,90,91 264.567 1541.41 264.567 1541.41 264.558 1497.95 c 0,92,93 264.554 1477.09 264.554 1477.09 260.5 1456.5 c 0,94,95 248 1393 248 1393 248 1330 c 0,96,97 248 1249 248 1249 285 1147 c 0,98,99 322 1045 322 1045 265 1006 c 0,100,101 284 1036 284 1036 260 1067.5 c 0,102,103 249.5 1081.28 249.5 1081.28 239 1081.18 c 0,104,105 225.501 1081.06 225.501 1081.06 212 1058 c 0,106,107 200.001 1037 200.001 1037 194.5 961.5 c 0,108,109 194.818 919.869 l 0,110,111 199.301 880.069 199.301 880.069 222 867 c 0,112,113 230.364 862.221 230.364 862.221 237.166 862.215 c 0,114,115 253.136 862.201 253.136 862.201 260.5 888.5 c 0,116,117 271 926 271 926 241 959 c 0,118,119 276.001 959 276.001 959 291.5 913 c 0,120,121 298.669 891.725 298.669 891.725 298.672 873.017 c 0,122,123 298.675 851.275 298.675 851.275 289 833 c 0,124,125 280 814 280 814 268 731.5 c 0,126,127 255.999 648.995 255.999 648.995 252.5 557.5 c 0,128,129 252.749 465.02 l 0,130,131 254.6 426.799 254.6 426.799 259.5 392.5 c 0,132,133 270 319 270 319 307 318 c 0,134,135 352 316 352 316 381.5 366 c 0,136,137 411 416 411 416 477 413 c 0,138,139 545 407 545 407 533 332 c 0,140,141 517.466 372.206 517.466 372.206 481.891 372.75 c 0,142,143 478.534 372.802 478.534 372.802 475 372.5 c 0,144,145 443.78 369.835 443.78 369.835 443.871 339.628 c 0,146,147 443.899 330.165 443.899 330.165 447 318 c 0,148,149 450 303 450 303 481 292.5 c 0,150,151 503.812 289.566 l 0,152,153 536.914 289.914 536.914 289.914 597 309 c 0,154,155 646 324 646 324 742 359 c 0,156,157 838 394 838 394 825 292 c 0,158,159 798 357 798 357 757 314.5 c 0,160,161 716 272 716 272 754 257 c 0,162,163 800.183 238.107 800.183 238.107 842.224 238.075 c 0,164,165 900.317 238.031 900.317 238.031 950.5 274 c 0,166,167 1024.75 327.219 1024.75 327.219 1024.95 450.456 c 0,168,169 1024.98 470.777 1024.98 470.777 1023 493 c 0,170,171 1042.44 425.955 1042.44 425.955 1042.51 374.013 c 0,172,173 1042.59 319.048 1042.59 319.048 1021 281 c 0,174,175 978.999 206.999 978.999 206.999 896 173.5 c 0,176,177 812.998 139.999 812.998 139.999 709 136.5 c 0,178,179 566.939 135.419 l 0,180,181 543.748 135.952 543.748 135.952 522 137 c 0,182,183 471.006 138.999 471.006 138.999 411 151.5 c 0,184,185 390.2 155.833 390.2 155.833 365.795 155.78 c 0,186,187 319.799 155.68 319.799 155.68 261 140 c 0,188,189 219.505 128.553 219.505 128.553 174.425 128.623 c 0,190,191 156.496 128.65 156.496 128.65 138 130.5 c 0,192,193 73.0009 136.999 73.0009 136.999 37 161 c 0,194,195 8.00005 179 8.00005 179 3.5 221.5 c 0,196,197 -1 263.999 -1 263.999 41 292 c 0,0,1 EndSplineSet KernsSLIF: 116 -286 0 0 121 -156 0 0 105 -78 0 0 45 -156 0 0 115 -130 0 0 119 -195 0 0 EndChar StartChar: m Encoding: 109 109 24 Width: 1471 Flags: HMW VStem: 93 114<55 195> 100 187<251 1528> 312.5 89.5<154.5 421> 1036 199<169 1576> 1134.5 100.5<-115 169> Fore 1025 -231 m 1,0,1 1079 -195 1079 -195 1134.5 -115 c 0,2,3 1190 -35 1190 -35 1184 71 c 0,4,5 1181 106 1181 106 1161.5 152 c 0,6,7 1142 198.001 1142 198.001 1093 204 c 0,8,9 1079 204 1079 204 1059.5 200.5 c 0,10,11 1040 197.001 1040 197.001 1034 182 c 0,12,13 1024.39 155.698 1024.39 155.698 1024.37 134.251 c 0,14,15 1024.36 113.308 1024.36 113.308 1033.5 97 c 0,16,17 1047.33 72.3194 1047.33 72.3194 1073.76 72.2502 c 0,18,19 1082.67 72.2269 1082.67 72.2269 1093 75 c 0,20,21 1078.76 49.3729 1078.76 49.3729 1038.4 49.4211 c 0,22,23 1036.24 49.4237 1036.24 49.4237 1034 49.5 c 0,24,25 990 51.0002 990 51.0002 966 77 c 0,26,27 933.272 109.728 933.272 109.728 933.041 162.846 c 0,28,29 932.982 176.272 932.982 176.272 935 191 c 0,30,31 946 272 946 272 972.5 349.5 c 0,32,33 999 426.998 999 426.998 1014 503 c 0,34,35 1024.01 554 1024.01 554 1041 677 c 0,36,37 1058 800.036 1058 800.036 1058 853 c 0,38,39 1058 893 1058 893 1053.5 957 c 0,40,41 1049 1021 1049 1021 1003 1042 c 0,42,43 987.084 1049.23 987.084 1049.23 970.385 1049.21 c 0,44,45 940.911 1049.16 940.911 1049.16 909 1026.5 c 0,46,47 875.767 1002.9 875.767 1002.9 875.667 973.785 c 0,48,49 875.617 959.096 875.617 959.096 884 943 c 0,50,51 895.195 919.951 895.195 919.951 909.426 919.67 c 0,52,53 921.873 923.425 l 0,54,55 923.421 924.349 923.421 924.349 925 925.5 c 0,56,57 949 943 949 943 958 976 c 0,58,59 977 914 977 914 943 862 c 0,60,61 911.999 817.999 911.999 817.999 842.5 811.5 c 0,62,63 773 805 773 805 718 805 c 0,64,65 667 805 667 805 642 779 c 0,66,67 617 753 617 753 615 726 c 0,68,69 612 694 612 694 627 656.5 c 0,70,71 642 619 642 619 665 607 c 0,72,73 739 567 739 567 769 589 c 0,74,75 799 611 799 611 808 638 c 0,76,77 808.615 615.462 l 0,78,79 805.87 596.063 805.87 596.063 791.5 578.5 c 0,80,81 769 551 769 551 751 548 c 0,82,83 684 533 684 533 658 548.5 c 0,84,85 632 564 632 564 608 589 c 0,86,87 558 640 558 640 542 729.5 c 0,88,89 526.001 818.995 526.001 818.995 525 879 c 0,90,91 524 915.999 524 915.999 504 953 c 0,92,93 484 990 484 990 441 992 c 0,94,95 411 993 411 993 412.5 963.5 c 0,96,97 414 934 414 934 459 958 c 0,98,99 450 922 450 922 424 920 c 0,100,101 398 918 398 918 377 930 c 0,102,103 351 942 351 942 350.5 981.5 c 0,104,105 350 1020.99 350 1020.99 358 1064 c 0,106,107 359.954 1094.75 l 0,108,109 358.246 1117.65 358.246 1117.65 345 1129 c 0,110,111 333.574 1137.92 333.574 1137.92 323.779 1138.06 c 0,112,113 317.203 1138.15 317.203 1138.15 311.363 1134.29 c 0,114,115 294.684 1123.27 294.684 1123.27 284 1080 c 0,116,117 264 999 264 999 264 950 c 0,118,119 264 801.001 264 801.001 308 643 c 0,120,121 323 590 323 590 354.5 531.5 c 0,122,123 386 473 386 473 402 421 c 0,124,125 426 337 426 337 420 268 c 0,126,127 409.999 148.999 409.999 148.999 332 123 c 0,128,129 307.489 114.489 307.489 114.489 288.773 114.554 c 0,130,131 252.511 114.681 252.511 114.681 238 147 c 0,132,133 249.812 142.94 249.812 142.94 263.055 142.899 c 0,134,135 285.688 142.829 285.688 142.829 312.5 154.5 c 0,136,137 352.19 171.777 352.19 171.777 352.198 209.549 c 0,138,139 352.198 212.223 352.198 212.223 352 215 c 0,140,141 349 275 349 275 287 251 c 0,142,143 225 227 225 227 207 195 c 0,144,145 176.999 141.999 176.999 141.999 170.5 79.5 c 0,146,147 167.94 21.3888 l 0,148,149 168.706 -1.8226 168.706 -1.8226 173 -19 c 0,150,151 203 -149 203 -149 259.5 -205.5 c 0,152,153 315.999 -261.999 315.999 -261.999 374 -308 c 0,154,155 254 -285.999 254 -285.999 172 -175.5 c 0,156,157 89.9995 -64.9995 89.9995 -64.9995 93 55 c 0,158,159 95 136 95 136 136.5 219.5 c 0,160,161 178 302.999 178 302.999 190 384 c 0,162,163 194.996 416.975 194.996 416.975 206 474 c 0,164,165 209 507.333 l 0,166,167 207.667 536 207.667 536 189 546 c 0,168,169 176.804 551.963 176.804 551.963 167.289 552.233 c 0,170,171 153.866 549.07 l 0,172,173 139.867 541.011 139.867 541.011 135.5 512.5 c 0,174,175 126.999 457 126.999 457 158 448 c 0,176,177 95 448 95 448 89 503.5 c 0,178,179 83 559 83 559 89 601 c 0,180,181 95 640 95 640 120.5 683.5 c 0,182,183 146 727 146 727 152 766 c 0,184,185 155.588 821.346 l 0,186,187 155.088 894.71 155.088 894.71 125.5 959 c 0,188,189 84.9961 1047.01 84.9961 1047.01 58 1140 c 0,190,191 32.9998 1225.01 32.9998 1225.01 30.5 1276 c 0,192,193 28 1327 28 1327 73 1414 c 0,194,195 89.0001 1447 89.0001 1447 120.5 1453 c 0,196,197 145.355 1454.66 l 0,198,199 156.698 1453.36 156.698 1453.36 162 1447 c 0,200,201 119.001 1444 119.001 1444 110 1383.5 c 0,202,203 101 1323.01 101 1323.01 135 1322 c 0,204,205 161.228 1323.78 l 0,206,207 189.587 1330.18 189.587 1330.18 203 1357 c 0,208,209 222 1394.99 222 1394.99 227 1440 c 0,210,211 227.387 1482.88 l 0,212,213 225.876 1502 225.876 1502 221.5 1522.5 c 0,214,215 213.181 1561.47 213.181 1561.47 157.691 1561.71 c 0,216,217 149.82 1561.75 149.82 1561.75 141 1561 c 0,218,219 122.004 1558 122.004 1558 111.5 1542.5 c 0,220,221 101.718 1528.07 101.718 1528.07 100 1528 c 0,222,223 103.126 1559.45 l 0,224,225 113.773 1604.2 113.773 1604.2 160.5 1617.5 c 0,226,227 174.44 1621.47 174.44 1621.47 187.84 1621.5 c 0,228,229 224.431 1621.6 224.431 1621.6 257.003 1592.39 c 0,230,231 265.126 1585.11 265.126 1585.11 273 1576 c 0,232,233 321.005 1518.99 321.005 1518.99 350 1446 c 0,234,235 379 1372.99 379 1372.99 415 1314 c 0,236,-1 463 1243 l 0,237,238 511 1172.01 511 1172.01 543 1210 c 0,239,240 552 1220.72 552 1220.72 552.092 1232.53 c 0,241,242 552.188 1244.99 552.188 1244.99 542.38 1258.68 c 0,243,244 539.786 1262.3 539.786 1262.3 536.5 1266 c 0,245,246 513.03 1292.46 513.03 1292.46 484.812 1292.69 c 0,247,248 479.976 1292.73 479.976 1292.73 475 1292 c 0,249,250 490.916 1311.9 490.916 1311.9 512.538 1312.16 c 0,251,252 518.082 1312.22 518.082 1312.22 524 1311 c 0,253,254 553 1305 553 1305 568 1296 c 0,255,256 599.001 1273.99 599.001 1273.99 602 1228 c 0,257,258 604 1180.99 604 1180.99 627.5 1135.5 c 0,259,260 651 1090.01 651 1090.01 690 1110 c 0,261,262 726 1128 726 1128 741 1174.5 c 0,263,264 756 1221 756 1221 779 1281 c 0,265,266 808.994 1362.99 808.994 1362.99 892.5 1461.5 c 0,267,268 975.99 1559.99 975.99 1559.99 1036 1576 c 0,269,270 1115.38 1596.09 1115.38 1596.09 1210.29 1596.05 c 0,271,272 1214.63 1596.04 1214.63 1596.04 1219 1596 c 0,273,274 1319.01 1594.99 1319.01 1594.99 1393 1542 c 0,275,276 1431.02 1514.98 1431.02 1514.98 1470.5 1467 c 0,277,278 1510 1418.99 1510 1418.99 1510 1364 c 0,279,280 1510 1333.99 1510 1333.99 1503 1307.5 c 0,281,282 1496 1281 1496 1281 1463 1263 c 0,283,284 1484.46 1289.96 1484.46 1289.96 1484.42 1324.94 c 0,285,286 1484.39 1353.54 1484.39 1353.54 1470 1387.5 c 0,287,288 1438.01 1462.99 1438.01 1462.99 1378 1491 c 0,289,290 1313.98 1520 1313.98 1520 1244.5 1523 c 0,291,292 1222.23 1520.55 l 0,293,294 1174.12 1506.48 1174.12 1506.48 1170 1414 c 0,295,296 1172.56 1390 l 0,297,298 1180.15 1360.99 1180.15 1360.99 1209.5 1332 c 0,299,300 1235.32 1306.5 1235.32 1306.5 1253.58 1306.53 c 0,301,302 1264.68 1306.55 1264.68 1306.55 1273 1316 c 0,303,304 1290.28 1335.2 1290.28 1335.2 1290.36 1350.31 c 0,305,306 1290.4 1358.8 1290.4 1358.8 1285 1366 c 0,307,308 1269.99 1386 1269.99 1386 1246 1395 c 0,309,310 1256 1408.33 1256 1408.33 1270.17 1408.55 c 0,311,312 1286.92 1404.85 l 0,313,314 1291.08 1403.1 1291.08 1403.1 1295.5 1400.5 c 0,315,316 1327 1382 1327 1382 1332 1373 c 0,317,318 1340.68 1353.09 1340.68 1353.09 1340.88 1329 c 0,319,320 1337.14 1293.77 l 0,321,322 1335.62 1286.54 1335.62 1286.54 1333.5 1279 c 0,323,324 1318.01 1224.02 1318.01 1224.02 1288 1187 c 0,325,326 1193.99 1074.99 1193.99 1074.99 1222 947 c 0,327,328 1240 856.01 1240 856.01 1267.5 819 c 0,329,-1 1321 744 l 0,330,331 1374.27 666.794 1374.27 666.794 1374.49 580.64 c 0,332,333 1374.56 555.209 1374.56 555.209 1370 529 c 0,334,335 1364 496.019 1364 496.019 1350 464.5 c 0,336,337 1336.01 433.005 1336.01 433.005 1300 407 c 0,338,339 1291 401 1291 401 1267 392.5 c 0,340,341 1248.3 389.491 l 0,342,343 1235.95 390.219 1235.95 390.219 1226 399 c 0,344,345 1274 422 1274 422 1283 456 c 0,346,347 1289.22 479.507 1289.22 479.507 1289.23 503 c 0,348,349 1289.24 513.5 1289.24 513.5 1288 524 c 0,350,351 1285 547 1285 547 1246 548 c 0,352,353 1225.66 544.999 l 0,354,355 1203.25 536.886 1203.25 536.886 1194 507 c 0,356,357 1182 468 1182 468 1180.5 415 c 0,358,359 1182.17 345.543 l 0,360,361 1183.28 332.776 1183.28 332.776 1185 321 c 0,362,363 1194 262.984 1194 262.984 1208.5 232.5 c 0,364,365 1222.98 202.047 1222.98 202.047 1235 169 c 0,366,367 1253.25 119.481 1253.25 119.481 1253.23 68.6809 c 0,368,369 1253.23 41.5239 1253.23 41.5239 1248 14 c 0,370,371 1234.01 -55.9778 1234.01 -55.9778 1188.5 -125 c 0,372,373 1143.01 -193.999 1143.01 -193.999 1025 -231 c 1,0,1 EndSplineSet KernsSLIF: 97 -91 0 0 105 65 0 0 EndChar StartChar: n Encoding: 110 110 50 Width: 1072 Flags: HMW VStem: 116 176<173 1259> 669 262<167 1382> Fore 84 54 m 0,0,1 67.6022 106.707 67.6022 106.707 67.6669 159.757 c 0,2,3 67.7127 197.292 67.7127 197.292 76 235 c 0,4,5 95.9999 326 95.9999 326 112 413 c 0,6,7 119.449 452.538 119.449 452.538 119.387 491.624 c 0,8,9 119.234 588.963 119.234 588.963 72.5 683.5 c 0,10,11 6.99995 816 6.99995 816 36 919 c 0,12,13 38 928 38 928 58.5 946 c 0,14,15 79.0001 964 79.0001 964 107 951 c 0,16,17 28 913 28 913 86.5 877.5 c 0,18,19 145 842 145 842 145 927 c 0,20,21 145 1008.01 145 1008.01 130.5 1094 c 0,22,23 115.999 1179.99 115.999 1179.99 116 1259 c 0,24,25 116 1331.99 116 1331.99 122.5 1411.5 c 0,26,27 128.999 1491 128.999 1491 177 1539 c 0,28,29 193.772 1556.4 193.772 1556.4 215.176 1556.62 c 0,30,31 236.709 1552.9 l 0,32,33 239.815 1551.85 239.815 1551.85 243 1550.5 c 0,34,35 282 1534 282 1534 282 1511 c 0,36,37 244.773 1542.56 244.773 1542.56 220.07 1543.1 c 0,38,39 205.24 1540.12 l 0,40,41 181.674 1529.11 181.674 1529.11 174.5 1477.5 c 0,42,43 171.376 1428.44 l 0,44,45 172.982 1352.49 172.982 1352.49 219 1308 c 0,46,47 273.009 1255 273.009 1255 349.5 1225 c 0,48,49 425.994 1195 425.994 1195 462 1148 c 0,50,51 488.105 1114.38 488.105 1114.38 488.397 1086.39 c 0,52,53 485.131 1066.6 l 0,54,55 474.466 1036.51 474.466 1036.51 429 1014 c 0,56,-1 448 1047 l 0,57,58 453.854 1057.54 453.854 1057.54 453.882 1069.79 c 0,59,60 453.903 1078.47 453.903 1078.47 451 1088 c 0,61,62 444 1110.01 444 1110.01 427 1115 c 0,63,64 414.31 1115.26 l 0,65,66 405.925 1112.67 405.925 1112.67 400 1102 c 0,67,68 392.365 1089.51 392.365 1089.51 392.438 1065.21 c 0,69,70 392.576 1019.49 392.576 1019.49 420 932 c 0,71,72 462 798 462 798 506 806 c 0,73,74 550.453 813.17 550.453 813.17 551.467 837.304 c 0,75,76 548.076 853.531 l 0,77,78 546.968 856.195 546.968 856.195 545.5 859 c 0,79,80 523.001 901.999 523.001 901.999 496 924 c 0,81,82 594 900 594 900 600.5 818.5 c 0,83,84 607 737 607 737 607 656 c 0,85,86 607 591 607 591 653.5 558.5 c 0,87,88 665.214 550.313 665.214 550.313 674.992 550.407 c 0,89,90 704.03 550.687 704.03 550.687 716 624 c 0,91,92 725 682 725 682 729 739.5 c 0,93,94 733 797 733 797 717 858 c 0,95,96 708 891 708 891 685.5 936.5 c 0,97,98 663 982 663 982 663 1022 c 0,99,100 663 1060.01 663 1060.01 678 1090.5 c 0,101,102 691.45 1117.84 691.45 1117.84 727.403 1118.26 c 0,103,104 731.552 1118.31 731.552 1118.31 736 1118 c 0,105,106 719.991 1101.99 719.991 1101.99 707 1077 c 0,107,108 701.61 1066.63 701.61 1066.63 701.549 1057.82 c 0,109,110 701.463 1045.37 701.463 1045.37 712 1036 c 0,111,112 737 1012 737 1012 751 1060 c 0,113,114 765 1108 765 1108 765 1118 c 0,115,116 765 1180.99 765 1180.99 733.5 1225.5 c 0,117,118 701.999 1270.01 701.999 1270.01 696 1331 c 0,119,120 696.659 1361.08 l 0,121,122 702.981 1402.43 702.981 1402.43 740 1435 c 0,123,124 759.78 1452.4 759.78 1452.4 778.152 1452.6 c 0,125,126 787.631 1452.7 787.631 1452.7 796.735 1448.21 c 0,127,128 814.589 1439.42 814.589 1439.42 831 1413 c 0,129,130 757 1422 757 1422 761.5 1360.5 c 0,131,132 766 1299 766 1299 817 1299 c 0,133,134 891.998 1299 891.998 1299 931 1382 c 0,135,136 950.863 1422.37 950.863 1422.37 950.815 1479.56 c 0,137,138 950.788 1511.64 950.788 1511.64 944.5 1549 c 0,139,140 926.997 1653.01 926.997 1653.01 876 1703 c 0,141,142 957.002 1649 957.002 1649 977 1552 c 0,143,144 997 1454.99 997 1454.99 997 1434 c 0,145,146 997 1371 997 1371 969.5 1318 c 0,147,148 942.002 1265.01 942.002 1265.01 930 1211 c 0,149,150 924.391 1186.32 924.391 1186.32 924.235 1164.02 c 0,151,152 927.798 1128.33 l 0,153,154 931.489 1111.34 931.489 1111.34 939 1096 c 0,155,156 963 1046.99 963 1046.99 985 994 c 0,157,158 1013.99 919 1013.99 919 1027 860.5 c 0,159,160 1028.01 839.43 l 0,161,162 1021.88 793.213 1021.88 793.213 941 754 c 0,163,164 953 769 953 769 967.5 790 c 0,165,166 982 811 982 811 982 832 c 0,167,168 982 866 982 866 959 866 c 0,169,170 934.737 863.08 l 0,171,172 896.5 851.954 896.5 851.954 892 797 c 0,173,-1 873 581 l 0,174,175 863 470 863 470 842 367 c 0,176,177 827 297.001 827 297.001 755 159.5 c 0,178,179 683 21.9999 683 21.9999 591 40 c 0,180,181 633 60 633 60 646.5 91.5 c 0,182,183 660 123 660 123 669 167 c 0,184,185 680 225.001 680 225.001 638 356 c 0,186,187 596 487 596 487 525 478 c 0,188,189 501 474 501 474 504.5 443.5 c 0,190,191 507.29 419.188 507.29 419.188 527.552 418.703 c 0,192,193 539 420 l 0,194,195 517 393 517 393 485 416.5 c 0,196,197 452.999 440.001 452.999 440.001 448 457 c 0,198,199 417.999 548.003 417.999 548.003 413 613.5 c 0,200,201 408 679 408 679 381 763 c 0,202,203 361.001 820.999 361.001 820.999 338 828 c 0,204,205 315 835 315 835 338 754 c 0,206,207 345.7 724.299 345.7 724.299 345.686 690.97 c 0,208,209 345.675 663.7 345.675 663.7 340.5 634 c 0,210,211 329 568 329 568 248 600 c 0,212,213 320 597 320 597 288 653 c 0,214,215 256 709 256 709 232 655 c 0,216,217 218.999 625 218.999 625 220 583.5 c 0,218,219 221.001 541.997 221.001 541.997 231 515 c 0,220,221 272 401 272 401 298.5 353.5 c 0,222,223 310.319 332.316 310.319 332.316 310.303 294.126 c 0,224,225 310.283 246.685 310.283 246.685 292 173 c 0,226,227 283 137.999 283 137.999 248.5 118 c 0,228,229 213.999 97.9998 213.999 97.9998 179 90 c 0,230,231 216.999 109.999 216.999 109.999 233 174.5 c 0,232,233 236.04 199.261 l 0,234,235 234.584 237.113 234.584 237.113 182 237 c 0,236,237 142.999 235.999 142.999 235.999 132 189.5 c 0,238,239 121.001 143 121.001 143 121 101 c 0,240,241 121 -12.9997 121 -12.9997 205.5 -65.5 c 0,242,243 290 -118 290 -118 387 -123 c 0,244,245 331.946 -127.042 l 0,246,247 248.215 -126.958 248.215 -126.958 188.5 -85.5 c 0,248,249 109.999 -30.9992 109.999 -30.9992 84 54 c 0,0,1 EndSplineSet KernsSLIF: 97 -208 0 0 EndChar StartChar: o Encoding: 111 111 48 Width: 1255 Flags: W Fore 273 143 m 1,0,1 247 130.5 247 130.5 220.5 130.5 c 0,2,3 194 130.5 194 130.5 167 143 c 0,4,5 68 183.001 68 183.001 68 276 c 0,6,7 68 342 68 342 113 506.5 c 0,8,-1 174 733 l 0,9,10 180.001 758.004 180.001 758.004 183.5 796 c 0,11,12 181.908 815.246 l 0,13,14 175.585 834.878 175.585 834.878 148 837 c 0,15,16 82 841 82 841 89 763 c 0,17,18 37 804 37 804 84.5 974.5 c 0,19,20 132.003 1145.01 132.003 1145.01 147 1245 c 0,21,22 158 1319 158 1319 197 1388 c 0,23,24 220.787 1430.08 220.787 1430.08 268.011 1430.13 c 0,25,26 298.212 1430.16 298.212 1430.16 338 1413 c 0,27,28 247.27 1410.33 247.27 1410.33 246.344 1359.79 c 0,29,30 247.5 1346.5 l 0,31,32 258.818 1284.01 258.818 1284.01 300 1284 c 0,33,34 367.003 1284 367.003 1284 435.5 1390 c 0,35,36 504 1496.01 504 1496.01 459 1522 c 0,37,38 433.333 1536.36 433.333 1536.36 413.25 1536.61 c 0,39,40 394.256 1533.23 l 0,41,42 380.637 1527.76 380.637 1527.76 370.5 1513.5 c 0,43,44 340.989 1471.98 340.989 1471.98 330 1451 c 0,45,46 326.246 1484.15 l 0,47,48 326.881 1531.42 326.881 1531.42 366 1560 c 0,49,50 414.154 1595.18 414.154 1595.18 488.874 1595.22 c 0,51,52 494.849 1595.22 494.849 1595.22 501 1595 c 0,53,54 584.988 1590.01 584.988 1590.01 693.5 1539 c 0,55,56 802 1488 802 1488 835 1428 c 0,57,-1 899 1286.5 l 0,58,59 954.143 1164.13 954.143 1164.13 999 1164 c 0,60,61 1059.17 1168.63 1059.17 1168.63 1059.54 1207.77 c 0,62,63 1059.63 1218.49 1059.63 1218.49 1054.5 1234 c 0,64,65 1032 1297.99 1032 1297.99 975 1299 c 0,66,67 1019.99 1302.45 l 0,68,69 1090.79 1301.3 1090.79 1301.3 1107.5 1250 c 0,70,71 1119.87 1212.01 1119.87 1212.01 1119.83 1182.65 c 0,72,73 1119.79 1160.98 1119.79 1160.98 1113 1144 c 0,74,75 1092.07 1091.19 1092.07 1091.19 1037 938 c 0,76,77 996.721 825.96 996.721 825.96 996.666 771.829 c 0,78,79 996.647 752.046 996.647 752.046 1002 740 c 0,80,81 1014 710 1014 710 1060.5 710.5 c 0,82,83 1107 711 1107 711 1118 750 c 0,84,85 1120.72 775.054 l 0,86,87 1118.42 818.286 1118.42 818.286 1059 827 c 0,88,89 1066.89 837.526 1066.89 837.526 1087.53 837.526 c 0,90,91 1106.1 837.526 1106.1 837.526 1135 829 c 0,92,93 1196.01 811 1196.01 811 1195 746 c 0,94,95 1190.99 608.991 1190.99 608.991 1083.5 510.5 c 0,96,97 976.003 412.007 976.003 412.007 925 303 c 0,98,99 910 273 910 273 941.5 249 c 0,100,101 973 225 973 225 1048 270 c 0,102,103 1015 183 1015 183 859 163.5 c 0,104,105 703 144 703 144 659 120 c 0,106,107 608 91.9995 608 91.9995 531 69.5 c 0,108,109 493.463 58.5313 493.463 58.5313 454.499 58.6135 c 0,110,111 413.537 58.7 413.537 58.7 371 71 c 0,112,113 361 72.9999 361 72.9999 341 87 c 0,114,115 321 101 321 101 317 129 c 0,116,117 362 91.9995 362 91.9995 398 95 c 0,118,119 434 98 434 98 452 118 c 0,120,121 459.368 126.105 459.368 126.105 459.271 134.686 c 0,122,123 459.105 149.395 459.105 149.395 437 165.5 c 0,124,125 402.002 190.999 402.002 190.999 350 210 c 0,126,127 298 229.001 298 229.001 248 237 c 0,128,129 209.512 240.063 l 0,130,131 194.138 239.207 194.138 239.207 190 233 c 0,132,133 178.857 216.286 178.857 216.286 178.827 202.327 c 0,134,135 178.786 183.714 178.786 183.714 198.5 170 c 0,136,137 233 146 233 146 273 143 c 1,0,1 803 384 m 0,79,80 814 403 814 403 806.5 436 c 0,81,82 799 469 799 469 757 454 c 0,83,84 714 439 714 439 719.5 402.5 c 0,85,86 725.001 365.999 725.001 365.999 744 364 c 0,87,88 686 364 686 364 682 416 c 0,89,90 682.987 446.036 l 0,91,92 689.14 481.814 689.14 481.814 720.5 502 c 0,93,94 764 530 764 530 805 574 c 0,95,96 818 588 818 588 852.5 708 c 0,97,98 887 828 887 828 872 893 c 0,99,100 852.999 968.001 852.999 968.001 790.5 1001.5 c 0,101,102 728 1034.99 728 1034.99 728 1128 c 0,103,104 728 1139.99 728 1139.99 743.5 1150 c 0,105,106 751.596 1155.23 751.596 1155.23 760.376 1155.26 c 0,107,108 768.402 1155.3 768.402 1155.3 777 1151 c 0,109,110 764.093 1148.42 764.093 1148.42 763.773 1134.36 c 0,111,112 763.721 1132.08 763.721 1132.08 764 1129.5 c 0,113,114 766 1111 766 1111 781 1111 c 0,115,116 792.638 1113.28 l 0,117,118 801.466 1118.77 801.466 1118.77 801.409 1136.92 c 0,119,120 801.343 1157.82 801.343 1157.82 789.5 1195.5 c 0,121,122 761.999 1283 761.999 1283 675 1301 c 0,123,124 582 1320.01 582 1320.01 516.5 1283 c 0,125,126 451 1245.99 451 1245.99 451 1187 c 0,127,128 451 1166.01 451 1166.01 478.5 1151.5 c 0,129,130 496.123 1142.2 496.123 1142.2 515.194 1142.16 c 0,131,132 525.87 1142.13 525.87 1142.13 537 1145 c 0,133,134 579 1154 579 1154 553 1199 c 0,135,136 583.043 1194.13 583.043 1194.13 583.417 1158.6 c 0,137,138 582 1140.5 l 0,139,140 574 1087.99 574 1087.99 547 1077 c 0,141,142 514.021 1064 514.021 1064 466 1056.5 c 0,143,144 418.018 1049 418.018 1049 379 1032 c 0,145,146 325 1008 325 1008 295.5 850.5 c 0,147,148 267.83 702.772 267.83 702.772 267.873 661.932 c 0,149,150 267.876 659.233 267.876 659.233 268 657 c 0,151,152 270 581 270 581 314.5 564 c 0,153,154 359 547 359 547 403 502 c 0,155,156 425 477 425 477 423.5 434.5 c 0,157,158 422 392 422 392 391 389 c 0,159,160 404 412 404 412 394 428 c 0,161,162 387.333 438.667 387.333 438.667 372.222 438.667 c 0,163,164 364.667 438.667 364.667 438.667 355 436 c 0,165,166 323 427 323 427 329 389 c 0,167,168 335 350.999 335 350.999 365 334 c 0,169,170 446.945 286.393 446.945 286.393 553.56 286.295 c 0,171,172 583.554 286.268 583.554 286.268 615.5 290 c 0,173,174 760.999 306.999 760.999 306.999 803 384 c 0,79,80 EndSplineSet KernsSLIF: 121 -65 0 0 97 -156 0 0 120 -143 0 0 119 -195 0 0 116 -313 0 0 EndChar StartChar: p Encoding: 112 112 62 Width: 1149 Flags: MW VStem: 186 277<161 1354.5> Fore 459 842 m 0,0,1 533 791 533 791 552 852 c 0,2,3 571 918 571 918 538 911.5 c 0,4,5 505.001 905.001 505.001 905.001 490 888 c 0,6,7 484.931 894.589 484.931 894.589 485.001 903.875 c 0,8,9 485.068 912.911 485.068 912.911 490 924.5 c 0,10,11 500.001 948.002 500.001 948.002 510 959 c 0,12,13 552 1001 552 1001 594.5 970.5 c 0,14,15 636.999 940.001 636.999 940.001 684 927 c 0,16,17 743 909 743 909 765.5 991.5 c 0,18,19 788 1074 788 1074 793 1146 c 0,20,21 791.31 1194.24 l 0,22,23 786.836 1233.11 786.836 1233.11 772.5 1275.5 c 0,24,25 748.997 1345 748.997 1345 689 1378 c 0,26,27 653.011 1395.99 653.011 1395.99 614.5 1397 c 0,28,29 576 1398.01 576 1398.01 580 1334 c 0,30,31 582 1300.99 582 1300.99 610.5 1297.5 c 0,32,33 640.125 1297.91 l 0,34,35 655.135 1300.05 655.135 1300.05 671 1306 c 0,36,37 664.999 1278.99 664.999 1278.99 636.5 1266.5 c 0,38,39 618.241 1258.49 618.241 1258.49 605.122 1258.49 c 0,40,41 597.752 1258.48 597.752 1258.48 592 1261 c 0,42,43 532.006 1283.99 532.006 1283.99 502.5 1321.5 c 0,44,45 473 1359 473 1359 453 1368 c 0,46,47 432.95 1375.16 432.95 1375.16 416.875 1375.14 c 0,48,49 388.049 1375.11 388.049 1375.11 372 1352 c 0,50,51 352 1322 352 1322 350.5 1246.5 c 0,52,53 352.925 1165.25 l 0,54,55 355.829 1127.66 355.829 1127.66 362 1088.5 c 0,56,57 375.001 1005.99 375.001 1005.99 400 935 c 0,58,59 425.001 864 425.001 864 459 842 c 0,0,1 219 40 m 0,36,37 217.856 126.542 l 0,38,39 221.958 253.051 221.958 253.051 260 376.5 c 0,40,41 291.04 477.228 291.04 477.228 290.964 584.069 c 0,42,43 290.915 652.771 290.915 652.771 278 724 c 0,44,45 263 800 263 800 215.5 853.5 c 0,46,47 168.001 906.999 168.001 906.999 158 973 c 0,48,49 157.625 1002.88 l 0,50,51 159.2 1017.98 159.2 1017.98 164 1035.5 c 0,52,53 174.001 1071.99 174.001 1071.99 208 1076 c 0,54,55 194.139 1039.57 194.139 1039.57 193.923 1016.15 c 0,56,57 196.953 996.417 l 0,58,59 203.629 978.699 203.629 978.699 225 975 c 0,60,61 246.691 974.559 l 0,62,63 276.931 980 276.931 980 283 1024 c 0,64,65 282.228 1068.73 l 0,66,67 280.438 1090.45 280.438 1090.45 276.5 1120.5 c 0,68,69 266.999 1193.01 266.999 1193.01 244.5 1258 c 0,70,71 221.997 1323 221.997 1323 186 1354.5 c 0,72,73 173.294 1365.62 173.294 1365.62 158.969 1365.71 c 0,74,75 144.032 1365.81 144.032 1365.81 127.335 1353.92 c 0,76,77 114.674 1344.91 114.674 1344.91 101 1329 c 0,78,79 68.9429 1292.23 68.9429 1292.23 68.889 1247.01 c 0,80,81 68.8857 1244.27 68.8857 1244.27 69 1241.5 c 0,82,83 70.9999 1193.01 70.9999 1193.01 89 1171 c 0,84,85 104.009 1149.99 104.009 1149.99 111 1137 c 0,86,87 117.997 1124 117.997 1124 139 1118 c 0,88,89 85.8527 1124.89 85.8527 1124.89 76 1137 c 0,90,91 66.9851 1149.02 66.9851 1149.02 47 1169 c 0,92,93 28 1206.99 28 1206.99 27 1238 c 0,94,95 26 1269.01 26 1269.01 32 1307 c 0,96,97 42.001 1376.01 42.001 1376.01 79 1420 c 0,98,99 169 1523.01 169 1523.01 248 1547.5 c 0,100,101 321.281 1570.22 321.281 1570.22 448.769 1570.15 c 0,102,103 458.716 1570.14 458.716 1570.14 469 1570 c 0,104,105 609.017 1567 609.017 1567 708.5 1534.5 c 0,106,107 808 1501.99 808 1501.99 929 1422 c 0,108,109 988.991 1381.01 988.991 1381.01 1042 1319 c 0,110,111 1071.32 1284.7 1071.32 1284.7 1071.57 1242.43 c 0,112,113 1071.66 1225.04 1071.66 1225.04 1066.84 1206.3 c 0,114,115 1062.2 1188.27 1062.2 1188.27 1053 1169 c 0,116,117 1025 1111.01 1025 1111.01 956 1104 c 0,118,119 978.832 1141.7 978.832 1141.7 979.109 1171.22 c 0,120,121 975.706 1193.58 l 0,122,123 971.477 1206.24 971.477 1206.24 962 1217 c 0,124,125 952.994 1226.01 952.994 1226.01 924 1232.5 c 0,126,127 895 1238.99 895 1238.99 895 1195 c 0,128,129 893 1118.01 893 1118.01 898 1043.5 c 0,130,131 898.872 971.375 l 0,132,133 897.219 932.389 897.219 932.389 891 893 c 0,134,135 883 845 883 845 841.5 736 c 0,136,137 800 627 800 627 729 600 c 0,138,139 704.81 590.534 704.81 590.534 673.984 590.609 c 0,140,141 646.19 590.677 646.19 590.677 613 598.5 c 0,142,143 543 615 543 615 526 669 c 0,144,145 568.61 646.769 568.61 646.769 613.795 646.846 c 0,146,147 617.39 646.853 617.39 646.853 621 647 c 0,148,149 675 650 675 650 679 678.5 c 0,150,151 676.92 691.447 l 0,152,153 667.063 711.922 667.063 711.922 615 728 c 0,154,155 572 741 572 741 525.5 732 c 0,156,157 479 723 479 723 452 689 c 0,158,159 432 663 432 663 414.5 579.5 c 0,160,161 397 496 397 496 412 436 c 0,162,163 428 362 428 362 444.5 296.5 c 0,164,165 461.001 230.997 461.001 230.997 463 161 c 0,166,167 464 15.9999 464 15.9999 401 -99 c 0,168,169 376.999 -141.002 376.999 -141.002 308.5 -197 c 0,170,171 239.999 -253 239.999 -253 190 -253 c 0,172,173 262 -218.001 262 -218.001 340.5 -113.5 c 0,174,175 419 -8.99995 419 -8.99995 383 78 c 0,176,177 363 124.999 363 124.999 327 121.5 c 0,178,179 291 118.001 291 118.001 264 82 c 0,180,181 251.066 64.7553 251.066 64.7553 251.04 37.4438 c 0,182,183 251.029 26.7444 251.029 26.7444 253 14.5 c 0,184,185 260 -29 260 -29 269 -50 c 0,186,187 220.999 -15.9996 220.999 -15.9996 219 40 c 0,36,37 EndSplineSet KernsSLIF: 45 -104 0 0 46 -221 0 0 44 -208 0 0 116 -195 0 0 322 -299 0 0 97 -299 0 0 EndChar StartChar: q Encoding: 113 113 33 Width: 1161 Flags: W Fore 894 1526 m 1,0,1 939 1548.01 939 1548.01 988 1526 c 0,2,3 1076 1482.01 1076 1482.01 1076 1388 c 0,4,5 1076 1319.99 1076 1319.99 1035.5 1151.5 c 0,6,7 995.011 983.049 995.011 983.049 982 920 c 0,8,9 976 893 976 893 973 854.5 c 0,10,11 970 816 970 816 1005 813 c 0,12,13 1025.76 814.377 l 0,14,15 1058.35 822.828 1058.35 822.828 1058.55 874.124 c 0,16,17 1058.58 881.159 1058.58 881.159 1058 889 c 0,18,19 1084.77 857.216 1084.77 857.216 1084.79 810.971 c 0,20,21 1084.81 774.286 1084.81 774.286 1068 728.5 c 0,22,23 1030 624.986 1030 624.986 1030 539 c 0,24,25 1030 452 1030 452 1057 408 c 0,26,27 1084 364 1084 364 1078 313 c 0,28,29 1069 237.011 1069 237.011 1032.5 176 c 0,30,31 1011.58 141.039 1011.58 141.039 973.09 140.897 c 0,32,33 946.128 140.797 946.128 140.797 910.547 157.778 c 0,34,35 908.291 158.855 908.291 158.855 906 160 c 0,36,37 997 161.999 997 161.999 986.5 227.5 c 0,38,39 976 293 976 293 940 293 c 0,40,41 924.998 291.999 924.998 291.999 890 261 c 0,42,43 855 229.999 855 229.999 855 191 c 0,44,45 854 138.001 854 138.001 876 122 c 0,46,47 897.996 106.003 897.996 106.003 926.5 90 c 0,48,49 955 73.9999 955 73.9999 981.5 40.5 c 0,50,51 1008.01 6.99366 1008.01 6.99366 1016 -79 c 0,52,53 985 -1 985 -1 920.5 42 c 0,54,55 856 85.0001 856 85.0001 835 26 c 0,56,57 820 -13 820 -13 902.5 -103 c 0,58,59 985 -193 985 -193 1095 -199 c 0,60,61 1038.78 -196.757 l 0,62,63 961.445 -188.18 961.445 -188.18 897.5 -149 c 0,64,65 811 -96.0005 811 -96.0005 754 -39 c 0,66,67 703 10 703 10 704 62.5 c 0,68,69 705 115 705 115 683 124 c 0,70,71 671.055 128.52 671.055 128.52 660.204 128.453 c 0,72,73 637.445 128.315 637.445 128.315 619.5 108 c 0,74,75 593 78 593 78 533 67 c 0,76,77 296 22 296 22 276 156 c 0,78,79 332 109.001 332 109.001 375.5 127.5 c 0,80,81 419 145.999 419 145.999 391 207 c 0,82,83 384 220.999 384 220.999 333 351 c 0,84,85 282 481 282 481 244 478 c 0,86,87 190.301 472.63 190.301 472.63 189.566 432.54 c 0,88,89 193.349 407.215 l 0,90,91 193.662 406.115 193.662 406.115 194 405 c 0,92,93 213.999 339 213.999 339 265 339 c 0,94,95 248.288 325.169 248.288 325.169 231.244 325.121 c 0,96,97 218.712 325.085 218.712 325.085 206 332.5 c 0,98,99 175.998 350.001 175.998 350.001 170 357 c 0,100,101 138.31 395.028 138.31 395.028 138.359 449.918 c 0,102,103 138.38 472.972 138.38 472.972 144 499 c 0,104,105 155.998 553.993 155.998 553.993 207.5 709.5 c 0,106,107 258.999 865 258.999 865 242 913 c 0,108,109 230.225 942.439 230.225 942.439 188.5 942.5 c 0,110,111 147 942 147 942 138 903 c 0,112,113 135.388 876.036 l 0,114,115 137.633 831.849 137.633 831.849 191 824 c 0,116,117 176 803 176 803 122 821 c 0,118,119 68 839 68 839 69 907 c 0,120,121 72.0001 1046.01 72.0001 1046.01 168 1147 c 0,122,123 263.993 1247.99 263.993 1247.99 311 1361 c 0,124,125 314.463 1377.59 l 0,126,127 314.082 1394.93 314.082 1394.93 293.5 1404 c 0,128,129 280.413 1405.97 l 0,130,131 254.722 1403.08 254.722 1403.08 220 1351 c 0,132,133 224.001 1422 224.001 1422 270.5 1455 c 0,134,135 316.989 1487.99 316.989 1487.99 374 1502.5 c 0,136,137 431 1517.01 431 1517.01 482 1523.5 c 0,138,139 532.995 1529.99 532.995 1529.99 548 1548 c 0,140,141 556.237 1558.37 556.237 1558.37 556.563 1567.91 c 0,142,143 553.491 1580.23 l 0,144,145 545.526 1594.7 545.526 1594.7 517 1607 c 0,146,147 459 1632.01 459 1632.01 408 1580 c 0,148,149 414 1645.99 414 1645.99 485 1659 c 0,150,151 518.084 1665.06 518.084 1665.06 542.705 1665.04 c 0,152,153 570.911 1665.01 570.911 1665.01 588 1657 c 0,154,155 646.008 1630 646.008 1630 681 1590 c 0,156,-1 732 1531 l 0,157,158 785.011 1462.99 785.011 1462.99 864.5 1431 c 0,159,160 902.895 1415.55 902.895 1415.55 928.109 1415.49 c 0,161,162 955.109 1415.42 955.109 1415.42 967 1433 c 0,163,164 992 1470.01 992 1470.01 960.5 1496 c 0,165,166 929 1521.99 929 1521.99 894 1526 c 0,167,-1 894 1526 l 1,0,1 714 1394 m 1,101,102 629.017 1394 629.017 1394 539 1366.5 c 0,103,104 449 1339.01 449 1339.01 420 1278 c 0,105,106 413.818 1265.02 413.818 1265.02 413.751 1247.07 c 0,107,108 413.709 1235.98 413.709 1235.98 416 1223 c 0,109,110 422 1188.99 422 1188.99 461 1205 c 0,111,112 499 1220 499 1220 494 1257.5 c 0,113,114 489.001 1295 489.001 1295 472 1298 c 0,115,116 494.625 1295.06 l 0,117,118 524.25 1285.5 524.25 1285.5 528 1245 c 0,119,120 526.001 1211.45 l 0,121,122 519.32 1176.2 519.32 1176.2 492.5 1156 c 0,123,124 454.022 1127.02 454.022 1127.02 418 1083 c 0,125,126 406 1068 406 1068 372 943.5 c 0,127,128 347.868 855.136 347.868 855.136 347.917 796.743 c 0,129,130 347.937 772.865 347.937 772.865 352 754 c 0,131,132 368 676 368 676 431 615 c 0,133,134 494 554 494 554 494 459 c 0,135,136 494 446.001 494 446.001 480 436 c 0,137,138 466 426 466 426 451 435 c 0,139,140 462.186 437.581 462.186 437.581 462.266 451.639 c 0,141,142 462.279 453.919 462.279 453.919 462 456.5 c 0,143,144 460 475 460 475 448 477 c 0,145,146 415 479 415 479 409 417.5 c 0,147,148 403 356 403 356 459 317 c 0,149,150 543 254 543 254 606 284 c 0,151,152 656 306 656 306 647 353 c 0,153,154 638 400 638 400 584 430 c 0,155,156 665 426 665 426 676.5 381 c 0,157,158 688 336 688 336 742 333 c 0,159,160 775 330 775 330 792 361 c 0,161,162 809 392 809 392 809 407 c 0,163,164 806 469 806 469 732 451 c 0,165,166 693 440 693 440 718 395 c 0,167,168 684 401 684 401 691 455 c 0,169,170 698 509 698 509 724 521 c 0,171,172 752.003 533.001 752.003 533.001 808.5 549.5 c 0,173,174 865 566 865 566 886 619 c 0,175,176 906 672 906 672 888 854.5 c 0,177,178 870 1037 870 1037 777 1157 c 0,179,180 757.882 1180.9 757.882 1180.9 758 1225 c 0,181,182 759 1268.01 759 1268.01 788 1273 c 0,183,184 780.325 1258.24 780.325 1258.24 780.318 1246.44 c 0,185,186 780.313 1238.26 780.313 1238.26 784 1231.5 c 0,187,188 793 1215 793 1215 820 1224 c 0,189,190 848 1233 848 1233 848 1276 c 0,191,192 848 1319 848 1319 828 1343 c 0,193,194 784 1391 784 1391 714 1394 c 1,101,102 EndSplineSet EndChar StartChar: r Encoding: 114 114 58 Width: 1124 Flags: HMW VStem: 91 270<64 1451> Fore 955 37 m 0,0,1 952 91 952 91 911.5 135 c 0,2,3 870.999 179 870.999 179 819 191 c 0,4,5 794.703 192.621 l 0,6,7 770.125 190 770.125 190 755 168 c 0,8,9 745.623 154.361 745.623 154.361 745.693 141.266 c 0,10,11 745.787 123.639 745.787 123.639 763 107 c 0,12,13 789 80 789 80 804 91.5 c 0,14,15 819 103 819 103 834 124 c 0,16,17 849 52 849 52 786 35 c 0,18,19 723 18 723 18 687 71 c 0,20,21 657.999 113.002 657.999 113.002 650 167.5 c 0,22,23 642 221.999 642 221.999 629 268 c 0,24,25 605 346 605 346 541.5 461.5 c 0,26,27 478 577 478 577 396 594 c 0,28,29 366 600 366 600 324 584 c 0,30,31 282 568 282 568 282 504 c 0,32,33 282 388 282 388 319 283 c 0,34,35 356 178 356 178 349 52 c 0,36,37 345 -12 345 -12 286 -82.5 c 0,38,39 227.001 -152.999 227.001 -152.999 166 -175 c 0,40,41 73 -208 73 -208 -6 -196 c 0,42,43 48 -188.001 48 -188.001 113 -160 c 0,44,45 149.001 -141.999 149.001 -141.999 206.5 -91 c 0,46,47 263.999 -40 263.999 -40 268 35 c 0,48,49 267.157 86.4993 l 0,50,51 264.878 110.469 264.878 110.469 259 133 c 0,52,53 247.316 177.79 247.316 177.79 183 178 c 0,54,55 132.68 176.027 132.68 176.027 132.5 103 c 0,56,57 132.999 30.0002 132.999 30.0002 184 11 c 0,58,59 139 9 139 9 119.5 27.5 c 0,60,61 100 46 100 46 91 64 c 0,62,63 46 143.001 46 143.001 96.5 293 c 0,64,65 146.998 442.991 146.998 442.991 166 525 c 0,66,67 187 621 187 621 166 636.5 c 0,68,69 156.351 643.621 156.351 643.621 147.758 643.671 c 0,70,71 137.649 643.73 137.649 643.73 129 634 c 0,72,73 113.001 616.001 113.001 616.001 110.5 587 c 0,74,75 107.999 558 107.999 558 123 546 c 0,76,77 64.9999 548 64.9999 548 58.5 598.5 c 0,78,79 52 649 52 649 59 679 c 0,80,81 71 730 71 730 105 787 c 0,82,83 139.001 844 139.001 844 153 896 c 0,84,85 167.911 959.375 167.911 959.375 167.814 1022.19 c 0,86,87 167.781 1043.63 167.781 1043.63 166 1065 c 0,88,89 155.002 1181.99 155.002 1181.99 136 1306 c 0,90,91 132.713 1352.23 l 0,92,93 134.048 1449.51 134.048 1449.51 207 1533 c 0,94,95 277.995 1615 277.995 1615 419.5 1625.5 c 0,96,97 561 1636 561 1636 567 1480 c 0,98,99 533 1558 533 1558 442.5 1553.5 c 0,100,101 360.829 1549.44 360.829 1549.44 360.191 1469.23 c 0,102,103 360.122 1460.56 360.122 1460.56 361 1451 c 0,104,105 366 1387.99 366 1387.99 491.5 1375.5 c 0,106,107 547.456 1373.25 l 0,108,109 617.51 1376 617.51 1376 619 1414 c 0,110,111 616.188 1429.37 l 0,112,113 607.359 1448.45 607.359 1448.45 570.946 1448.57 c 0,114,115 564.416 1448.59 564.416 1448.59 557 1448 c 0,116,117 588.229 1465.3 588.229 1465.3 621.879 1465.4 c 0,118,119 654.905 1465.5 654.905 1465.5 690.262 1449.03 c 0,120,121 693.869 1447.35 693.869 1447.35 697.5 1445.5 c 0,122,123 773.003 1406.99 773.003 1406.99 802 1323 c 0,124,125 823 1257 823 1257 854.5 1237.5 c 0,126,127 886 1218 886 1218 940 1170 c 0,128,129 964.001 1147.99 964.001 1147.99 973 1098.5 c 0,130,131 982 1049 982 1049 926 1019 c 0,132,133 964 1061 964 1061 938 1095.5 c 0,134,135 921.406 1117.52 921.406 1117.52 906.846 1118.56 c 0,136,137 894.877 1115.67 l 0,138,139 892.918 1114.55 892.918 1114.55 891 1113 c 0,140,141 877.293 1101.25 877.293 1101.25 877.365 1072.37 c 0,142,143 877.441 1042.25 877.441 1042.25 892.5 993.5 c 0,144,145 922 898 922 898 900 805 c 0,146,147 879 719 879 719 799.5 707 c 0,148,149 720 695 720 695 687 725 c 0,150,151 721 725 721 725 748 745 c 0,152,153 768.483 760.172 768.483 760.172 768.823 785.704 c 0,154,155 767 803 l 0,156,157 755 863 755 863 684 802.5 c 0,158,159 622.198 749.838 622.198 749.838 621.768 695.282 c 0,160,161 621.704 687.162 621.704 687.162 623 679 c 0,162,163 628 642 628 642 678.5 602.5 c 0,164,165 714.169 574.601 714.169 574.601 735.12 574.389 c 0,166,167 743.832 574.301 743.832 574.301 750 579 c 0,168,169 767 593 767 593 753 613.5 c 0,170,171 739 634 739 634 703 634 c 0,172,173 706.918 659.463 706.918 659.463 751.5 659.5 c 0,174,175 796 659 796 659 817 635 c 0,176,177 845 602 845 602 837.5 533 c 0,178,179 830 464 830 464 830 422 c 0,180,181 830 331.001 830 331.001 895 304.5 c 0,182,183 960 278 960 278 1008 210 c 0,184,185 1044.01 154.989 1044.01 154.989 1056.5 81 c 0,186,187 1063.49 39.6195 1063.49 39.6195 1063.44 4.82321 c 0,188,189 1063.41 -22.6343 1063.41 -22.6343 1059 -46 c 0,190,191 1012.01 -279.997 1012.01 -279.997 833 -375 c 0,192,193 654 -470 654 -470 447 -500 c 0,194,195 651 -443 651 -443 809 -321.5 c 0,196,197 967 -200 967 -200 955 37 c 0,0,1 502 848 m 0,122,123 524 824 524 824 556 836 c 0,124,125 588 848 588 848 624 872 c 0,126,127 708 930 708 930 720 1081.5 c 0,128,129 721.045 1138.14 l 0,130,131 716.188 1217.67 716.188 1217.67 668.868 1217.71 c 0,132,133 661.895 1217.72 661.895 1217.72 654 1216 c 0,134,135 621 1208.01 621 1208.01 618 1181.5 c 0,136,137 619.974 1168.14 l 0,138,139 627.885 1149.33 627.885 1149.33 665 1133 c 0,140,141 627.903 1130.74 l 0,142,143 584.539 1132.87 584.539 1132.87 560.5 1160.5 c 0,144,145 527.011 1198.99 527.011 1198.99 492 1220 c 0,146,147 456.982 1241.43 456.982 1241.43 425.381 1241.41 c 0,148,149 396.515 1241.4 396.515 1241.4 370.5 1223.5 c 0,150,151 315.999 1186 315.999 1186 290 1108 c 0,152,153 276.999 1070.99 276.999 1070.99 269.5 953 c 0,154,155 269.879 905.901 l 0,156,157 277.054 832.123 277.054 832.123 330 822 c 0,158,159 394 808 394 808 391 879 c 0,160,161 387.786 911.935 387.786 911.935 350.375 911.961 c 0,162,163 341.213 911.967 341.213 911.967 330 910 c 0,164,165 327 927 327 927 359.5 939 c 0,166,167 392 951 392 951 409 941 c 0,168,169 472 898 472 898 464.5 896.5 c 0,170,171 457 895 457 895 502 848 c 0,122,123 EndSplineSet KernsSLIF: 121 -156 0 0 115 -182 0 0 103 -104 0 0 116 -339 0 0 118 -43 0 0 119 -150 0 0 EndChar StartChar: s Encoding: 115 115 25 Width: 1163 Flags: HW Fore 509 51 m 0,0,1 494 57 494 57 471.5 79 c 0,2,3 449 101 449 101 453 122 c 0,4,-1 495.5 92.5 l 0,5,6 517 77.0001 517 77.0001 538 93 c 0,7,8 553.149 104.584 553.149 104.584 553.111 115.871 c 0,9,10 553.064 129.916 553.064 129.916 529.5 143.5 c 0,11,12 487 167.999 487 167.999 420 191.5 c 0,13,-1 286.5 238 l 0,14,15 220 261 220 261 205 285 c 0,16,17 181 321 181 321 187 375.5 c 0,18,19 193 430.001 193 430.001 241 441 c 0,20,21 233.001 324 233.001 324 343 358 c 0,22,23 379 369 379 369 372 414 c 0,24,25 365 459 365 459 353 483 c 0,26,27 327 534 327 534 258 563 c 0,28,29 188.998 592 188.998 592 134 601 c 0,30,31 96.4745 601.959 l 0,32,33 84.3876 601.016 84.3876 601.016 72 598.5 c 0,34,-1 8 586 l 0,35,36 67.4219 631.557 67.4219 631.557 112 631.5 c 0,37,38 156 631 156 631 171 630 c 0,39,40 212.002 627 212.002 627 278.5 599 c 0,41,42 345 571 345 571 373 545 c 0,43,44 420.001 499.999 420.001 499.999 465.5 423 c 0,45,46 511 346 511 346 567 302 c 0,47,48 599 275 599 275 666.5 261 c 0,49,50 689 256.333 689 256.333 707.667 256.333 c 0,51,52 745 256.333 745 256.333 767 275 c 0,53,54 849 347 849 347 861.5 443 c 0,55,56 874 539 874 539 844 610 c 0,57,58 828.999 645.001 828.999 645.001 760.5 693.5 c 0,59,60 692 742 692 742 642 745 c 0,61,62 582 748 582 748 582 710 c 0,63,64 582 667 582 667 600 657.5 c 0,65,-1 650 630 l 0,66,67 605 613 605 613 562.5 634.5 c 0,68,69 520 656 520 656 504 696 c 0,70,-1 465 789.5 l 0,71,72 434 864 434 864 392 943.5 c 0,73,74 350 1023 350 1023 304 1081.5 c 0,75,76 266.656 1128.99 266.656 1128.99 233.93 1129.36 c 0,77,78 226.341 1129.45 226.341 1129.45 219 1127 c 0,79,80 188.007 1116.35 188.007 1116.35 188 1063.5 c 0,81,82 189 1011 189 1011 219 1004 c 0,83,84 196.609 1001.73 l 0,85,86 170.282 1003.7 170.282 1003.7 155.5 1032 c 0,87,88 136 1071 136 1071 136 1089 c 0,89,90 136 1144 136 1144 148.5 1184.5 c 0,91,92 160.999 1225 160.999 1225 182 1267 c 0,93,94 231.001 1368 231.001 1368 351 1456 c 0,95,96 471 1544.01 471 1544.01 521 1573 c 0,97,98 587 1612 587 1612 649.5 1637.5 c 0,99,100 678.818 1649.46 678.818 1649.46 728.714 1649.43 c 0,101,102 785.176 1649.39 785.176 1649.39 868 1634 c 0,103,104 955.012 1617.99 955.012 1617.99 1003 1567.5 c 0,105,106 1051.01 1516.99 1051.01 1516.99 1056 1476 c 0,107,108 1013.4 1532.09 1013.4 1532.09 946.088 1532.22 c 0,109,110 918.604 1532.28 918.604 1532.28 887 1523 c 0,111,112 851 1511 851 1511 833.5 1473.5 c 0,113,114 819.161 1442.77 819.161 1442.77 819.256 1410.37 c 0,115,116 819.277 1403.23 819.277 1403.23 820 1396 c 0,117,118 829 1279 829 1279 945 1291 c 0,119,120 1061.01 1303 1061.01 1303 1138 1327 c 0,121,122 1091 1261.99 1091 1261.99 1004 1243.5 c 0,123,124 945.303 1231.02 945.303 1231.02 908.464 1231.06 c 0,125,126 890.69 1231.07 890.69 1231.07 878 1234 c 0,127,128 803 1250.01 803 1250.01 768 1286.5 c 0,129,130 732.944 1323.05 732.944 1323.05 683 1367 c 0,131,132 648.004 1397.71 648.004 1397.71 602.286 1397.82 c 0,133,134 584.001 1397.86 584.001 1397.86 564 1393 c 0,135,136 494 1376.01 494 1376.01 464 1312 c 0,137,138 442.001 1264 442.001 1264 433.5 1173.5 c 0,139,140 425 1083.01 425 1083.01 473 1046 c 0,141,142 567 971 567 971 609.5 983.5 c 0,143,144 635.732 991.215 635.732 991.215 669.393 991.121 c 0,145,146 690.268 991.062 690.268 991.062 714 988 c 0,147,148 749 983 749 983 784.5 953.5 c 0,149,150 820 924 820 924 801 876 c 0,151,152 778 934 778 934 751.5 937 c 0,153,154 725 940 725 940 710 921 c 0,155,156 703.558 912.65 703.558 912.65 703.463 902.677 c 0,157,158 703.364 892.286 703.364 892.286 710.156 880.133 c 0,159,160 724.167 855.064 724.167 855.064 767.5 822.5 c 0,161,162 852 759 852 759 885 749 c 0,163,164 912 740 912 740 944.5 746.5 c 0,165,166 957.24 749.048 957.24 749.048 957.149 759.202 c 0,167,168 957.008 774.952 957.008 774.952 926 809 c 0,169,170 995 803 995 803 1002.5 737.5 c 0,171,172 1006.09 675.401 l 0,173,174 1005.75 651.29 1005.75 651.29 1002 633 c 0,175,176 994 600 994 600 982.5 508.5 c 0,177,178 971 417 971 417 998 358 c 0,179,180 1019 310 1019 310 1040 298.5 c 0,181,182 1061 286.999 1061 286.999 1073 214 c 0,183,184 1071.38 184.394 l 0,185,186 1067.63 161.887 1067.63 161.887 1057 130 c 0,187,188 1037.99 72.9995 1037.99 72.9995 975 67 c 0,189,190 985.997 86.995 985.997 86.995 1019.5 137 c 0,191,192 1030.29 153.102 1030.29 153.102 1030.65 164.951 c 0,193,194 1027.91 176.689 l 0,195,196 1019.57 191.491 1019.57 191.491 986 196 c 0,197,198 959 199 959 199 935 161.5 c 0,199,200 911 124 911 124 908 120 c 0,201,202 854 37.0001 854 37.0001 726 23 c 0,203,204 659.279 19.5269 l 0,205,206 573.801 20.4195 573.801 20.4195 509 51 c 0,0,1 EndSplineSet KernsSLIF: 99 -52 0 0 115 -104 0 0 116 -78 0 0 EndChar StartChar: t Encoding: 116 116 84 Width: 1471 Flags: HMW HStem: 1266 219.5<365 1069.5> VStem: 624 185.5<219 1233.5> Fore 624 219 m 0,0,1 642.376 322.018 642.376 322.018 642.302 416.663 c 0,2,3 642.244 491.983 642.244 491.983 630.5 562 c 0,4,5 604 720 604 720 562 888 c 0,6,7 553 921 553 921 563 987 c 0,8,9 572.193 1047.67 572.193 1047.67 616.886 1048.34 c 0,10,11 620.807 1048.4 620.807 1048.4 625 1048 c 0,12,13 616.998 1048 616.998 1048 607 1029 c 0,14,15 597 1009.99 597 1009.99 597 1002 c 0,16,17 599 963.001 599 963.001 629.5 959 c 0,18,19 641.54 960.523 l 0,20,21 657.957 968.155 657.957 968.155 658.121 1008.79 c 0,22,23 658.137 1012.74 658.137 1012.74 658 1017 c 0,24,25 656.003 1055.96 656.003 1055.96 647 1181.5 c 0,26,27 639.493 1286.18 639.493 1286.18 588.846 1287.54 c 0,28,29 567 1284 l 0,30,31 554.021 1280 554.021 1280 476 1274 c 0,32,33 397.691 1267.98 397.691 1267.98 365 1266 c 0,34,35 299 1263 299 1263 245.5 1300.5 c 0,36,37 210.991 1324.69 210.991 1324.69 210.807 1365.73 c 0,38,39 210.708 1387.86 210.708 1387.86 221 1416 c 0,40,41 221 1344.01 221 1344.01 259 1340 c 0,42,43 283.415 1340.61 l 0,44,45 310.784 1345.98 310.784 1345.98 311.168 1375.6 c 0,46,47 311.254 1382.2 311.254 1382.2 310 1390 c 0,48,49 301 1445.99 301 1445.99 269 1456 c 0,50,51 189.025 1479.99 189.025 1479.99 142 1484 c 0,52,53 113.297 1482.43 l 0,54,55 75.4871 1475.66 75.4871 1475.66 27 1445 c 0,56,57 46 1488.99 46 1488.99 95.5 1506.5 c 0,58,59 137.72 1521.43 137.72 1521.43 172.316 1521.44 c 0,60,61 178.271 1521.44 178.271 1521.44 184 1521 c 0,62,63 358 1506 358 1506 570 1483.5 c 0,64,65 782 1461 782 1461 932 1470 c 0,66,67 1011.07 1474.01 1011.07 1474.01 1069.5 1485.5 c 0,68,69 1104.15 1492.31 1104.15 1492.31 1144.26 1492.28 c 0,70,71 1171.84 1492.26 1171.84 1492.26 1202 1489 c 0,72,73 1287.72 1478.71 1287.72 1478.71 1288.21 1436.1 c 0,74,75 1286 1421 l 0,76,77 1272.84 1374.96 1272.84 1374.96 1270 1376 c 0,78,79 1266.61 1438.7 1266.61 1438.7 1221.94 1439.3 c 0,80,81 1204.5 1437.5 l 0,82,83 1143.01 1425.01 1143.01 1425.01 1136 1401 c 0,84,85 1131.97 1388.36 1131.97 1388.36 1131.98 1377.27 c 0,86,87 1132.03 1347.14 1132.03 1347.14 1162 1328.5 c 0,88,89 1202.99 1303 1202.99 1303 1257 1303 c 0,90,91 1311 1303 1311 1303 1355.5 1332.5 c 0,92,93 1392.39 1356.95 1392.39 1356.95 1392.51 1405.11 c 0,94,95 1392.54 1415.05 1392.54 1415.05 1391 1426 c 0,96,97 1394.7 1412.33 1394.7 1412.33 1394.7 1396.19 c 0,98,99 1394.72 1368.69 1394.72 1368.69 1384 1334 c 0,100,101 1367.01 1279 1367.01 1279 1286 1255 c 0,102,103 1209.95 1231.81 1209.95 1231.81 1143.93 1231.74 c 0,104,105 1087.56 1231.69 1087.56 1231.69 1038.5 1248.5 c 0,106,107 931.985 1285 931.985 1285 848 1285 c 0,108,109 810 1285 810 1285 809.5 1233.5 c 0,110,111 812.56 1134.13 l 0,112,113 812.772 1131.07 812.772 1131.07 813 1128 c 0,114,-1 820.5 1062 l 0,115,116 828 996 828 996 900 901 c 0,117,118 933 856 933 856 915 750 c 0,119,120 897 644 897 644 814 656 c 0,121,122 874 656 874 656 868 747.5 c 0,123,124 862 839 862 839 820 803 c 0,125,126 789 777.001 789 777.001 784 755.5 c 0,127,128 781.13 743.159 781.13 743.159 781.225 717.148 c 0,129,130 781.296 697.84 781.296 697.84 783 671 c 0,131,132 792 520.002 792 520.002 825.5 433.5 c 0,133,134 859 347 859 347 853 158 c 0,135,136 847 17 847 17 757 -3 c 0,137,138 808 55 808 55 800 89.5 c 0,139,140 792 124 792 124 763.5 129.5 c 0,141,142 744.112 129.608 l 0,143,144 725.165 126.183 725.165 126.183 706 109 c 0,145,146 684.494 89.7188 684.494 89.7188 684.436 50.0908 c 0,147,148 684.416 36.2807 684.416 36.2807 687 20 c 0,149,150 709.999 -130.999 709.999 -130.999 754.5 -171 c 0,151,-1 828 -238 l 0,152,153 706 -212 706 -212 654.5 -55.5 c 0,154,155 603 101 603 101 624 219 c 0,0,1 EndSplineSet KernsSLIF: 322 -326 0 0 117 -117 0 0 104 -169 0 0 45 -221 0 0 46 -260 0 0 44 -260 0 0 243 -208 0 0 115 -208 0 0 111 -182 0 0 97 -448 0 0 EndChar StartChar: u Encoding: 117 117 67 Width: 1204 Flags: W Fore 46 335 m 0,0,1 -12 419 -12 419 50.5 484.5 c 0,2,3 113 550 113 550 146 550 c 0,4,5 107 520 107 520 95 443.5 c 0,6,7 83 367 83 367 171 394 c 0,8,9 196.001 402 196.001 402 204 489 c 0,10,11 208.642 539.483 208.642 539.483 208.57 585.923 c 0,12,13 208.518 619.519 208.518 619.519 206 651 c 0,14,15 198.001 728.999 198.001 728.999 158.5 773 c 0,16,17 147.119 785.678 147.119 785.678 140.179 786.152 c 0,18,19 134.174 783.358 l 0,20,21 129.301 777.2 129.301 777.2 129.337 757.553 c 0,22,23 129.368 740.725 129.368 740.725 133 714 c 0,24,25 81.8411 754.35 81.8411 754.35 81.5628 831.304 c 0,26,27 81.4631 858.861 81.4631 858.861 87.8877 891.11 c 0,28,29 88.4213 893.788 88.4213 893.788 89 896.5 c 0,30,31 116 1023 116 1023 106 1188 c 0,32,33 103.71 1273.97 l 0,34,35 106.169 1385.74 106.169 1385.74 140 1454.5 c 0,36,37 186.008 1548.01 186.008 1548.01 245 1590.5 c 0,38,39 303.999 1632.99 303.999 1632.99 355.5 1640 c 0,40,41 405.982 1646.87 405.982 1646.87 406 1647 c 0,42,43 337.006 1635 337.006 1635 274.5 1567 c 0,44,45 212.006 1499.01 212.006 1499.01 185 1425 c 0,46,47 170.414 1385.03 170.414 1385.03 170.42 1350.16 c 0,48,49 170.425 1320.48 170.425 1320.48 181 1294.5 c 0,50,51 200.164 1247.42 200.164 1247.42 274.889 1247.21 c 0,52,53 289.833 1247.17 289.833 1247.17 307 1249 c 0,54,55 359.668 1254.35 359.668 1254.35 359.608 1300.76 c 0,56,57 359.589 1315.16 359.589 1315.16 354.5 1333.5 c 0,58,59 335.326 1402.62 335.326 1402.62 276.773 1402.94 c 0,60,61 269.676 1402.97 269.676 1402.97 262 1402 c 0,62,63 286.672 1406.42 286.672 1406.42 306.953 1406.43 c 0,64,65 396.829 1406.48 396.829 1406.48 400.5 1320 c 0,66,67 400.121 1249.19 l 0,68,69 396.789 1203.44 396.789 1203.44 384 1187 c 0,70,71 304 1085 304 1085 299.5 912.5 c 0,72,73 295 740 295 740 303 615 c 0,74,75 307.999 531.003 307.999 531.003 343 441 c 0,76,77 378 351 378 351 454 381 c 0,78,79 508 402 508 402 466 449 c 0,80,81 424 496 424 496 403 440 c 0,82,83 400.021 467.968 l 0,84,85 401.42 496.722 401.42 496.722 426 505.5 c 0,86,87 461 518 461 518 482 512 c 0,88,89 561.579 485.473 561.579 485.473 561.729 423.945 c 0,90,91 561.737 420.526 561.737 420.526 561.5 417 c 0,92,93 557 350 557 350 553 329 c 0,94,95 551.037 308.068 l 0,96,97 553.844 275.341 553.844 275.341 595.5 250.5 c 0,98,99 610.331 241.656 610.331 241.656 628.383 241.735 c 0,100,101 676.669 241.947 676.669 241.947 748 306 c 0,102,103 763 319 763 319 797 375 c 0,104,105 830.998 430.995 830.998 430.995 853 497 c 0,106,107 875 563 875 563 869.5 623 c 0,108,109 863.999 683 863.999 683 800 707 c 0,110,111 780.712 710.301 l 0,112,113 758.425 708.952 758.425 708.952 758.366 675.576 c 0,114,115 758.361 672.891 758.361 672.891 758.5 670 c 0,116,117 761 617.999 761 617.999 798 594 c 0,118,119 711.001 634.999 711.001 634.999 705.5 715 c 0,120,121 700 795 700 795 728.5 892.5 c 0,122,123 757 990 757 990 795.5 1095 c 0,124,125 834 1200 834 1200 835 1292 c 0,126,127 835 1305.01 835 1305.01 852.5 1409 c 0,128,129 867.429 1497.72 867.429 1497.72 946.032 1497.66 c 0,130,131 959.572 1497.64 959.572 1497.64 975 1495 c 0,132,133 951.995 1495 951.995 1495 926.5 1468.5 c 0,134,135 911.116 1452.51 911.116 1452.51 910.836 1433.8 c 0,136,137 914.401 1414.21 l 0,138,139 915.524 1411.14 915.524 1411.14 917 1408 c 0,140,141 937.073 1367.26 937.073 1367.26 962.372 1366.61 c 0,142,143 978.379 1369.98 l 0,144,145 988.798 1374.48 988.798 1374.48 1000 1385 c 0,146,147 1024 1406.6 1024 1406.6 1024.06 1454.48 c 0,148,149 1024.1 1486.4 1024.1 1486.4 1013.5 1530 c 0,150,151 987 1639.01 987 1639.01 850 1617 c 0,152,153 950 1666.99 950 1666.99 1035.5 1573.5 c 0,154,155 1080.31 1524.5 1080.31 1524.5 1080.48 1450.07 c 0,156,157 1080.58 1406.75 1080.58 1406.75 1065.56 1354.82 c 0,158,159 1057.15 1325.76 1057.15 1325.76 1044 1294 c 0,160,161 1013.95 1220.87 1013.95 1220.87 979 1119.5 c 0,162,163 944 1017.99 944 1017.99 941 959 c 0,164,165 936 887 936 887 974 864 c 0,166,167 997.65 849.686 997.65 849.686 1019.56 849.509 c 0,168,169 1031.83 849.41 1031.83 849.41 1045.5 854.5 c 0,170,171 1079 868.002 1079 868.002 1085 913 c 0,172,173 1091 958 1091 958 1022 1023 c 0,174,175 1143.01 1012 1143.01 1012 1145 909 c 0,176,177 1142.12 849.83 l 0,178,179 1133.28 771.826 1133.28 771.826 1098 684 c 0,180,181 1048.99 561.998 1048.99 561.998 984 456.5 c 0,182,183 919 351 919 351 906 335 c 0,184,185 872.999 294.998 872.999 294.998 847.5 240 c 0,186,187 840.928 225.825 840.928 225.825 840.965 216.299 c 0,188,189 841.041 196.841 841.041 196.841 868.696 196.786 c 0,190,191 880.031 196.763 880.031 196.763 896 200 c 0,192,193 930.895 206.264 930.895 206.264 931.366 231.74 c 0,194,195 931.421 234.737 931.421 234.737 931 238 c 0,196,197 927 269 927 269 913 308 c 0,198,199 977.209 274.007 977.209 274.007 977.222 212.054 c 0,200,201 977.226 191.993 977.226 191.993 970.5 169 c 0,202,203 943.001 75.0001 943.001 75.0001 865 74 c 0,204,205 732.561 75.6253 l 0,206,207 459.222 87.5019 459.222 87.5019 292.5 172 c 0,208,209 88.0008 275.999 88.0008 275.999 46 335 c 0,0,1 EndSplineSet KernsSLIF: 116 -78 0 0 120 -104 0 0 EndChar StartChar: v Encoding: 118 118 70 Width: 1087 Flags: W Fore 305 1015 m 1,0,1 390 991 390 991 393 922.5 c 0,2,3 393.509 829.461 l 0,4,5 392.953 816.677 392.953 816.677 392 805 c 0,6,7 386 748 386 748 378.5 703.5 c 0,8,9 377.807 678.574 l 0,10,11 381.441 653.166 381.441 653.166 405 640 c 0,12,13 413.621 635.115 413.621 635.115 420.879 634.937 c 0,14,15 431.632 637.67 l 0,16,17 441.986 643.7 441.986 643.7 448.5 663 c 0,18,19 462 703 462 703 466.5 760 c 0,20,21 471 817 471 817 470 870.5 c 0,22,23 469 923.975 469 923.975 469 934 c 0,24,25 469 1002 469 1002 473.5 1056.5 c 0,26,27 478.001 1111.01 478.001 1111.01 499 1176 c 0,28,29 514.003 1223 514.003 1223 546.5 1260.5 c 0,30,31 578.993 1297.99 578.993 1297.99 605 1311 c 0,32,33 619 1313.94 l 0,34,35 626.997 1313.57 626.997 1313.57 635 1308.5 c 0,36,37 650 1299.01 650 1299.01 650 1287 c 0,38,39 637.454 1293.55 637.454 1293.55 628.479 1293.58 c 0,40,41 606.104 1293.67 606.104 1293.67 605.918 1253.32 c 0,42,43 605.905 1250.51 605.905 1250.51 606 1247.5 c 0,44,45 608 1184 608 1184 634 1184 c 0,46,47 662 1184 662 1184 673.5 1211 c 0,48,49 685 1238 685 1238 685 1259 c 0,50,51 685 1341.01 685 1341.01 698.5 1403 c 0,52,53 712.006 1465.02 712.006 1465.02 734 1540 c 0,54,55 740.003 1566.01 740.003 1566.01 763 1593.5 c 0,56,57 786.018 1621.02 786.018 1621.02 799 1633 c 0,58,59 822.005 1653.13 822.005 1653.13 871 1653 c 0,60,61 919 1651.99 919 1651.99 925 1623 c 0,62,63 888 1659 888 1659 826 1611 c 0,64,65 764 1563 764 1563 805 1494 c 0,66,67 819.935 1468.52 819.935 1468.52 842.394 1468.42 c 0,68,69 863.65 1468.32 863.65 1468.32 891.649 1490.95 c 0,70,71 901.414 1498.84 901.414 1498.84 912 1509.5 c 0,72,73 985 1583 985 1583 996 1616 c 0,74,75 1013.4 1672.65 1013.4 1672.65 1013.38 1712.89 c 0,76,77 1013.36 1762.85 1013.36 1762.85 986.5 1787.5 c 0,78,79 937.961 1832.04 937.961 1832.04 924 1847 c 0,80,81 981.007 1818.99 981.007 1818.99 1008.5 1784.5 c 0,82,83 1036 1749.99 1036 1749.99 1036 1677 c 0,84,85 1036 1607.99 1036 1607.99 1000.5 1547.5 c 0,86,87 964.989 1486.99 964.989 1486.99 926 1442 c 0,88,89 743 1230.01 743 1230.01 737 927 c 0,90,91 736 901 736 901 738.5 830.5 c 0,92,93 741 760 741 760 735.5 680 c 0,94,95 729.999 599.996 729.999 599.996 712 529 c 0,96,97 694 458 694 458 652 433 c 0,98,99 688.123 508.663 688.123 508.663 688.026 560.736 c 0,100,101 687.924 615.337 687.924 615.337 648 644 c 0,102,103 585 689 585 689 553 602 c 0,104,105 521 515 521 515 512 471 c 0,106,107 497 399 497 399 486.5 331 c 0,108,109 476 263 476 263 557 266 c 0,110,111 564 266 564 266 577 283.5 c 0,112,113 586.241 295.94 586.241 295.94 586.386 311.664 c 0,114,115 586.446 318.06 586.446 318.06 585 325 c 0,116,117 577 361 577 361 524 372 c 0,118,119 556 398 556 398 584 387 c 0,120,121 612 376 612 376 627 349 c 0,122,123 655 295 655 295 637 239.5 c 0,124,125 619 184.001 619 184.001 590 168 c 0,126,-1 500 116 l 0,127,128 462 93.9995 462 93.9995 462 13 c 0,129,130 462 -101 462 -101 542 -147.5 c 0,131,132 614.087 -189.401 614.087 -189.401 704.039 -189.485 c 0,133,134 713.912 -189.494 713.912 -189.494 724 -189 c 0,135,136 678.195 -202.572 678.195 -202.572 634.149 -202.553 c 0,137,138 600.305 -202.538 600.305 -202.538 567.5 -194.5 c 0,139,140 492 -176.001 492 -176.001 462 -143 c 0,141,142 361 -30.0001 361 -30.0001 359.5 119.5 c 0,143,144 358 269 358 269 283 374 c 0,145,146 269 392 269 392 236 406.5 c 0,147,148 220.144 410.016 l 0,149,150 200.816 409.305 200.816 409.305 190 376 c 0,151,152 169 298 169 298 244 282 c 0,153,154 211.123 281.752 l 0,155,156 195.064 283.447 195.064 283.447 177.5 288.5 c 0,157,158 141 299 141 299 117 359 c 0,159,160 102.015 394.589 102.015 394.589 101.942 433.139 c 0,161,162 101.858 476.911 101.858 476.911 121 524.5 c 0,163,164 157 614 157 614 157 692 c 0,165,166 157 815 157 815 116.5 925 c 0,167,168 75.9978 1035.01 75.9978 1035.01 52 1150 c 0,169,170 43.9902 1184.05 43.9902 1184.05 30 1258.5 c 0,171,172 16 1333.01 16 1333.01 19 1416 c 0,173,174 20.0001 1473.01 20.0001 1473.01 49.5 1551.5 c 0,175,176 79.0021 1630 79.0021 1630 124 1636 c 0,177,178 104.996 1609 104.996 1609 90 1569 c 0,179,180 75 1528.99 75 1528.99 80 1500 c 0,181,182 90.1461 1428.98 90.1461 1428.98 169.197 1428.57 c 0,183,184 175.854 1428.53 175.854 1428.53 183 1429 c 0,185,186 230 1432 230 1432 237.5 1511 c 0,187,188 241.099 1585.22 l 0,189,190 240.776 1614.29 240.776 1614.29 237 1636 c 0,191,192 222 1708 222 1708 140 1720 c 0,193,194 248 1733.01 248 1733.01 277.5 1636 c 0,195,196 307 1538.99 307 1538.99 298 1477 c 0,197,198 292.001 1435.01 292.001 1435.01 269.5 1353 c 0,199,200 246.994 1270.97 246.994 1270.97 238 1222 c 0,201,202 235.011 1207.06 235.011 1207.06 235.093 1163.63 c 0,203,204 235.121 1148.94 235.121 1148.94 235.5 1131 c 0,205,206 237 1060.01 237 1060.01 246 988.5 c 0,207,208 255 917 255 917 274.5 871.5 c 0,209,210 294 826 294 826 327 856 c 0,211,212 363 890 363 890 350 940 c 0,213,214 337 990 337 990 305 1015 c 1,0,1 EndSplineSet KernsSLIF: 246 -172 0 0 111 -143 0 0 45 -182 0 0 46 -182 0 0 44 -208 0 0 105 -104 0 0 97 -257 0 0 EndChar StartChar: w Encoding: 119 119 26 Width: 1586 Flags: HW Fore 1014 -90 m 0,0,1 965 -75 965 -75 934.5 -33.5 c 0,2,3 904 8 904 8 892 43 c 0,4,5 868.999 107.005 868.999 107.005 855 192.5 c 0,6,7 841 278 841 278 813 329 c 0,8,9 773 399 773 399 745.5 404 c 0,10,11 718 409 718 409 682 359 c 0,12,13 655 320 655 320 656.5 224.5 c 0,14,15 658 129.001 658 129.001 687 96 c 0,16,17 710 69 710 69 759 61 c 0,18,19 715.03 35.2941 715.03 35.2941 668.313 35.2145 c 0,20,21 645.97 35.1765 645.97 35.1765 623 41 c 0,22,23 552 59 552 59 522 89 c 0,24,25 493 116 493 116 472.5 149 c 0,26,-1 431 218 l 0,27,28 408 257 408 257 396.5 274 c 0,29,30 385 291 385 291 337 307 c 0,31,32 328 310 328 310 309.5 303 c 0,33,34 291 296 291 296 288 285 c 0,35,36 282.97 270.441 282.97 270.441 282.916 258.825 c 0,37,38 282.819 238.131 282.819 238.131 298.512 226.777 c 0,39,40 307.287 220.428 307.287 220.428 321 217 c 0,41,42 306.593 210.22 306.593 210.22 293.802 210.084 c 0,43,44 284.612 209.986 284.612 209.986 276.255 213.318 c 0,45,46 268.795 216.292 268.795 216.292 262 222 c 0,47,48 237 243 237 243 234 267 c 0,49,50 227.71 307.884 227.71 307.884 227.739 342.862 c 0,51,52 227.766 374.615 227.766 374.615 233 401.5 c 0,53,54 243.998 457.993 243.998 457.993 262 521 c 0,55,56 301 653 301 653 299 782.5 c 0,57,58 297.001 911.997 297.001 911.997 241 1033 c 0,59,60 210.985 1095.03 210.985 1095.03 177 1152 c 0,61,62 143 1209 143 1209 140 1284 c 0,63,64 141.271 1338.67 l 0,65,66 151.107 1435.81 151.107 1435.81 219 1443 c 0,67,68 276 1447.01 276 1447.01 276 1395 c 0,69,70 264.083 1406.32 264.083 1406.32 248.788 1406.46 c 0,71,72 238.421 1406.55 238.421 1406.55 226.5 1401.5 c 0,73,74 207.837 1393.6 207.837 1393.6 207.785 1366.27 c 0,75,76 207.755 1350.41 207.755 1350.41 214 1328 c 0,77,78 222.184 1296.75 222.184 1296.75 252.786 1296.23 c 0,79,80 276.5 1299.5 l 0,81,82 328 1313 328 1313 328 1354 c 0,83,84 327 1443 327 1443 273.5 1477 c 0,85,86 220.007 1511 220.007 1511 157 1511 c 0,87,88 72.0033 1511 72.0033 1511 43.5 1467 c 0,89,90 15 1423.01 15 1423.01 3 1401 c 0,91,92 17 1534.99 17 1534.99 162 1545 c 0,93,94 237 1549.99 237 1549.99 298 1504.5 c 0,95,96 358.995 1459.01 358.995 1459.01 383 1414 c 0,97,98 429.636 1322.85 429.636 1322.85 429.838 1258.41 c 0,99,100 429.922 1231.65 429.922 1231.65 422 1209.5 c 0,101,102 395 1134.01 395 1134.01 386 993 c 0,103,104 383 950 383 950 382.5 891 c 0,105,106 382 832 382 832 411 799 c 0,107,108 431.326 774.91 431.326 774.91 446.268 774.622 c 0,109,110 451.174 774.528 451.174 774.528 455.5 777 c 0,111,112 473 787 473 787 472 808 c 0,113,114 470.999 827.004 470.999 827.004 465.5 843.5 c 0,115,116 460 860 460 860 415 863 c 0,117,118 443.027 877.205 443.027 877.205 466.042 877.26 c 0,119,120 502.973 877.348 502.973 877.348 527 841 c 0,121,122 551 801 551 801 546.5 771 c 0,123,124 542 741 542 741 537 714 c 0,125,126 521 630 521 630 520.5 586 c 0,127,128 523.692 560.121 l 0,129,130 531 533.828 531 533.828 555 516 c 0,131,132 578 498 578 498 624.5 589.5 c 0,133,134 671 681 671 681 692 727 c 0,135,136 714 775 714 775 737 806.5 c 0,137,138 759.999 837.999 759.999 837.999 831 871 c 0,139,140 789 810 789 810 777.5 774 c 0,141,142 766 738 766 738 776 672 c 0,143,144 781 632 781 632 795.5 598.5 c 0,145,146 810 565 810 565 845 561 c 0,147,148 915 552 915 552 953 646 c 0,149,150 991 740 991 740 997 791 c 0,151,152 998.001 801.003 998.001 801.003 1014.5 884.5 c 0,153,154 1019.54 910.001 1019.54 910.001 1019.59 927.713 c 0,155,156 1019.69 963 1019.69 963 999.982 967.379 c 0,157,158 997.19 968 997.19 968 994 968 c 0,159,160 970 968 970 968 962.5 943.5 c 0,161,162 955 919 955 919 973 903 c 0,163,164 934 909 934 909 934 949.5 c 0,165,166 934 990 934 990 943 1005 c 0,167,168 972.994 1052.99 972.994 1052.99 1017.5 1088.5 c 0,169,170 1062 1124 1062 1124 1089 1157 c 0,171,172 1131.02 1208.03 1131.02 1208.03 1142 1228.5 c 0,173,174 1153.01 1249.04 1153.01 1249.04 1171 1303 c 0,175,176 1184.99 1346.01 1184.99 1346.01 1219 1438 c 0,177,178 1253.01 1530.01 1253.01 1530.01 1295 1572 c 0,179,180 1354.39 1631.39 1354.39 1631.39 1409.01 1631.59 c 0,181,182 1420.61 1631.63 1420.61 1631.63 1432 1629 c 0,183,-1 1361.5 1588 l 0,184,185 1328 1568.99 1328 1568.99 1307 1515 c 0,186,187 1293.8 1483.93 1293.8 1483.93 1293.87 1441.71 c 0,188,189 1293.88 1429.57 1293.88 1429.57 1295 1416.5 c 0,190,191 1299.99 1358 1299.99 1358 1350 1352 c 0,192,193 1408.01 1346 1408.01 1346 1458 1382 c 0,194,195 1508 1418.01 1508 1418.01 1532 1472 c 0,196,197 1546.97 1507.94 1546.97 1507.94 1565.5 1542 c 0,198,199 1580.79 1570.11 1580.79 1570.11 1580.71 1634.4 c 0,200,201 1580.7 1647.9 1580.7 1647.9 1580 1663 c 0,202,203 1574 1753.99 1574 1753.99 1443 1824 c 0,204,205 1597 1790 1597 1790 1619 1646 c 0,206,207 1622.07 1590.37 l 0,208,209 1621.42 1545.07 1621.42 1545.07 1611 1496 c 0,210,211 1594 1416 1594 1416 1542 1356 c 0,212,213 1468.98 1272.99 1468.98 1272.99 1374 1201 c 0,214,215 1337.98 1173.98 1337.98 1173.98 1280.5 1098 c 0,216,217 1246.65 1053.25 1246.65 1053.25 1246.59 1018.22 c 0,218,219 1246.55 993.741 1246.55 993.741 1263 974 c 0,220,221 1269.62 966.056 1269.62 966.056 1283.03 966 c 0,222,223 1289.88 965.972 1289.88 965.972 1298.5 968 c 0,224,225 1324 974 1324 974 1330 996 c 0,226,227 1334.96 1014.94 1334.96 1014.94 1334.94 1027.17 c 0,228,229 1334.91 1042.06 1334.91 1042.06 1327.5 1047 c 0,230,-1 1295 1069 l 0,231,232 1323.65 1072.59 l 0,233,234 1361.04 1071.97 1361.04 1071.97 1370 1036.5 c 0,235,236 1376.58 1010.46 1376.58 1010.46 1376.55 986.389 c 0,237,238 1376.52 966.529 1376.52 966.529 1372 948 c 0,239,240 1355.99 885.999 1355.99 885.999 1300 860 c 0,241,242 1243.99 833.995 1243.99 833.995 1199 797 c 0,243,244 1148.02 754.015 1148.02 754.015 1106.5 707.5 c 0,245,246 1065.01 661.014 1065.01 661.014 1055 595 c 0,247,248 1049.56 560.034 1049.56 560.034 1049.63 531.26 c 0,249,250 1049.74 485.962 1049.74 485.962 1063.5 456 c 0,251,-1 1119 332 l 0,252,253 1141.99 276 1141.99 276 1149 213 c 0,254,255 1148.59 180.883 l 0,256,257 1142.04 129.433 1142.04 129.433 1099 66 c 0,258,259 1099 93 1099 93 1111 155.5 c 0,260,261 1112.74 183.814 l 0,262,263 1109.16 226.59 1109.16 226.59 1065 254 c 0,264,265 1024.01 278 1024.01 278 991.5 228 c 0,266,267 959 178.001 959 178.001 957 79 c 0,268,269 955 38 955 38 979 -6 c 0,270,271 1003 -50 1003 -50 1042 -68 c 0,272,273 1079.01 -86 1079.01 -86 1162 -88 c 0,274,275 1136.9 -100.085 1136.9 -100.085 1097.11 -100.071 c 0,276,277 1094.1 -100.07 1094.1 -100.07 1091 -100 c 0,278,279 1047 -98.9998 1047 -98.9998 1014 -90 c 0,0,1 EndSplineSet KernsSLIF: 246 -42 0 0 322 -300 0 0 104 -104 0 0 45 -117 0 0 46 -195 0 0 44 -208 0 0 115 -91 0 0 105 13 0 0 243 -156 0 0 111 -91 0 0 228 -228 0 0 261 -313 0 0 97 -342 0 0 EndChar StartChar: x Encoding: 120 120 28 Width: 1239 Flags: HW Fore 659 1394 m 0,0,1 619.965 1385.64 619.965 1385.64 619.801 1356.11 c 0,2,3 619.788 1353.86 619.788 1353.86 620 1351.5 c 0,4,5 623 1318.99 623 1318.99 623 1318 c 0,6,7 587.525 1334.5 587.525 1334.5 587.443 1378.22 c 0,8,9 587.425 1387.5 587.425 1387.5 589 1398 c 0,10,11 594 1451.01 594 1451.01 659 1468 c 0,12,13 695.043 1477.01 695.043 1477.01 742 1494.5 c 0,14,15 789.016 1512.01 789.016 1512.01 820 1533 c 0,16,17 832 1542 832 1542 845.5 1570.5 c 0,18,19 858.997 1598.99 858.997 1598.99 863 1616 c 0,20,21 879 1701.99 879 1701.99 812 1712 c 0,22,23 845 1721 845 1721 866.5 1701.5 c 0,24,25 888 1682 888 1682 888 1656 c 0,26,27 888 1633.99 888 1633.99 882 1558.5 c 0,28,29 881.281 1511.03 l 0,30,31 883.815 1483 883.815 1483 896 1483 c 0,32,33 912.786 1485.53 l 0,34,35 929.979 1492.51 929.979 1492.51 941 1518 c 0,36,37 960.999 1566 960.999 1566 962 1610 c 0,38,39 963.001 1654 963.001 1654 982 1696 c 0,40,41 999.999 1735 999.999 1735 1035.5 1760 c 0,42,43 1065.03 1780.8 1065.03 1780.8 1090.77 1780.83 c 0,44,45 1095.96 1780.84 1095.96 1780.84 1101 1780 c 0,46,47 1029 1757.99 1029 1757.99 1029 1701 c 0,48,49 1029 1659 1029 1659 1074 1659 c 0,50,51 1094 1659 1094 1659 1101 1678 c 0,52,53 1105.12 1689.17 1105.12 1689.17 1105.08 1698.97 c 0,54,55 1105.06 1705.82 1105.06 1705.82 1103 1712 c 0,56,57 1136 1707.99 1136 1707.99 1136 1667 c 0,58,59 1136 1625.99 1136 1625.99 1126 1609 c 0,60,61 1111 1583.01 1111 1583.01 1078 1549 c 0,62,-1 1024 1495 l 0,63,-1 922 1402 l 0,64,65 840.994 1328.99 840.994 1328.99 816 1271 c 0,66,67 801.993 1240.98 801.993 1240.98 770 1138 c 0,68,69 756.589 1094.83 756.589 1094.83 756.527 1063.96 c 0,70,71 756.441 1021.17 756.441 1021.17 782 1002 c 0,72,73 804 985 804 985 828.5 999 c 0,74,75 852.987 1012.99 852.987 1012.99 864 1027 c 0,76,77 875.229 1041.97 875.229 1041.97 875.513 1054.86 c 0,78,79 872.132 1069.17 l 0,80,81 868.752 1075.66 868.752 1075.66 862 1081.5 c 0,82,83 835.994 1104.01 835.994 1104.01 818 1106 c 0,84,85 855 1118 855 1118 885 1103 c 0,86,87 914.998 1088 914.998 1088 921 1071 c 0,88,89 942 993 942 993 894.5 964.5 c 0,90,91 847 936 847 936 802 891 c 0,92,93 754.999 845.999 754.999 845.999 753 810.5 c 0,94,95 751 775 751 775 757 739 c 0,96,97 772 636 772 636 907 471 c 0,98,-1 1101 234 l 0,99,100 1123.99 205.001 1123.99 205.001 1140 136 c 0,101,102 1156.01 67 1156.01 67 1119 34 c 0,103,104 1150.99 92.9999 1150.99 92.9999 1098 169 c 0,105,106 1045.01 244.998 1045.01 244.998 995 254 c 0,107,108 968.167 255.138 l 0,109,110 937.522 251.594 937.522 251.594 928.5 222 c 0,111,112 922.338 201.789 922.338 201.789 922.373 184.251 c 0,113,114 922.408 166.211 922.408 166.211 929 151 c 0,115,116 965 65.0001 965 65.0001 1025.5 36.5 c 0,117,118 1085.99 8 1085.99 8 1144 7 c 0,119,120 1202.59 9.65475 l 0,121,122 1224.73 12.2988 1224.73 12.2988 1243.5 17.5 c 0,123,124 1271 25.1205 1271 25.1205 1280.28 25.0566 c 0,125,126 1285 25.0241 1285 25.0241 1285 23 c 0,127,128 1192.24 -6.79408 1192.24 -6.79408 1118.61 -6.88269 c 0,129,130 1061.26 -6.95171 1061.26 -6.95171 1015.5 11 c 0,131,132 911 52 911 52 870 160 c 0,133,134 845.997 221.008 845.997 221.008 811.5 322.5 c 0,135,136 777 424 777 424 750 427 c 0,137,138 696 431 696 431 696 382 c 0,139,140 696 336 696 336 739 342 c 0,141,142 717 315 717 315 691.5 326 c 0,143,144 666 337 666 337 657 358 c 0,145,146 635.001 402.998 635.001 402.998 631 455.5 c 0,147,148 627 508 627 508 627 568 c 0,149,150 627 589 627 589 617 628 c 0,151,152 607 667 607 667 580 671 c 0,153,154 514 678 514 678 468.5 563 c 0,155,156 436.8 482.877 436.8 482.877 436.894 455.18 c 0,157,158 436.935 443.123 436.935 443.123 443 441 c 0,159,160 455.538 439.465 l 0,161,162 466.861 441.222 466.861 441.222 479 454 c 0,163,164 500 475 500 475 469 506 c 0,165,166 487 506 487 506 501 486.5 c 0,167,168 515 467 515 467 515 449 c 0,169,170 515 414 515 414 487.5 372.5 c 0,171,172 460.001 331 460.001 331 425 322 c 0,173,174 379 310 379 310 340.5 285 c 0,175,176 302 260 302 260 291 212 c 0,177,178 278.998 157.992 278.998 157.992 266 109 c 0,179,180 253 59.9999 253 59.9999 230 30 c 0,181,182 219.999 16.9999 219.999 16.9999 184 7 c 0,183,184 163.709 1.36363 163.709 1.36363 148.819 1.44562 c 0,185,186 137.291 1.50909 137.291 1.50909 129 5 c 0,187,188 177.001 11.0001 177.001 11.0001 203 57 c 0,189,190 219 85.9999 219 85.9999 219.5 143.5 c 0,191,192 216.668 168.843 l 0,193,194 207.895 201 207.895 201 172 201 c 0,195,196 119 201 119 201 89.5 137 c 0,197,198 59.9999 72.9999 59.9999 72.9999 60 28 c 0,199,200 60 -48.0001 60 -48.0001 140 -88 c 0,201,202 81.0005 -88 81.0005 -88 54 -50 c 0,203,204 27 -12 27 -12 24 28 c 0,205,206 16 129 16 129 78 217 c 0,207,208 109 262 109 262 210 369 c 0,209,210 311 476 311 476 309 521 c 0,211,212 309 548 309 548 273 548 c 0,213,214 255 548 255 548 254.5 529 c 0,215,216 254.999 510 254.999 510 262 501 c 0,217,218 241 495 241 495 221.5 518.5 c 0,219,220 212.134 529.788 212.134 529.788 212.111 544.881 c 0,221,222 212.087 561.212 212.087 561.212 223 582 c 0,223,224 239.999 615 239.999 615 289 644 c 0,225,226 337.997 672.998 337.997 672.998 367 699 c 0,227,228 395 726 395 726 429.5 778 c 0,229,230 464 830 464 830 464 873 c 0,231,232 464 901 464 901 440.5 913 c 0,233,234 417 925 417 925 394 925 c 0,235,236 327 922 327 922 336 877.5 c 0,237,238 345 833 345 833 371 833 c 0,239,240 338.017 831.603 l 0,241,242 312.765 833.673 312.765 833.673 291.5 846 c 0,243,244 257 866 257 866 257 914 c 0,245,246 257 952 257 952 278 992 c 0,247,248 299.005 1032.01 299.005 1032.01 307 1066 c 0,249,250 313.999 1095.99 313.999 1095.99 315 1138.5 c 0,251,252 312.455 1183.29 l 0,253,254 310.196 1197.83 310.196 1197.83 306 1210 c 0,255,256 284 1267 284 1267 239 1313.5 c 0,257,258 194 1360 194 1360 194 1432 c 0,259,260 194 1451.01 194 1451.01 215 1489 c 0,261,262 236 1526.99 236 1526.99 270 1528 c 0,263,264 236 1496.01 236 1496.01 236 1452 c 0,265,266 236 1440 236 1440 247 1420.5 c 0,267,268 257.999 1401 257.999 1401 277 1401 c 0,269,270 331 1401 331 1401 331 1456 c 0,271,272 331 1616.55 331 1616.55 200.138 1616.46 c 0,273,274 193.252 1616.45 193.252 1616.45 186 1616 c 0,275,276 285 1646 285 1646 330 1596.5 c 0,277,278 375 1547 375 1547 394 1472 c 0,279,280 409 1407.01 409 1407.01 417 1338 c 0,281,282 425 1269 425 1269 443 1206 c 0,283,284 449.999 1179.01 449.999 1179.01 481.5 1130 c 0,285,286 506.465 1091.16 506.465 1091.16 534.26 1090.65 c 0,287,288 549 1093 l 0,289,290 590.995 1106.99 590.995 1106.99 627 1158 c 0,291,292 662.996 1208.99 662.996 1208.99 678 1250 c 0,293,294 683.003 1263.01 683.003 1263.01 694 1333.5 c 0,295,296 695.76 1365.97 l 0,297,298 693.084 1394.55 693.084 1394.55 670.648 1395.23 c 0,299,300 659 1394 l 0,0,1 EndSplineSet KernsSLIF: 45 -208 0 0 EndChar StartChar: y Encoding: 121 121 27 Width: 1145 Flags: HMW VStem: 362 278<103 873> Fore 516 -249 m 1,0,1 569 -202.999 569 -202.999 604.5 -50.5 c 0,2,3 640 102 640 102 589 147 c 0,4,5 567.001 165.999 567.001 165.999 504.5 170 c 0,6,7 477.767 168.457 l 0,8,9 455.328 163.118 455.328 163.118 455.365 142.228 c 0,10,11 455.38 133.861 455.38 133.861 459 123 c 0,12,13 468 92.0002 468 92.0002 495.5 86.5 c 0,14,15 519.369 85.4306 l 0,16,17 534.421 87.1496 534.421 87.1496 549 95 c 0,18,19 549 54.9999 549 54.9999 463 48.5 c 0,20,21 377 42 377 42 362 103 c 0,22,23 355.586 126.249 355.586 126.249 355.68 149.9 c 0,24,25 355.821 185.251 355.821 185.251 370.5 221.5 c 0,26,27 395.006 282.015 395.006 282.015 415 340 c 0,28,29 424 366 424 366 455 504 c 0,30,31 486 642 486 642 438 650 c 0,32,33 419 653 419 653 398 640.5 c 0,34,35 377 628 377 628 378 601 c 0,36,37 378 580.999 378 580.999 418 573 c 0,38,39 386 561 386 561 346 568.5 c 0,40,41 306 576 306 576 292 607 c 0,42,43 286.399 619.52 286.399 619.52 286.497 633.18 c 0,44,45 286.697 660.981 286.697 660.981 310.5 693.5 c 0,46,47 345.999 741.998 345.999 741.998 355 780 c 0,48,49 369 840 369 840 346.5 900.5 c 0,50,51 324 961 324 961 288 1000 c 0,52,53 272 1015 272 1015 252 995.5 c 0,54,55 232.001 976 232.001 976 246 956 c 0,56,57 256.001 940.999 256.001 940.999 263 936.5 c 0,58,59 270 932 270 932 306 932 c 0,60,61 300 916.001 300 916.001 256.5 913.5 c 0,62,63 213 911 213 911 189 929 c 0,64,65 151.001 958 151.001 958 163.5 1022 c 0,66,67 176 1086.01 176 1086.01 176 1126 c 0,68,69 176 1218 176 1218 110.5 1270.5 c 0,70,71 44.9999 1323 44.9999 1323 33 1407 c 0,72,73 18 1494 18 1494 57.5 1593 c 0,74,75 96.9998 1692 96.9998 1692 216 1740 c 0,76,77 135 1689 135 1689 92 1606.5 c 0,78,79 69.4154 1563.17 69.4154 1563.17 69.4513 1518.87 c 0,80,81 69.4837 1478.83 69.4837 1478.83 88 1438 c 0,82,83 112.858 1381.83 112.858 1381.83 177.572 1381.62 c 0,84,85 183.138 1381.6 183.138 1381.6 189 1382 c 0,86,87 262.991 1386.99 262.991 1386.99 299 1428 c 0,88,89 310.937 1441.84 310.937 1441.84 311.247 1455.12 c 0,90,91 308.015 1469.67 l 0,92,93 304.702 1476.67 304.702 1476.67 298 1483.5 c 0,94,95 280.194 1501.65 280.194 1501.65 252.532 1501.74 c 0,96,97 239.809 1501.78 239.809 1501.78 225 1498 c 0,98,99 263.544 1524.4 263.544 1524.4 296.233 1524.59 c 0,100,101 312.955 1524.69 312.955 1524.69 328.145 1517.93 c 0,102,103 339.5 1512.88 339.5 1512.88 350 1504 c 0,104,105 374.854 1481.76 374.854 1481.76 375.11 1449.04 c 0,106,107 371.339 1421.03 l 0,108,109 370.117 1416.35 370.117 1416.35 368.5 1411.5 c 0,110,111 349.989 1355.97 349.989 1355.97 349.951 1317.11 c 0,112,113 349.949 1315.03 349.949 1315.03 350 1313 c 0,114,115 351.001 1224.99 351.001 1224.99 385 1074.5 c 0,116,117 411.928 955.304 411.928 955.304 474.61 954.347 c 0,118,119 499.5 958.184 l 0,120,121 504.651 959.766 504.651 959.766 510 962 c 0,122,123 546 977 546 977 584 1038 c 0,124,125 622.001 1099.01 622.001 1099.01 630 1128 c 0,126,127 631.185 1147.49 l 0,128,129 629.345 1163.19 629.345 1163.19 620 1184.5 c 0,130,131 609.445 1208.57 609.445 1208.57 592.368 1208.51 c 0,132,133 583.553 1208.47 583.553 1208.47 573 1202 c 0,134,135 556.8 1191.8 556.8 1191.8 556.8 1181.24 c 0,136,137 556.8 1174.2 556.8 1174.2 564 1167 c 0,138,139 582 1149 582 1149 603 1149 c 0,140,141 571 1128 571 1128 542.5 1143 c 0,142,143 514 1158 514 1158 510 1180 c 0,144,145 507.91 1207.16 l 0,146,147 511.963 1262.94 511.963 1262.94 588.5 1301 c 0,148,149 682.991 1347.99 682.991 1347.99 732 1405 c 0,150,151 768.009 1445.01 768.009 1445.01 792 1500 c 0,152,153 816 1555.01 816 1555.01 846 1599 c 0,154,-1 874.5 1643 l 0,155,156 903 1686.99 903 1686.99 957 1673 c 0,157,158 907.003 1659.01 907.003 1659.01 891.5 1616.5 c 0,159,160 887.421 1605.32 887.421 1605.32 887.324 1595.41 c 0,161,162 887.226 1585.39 887.226 1585.39 891.206 1576.68 c 0,163,164 898.238 1561.29 898.238 1561.29 918 1550 c 0,165,166 937 1538 937 1538 967.5 1551.5 c 0,167,168 998.009 1565 998.009 1565 1006 1574 c 0,169,170 1046.5 1622 1046.5 1622 1046.75 1658 c 0,171,172 1046.85 1672.4 1046.85 1672.4 1040.51 1684.88 c 0,173,174 1031 1703.6 1031 1703.6 1007 1718 c 0,175,176 927.02 1765.99 927.02 1765.99 906 1773 c 0,177,178 983.986 1759.01 983.986 1759.01 1020.5 1727 c 0,179,180 1057 1695 1057 1695 1060 1689 c 0,181,182 1076.31 1652.31 1076.31 1652.31 1076.45 1623.69 c 0,183,184 1076.52 1610.2 1076.52 1610.2 1073 1598.5 c 0,185,186 1062.01 1562.02 1062.01 1562.02 1024 1505 c 0,187,188 987.005 1448.01 987.005 1448.01 903.5 1384 c 0,189,190 819.999 1319.99 819.999 1319.99 811 1257 c 0,191,192 809.173 1213.58 l 0,193,194 810.601 1181.82 810.601 1181.82 820.5 1146.5 c 0,195,196 837 1089 837 1089 839 1036 c 0,197,198 839 1010 839 1010 819 933 c 0,199,200 799 856 799 856 709 850 c 0,201,202 745 861 745 861 768 927 c 0,203,204 791 993 791 993 716 993 c 0,205,206 672 993 672 993 656 947 c 0,207,208 640 901.001 640 901.001 640 873 c 0,209,210 640 803 640 803 697 793 c 0,211,212 726.152 787.237 726.152 787.237 749.1 787.335 c 0,213,214 793.848 787.525 793.848 787.525 815 810 c 0,215,216 833.353 829.5 833.353 829.5 833.285 849 c 0,217,218 833.235 863.5 833.235 863.5 823 878 c 0,219,220 848 875 848 875 858 850 c 0,221,222 865.632 830.921 865.632 830.921 865.692 818.831 c 0,223,224 865.711 815.079 865.711 815.079 865 812 c 0,225,226 835 710 835 710 753.5 661.5 c 0,227,228 672 613 672 613 642 505 c 0,229,230 631 467 631 467 622.5 420.5 c 0,231,232 614 374 614 374 614 333 c 0,233,234 614 291 614 291 631.5 245 c 0,235,236 649.004 198.989 649.004 198.989 665 162 c 0,237,238 678.513 129.86 678.513 129.86 678.555 90.5183 c 0,239,240 678.626 22.1387 678.626 22.1387 638 -68 c 0,241,242 573.999 -210.001 573.999 -210.001 516 -249 c 1,0,1 EndSplineSet KernsSLIF: 111 -130 0 0 322 -260 0 0 115 -208 0 0 45 -169 0 0 46 -195 0 0 44 -208 0 0 97 -363 0 0 EndChar StartChar: z Encoding: 122 122 31 Width: 1565 Flags: HMW HStem: 147 132.5<256.5 1230.5> 1333 115<337 1066> Fore 192 -73 m 0,0,1 107 -73 107 -73 98 23 c 0,2,3 96.9999 29 96.9999 29 101.5 75 c 0,4,5 106 121.001 106 121.001 142 130 c 0,6,7 127 112 127 112 121.5 80.5 c 0,8,9 121.118 58.5858 l 0,10,11 123.865 43.8878 123.865 43.8878 136 36 c 0,12,13 157.196 21.0841 157.196 21.0841 178.239 21.0364 c 0,14,15 210.804 20.9627 210.804 20.9627 243 56.5 c 0,16,17 288.962 107.232 288.962 107.232 289.049 160.597 c 0,18,19 289.062 168.768 289.062 168.768 288 177 c 0,20,21 281 231.999 281 231.999 256.5 279.5 c 0,22,23 233.051 324.964 233.051 324.964 232.961 390.117 c 0,24,25 232.957 393.038 232.957 393.038 233 396 c 0,26,27 233 426.002 233 426.002 253.5 467 c 0,28,29 274 508 274 508 310 517 c 0,30,31 319 520 319 520 341.5 521 c 0,32,33 358.339 518.81 l 0,34,35 366.273 515.636 366.273 515.636 369 508 c 0,36,37 349 520 349 520 313.5 502 c 0,38,39 278.001 484.001 278.001 484.001 277 463 c 0,40,41 274 439 274 439 280 410 c 0,42,43 286 381 286 381 319 381 c 0,44,45 358 381 358 381 408 486 c 0,46,47 458 591 458 591 467 627 c 0,48,49 491 716 491 716 498.5 795.5 c 0,50,51 506 875 506 875 519 955 c 0,52,53 522 977.999 522 977.999 536 1011.5 c 0,54,55 550.003 1045 550.003 1045 568 1060 c 0,56,57 614.007 1102.01 614.007 1102.01 662.5 1108.5 c 0,58,59 695.795 1109.75 l 0,60,61 715.86 1107.71 715.86 1107.71 723 1097 c 0,62,63 702.171 1098.72 l 0,64,65 673.014 1096.04 673.014 1096.04 638 1066.5 c 0,66,67 590 1026 590 1026 625 993 c 0,68,69 635.364 982.636 635.364 982.636 649.389 982.592 c 0,70,71 665.136 982.541 665.136 982.541 685.5 995.5 c 0,72,73 723.984 1019.98 723.984 1019.98 737 1037 c 0,74,-1 789 1107.5 l 0,75,76 816.971 1146.95 816.971 1146.95 837 1182 c 0,77,78 858 1218 858 1218 870.5 1258.5 c 0,79,80 873.186 1278.82 l 0,81,82 871.615 1307.02 871.615 1307.02 839 1330 c 0,83,84 801.009 1356.99 801.009 1356.99 740.5 1364 c 0,85,86 680.044 1371 680.044 1371 635 1371 c 0,87,88 532.993 1371 532.993 1371 488 1338.5 c 0,89,-1 383 1259 l 0,90,-1 358.5 1239 l 0,91,92 340.993 1225 340.993 1225 330 1225 c 0,93,94 299.544 1226.95 l 0,95,96 286.046 1229.27 286.046 1229.27 269.5 1234 c 0,97,98 231.001 1244.99 231.001 1244.99 222 1284 c 0,99,100 229.997 1268 229.997 1268 286.5 1259 c 0,101,102 306.838 1259.13 l 0,103,104 337.526 1265.89 337.526 1265.89 337.576 1317.74 c 0,105,106 337.583 1324.94 337.583 1324.94 337 1333 c 0,107,108 332 1395.01 332 1395.01 253.5 1400 c 0,109,110 178.634 1401.45 l 0,111,112 156.61 1400.4 156.61 1400.4 143 1397 c 0,113,114 33.0001 1368.01 33.0001 1368.01 34.5 1305.5 c 0,115,116 35 1212 l 0,117,118 14.6647 1264.87 14.6647 1264.87 14.6483 1304.98 c 0,119,120 14.6284 1353.63 14.6284 1353.63 44.5 1383.5 c 0,121,122 99.0072 1438 99.0072 1438 147 1453 c 0,123,124 205.397 1470.43 205.397 1470.43 268.328 1470.39 c 0,125,126 277.615 1470.39 277.615 1470.39 287 1470 c 0,127,128 360.084 1467 360.084 1467 429 1460 c 0,129,130 489.53 1456.4 l 0,131,132 508.127 1456.49 508.127 1456.49 527 1458 c 0,133,134 563.734 1460.94 563.734 1460.94 564.304 1486.01 c 0,135,136 560.419 1505.87 l 0,137,138 560 1507 l 0,139,140 549.725 1533.71 549.725 1533.71 523.728 1534.15 c 0,141,142 499.826 1530.11 l 0,143,144 498.185 1529.59 498.185 1529.59 496.5 1529 c 0,145,146 448.004 1512.01 448.004 1512.01 444 1498 c 0,147,148 443.297 1522.75 l 0,149,150 445.875 1541.5 445.875 1541.5 459 1554 c 0,151,152 480.015 1574.01 480.015 1574.01 498 1579 c 0,153,154 519.22 1584.14 519.22 1584.14 547.867 1584.12 c 0,155,156 563.788 1584.11 563.788 1584.11 582 1582.5 c 0,157,158 632.988 1578 632.988 1578 666 1561 c 0,159,-1 770 1503.5 l 0,160,161 827.016 1471.99 827.016 1471.99 874 1461 c 0,162,163 926.975 1448 926.975 1448 969 1446.5 c 0,164,165 1061.49 1447.76 l 0,166,167 1063.75 1447.88 1063.75 1447.88 1066 1448 c 0,168,169 1144.4 1445.44 l 0,170,171 1155 1444.6 1155 1444.6 1166 1443.5 c 0,172,173 1221.01 1437.99 1221.01 1437.99 1257 1405 c 0,174,175 1282.01 1381 1282.01 1381 1284 1322.5 c 0,176,177 1281.53 1288.39 l 0,178,179 1274.87 1255.1 1274.87 1255.1 1251 1236 c 0,180,181 1233.82 1220.31 1233.82 1220.31 1198.24 1220.25 c 0,182,183 1186.18 1220.23 1186.18 1220.23 1172 1222 c 0,184,185 1199 1223.01 1199 1223.01 1227.5 1271 c 0,186,187 1239.27 1290.83 1239.27 1290.83 1239.19 1309.97 c 0,188,189 1239.06 1337.18 1239.06 1337.18 1215 1363 c 0,190,191 1204.09 1373.91 1204.09 1373.91 1185.45 1373.96 c 0,192,193 1169.91 1374 1169.91 1374 1149 1366.5 c 0,194,195 1103 1350 1103 1350 1088 1334 c 0,196,197 1024.02 1263.03 1024.02 1263.03 959.5 1150.5 c 0,198,199 895 1038 895 1038 856 951 c 0,200,201 832.001 895.003 832.001 895.003 817.5 818 c 0,202,203 803 741.002 803 741.002 795 679 c 0,204,205 786 618 786 618 751 587.5 c 0,206,207 716 557 716 557 637 590 c 0,208,209 659.766 589.972 l 0,210,211 678.989 592.981 678.989 592.981 702.5 605.5 c 0,212,213 741 626 741 626 725 677 c 0,214,215 707 731 707 731 653 680 c 0,216,217 599 629 599 629 596 596 c 0,218,219 590 541 590 541 588.5 442 c 0,220,221 587 343 587 343 660 325 c 0,222,223 760 298 760 298 856 298 c 0,224,225 936 298 936 298 972 357 c 0,226,227 1007.98 415.974 1007.98 415.974 1049 469 c 0,228,229 1105.57 542.286 1105.57 542.286 1153.05 542.837 c 0,230,231 1173.67 539.5 l 0,232,233 1188.84 534.299 1188.84 534.299 1203 521 c 0,234,235 1265.25 462.519 1265.25 462.519 1265 433 c 0,236,237 1250 456 1250 456 1196 475.5 c 0,238,239 1178.91 481.671 1178.91 481.671 1164.73 481.583 c 0,240,241 1134.09 481.393 1134.09 481.393 1117 452 c 0,242,243 1099 422 1099 422 1099 367 c 0,244,245 1099 335.005 1099 335.005 1137 302.5 c 0,246,247 1174.99 270 1174.99 270 1197 261 c 0,248,249 1228.05 248.984 1228.05 248.984 1273 233 c 0,250,251 1317.95 217.016 1317.95 217.016 1349 205 c 0,252,253 1409 179.999 1409 179.999 1446.5 127.5 c 0,254,255 1474.23 88.6715 1474.23 88.6715 1474.35 48.4816 c 0,256,257 1474.39 34.3255 1474.39 34.3255 1471 20 c 0,258,259 1456 56 1456 56 1429 96.5 c 0,260,261 1402 136.999 1402 136.999 1336 144 c 0,262,263 1246.66 147.183 l 0,264,265 1238.67 147.142 1238.67 147.142 1230.5 147 c 0,266,267 1172.99 145.999 1172.99 145.999 1126 134 c 0,268,269 1084 123.001 1084 123.001 1045 98 c 0,270,271 1006 72.9999 1006 72.9999 970 59 c 0,272,273 918 39 918 39 879 33.5 c 0,274,275 840 28 840 28 810 59 c 0,276,277 797 71 797 71 799.5 90 c 0,278,279 802 109.001 802 109.001 808 115 c 0,280,281 816 76 816 76 840 76 c 0,282,283 878 76 878 76 883 111 c 0,284,285 881.225 124.68 l 0,286,287 871.742 145.173 871.742 145.173 818.066 145.18 c 0,288,289 808.269 145.181 808.269 145.181 797 144.5 c 0,290,291 705.966 138.997 705.966 138.997 695 138 c 0,292,293 584.998 118.999 584.998 118.999 504.5 71.5 c 0,294,295 424 24 424 24 329 -23 c 0,296,-1 262.5 -54 l 0,297,298 223.001 -73.0001 223.001 -73.0001 192 -73 c 0,0,1 EndSplineSet KernsSLIF: 121 -195 0 0 322 -247 0 0 105 -143 0 0 101 -104 0 0 98 -156 0 0 45 -364 0 0 EndChar StartChar: Adieresis Encoding: 196 196 75 Width: 1568 Flags: HW Fore 128 -308 m 1,0,1 33 -174 33 -174 20.5 -51 c 0,2,3 8.00005 72 8.00005 72 37.5 184.5 c 0,4,5 67 297 67 297 118.5 399.5 c 0,6,7 170.001 502.002 170.001 502.002 203 595 c 0,8,9 224 654 224 654 227 761.5 c 0,10,11 230 869 230 869 240.5 978.5 c 0,12,13 251.001 1088.01 251.001 1088.01 282.5 1177 c 0,14,15 314.004 1266.01 314.004 1266.01 394 1289 c 0,16,17 318 1214 318 1214 362.5 1157 c 0,18,19 379.049 1136.49 379.049 1136.49 415 1148 c 0,20,21 441.428 1156.46 441.428 1156.46 466 1283 c 0,22,23 486 1386.01 486 1386.01 583.5 1530.5 c 0,24,25 678.497 1672.92 678.497 1672.92 755.5 1733.5 c 0,26,27 805.557 1772.89 805.557 1772.89 859.876 1772.89 c 0,28,29 912.441 1772.89 912.441 1772.89 969 1736 c 0,30,31 934.103 1737 l 0,32,33 864.411 1730.95 864.411 1730.95 851 1653 c 0,34,35 847.071 1630.16 847.071 1630.16 847.122 1606.63 c 0,36,37 847.278 1534.34 847.278 1534.34 885 1455.5 c 0,38,39 932.227 1356.79 932.227 1356.79 966 1356 c 0,40,41 1004 1360.01 1004 1360.01 1007 1379.5 c 0,42,43 1007.48 1398.72 l 0,44,45 1003.15 1423.01 1003.15 1423.01 974 1448 c 0,46,47 1089.92 1426.41 1089.92 1426.41 1090.5 1312.5 c 0,48,49 1090.4 1270.56 1090.4 1270.56 1109.82 1163.16 c 0,50,51 1116.69 1125.17 1116.69 1125.17 1126 1079 c 0,52,53 1150 959.018 1150 959.018 1168.5 919.5 c 0,54,55 1188.08 877.713 1188.08 877.713 1221 891 c 0,56,57 1269.26 910.472 1269.26 910.472 1260 966 c 0,58,59 1248 1038 1248 1038 1209 1083 c 0,60,61 1296 1030 1296 1030 1320.5 961 c 0,62,63 1341.19 902.719 1341.19 902.719 1341.2 841.959 c 0,64,65 1341.2 830.773 1341.2 830.773 1340.5 819.5 c 0,66,67 1336 746.97 1336 746.97 1320 679 c 0,68,69 1309.29 633.487 1309.29 633.487 1309.33 596.017 c 0,70,71 1309.36 577.528 1309.36 577.528 1312 561 c 0,72,73 1327 457.016 1327 457.016 1374 353 c 0,74,75 1420.99 249 1420.99 249 1453.5 137 c 0,76,77 1481.72 39.766 1481.72 39.766 1481.67 -66.1854 c 0,78,79 1481.66 -82.2438 1481.66 -82.2438 1481 -98.5 c 0,80,81 1476.01 -221.982 1476.01 -221.982 1387 -366 c 0,82,83 1415.72 -269.572 1415.72 -269.572 1415.68 -151.161 c 0,84,85 1415.66 -96.4285 1415.66 -96.4285 1409.5 -37 c 0,86,87 1390.4 147.188 1390.4 147.188 1260.35 147.146 c 0,88,89 1256.72 147.145 1256.72 147.145 1253 147 c 0,90,91 1175.99 144 1175.99 144 1153 79.5 c 0,92,93 1130.01 15 1130.01 15 1156 -73 c 0,94,95 1040.99 -4 1040.99 -4 1078 170 c 0,96,97 1113.08 334.959 1113.08 334.959 1113.1 447.845 c 0,98,99 1113.1 454.001 1113.1 454.001 1113 460 c 0,100,101 1111.01 586.996 1111.01 586.996 1030 636 c 0,102,103 949 685 949 685 856 667 c 0,104,105 753.973 646.352 753.973 646.352 720.5 592 c 0,106,107 673.661 518 673.661 518 608 518 c 0,108,109 554 518 554 518 528 537 c 0,110,111 627.133 541.425 627.133 541.425 627.252 603.216 c 0,112,113 627.265 610.238 627.265 610.238 626 618 c 0,114,115 614.656 687.608 614.656 687.608 539 671 c 0,116,117 470.971 656.062 470.971 656.062 437.5 614 c 0,118,119 381.001 543.002 381.001 543.002 365 441 c 0,120,121 353.351 369.356 353.351 369.356 353.406 284.484 c 0,122,123 353.445 223.641 353.445 223.641 359.5 156 c 0,124,125 374 -6 374 -6 262 -68 c 0,126,127 308.115 30.5945 308.115 30.5945 274 92 c 0,128,129 254.66 126.814 254.66 126.814 187.626 127.026 c 0,130,131 185.341 127.033 185.341 127.033 183 127 c 0,132,133 153.87 123.844 l 0,134,135 79.7216 105.672 79.7216 105.672 79 -17 c 0,136,137 77.9999 -186.999 77.9999 -186.999 128 -308 c 1,0,1 564 987 m 0,77,78 564 913 564 913 632.5 878.5 c 0,79,80 701 844 701 844 782.5 839.5 c 0,81,82 871.984 834.559 871.984 834.559 930.5 856 c 0,83,84 996 880 996 880 993 914 c 0,85,86 987.893 969.548 987.893 969.548 889.5 1045 c 0,87,88 832.997 1088.33 832.997 1088.33 832.548 1133.03 c 0,89,90 836.254 1156.84 l 0,91,92 842.636 1176.79 842.636 1176.79 860 1197 c 0,93,94 858.922 1165.93 l 0,95,96 861.742 1140.27 861.742 1140.27 880.656 1139.92 c 0,97,98 893.5 1142 l 0,99,100 919.125 1149.84 919.125 1149.84 919.484 1172.94 c 0,101,102 915.537 1194.44 l 0,103,104 913.05 1201.75 913.05 1201.75 909 1210 c 0,105,106 881.004 1263.99 881.004 1263.99 815 1328 c 0,107,108 767.167 1374.39 767.167 1374.39 731.412 1374.55 c 0,109,110 717.835 1374.61 717.835 1374.61 706 1368 c 0,111,112 658 1341 658 1341 664.5 1294.5 c 0,113,114 670.998 1248.01 670.998 1248.01 689 1196 c 0,115,116 707.001 1143.99 707.001 1143.99 714.5 1094.5 c 0,117,118 722 1045 722 1045 677 1012 c 0,119,120 698 1091.99 698 1091.99 617 1078 c 0,121,122 564.452 1070.36 564.452 1070.36 563.972 992.397 c 0,123,124 563.956 989.741 563.956 989.741 564 987 c 0,77,78 509 1815 m 1,99,100 455 1950 455 1950 538 2068.5 c 0,101,102 614.315 2177.46 614.315 2177.46 728.667 2177.78 c 0,103,104 738.687 2177.81 738.687 2177.81 749 2177 c 0,105,106 618.485 2101.78 618.485 2101.78 618.174 2040.1 c 0,107,108 618.142 2033.73 618.142 2033.73 619.5 2027.5 c 0,109,110 627.779 1989.54 627.779 1989.54 673.706 1989.54 c 0,111,112 708.221 1989.55 708.221 1989.55 764 2011 c 0,113,114 745.001 1939.01 745.001 1939.01 646.5 1914 c 0,115,116 548 1888.99 548 1888.99 509 1815 c 1,99,100 1081 1812 m 1,108,109 1077.59 1842.42 l 0,110,111 1078.03 1909.94 1078.03 1909.94 1140 2017 c 0,112,113 1210.35 2138.52 1210.35 2138.52 1316.61 2138.99 c 0,114,115 1326.64 2139.04 1326.64 2139.04 1337 2138 c 0,116,117 1282.21 2087.85 1282.21 2087.85 1282.18 2034.27 c 0,118,119 1282.18 2030.14 1282.18 2030.14 1282.5 2026 c 0,120,121 1285.05 1993.14 1285.05 1993.14 1326.92 1993.02 c 0,122,123 1358.95 1992.93 1358.95 1992.93 1414 2012 c 0,124,125 1358.01 1928 1358.01 1928 1264.5 1910 c 0,126,127 1171.01 1892 1171.01 1892 1081 1812 c 1,108,109 EndSplineSet EndChar StartChar: Oacute Encoding: 211 211 45 Width: 1442 Flags: W Fore 702 -166 m 0,0,1 595.001 -155.001 595.001 -155.001 494.5 -66 c 0,2,3 394 23 394 23 316.5 126.5 c 0,4,5 239 230 239 230 192 315 c 0,6,7 145 400.001 145 400.001 145 402 c 0,8,9 128.001 450 128.001 450 92.5 525.5 c 0,10,11 57.0008 600.998 57.0008 600.998 34 678 c 0,12,13 11 755 11 755 16 820.5 c 0,14,15 20.9999 885.999 20.9999 885.999 86 914 c 0,16,17 120.999 928 120.999 928 151 910 c 0,18,19 76 883 76 883 92 806.5 c 0,20,21 108.001 730 108.001 730 144 769 c 0,22,23 185.999 812.998 185.999 812.998 246 939.5 c 0,24,25 281.016 1013.32 281.016 1013.32 281.292 1054.96 c 0,26,27 281.388 1069.49 281.388 1069.49 277.259 1080.1 c 0,28,29 272.94 1091.19 272.94 1091.19 264 1098 c 0,30,31 250.79 1107.15 250.79 1107.15 239.416 1107.23 c 0,32,33 226.112 1107.32 226.112 1107.32 215.319 1095.02 c 0,34,35 208.425 1087.16 208.425 1087.16 202 1073 c 0,36,37 191.968 1050.32 191.968 1050.32 192.019 1029.54 c 0,38,39 192.085 1002.68 192.085 1002.68 209 979 c 0,40,41 143.612 1022.32 143.612 1022.32 143.36 1067.98 c 0,42,43 143.304 1078.18 143.304 1078.18 146.5 1088.5 c 0,44,45 164.001 1145.01 164.001 1145.01 222 1193.5 c 0,46,47 280.032 1242.02 280.032 1242.02 350 1277 c 0,48,49 420.039 1312.01 420.039 1312.01 445 1321 c 0,50,51 491 1339 491 1339 595 1370.5 c 0,52,53 671.347 1393.62 671.347 1393.62 672.246 1429.41 c 0,54,55 668.639 1446.62 l 0,56,57 666.47 1451.7 666.47 1451.7 663 1457 c 0,58,59 646.528 1481.71 646.528 1481.71 625.907 1481.67 c 0,60,61 611.47 1481.65 611.47 1481.65 595 1469.5 c 0,62,63 554.997 1439.99 554.997 1439.99 543 1410 c 0,64,65 535.72 1416.76 535.72 1416.76 535.606 1430.01 c 0,66,67 535.507 1441.42 535.507 1441.42 541.5 1460 c 0,68,69 553.997 1497 553.997 1497 564 1506 c 0,70,71 632 1564.99 632 1564.99 717.5 1536 c 0,72,73 802.989 1507.01 802.989 1507.01 890 1438 c 0,74,75 977.001 1369 977.001 1369 1057 1284.5 c 0,76,77 1136.96 1200.04 1136.96 1200.04 1194 1148 c 0,78,79 1225.01 1119.01 1225.01 1119.01 1236 1169 c 0,80,81 1236.66 1189.31 l 0,82,83 1230.47 1227.67 1230.47 1227.67 1167 1261 c 0,84,85 1307.99 1261 1307.99 1261 1328.5 1135 c 0,86,87 1337.08 1082.31 1337.08 1082.31 1336.99 1022.87 c 0,88,89 1336.87 940.211 1336.87 940.211 1320 844.5 c 0,90,91 1291.02 680.102 1291.02 680.102 1247 520.5 c 0,92,93 1213.1 397.602 1213.1 397.602 1213.03 329.64 c 0,94,95 1213.01 309.382 1213.01 309.382 1216 294 c 0,96,97 1219 276 1219 276 1243 276.5 c 0,98,99 1266.99 276.999 1266.99 276.999 1283 295 c 0,100,101 1337 358 1337 358 1292 429 c 0,102,103 1349 412.001 1349 412.001 1358 350 c 0,104,105 1360.83 303.874 l 0,106,107 1358.57 224.182 1358.57 224.182 1302.5 174 c 0,108,109 1230.99 109.998 1230.99 109.998 1124.5 74.5 c 0,110,111 1018 39 1018 39 903.5 23 c 0,112,113 789 6.99995 789 6.99995 720 -9 c 0,114,115 666 -21 666 -21 709 -76.5 c 0,116,117 724.904 -97.0275 724.904 -97.0275 749.016 -96.9665 c 0,118,119 790.096 -96.8626 790.096 -96.8626 855 -37 c 0,120,121 843 -89.0001 843 -89.0001 797 -129.5 c 0,122,123 755.357 -166.164 755.357 -166.164 711.257 -166.359 c 0,124,125 706.642 -166.379 706.642 -166.379 702 -166 c 0,0,1 529 896 m 0,66,67 484.999 861 484.999 861 450 857.5 c 0,68,69 415 854 415 854 385 860 c 0,70,71 514 904 514 904 484 1000 c 0,72,73 479.058 1014.83 479.058 1014.83 459.197 1014.73 c 0,74,75 454.941 1014.71 454.941 1014.71 450 1014 c 0,76,77 421.994 1009.99 421.994 1009.99 409 998 c 0,78,79 370.001 960.001 370.001 960.001 332.5 887.5 c 0,80,81 295 815 295 815 274 739 c 0,82,83 253 663 253 663 256 600 c 0,84,85 259 537 259 537 301 521 c 0,86,87 406 479 406 479 388.5 555 c 0,88,89 371 631 371 631 317 642 c 0,90,91 370 663 370 663 417.5 617 c 0,92,93 465.001 570.999 465.001 570.999 497 502.5 c 0,94,95 529.001 433.997 529.001 433.997 541 365.5 c 0,96,97 553 297 553 297 535 273 c 0,98,99 534 318.001 534 318.001 504.5 336 c 0,100,101 475 354 475 354 448 323 c 0,102,103 414.348 283.229 414.348 283.229 414.233 251.128 c 0,104,105 414.135 223.66 414.135 223.66 438.591 201.807 c 0,106,107 441.609 199.111 441.609 199.111 445 196.5 c 0,108,109 508 148.001 508 148.001 617.5 141 c 0,110,111 727 133.999 727 133.999 842 174 c 0,112,113 957 214 957 214 996 314 c 0,114,115 1004.81 337.305 1004.81 337.305 1004.94 355.037 c 0,116,117 1005.04 368.522 1005.04 368.522 1000.11 378.784 c 0,118,119 988.723 402.504 988.723 402.504 950.5 409 c 0,120,121 874 422 874 422 893 308 c 0,122,123 855.407 364.132 855.407 364.132 855.207 406.739 c 0,124,125 855.109 427.468 855.109 427.468 863.863 444.996 c 0,126,127 872.055 461.4 872.055 461.4 888 475 c 0,128,129 956.012 533.01 956.012 533.01 1034 609 c 0,130,131 1157 729 1157 729 1139 875.5 c 0,132,133 1121 1022 1121 1022 995 1139 c 0,134,135 911.451 1215.28 911.451 1215.28 853.874 1215.69 c 0,136,137 848.054 1215.73 848.054 1215.73 842.5 1215 c 0,138,139 782 1207.01 782 1207.01 734 1153.5 c 0,140,141 685.991 1099.98 685.991 1099.98 639.5 1023.5 c 0,142,143 593 947 593 947 529 896 c 0,66,67 834 1616 m 1,109,110 771.325 1690.07 771.325 1690.07 771.259 1771.76 c 0,111,112 771.244 1790.43 771.244 1790.43 774.5 1809.5 c 0,113,114 792 1911.99 792 1911.99 860 1982 c 0,115,116 927.993 2052 927.993 2052 1025.5 2068.5 c 0,117,118 1123 2085 1123 2085 1207 2004 c 0,119,120 1142.86 2052.29 1142.86 2052.29 1091.17 2052.27 c 0,121,122 1071.15 2052.26 1071.15 2052.26 1053 2045 c 0,123,124 988.002 2019 988.002 2019 956.5 1966.5 c 0,125,126 925 1914 925 1914 933 1867.5 c 0,127,128 938.015 1838.35 938.015 1838.35 963.071 1838.08 c 0,129,130 985.38 1842.18 l 0,131,132 992.25 1844.45 992.25 1844.45 1000 1848 c 0,133,134 1013.12 1852.92 1013.12 1852.92 1013.09 1871.6 c 0,135,136 1013.06 1887.07 1013.06 1887.07 1004 1912 c 0,137,138 1040.78 1864.25 1040.78 1864.25 1040.82 1834.9 c 0,139,140 1040.83 1826.74 1040.83 1826.74 1038 1820 c 0,141,142 1025 1789 1025 1789 986 1764 c 0,143,-1 900.5 1708 l 0,144,145 853.995 1676.99 853.995 1676.99 834 1616 c 1,109,110 EndSplineSet KernsSLIF: 84 -286 0 0 87 -182 0 0 EndChar StartChar: Odieresis Encoding: 214 214 79 Width: 1622 Flags: HW Fore 1078 -11 m 0,0,1 1064.01 0.998647 1064.01 0.998647 973.5 11.5 c 0,2,3 883 22 883 22 778 24 c 0,4,5 673 26 673 26 585.5 15 c 0,6,7 499.124 4.14128 499.124 4.14128 491 -27 c 0,8,9 485 -50 485 -50 507.5 -75 c 0,10,11 530 -100 530 -100 615 -130 c 0,12,13 563.194 -132.16 l 0,14,15 497.059 -129.791 497.059 -129.791 433 -101 c 0,16,17 325.829 -52.8336 325.829 -52.8336 300 23 c 0,18,19 240.001 203.998 240.001 203.998 222.5 289 c 0,20,21 190.738 481.604 190.738 481.604 176 512 c 0,22,23 128 611 128 611 44.5 753.5 c 0,24,25 -39.0001 896 -39.0001 896 43 1037 c 0,26,27 37 930 37 930 69 916.5 c 0,28,29 101 903 101 903 132 921 c 0,30,31 165 941 165 941 227 1097.5 c 0,32,33 289.014 1254.03 289.014 1254.03 306 1300 c 0,34,35 321.216 1342.27 321.216 1342.27 321.243 1370.28 c 0,36,37 321.265 1394.44 321.265 1394.44 310 1408 c 0,38,39 289.612 1432.55 289.612 1432.55 262.475 1432.69 c 0,40,41 243.542 1432.78 243.542 1432.78 221.325 1421 c 0,42,43 198.844 1409.08 198.844 1409.08 173 1385 c 0,44,45 183 1455 183 1455 225 1491 c 0,46,47 283.465 1538.64 283.465 1538.64 372.5 1543 c 0,48,49 411.143 1545.55 411.143 1545.55 546 1607.5 c 0,50,51 605.628 1634.94 605.628 1634.94 705 1636 c 0,52,53 799.002 1637.01 799.002 1637.01 813 1682 c 0,54,55 832 1746.01 832 1746.01 714 1766 c 0,56,57 744.427 1778.86 744.427 1778.86 774.49 1778.95 c 0,58,59 807.009 1779.05 807.009 1779.05 839.1 1764.21 c 0,60,61 846.561 1760.76 846.561 1760.76 854 1756.5 c 0,62,63 922.99 1717.01 922.99 1717.01 985.5 1648 c 0,64,65 1048.01 1579 1048.01 1579 1101 1501 c 0,66,67 1153.99 1423.01 1153.99 1423.01 1193 1376 c 0,68,69 1258.99 1295.01 1258.99 1295.01 1395.5 1208.5 c 0,70,71 1531.99 1122 1531.99 1122 1545 955 c 0,72,73 1493.91 1031.63 1493.91 1031.63 1456.6 1031.78 c 0,74,75 1450.09 1031.8 1450.09 1031.8 1444 1029.5 c 0,76,77 1403 1014 1403 1014 1395 988 c 0,78,79 1368.69 904.7 1368.69 904.7 1368.67 830.234 c 0,80,81 1368.66 785.795 1368.66 785.795 1378 744.5 c 0,82,83 1413.42 587.936 1413.42 587.936 1437 543.5 c 0,84,85 1485.01 452.991 1485.01 452.991 1485.5 381.5 c 0,86,87 1487.95 300.016 1487.95 300.016 1436 257 c 0,88,89 1444.29 298.88 1444.29 298.88 1444.3 328.871 c 0,90,91 1444.31 367.613 1444.31 367.613 1430.5 386.5 c 0,92,93 1412.56 411.031 1412.56 411.031 1386.84 411.164 c 0,94,95 1377.44 411.213 1377.44 411.213 1367 408 c 0,96,97 1341.99 400 1341.99 400 1311.5 301 c 0,98,99 1281.05 202.142 1281.05 202.142 1240 93.5 c 0,100,101 1189.08 -41.2672 1189.08 -41.2672 1145 -92 c 0,102,103 1105.04 -137.992 1105.04 -137.992 1053.71 -137.938 c 0,104,105 1036.96 -137.921 1036.96 -137.921 1019 -133 c 0,106,107 1091 -116.999 1091 -116.999 1100 -78.5 c 0,108,109 1101.97 -55.1353 l 0,110,111 1099.91 -29.7823 1099.91 -29.7823 1078 -11 c 0,0,1 645 195 m 0,62,63 762.759 189.131 762.759 189.131 808.5 268.5 c 0,64,65 885 399 885 399 996 351 c 0,66,67 909.315 332.426 909.315 332.426 948 261 c 0,68,69 966.315 227.184 966.315 227.184 1035 231 c 0,70,71 1090.8 234.1 1090.8 234.1 1138 328.5 c 0,72,73 1210.49 473.474 1210.49 473.474 1218 561.5 c 0,74,75 1224.79 641.024 1224.79 641.024 1224.69 711.756 c 0,76,77 1224.62 765.961 1224.62 765.961 1220.5 815 c 0,78,79 1206.48 958.433 1206.48 958.433 1193 985 c 0,80,81 1174.69 1020.77 1174.69 1020.77 1130 1010.5 c 0,82,83 1085.67 1001.18 1085.67 1001.18 1085.09 966.896 c 0,84,85 1089.04 942.902 l 0,86,87 1092.23 932.685 1092.23 932.685 1098 921 c 0,88,89 1018.73 960.128 1018.73 960.128 1008 1035 c 0,90,91 1008.69 1052 1008.69 1052 1016.5 1197 c 0,92,93 1019.84 1268.11 1019.84 1268.11 961 1356 c 0,94,95 933.657 1396.84 933.657 1396.84 792 1419 c 0,96,97 759.176 1420.36 l 0,98,99 704.916 1416.09 704.916 1416.09 658.5 1367.5 c 0,100,101 570.656 1275.53 570.656 1275.53 568 1232.5 c 0,102,103 553.425 996.171 553.425 996.171 549 981 c 0,104,105 515.298 859.438 515.298 859.438 442.5 819 c 0,106,107 486.422 946.219 486.422 946.219 363 948.5 c 0,108,109 309.74 949.484 309.74 949.484 312 819 c 0,110,111 314.316 685.281 314.316 685.281 318 642 c 0,112,113 327.896 514.557 327.896 514.557 374 427 c 0,114,115 450.349 282.004 450.349 282.004 489 249 c 0,116,117 547.345 199.867 547.345 199.867 645 195 c 0,62,63 290 1856 m 1,94,95 294.001 1943.01 294.001 1943.01 364.5 2072.5 c 0,96,97 435 2202 435 2202 526 2218 c 0,98,99 467.076 2106.95 467.076 2106.95 466.932 2058.68 c 0,100,101 466.886 2043.05 466.886 2043.05 473 2034 c 0,102,103 497.993 1997.01 497.993 1997.01 583 1993 c 0,104,105 571.999 1943 571.999 1943 455 1914.5 c 0,106,107 338 1886 338 1886 290 1856 c 1,94,95 1051 1877 m 1,103,104 1063 1958.01 1063 1958.01 1145 2049.5 c 0,105,106 1227.01 2141 1227.01 2141 1326 2165 c 0,107,108 1259 2099.01 1259 2099.01 1245.5 2036 c 0,109,110 1244.66 2015.26 l 0,111,112 1251.83 1967.83 1251.83 1967.83 1347 1943 c 0,113,114 1311.37 1914.87 1311.37 1914.87 1267.16 1914.68 c 0,115,116 1244.88 1914.58 1244.88 1914.58 1220.42 1921.57 c 0,117,118 1215.75 1922.91 1215.75 1922.91 1211 1924.5 c 0,119,120 1190.26 1931.46 1190.26 1931.46 1169.39 1931.49 c 0,121,122 1110.74 1931.58 1110.74 1931.58 1051 1877 c 1,103,104 EndSplineSet EndChar StartChar: Udieresis Encoding: 220 220 77 Width: 1564 Flags: HW Fore 934.5 -28 m 128,-1,0 945 -89.9999 945 -89.9999 1050 -50 c 0,1,2 1006.09 -119.363 1006.09 -119.363 934.178 -119.579 c 0,3,4 901.082 -119.678 901.082 -119.678 862.054 -105.131 c 0,5,6 855.121 -102.547 855.121 -102.547 848 -99.5 c 0,7,8 819.129 -87.1482 819.129 -87.1482 609 -54 c 0,9,-1 445 -26 l 0,10,11 324 -27 324 -27 318 108 c 0,12,13 370.439 64.3008 370.439 64.3008 408.5 112 c 0,14,15 417.639 123.453 417.639 123.453 417.618 139.02 c 0,16,17 417.598 154.083 417.598 154.083 409 173 c 0,18,19 389.182 216.601 389.182 216.601 357 252 c 0,20,-1 307 307 l 0,21,22 283.139 331.714 283.139 331.714 245 311.5 c 0,23,24 213.696 295.848 213.696 295.848 213.789 268.858 c 0,25,26 213.854 250.152 213.854 250.152 229 226 c 0,27,28 164.711 239.834 164.711 239.834 164.281 312.053 c 0,29,30 164.189 327.45 164.189 327.45 167 345.5 c 0,31,32 171.076 371.671 171.076 371.671 171.038 399.582 c 0,33,34 170.963 454.432 170.963 454.432 155 516 c 0,35,36 106.307 701.036 106.307 701.036 57.5 767.5 c 0,37,38 -42 906 -42 906 28 1063 c 0,39,40 30.0443 991.442 30.0443 991.442 69.5 991.5 c 0,41,42 98.0043 991.542 98.0043 991.542 112 1027 c 0,43,44 115.628 1036.19 115.628 1036.19 115.6 1052.67 c 0,45,46 115.51 1104.31 115.51 1104.31 79.5 1227.5 c 0,47,48 34.0309 1383.05 34.0309 1383.05 33.9195 1433.69 c 0,49,50 33.9145 1435.95 33.9145 1435.95 34 1438 c 0,51,52 38.9997 1630.99 38.9997 1630.99 161 1782 c 0,53,54 121.48 1676.06 121.48 1676.06 121.46 1567.79 c 0,55,56 121.453 1531.03 121.453 1531.03 126 1494 c 0,57,58 145.116 1338.34 145.116 1338.34 247 1320 c 0,59,60 271.932 1319.82 l 0,61,62 301.474 1323.99 301.474 1323.99 340 1347.5 c 0,63,64 408.002 1389.01 408.002 1389.01 429 1501 c 0,65,66 469 1403.01 469 1403.01 434.5 1315 c 0,67,68 402.62 1233.68 402.62 1233.68 390 1118 c 0,69,70 386.268 1050.09 l 0,71,72 386.641 983.869 386.641 983.869 404.5 934 c 0,73,74 411.708 913.872 411.708 913.872 411.703 895.446 c 0,75,76 411.688 846.128 411.688 846.128 360 809 c 0,77,78 372 866 372 866 354 888.5 c 0,79,80 328.77 920.038 328.77 920.038 300 866 c 0,81,82 291.392 849.833 291.392 849.833 291.384 816.023 c 0,83,84 291.375 776.696 291.375 776.696 303 713.5 c 0,85,86 322.001 607.499 322.001 607.499 337 567.5 c 0,87,88 362.966 495.17 362.966 495.17 399 435 c 0,89,90 463.641 335.174 463.641 335.174 520 288 c 0,91,92 563.185 268.568 563.185 268.568 581 283.5 c 0,93,94 615 312 615 312 572 367 c 0,95,96 694.138 356.907 694.138 356.907 709.5 243 c 0,97,98 720.458 160.941 720.458 160.941 775.5 166.5 c 0,99,100 843.666 172.427 843.666 172.427 885 261 c 0,101,102 923.283 343.035 923.283 343.035 944.5 420.5 c 0,103,104 975.867 535.024 975.867 535.024 981 573 c 0,105,106 996.001 687.004 996.001 687.004 1069 738 c 0,107,108 1054.05 699.755 1054.05 699.755 1053.95 673.431 c 0,109,110 1053.85 648.277 1053.85 648.277 1067.3 634.007 c 0,111,112 1072.24 628.771 1072.24 628.771 1079 625 c 0,113,114 1089.88 618.928 1089.88 618.928 1101.28 618.984 c 0,115,116 1117.15 619.061 1117.15 619.061 1134 631 c 0,117,118 1158.82 648.023 1158.82 648.023 1158.75 739.476 c 0,119,120 1158.72 776.982 1158.72 776.982 1154.5 827 c 0,121,122 1139.2 1008.54 1139.2 1008.54 1122 1097 c 0,123,124 1097.76 1221.73 1097.76 1221.73 1080.5 1273.5 c 0,125,126 1063.07 1325.8 1063.07 1325.8 1063.03 1375.37 c 0,127,128 1062.97 1455.21 1062.97 1455.21 1108 1528 c 0,129,130 1118.73 1412.85 1118.73 1412.85 1175.5 1374.5 c 0,131,132 1218.91 1345.17 1218.91 1345.17 1245.11 1344.85 c 0,133,134 1260.78 1347.91 l 0,135,136 1263.55 1349.19 1263.55 1349.19 1266 1351 c 0,137,138 1338.58 1407.54 1338.58 1407.54 1358 1591.5 c 0,139,140 1363.39 1642.57 1363.39 1642.57 1363.33 1689.38 c 0,141,142 1363.21 1781.42 1363.21 1781.42 1342 1857 c 0,143,144 1407.99 1746.01 1407.99 1746.01 1425.5 1582 c 0,145,146 1431.64 1524.47 1431.64 1524.47 1431.56 1469.76 c 0,147,148 1431.42 1368.54 1431.42 1368.54 1410 1277 c 0,149,150 1389.43 1189.71 1389.43 1189.71 1389.41 1113.87 c 0,151,152 1389.4 1053.29 1389.4 1053.29 1402.5 1000 c 0,153,154 1413.81 954.001 1413.81 954.001 1413.73 916.817 c 0,155,156 1413.6 857.002 1413.6 857.002 1384 820 c 0,157,158 1382.46 849.538 l 0,159,160 1377.56 874.521 1377.56 874.521 1359.5 887 c 0,161,162 1353.45 891.18 1353.45 891.18 1347.91 891.101 c 0,163,164 1328.26 890.82 1328.26 890.82 1315 837 c 0,165,166 1299.92 775.08 1299.92 775.08 1299.92 700.686 c 0,167,168 1299.92 636.926 1299.92 636.926 1311 564 c 0,169,170 1335 406 1335 406 1272 322 c 0,171,172 1272 435 1272 435 1221 426 c 0,173,174 1166.23 416.106 1166.23 416.106 1047 219 c 0,175,176 926.422 19.6906 926.422 19.6906 934.5 -28 c 128,-1,0 194 1948 m 1,92,93 246.065 1994.11 246.065 1994.11 269.5 2145.5 c 0,94,95 287.998 2264.99 287.998 2264.99 402 2296 c 0,96,97 332.966 2219.29 332.966 2219.29 333.064 2156.71 c 0,98,99 333.094 2137.71 333.094 2137.71 339.5 2120 c 0,100,101 358.415 2064.52 358.415 2064.52 387.209 2063.76 c 0,102,103 403.103 2067.17 l 0,104,105 425.939 2077.12 425.939 2077.12 454 2116 c 0,106,107 465.818 2098.7 465.818 2098.7 465.962 2079.71 c 0,108,109 466.059 2067.01 466.059 2067.01 460.94 2053.55 c 0,110,111 447.15 2017.29 447.15 2017.29 395.5 1975.5 c 0,112,113 335.507 1926.96 335.507 1926.96 274.599 1926.96 c 0,114,115 234.497 1926.96 234.497 1926.96 194 1948 c 1,92,93 1193 1962 m 1,101,102 1226.99 1976.99 1226.99 1976.99 1252 2032.5 c 0,103,104 1276.85 2085.8 1276.85 2085.8 1297 2142.5 c 0,105,106 1319.99 2197.98 1319.99 2197.98 1351.5 2236.5 c 0,107,108 1374 2264 1374 2264 1409 2264.2 c 0,109,110 1423 2264.29 1423 2264.29 1439 2260 c 0,111,112 1405.72 2244.42 1405.72 2244.42 1380.5 2194 c 0,113,114 1358.7 2150.38 1358.7 2150.38 1358.67 2098.08 c 0,115,116 1358.67 2091.61 1358.67 2091.61 1359 2085 c 0,117,118 1361.09 2061.73 1361.09 2061.73 1403 2050.5 c 0,119,120 1424.24 2049.35 l 0,121,122 1450 2052.01 1450 2052.01 1490 2071 c 0,123,124 1442.32 1997.88 1442.32 1997.88 1335 1953.5 c 0,125,126 1299.06 1938.64 1299.06 1938.64 1267.06 1938.64 c 0,127,128 1227.48 1938.63 1227.48 1938.63 1193 1962 c 1,101,102 EndSplineSet EndChar StartChar: germandbls Encoding: 223 223 85 Width: 1114 Flags: HMW VStem: 55 281<-368 1583> Fore 118 967 m 0,0,1 118 1084.53 118 1084.53 88 1118 c 0,2,3 34 1178 34 1178 62 1274 c 0,4,5 69.7902 1199.99 69.7902 1199.99 124 1247 c 0,6,7 134.791 1256.36 134.791 1256.36 148 1330 c 0,8,9 154 1363.45 154 1363.45 154 1436 c 0,10,11 154 1497.94 154 1497.94 119 1533 c 0,12,13 94.3849 1557.65 94.3849 1557.65 55.2625 1557.79 c 0,14,15 32.9829 1557.87 32.9829 1557.87 6 1550 c 0,16,17 97.9904 1627.49 97.9904 1627.49 183.416 1627.57 c 0,18,19 201.861 1627.59 201.861 1627.59 220 1624 c 0,20,21 251.926 1617.67 251.926 1617.67 371 1574 c 0,22,23 389.214 1567.32 389.214 1567.32 544 1540 c 0,24,25 583.266 1536.42 l 0,26,27 621.488 1537.23 621.488 1537.23 632 1560 c 0,28,29 637.571 1573 637.571 1573 637.538 1582.98 c 0,30,31 637.428 1616 637.428 1616 576 1616 c 0,32,33 659.582 1645.07 659.582 1645.07 698 1581.5 c 0,34,35 744.865 1503.95 744.865 1503.95 786 1494 c 0,36,37 830.007 1483.99 830.007 1483.99 908 1436 c 0,38,39 943.792 1413.98 943.792 1413.98 944.051 1385.79 c 0,40,41 944.151 1374.93 944.151 1374.93 938.978 1363.16 c 0,42,43 938.07 1361.09 938.07 1361.09 937 1359 c 0,44,45 927.441 1382.05 927.441 1382.05 909.851 1382.55 c 0,46,47 893.461 1378.91 l 0,48,49 884.467 1375.02 884.467 1375.02 874 1367 c 0,50,51 867.597 1362.09 867.597 1362.09 867.581 1353.42 c 0,52,53 867.53 1327.07 867.53 1327.07 926.5 1266 c 0,54,55 972.687 1218.16 972.687 1218.16 972.762 1181.23 c 0,56,57 972.794 1165.07 972.794 1165.07 964 1151 c 0,58,59 968.156 1203.53 968.156 1203.53 920 1172 c 0,60,61 891.619 1153.41 891.619 1153.41 880 1096 c 0,62,63 873.279 1062.79 873.279 1062.79 873.335 1041.2 c 0,64,65 873.41 1011.87 873.41 1011.87 886 1004 c 0,66,67 896.666 997.333 896.666 997.333 906.222 997.333 c 0,68,69 925.333 997.333 925.333 997.333 940 1024 c 0,70,71 955.756 941.28 955.756 941.28 762 870 c 0,72,73 695.301 845.461 695.301 845.461 708 774 c 0,74,75 719.596 708.712 719.596 708.712 767.426 708.519 c 0,76,77 774.784 708.489 774.784 708.489 783 710 c 0,78,79 957 742 957 742 951 626 c 0,80,81 924.609 688.556 924.609 688.556 882 666 c 0,82,83 858.918 653.781 858.918 653.781 909 525 c 0,84,85 972.715 358.127 972.715 358.127 993 357 c 0,86,87 1035 354 1035 354 1041 411 c 0,88,89 1056.22 397.957 1056.22 397.957 1056.4 376.249 c 0,90,91 1056.5 364.686 1056.5 364.686 1052.34 350.665 c 0,92,93 1042.74 318.359 1042.74 318.359 1010.5 273 c 0,94,95 945.852 179.834 945.852 179.834 945.454 148.336 c 0,96,97 945.372 141.868 945.372 141.868 948 138 c 0,98,99 917.598 92.499 917.598 92.499 840.5 36 c 0,100,101 786.888 -3.30363 786.888 -3.30363 794 -41 c 0,102,103 804 -93.9999 804 -93.9999 890 -68 c 0,104,105 866.618 -120.33 866.618 -120.33 733.273 -120.517 c 0,106,107 685.65 -120.584 685.65 -120.584 624 -114 c 0,108,109 418 -91.9999 418 -91.9999 394 -45 c 0,110,111 625.996 -66.7838 625.996 -66.7838 714 75 c 0,112,113 722.786 89.1553 722.786 89.1553 723.001 101.566 c 0,114,115 719.591 117.104 l 0,116,117 716.737 123.045 716.737 123.045 711.5 128.5 c 0,118,119 701.576 138.839 701.576 138.839 689.308 138.97 c 0,120,121 680.36 139.067 680.36 139.067 670.166 133.733 c 0,122,123 660.629 128.743 660.629 128.743 650 119 c 0,124,125 652 165 652 165 701.5 187.5 c 0,126,127 780.66 223.482 780.66 223.482 796 242.5 c 0,128,129 815.469 266.638 815.469 266.638 819 351 c 0,130,131 816.128 388.012 l 0,132,133 807.98 434.589 807.98 434.589 777.5 498.5 c 0,134,135 759.191 536.891 759.191 536.891 723 585 c 0,136,137 680.348 641.698 680.348 641.698 644 645 c 0,138,139 628.856 642.918 l 0,140,141 618.212 638.877 618.212 638.877 608.5 627.5 c 0,142,143 590 608 590 608 613 579 c 0,144,145 588.638 580.55 l 0,146,147 552.063 589.3 552.063 589.3 534.5 638.5 c 0,148,149 513.743 696.65 513.743 696.65 469 735 c 0,150,151 474.064 740.88 474.064 740.88 406 801.5 c 0,152,153 386.095 819.228 386.095 819.228 385.923 839.472 c 0,154,155 385.827 850.808 385.827 850.808 393 865 c 0,156,157 399.384 832.1 399.384 832.1 431.868 831.868 c 0,158,159 445.55 831.771 445.55 831.771 463.862 837.468 c 0,160,161 478.251 841.945 478.251 841.945 495.5 850 c 0,162,163 592 896 592 896 607 919 c 0,164,165 617.211 934.495 617.211 934.495 618 948.5 c 0,166,167 620 984 620 984 578 969 c 0,168,169 582.733 1004.49 582.733 1004.49 686.5 1026 c 0,170,171 737.466 1036.56 737.466 1036.56 755 1073.5 c 0,172,173 768.109 1101.59 768.109 1101.59 768.067 1145.9 c 0,174,175 768.064 1148.91 768.064 1148.91 768 1152 c 0,176,177 766.896 1205.52 766.896 1205.52 759 1212.5 c 0,178,179 725 1242.5 725 1242.5 722 1197.5 c 0,180,181 679.373 1223.49 679.373 1223.49 678.841 1259.22 c 0,182,183 682.49 1282.11 l 0,184,185 684.128 1287.22 684.128 1287.22 686.5 1292.5 c 0,186,187 693.835 1309.57 693.835 1309.57 693.858 1326.34 c 0,188,189 693.884 1345.87 693.884 1345.87 684 1365 c 0,190,191 659.831 1408.89 659.831 1408.89 558 1389 c 0,192,193 488.278 1375.38 488.278 1375.38 467 1359 c 0,194,195 440.515 1338.04 440.515 1338.04 416.774 1338.07 c 0,196,197 397.482 1338.1 397.482 1338.1 380 1352 c 0,198,199 415.734 1352 415.734 1352 427 1363 c 0,200,201 436.501 1372.28 436.501 1372.28 436.539 1387.56 c 0,202,203 436.555 1393.78 436.555 1393.78 435 1401 c 0,204,205 428.085 1432.13 428.085 1432.13 417 1435 c 0,206,207 398.473 1439.81 398.473 1439.81 384.817 1439.86 c 0,208,209 366.071 1439.92 366.071 1439.92 356.5 1431 c 0,210,211 277.822 1354.86 277.822 1354.86 302 1306.5 c 0,212,213 328.119 1254.26 328.119 1254.26 328.201 1225.13 c 0,214,215 328.269 1201.37 328.269 1201.37 311 1193 c 0,216,217 311 1216.07 311 1216.07 295.615 1216.67 c 0,218,219 285 1215 l 0,220,221 255.639 1204.93 255.639 1204.93 255.571 1140.69 c 0,222,223 255.562 1132.76 255.562 1132.76 256 1124 c 0,224,225 259.68 1050.41 259.68 1050.41 271 1033 c 0,226,227 286.562 1010.12 286.562 1010.12 302.5 1009.5 c 0,228,229 323.004 1009.7 323.004 1009.7 328 1038 c 0,230,231 355 996 355 996 330.5 920.5 c 0,232,233 306.001 845.001 306.001 845.001 302 807 c 0,234,235 299.425 755.455 l 0,236,237 301.69 689.489 301.69 689.489 338 668 c 0,238,239 387 639 387 639 360 579 c 0,240,241 355.031 622.897 355.031 622.897 321.24 623.294 c 0,242,243 315.096 623.366 315.096 623.366 308 622 c 0,244,245 271.879 615.048 271.879 615.048 266.5 483.5 c 0,246,247 266.151 393.507 l 0,248,249 268.939 337.887 268.939 337.887 281 321 c 0,250,251 294.707 301.81 294.707 301.81 317 304.5 c 0,252,253 343.999 307.999 343.999 307.999 348 349 c 0,254,255 378 316 378 316 352.5 227 c 0,256,257 323.944 127.336 323.944 127.336 291 51 c 0,258,259 272.96 9.19997 272.96 9.19997 272.925 -44.2157 c 0,260,261 272.88 -112.2 272.88 -112.2 302 -199 c 0,262,263 328 -276.499 328 -276.499 328 -326.999 c 0,264,265 328 -376.818 328 -376.818 302 -401 c 0,266,267 302.608 -376.581 l 0,268,269 298.602 -349.953 298.602 -349.953 272.5 -332.5 c 0,270,271 242.027 -312.125 242.027 -312.125 218 -312 c 0,272,273 175.052 -314.051 175.052 -314.051 141 -347.5 c 0,274,275 121.999 -366 121.999 -366 105 -421 c 0,276,277 92 -461 92 -461 89.5 -519 c 0,278,279 86.9999 -577 86.9999 -577 94 -622 c 0,280,281 74.9999 -568 74.9999 -568 61 -503 c 0,282,283 47.9576 -442.447 47.9576 -442.447 55 -368 c 0,284,285 62 -294 62 -294 91 -142.5 c 0,286,287 119.999 9 119.999 9 81 94 c 0,288,289 63.9996 128.001 63.9996 128.001 48 196.5 c 0,290,291 41.9721 222.307 41.9721 222.307 42.0474 243.927 c 0,292,293 42.1721 279.693 42.1721 279.693 59 304 c 0,294,295 56.1273 271.443 56.1273 271.443 79 271 c 0,296,297 95.4265 270.777 95.4265 270.777 110 288 c 0,298,299 130.215 313.73 130.215 313.73 136 360 c 0,300,301 140.9 399.204 140.9 399.204 127 465 c 0,302,303 121.971 496.186 121.971 496.186 101 501 c 0,304,305 51.9536 514 51.9536 514 58 450 c 0,306,307 42.0932 466.57 42.0932 466.57 42.0707 502.115 c 0,308,309 42.0269 571.209 42.0269 571.209 102 712 c 0,310,311 118.001 749.562 118.001 749.562 118 967 c 0,0,1 EndSplineSet KernsSLIF: 116 -195 0 0 84 -313 0 0 EndChar StartChar: adieresis Encoding: 228 228 76 Width: 1332 Flags: HW Fore 108.8 -261.8 m 1,0,1 28.0497 -147.901 28.0497 -147.901 17.4248 -43.3496 c 0,2,3 6.79985 61.2002 6.79985 61.2002 31.875 156.825 c 0,4,5 56.9505 252.451 56.9505 252.451 100.725 339.575 c 0,6,7 144.501 426.702 144.501 426.702 172.55 505.75 c 0,8,9 190.4 555.899 190.4 555.899 192.95 647.275 c 0,10,11 195.5 738.65 195.5 738.65 204.425 831.725 c 0,12,13 213.35 924.8 213.35 924.8 240.125 1000.45 c 0,14,15 266.904 1076.11 266.904 1076.11 334.9 1095.65 c 0,16,17 270.299 1031.9 270.299 1031.9 308.125 983.45 c 0,18,19 322.192 966.021 322.192 966.021 352.75 975.8 c 0,20,21 375.215 982.988 375.215 982.988 396.1 1090.55 c 0,22,23 413.098 1178.1 413.098 1178.1 495.975 1300.92 c 0,24,25 576.726 1421.98 576.726 1421.98 642.175 1473.47 c 0,26,27 684.84 1507.04 684.84 1507.04 731.145 1506.95 c 0,28,29 775.711 1506.86 775.711 1506.86 823.65 1475.6 c 0,30,31 791.682 1476.23 l 0,32,33 734.526 1470.01 734.526 1470.01 723.35 1405.05 c 0,34,35 720.073 1363.06 l 0,36,37 720.858 1302.78 720.858 1302.78 752.25 1237.17 c 0,38,39 794.078 1149.77 794.078 1149.77 821.1 1152.6 c 0,40,41 853.4 1156.01 853.4 1156.01 855.95 1172.58 c 0,42,43 856.239 1189.56 l 0,44,45 852.29 1209.9 852.29 1209.9 827.9 1230.8 c 0,46,47 926.311 1212.47 926.311 1212.47 926.925 1115.62 c 0,48,49 926.826 1076.61 926.826 1076.61 946.613 970.938 c 0,50,51 951.299 945.912 951.299 945.912 957.1 917.15 c 0,52,53 977.5 815.151 977.5 815.151 993.225 781.575 c 0,54,55 1005.77 754.812 1005.77 754.812 1024.74 754.627 c 0,56,57 1030.95 754.566 1030.95 754.566 1037.85 757.35 c 0,58,59 1078.88 773.9 1078.88 773.9 1071 821.1 c 0,60,61 1060.8 882.3 1060.8 882.3 1027.65 920.55 c 0,62,63 1101.6 875.501 1101.6 875.501 1122.42 816.85 c 0,64,65 1139.96 767.482 1139.96 767.482 1140.01 715.971 c 0,66,67 1140.02 706.31 1140.02 706.31 1139.42 696.575 c 0,68,69 1135.59 634.892 1135.59 634.892 1122 577.15 c 0,70,71 1112.87 538.38 1112.87 538.38 1112.93 506.472 c 0,72,73 1112.96 490.835 1112.96 490.835 1115.2 476.85 c 0,74,75 1127.95 388.465 1127.95 388.465 1167.9 300.05 c 0,76,77 1207.87 211.588 1207.87 211.588 1235.47 116.45 c 0,78,79 1259.51 33.6266 1259.51 33.6266 1259.42 -56.6199 c 0,80,81 1258.85 -83.7246 l 0,82,83 1254.61 -188.683 1254.61 -188.683 1178.95 -311.1 c 0,84,85 1203.42 -228.959 1203.42 -228.959 1203.33 -128.066 c 0,86,87 1203.3 -81.7345 1203.3 -81.7345 1198.08 -31.4502 c 0,88,89 1181.92 124.337 1181.92 124.337 1072.39 125.071 c 0,90,91 1068.77 125.095 1068.77 125.095 1065.05 124.95 c 0,92,93 1000.37 122.43 1000.37 122.43 980.05 67.5752 c 0,94,95 960.501 12.75 960.501 12.75 982.6 -62.0498 c 0,96,97 884.849 -3.4004 884.849 -3.4004 916.3 144.5 c 0,98,99 946.219 285.196 946.219 285.196 946.137 381.283 c 0,100,101 946.133 386.201 946.133 386.201 946.05 391 c 0,102,103 944.351 498.949 944.351 498.949 875.5 540.6 c 0,104,105 806.65 582.25 806.65 582.25 727.6 566.95 c 0,106,107 640.877 549.399 640.877 549.399 612.425 503.2 c 0,108,109 572.61 440.3 572.61 440.3 516.8 440.3 c 0,110,111 470.899 440.3 470.899 440.3 448.8 456.45 c 0,112,113 542.639 460.64 542.639 460.64 532.1 525.3 c 0,114,115 524.543 571.665 524.543 571.665 483.418 573.028 c 0,116,117 458.15 570.35 l 0,118,119 400.326 557.651 400.326 557.651 371.875 521.9 c 0,120,121 323.851 461.552 323.851 461.552 310.25 374.85 c 0,122,123 300.338 313.888 300.338 313.888 300.395 241.659 c 0,124,125 300.436 190.01 300.436 190.01 305.575 132.6 c 0,126,127 317.9 -5.09955 317.9 -5.09955 222.7 -57.7998 c 0,128,129 261.896 26.0049 261.896 26.0049 232.9 78.2002 c 0,130,131 216.34 108.009 216.34 108.009 155.55 107.95 c 0,132,133 128.74 104.737 l 0,134,135 67.7534 88.1114 67.7534 88.1114 67.1504 -14.4502 c 0,136,137 66.2997 -158.949 66.2997 -158.949 108.8 -261.8 c 1,0,1 479.4 838.95 m 0,77,78 479.4 776.051 479.4 776.051 537.625 746.725 c 0,79,80 595.851 717.4 595.851 717.4 665.125 713.575 c 0,81,82 724.336 714 l 0,83,84 762.062 717.024 762.062 717.024 790.925 727.6 c 0,85,86 843.456 746.848 843.456 746.848 844.05 776.9 c 0,87,88 839.707 824.116 839.707 824.116 756.075 888.25 c 0,89,90 707.698 925.347 707.698 925.347 707.663 963.627 c 0,91,92 707.638 990.253 707.638 990.253 731 1017.45 c 0,93,94 730.287 989.406 l 0,95,96 733.091 969.257 733.091 969.257 748.499 968.932 c 0,97,98 759.475 970.7 l 0,99,100 781.225 977.353 781.225 977.353 781.56 996.947 c 0,101,102 777.499 1017.28 l 0,103,104 775.544 1022.6 775.544 1022.6 772.65 1028.5 c 0,105,106 748.854 1074.39 748.854 1074.39 692.75 1128.8 c 0,107,108 652.395 1167.94 652.395 1167.94 622.154 1168.36 c 0,109,110 604.83 1165.09 l 0,111,112 602.425 1164.1 602.425 1164.1 600.1 1162.8 c 0,113,114 564.525 1142.79 564.525 1142.79 564.17 1110.18 c 0,115,116 564.118 1105.39 564.118 1105.39 564.825 1100.33 c 0,117,118 570.349 1060.81 570.349 1060.81 585.65 1016.6 c 0,119,120 600.95 972.4 600.95 972.4 607.325 930.325 c 0,121,122 613.7 888.25 613.7 888.25 575.45 860.2 c 0,123,124 593.3 928.2 593.3 928.2 524.45 916.3 c 0,125,126 479.456 909.755 479.456 909.755 479.4 838.95 c 0,77,78 432.65 1542.75 m 1,99,100 414.656 1587.74 414.656 1587.74 414.559 1630.56 c 0,101,102 414.46 1674.09 414.46 1674.09 432.846 1715.39 c 0,103,104 442.516 1737.11 442.516 1737.11 457.3 1758.22 c 0,105,106 522.348 1851.09 522.348 1851.09 619.897 1851.11 c 0,107,108 628.156 1851.11 628.156 1851.11 636.65 1850.45 c 0,109,110 525.809 1786.57 525.809 1786.57 525.449 1734.18 c 0,111,112 525.411 1728.72 525.411 1728.72 526.575 1723.38 c 0,113,114 533.582 1691.24 533.582 1691.24 572.317 1691.11 c 0,115,116 601.716 1691.01 601.716 1691.01 649.4 1709.35 c 0,117,118 633.251 1648.15 633.251 1648.15 549.525 1626.9 c 0,119,120 465.8 1605.65 465.8 1605.65 432.65 1542.75 c 1,99,100 918.85 1540.2 m 1,108,109 915.999 1568.74 l 0,110,111 917.542 1625.56 917.542 1625.56 969 1714.45 c 0,112,113 1028.97 1818.05 1028.97 1818.05 1119.65 1818.14 c 0,114,115 1127.92 1818.15 1127.92 1818.15 1136.45 1817.3 c 0,116,117 1089.98 1774.77 1089.98 1774.77 1089.85 1729.33 c 0,118,119 1089.84 1725.72 1089.84 1725.72 1090.12 1722.1 c 0,120,121 1092.3 1693.97 1092.3 1693.97 1128.39 1694.07 c 0,122,123 1155.54 1694.14 1155.54 1694.14 1201.9 1710.2 c 0,124,125 1154.31 1638.8 1154.31 1638.8 1074.83 1623.5 c 0,126,127 995.359 1608.2 995.359 1608.2 918.85 1540.2 c 1,108,109 EndSplineSet EndChar StartChar: oacute Encoding: 243 243 46 Width: 1230 Flags: HW Fore 601 -2 m 0,0,1 510 5.99999 510 5.99999 424.5 82 c 0,2,3 338.998 158.003 338.998 158.003 273 246 c 0,4,5 207.001 333.999 207.001 333.999 167 406 c 0,6,7 127 477.999 127 477.999 127 480 c 0,8,9 113.001 520 113.001 520 83 584.5 c 0,10,11 53 649 53 649 33.5 714.5 c 0,12,13 14 780 14 780 18 835.5 c 0,14,15 22 891 22 891 77 915 c 0,16,17 106 927 106 927 133 912 c 0,18,19 80.6363 893.182 80.6363 893.182 80.1529 846.248 c 0,20,21 82.5 824 l 0,22,23 96 759 96 759 127 792 c 0,24,25 162.002 830.002 162.002 830.002 213.5 937.5 c 0,26,27 243.557 1000.24 243.557 1000.24 243.809 1035.56 c 0,28,29 243.905 1049 243.905 1049 239.684 1058.47 c 0,30,31 235.993 1066.76 235.993 1066.76 229 1072 c 0,32,33 217.589 1079.95 217.589 1079.95 207.672 1079.89 c 0,34,35 188.912 1079.78 188.912 1079.78 175.5 1051 c 0,36,37 166.787 1032.3 166.787 1032.3 166.655 1015.05 c 0,38,39 166.556 1002.3 166.556 1002.3 171.139 990.344 c 0,40,41 174.951 980.399 174.951 980.399 182 971 c 0,42,43 126.43 1007.77 126.43 1007.77 126.29 1046.55 c 0,44,45 126.258 1055.23 126.258 1055.23 129 1064 c 0,46,47 143.998 1111.99 143.998 1111.99 193.5 1153.5 c 0,48,49 242.971 1194.98 242.971 1194.98 302.5 1224.5 c 0,50,51 362 1254.01 362 1254.01 383 1262 c 0,52,53 421.942 1276.98 421.942 1276.98 510 1303.5 c 0,54,55 598 1330.01 598 1330.01 568 1377 c 0,56,57 553.93 1398.1 553.93 1398.1 536.426 1398.25 c 0,58,59 524.536 1398.34 524.536 1398.34 510 1388 c 0,60,61 476 1362.99 476 1362.99 465 1337 c 0,62,63 458.647 1342.82 458.647 1342.82 458.741 1354.39 c 0,64,65 458.824 1364.68 458.824 1364.68 464 1379.5 c 0,66,67 475.002 1411.01 475.002 1411.01 484 1419 c 0,68,69 541 1468.99 541 1468.99 614 1444.5 c 0,70,71 686.989 1420.01 686.989 1420.01 760.5 1361.5 c 0,72,73 834 1303 834 1303 902 1231 c 0,74,75 970.031 1158.97 970.031 1158.97 1019 1115 c 0,76,77 1028.75 1105.97 1028.75 1105.97 1036.15 1105.75 c 0,78,79 1043.94 1108.44 l 0,80,81 1051.13 1114.23 1051.13 1114.23 1055 1132.5 c 0,82,83 1055.19 1151.12 l 0,84,85 1048.84 1183.02 1048.84 1183.02 996 1211 c 0,86,87 1116 1211 1116 1211 1133.5 1103.5 c 0,88,89 1140.87 1058.24 1140.87 1058.24 1140.79 1007.3 c 0,90,91 1140.68 937.275 1140.68 937.275 1126.5 856.5 c 0,92,93 1102.01 717.049 1102.01 717.049 1064.5 581.5 c 0,94,95 1035.57 476.98 1035.57 476.98 1035.51 419.158 c 0,96,97 1035.49 402.028 1035.49 402.028 1038 389 c 0,98,99 1039.99 374 1039.99 374 1060.5 374.5 c 0,100,101 1080.99 374.999 1080.99 374.999 1094 390 c 0,102,103 1119.37 418.072 1119.37 418.072 1119.68 448.764 c 0,104,105 1115.99 473.526 l 0,106,107 1111.6 487.99 1111.6 487.99 1102 503 c 0,108,109 1150 489 1150 489 1159 437 c 0,110,111 1161.09 395.311 l 0,112,113 1158.04 329.427 1158.04 329.427 1111.5 287.5 c 0,114,115 1051.01 233.004 1051.01 233.004 960.5 202.5 c 0,116,117 869.996 171.999 869.996 171.999 772.5 158 c 0,118,119 675.01 144.002 675.01 144.002 616 130 c 0,120,121 570 119.001 570 119.001 607 72.5 c 0,122,123 620.616 55.388 620.616 55.388 641.139 55.4071 c 0,124,125 676.384 55.44 676.384 55.44 732 106 c 0,126,127 721 61 721 61 682 28 c 0,128,129 643 -5 643 -5 601 -2 c 0,0,1 454 901 m 0,66,67 416 871 416 871 387 867.5 c 0,68,69 358 864 358 864 331 870 c 0,70,71 419.739 899.849 419.739 899.849 419.97 958.983 c 0,72,73 420.025 973.151 420.025 973.151 415 989 c 0,74,75 411.054 1000.84 411.054 1000.84 395.575 1001.15 c 0,76,77 391.448 1001.24 391.448 1001.24 386.5 1000.5 c 0,78,79 363 997 363 997 352 987 c 0,80,81 286 924 286 924 237 767 c 0,82,83 217.135 703.352 217.135 703.352 217.157 660.905 c 0,84,85 217.189 598.649 217.189 598.649 260 582 c 0,86,87 350 546 350 546 334.5 610.5 c 0,88,89 319 675 319 675 273 684 c 0,90,91 318 702 318 702 358.5 663 c 0,92,93 399 624 399 624 426.5 566 c 0,94,95 454 508 454 508 464 449.5 c 0,96,97 474 391 474 391 459 371 c 0,98,99 458 408 458 408 432.5 424 c 0,100,101 407 440 407 440 385 413 c 0,102,103 356.738 379.691 356.738 379.691 356.366 352.75 c 0,104,105 359.552 334.59 l 0,106,107 365.495 319.032 365.495 319.032 382.5 306 c 0,108,109 436 265 436 265 529 259 c 0,110,111 622 253 622 253 720 287 c 0,112,113 818 321.001 818 321.001 851 406 c 0,114,115 877 475 877 475 812 486.5 c 0,116,117 790.15 486.903 l 0,118,119 759.741 481.142 759.741 481.142 759.84 434.141 c 0,120,121 759.871 419.164 759.871 419.164 763 400 c 0,122,123 731.127 447.81 731.127 447.81 730.967 483.991 c 0,124,125 730.869 506.399 730.869 506.399 742.934 524.347 c 0,126,127 749.283 533.791 749.283 533.791 759 542 c 0,128,129 817 591 817 591 883 657 c 0,130,131 988 759 988 759 973 883 c 0,132,133 958.001 1006.99 958.001 1006.99 850 1107 c 0,134,135 778.288 1172.36 778.288 1172.36 729.654 1172.62 c 0,136,137 724.708 1172.65 724.708 1172.65 720 1172 c 0,138,139 668.989 1164.99 668.989 1164.99 628 1119 c 0,140,141 586.987 1072.98 586.987 1072.98 547.5 1008.5 c 0,142,143 508 944 508 944 454 901 c 0,66,67 713 1513 m 1,107,108 659.89 1575.91 659.89 1575.91 659.855 1645.51 c 0,109,110 659.847 1661.09 659.847 1661.09 662.5 1677 c 0,111,112 677 1764 677 1764 735 1823.5 c 0,113,114 793 1883.01 793 1883.01 876 1897 c 0,115,116 911.02 1899.19 l 0,117,118 974.217 1896.21 974.217 1896.21 1030 1842 c 0,119,120 976.262 1882.84 976.262 1882.84 932.539 1883.13 c 0,121,122 917.33 1883.23 917.33 1883.23 903.333 1878.42 c 0,123,124 901.405 1877.76 901.405 1877.76 899.5 1877 c 0,125,126 843.996 1854.99 843.996 1854.99 817 1810 c 0,127,128 795.751 1774.59 795.751 1774.59 795.56 1742.58 c 0,129,130 795.509 1733.91 795.509 1733.91 797 1725.5 c 0,131,132 804 1686.01 804 1686.01 854 1709 c 0,133,134 864.909 1713.36 864.909 1713.36 865.107 1729.33 c 0,135,136 860.634 1755.7 l 0,137,138 859.468 1759.69 859.468 1759.69 858 1764 c 0,139,140 887.56 1724.58 887.56 1724.58 888.396 1699.82 c 0,141,142 886 1685.5 l 0,143,144 875.003 1659 875.003 1659 842 1638 c 0,145,-1 769.5 1591 l 0,146,147 729.999 1565 729.999 1565 713 1513 c 1,107,108 EndSplineSet KernsSLIF: 116 -234 0 0 119 -156 0 0 EndChar StartChar: odieresis Encoding: 246 246 80 Width: 1378 Flags: HW Fore 916.3 -9.34961 m 0,0,1 904.401 0.849471 904.401 0.849471 827.475 9.77539 c 0,2,3 750.552 18.7001 750.552 18.7001 661.3 20.4004 c 0,4,5 572.05 22.0996 572.05 22.0996 497.675 12.75 c 0,6,7 424.255 3.52052 424.255 3.52052 417.35 -22.9502 c 0,8,9 412.25 -42.5 412.25 -42.5 431.375 -63.75 c 0,10,11 450.5 -85.0001 450.5 -85.0001 522.75 -110.5 c 0,12,13 475.333 -112.195 l 0,14,15 420.862 -109.586 420.862 -109.586 368.05 -85.8496 c 0,16,17 276.266 -44.5988 276.266 -44.5988 255 19.5498 c 0,18,19 204.001 173.398 204.001 173.398 189.125 245.65 c 0,20,21 162.128 409.363 162.128 409.363 149.6 435.2 c 0,22,23 108.8 519.35 108.8 519.35 37.8252 640.475 c 0,24,25 -33.1504 761.6 -33.1504 761.6 36.5498 881.45 c 0,26,27 36.886 828.045 l 0,28,29 40.8577 786.531 40.8577 786.531 58.6504 779.025 c 0,30,31 85.8496 767.55 85.8496 767.55 112.2 782.85 c 0,32,33 140.25 799.849 140.25 799.849 192.95 932.875 c 0,34,35 245.705 1066.04 245.705 1066.04 260.1 1105 c 0,36,37 272.902 1140.56 272.902 1140.56 273.054 1164.26 c 0,38,39 273.151 1179.36 273.151 1179.36 268.108 1189.64 c 0,40,41 266.18 1193.57 266.18 1193.57 263.5 1196.8 c 0,42,43 246.17 1217.66 246.17 1217.66 223.104 1217.78 c 0,44,45 203.924 1217.88 203.924 1217.88 180.779 1203.64 c 0,46,47 164.853 1193.84 164.853 1193.84 147.05 1177.25 c 0,48,49 155.55 1236.75 155.55 1236.75 191.25 1267.35 c 0,50,51 240.928 1307.83 240.928 1307.83 316.625 1311.55 c 0,52,53 349.497 1313.73 349.497 1313.73 464.1 1366.38 c 0,54,55 514.772 1389.7 514.772 1389.7 599.25 1390.6 c 0,56,57 679.152 1391.46 679.152 1391.46 691.05 1429.7 c 0,58,59 707.201 1484.1 707.201 1484.1 606.9 1501.1 c 0,60,61 667.25 1526.6 667.25 1526.6 725.9 1493.03 c 0,62,63 784.558 1459.44 784.558 1459.44 837.675 1400.8 c 0,64,65 890.8 1342.15 890.8 1342.15 935.85 1275.85 c 0,66,67 980.915 1209.53 980.915 1209.53 1014.05 1169.6 c 0,68,69 1070.16 1100.74 1070.16 1100.74 1186.17 1027.22 c 0,70,71 1302.19 953.7 1302.19 953.7 1313.25 811.75 c 0,72,73 1269.97 876.665 1269.97 876.665 1238.32 877.009 c 0,74,75 1232.68 877.07 1232.68 877.07 1227.4 875.075 c 0,76,77 1192.54 861.896 1192.54 861.896 1185.75 839.8 c 0,78,79 1163.33 768.803 1163.33 768.803 1163.37 705.357 c 0,80,81 1163.39 667.767 1163.39 667.767 1171.3 632.825 c 0,82,83 1201.41 499.741 1201.41 499.741 1221.45 461.975 c 0,84,85 1262.25 385.05 1262.25 385.05 1262.67 324.275 c 0,86,87 1260.17 287.831 l 0,88,89 1252.31 244.712 1252.31 244.712 1220.6 218.45 c 0,90,91 1236.76 300.05 1236.76 300.05 1215.92 328.525 c 0,92,93 1200.89 349.086 1200.89 349.086 1179.42 349.482 c 0,94,95 1161.95 346.8 l 0,96,97 1140.7 340.002 1140.7 340.002 1114.78 255.85 c 0,98,99 1088.84 171.7 1088.84 171.7 1054 79.4746 c 0,100,101 1010.71 -35.0859 1010.71 -35.0859 973.25 -78.2002 c 0,102,103 939.558 -116.979 939.558 -116.979 896.355 -117.246 c 0,104,105 881.793 -117.336 881.793 -117.336 866.15 -113.05 c 0,106,107 927.35 -99.4494 927.35 -99.4494 935 -66.7246 c 0,108,109 936.469 -44.7745 l 0,110,111 934.018 -24.5366 934.018 -24.5366 916.3 -9.34961 c 0,0,1 548.25 165.75 m 0,62,63 648.347 160.761 648.347 160.761 687.225 228.225 c 0,64,65 752.25 339.15 752.25 339.15 846.6 298.35 c 0,66,67 772.919 282.561 772.919 282.561 805.8 221.85 c 0,68,69 821.369 193.105 821.369 193.105 879.75 196.35 c 0,70,71 927.179 198.985 927.179 198.985 967.3 279.225 c 0,72,73 1028.91 402.453 1028.91 402.453 1035.3 477.275 c 0,74,75 1041.05 544.612 1041.05 544.612 1040.99 604.498 c 0,76,77 1040.95 650.853 1040.95 650.853 1037.42 692.75 c 0,78,79 1025.49 814.679 1025.49 814.679 1014.05 837.25 c 0,80,81 998.48 867.665 998.48 867.665 960.5 858.925 c 0,82,83 922.666 850.974 922.666 850.974 922.325 821.624 c 0,84,85 926.362 799.386 l 0,86,87 928.982 791.603 928.982 791.603 933.3 782.85 c 0,88,89 865.909 816.107 865.909 816.107 856.8 879.75 c 0,90,91 857.365 893.879 857.365 893.879 864.025 1017.45 c 0,92,93 866.867 1077.89 866.867 1077.89 816.85 1152.6 c 0,94,95 793.608 1187.32 793.608 1187.32 673.2 1206.15 c 0,96,97 610.858 1215.9 610.858 1215.9 559.725 1162.38 c 0,98,99 485.058 1084.22 485.058 1084.22 482.8 1047.62 c 0,100,101 470.41 846.737 470.41 846.737 466.65 833.85 c 0,102,103 438.003 730.523 438.003 730.523 376.125 696.15 c 0,104,105 413.458 804.286 413.458 804.286 308.55 806.225 c 0,106,107 294.277 803.159 l 0,108,109 265.044 788.558 265.044 788.558 265.122 704.552 c 0,110,111 265.126 700.434 265.126 700.434 265.2 696.15 c 0,112,113 267.169 582.489 267.169 582.489 270.3 545.7 c 0,114,115 278.711 437.373 278.711 437.373 317.9 362.95 c 0,116,117 383.163 239.008 383.163 239.008 415.65 211.65 c 0,118,119 465.243 169.889 465.243 169.889 548.25 165.75 c 0,62,63 246.5 1577.6 m 1,94,95 249.901 1651.55 249.901 1651.55 309.825 1761.62 c 0,96,97 369.744 1871.69 369.744 1871.69 447.1 1885.3 c 0,98,99 396.908 1790.71 396.908 1790.71 396.892 1749.7 c 0,100,101 396.887 1736.54 396.887 1736.54 402.05 1728.9 c 0,102,103 423.294 1697.46 423.294 1697.46 495.55 1694.05 c 0,104,105 486.201 1651.56 486.201 1651.56 386.75 1627.33 c 0,106,107 287.314 1603.11 287.314 1603.11 246.5 1577.6 c 1,94,95 893.35 1595.45 m 1,103,104 903.551 1664.31 903.551 1664.31 973.25 1742.08 c 0,105,106 1042.95 1819.85 1042.95 1819.85 1127.1 1840.25 c 0,107,108 1070.15 1784.15 1070.15 1784.15 1058.67 1730.6 c 0,109,110 1047.2 1677.05 1047.2 1677.05 1144.95 1651.55 c 0,111,112 1114.52 1627.53 1114.52 1627.53 1076.72 1627.48 c 0,113,114 1054.33 1627.45 1054.33 1627.45 1029.35 1635.83 c 0,115,116 962.2 1658.34 962.2 1658.34 893.35 1595.45 c 1,103,104 EndSplineSet EndChar StartChar: udieresis Encoding: 252 252 78 Width: 1329 Flags: HW Fore 794.325 -23.7998 m 128,-1,0 803.25 -76.5 803.25 -76.5 892.5 -42.5 c 0,1,2 855.06 -101.644 855.06 -101.644 793.666 -101.642 c 0,3,4 760.689 -101.641 760.689 -101.641 720.8 -84.5752 c 0,5,6 696.261 -74.0762 696.261 -74.0762 517.65 -45.9004 c 0,7,-1 378.25 -22.0996 l 0,8,9 345.296 -18.8683 l 0,10,11 274.509 -2.90244 274.509 -2.90244 270.3 91.7998 c 0,12,13 314.873 54.6553 314.873 54.6553 347.225 95.2002 c 0,14,15 354.846 104.75 354.846 104.75 354.974 117.666 c 0,16,17 355.071 127.561 355.071 127.561 350.77 139.432 c 0,18,19 349.425 143.144 349.425 143.144 347.65 147.05 c 0,20,21 330.805 184.111 330.805 184.111 303.45 214.2 c 0,22,-1 260.95 260.95 l 0,23,24 240.668 281.956 240.668 281.956 208.25 264.775 c 0,25,26 181.797 251.548 181.797 251.548 181.721 228.796 c 0,27,28 181.667 212.801 181.667 212.801 194.65 192.1 c 0,29,30 140.102 203.838 140.102 203.838 139.64 265.025 c 0,31,32 139.541 278.203 139.541 278.203 141.95 293.675 c 0,33,34 145.373 341.637 l 0,35,36 145.028 387.385 145.028 387.385 131.75 438.6 c 0,37,38 90.3602 595.881 90.3602 595.881 48.875 652.375 c 0,39,40 -35.7002 770.099 -35.7002 770.099 23.7998 903.55 c 0,41,42 25.5382 842.726 25.5382 842.726 59.0752 842.775 c 0,43,44 83.3029 842.811 83.3029 842.811 95.2002 872.95 c 0,45,46 107.95 905.249 107.95 905.249 67.5752 1043.38 c 0,47,48 27.2001 1181.5 27.2001 1181.5 28.9004 1222.3 c 0,49,50 33.1501 1386.34 33.1501 1386.34 136.85 1514.7 c 0,51,52 91.8515 1394.07 91.8515 1394.07 107.1 1269.9 c 0,53,54 123.35 1137.58 123.35 1137.58 209.95 1122 c 0,55,56 232.44 1122.04 l 0,57,58 257.102 1125.91 257.102 1125.91 289 1145.38 c 0,59,60 346.8 1180.65 346.8 1180.65 364.65 1275.85 c 0,61,62 398.65 1192.55 398.65 1192.55 369.325 1117.75 c 0,63,64 342.227 1048.63 342.227 1048.63 331.5 950.3 c 0,65,66 328.38 887.9 l 0,67,68 329.279 834.519 329.279 834.519 343.825 793.9 c 0,69,70 350.026 776.584 350.026 776.584 349.946 760.75 c 0,71,72 349.736 719.066 349.736 719.066 306 687.65 c 0,73,74 316.2 736.1 316.2 736.1 300.9 755.225 c 0,75,76 279.454 782.031 279.454 782.031 255 736.1 c 0,77,78 239.174 706.375 239.174 706.375 257.55 606.475 c 0,79,80 273.701 516.374 273.701 516.374 286.45 482.375 c 0,81,82 308.524 420.886 308.524 420.886 339.15 369.75 c 0,83,84 394.097 284.896 394.097 284.896 442 244.8 c 0,85,86 462.424 235.609 462.424 235.609 476.172 235.462 c 0,87,88 485.273 235.364 485.273 235.364 493.85 240.975 c 0,89,90 506.463 251.547 506.463 251.547 506.61 266.41 c 0,91,92 506.707 276.331 506.707 276.331 501.251 288.163 c 0,93,94 496.151 299.222 496.151 299.222 486.2 311.95 c 0,95,96 590.019 303.37 590.019 303.37 603.075 206.55 c 0,97,98 612.388 136.8 612.388 136.8 659.175 141.525 c 0,99,100 717.115 146.564 717.115 146.564 752.25 221.85 c 0,101,102 784.79 291.579 784.79 291.579 802.825 357.425 c 0,103,104 829.489 454.781 829.489 454.781 833.85 487.05 c 0,105,106 846.6 583.95 846.6 583.95 908.65 627.3 c 0,107,108 879.354 552.334 879.354 552.334 917.15 531.25 c 0,109,110 939.276 518.908 939.276 518.908 963.9 536.35 c 0,111,112 984.9 550.75 984.9 550.75 984.935 627.832 c 0,113,114 984.95 659.95 984.95 659.95 981.325 702.95 c 0,115,116 968.318 857.227 968.318 857.227 953.7 932.45 c 0,117,118 933.107 1038.42 933.107 1038.42 918.425 1082.47 c 0,119,120 903.528 1127.16 903.528 1127.16 903.575 1169.52 c 0,121,122 903.651 1237.13 903.651 1237.13 941.8 1298.8 c 0,123,124 950.924 1200.93 950.924 1200.93 999.175 1168.33 c 0,125,126 1036.52 1143.09 1036.52 1143.09 1058.89 1143.12 c 0,127,128 1069.04 1143.14 1069.04 1143.14 1076.1 1148.35 c 0,129,130 1137.78 1196.39 1137.78 1196.39 1154.3 1352.78 c 0,131,132 1158.92 1396.53 1158.92 1396.53 1158.83 1436.6 c 0,133,134 1158.66 1514.46 1158.66 1514.46 1140.7 1578.45 c 0,135,136 1196.81 1484.09 1196.81 1484.09 1211.67 1344.7 c 0,137,138 1216.91 1295.64 1216.91 1295.64 1216.83 1248.99 c 0,139,140 1216.68 1163.11 1216.68 1163.11 1198.5 1085.45 c 0,141,142 1180.94 1010.95 1180.94 1010.95 1181 946.244 c 0,143,144 1181.05 895.058 1181.05 895.058 1192.12 850 c 0,145,146 1217.2 748 1217.2 748 1176.4 697 c 0,147,148 1174.77 723.682 l 0,149,150 1170.35 743.741 1170.35 743.741 1155.58 753.95 c 0,151,152 1132.2 770.1 1132.2 770.1 1117.75 711.45 c 0,153,154 1104.92 658.776 1104.92 658.776 1104.93 595.482 c 0,155,156 1104.94 541.33 1104.94 541.33 1114.35 479.4 c 0,157,158 1120.07 441.729 1120.07 441.729 1119.98 409.006 c 0,159,160 1119.73 325.072 1119.73 325.072 1081.2 273.7 c 0,161,162 1081.2 362.144 1081.2 362.144 1044.44 362.661 c 0,163,164 1041.28 362.706 1041.28 362.706 1037.85 362.1 c 0,165,166 991.308 353.69 991.308 353.69 889.95 186.15 c 0,167,168 787.459 16.7373 787.459 16.7373 794.325 -23.7998 c 128,-1,0 164.9 1655.8 m 1,92,93 209.152 1694.99 209.152 1694.99 229.075 1823.67 c 0,94,95 244.799 1925.24 244.799 1925.24 341.7 1951.6 c 0,96,97 283.098 1886.48 283.098 1886.48 283.104 1833.34 c 0,98,99 283.106 1817.11 283.106 1817.11 288.575 1802 c 0,100,101 304.802 1754.41 304.802 1754.41 329.579 1754.19 c 0,102,103 340.419 1754.09 340.419 1754.09 352.896 1763.06 c 0,104,105 368.171 1774.03 368.171 1774.03 385.9 1798.6 c 0,106,107 420.75 1747.6 420.75 1747.6 336.175 1679.17 c 0,108,109 251.6 1610.76 251.6 1610.76 164.9 1655.8 c 1,92,93 1014.05 1667.7 m 1,101,102 1042.95 1680.45 1042.95 1680.45 1064.2 1727.62 c 0,103,104 1085.34 1772.94 1085.34 1772.94 1102.45 1821.12 c 0,105,106 1121.99 1868.28 1121.99 1868.28 1148.78 1901.03 c 0,107,108 1168 1924.51 1168 1924.51 1197.93 1924.57 c 0,109,110 1209.71 1924.6 1209.71 1924.6 1223.15 1921 c 0,111,112 1194.86 1907.76 1194.86 1907.76 1173.42 1864.9 c 0,113,114 1154.85 1827.74 1154.85 1827.74 1154.87 1783.15 c 0,115,116 1154.87 1777.75 1154.87 1777.75 1155.15 1772.25 c 0,117,118 1156.92 1752.48 1156.92 1752.48 1192.55 1742.92 c 0,119,120 1216.35 1736.55 1216.35 1736.55 1266.5 1760.35 c 0,121,122 1225.96 1698.19 1225.96 1698.19 1134.75 1660.47 c 0,123,124 1104.12 1647.8 1104.12 1647.8 1076.85 1647.84 c 0,125,126 1042.83 1647.88 1042.83 1647.88 1014.05 1667.7 c 1,101,102 EndSplineSet EndChar StartChar: Aogonek Encoding: 260 260 79 Width: 1433 Flags: HW Fore 1029 333 m 0,0,1 1023.7 401.322 1023.7 401.322 971 464 c 0,2,3 877 590 877 590 812.5 602.5 c 0,4,5 744.95 615.59 744.95 615.59 699 592.5 c 0,6,-1 607.5 541.5 l 0,7,8 546 534 546 534 522 591 c 0,9,10 512.517 613.165 512.517 613.165 518.5 646.5 c 0,11,12 521.999 665.998 521.999 665.998 539 687 c 0,13,14 554.303 602.429 554.303 602.429 598 660.5 c 0,15,16 637.977 713.627 637.977 713.627 580 748 c 0,17,18 442.531 829.503 442.531 829.503 400.5 697 c 0,19,20 371.001 604.004 371.001 604.004 365.5 479 c 0,21,22 359.999 353.995 359.999 353.995 330.5 250 c 0,23,24 306.258 164.54 306.258 164.54 200.652 164.16 c 0,25,26 177.741 164.078 177.741 164.078 151 168 c 0,27,28 207 174 207 174 229.5 192 c 0,29,30 253.321 209.628 253.321 209.628 253.516 233.935 c 0,31,32 253.613 245.962 253.613 245.962 247.925 259.624 c 0,33,34 246.616 262.768 246.616 262.768 245 266 c 0,35,36 210.517 328.87 210.517 328.87 161 300.5 c 0,37,38 113.001 273.001 113.001 273.001 98.5 206.5 c 0,39,40 94.6267 188.736 94.6267 188.736 94.7136 170.045 c 0,41,42 94.9521 118.764 94.9521 118.764 125 60.5 c 0,43,44 165.999 -18.9998 165.999 -18.9998 307 -62 c 0,45,46 102 -62 102 -62 35 76.5 c 0,47,48 3.95718 140.67 3.95718 140.67 3.82694 205.378 c 0,49,50 3.72716 254.951 3.72716 254.951 21.7708 304.839 c 0,51,52 31.0079 330.378 31.0079 330.378 45 356 c 0,53,54 110.993 472.988 110.993 472.988 207.5 625.5 c 0,55,56 332.475 822.999 332.475 822.999 312 1096 c 0,57,58 312.923 1135.59 l 0,59,60 320.24 1195.69 320.24 1195.69 363.5 1255.5 c 0,61,62 399.342 1306.42 399.342 1306.42 444.631 1306.68 c 0,63,64 461.621 1306.78 461.621 1306.78 479.94 1299.75 c 0,65,66 494.548 1294.14 494.548 1294.14 510 1284 c 0,67,68 479.738 1283.76 l 0,69,70 447.266 1279 447.266 1279 427 1253.5 c 0,71,72 411.213 1233.8 411.213 1233.8 411.267 1214.56 c 0,73,74 411.319 1196.07 411.319 1196.07 426 1178 c 0,75,76 442.916 1157.08 442.916 1157.08 460.13 1156.77 c 0,77,78 475.394 1160.51 l 0,79,80 489.351 1167.58 489.351 1167.58 503.5 1188 c 0,81,82 542.995 1244.99 542.995 1244.99 580 1337 c 0,83,84 617 1428.99 617 1428.99 648.5 1523 c 0,85,86 679.997 1617 679.997 1617 703 1644 c 0,87,88 769 1722 769 1722 840 1714.5 c 0,89,90 911 1707 911 1707 911 1580 c 0,91,92 893.378 1613.83 893.378 1613.83 870.288 1613.88 c 0,93,94 860.623 1613.9 860.623 1613.9 850 1608 c 0,95,96 821.002 1591.01 821.002 1591.01 809 1529 c 0,97,98 800.755 1486.41 800.755 1486.41 800.771 1440.51 c 0,99,100 800.779 1419.59 800.779 1419.59 802.5 1398 c 0,101,102 808.001 1328.99 808.001 1328.99 832 1273 c 0,103,104 855.257 1218.74 855.257 1218.74 900 1215 c 0,105,106 936 1212 936 1212 927 1249.5 c 0,107,108 918 1287 918 1287 891 1320 c 0,109,110 949.002 1302 949.002 1302 969 1233.5 c 0,111,112 989 1164.99 989 1164.99 993 1080.5 c 0,113,114 995.825 937.374 l 0,115,116 995.723 924.927 995.723 924.927 995.5 912.5 c 0,117,118 994 829 994 829 1010 782 c 0,119,120 1023.01 742 1023.01 742 1098.5 638 c 0,121,122 1173.99 534 1173.99 534 1242.5 420 c 0,123,124 1311 306.016 1311 306.016 1338 208.5 c 0,125,126 1344.72 184.225 1344.72 184.225 1344.69 164.443 c 0,127,128 1344.59 104.775 1344.59 104.775 1283 86 c 0,129,130 1297.93 112.12 1297.93 112.12 1297.96 128.075 c 0,131,132 1298 152.964 1298 152.964 1261.79 153.122 c 0,133,134 1259 153.134 1259 153.134 1256 153 c 0,135,136 1228.22 152.133 1228.22 152.133 1228.3 114.634 c 0,137,138 1228.35 90.4386 1228.35 90.4386 1240 51 c 0,139,140 1280.48 -87.1799 1280.48 -87.1799 1280.48 -185.313 c 0,141,142 1280.48 -249.802 1280.48 -249.802 1263 -297 c 0,143,144 1234.55 -373.8 1234.55 -373.8 1191 -416 c 0,145,146 1107.92 -495.703 1107.92 -495.703 1027.5 -512.5 c 0,147,148 888.41 -542.467 888.41 -542.467 798 -505 c 0,149,150 874.226 -508.555 874.226 -508.555 927 -498 c 0,151,152 980.597 -487.281 980.597 -487.281 1038 -441 c 0,153,154 1076.94 -409.604 1076.94 -409.604 1099.5 -351.5 c 0,155,156 1104.33 -339.051 1104.33 -339.051 1104.24 -327.737 c 0,157,158 1104 -295.17 1104 -295.17 1063 -272 c 0,159,160 1048.68 -263.905 1048.68 -263.905 1035.82 -263.715 c 0,161,162 1019.54 -266.886 l 0,163,164 1002.14 -274.218 1002.14 -274.218 987 -300 c 0,165,166 975 -321 975 -321 984 -386 c 0,167,168 945.74 -313.824 945.74 -313.824 963 -263 c 0,169,170 981 -209.999 981 -209.999 1021 -191.5 c 0,171,172 1131.73 -140.111 1131.73 -140.111 1152 -75 c 0,173,174 1177.68 7.50585 1177.68 7.50585 1116 21 c 0,175,176 1069.64 31.1432 1069.64 31.1432 1059 18 c 0,177,178 1050.41 7.81504 1050.41 7.81504 1050.19 -3.31424 c 0,179,180 1053.95 -19.2845 l 0,181,182 1060.04 -32.0857 1060.04 -32.0857 1076 -46 c 0,183,184 1003.72 -45.1274 1003.72 -45.1274 1016 57 c 0,185,186 1031.7 187.605 1031.7 187.605 1031.61 272.387 c 0,187,188 1031.58 306.378 1031.58 306.378 1029 333 c 0,0,1 733 888 m 0,93,94 763.873 888.762 l 0,95,96 796.902 894.015 796.902 894.015 817.5 919.5 c 0,97,98 846.999 955.998 846.999 955.998 852.5 997.5 c 0,99,100 853.215 1029.13 l 0,101,102 851 1049.91 851 1049.91 841 1065.5 c 0,103,104 822.658 1086.53 822.658 1086.53 805.386 1086.66 c 0,105,106 795.518 1086.74 795.518 1086.74 786 1080 c 0,107,108 767.953 1069.48 767.953 1069.48 767.749 1054.02 c 0,109,110 767.651 1046.6 767.651 1046.6 771.657 1038.05 c 0,111,112 773.597 1033.91 773.597 1033.91 776.5 1029.5 c 0,113,114 789.996 1009 789.996 1009 823 997 c 0,115,116 746.568 970.543 746.568 970.543 715 1020 c 0,117,118 700.983 1041.96 700.983 1041.96 701.047 1068.4 c 0,119,120 701.12 1098.54 701.12 1098.54 719.5 1134.5 c 0,121,122 754.648 1203.27 754.648 1203.27 717 1220 c 0,123,124 681 1236.01 681 1236.01 640 1190 c 0,125,126 598.998 1143.99 598.998 1143.99 585.5 1079.5 c 0,127,128 572 1015 572 1015 600.5 956 c 0,129,130 629 897 629 897 733 888 c 0,93,94 EndSplineSet KernsSLIF: 87 -208 0 0 EndChar StartChar: aogonek Encoding: 261 261 80 Width: 1218 Flags: HW Fore 874.65 283.05 m 0,0,1 870.156 341.119 870.156 341.119 825.35 394.4 c 0,2,3 745.449 501.501 745.449 501.501 690.625 512.125 c 0,4,5 669.512 516.217 669.512 516.217 650.882 516.15 c 0,6,7 618.846 516.035 618.846 516.035 594.15 503.625 c 0,8,-1 516.375 460.275 l 0,9,10 464.1 453.9 464.1 453.9 443.7 502.35 c 0,11,12 438.716 514.002 438.716 514.002 438.758 529.284 c 0,13,14 438.785 538.714 438.785 538.714 440.725 549.525 c 0,15,16 443.699 566.098 443.699 566.098 458.15 583.95 c 0,17,18 465.711 542.167 465.711 542.167 481.426 541.346 c 0,19,20 492.256 544.975 l 0,21,22 499.619 549.888 499.619 549.888 508.3 561.425 c 0,23,24 542.28 606.583 542.28 606.583 493 635.8 c 0,25,26 448.906 661.942 448.906 661.942 416.364 662.182 c 0,27,28 402.973 662.28 402.973 662.28 391.537 657.992 c 0,29,30 357.121 645.087 357.121 645.087 340.425 592.45 c 0,31,32 315.351 513.404 315.351 513.404 310.675 407.15 c 0,33,34 305.999 300.895 305.999 300.895 280.925 212.5 c 0,35,36 260.287 139.743 260.287 139.743 170.268 139.535 c 0,37,38 150.912 139.491 150.912 139.491 128.35 142.8 c 0,39,40 175.95 147.9 175.95 147.9 195.075 163.2 c 0,41,42 215.219 178.107 215.219 178.107 215.486 198.634 c 0,43,44 211.531 218.694 l 0,45,46 210.136 222.328 210.136 222.328 208.25 226.1 c 0,47,48 178.939 279.538 178.939 279.538 136.85 255.425 c 0,49,50 96.05 232.05 96.05 232.05 83.7246 175.525 c 0,51,52 80.5269 142.666 l 0,53,54 81.2572 99.8871 81.2572 99.8871 106.25 51.4248 c 0,55,56 141.1 -16.1504 141.1 -16.1504 260.95 -52.7002 c 0,57,58 86.7002 -52.7002 86.7002 -52.7002 29.75 65.0254 c 0,59,60 3.24371 119.818 3.24371 119.818 3.25233 175.071 c 0,61,62 3.26224 238.532 3.26224 238.532 38.25 302.6 c 0,63,64 94.3515 402.053 94.3515 402.053 176.375 531.675 c 0,65,66 267.729 676.043 267.729 676.043 267.65 867.872 c 0,67,68 267.637 899.106 267.637 899.106 265.2 931.6 c 0,69,70 266.376 968.254 l 0,71,72 273.284 1017.82 273.284 1017.82 308.975 1067.17 c 0,73,74 339.503 1110.54 339.503 1110.54 378.091 1110.68 c 0,75,76 403.982 1110.77 403.982 1110.77 433.5 1091.4 c 0,77,78 406.329 1090.97 l 0,79,80 379.719 1086.58 379.719 1086.58 362.95 1065.47 c 0,81,82 336.635 1032.64 336.635 1032.64 362.1 1001.3 c 0,83,84 376.748 983.182 376.748 983.182 391.659 983.246 c 0,85,86 409.627 983.323 409.627 983.323 427.975 1009.8 c 0,87,88 461.545 1058.24 461.545 1058.24 493 1136.45 c 0,89,90 524.45 1214.65 524.45 1214.65 551.225 1294.55 c 0,91,92 577.997 1374.45 577.997 1374.45 597.55 1397.4 c 0,93,94 648.354 1457.44 648.354 1457.44 702.637 1457.89 c 0,95,96 708.3 1457.93 708.3 1457.93 714 1457.33 c 0,97,98 774.35 1450.95 774.35 1450.95 774.35 1343 c 0,99,100 759.658 1371.21 759.658 1371.21 740.495 1371.79 c 0,101,102 725.624 1368.4 l 0,103,104 722.5 1366.8 l 0,105,106 697.852 1352.36 697.852 1352.36 687.65 1299.65 c 0,107,108 680.656 1263.52 680.656 1263.52 680.656 1224.58 c 0,109,110 680.655 1206.73 680.655 1206.73 682.125 1188.3 c 0,111,112 686.801 1129.64 686.801 1129.64 707.2 1082.05 c 0,113,114 726.976 1035.91 726.976 1035.91 765 1032.75 c 0,115,116 780.597 1034.61 l 0,117,118 789.506 1038.67 789.506 1038.67 789.48 1050.78 c 0,119,120 789.469 1055.75 789.469 1055.75 787.95 1062.08 c 0,121,122 780.302 1093.95 780.302 1093.95 757.35 1122 c 0,123,124 806.651 1106.7 806.651 1106.7 823.65 1048.47 c 0,125,126 840.518 990.703 840.518 990.703 844.05 918.425 c 0,127,128 847.451 846.6 847.451 846.6 846.175 775.625 c 0,129,130 848.559 712.944 l 0,131,132 851.634 684.868 851.634 684.868 858.5 664.7 c 0,133,134 869.551 630.7 869.551 630.7 933.725 542.3 c 0,135,136 997.93 453.859 997.93 453.859 1056.12 357 c 0,137,138 1114.35 260.1 1114.35 260.1 1137.3 177.225 c 0,139,140 1143.06 156.431 1143.06 156.431 1142.98 139.517 c 0,141,142 1142.76 89.0173 1142.76 89.0173 1090.55 73.0996 c 0,143,144 1103.06 94.9886 1103.06 94.9886 1103.26 108.48 c 0,145,146 1100.22 120.124 l 0,147,148 1093.75 129.824 1093.75 129.824 1073.52 130.144 c 0,149,150 1070.7 130.189 1070.7 130.189 1067.6 130.05 c 0,151,152 1043.98 129.312 1043.98 129.312 1044.05 97.4379 c 0,153,154 1044.09 76.8749 1044.09 76.8749 1054 43.3496 c 0,155,156 1088.46 -74.2999 1088.46 -74.2999 1088.41 -157.795 c 0,157,158 1088.37 -212.434 1088.37 -212.434 1073.55 -252.45 c 0,159,160 1049.17 -318.284 1049.17 -318.284 1012.35 -353.6 c 0,161,162 941.723 -421.348 941.723 -421.348 873.375 -435.625 c 0,163,164 755.148 -461.096 755.148 -461.096 678.3 -429.25 c 0,165,166 745.832 -428.787 l 0,167,168 768.723 -427.145 768.723 -427.145 787.95 -423.3 c 0,169,170 833.506 -414.188 833.506 -414.188 882.3 -374.85 c 0,171,172 915.4 -348.164 915.4 -348.164 934.575 -298.775 c 0,173,174 950.506 -257.74 950.506 -257.74 903.55 -231.2 c 0,175,176 891.257 -224.252 891.257 -224.252 880.236 -224.155 c 0,177,178 869.238 -224.059 869.238 -224.059 859.507 -230.783 c 0,179,180 848.405 -238.453 848.405 -238.453 838.95 -255 c 0,181,182 833.076 -265.28 833.076 -265.28 833.122 -287.966 c 0,183,184 833.156 -304.67 833.156 -304.67 836.4 -328.1 c 0,185,186 803.878 -266.751 803.878 -266.751 818.55 -223.55 c 0,187,188 833.851 -178.499 833.851 -178.499 867.85 -162.775 c 0,189,190 961.975 -119.091 961.975 -119.091 979.2 -63.75 c 0,191,192 1001.03 6.37995 1001.03 6.37995 948.6 17.8496 c 0,193,194 909.195 26.4718 909.195 26.4718 900.15 15.2998 c 0,195,196 892.906 6.70984 892.906 6.70984 892.667 -2.67166 c 0,197,198 896.39 -17.4706 l 0,199,200 901.706 -27.8569 901.706 -27.8569 914.6 -39.0996 c 0,201,202 853.165 -38.3584 853.165 -38.3584 863.6 48.4502 c 0,203,204 876.96 159.575 876.96 159.575 876.87 231.658 c 0,205,206 876.835 260.474 876.835 260.474 874.65 283.05 c 0,0,1 623.05 754.8 m 0,93,94 651.68 755.862 l 0,95,96 678.117 760.841 678.117 760.841 694.875 781.575 c 0,97,98 719.949 812.598 719.949 812.598 724.625 847.875 c 0,99,100 724.988 876.826 l 0,101,102 722.85 893.204 722.85 893.204 714.85 905.675 c 0,103,104 699.258 923.547 699.258 923.547 684.578 923.664 c 0,105,106 676.19 923.731 676.19 923.731 668.1 918 c 0,107,108 652.852 909.109 652.852 909.109 652.589 896.07 c 0,109,110 656.305 881.517 l 0,111,112 657.846 878.384 657.846 878.384 660.025 875.075 c 0,113,114 671.5 857.65 671.5 857.65 699.55 847.45 c 0,115,116 677.045 839.66 677.045 839.66 659.116 839.612 c 0,117,118 625.288 839.523 625.288 839.523 607.75 867 c 0,119,120 595.874 885.605 595.874 885.605 595.89 907.989 c 0,121,122 595.907 933.67 595.907 933.67 611.575 964.325 c 0,123,124 625.829 992.219 625.829 992.219 625.998 1010.04 c 0,125,126 626.093 1020.15 626.093 1020.15 621.652 1027.02 c 0,127,128 617.518 1033.42 617.518 1033.42 609.45 1037 c 0,129,130 592.831 1040.51 l 0,131,132 569.558 1040.18 569.558 1040.18 544 1011.5 c 0,133,134 509.15 972.399 509.15 972.399 497.675 917.575 c 0,135,136 486.2 862.75 486.2 862.75 510.425 812.6 c 0,137,138 534.65 762.451 534.65 762.451 623.05 754.8 c 0,93,94 EndSplineSet KernsSLIF: 119 -182 0 0 EndChar StartChar: Cacute Encoding: 262 262 81 Width: 1221 Flags: W Fore 769 -106 m 0,0,1 471 -10 471 -10 308.5 95.5 c 0,2,3 146.001 200.999 146.001 200.999 52 521 c 0,4,5 -21 771 -21 771 61.5 803 c 0,6,7 144 835 144 835 183 814 c 0,8,9 100 809 100 809 92 748 c 0,10,11 87.9999 724 87.9999 724 107 703.5 c 0,12,13 113.742 696.226 113.742 696.226 123.506 696.065 c 0,14,15 140.554 700.134 l 0,16,17 153.145 705.726 153.145 705.726 169 719 c 0,18,19 250.999 787.999 250.999 787.999 313.5 936.5 c 0,20,21 345.304 1012.07 345.304 1012.07 345.388 1061.87 c 0,22,23 345.468 1109.93 345.468 1109.93 316 1134 c 0,24,25 297.495 1147.88 297.495 1147.88 285.093 1147.79 c 0,26,27 268.004 1147.66 268.004 1147.66 262.5 1121 c 0,28,29 259.612 1088.31 l 0,30,31 260.551 1059.54 260.551 1059.54 274 1032 c 0,32,33 211.33 1083.77 211.33 1083.77 211.355 1131.42 c 0,34,35 211.358 1136.23 211.358 1136.23 212 1141 c 0,36,37 219 1193 219 1193 230 1211 c 0,38,39 257 1259 257 1259 334 1308.5 c 0,40,-1 490.5 1405 l 0,41,42 570 1451.99 570 1451.99 629 1495 c 0,43,44 680.531 1532.56 680.531 1532.56 680.952 1564.77 c 0,45,46 681.013 1569.44 681.013 1569.44 680 1574 c 0,47,48 673.091 1599.91 673.091 1599.91 657.729 1600.63 c 0,49,50 643.631 1596.94 l 0,51,52 637.511 1593.8 637.511 1593.8 630.5 1588 c 0,53,54 595.679 1559.21 595.679 1559.21 596 1532 c 0,55,56 592.844 1540.68 592.844 1540.68 592.879 1559.48 c 0,57,58 592.931 1588.32 592.931 1588.32 600.5 1641 c 0,59,60 613 1728 613 1728 715 1686 c 0,61,62 978.009 1575 978.009 1575 1049 1418 c 0,63,64 1076.75 1356.64 1076.75 1356.64 1076.7 1303.38 c 0,65,66 1076.62 1220.35 1076.62 1220.35 1009 1157 c 0,67,68 1022 1185.98 1022 1185.98 1029.5 1285.5 c 0,69,70 1028.57 1316.85 l 0,71,72 1021.6 1358.1 1021.6 1358.1 980.781 1358.56 c 0,73,74 950.888 1354.61 l 0,75,76 941.948 1352.41 941.948 1352.41 932 1349 c 0,77,78 853.592 1320.96 853.592 1320.96 853.408 1261.41 c 0,79,80 853.309 1229.29 853.309 1229.29 875.979 1188 c 0,81,82 877.205 1185.76 877.205 1185.76 878.5 1183.5 c 0,83,84 948 1062 948 1062 1087 1047 c 0,85,86 1059.4 1041.56 1059.4 1041.56 1030.84 1041.64 c 0,87,88 991.108 1041.74 991.108 1041.74 949.5 1052.5 c 0,89,90 878.012 1070.99 878.012 1070.99 860 1091 c 0,91,92 812 1144 812 1144 810 1175.5 c 0,93,94 808.001 1206.99 808.001 1206.99 786 1292 c 0,95,96 763 1376 763 1376 698.5 1364 c 0,97,98 633.992 1352 633.992 1352 569 1292.5 c 0,99,100 504 1232.99 504 1232.99 460.5 1151.5 c 0,101,102 430.805 1095.87 430.805 1095.87 430.701 1053.04 c 0,103,104 430.653 1033.14 430.653 1033.14 437 1016 c 0,105,106 454 967 454 967 502 988 c 0,107,108 538.099 1003.79 538.099 1003.79 538 1030.05 c 0,109,110 537.967 1038.71 537.967 1038.71 534 1048.5 c 0,111,112 517.997 1088 517.997 1088 478 1100 c 0,113,114 498.94 1109.19 498.94 1109.19 516.623 1109.26 c 0,115,116 533.557 1109.31 533.557 1109.31 547.5 1101 c 0,117,118 575.996 1084.01 575.996 1084.01 588 1063 c 0,119,120 600.251 1038.5 600.251 1038.5 600.196 1012.93 c 0,121,122 600.043 942.503 600.043 942.503 506.5 864 c 0,123,124 379 757 379 757 334 658 c 0,125,126 235 442 235 442 332 274 c 0,127,128 383.944 184.036 383.944 184.036 477.181 184.115 c 0,129,130 558.055 184.183 558.055 184.183 670 252 c 0,131,132 682.002 259.002 682.002 259.002 725.5 306.5 c 0,133,134 769 354 769 354 819.5 396 c 0,135,136 870 438 870 438 915 451 c 0,137,138 934.367 452.983 l 0,139,140 963.5 449.533 963.5 449.533 975 402 c 0,141,142 939 430 939 430 905 404.5 c 0,143,144 871 379 871 379 857.5 341.5 c 0,145,146 844 304 844 304 861 274 c 0,147,148 871.446 255.566 871.446 255.566 900.392 255.633 c 0,149,150 918.554 255.675 918.554 255.675 944 263 c 0,151,152 1110.72 309.975 1110.72 309.975 1110.72 453.253 c 0,153,154 1110.72 465.522 1110.72 465.522 1109.5 478.5 c 0,155,156 1094.01 642.999 1094.01 642.999 988 698 c 0,157,158 1127.99 642 1127.99 642 1145.5 504 c 0,159,160 1163.01 366 1163.01 366 1090 284 c 0,161,162 1042 228.999 1042 228.999 932.5 158 c 0,163,164 823 87.0005 823 87.0005 852 36 c 0,165,166 891 -36 891 -36 945.5 18 c 0,167,168 1000.01 72.0056 1000.01 72.0056 1002 120 c 0,169,170 1020 14 1020 14 942.5 -61.5 c 0,171,172 887.78 -114.807 887.78 -114.807 823.84 -115.023 c 0,173,174 797.219 -115.113 797.219 -115.113 769 -106 c 0,0,1 885 1767 m 1,90,91 839 1752 839 1752 797 1798.5 c 0,92,93 754.997 1845 754.997 1845 735 1912 c 0,94,95 722.259 1954.69 722.259 1954.69 722.302 1997.77 c 0,96,97 722.326 2022.32 722.326 2022.32 726.5 2047 c 0,98,99 738.001 2115 738.001 2115 798 2142 c 0,100,101 765 2105 765 2105 766 2047.5 c 0,102,103 766.946 1993.17 766.946 1993.17 807.179 1992.85 c 0,104,105 809.523 1992.83 809.523 1992.83 812 1993 c 0,106,107 865.773 1996.58 865.773 1996.58 866.085 2049.52 c 0,108,109 866.183 2066.19 866.183 2066.19 860.977 2087.76 c 0,110,111 859.658 2093.22 859.658 2093.22 858 2099 c 0,112,113 888.014 2051.29 888.014 2051.29 888.119 2012.75 c 0,114,115 888.15 2001.21 888.15 2001.21 885.5 1990.5 c 0,116,117 873.997 1943.99 873.997 1943.99 855.5 1906 c 0,118,119 837.001 1868.01 837.001 1868.01 833 1835 c 0,120,121 834.75 1818.37 l 0,122,123 843.001 1793.25 843.001 1793.25 885 1767 c 1,90,91 EndSplineSet EndChar StartChar: cacute Encoding: 263 263 82 Width: 1053 Flags: W Fore 667 50 m 0,0,1 414.002 130.999 414.002 130.999 276 221.5 c 0,2,3 138 312 138 312 58 584 c 0,4,5 -3.99995 797 -3.99995 797 66 824 c 0,6,7 136.001 851 136.001 851 169 833 c 0,8,9 98.9995 830 98.9995 830 91 777 c 0,10,11 88 756 88 756 104.5 739 c 0,12,13 110.314 733.01 110.314 733.01 118.55 732.979 c 0,14,15 133.686 732.924 133.686 732.924 157 753 c 0,16,17 226 811 226 811 279.5 937 c 0,18,19 333 1063 333 1063 282 1105 c 0,20,21 245 1133.99 245 1133.99 237 1094.5 c 0,22,23 234.565 1064.17 l 0,24,25 235.643 1040.93 235.643 1040.93 246 1019 c 0,26,27 193.643 1062.33 193.643 1062.33 193.438 1102.81 c 0,28,29 193.416 1107.17 193.416 1107.17 194 1111.5 c 0,30,31 199.999 1156 199.999 1156 209 1171 c 0,32,33 231.999 1211.01 231.999 1211.01 297.5 1253.5 c 0,34,-1 430.5 1336 l 0,35,36 498 1376.01 498 1376.01 548 1412.5 c 0,37,38 591.233 1444.06 591.233 1444.06 591.851 1470.76 c 0,39,40 591.947 1474.94 591.947 1474.94 591 1479 c 0,41,42 581 1516.99 581 1516.99 549 1491 c 0,43,44 519.723 1467.22 519.723 1467.22 520 1444 c 0,45,46 517.162 1451.3 517.162 1451.3 517.2 1467.88 c 0,47,48 517.257 1492.2 517.257 1492.2 523.5 1536.5 c 0,49,50 530.554 1586.55 530.554 1586.55 572.133 1586.73 c 0,51,52 592.446 1586.82 592.446 1586.82 621 1575 c 0,53,54 843.999 1481 843.999 1481 905 1347 c 0,55,56 928.906 1294.49 928.906 1294.49 928.852 1249.04 c 0,57,58 928.771 1179.09 928.771 1179.09 871 1125 c 0,59,60 882.999 1149 882.999 1149 888.5 1233.5 c 0,61,62 886.96 1262.72 l 0,63,64 879.922 1295.56 879.922 1295.56 846.301 1295.86 c 0,65,66 818.321 1291.76 l 0,67,68 812.409 1290.18 812.409 1290.18 806 1288 c 0,69,70 739.114 1264.43 739.114 1264.43 738.776 1213.88 c 0,71,72 738.677 1198.96 738.677 1198.96 744.373 1181.69 c 0,73,74 749.675 1165.61 749.675 1165.61 760 1147.5 c 0,75,76 818.997 1044.01 818.997 1044.01 937 1031 c 0,77,78 914.022 1026.49 914.022 1026.49 890.21 1026.52 c 0,79,80 855.966 1026.56 855.966 1026.56 820 1036 c 0,81,82 759 1052.01 759 1052.01 744 1069 c 0,83,84 703 1114 703 1114 701.5 1140.5 c 0,85,86 700 1167 700 1167 682 1239 c 0,87,88 662 1311 662 1311 607 1300.5 c 0,89,90 552.008 1290 552.008 1290 497 1240 c 0,91,92 442.012 1190.02 442.012 1190.02 405 1120.5 c 0,93,94 379.853 1073.27 379.853 1073.27 379.65 1036.89 c 0,95,96 379.554 1019.74 379.554 1019.74 385 1005 c 0,97,98 394.672 975.982 394.672 975.982 417.234 975.605 c 0,99,100 436.705 979.633 l 0,101,102 438.331 980.267 438.331 980.267 440 981 c 0,103,104 470 994.5 470 994.5 470.188 1017 c 0,105,106 470.25 1024.5 470.25 1024.5 467 1033 c 0,107,108 454.002 1067 454.002 1067 419 1076 c 0,109,110 436.939 1083.69 436.939 1083.69 452.123 1083.76 c 0,111,112 466.558 1083.82 466.558 1083.82 478.5 1077 c 0,113,114 502.995 1063.01 502.995 1063.01 513 1045 c 0,115,116 552 967 552 967 444 876 c 0,117,118 336 785 336 785 297 701 c 0,119,120 213 518 213 518 295.5 374.5 c 0,121,122 339.547 297.884 339.547 297.884 418.515 297.806 c 0,123,124 487.451 297.739 487.451 297.739 583 356 c 0,125,126 592.998 361.999 592.998 361.999 630 402.5 c 0,127,128 667.002 443.001 667.002 443.001 710 478.5 c 0,129,130 753 514 753 514 791.5 524.5 c 0,131,132 830 535 830 535 842 483 c 0,133,134 812 506 812 506 783 484.5 c 0,135,136 754.001 463.001 754.001 463.001 742.5 431 c 0,137,138 737.254 416.404 737.254 416.404 737.314 403.264 c 0,139,140 737.386 387.597 737.386 387.597 745 374 c 0,141,142 759 349 759 349 816 365 c 0,143,144 969 407 969 407 956 547.5 c 0,145,146 943 688 943 688 853 735 c 0,147,148 972.001 687 972.001 687 987.5 569.5 c 0,149,150 1003 452 1003 452 940 382 c 0,151,152 898 336 898 336 806 275.5 c 0,153,154 714 215.001 714 215.001 738 172 c 0,155,156 771 109 771 109 817 156 c 0,157,158 863 202.999 863 202.999 865 244 c 0,159,160 880 152.999 880 152.999 814 88 c 0,161,162 748 23 748 23 667 50 c 0,0,1 766 1644 m 1,90,91 727 1630.01 727 1630.01 691 1669.5 c 0,92,93 655.004 1708.99 655.004 1708.99 638.5 1766.5 c 0,94,95 628.026 1803 628.026 1803 628.029 1839.5 c 0,96,97 628.031 1860.5 628.031 1860.5 631.5 1881.5 c 0,98,99 641.001 1939.01 641.001 1939.01 692 1962 c 0,100,101 664.696 1930.8 664.696 1930.8 664.5 1881.5 c 0,102,103 664.967 1836.2 664.967 1836.2 699.025 1835.83 c 0,104,105 701.429 1835.8 701.429 1835.8 704 1836 c 0,106,107 749.303 1838.88 749.303 1838.88 749.618 1883.64 c 0,108,109 749.718 1897.74 749.718 1897.74 745.351 1916 c 0,110,111 744.304 1920.38 744.304 1920.38 743 1925 c 0,112,113 768.109 1884.68 768.109 1884.68 768.324 1852.45 c 0,114,115 768.391 1842.33 768.391 1842.33 766 1833 c 0,116,117 756.002 1794.01 756.002 1794.01 740.5 1761.5 c 0,118,119 725.516 1730.08 725.516 1730.08 721.5 1701.5 c 0,120,121 723.355 1686.49 l 0,122,123 730.94 1665.91 730.94 1665.91 766 1644 c 1,90,91 EndSplineSet EndChar StartChar: Eogonek Encoding: 280 280 83 Width: 1514 Flags: HMW HStem: -25.5 188.5<428 1169.5> 701.5 157<313.5 758.5> 1353 218<196 987> VStem: 82 215<-28 1037> 585 218.5<-320.5 -47> Fore 500 -334 m 132,-1,0 530 -270.001 530 -270.001 573 -221 c 0,1,2 616.001 -171.999 616.001 -171.999 637 -132 c 0,3,4 658 -91.9995 658 -91.9995 585 -47 c 0,5,6 556 -29 556 -29 469.5 -23 c 0,7,8 383 -17 383 -17 297 -28 c 0,9,10 211 -39 211 -39 155.5 -70.5 c 0,11,12 100 -102 100 -102 133 -159 c 0,13,14 154 -195.001 154 -195.001 230 -206 c 0,15,16 203.189 -212.105 203.189 -212.105 180.923 -212.01 c 0,17,18 119.311 -211.745 119.311 -211.745 92.5 -164 c 0,19,20 56.0001 -99.0005 56.0001 -99.0005 53 -3.5 c 0,21,22 50 92 50 92 65 190 c 0,23,24 80 288 80 288 82 330 c 0,25,26 83.3538 453.119 l 0,27,28 81.2241 552.794 81.2241 552.794 68.5 649 c 0,29,30 48 804 48 804 12 960 c 0,31,32 0 1020 0 1020 8.5 1078.5 c 0,33,34 17 1137 17 1137 83 1158 c 0,35,36 45 1137 45 1137 38 1069.5 c 0,37,38 38.125 1042.16 l 0,39,40 41.0576 1025.78 41.0576 1025.78 52.8586 1025.08 c 0,41,42 68.1897 1028.89 l 0,43,44 74.4608 1031.83 74.4608 1031.83 82 1037 c 0,45,46 149.999 1082 149.999 1082 190.5 1236.5 c 0,47,48 206.042 1295.79 206.042 1295.79 206.047 1335.86 c 0,49,50 206.056 1400.21 206.056 1400.21 166 1415 c 0,51,52 79 1445 79 1445 58 1386.5 c 0,53,54 37 1328 37 1328 52 1256 c 0,55,56 11.599 1313.04 11.599 1313.04 11.6157 1374.49 c 0,57,58 11.6272 1416.47 11.6272 1416.47 30.5 1460.5 c 0,59,60 77.0044 1569.01 77.0044 1569.01 196 1571 c 0,61,62 295 1572.01 295 1572.01 408.5 1527.5 c 0,63,64 462.924 1506.16 462.924 1506.16 512.867 1506.09 c 0,65,66 567.073 1506.02 567.073 1506.02 616 1531 c 0,67,68 632.022 1539.01 632.022 1539.01 754 1572 c 0,69,70 876.019 1605.01 876.019 1605.01 1026.5 1607 c 0,71,72 1102.39 1604.14 l 0,73,74 1212.74 1594.25 1212.74 1594.25 1317.5 1551 c 0,75,76 1458.01 1492.99 1458.01 1492.99 1511 1320 c 0,77,78 1461 1392 1461 1392 1429.5 1422.5 c 0,79,80 1397.99 1453 1397.99 1453 1350 1474 c 0,81,82 1328.96 1482.01 1328.96 1482.01 1257.5 1498.5 c 0,83,84 1185.99 1515 1185.99 1515 1115 1513.5 c 0,85,86 1043.99 1512 1043.99 1512 999 1478 c 0,87,88 973.44 1458.69 973.44 1458.69 973.045 1420.99 c 0,89,90 977.026 1386.64 l 0,91,92 980.5 1370.93 980.5 1370.93 987 1353 c 0,93,94 1002 1309.01 1002 1309.01 1053 1329 c 0,95,96 1104 1348.99 1104 1348.99 1119 1395 c 0,97,98 1116 1316 1116 1316 1076 1295 c 0,99,100 1046.63 1279.59 1046.63 1279.59 1009.73 1279.53 c 0,101,102 996.362 1279.51 996.362 1279.51 982 1281.5 c 0,103,104 928.02 1289 928.02 1289 872.5 1310.5 c 0,105,106 816.976 1332 816.976 1332 783 1338 c 0,107,108 724.708 1347.93 724.708 1347.93 671.147 1347.88 c 0,109,110 514.287 1347.73 514.287 1347.73 398 1262 c 0,111,112 281.569 1176.17 281.569 1176.17 281.56 1027.39 c 0,113,114 281.557 976.831 281.557 976.831 295 919 c 0,115,116 312.784 837.568 312.784 837.568 406.788 837.613 c 0,117,118 413.215 837.616 413.215 837.616 420 838 c 0,119,120 526 844 526 844 481 923 c 0,121,122 453 971 453 971 418 937 c 0,123,124 383 903 383 903 391 882 c 0,125,126 387.648 921.385 l 0,127,128 389.057 996.13 389.057 996.13 462.658 996.742 c 0,129,130 470.653 996.808 470.653 996.808 479.5 996 c 0,131,132 589.005 985.999 589.005 985.999 678 958 c 0,133,134 716 946 716 946 799.5 969 c 0,135,136 845.412 981.646 845.412 981.646 887.847 981.595 c 0,137,138 922.589 981.553 922.589 981.553 955 973 c 0,139,140 1018.01 954.998 1018.01 954.998 1056 886 c 0,141,142 1093.99 817 1093.99 817 1026 698 c 0,143,144 1060.99 815 1060.99 815 1008 860.5 c 0,145,146 958.847 902.697 958.847 902.697 894.212 902.75 c 0,147,148 889.153 902.754 889.153 902.754 884 902.5 c 0,149,150 813 899 813 899 758.5 858.5 c 0,151,152 704 818 704 818 737 763 c 0,153,154 743 753 743 753 781.5 754.5 c 0,155,156 820 756 820 756 808 801 c 0,157,158 856 777 856 777 837.5 748 c 0,159,160 819 719 819 719 798 709 c 0,161,162 733.814 680.116 733.814 680.116 661.903 680.2 c 0,163,164 644.186 680.221 644.186 680.221 626 682 c 0,165,166 534 691 534 691 453 701.5 c 0,167,168 372 712 372 712 313.5 701.5 c 0,169,170 255 691 255 691 245 615 c 0,171,172 236.91 558.37 236.91 558.37 236.919 518.43 c 0,173,174 236.932 459.629 236.932 459.629 254.5 437 c 0,175,176 284 399 284 399 314 408 c 0,177,178 344 417 344 417 349 445.5 c 0,179,180 347.674 456.176 l 0,181,182 340.847 469.073 340.847 469.073 305.92 469.043 c 0,183,184 296.076 469.035 296.076 469.035 284 468 c 0,185,186 294.001 486 294.001 486 322 487.5 c 0,187,188 350 489 350 489 361 486 c 0,189,190 428 463 428 463 423.5 394.5 c 0,191,192 419 326.002 419 326.002 411.5 262 c 0,193,194 404 197.999 404 197.999 428 163 c 0,195,196 452 128.001 452 128.001 577 172 c 0,197,198 622.009 187.003 622.009 187.003 761.5 242 c 0,199,200 901 297 901 297 925 216 c 0,201,202 903.999 228.001 903.999 228.001 882 228.5 c 0,203,204 866.839 226.005 l 0,205,206 859.566 222.478 859.566 222.478 859 214 c 0,207,208 860.873 195.111 l 0,209,210 873.894 153.483 873.894 153.483 969.23 153.319 c 0,211,212 975.913 153.308 975.913 153.308 983 153.5 c 0,213,214 1111.99 156.999 1111.99 156.999 1122 226 c 0,215,216 1121.24 242.091 l 0,217,218 1117.86 253.528 1117.86 253.528 1104.73 253.833 c 0,219,220 1091.5 252 l 0,221,222 1056.99 242.999 1056.99 242.999 1043 213 c 0,223,224 1059.01 279 1059.01 279 1095.5 286.5 c 0,225,226 1131.99 294 1131.99 294 1173.5 277.5 c 0,227,228 1214.99 261.005 1214.99 261.005 1255.5 236 c 0,229,230 1296 210.999 1296 210.999 1320 212 c 0,231,232 1442.73 214.707 1442.73 214.707 1443.3 346.089 c 0,233,234 1443.37 360.293 1443.37 360.293 1442 376 c 0,235,236 1499 268 1499 268 1409 178 c 0,237,238 1319 88 1319 88 1184 43 c 0,239,240 1148.59 31.1974 1148.59 31.1974 1148.41 11.023 c 0,241,242 1148.31 0.467999 1148.31 0.467999 1157.85 -12.3787 c 0,243,244 1162.52 -18.6647 1162.52 -18.6647 1169.5 -25.5 c 0,245,246 1187.51 -43.1428 1187.51 -43.1428 1204.22 -43.058 c 0,247,248 1232.49 -42.9144 1232.49 -42.9144 1257 8 c 0,249,250 1255.01 -59.9961 1255.01 -59.9961 1220 -73.5 c 0,251,252 1185.01 -87 1185.01 -87 1139 -76.5 c 0,253,254 1092.99 -66 1092.99 -66 1049 -46.5 c 0,255,256 1009.26 -28.8871 1009.26 -28.8871 987 -29 c 0,257,258 934 -34 934 -34 850.5 -63.5 c 0,259,260 767 -93.0001 767 -93.0001 776 -225 c 0,261,262 778.351 -264.189 778.351 -264.189 799.132 -264.677 c 0,263,264 812 -262 l 0,265,266 845 -248.999 845 -248.999 863 -195 c 0,267,268 858 -305.999 858 -305.999 803.5 -320.5 c 0,269,270 749 -335 749 -335 686.5 -332.5 c 0,271,272 636.585 -334.226 l 0,273,274 602.996 -338.11 602.996 -338.11 573.5 -349.5 c 0,275,276 523 -369 523 -369 526 -491 c 0,277,278 470 -398 470 -398 500 -334 c 132,-1,0 EndSplineSet EndChar StartChar: eogonek Encoding: 281 281 84 Width: 1305 Flags: HMW HStem: 148 160.5<389.5 1019.5> 766 133.5<291.5 670> 1320.5 185<192 865> VStem: 96 182<145 1051.5> 523 185.5<-102 129.5> Fore 451 -113 m 132,-1,0 476 -58.5001 476 -58.5001 512.5 -17 c 0,1,2 549 24.5 549 24.5 566.5 58 c 0,3,4 570.294 65.2622 570.294 65.2622 570.398 72.736 c 0,5,6 566.895 87.9464 l 0,7,8 557.508 108.003 557.508 108.003 523 129.5 c 0,9,10 497.999 144.501 497.999 144.501 424.5 149.5 c 0,11,12 351 154.499 351 154.499 278 145 c 0,13,14 205.003 135.501 205.003 135.501 157.5 109.5 c 0,15,16 109.999 83.5001 109.999 83.5001 138 35.5 c 0,17,18 156 5.50008 156 5.50008 221 -4.5 c 0,19,20 135.001 -23.5 135.001 -23.5 104 31.5 c 0,21,22 72.9999 86.5001 72.9999 86.5001 70.5 167.5 c 0,23,24 67.9999 248.5 67.9999 248.5 81 331.5 c 0,25,26 94.0001 414.5 94.0001 414.5 96 450.5 c 0,27,28 102 589.5 102 589.5 84 721.5 c 0,29,30 66 853.5 66 853.5 36 985.5 c 0,31,32 28.6337 1016.81 28.6337 1016.81 28.6154 1047.74 c 0,33,34 28.604 1067.2 28.604 1067.2 31.5 1086.5 c 0,35,36 39.0008 1136.5 39.0008 1136.5 96 1154.5 c 0,37,38 63 1136.5 63 1136.5 57.5 1079.5 c 0,39,40 58.1818 1054.81 l 0,41,42 61.2307 1042.02 61.2307 1042.02 71.4697 1041.73 c 0,43,44 86.6965 1046.05 l 0,45,46 91.0331 1048.23 91.0331 1048.23 96 1051.5 c 0,47,48 152.998 1090.5 152.998 1090.5 187 1221.5 c 0,49,50 200.06 1271.82 200.06 1271.82 200.136 1305.76 c 0,51,52 200.234 1349.58 200.234 1349.58 178.69 1366.1 c 0,53,54 173.478 1370.1 173.478 1370.1 167 1372.5 c 0,55,56 141.459 1381.35 141.459 1381.35 122.587 1381.45 c 0,57,58 103.52 1381.55 103.52 1381.55 91.2603 1372.71 c 0,59,60 80.0198 1364.61 80.0198 1364.61 74.5 1349 c 0,61,62 64.4434 1320.55 64.4434 1320.55 64.459 1288.31 c 0,63,64 64.4706 1264.45 64.4706 1264.45 70 1238.5 c 0,65,66 35.4682 1286.73 35.4682 1286.73 35.4975 1338.85 c 0,67,68 35.5174 1374.28 35.5174 1374.28 51.5 1411.5 c 0,69,70 91.0043 1503.51 91.0043 1503.51 192 1505.5 c 0,71,72 276 1505.5 276 1505.5 372.5 1468 c 0,73,74 418.698 1450.05 418.698 1450.05 461.118 1450.09 c 0,75,76 507.299 1450.13 507.299 1450.13 549 1471.5 c 0,77,78 561.963 1478.48 561.963 1478.48 666 1506.5 c 0,79,80 769.98 1534.5 769.98 1534.5 898 1536 c 0,81,82 968.2 1532.96 l 0,83,84 1059.08 1523.94 1059.08 1523.94 1145.5 1488.5 c 0,85,86 1265 1439.5 1265 1439.5 1310 1291.5 c 0,87,88 1267.99 1352.52 1267.99 1352.52 1241.5 1378.5 c 0,89,90 1214.98 1404.51 1214.98 1404.51 1173 1422.5 c 0,91,92 1155.08 1429.48 1155.08 1429.48 1094.5 1444 c 0,93,94 1039.52 1457.18 1039.52 1457.18 984.499 1457.14 c 0,95,96 979.002 1457.14 979.002 1457.14 973.5 1457 c 0,97,98 912.999 1455.5 912.999 1455.5 875 1427 c 0,99,100 853.056 1410.54 853.056 1410.54 853.121 1377.58 c 0,101,102 853.169 1353.46 853.169 1353.46 865 1320.5 c 0,103,104 873.107 1295.5 873.107 1295.5 895.597 1295.15 c 0,105,106 917.149 1299.25 l 0,107,108 918.801 1299.84 918.801 1299.84 920.5 1300.5 c 0,109,110 963.998 1317.49 963.998 1317.49 976 1356.5 c 0,111,112 972.121 1252.54 972.121 1252.54 904.433 1251.81 c 0,113,114 874.102 1255.82 l 0,115,116 867.279 1257.54 867.279 1257.54 860 1260 c 0,117,118 749.03 1297.49 749.03 1297.49 691 1307.5 c 0,119,120 496 1340.5 496 1340.5 363.5 1243 c 0,121,122 231 1145.5 231 1145.5 276 950.5 c 0,123,124 290.949 882.298 290.949 882.298 370.925 882.18 c 0,125,126 376.552 882.171 376.552 882.171 382.5 882.5 c 0,127,128 445.726 885.993 445.726 885.993 445.745 920.236 c 0,129,130 445.753 935.007 445.753 935.007 434 955.5 c 0,131,132 410 994.5 410 994.5 380.5 966.5 c 0,133,134 351 938.5 351 938.5 358 920.5 c 0,135,136 355.178 956.588 l 0,137,138 357.557 1016.96 357.557 1016.96 418.311 1017.63 c 0,139,140 425.273 1017.71 425.273 1017.71 433 1017 c 0,141,142 526.022 1008.49 526.022 1008.49 602 984.5 c 0,143,144 613.184 981.005 613.184 981.005 629.133 981.052 c 0,145,146 658.816 981.14 658.816 981.14 705 993.5 c 0,147,148 776 1012.51 776 1012.51 837 996.5 c 0,149,150 891 981.5 891 981.5 923 923 c 0,151,152 955 864.5 955 864.5 898 763.5 c 0,153,154 909.411 802.85 909.411 802.85 909.365 832.678 c 0,155,156 909.292 878.65 909.292 878.65 882 902 c 0,157,158 837 940.5 837 940.5 776.5 937.5 c 0,159,160 716 934.5 716 934.5 670 899.5 c 0,161,162 624 864.5 624 864.5 652 818.5 c 0,163,164 657 809.5 657 809.5 689.5 810.5 c 0,165,166 722 811.5 722 811.5 712 850.5 c 0,167,168 741.022 836.343 741.022 836.343 741.734 819.93 c 0,169,170 738.701 808.047 l 0,171,172 738.15 807.027 738.15 807.027 737.5 806 c 0,173,174 722 781.499 722 781.499 704 773.5 c 0,175,176 649.462 748.636 649.462 748.636 588.167 748.539 c 0,177,178 573.039 748.515 573.039 748.515 557.5 750 c 0,179,180 479 757.5 479 757.5 410 766.5 c 0,181,182 341 775.5 341 775.5 291.5 766 c 0,183,184 242 756.5 242 756.5 233 692.5 c 0,185,186 226.133 644.427 226.133 644.427 226.201 610.552 c 0,187,188 226.301 560.572 226.301 560.572 241.5 541.5 c 0,189,190 267 509.5 267 509.5 292.5 517 c 0,191,192 318 524.5 318 524.5 322 548.5 c 0,193,194 320.371 558.225 l 0,195,196 313.925 568.374 313.925 568.374 285.403 568.362 c 0,197,198 277.13 568.358 277.13 568.358 267 567.5 c 0,199,200 276 582.5 276 582.5 299.5 584.5 c 0,201,202 323 586.5 323 586.5 332 583.5 c 0,203,204 389 563.5 389 563.5 385.5 505.5 c 0,205,206 382.001 447.516 382.001 447.516 375.5 393 c 0,207,208 374.494 354.701 l 0,209,210 376.885 326.961 376.885 326.961 389.5 308.5 c 0,211,212 398.494 295.338 398.494 295.338 423.946 295.265 c 0,213,214 456.506 295.172 456.506 295.172 516 316.5 c 0,215,216 555 329.5 555 329.5 673.5 376 c 0,217,218 792 422.5 792 422.5 812 353.5 c 0,219,220 794.002 363.499 794.002 363.499 775 364.5 c 0,221,222 762.368 362.683 l 0,223,224 756 359.605 756 359.605 756 351.5 c 0,225,226 752 297.5 752 297.5 861 300.5 c 0,227,228 970 303.5 970 303.5 979 361.5 c 0,229,230 983 391.5 983 391.5 953.5 384.5 c 0,231,232 924 377.5 924 377.5 912 351.5 c 0,233,234 940 462.5 940 462.5 1023 406 c 0,235,236 1104.66 350.411 1104.66 350.411 1147 350.5 c 0,237,238 1251.4 352.3 1251.4 352.3 1252.12 464.26 c 0,239,240 1252.2 476.7 1252.2 476.7 1251 490.5 c 0,241,242 1269.94 454.563 1269.94 454.563 1270.06 421.088 c 0,243,244 1270.15 393.428 1270.15 393.428 1257.4 367.45 c 0,245,246 1245.66 343.511 1245.66 343.511 1223 321 c 0,247,248 1146.01 244.502 1146.01 244.502 1032 206.5 c 0,249,250 978 188.5 978 188.5 1019.5 148 c 0,251,252 1034.82 133.05 1034.82 133.05 1048.98 133.021 c 0,253,254 1073.18 132.97 1073.18 132.97 1094 176.5 c 0,255,256 1092.56 92.98 1092.56 92.98 1041.35 92.1448 c 0,257,258 1015.84 95.942 l 0,259,260 1005.59 98.8556 1005.59 98.8556 994 104 c 0,261,262 896 147.5 896 147.5 865 144.5 c 0,263,264 820 139.501 820 139.501 749 114.5 c 0,265,266 684.311 91.7219 684.311 91.7219 684.372 -1.61601 c 0,267,268 684.378 -10.7222 684.378 -10.7222 685 -20.5 c 0,269,270 688 -62.5 688 -62.5 716 -52 c 0,271,272 744 -41.5 744 -41.5 759 4.5 c 0,273,274 755 -89.5 755 -89.5 708.5 -102 c 0,275,276 662 -114.499 662 -114.499 609 -112.5 c 0,277,278 556 -110.501 556 -110.501 513 -127 c 0,279,280 472.855 -142.404 472.855 -142.404 472.804 -234.077 c 0,281,282 472.801 -240.595 472.801 -240.595 473 -247.5 c 0,283,284 442.424 -195.455 442.424 -195.455 442.32 -154.203 c 0,285,286 442.264 -132.044 442.264 -132.044 451 -113 c 132,-1,0 EndSplineSet EndChar StartChar: Lslash Encoding: 321 321 85 Width: 1737 Flags: HMW HStem: 8 320<774 1387> VStem: 583 159<31.5 1459> Fore 687 1538 m 1,0,1 655 1514 655 1514 655.5 1490 c 0,2,3 656 1465.99 656 1465.99 694 1464 c 0,4,5 708.349 1466.74 l 0,6,7 744.986 1483.48 744.986 1483.48 776 1600 c 0,8,9 786.895 1640.93 786.895 1640.93 786.865 1673.36 c 0,10,11 786.795 1751.08 786.795 1751.08 724 1780 c 0,12,13 790 1796.01 790 1796.01 821 1709.5 c 0,14,15 841.964 1651 841.964 1651 841.891 1584.05 c 0,16,17 841.856 1551.99 841.856 1551.99 837 1518 c 0,18,19 828.998 1467.99 828.998 1467.99 808.5 1382.5 c 0,20,21 788 1297 788 1297 775 1212 c 0,22,23 762 1126.99 762 1126.99 768 1062 c 0,24,25 774 996.999 774 996.999 820 989 c 0,26,27 877 977 877 977 952 1030 c 0,28,29 1000.71 1064.42 1000.71 1064.42 1001.33 1095.05 c 0,30,31 997.749 1112.28 l 0,32,33 994.418 1119.76 994.418 1119.76 988 1127 c 0,34,35 949 1170.01 949 1170.01 921.5 1131.5 c 0,36,37 893.998 1092.99 893.998 1092.99 880 1058 c 0,38,39 883 1167.99 883 1167.99 947.5 1188.5 c 0,40,41 1011.96 1208.99 1011.96 1208.99 1098.5 1213 c 0,42,43 1185.01 1217.01 1185.01 1217.01 1273 1242.5 c 0,44,45 1361 1268 1361 1268 1412 1389 c 0,46,47 1401.99 1282.99 1401.99 1282.99 1351 1231.5 c 0,48,49 1300.01 1180.01 1300.01 1180.01 1239.5 1144.5 c 0,50,51 1178.91 1108.94 1178.91 1108.94 1124.5 1070 c 0,52,53 1070.01 1031 1070.01 1031 1054 951 c 0,54,55 1048 927 1048 927 1070.5 924.5 c 0,56,57 1095.88 925.692 l 0,58,59 1107.45 927.889 1107.45 927.889 1120 933 c 0,60,61 1158 947.001 1158 947.001 1158 999 c 0,62,63 1201.99 920 1201.99 920 1156.5 883.5 c 0,64,65 1111.01 847.004 1111.01 847.004 1037 831 c 0,66,67 963 815 963 815 889.5 808.5 c 0,68,69 816 802 816 802 804 783 c 0,70,71 744 693 744 693 729 563 c 0,72,73 714 433 714 433 774 328 c 0,74,75 837 215.001 837 215.001 958 230.5 c 0,76,77 1078.99 245.997 1078.99 245.997 1204.5 286 c 0,78,79 1330.01 326.002 1330.01 326.002 1433 337 c 0,80,81 1465.48 336.915 l 0,82,83 1540.7 327.344 1540.7 327.344 1564 225 c 0,84,85 1540 267.001 1540 267.001 1489.5 277 c 0,86,87 1438.99 287 1438.99 287 1419 266 c 0,88,89 1353 195.001 1353 195.001 1416 150.5 c 0,90,91 1464.57 116.195 1464.57 116.195 1534.23 116.061 c 0,92,93 1554.93 116.022 1554.93 116.022 1577.5 119 c 0,94,95 1676 132 1676 132 1764.5 216 c 0,96,97 1853 300 1853 300 1838 486 c 0,98,99 1857.76 416.141 1857.76 416.141 1857.67 356.651 c 0,100,101 1857.47 208.36 1857.47 208.36 1734 124.5 c 0,102,103 1562.5 8.01583 1562.5 8.01583 1387 8 c 0,104,105 1300.01 8 1300.01 8 1176 51.5 c 0,106,107 1051.99 95 1051.99 95 1035 3 c 0,108,109 1033.55 -20.8143 l 0,110,111 1037.84 -57.1116 1037.84 -57.1116 1089.5 -57.5 c 0,112,113 1155.99 -58 1155.99 -58 1196 -13 c 0,114,115 1155.11 -117.502 1155.11 -117.502 1089.03 -117.958 c 0,116,117 1082.39 -118.004 1082.39 -118.004 1075.5 -117 c 0,118,119 1000 -106 1000 -106 914.5 -57.5 c 0,120,121 829 -9.00005 829 -9.00005 742 31.5 c 0,122,123 655 72 655 72 587 17 c 0,124,125 496 -56.0001 496 -56.0001 575 -133 c 0,126,127 650.982 -207.057 650.982 -207.057 726.037 -207.112 c 0,128,129 729.019 -207.115 729.019 -207.115 732 -207 c 0,130,131 685.805 -218.957 685.805 -218.957 649.06 -218.951 c 0,132,133 618.756 -218.946 618.756 -218.946 594 -210.5 c 0,134,135 541 -192 541 -192 496 -135 c 0,136,137 445 -70.0001 445 -70.0001 467 29 c 0,138,139 489.002 128.007 489.002 128.007 524.5 231 c 0,140,141 560 334 560 334 578.5 424.5 c 0,142,143 583.04 446.711 583.04 446.711 582.973 466.241 c 0,144,145 582.766 526.289 582.766 526.289 539 561 c 0,146,147 488 600 488 600 440 572.5 c 0,148,149 392 545 392 545 343 505 c 0,150,151 293.999 464.999 293.999 464.999 242 439.5 c 0,152,153 222.917 430.142 222.917 430.142 203.161 430.009 c 0,154,155 188.511 429.911 188.511 429.911 173.491 434.885 c 0,156,157 153.571 441.481 153.571 441.481 133 457 c 0,158,159 239.999 453 239.999 453 251.5 513 c 0,160,161 254.696 548.121 l 0,162,163 253.566 580.482 253.566 580.482 234 596 c 0,164,165 171 642 171 642 127.5 606 c 0,166,167 84 570 84 570 66.5 503.5 c 0,168,169 49 437 49 437 61 365.5 c 0,170,171 72.9998 294.001 72.9998 294.001 121 269 c 0,172,173 13 315 13 315 16.5 463.5 c 0,174,175 20 612 20 612 57 656 c 0,176,177 163.999 785 163.999 785 306 763 c 0,178,179 337.145 758.175 337.145 758.175 367.568 758.208 c 0,180,181 475.854 758.327 475.854 758.327 575 820 c 0,182,183 593 830 593 830 581.5 953.5 c 0,184,185 570.001 1076.98 570.001 1076.98 566 1215.5 c 0,186,187 566.756 1320.01 l 0,188,189 570.322 1395.61 570.322 1395.61 583 1459 c 0,190,191 599.759 1542.8 599.759 1542.8 656.009 1543.16 c 0,192,193 670.24 1543.25 670.24 1543.25 687 1538 c 1,0,1 EndSplineSet KernsSLIF: 89 -156 0 0 121 -78 0 0 84 -208 0 0 87 -321 0 0 EndChar StartChar: lslash Encoding: 322 322 86 Width: 1480 Flags: HMW HStem: 128 272<667 1188> VStem: 505 135<147.5 1361> Fore 593 1428 m 1,0,1 567.318 1408.02 567.318 1408.02 566.5 1387 c 0,2,3 567 1366.99 567 1366.99 599 1365 c 0,4,5 637 1362 637 1362 668.5 1480.5 c 0,6,7 677.632 1514.85 677.632 1514.85 677.729 1542.19 c 0,8,9 677.827 1569.77 677.827 1569.77 668.732 1590.2 c 0,10,11 655.742 1619.38 655.742 1619.38 624 1634 c 0,12,13 647.265 1635.96 l 0,14,15 686.64 1632.06 686.64 1632.06 707 1574.5 c 0,16,17 724.413 1525.27 724.413 1525.27 724.333 1468.65 c 0,18,19 724.294 1440.72 724.294 1440.72 720 1411 c 0,20,21 714.001 1369.01 714.001 1369.01 696.5 1296 c 0,22,23 678.997 1222.99 678.997 1222.99 668 1151 c 0,24,25 660.378 1101.11 660.378 1101.11 660.438 1059.38 c 0,26,27 660.465 1040.89 660.465 1040.89 662 1024 c 0,28,29 666.999 969.001 666.999 969.001 706 962 c 0,30,31 755 952 755 952 818.5 997 c 0,32,33 860.317 1026.63 860.317 1026.63 860.285 1052.8 c 0,34,35 860.268 1066.36 860.268 1066.36 849 1079 c 0,36,37 831.104 1097.95 831.104 1097.95 816.257 1097.92 c 0,38,39 802.894 1097.9 802.894 1097.9 792 1082.5 c 0,40,41 768.995 1049.99 768.995 1049.99 758 1020 c 0,42,43 760 1114.01 760 1114.01 815 1131 c 0,44,45 870.001 1147.99 870.001 1147.99 943 1152 c 0,46,47 1016 1156.01 1016 1156.01 1091 1177.5 c 0,48,49 1165.99 1198.99 1165.99 1198.99 1209 1302 c 0,50,51 1200 1211.99 1200 1211.99 1157 1168 c 0,52,53 1113.98 1123.99 1113.98 1123.99 1062.5 1094 c 0,54,55 1011.02 1064.01 1011.02 1064.01 964.5 1030.5 c 0,56,57 918.002 997.006 918.002 997.006 905 929 c 0,58,59 904.926 915.649 l 0,60,61 907.773 908.182 907.773 908.182 919 907 c 0,62,63 938 905 938 905 961 914 c 0,64,65 993 926 993 926 993 970 c 0,66,67 1011.22 936.52 1011.22 936.52 1011.25 912.127 c 0,68,69 1011.29 886.983 1011.29 886.983 992 871.5 c 0,70,71 954 841 954 841 891 827.5 c 0,72,73 828 814 828 814 765 808.5 c 0,74,75 702 803 702 803 692 787 c 0,76,77 641 709 641 709 628.5 599 c 0,78,79 626.227 545.05 l 0,80,81 628.814 466.638 628.814 466.638 667 400 c 0,82,83 721 304 721 304 824 317.5 c 0,84,85 927 331 927 331 1033.5 364.5 c 0,86,87 1140 398.001 1140 398.001 1227 407.5 c 0,88,89 1314 417 1314 417 1338 313 c 0,90,91 1317 348 1317 348 1275 356.5 c 0,92,93 1246.05 359.1 l 0,94,95 1226.37 357.983 1226.37 357.983 1216 347 c 0,96,97 1160.01 286 1160.01 286 1213 248.5 c 0,98,99 1254.39 219.212 1254.39 219.212 1314.7 219.203 c 0,100,101 1331.61 219.201 1331.61 219.201 1350 221.5 c 0,102,103 1433.99 231.999 1433.99 231.999 1508.5 303.5 c 0,104,105 1572.66 365.071 1572.66 365.071 1572.66 491.539 c 0,106,107 1572.67 511.925 1572.67 511.925 1571 534 c 0,108,109 1629.01 327 1629.01 327 1482.5 227 c 0,110,111 1337.49 128.018 1337.49 128.018 1188 128 c 0,112,113 1115 128 1115 128 1009.5 164.5 c 0,114,115 975.793 176.162 975.793 176.162 951.324 176.135 c 0,116,117 899.207 176.079 899.207 176.079 889 123 c 0,118,119 879 70.9999 879 70.9999 935.5 70.5 c 0,120,121 992 70.0001 992 70.0001 1025 109 c 0,122,123 987 11 987 11 923 20.5 c 0,124,125 859 30 859 30 786.5 71.5 c 0,126,127 714.005 112.997 714.005 112.997 640 147.5 c 0,128,129 608.606 162.136 608.606 162.136 580.092 162.104 c 0,130,131 541.931 162.061 541.931 162.061 508 135 c 0,132,133 430 72 430 72 497.5 7.5 c 0,134,135 565 -57 565 -57 632 -55 c 0,136,137 559 -74.0001 559 -74.0001 514 -58 c 0,138,139 469 -42 469 -42 431 5 c 0,140,141 400.295 42.6839 400.295 42.6839 400.27 95.4635 c 0,142,143 400.259 118.317 400.259 118.317 406 144 c 0,144,145 425.001 229.002 425.001 229.002 455 317 c 0,146,147 485 405 485 405 501 482 c 0,148,149 504.875 518.125 l 0,150,151 504.5 568.75 504.5 568.75 467 598 c 0,152,153 424 631 424 631 383 607.5 c 0,154,155 341.997 583.997 341.997 583.997 300.5 550 c 0,156,157 259.003 516.002 259.003 516.002 215 494 c 0,158,159 171.001 472 171.001 472 122 509 c 0,160,161 213.001 506 213.001 506 222.5 557 c 0,162,163 225.013 589.347 l 0,164,165 223.428 614.785 223.428 614.785 208 627 c 0,166,167 177.736 648.857 177.736 648.857 152.812 648.885 c 0,168,169 133.264 648.906 133.264 648.906 117 635.5 c 0,170,171 79.9999 605 79.9999 605 65 548.5 c 0,172,173 50 492 50 492 60.5 431.5 c 0,174,175 71 371 71 371 112 350 c 0,176,177 20 389 20 389 23 515 c 0,178,179 26 641 26 641 57 679 c 0,180,181 134.265 772.396 134.265 772.396 233.155 772.797 c 0,182,183 250.736 772.868 250.736 772.868 269 770 c 0,184,185 390 751 390 751 498 818 c 0,186,187 513 827 513 827 503.5 931.5 c 0,188,189 493.999 1036.03 493.999 1036.03 490.5 1154 c 0,190,191 487 1272.01 487 1272.01 505 1361 c 0,192,193 519.319 1431.8 519.319 1431.8 566.539 1432.36 c 0,194,195 591.921 1428.33 l 0,196,197 593 1428 l 1,0,1 EndSplineSet KernsSLIF: 121 -104 0 0 116 -208 0 0 119 -385 0 0 EndChar StartChar: Nacute Encoding: 323 323 87 Width: 1285 Flags: MW VStem: 131 270.5<220 1558.5> 626 189<1760.5 1967> 822.5 107<83 1472> Fore 324 1593 m 0,0,1 346.986 1609 346.986 1609 395 1624 c 0,2,3 417.177 1627.12 l 0,4,5 451.57 1625.67 451.57 1625.67 479 1583 c 0,6,7 455.226 1594.71 455.226 1594.71 438.565 1595.02 c 0,8,9 422.575 1592.01 l 0,10,11 406.252 1584.52 406.252 1584.52 401.5 1558.5 c 0,12,13 397.146 1534.66 397.146 1534.66 397.177 1505.92 c 0,14,15 397.22 1465.34 397.22 1465.34 406 1415 c 0,16,17 421.004 1328.98 421.004 1328.98 446.5 1246 c 0,18,19 471.753 1163.81 471.753 1163.81 480 1146 c 0,20,21 493 1111.01 493 1111.01 527.5 1101 c 0,22,23 547.556 1098.57 l 0,24,25 567.655 1100.11 567.655 1100.11 580 1120 c 0,26,27 604 1160.01 604 1160.01 572.5 1183 c 0,28,29 547.425 1201.3 547.425 1201.3 515.706 1201.24 c 0,30,31 507.571 1201.22 507.571 1201.22 499 1200 c 0,32,33 536.359 1222.03 536.359 1222.03 565.234 1222.04 c 0,34,35 596.638 1222.05 596.638 1222.05 618 1196 c 0,36,37 658.999 1146.01 658.999 1146.01 679 1080 c 0,38,39 688 1047 688 1047 704 978 c 0,40,41 720 909 720 909 741.5 846.5 c 0,42,43 763 784 763 784 790 750.5 c 0,44,45 817 717 817 717 849 755 c 0,46,47 888.427 802.159 888.427 802.159 888.409 889.659 c 0,48,49 888.404 915.342 888.404 915.342 885 944.5 c 0,50,51 870.005 1072.96 870.005 1072.96 847 1212 c 0,52,53 824 1351.01 824 1351.01 822.5 1472 c 0,54,55 821 1593.01 821 1593.01 899 1640 c 0,56,57 893.009 1624.02 893.009 1624.02 861.5 1558 c 0,58,59 852.5 1539.14 852.5 1539.14 852.357 1523.63 c 0,60,61 852.259 1512.93 852.259 1512.93 856.378 1503.82 c 0,62,63 867.182 1479.93 867.182 1479.93 907 1467 c 0,64,65 923.542 1461.31 923.542 1461.31 938.201 1461.19 c 0,66,67 960.888 1464.7 l 0,68,69 1010.83 1481.53 1010.83 1481.53 1033.5 1579 c 0,70,71 1045.45 1630.38 1045.45 1630.38 1045.5 1672.21 c 0,72,73 1045.59 1747.62 1045.59 1747.62 1007 1792 c 0,74,75 1087.86 1740.37 1087.86 1740.37 1088.52 1642.23 c 0,76,77 1088.54 1639.63 1088.54 1639.63 1088.5 1637 c 0,78,79 1087 1535.03 1087 1535.03 1067 1436.5 c 0,80,81 1046.99 1337.91 1046.99 1337.91 1042 1269.5 c 0,82,83 1043.5 1244.33 l 0,84,85 1050.72 1214.15 1050.72 1214.15 1086.69 1213.97 c 0,86,87 1098.34 1213.91 1098.34 1213.91 1113 1217 c 0,88,89 1169.68 1227.56 1169.68 1227.56 1169.6 1287.95 c 0,90,91 1169.6 1290.43 1169.6 1290.43 1169.5 1293 c 0,92,93 1166.99 1358 1166.99 1358 1116 1404 c 0,94,95 1221 1357.99 1221 1357.99 1222.5 1273.5 c 0,96,97 1219.36 1222.38 l 0,98,99 1210.9 1161.16 1210.9 1161.16 1180 1095.5 c 0,100,101 1136 1001.99 1136 1001.99 1076.5 914 c 0,102,103 1017 826.012 1017 826.012 1002 774 c 0,104,105 982.94 710.755 982.94 710.755 983.02 577.323 c 0,106,107 983.032 556.746 983.032 556.746 983.5 534.5 c 0,108,109 987 368 987 368 981 279 c 0,110,111 973.999 187.997 973.999 187.997 929.5 83 c 0,112,113 885 -22 885 -22 805 -81 c 0,114,115 844 36 844 36 846 218 c 0,116,117 848 400 848 400 728 455 c 0,118,119 712.982 458.284 l 0,120,121 695.093 457.395 695.093 457.395 685 430 c 0,122,123 671 392 671 392 695 371 c 0,124,125 715.996 352.003 715.996 352.003 721.5 348 c 0,126,127 727 344 727 344 753 335 c 0,128,129 678 326 678 326 656.5 358 c 0,130,131 634.999 390.001 634.999 390.001 630 442 c 0,132,133 610.999 635.01 610.999 635.01 588.5 804 c 0,134,135 566 973 566 973 379 1038 c 0,136,137 359.306 1041.07 l 0,138,139 316.358 1039.59 316.358 1039.59 295 959.5 c 0,140,141 269 862 269 862 316 823 c 0,142,143 352 793 352 793 387.5 821.5 c 0,144,145 423 850 423 850 381 902 c 0,146,147 407.792 899.407 l 0,148,149 449.736 888.761 449.736 888.761 449.941 835.163 c 0,150,151 449.973 826.849 449.973 826.849 449 817.5 c 0,152,153 440 731.001 440 731.001 398 617.5 c 0,154,155 356 504 356 504 309 395.5 c 0,156,157 263.887 291.355 263.887 291.355 264 246 c 0,158,159 271.999 70.0008 271.999 70.0008 326.5 23 c 0,160,161 380.996 -23.9972 380.996 -23.9972 485 -93 c 0,162,163 359 -70.9999 359 -70.9999 260.5 12.5 c 0,164,165 162.001 95.9991 162.001 95.9991 131 220 c 0,166,167 95 367 95 367 155.5 536 c 0,168,169 184.99 618.377 184.99 618.377 185.137 667.728 c 0,170,171 185.236 701.109 185.236 701.109 171.911 719.38 c 0,172,173 164.52 729.514 164.52 729.514 153 735 c 0,174,175 130 745.667 130 745.667 114.167 745.833 c 0,176,177 104.718 745.933 104.718 745.933 97.8211 742.293 c 0,178,179 81.6048 733.734 81.6048 733.734 79.5 704.5 c 0,180,181 75 642 75 642 111 630 c 0,182,183 31 635 31 635 21 692 c 0,184,185 10.9999 749 10.9999 749 33.5 820.5 c 0,186,187 56 892 56 892 91 960 c 0,188,189 125.995 1027.99 125.995 1027.99 137 1055 c 0,190,191 169.999 1143.99 169.999 1143.99 217.5 1347.5 c 0,192,193 264.999 1551 264.999 1551 324 1593 c 0,0,1 587 1669 m 1,98,99 630 1708 630 1708 626 1760.5 c 0,100,101 621.997 1813.03 621.997 1813.03 615 1866 c 0,102,103 608 1918.99 608 1918.99 621 1965 c 0,104,105 634 2011.01 634 2011.01 711 2037 c 0,106,107 679.998 2023.99 679.998 2023.99 666.5 1988 c 0,108,109 662.585 1968.38 l 0,110,111 662.9 1947.8 662.9 1947.8 686 1938 c 0,112,113 760 1906.01 760 1906.01 767 2010 c 0,114,115 767.449 2068.65 l 0,116,117 763.629 2125.31 763.629 2125.31 741 2150 c 0,118,119 743.995 2150 743.995 2150 782.5 2104.5 c 0,120,121 815.68 2065.29 815.68 2065.29 815.809 1991.54 c 0,122,123 815.829 1979.71 815.829 1979.71 815 1967 c 0,124,125 798 1712.99 798 1712.99 587 1669 c 1,98,99 EndSplineSet EndChar StartChar: nacute Encoding: 324 324 88 Width: 1095 Flags: MW VStem: 114 229<334 1471> 534.5 160.5<1643 1818> 701.5 91<216 1398> Fore 278 1500 m 0,0,1 297 1513.99 297 1513.99 338 1527 c 0,2,3 358.082 1529.67 l 0,4,5 386.604 1527.83 386.604 1527.83 409 1492 c 0,6,7 352 1520.01 352 1520.01 343 1471 c 0,8,9 339.238 1450.51 339.238 1450.51 339.32 1425.84 c 0,10,11 339.434 1391.49 339.434 1391.49 347 1349 c 0,12,13 360 1276 360 1276 382 1205.5 c 0,14,15 404 1135 404 1135 410 1120 c 0,16,17 422 1091.01 422 1091.01 451 1082.5 c 0,18,19 469.146 1080.48 l 0,20,21 485.113 1082.18 485.113 1082.18 495 1098 c 0,22,23 516 1132.01 516 1132.01 489 1152 c 0,24,25 468.094 1167.48 468.094 1167.48 442.398 1167.38 c 0,26,27 434.903 1167.35 434.903 1167.35 427 1166 c 0,28,29 458.365 1184.53 458.365 1184.53 482.731 1184.66 c 0,30,31 501.908 1184.76 501.908 1184.76 516.747 1173.46 c 0,32,33 522.726 1168.9 522.726 1168.9 528 1162.5 c 0,34,35 562.996 1120.01 562.996 1120.01 580 1064 c 0,36,37 588 1035.99 588 1035.99 601.5 977 c 0,38,39 615 918 615 918 633 865.5 c 0,40,41 651 813 651 813 674 784 c 0,42,43 697 755 697 755 724 788 c 0,44,45 757.888 828.051 757.888 828.051 757.965 901.911 c 0,46,47 757.988 923.95 757.988 923.95 755 949 c 0,48,49 742 1058 742 1058 722.5 1176.5 c 0,50,51 703 1295 703 1295 701.5 1398 c 0,52,53 704.502 1442.42 l 0,54,55 715.57 1510.06 715.57 1510.06 767 1540 c 0,56,57 760.949 1525.89 760.949 1525.89 734.5 1470 c 0,58,59 726.928 1454 726.928 1454 726.826 1440.86 c 0,60,61 726.731 1428.6 726.731 1428.6 733.137 1418.82 c 0,62,63 743.897 1402.4 743.897 1402.4 773 1393 c 0,64,65 787.331 1388.1 787.331 1388.1 799.999 1388.12 c 0,66,67 857.17 1388.22 857.17 1388.22 880.5 1488.5 c 0,68,69 909 1611.01 909 1611.01 858 1670 c 0,70,71 926.936 1625.68 926.936 1625.68 927 1538.5 c 0,72,73 926 1452 926 1452 909.5 1368 c 0,74,75 893 1284 893 1284 888.5 1225.5 c 0,76,77 889.952 1203 l 0,78,79 896.331 1178.48 896.331 1178.48 926.052 1178.3 c 0,80,81 936.173 1178.24 936.173 1178.24 949 1181 c 0,82,83 998 1190 998 1190 995.5 1245.5 c 0,84,85 993 1301 993 1301 951 1340 c 0,86,87 1040.99 1301 1040.99 1301 1042 1229 c 0,88,89 1038.7 1182.13 l 0,90,91 1031 1131.55 1031 1131.55 1005.5 1077.5 c 0,92,93 968 998 968 998 917.5 923 c 0,94,95 867.001 848.003 867.001 848.003 854 804 c 0,96,97 838.122 749.311 838.122 749.311 838.195 632.77 c 0,98,99 838.205 617.187 838.205 617.187 838.5 600.5 c 0,100,101 838.195 430.678 l 0,102,103 837.386 404.787 837.386 404.787 836 384 c 0,104,105 830 306 830 306 792.5 216 c 0,106,107 755 126 755 126 687 77 c 0,108,109 720 177 720 177 721.5 331.5 c 0,110,111 723 486 723 486 621 534 c 0,112,113 607.018 536.132 l 0,114,115 593.061 533.918 593.061 533.918 584.5 512 c 0,116,117 572 480 572 480 593 462 c 0,118,119 616 440 616 440 643 431 c 0,120,121 579 424 579 424 560.5 450.5 c 0,122,123 542 477 542 477 538 522 c 0,124,125 521.997 687.025 521.997 687.025 503 830.5 c 0,126,127 484 974 484 974 325 1029 c 0,128,129 306.614 1031.48 l 0,130,131 270.724 1028.86 270.724 1028.86 253 962 c 0,132,133 230.999 879 230.999 879 271 846 c 0,134,135 302 820 302 820 332 844 c 0,136,137 362 868 362 868 326 913 c 0,138,139 392 915 392 915 384 841.5 c 0,140,141 376 768 376 768 340.5 671.5 c 0,142,143 304.992 574.979 304.992 574.979 265 483 c 0,144,145 226.89 395.349 226.89 395.349 227 356 c 0,146,147 233 206 233 206 280 165 c 0,148,149 327.001 124 327.001 124 414 67 c 0,150,151 307 85 307 85 223.5 156.5 c 0,152,153 139.999 228.001 139.999 228.001 114 334 c 0,154,155 82.9999 459 82.9999 459 135 602.5 c 0,156,157 160.46 672.76 160.46 672.76 160.509 714.612 c 0,158,159 160.561 758.24 160.561 758.24 133 771 c 0,160,161 73 798 73 798 69.5 745 c 0,162,163 66.0001 692 66.0001 692 97 682 c 0,164,165 29 686 29 686 20.5 734.5 c 0,166,167 17.9648 771.712 l 0,168,169 18.9725 805.202 18.9725 805.202 31 843.5 c 0,170,171 50 904 50 904 80 962 c 0,172,173 110 1020.01 110 1020.01 119 1043 c 0,174,175 146.995 1117.98 146.995 1117.98 187 1291 c 0,176,177 227.002 1464 227.002 1464 278 1500 c 0,0,1 501 1565 m 1,97,98 534.679 1595.04 534.679 1595.04 534.802 1635.02 c 0,99,100 534.814 1638.96 534.814 1638.96 534.5 1643 c 0,101,102 531 1688 531 1688 525.5 1733 c 0,103,104 520 1778 520 1778 530.5 1817 c 0,105,106 541 1856 541 1856 607 1877 c 0,107,108 580.003 1866.01 580.003 1866.01 568.5 1836 c 0,109,110 565.261 1819.15 l 0,111,112 565.976 1802.29 565.976 1802.29 586 1794 c 0,113,114 649 1767 649 1767 654.5 1855.5 c 0,115,116 660 1944 660 1944 633 1974 c 0,117,118 636 1974 636 1974 668 1935 c 0,119,120 700 1896 700 1896 695 1818 c 0,121,122 681.056 1601.86 681.056 1601.86 501 1565 c 1,97,98 EndSplineSet EndChar StartChar: Sacute Encoding: 346 346 89 Width: 1144 Flags: HW Fore 683 -50 m 0,0,1 575 -44 575 -44 470.5 -51 c 0,2,3 366 -58 366 -58 278.5 -43.5 c 0,4,5 191.001 -29 191.001 -29 128.5 23 c 0,6,7 65.9999 75 65.9999 75 43 201 c 0,8,9 70.0002 133 70.0002 133 142 103 c 0,10,11 155.224 97.4898 155.224 97.4898 166.729 97.3099 c 0,12,13 184.056 100.442 l 0,14,15 220.947 115.345 220.947 115.345 235 201 c 0,16,17 236.947 234.883 l 0,18,19 233.812 282.336 233.812 282.336 194 307.5 c 0,20,21 161.449 328.075 161.449 328.075 120.976 328.092 c 0,22,23 95.5509 328.102 95.5509 328.102 67 320 c 0,24,25 131.999 431 131.999 431 228 360 c 0,26,27 324 289 324 289 360 229 c 0,28,29 453 70 453 70 534 100 c 0,30,31 615 130 615 130 656.5 224.5 c 0,32,33 698 319 698 319 685 417 c 0,34,35 674.43 496.682 674.43 496.682 610.31 497.032 c 0,36,37 595.57 497.112 595.57 497.112 578 493 c 0,38,39 551 486 551 486 551.5 462 c 0,40,41 552 438 552 438 573 419 c 0,42,43 600 392 600 392 641 423 c 0,44,45 608.573 339.022 608.573 339.022 568.541 339.041 c 0,46,47 560.427 339.045 560.427 339.045 552 342.5 c 0,48,49 502 363.001 502 363.001 456 430 c 0,50,51 410 497 410 497 375.5 573 c 0,52,53 341 649 341 649 333 658 c 0,54,55 198.002 796.998 198.002 796.998 75.5 956.5 c 0,56,57 9.56444 1042.35 9.56444 1042.35 9.53848 1139.94 c 0,58,59 9.5162 1223.65 9.5162 1223.65 58 1316 c 0,60,61 71.9999 1343 71.9999 1343 107 1359.5 c 0,62,63 116.032 1363.76 116.032 1363.76 124.532 1363.79 c 0,64,65 148.967 1363.87 148.967 1363.87 169 1329 c 0,66,67 153.833 1338.39 153.833 1338.39 140.232 1338.32 c 0,68,69 116.166 1338.21 116.166 1338.21 97 1308.5 c 0,70,71 83.5354 1287.63 83.5354 1287.63 83.5672 1272.7 c 0,72,73 83.6063 1254.37 83.6063 1254.37 104 1245 c 0,74,75 114.919 1239.84 114.919 1239.84 126.863 1239.92 c 0,76,77 175.081 1240.25 175.081 1240.25 240 1326 c 0,78,79 321 1432.99 321 1432.99 276 1491 c 0,80,81 263.212 1506.89 263.212 1506.89 248.323 1507.16 c 0,82,83 233.127 1503.63 l 0,84,85 215.806 1495.55 215.806 1495.55 196 1469 c 0,86,87 195.152 1498.14 l 0,88,89 201.306 1554.44 201.306 1554.44 273 1577 c 0,90,91 362 1605.01 362 1605.01 480.5 1604 c 0,92,93 599.036 1602.99 599.036 1602.99 711.5 1586.5 c 0,94,95 824 1570 824 1570 859 1561 c 0,96,97 944.601 1539.42 944.601 1539.42 944.717 1476.2 c 0,98,99 944.767 1448.57 944.767 1448.57 928.5 1413 c 0,100,101 874.997 1295.99 874.997 1295.99 785 1261 c 0,102,103 814.991 1296.99 814.991 1296.99 845 1350 c 0,104,105 875 1402.99 875 1402.99 848 1434 c 0,106,107 826.995 1457 826.995 1457 788.5 1458.5 c 0,108,109 770.041 1455.64 l 0,110,111 743.053 1445.86 743.053 1445.86 722 1403 c 0,112,113 685.428 1330.43 685.428 1330.43 685.265 1283.65 c 0,114,115 685.167 1255.51 685.167 1255.51 698.253 1236.7 c 0,116,117 701.476 1232.07 701.476 1232.07 705.5 1228 c 0,118,119 751.965 1181.05 751.965 1181.05 842.5 1181 c 0,120,121 932.029 1182.01 932.029 1182.01 1028.5 1217.5 c 0,122,123 1124.99 1253.01 1124.99 1253.01 1159 1294 c 0,124,125 1084 1171 1084 1171 940 1120 c 0,126,127 870.72 1095.46 870.72 1095.46 800.75 1095.46 c 0,128,129 725.277 1095.46 725.277 1095.46 649 1124 c 0,130,131 571.991 1151 571.991 1151 521 1198.5 c 0,132,133 470 1246.01 470 1246.01 430.5 1275 c 0,134,135 400.256 1297.2 400.256 1297.2 373.833 1297.43 c 0,136,137 365.737 1297.49 365.737 1297.49 358 1295.5 c 0,138,139 324.998 1286.99 324.998 1286.99 285 1203 c 0,140,141 261.211 1152.62 261.211 1152.62 261.165 1096.13 c 0,142,143 261.145 1071.88 261.145 1071.88 265.5 1046.5 c 0,144,145 280 962 280 962 355 904 c 0,146,147 370.918 891.619 370.918 891.619 387.13 891.556 c 0,148,149 407.581 891.476 407.581 891.476 428.5 911 c 0,150,151 466 946 466 946 411 982 c 0,152,153 441.509 992.17 441.509 992.17 466.463 992.083 c 0,154,155 495.49 991.981 495.49 991.981 517 978 c 0,156,157 556.998 952.002 556.998 952.002 612 865 c 0,158,159 631.998 832.002 631.998 832.002 712 740 c 0,160,161 792.002 647.997 792.002 647.997 863 543 c 0,162,163 934 438 934 438 961 343 c 0,164,165 967.496 320.143 967.496 320.143 967.451 300.585 c 0,166,167 967.308 238.857 967.308 238.857 902 210 c 0,168,169 899.454 252.437 l 0,170,171 897.919 262.322 897.919 262.322 895.5 272 c 0,172,173 888 302 888 302 851 293 c 0,174,175 848 292 848 292 819.5 250 c 0,176,177 791 208 791 208 770 161.5 c 0,178,179 749 115 749 115 751.5 82 c 0,180,181 754 49 754 49 814 66 c 0,182,183 838 72 838 72 836.5 92.5 c 0,184,185 835 113.001 835 113.001 839 137 c 0,186,187 914 60.0001 914 60.0001 819.5 4 c 0,188,189 725 -52 725 -52 683 -50 c 0,0,1 414 1714 m 1,98,99 395.009 1728.03 395.009 1728.03 395.108 1801.05 c 0,100,101 395.129 1816.46 395.129 1816.46 396 1834.5 c 0,102,103 401 1938 401 1938 446.5 2042 c 0,104,105 491.999 2145.99 491.999 2145.99 585.5 2208.5 c 0,106,107 631.398 2239.18 631.398 2239.18 691.879 2239.14 c 0,108,109 754.596 2239.09 754.596 2239.09 833 2206 c 0,110,111 746.818 2206.21 l 0,112,113 690.669 2203.56 690.669 2203.56 649 2193 c 0,114,115 578 2175 578 2175 545 2079 c 0,116,117 530.449 2035.69 530.449 2035.69 530.302 2007.15 c 0,118,119 530.21 1989.43 530.21 1989.43 535.67 1977.4 c 0,120,121 546.801 1952.87 546.801 1952.87 581 1952 c 0,122,123 606.959 1954.33 l 0,124,125 630.094 1960.29 630.094 1960.29 630.065 1981.19 c 0,126,127 630.039 1999.11 630.039 1999.11 613 2028 c 0,128,129 669 2013 669 2013 673.5 1945 c 0,130,131 672.229 1913.5 l 0,132,133 665.109 1871.18 665.109 1871.18 627 1854 c 0,134,135 536.013 1812.01 536.013 1812.01 491.5 1808 c 0,136,137 446.998 1803.99 446.998 1803.99 414 1714 c 1,98,99 EndSplineSet EndChar StartChar: sacute Encoding: 347 347 90 Width: 1004 Flags: HW Fore 589 120 m 0,0,1 406 130.001 406 130.001 245 125.5 c 0,2,3 204.652 128.097 l 0,4,5 78.8561 149.094 78.8561 149.094 45 334 c 0,6,7 67 277 67 277 128.5 251.5 c 0,8,9 190 226 190 226 208 334 c 0,10,11 208.984 365.264 l 0,12,13 205.085 404.631 205.085 404.631 172.5 425.5 c 0,14,15 145.386 442.865 145.386 442.865 111.404 442.967 c 0,16,17 89.6139 443.033 89.6139 443.033 65 436 c 0,18,19 98.2419 492.813 98.2419 492.813 141.164 493.188 c 0,20,21 152.496 493.287 152.496 493.287 164.502 489.453 c 0,22,23 182.263 483.78 182.263 483.78 201.5 469.5 c 0,24,25 282.999 409 282.999 409 314 358 c 0,26,27 393 223 393 223 462 248.5 c 0,28,29 531 274 531 274 566 354.5 c 0,30,31 601 435 601 435 590 518 c 0,32,33 581.055 585.495 581.055 585.495 526.482 585.539 c 0,34,35 513.945 585.55 513.945 585.55 499 582 c 0,36,37 475 576 475 576 476 556 c 0,38,39 477 536 477 536 495 520 c 0,40,41 505.707 509.293 505.707 509.293 519.014 509.205 c 0,42,43 533.844 509.107 533.844 509.107 553 523 c 0,44,45 525.682 451.808 525.682 451.808 491.854 451.542 c 0,46,47 484.818 451.487 484.818 451.487 477.5 454.5 c 0,48,49 435 472 435 472 396 529 c 0,50,51 357 586 357 586 327.5 650.5 c 0,52,53 297.998 715.003 297.998 715.003 291 723 c 0,54,55 175.998 841.002 175.998 841.002 71 977 c 0,56,57 14.885 1049.69 14.885 1049.69 14.7503 1131.79 c 0,58,59 14.651 1192.36 14.651 1192.36 45.0218 1258.07 c 0,60,61 50.513 1269.95 50.513 1269.95 57 1282 c 0,62,63 69.0071 1305.01 69.0071 1305.01 98.5 1319 c 0,64,65 114.087 1322.62 l 0,66,67 134.507 1322.16 134.507 1322.16 152 1293 c 0,68,69 139.415 1300.69 139.415 1300.69 128.112 1300.87 c 0,70,71 113.474 1297.69 l 0,72,73 101.083 1291.89 101.083 1291.89 90.5 1275.5 c 0,74,75 79.2991 1258.15 79.2991 1258.15 78.9994 1245.72 c 0,76,77 81.6689 1234.06 l 0,78,79 85.7401 1226.63 85.7401 1226.63 96 1222 c 0,80,81 105.319 1217.64 105.319 1217.64 115.503 1217.7 c 0,82,83 156.677 1217.94 156.677 1217.94 212 1290.5 c 0,84,85 256.445 1348.79 256.445 1348.79 256.495 1390.28 c 0,86,87 256.523 1413.21 256.523 1413.21 243 1431 c 0,88,89 232.294 1444.38 232.294 1444.38 219.834 1444.75 c 0,90,91 206.014 1441.43 l 0,92,93 191.532 1434.32 191.532 1434.32 175 1412 c 0,94,95 174.516 1438.21 l 0,96,97 180.593 1484.96 180.593 1484.96 240.5 1504 c 0,98,99 314.701 1527.59 314.701 1527.59 417 1527.5 c 0,100,101 518 1527.01 518 1527.01 613 1512.5 c 0,102,103 708.126 1497.98 708.126 1497.98 738 1491 c 0,104,105 810.628 1472.32 810.628 1472.32 811.25 1418.96 c 0,106,107 807.364 1391.21 l 0,108,109 803.94 1378.58 803.94 1378.58 797.5 1364.5 c 0,110,111 751.998 1265 751.998 1265 675 1235 c 0,112,113 700.011 1266.02 700.011 1266.02 726 1311 c 0,114,115 739.549 1334.45 739.549 1334.45 739.791 1352.74 c 0,116,117 736.569 1370.08 l 0,118,119 733.894 1376.47 733.894 1376.47 729 1382 c 0,120,121 710.995 1402 710.995 1402 678 1403.5 c 0,122,123 661.255 1400.79 l 0,124,125 638.683 1392.11 638.683 1392.11 621 1356 c 0,126,127 567 1248 567 1248 607.5 1207.5 c 0,128,129 646.962 1168.04 646.962 1168.04 724 1168 c 0,130,131 800.014 1169.01 800.014 1169.01 882 1199 c 0,132,133 963.994 1229 963.994 1229 993 1264 c 0,134,135 930.004 1159.01 930.004 1159.01 807.5 1116 c 0,136,137 685 1072.99 685 1072.99 560 1119 c 0,138,139 431.01 1165.99 431.01 1165.99 374.5 1247.5 c 0,140,141 354.599 1276.2 354.599 1276.2 333.396 1277.06 c 0,142,143 317.756 1273.98 l 0,144,145 285.794 1260.26 285.794 1260.26 251 1186 c 0,146,147 229.83 1142.95 229.83 1142.95 229.824 1094.68 c 0,148,149 229.821 1074.55 229.821 1074.55 233.5 1053.5 c 0,150,151 245.999 982 245.999 982 310 932 c 0,152,153 340 908 340 908 372 938 c 0,154,155 404 968 404 968 357 998 c 0,156,157 414 1017.01 414 1017.01 447.5 995 c 0,158,159 481.001 972.998 481.001 972.998 528 899 c 0,160,161 544.996 871.005 544.996 871.005 613 793 c 0,162,163 681.005 714.993 681.005 714.993 741.5 625.5 c 0,164,165 802.001 535.997 802.001 535.997 825 455 c 0,166,167 830.495 435.646 830.495 435.646 830.51 419.09 c 0,168,169 830.557 366.353 830.557 366.353 775 342 c 0,170,171 775 369 775 369 769 394.5 c 0,172,173 763 420 763 420 731 412 c 0,174,175 728 411 728 411 704 376 c 0,176,177 680.003 341.004 680.003 341.004 662.5 301.5 c 0,178,179 646.815 266.098 646.815 266.098 646.795 239.931 c 0,180,181 646.793 236.903 646.793 236.903 647 234 c 0,182,183 648.32 215.509 648.32 215.509 671.01 215.335 c 0,184,185 682.679 215.245 682.679 215.245 700 220 c 0,186,187 719.174 225.478 719.174 225.478 719.5 243 c 0,188,189 720.689 277.847 l 0,190,191 720.838 278.919 720.838 278.919 721 280 c 0,192,193 748.912 251.652 748.912 251.652 749.34 226.442 c 0,194,195 745.982 208.436 l 0,196,197 737.062 186.118 737.062 186.118 704.5 166.5 c 0,198,199 624 118.001 624 118.001 589 120 c 0,0,1 360 1621 m 1,94,95 340 1634.99 340 1634.99 344.5 1723 c 0,96,97 349 1811 349 1811 388 1899.5 c 0,98,99 427.003 1988.01 427.003 1988.01 506 2041 c 0,100,101 544.749 2066.99 544.749 2066.99 596.004 2067.01 c 0,102,103 649.255 2067.03 649.255 2067.03 716 2039 c 0,104,105 636.712 2038.65 l 0,106,107 592.755 2036.02 592.755 2036.02 559.5 2027.5 c 0,108,109 499 2012.01 499 2012.01 472 1930 c 0,110,111 436 1825 436 1825 502 1823.5 c 0,112,113 568 1822 568 1822 529 1888 c 0,114,115 577.001 1874.99 577.001 1874.99 580.5 1817 c 0,116,117 578.704 1787.04 l 0,118,119 571.864 1754.29 571.864 1754.29 541 1740 c 0,120,121 462.986 1703.99 462.986 1703.99 425.5 1700.5 c 0,122,123 388 1697.01 388 1697.01 360 1621 c 1,94,95 EndSplineSet EndChar StartChar: Zacute Encoding: 377 377 91 Width: 1478 Flags: HMW HStem: -67.4639 277.536<303.18 1275.14> 1344.32 217.56<298.476 1314.54> 1899.4 128.77<686.556 1148.72> Fore 1282.79 1570.7 m 0,0,1 1372.16 1569.53 1372.16 1569.53 1401.56 1504.26 c 0,2,3 1421.76 1459.42 1421.76 1459.42 1421.7 1406.8 c 0,4,5 1421.67 1382.84 1421.67 1382.84 1417.44 1357.26 c 0,6,7 1403.93 1275.56 1403.93 1275.56 1357.46 1202.62 c 0,8,9 1311 1129.7 1311 1129.7 1249.86 1114.42 c 0,10,11 1352.93 1230.64 1352.93 1230.64 1352.86 1291.21 c 0,12,13 1352.82 1328.08 1352.82 1328.08 1314.54 1344.32 c 0,14,15 1293.11 1353.42 1293.11 1353.42 1272.11 1353.51 c 0,16,17 1250.07 1353.61 1250.07 1353.61 1228.5 1343.8 c 0,18,19 1173.58 1318.83 1173.58 1318.83 1121.68 1229.66 c 0,20,21 1084.05 1164.98 1084.05 1164.98 1074.64 1051.5 c 0,22,23 1065.23 938.016 1065.23 938.016 1046.41 863.928 c 0,24,25 1028.77 800.421 1028.77 800.421 986.436 744.563 c 0,26,27 944.1 688.704 944.1 688.704 870.012 734.568 c 0,28,29 920.58 743.976 920.58 743.976 926.46 779.256 c 0,30,31 932.34 814.536 932.34 814.536 901.764 815.712 c 0,32,33 839.436 816.888 839.436 816.888 810.036 749.268 c 0,34,35 780.636 681.646 780.636 681.646 759.468 600.504 c 0,36,37 738.3 519.36 738.3 519.36 714.78 452.328 c 0,38,39 691.26 385.296 691.26 385.296 643.044 390 c 0,40,41 681.852 437.04 681.852 437.04 669.504 464.088 c 0,42,43 657.156 491.136 657.156 491.136 635.988 486.432 c 0,44,45 583.066 473.496 583.066 473.496 536.616 361.188 c 0,46,47 490.164 248.88 490.164 248.88 506.628 213.6 c 0,48,49 532.5 153.624 532.5 153.624 653.628 151.271 c 0,50,51 718.72 153.447 l 0,52,53 779.51 159.89 779.51 159.89 790.044 184.2 c 0,54,55 805.332 218.304 805.332 218.304 770.052 233.592 c 0,56,57 734.771 248.88 734.771 248.88 718.308 224.184 c 0,58,59 753.588 322.968 753.588 322.968 848.256 248.88 c 0,60,61 942.924 174.792 942.924 174.792 1031.12 157.152 c 0,62,63 1075.81 147.744 1075.81 147.744 1142.84 174.792 c 0,64,65 1209.88 201.84 1209.88 201.84 1275.14 210.072 c 0,66,67 1340.41 218.304 1340.41 218.304 1392.74 178.908 c 0,68,69 1445.07 139.512 1445.07 139.512 1460.36 -1.6084 c 0,70,71 1422.73 93.6475 1422.73 93.6475 1351.58 86.5918 c 0,72,73 1280.44 79.5361 1280.44 79.5361 1203.41 28.9678 c 0,74,75 1126.37 -21.611 1126.37 -21.611 1058.76 -84.5156 c 0,76,77 991.14 -147.432 991.14 -147.432 961.74 -167.424 c 0,78,79 922.932 -190.944 922.932 -190.944 842.964 -180.36 c 0,80,81 762.996 -169.776 762.996 -169.776 750.06 -123.912 c 0,82,83 769.443 -127.877 769.443 -127.877 787.093 -127.799 c 0,84,85 816.561 -127.668 816.561 -127.668 841.2 -116.269 c 0,86,87 857.586 -108.687 857.586 -108.687 858.002 -97.3406 c 0,88,89 854.262 -84.773 l 0,90,91 847.346 -72.9171 847.346 -72.9171 827.676 -58.0557 c 0,92,93 767.7 -12.1925 767.7 -12.1925 569.544 -27.4805 c 0,94,95 371.388 -42.7687 371.388 -42.7687 303.18 -67.4639 c 0,96,97 220.858 -95.6885 220.858 -95.6885 118.548 -67.4639 c 0,98,99 16.2354 -39.2402 16.2354 -39.2402 16.2354 38.376 c 0,100,101 85.6201 -29.832 85.6201 -29.832 165 -9.25195 c 0,102,103 244.38 11.3281 244.38 11.3281 263.196 112.464 c 0,104,105 274.956 177.144 274.956 177.144 259.668 261.816 c 0,106,107 244.38 346.488 244.38 346.488 244.38 418.224 c 0,108,109 244.38 489.96 244.38 489.96 280.836 532.296 c 0,110,111 317.292 574.632 317.292 574.632 434.892 554.64 c 0,112,113 377.268 542.88 377.268 542.88 370.212 521.712 c 0,114,115 364.587 510.863 364.587 510.863 364.316 503.172 c 0,116,117 366.552 493.963 l 0,118,119 370.814 487.229 370.814 487.229 383.147 485.256 c 0,120,121 460.764 467.616 460.764 467.616 557.784 590.508 c 0,122,123 654.804 713.4 654.804 713.4 577.188 774.552 c 0,124,125 541.908 800.424 541.908 800.424 519.563 766.908 c 0,126,127 497.219 733.39 497.219 733.39 486.636 702.816 c 0,128,129 459.588 771.022 459.588 771.022 540.144 836.88 c 0,130,131 620.7 902.736 620.7 902.736 721.836 973.884 c 0,132,133 822.936 1045 822.936 1045 900 1125 c 0,134,135 954.038 1181.1 954.038 1181.1 953.961 1245.89 c 0,136,137 953.928 1273.45 953.928 1273.45 944.1 1302.58 c 0,138,139 936.209 1323.38 936.209 1323.38 914.101 1323.4 c 0,140,141 899.961 1323.41 899.961 1323.41 880.008 1314.92 c 0,142,143 828.957 1293.22 828.957 1293.22 771.228 1271.41 c 0,144,145 713.604 1249.66 713.604 1249.66 668.328 1255.54 c 0,146,147 623.052 1261.42 623.052 1261.42 623.052 1349.62 c 0,148,149 673.62 1284.94 673.62 1284.94 723.012 1320.22 c 0,150,151 739.476 1330.8 739.476 1330.8 740.063 1354.32 c 0,152,153 737.416 1374.98 l 0,154,155 734.913 1381.67 734.913 1381.67 730.067 1384.9 c 0,156,157 667.74 1423.71 667.74 1423.71 607.764 1389.01 c 0,158,159 547.788 1354.31 547.788 1354.31 488.988 1308.46 c 0,160,161 430.188 1262.59 430.188 1262.59 370.212 1237.9 c 0,162,163 310.234 1213.2 310.234 1213.2 249.084 1273.18 c 0,164,165 213.804 1304.93 213.804 1304.93 213.804 1361.38 c 0,166,167 217.335 1346.08 217.335 1346.08 264.96 1316.1 c 0,168,169 297.51 1295.61 297.51 1295.61 325.383 1295.71 c 0,170,171 338.304 1295.75 338.304 1295.75 350.22 1300.22 c 0,172,173 385.506 1313.17 385.506 1313.17 402.552 1333.74 c 0,174,175 414.513 1348.18 414.513 1348.18 414.612 1380.26 c 0,176,177 414.655 1393.92 414.655 1393.92 412.548 1410.77 c 0,178,179 393.73 1541.3 393.73 1541.3 254.964 1490.15 c 0,180,181 116.189 1438.98 116.189 1438.98 72.6836 1360.2 c 0,182,183 45.6312 1311.97 45.6312 1311.97 30.3477 1250.83 c 0,184,185 28.8703 1292.72 l 0,186,187 30.8234 1327.58 30.8234 1327.58 43.2842 1363.14 c 0,188,189 63.2687 1420.17 63.2687 1420.17 86.7959 1451.93 c 0,190,191 162.06 1557.77 162.06 1557.77 298.476 1561.88 c 0,192,193 434.892 1566.01 434.892 1566.01 547.788 1534.25 c 0,194,195 615.363 1515.28 615.363 1515.28 705.509 1515.29 c 0,196,197 794.181 1515.29 794.181 1515.29 904.704 1533.66 c 0,198,199 1127.58 1570.7 1127.58 1570.7 1282.79 1570.7 c 0,0,1 1148.72 2028.17 m 1,119,120 1051.12 1851.78 1051.12 1851.78 857.076 1850.59 c 0,121,122 775.932 1849.42 775.932 1849.42 745.944 1796.5 c 0,123,124 715.958 1743.58 715.958 1743.58 699.492 1669.49 c 0,125,126 655.406 1731.47 655.406 1731.47 655.406 1793.96 c 0,127,128 655.405 1846.49 655.405 1846.49 686.556 1899.4 c 0,129,130 754.76 2015.22 754.76 2015.22 860.604 2057.57 c 0,131,132 898.203 2071.67 898.203 2071.67 939.396 2074.03 c 0,133,134 980.556 2076.39 980.556 2076.39 988.788 2050.51 c 0,135,136 946.452 2061.1 946.452 2061.1 915.288 2031.7 c 0,137,138 884.124 2002.3 884.124 2002.3 911.172 1978.78 c 0,139,140 946.337 1945.68 946.337 1945.68 985.142 1945.74 c 0,141,142 1012.52 1945.77 1012.52 1945.77 1041.71 1962.31 c 0,143,144 1112.3 2002.32 1112.3 2002.32 1148.72 2028.17 c 1,119,120 EndSplineSet EndChar StartChar: zacute Encoding: 378 378 92 Width: 1265 Flags: HMW HStem: 9 236<259 1085.5> 1209.5 185<255 1119> 1681.5 109.5<585 978> Fore 1092 1402 m 0,0,1 1168 1400.99 1168 1400.99 1193 1345.5 c 0,2,3 1210.2 1307.32 1210.2 1307.32 1210.13 1262.5 c 0,4,5 1206.5 1220.5 l 0,6,7 1194.99 1150.99 1194.99 1150.99 1155.5 1089 c 0,8,9 1116.01 1027.01 1116.01 1027.01 1064 1014 c 0,10,11 1151.63 1112.81 1151.63 1112.81 1151.58 1164.32 c 0,12,13 1151.55 1195.69 1151.55 1195.69 1119 1209.5 c 0,14,15 1100.65 1217.29 1100.65 1217.29 1082.66 1217.31 c 0,16,17 1016.35 1217.4 1016.35 1217.4 955 1112 c 0,18,19 922.999 1056.99 922.999 1056.99 915 960.5 c 0,20,21 907 864 907 864 891 801 c 0,22,23 876 747 876 747 840 699.5 c 0,24,25 804 652 804 652 741 691 c 0,26,27 784 699 784 699 789 729 c 0,28,29 794 759 794 759 768 760 c 0,30,31 743.841 757.016 l 0,32,33 708.911 746.994 708.911 746.994 690 703.5 c 0,34,35 665 646 665 646 647 577 c 0,36,37 629 508 629 508 609 451 c 0,38,39 590.312 397.737 590.312 397.737 553.287 397.738 c 0,40,41 550.689 397.738 550.689 397.738 548 398 c 0,42,43 581 438 581 438 570.5 461 c 0,44,45 561.842 479.965 561.842 479.965 548.085 480.573 c 0,46,47 542 480 l 0,48,49 497 469 497 469 457.5 373.5 c 0,50,51 418 278 418 278 432 248 c 0,52,53 454.001 196.999 454.001 196.999 557 195 c 0,54,55 614.825 197.124 l 0,56,57 664.258 202.828 664.258 202.828 673 223 c 0,58,59 686 251.999 686 251.999 656 265 c 0,60,61 626 278 626 278 612 257 c 0,62,63 642 341 642 341 722.5 278 c 0,64,65 803 215 803 215 878 200 c 0,66,67 916 192.001 916 192.001 973 215 c 0,68,69 1030 237.999 1030 237.999 1085.5 245 c 0,70,71 1118.85 245.448 l 0,72,73 1154.79 241.615 1154.79 241.615 1185.5 218.5 c 0,74,75 1229.99 185.009 1229.99 185.009 1243 65 c 0,76,77 1213.43 139.87 1213.43 139.87 1159.49 140.41 c 0,78,79 1155.08 140.454 1155.08 140.454 1150.5 140 c 0,80,81 1090.01 134 1090.01 134 1024.5 91 c 0,82,83 959 48 959 48 901.5 -5.5 c 0,84,85 844 -59 844 -59 819 -76 c 0,86,87 786 -95.9999 786 -95.9999 718 -87 c 0,88,89 649.999 -77.9999 649.999 -77.9999 639 -39 c 0,90,91 673.033 -42.2686 l 0,92,93 696.616 -41.7 696.616 -41.7 716.5 -32.5 c 0,94,95 750 -17 750 -17 705 17 c 0,96,97 654 56 654 56 485.5 43 c 0,98,99 317 30 317 30 259 9 c 0,100,101 223.777 -3.07646 223.777 -3.07646 184.25 -2.99951 c 0,102,103 145.223 -2.92354 145.223 -2.92354 102 9 c 0,104,105 15 33 15 33 15 99 c 0,106,107 74 41 74 41 141.5 58.5 c 0,108,109 208.999 75.9999 208.999 75.9999 225 162 c 0,110,111 229.41 186.252 229.41 186.252 229.347 213.809 c 0,112,113 229.268 248.748 229.268 248.748 222 289 c 0,114,115 209 360.997 209 360.997 209 422 c 0,116,117 209 483.001 209 483.001 240 519 c 0,118,119 261.061 543.458 261.061 543.458 313.971 543.453 c 0,120,121 338.939 543.45 338.939 543.45 371 538 c 0,122,123 322 528 322 528 316 510 c 0,124,125 311.032 500.419 311.032 500.419 310.975 493.735 c 0,126,127 310.877 482.339 310.877 482.339 327 479 c 0,128,129 393 464 393 464 475.5 568.5 c 0,130,131 521.099 626.259 521.099 626.259 521.332 667.979 c 0,132,133 521.432 685.754 521.432 685.754 513.296 700.618 c 0,134,135 505.978 713.987 505.978 713.987 492 725 c 0,136,137 462 747 462 747 443 718.5 c 0,138,139 424 690 424 690 415 664 c 0,140,141 409.149 678.754 409.149 678.754 409.22 693.379 c 0,142,143 409.425 736.246 409.425 736.246 460.5 778 c 0,144,145 529.009 834.007 529.009 834.007 615 894.5 c 0,146,147 700.997 954.997 700.997 954.997 766.5 1023 c 0,148,149 812.481 1070.73 812.481 1070.73 812.385 1125.86 c 0,150,151 812.344 1149.27 812.344 1149.27 804 1174 c 0,152,153 793 1202.99 793 1202.99 749.5 1184.5 c 0,154,155 705.784 1165.91 705.784 1165.91 657 1147.5 c 0,156,157 618.64 1133.02 618.64 1133.02 586.715 1132.94 c 0,158,159 577.86 1132.92 577.86 1132.92 569.5 1134 c 0,160,161 531 1138.99 531 1138.99 531 1214 c 0,162,163 558.823 1178.41 558.823 1178.41 586.228 1178.41 c 0,164,165 601.176 1178.41 601.176 1178.41 616 1189 c 0,166,167 630 1198 630 1198 630.5 1218 c 0,168,169 627.915 1236.42 l 0,170,171 625.807 1241.46 625.807 1241.46 622 1244 c 0,172,173 593.97 1261.45 593.97 1261.45 566.502 1261.43 c 0,174,175 542.028 1261.4 542.028 1261.4 518 1247.5 c 0,176,177 466.973 1217.98 466.973 1217.98 417 1179 c 0,178,179 367 1140 367 1140 316 1119 c 0,180,181 301.146 1112.88 301.146 1112.88 286.207 1112.88 c 0,182,183 249.855 1112.85 249.855 1112.85 213 1149 c 0,184,185 183 1176 183 1176 183 1224 c 0,186,187 185.999 1211 185.999 1211 226.5 1185.5 c 0,188,189 267 1160 267 1160 299 1172 c 0,190,191 329 1182.99 329 1182.99 343.5 1200.5 c 0,192,193 353.794 1212.93 353.794 1212.93 353.756 1240.72 c 0,194,195 353.74 1252.08 353.74 1252.08 352 1266 c 0,196,197 340.537 1345.52 340.537 1345.52 276.723 1345.75 c 0,198,199 251.463 1345.84 251.463 1345.84 218 1333.5 c 0,200,201 99.9967 1290 99.9967 1290 63 1223 c 0,202,203 40 1182.01 40 1182.01 27 1130 c 0,204,205 25.9714 1169.14 l 0,206,207 28.0316 1197.06 28.0316 1197.06 38 1225.5 c 0,208,209 55.0032 1274 55.0032 1274 75 1301 c 0,210,211 139.004 1391.01 139.004 1391.01 255 1394.5 c 0,212,213 335.599 1393.09 l 0,214,215 405.421 1388.32 405.421 1388.32 467 1371 c 0,216,217 524.66 1354.82 524.66 1354.82 601.628 1354.88 c 0,218,219 676.847 1354.93 676.847 1354.93 770.5 1370.5 c 0,220,221 960 1402 960 1402 1092 1402 c 0,0,1 978 1791 m 1,119,120 895.003 1641.01 895.003 1641.01 730 1640 c 0,121,122 660.997 1638.99 660.997 1638.99 635.5 1594 c 0,123,124 610 1549 610 1549 596 1486 c 0,125,126 558.765 1538.35 558.765 1538.35 558.513 1591.13 c 0,127,128 558.415 1611.74 558.415 1611.74 563.958 1632.42 c 0,129,130 570.523 1656.91 570.523 1656.91 585 1681.5 c 0,131,132 642.997 1780 642.997 1780 733 1816 c 0,133,134 765.015 1828.01 765.015 1828.01 800 1830 c 0,135,136 822.603 1828.04 l 0,137,138 837.667 1823.62 837.667 1823.62 842 1810 c 0,139,140 818.356 1812.17 l 0,141,142 796.883 1810.4 796.883 1810.4 779.5 1794 c 0,143,144 765.367 1780.66 765.367 1780.66 765.313 1768.75 c 0,145,146 765.267 1758.33 765.267 1758.33 776 1749 c 0,147,148 805.866 1720.89 805.866 1720.89 838.816 1720.9 c 0,149,150 862.136 1720.91 862.136 1720.91 887 1735 c 0,151,152 947.068 1769.04 947.068 1769.04 978 1791 c 1,119,120 EndSplineSet EndChar StartChar: Zdotaccent Encoding: 379 379 93 Width: 1555 Flags: HMW HStem: -105.28 182.83<79.9004 1308.01> 1407.18 141.47<120.32 1356.42> 1778.01 73.79<756.7 935.3> Fore 899.58 1112.02 m 1,0,1 885.839 1123.16 885.839 1123.16 875.473 1123.15 c 0,2,3 859.6 1123.14 859.6 1123.14 851.64 1096.98 c 0,4,5 838.48 1053.73 838.48 1053.73 837.54 1039.64 c 0,6,7 802.76 1085.7 802.76 1085.7 843.18 1152.44 c 0,8,9 883.574 1219.13 883.574 1219.13 912.27 1277.46 c 0,10,11 926.839 1307.07 926.839 1307.07 926.965 1330.74 c 0,12,13 927.063 1349.1 927.063 1349.1 918.475 1363.88 c 0,14,15 916.345 1367.54 916.345 1367.54 913.68 1370.99 c 0,16,17 886.421 1406.24 886.421 1406.24 716.28 1389.32 c 0,18,19 660.522 1383.74 660.522 1383.74 630.27 1370.05 c 0,20,21 612.219 1361.74 612.219 1361.74 611.81 1344.53 c 0,22,23 615.659 1325.47 l 0,24,25 616.892 1322.25 616.892 1322.25 618.52 1318.82 c 0,26,27 633.4 1284.81 633.4 1284.81 658.163 1284.45 c 0,28,29 675.39 1287.8 l 0,30,31 712.521 1301.9 712.521 1301.9 742.6 1332.92 c 0,32,33 742.6 1263.36 742.6 1263.36 691.84 1237.04 c 0,34,35 641.08 1210.71 641.08 1210.71 574.81 1211.66 c 0,36,37 508.505 1212.61 508.505 1212.61 444.62 1231.87 c 0,38,39 380.701 1251.15 380.701 1251.15 354.38 1272.76 c 0,40,41 279.181 1331.03 279.181 1331.03 195.05 1417.99 c 0,42,43 153.956 1460.46 153.956 1460.46 120.822 1460.88 c 0,44,45 102.421 1457.64 l 0,46,47 78.9938 1448.77 78.9938 1448.77 60.1602 1415.64 c 0,48,49 48.9799 1395.91 48.9799 1395.91 48.8423 1384.23 c 0,50,51 48.7833 1379.22 48.7833 1379.22 50.7598 1375.69 c 0,52,53 57.38 1363.87 57.38 1363.87 71.4404 1342.32 c 0,54,55 -2.82025 1366.76 -2.82025 1366.76 7.51953 1438.2 c 0,56,57 23.5391 1548.56 23.5391 1548.56 110.343 1548.95 c 0,58,59 115.22 1548.97 115.22 1548.97 120.32 1548.65 c 0,60,61 199.929 1547.52 l 0,62,63 257.241 1549.51 257.241 1549.51 315.84 1559.46 c 0,64,65 345.926 1565.1 345.926 1565.1 379.29 1598.47 c 0,66,67 400.507 1619.69 400.507 1619.69 400.634 1635.02 c 0,68,69 400.707 1643.79 400.707 1643.79 393.86 1650.64 c 0,70,71 368.48 1673.2 368.48 1673.2 344.98 1664.74 c 0,72,73 321.479 1656.28 321.479 1656.28 291.4 1642.18 c 0,74,75 331.304 1714.47 331.304 1714.47 372.273 1715.24 c 0,76,77 390.844 1711.94 l 0,78,79 407.307 1705.8 407.307 1705.8 423.94 1688.24 c 0,80,81 491.602 1616.81 491.602 1616.81 547.08 1574.5 c 0,82,83 628.867 1510.58 628.867 1510.58 781.14 1499.3 c 0,84,85 854.669 1497.47 l 0,86,87 948.034 1500.65 948.034 1500.65 988.88 1535.96 c 0,88,89 998.844 1545.01 998.844 1545.01 998.771 1553.85 c 0,90,91 998.693 1563.36 998.693 1563.36 987 1572.62 c 0,92,93 960.068 1591.04 960.068 1591.04 941.426 1591.04 c 0,94,95 935.336 1591.04 935.336 1591.04 930.13 1589.07 c 0,96,97 908.941 1581.06 908.941 1581.06 880.78 1563.22 c 0,98,99 886.421 1611.17 886.421 1611.17 938.12 1632.78 c 0,100,101 949.999 1637.46 949.999 1637.46 966.568 1637.38 c 0,102,103 993.252 1637.26 993.252 1637.26 1032.12 1624.79 c 0,104,105 1095.13 1604.58 1095.13 1604.58 1169.36 1586.72 c 0,106,107 1233.67 1571.25 1233.67 1571.25 1298.71 1571.3 c 0,108,109 1308.76 1571.3 1308.76 1571.3 1318.82 1571.68 c 0,110,111 1394.03 1574.5 1394.03 1574.5 1449.48 1634.66 c 0,112,113 1507.75 1698.57 1507.75 1698.57 1441.02 1767.2 c 0,114,115 1512.47 1741.82 1512.47 1741.82 1512.93 1690.12 c 0,116,117 1509.33 1652.82 l 0,118,119 1502.52 1618.66 1502.52 1618.66 1482.85 1582.96 c 0,120,121 1452.26 1527.44 1452.26 1527.44 1410.47 1477.68 c 0,122,123 1368.67 1427.9 1368.67 1427.9 1356.42 1407.18 c 0,124,125 1319.75 1342.31 1319.75 1342.31 1317.88 1291.56 c 0,126,127 1316.11 1243.75 1316.11 1243.75 1225.93 1243.47 c 0,128,129 1220.37 1243.46 1220.37 1243.46 1214.48 1243.62 c 0,130,131 1256.77 1262.41 1256.77 1262.41 1278.87 1299.55 c 0,132,133 1287.73 1314.43 1287.73 1314.43 1288.05 1325.17 c 0,134,135 1284.94 1337.23 l 0,136,137 1280.54 1344.11 1280.54 1344.11 1269.94 1347.96 c 0,138,139 1254.4 1352.93 1254.4 1352.93 1239.99 1352.87 c 0,140,141 1210.82 1352.75 1210.82 1352.75 1186.28 1331.98 c 0,142,143 1149.62 1300.96 1149.62 1300.96 1128 1256.78 c 0,144,145 1106.39 1212.61 1106.39 1212.61 1102.62 1171.71 c 0,146,147 1103.32 1145.19 l 0,148,149 1106.66 1129.34 1106.66 1129.34 1118.6 1127.06 c 0,150,151 1149.01 1123.83 l 0,152,153 1183.71 1125.42 1183.71 1125.42 1184.4 1159.02 c 0,154,155 1181.58 1187.33 l 0,156,157 1175.31 1213.23 1175.31 1213.23 1155.26 1229.52 c 0,158,159 1207.9 1213.54 1207.9 1213.54 1220.12 1178.76 c 0,160,161 1226.02 1159.08 1226.02 1159.08 1226.03 1142.66 c 0,162,163 1226.05 1112.03 1226.05 1112.03 1205.55 1092.75 c 0,164,165 1174.05 1063.13 1174.05 1063.13 1128 1038.7 c 0,166,167 1081.99 1014.29 1081.99 1014.29 1040.58 984.18 c 0,168,169 999.219 954.096 999.219 954.096 997.34 898.64 c 0,170,171 995.46 844.12 995.46 844.12 1074.42 873.26 c 0,172,173 1063.14 833.78 1063.14 833.78 1026.48 814.98 c 0,174,175 989.819 796.18 989.819 796.18 960.68 786.78 c 0,176,177 862.921 756.701 862.921 756.701 761.4 647.66 c 0,178,179 659.881 538.622 659.881 538.622 606.3 418.3 c 0,180,181 567.675 331.563 567.675 331.563 567.641 256.305 c 0,182,183 567.628 227.167 567.628 227.167 573.4 199.75 c 0,184,185 594.081 101.52 594.081 101.52 740.72 94.9404 c 0,186,187 764.158 96.9563 l 0,188,189 790.657 103.873 790.657 103.873 806.99 132.54 c 0,190,191 817.439 150.879 817.439 150.879 817.342 166.896 c 0,192,193 817.225 186.181 817.225 186.181 801.82 202.1 c 0,194,195 774.56 227.48 774.56 227.48 739.78 213.38 c 0,196,197 705 199.28 705 199.28 684.32 175.78 c 0,198,199 694.659 249.099 694.659 249.099 734.61 259.91 c 0,200,201 749.507 263.941 749.507 263.941 765.712 263.855 c 0,202,203 792.962 263.709 792.962 263.709 823.91 251.92 c 0,204,205 873.255 233.122 873.255 233.122 923.55 200.22 c 0,206,207 973.841 167.32 973.841 167.32 1004.86 155.1 c 0,208,209 1213.54 67.6797 1213.54 67.6797 1308.01 77.5498 c 0,210,211 1402.48 87.42 1402.48 87.42 1532.2 208.68 c 0,212,213 1532.2 110.917 1532.2 110.917 1428.33 42.7695 c 0,214,215 1324.45 -25.381 1324.45 -25.381 1247.38 -31.96 c 0,216,217 1181.98 -32.991 l 0,218,219 1127.84 -30.5965 1127.84 -30.5965 1074.42 -17.3896 c 0,220,221 1048.4 -10.9567 1048.4 -10.9567 1024.38 -10.9157 c 0,222,223 969.438 -10.8217 969.438 -10.8217 924.96 -44.1797 c 0,224,225 895.82 -63.9199 895.82 -63.9199 926.84 -93.0596 c 0,226,227 952.966 -116.283 952.966 -116.283 970.127 -116.534 c 0,228,229 975.194 -116.609 975.194 -116.609 979.48 -114.68 c 0,230,-1 1023.66 -94.9404 l 0,231,232 1010.51 -152.28 1010.51 -152.28 970.08 -156.51 c 0,233,234 929.659 -160.74 929.659 -160.74 881.25 -141.94 c 0,235,236 832.84 -123.14 832.84 -123.14 786.31 -95.4102 c 0,237,238 739.78 -67.6797 739.78 -67.6797 714.4 -61.0996 c 0,239,240 634.502 -38.5407 634.502 -38.5407 561.65 2.82031 c 0,241,242 528.265 21.7742 528.265 21.7742 498.729 21.7766 c 0,243,244 463.815 21.7794 463.815 21.7794 434.28 -4.7002 c 0,245,246 419.28 -18.2478 419.28 -18.2478 419.225 -32.0451 c 0,247,248 419.172 -45.0517 419.172 -45.0517 432.4 -58.2803 c 0,249,250 449.496 -77.2754 449.496 -77.2754 469.951 -77.5578 c 0,251,252 489.438 -73.8738 l 0,253,254 500.884 -69.5507 500.884 -69.5507 513.24 -60.1602 c 0,255,256 513.24 -103.401 513.24 -103.401 457.31 -113.74 c 0,257,258 401.38 -124.08 401.38 -124.08 364.72 -107.16 c 0,259,260 349.68 -99.6393 349.68 -99.6393 302.21 -62.5098 c 0,261,262 254.739 -25.3793 254.739 -25.3793 203.98 -2.82031 c 0,263,264 153.22 19.7402 153.22 19.7402 114.68 6.11035 c 0,265,266 76.1396 -7.51953 76.1396 -7.51953 79.9004 -105.28 c 0,267,268 80.8399 -158.86 80.8399 -158.86 137.71 -173.43 c 0,269,270 166.776 -180.876 166.776 -180.876 194.982 -180.834 c 0,271,272 221.964 -180.794 221.964 -180.794 248.16 -173.9 c 0,273,274 210.53 -210.624 210.53 -210.624 164.261 -210.829 c 0,275,276 141.869 -210.928 141.869 -210.928 117.454 -202.474 c 0,277,278 87.722 -192.179 87.722 -192.179 54.9902 -169.2 c 0,279,280 -60.1601 -88.3605 -60.1601 -88.3605 20.6797 40.4199 c 0,281,282 101.52 169.2 101.52 169.2 232.65 252.39 c 0,283,284 363.779 335.579 363.779 335.579 440.86 465.3 c 0,285,286 506.658 578.096 506.658 578.096 568.23 757.17 c 0,287,288 629.8 936.24 629.8 936.24 731.32 956.92 c 0,289,290 715.341 942.82 715.341 942.82 710.17 918.38 c 0,291,292 705 893.94 705 893.94 719.1 878.9 c 0,293,294 731.321 864.8 731.321 864.8 767.04 894.41 c 0,295,296 802.76 924.02 802.76 924.02 837.54 967.73 c 0,297,298 872.326 1011.45 872.326 1011.45 893.47 1054.68 c 0,299,300 905.768 1079.82 905.768 1079.82 905.83 1095.11 c 0,301,302 905.875 1106.12 905.875 1106.12 899.58 1112.02 c 1,0,1 830.02 1714.56 m 0,157,158 744.479 1724.89 744.479 1724.89 756.7 1778.01 c 0,159,160 768.919 1831.12 768.919 1831.12 815.92 1867.78 c 0,161,162 850.152 1894.18 850.152 1894.18 877.328 1894.33 c 0,163,164 894.699 1894.43 894.699 1894.43 909.187 1883.81 c 0,165,166 923.688 1873.18 923.688 1873.18 935.3 1851.8 c 0,167,168 940.628 1841.7 940.628 1841.7 940.686 1829.77 c 0,169,170 940.784 1809.32 940.784 1809.32 925.404 1783.45 c 0,171,172 919.676 1773.82 919.676 1773.82 911.8 1763.44 c 0,173,174 874.489 1714.25 874.489 1714.25 837.937 1714.03 c 0,175,176 833.974 1714.01 833.974 1714.01 830.02 1714.56 c 0,157,158 EndSplineSet EndChar StartChar: zdotaccent Encoding: 380 380 94 Width: 1343 Flags: HMW HStem: -17.54 156.04<86.6797 1130.55> 1268.38 120.79<120.989 1172.38> 1583.75 62.51<661.489 814.239> Fore 783.22 1017.4 m 0,0,1 772.103 1026.72 772.103 1026.72 763.586 1027.15 c 0,2,3 754.464 1024.58 l 0,4,5 747.245 1019.63 747.245 1019.63 742.8 1005.18 c 0,6,7 731.52 968.522 731.52 968.522 731.52 956.301 c 0,8,9 717.44 974.78 717.44 974.78 717.468 996.967 c 0,10,11 717.499 1022.18 717.499 1022.18 735.75 1052.18 c 0,12,13 770.065 1108.59 770.065 1108.59 794.029 1157.93 c 0,14,15 806.23 1183.05 806.23 1183.05 806.254 1203.18 c 0,16,17 806.278 1222.59 806.278 1222.59 794.97 1237.36 c 0,18,19 779.213 1257.94 779.213 1257.94 706.485 1257.84 c 0,20,21 672.904 1257.79 672.904 1257.79 627.18 1253.34 c 0,22,23 520.02 1242.06 520.02 1242.06 544.46 1194.12 c 0,24,25 557.187 1164.42 557.187 1164.42 578.153 1163.98 c 0,26,27 592.869 1166.86 l 0,28,29 624.375 1179.09 624.375 1179.09 649.739 1205.4 c 0,30,31 649.739 1146.18 649.739 1146.18 606.5 1124.09 c 0,32,33 565.004 1102.89 565.004 1102.89 511.821 1102.9 c 0,34,35 509.586 1102.9 509.586 1102.9 507.33 1102.94 c 0,36,37 451.4 1103.89 451.4 1103.89 396.88 1119.86 c 0,38,39 342.376 1135.83 342.376 1135.83 319.8 1154.64 c 0,40,41 255.841 1203.55 255.841 1203.55 183.97 1277.78 c 0,42,43 148.579 1314.33 148.579 1314.33 120.359 1314.45 c 0,44,45 96.4207 1314.55 96.4207 1314.55 77.6431 1288.43 c 0,46,47 73.5809 1282.78 73.5809 1282.78 69.7598 1275.9 c 0,48,49 55.6592 1252.4 55.6592 1252.4 61.7695 1242.06 c 0,50,-1 79.1592 1213.86 l 0,51,52 23.9276 1232.27 23.9276 1232.27 23.9089 1277.95 c 0,53,54 23.9056 1285.91 23.9056 1285.91 25.5801 1294.7 c 0,55,56 39.6797 1394.34 39.6797 1394.34 120.989 1389.17 c 0,57,58 193.089 1388.53 l 0,59,60 239.478 1390.61 239.478 1390.61 286.899 1399.04 c 0,61,62 312.279 1402.81 312.279 1402.81 340.949 1431.47 c 0,63,64 359.124 1449.64 359.124 1449.64 359.356 1462.34 c 0,65,66 356.047 1472.51 l 0,67,68 355.007 1473.89 355.007 1473.89 353.64 1475.18 c 0,69,70 337.706 1489.73 337.706 1489.73 322.537 1489.73 c 0,71,72 317.125 1489.72 317.125 1489.72 311.81 1487.87 c 0,73,74 291.561 1480.81 291.561 1480.81 266.22 1468.6 c 0,75,76 300.537 1530.26 300.537 1530.26 335.576 1530.55 c 0,77,78 347.721 1530.65 347.721 1530.65 359.953 1523.37 c 0,79,80 369.46 1517.72 369.46 1517.72 379.02 1507.61 c 0,81,82 436.376 1446.96 436.376 1446.96 484.3 1411.26 c 0,83,84 553.867 1357.67 553.867 1357.67 683.109 1347.34 c 0,85,86 812.359 1337 812.359 1337 859.359 1378.36 c 0,87,88 867.431 1385.58 867.431 1385.58 867.823 1392.61 c 0,89,90 864.543 1402.45 l 0,91,92 861.995 1405.94 861.995 1405.94 857.479 1409.38 c 0,93,94 834.929 1424.89 834.929 1424.89 819.247 1425.07 c 0,95,96 814.01 1425.13 814.01 1425.13 809.54 1423.48 c 0,97,98 791.682 1416.9 791.682 1416.9 768.18 1400.92 c 0,99,100 771.939 1442.27 771.939 1442.27 816.119 1460.14 c 0,101,102 826.07 1464.56 826.07 1464.56 840.359 1464.58 c 0,103,104 862.506 1464.6 862.506 1464.6 895.08 1454.03 c 0,105,106 948.721 1436.62 948.721 1436.62 1012.11 1421.13 c 0,107,108 1066.09 1407.93 1066.09 1407.93 1120.42 1408.01 c 0,109,110 1129.95 1408.02 1129.95 1408.02 1139.48 1408.44 c 0,111,112 1203.41 1411.26 1203.41 1411.26 1250.4 1462.02 c 0,113,114 1273.28 1487.06 1273.28 1487.06 1273.56 1512.89 c 0,115,116 1269.86 1534.57 l 0,117,118 1262.91 1554.47 1262.91 1554.47 1242.88 1574.82 c 0,119,120 1303.99 1552.26 1303.99 1552.26 1304.45 1508.55 c 0,121,122 1300.89 1474.26 l 0,123,124 1294.94 1446.53 1294.94 1446.53 1279.07 1417.37 c 0,125,126 1253.26 1369.95 1253.26 1369.95 1217.5 1328.07 c 0,127,128 1181.77 1286.22 1181.77 1286.22 1172.38 1268.38 c 0,129,130 1140.42 1213.86 1140.42 1213.86 1139.01 1170.62 c 0,131,132 1137.7 1130.33 1137.7 1130.33 1062.53 1130.03 c 0,133,134 1057.02 1130.01 1057.02 1130.01 1051.12 1130.2 c 0,135,136 1087.78 1145.25 1087.78 1145.25 1105.64 1177.2 c 0,137,138 1112.71 1189.84 1112.71 1189.84 1113.01 1198.95 c 0,139,140 1110.36 1209.59 l 0,141,142 1106.73 1215.37 1106.73 1215.37 1098.12 1218.56 c 0,143,144 1082.16 1223.88 1082.16 1223.88 1067.74 1223.88 c 0,145,146 1010.8 1223.89 1010.8 1223.89 977.8 1141.01 c 0,147,148 954.788 1083.22 954.788 1083.22 954.764 1055.55 c 0,149,150 954.744 1033.48 954.744 1033.48 969.34 1030.56 c 0,151,152 996.981 1028.25 l 0,153,154 1025.07 1030.62 1025.07 1030.62 1025.74 1058.29 c 0,155,156 1022.83 1084.53 l 0,157,158 1017.29 1104.61 1017.29 1104.61 1001.3 1117.04 c 0,159,160 1045.49 1104.81 1045.49 1104.81 1055.82 1074.74 c 0,161,162 1069.92 1026.8 1069.92 1026.8 1043.13 1001.42 c 0,163,164 1016.33 976.035 1016.33 976.035 977.33 955.36 c 0,165,166 938.317 934.68 938.317 934.68 903.069 909.301 c 0,167,168 867.819 883.919 867.819 883.919 866.88 836.92 c 0,169,170 869.21 820.455 l 0,171,172 874.76 806.996 874.76 806.996 893.248 806.83 c 0,173,174 904.345 806.73 904.345 806.73 920.103 811.419 c 0,175,176 925.633 813.065 925.633 813.065 931.739 815.301 c 0,177,178 921.4 781.459 921.4 781.459 890.85 765.48 c 0,179,180 860.294 749.498 860.294 749.498 834.92 741.98 c 0,181,182 752.2 716.601 752.2 716.601 665.72 623.54 c 0,183,184 579.239 530.48 579.239 530.48 534.119 428.021 c 0,185,186 501.638 354.259 501.638 354.259 501.553 290.485 c 0,187,188 501.519 265.672 501.519 265.672 506.39 242.37 c 0,189,190 523.779 159.181 523.779 159.181 648.8 153.54 c 0,191,192 669.809 155.334 l 0,193,194 691.55 161.305 691.55 161.305 705.199 185.03 c 0,195,196 714.026 200.372 714.026 200.372 714.019 213.929 c 0,197,198 714.011 230.69 714.011 230.69 700.5 244.721 c 0,199,200 677 266.341 677 266.341 647.39 254.591 c 0,201,202 617.78 242.842 617.78 242.842 599.92 223.101 c 0,203,204 612.578 307.278 612.578 307.278 662.312 307.291 c 0,205,206 686.442 307.297 686.442 307.297 719.3 287.49 c 0,207,208 819.881 226.859 819.881 226.859 873.46 205.24 c 0,209,210 1050.18 130.04 1050.18 130.04 1130.55 138.5 c 0,211,212 1210.92 146.96 1210.92 146.96 1320.9 250.36 c 0,213,214 1320.9 166.696 1320.9 166.696 1232.54 108.42 c 0,215,216 1144.17 50.1396 1144.17 50.1396 1078.38 44.5 c 0,217,218 1005.06 38.8605 1005.06 38.8605 931.739 57.6602 c 0,219,220 858.42 76.46 858.42 76.46 804.84 35.1006 c 0,221,222 792.66 26.0785 792.66 26.0785 792.604 15.9739 c 0,223,224 792.542 5.02315 792.542 5.02315 806.72 -7.19922 c 0,225,226 835.859 -33.5195 835.859 -33.5195 850.899 -26.4697 c 0,227,-1 888.5 -9.08008 l 0,228,229 866.88 -104.96 866.88 -104.96 768.18 -48.5596 c 0,230,231 669.478 7.84116 669.478 7.84116 626.239 20.0605 c 0,232,233 557.619 38.8602 557.619 38.8602 496.05 74.5801 c 0,234,235 434.479 110.301 434.479 110.301 388.42 68 c 0,236,237 375.162 55.7245 375.162 55.7245 375.242 43.7057 c 0,238,239 375.315 32.7157 375.315 32.7157 386.54 21.9404 c 0,240,241 415.681 -10.96 415.681 -10.96 455.159 21 c 0,242,243 455.159 -16.5997 455.159 -16.5997 407.689 -25.5293 c 0,244,245 371.209 -28.8155 l 0,246,247 347.38 -28.2343 347.38 -28.2343 329.199 -19.4199 c 0,248,249 316.039 -13.7793 316.039 -13.7793 275.619 18.1807 c 0,250,251 235.197 50.1417 235.197 50.1417 192.43 69.8809 c 0,252,253 149.659 89.6201 149.659 89.6201 116.76 77.4004 c 0,254,255 83.8595 65.1806 83.8595 65.1806 86.6797 -17.54 c 0,256,257 87.6191 -62.6592 87.6191 -62.6592 136.029 -74.8799 c 0,258,259 184.439 -87.0996 184.439 -87.0996 229.56 -74.8799 c 0,260,261 197.553 -106.429 197.553 -106.429 157.984 -106.507 c 0,262,263 116.206 -106.589 116.206 -106.589 66 -71.5898 c 0,264,265 -31.7607 -3.4394 -31.7607 -3.4394 35.9199 107.48 c 0,266,267 104.54 216.521 104.54 216.521 216.399 287.021 c 0,268,269 328.261 357.522 328.261 357.522 393.119 468.44 c 0,270,271 449.521 564.32 449.521 564.32 501.689 716.601 c 0,272,273 553.859 868.881 553.859 868.881 640.34 885.801 c 0,274,275 617.12 865.821 617.12 865.821 617.166 847.081 c 0,276,277 617.2 833.201 617.2 833.201 630 820 c 0,278,279 634.076 815.747 634.076 815.747 640.206 815.804 c 0,280,281 666.594 816.047 666.594 816.047 731.05 896.141 c 0,282,283 810.479 994.839 810.479 994.839 783.22 1017.4 c 0,0,1 724 1529.7 m 0,147,148 660.063 1537.08 660.063 1537.08 660.1 1572.69 c 0,149,150 660.106 1577.92 660.106 1577.92 661.489 1583.75 c 0,151,152 672.301 1629.34 672.301 1629.34 712.72 1660.36 c 0,153,154 741.575 1683.03 741.575 1683.03 764.646 1683.11 c 0,155,156 794.183 1683.21 794.183 1683.21 814.239 1646.26 c 0,157,158 828.341 1618.06 828.341 1618.06 793.56 1571.53 c 0,159,160 762.282 1529.69 762.282 1529.69 731 1529.27 c 0,161,162 727.499 1529.23 727.499 1529.23 724 1529.7 c 0,147,148 EndSplineSet EndChar EndChars EndSplineFont ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1691062243.0 reportlab-4.1.0/src/reportlab/fonts/DarkGardenMK.afm0000664000175000017500000002415714462707743021762 0ustar00rptlabrptlabStartFontMetrics 2.0 Comment Generated by FontForge 20071110 Comment Creation Date: Wed Sep 10 17:07:49 2008 FontName DarkGardenMK FullName Dark Garden FamilyName Dark Garden Weight Medium Notice (Copyright (C) 1999, 2000, 2004 Michal Kosmulski ) Comment Comment Comment This font is free software; you can redistribute it and/or modify Comment it under the terms of the GNU General Public License as published by Comment the Free Software Foundation; either version 2 of the License, or Comment (at your option) any later version. Comment Comment This font is distributed in the hope that it will be useful, Comment but WITHOUT ANY WARRANTY; without even the implied warranty of Comment MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the Comment GNU General Public License for more details. Comment Comment You should have received a copy of the GNU General Public License Comment along with this font; if not, write to the Free Software Comment Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. Comment Comment As a special exception, if you create a document which uses Comment this font, and embed this font or unaltered portions of this font into Comment the document, this font does not by itself cause the resulting Comment document to be covered by the GNU General Public License. This Comment exception does not however invalidate any other reasons why the Comment document might be covered by the GNU General Public License. If you Comment modify this font, you may extend this exception to your version of the Comment font, but you are not obligated to do so. If you do not wish to do so, Comment delete this exception statement from your version. Comment ItalicAngle 0 IsFixedPitch false UnderlinePosition -420 UnderlineThickness 80 Version 1.1 EncodingScheme ISO10646-1 FontBBox -11 -331 935 1122 CapHeight 931 XHeight 869 Ascender 831 Descender -123 StartCharMetrics 86 C 0 ; WX 1000 ; N .notdef ; B 0 0 531 890 ; C 1 ; WX 0 ; N glyph1 ; B 0 0 0 0 ; C 2 ; WX 1000 ; N glyph2 ; B 0 0 0 0 ; C 32 ; WX 500 ; N space ; B 0 0 0 0 ; C 44 ; WX 130 ; N comma ; B 0 -76 123 105 ; C 45 ; WX 611 ; N hyphen ; B 46 364 560 519 ; C 46 ; WX 131 ; N period ; B 1 0 124 124 ; C 58 ; WX 187 ; N colon ; B 32 6 159 447 ; C 59 ; WX 187 ; N semicolon ; B 36 -98 163 470 ; C 65 ; WX 706 ; N A ; B 3 -162 670 853 ; C 66 ; WX 624 ; N B ; B -5 -27 602 911 ; C 67 ; WX 619 ; N C ; B -1 -52 590 846 ; C 68 ; WX 730 ; N D ; B 4 -133 703 912 ; C 69 ; WX 613 ; N E ; B 1 -100 613 836 ; C 70 ; WX 660 ; N F ; B 3 -96 629 833 ; C 71 ; WX 624 ; N G ; B 5 -61 594 898 ; C 72 ; WX 660 ; N H ; B 7 -177 629 876 ; C 73 ; WX 284 ; N I ; B 22 -179 271 932 ; C 74 ; WX 603 ; N J ; B 3 -93 570 863 ; C 75 ; WX 639 ; N K ; B 7 -182 625 921 ; C 76 ; WX 658 ; N L ; B 15 -3 616 903 ; C 77 ; WX 833 ; N M ; B 9 -236 861 874 ; C 78 ; WX 614 ; N N ; B 3 -135 579 917 ; C 79 ; WX 691 ; N O ; B 9 -35 659 848 ; C 80 ; WX 648 ; N P ; B 4 -203 605 846 ; C 81 ; WX 612 ; N Q ; B -11 -179 578 894 ; C 82 ; WX 647 ; N R ; B -1 -331 614 891 ; C 83 ; WX 666 ; N S ; B 3 -60 654 876 ; C 84 ; WX 829 ; N T ; B 0 -195 787 817 ; C 85 ; WX 688 ; N U ; B 6 -33 656 874 ; C 86 ; WX 618 ; N V ; B 4 -188 589 991 ; C 87 ; WX 985 ; N W ; B 4 -132 935 974 ; C 88 ; WX 690 ; N X ; B 6 -125 731 951 ; C 89 ; WX 645 ; N Y ; B 7 -209 609 953 ; C 90 ; WX 841 ; N Z ; B 14 -108 853 845 ; C 97 ; WX 612 ; N a ; B 13 -93 581 769 ; C 98 ; WX 528 ; N b ; B -4 -23 512 774 ; C 99 ; WX 571 ; N c ; B 42 15 545 779 ; C 100 ; WX 641 ; N d ; B 15 -60 609 829 ; C 101 ; WX 527 ; N e ; B 8 -35 528 760 ; C 102 ; WX 563 ; N f ; B 21 -25 553 765 ; C 103 ; WX 549 ; N g ; B 21 10 522 825 ; C 104 ; WX 581 ; N h ; B 24 -96 553 798 ; C 105 ; WX 256 ; N i ; B 22 -99 235 846 ; C 106 ; WX 527 ; N j ; B 17 -27 499 786 ; C 107 ; WX 543 ; N k ; B 6 -155 531 783 ; C 108 ; WX 525 ; N l ; B -1 62 510 832 ; C 109 ; WX 718 ; N m ; B 14 -151 738 792 ; C 110 ; WX 523 ; N n ; B 13 -63 502 832 ; C 111 ; WX 612 ; N o ; B 30 28 584 779 ; C 112 ; WX 561 ; N p ; B 13 -124 524 767 ; C 113 ; WX 566 ; N q ; B 33 -98 535 814 ; C 114 ; WX 548 ; N r ; B -3 -245 520 795 ; C 115 ; WX 567 ; N s ; B 3 9 556 806 ; C 116 ; WX 718 ; N t ; B 13 -117 682 743 ; C 117 ; WX 587 ; N u ; B 8 36 560 805 ; C 118 ; WX 530 ; N v ; B 9 -99 506 902 ; C 119 ; WX 774 ; N w ; B 1 -49 793 891 ; C 120 ; WX 604 ; N x ; B 11 -43 628 870 ; C 121 ; WX 559 ; N y ; B 14 -122 526 866 ; C 122 ; WX 764 ; N z ; B 7 -36 720 774 ; C 196 ; WX 765 ; N Adieresis ; B 8 -179 724 1064 ; C 211 ; WX 704 ; N Oacute ; B 7 -82 665 1012 ; C 214 ; WX 791 ; N Odieresis ; B 1 -68 755 1084 ; C 220 ; WX 763 ; N Udieresis ; B -1 -59 728 1122 ; C 223 ; WX 543 ; N germandbls ; B 2 -304 516 795 ; C 228 ; WX 650 ; N adieresis ; B 6 -152 615 904 ; C 243 ; WX 600 ; N oacute ; B 8 -2 567 928 ; C 246 ; WX 672 ; N odieresis ; B 0 -58 642 921 ; C 252 ; WX 648 ; N udieresis ; B -1 -50 619 953 ; C -1 ; WX 699 ; N Aogonek ; B 1 -257 657 838 ; C -1 ; WX 594 ; N aogonek ; B 1 -219 559 712 ; C -1 ; WX 596 ; N Cacute ; B 8 -57 561 1046 ; C -1 ; WX 514 ; N cacute ; B 14 20 484 959 ; C -1 ; WX 739 ; N Eogonek ; B 2 -240 738 785 ; C -1 ; WX 637 ; N eogonek ; B 13 -121 640 750 ; C -1 ; WX 848 ; N Lslash ; B 8 -107 908 871 ; C -1 ; WX 722 ; N lslash ; B 11 -32 776 799 ; C -1 ; WX 627 ; N Nacute ; B 8 -46 597 1050 ; C -1 ; WX 534 ; N nacute ; B 8 32 509 964 ; C -1 ; WX 558 ; N Sacute ; B 4 -27 566 1094 ; C -1 ; WX 490 ; N sacute ; B 7 58 485 1010 ; C -1 ; WX 721 ; N Zacute ; B 7 -90 714 1013 ; C -1 ; WX 617 ; N zacute ; B 7 -44 607 894 ; C -1 ; WX 759 ; N Zdotaccent ; B -7 -103 749 925 ; C -1 ; WX 655 ; N zdotaccent ; B 4 -53 645 822 ; EndCharMetrics StartKernData StartKernPairs 291 KPX hyphen Z -126 KPX hyphen z -101 KPX hyphen X -88 KPX hyphen x -76 KPX hyphen Y -63 KPX hyphen y -50 KPX hyphen W -88 KPX hyphen w -88 KPX hyphen T -139 KPX hyphen t -133 KPX hyphen S -114 KPX hyphen s -76 KPX hyphen A -114 KPX hyphen a -114 KPX A C -25 KPX A c -63 KPX A M -50 KPX A m -38 KPX A h -63 KPX A H -50 KPX A hyphen -82 KPX A s -139 KPX A S -120 KPX A y -145 KPX A Y -125 KPX A t -145 KPX A T -145 KPX A v -31 KPX A w -112 KPX A V -24 KPX A W -94 KPX C S -69 KPX C s -63 KPX C A -31 KPX C a -44 KPX D Z -88 KPX D z -69 KPX D a -101 KPX D A -73 KPX E S -63 KPX E s -63 KPX F t -139 KPX F T -82 KPX F hyphen -101 KPX F period -114 KPX F comma -133 KPX F A -239 KPX F a -229 KPX H A -44 KPX K o -50 KPX K O -25 KPX K s -107 KPX K S -101 KPX K g -88 KPX K G -38 KPX K c -114 KPX K C -69 KPX L t -203 KPX L T -203 KPX L Y -114 KPX L y -114 KPX L i -63 KPX L I -69 KPX L hyphen -107 KPX L S -114 KPX L w -133 KPX L W -139 KPX M A -50 KPX M a -50 KPX M i 38 KPX N A -114 KPX N a -101 KPX O y -38 KPX O Y -44 KPX O a -76 KPX O A -76 KPX O x -76 KPX O X -76 KPX O W -114 KPX O t -139 KPX O T -178 KPX P hyphen -101 KPX P period -126 KPX P comma -139 KPX P t -44 KPX P T -95 KPX P Lslash -177 KPX P lslash -177 KPX P A -166 KPX P a -177 KPX R Y -69 KPX R y -63 KPX R S -101 KPX R G -50 KPX R t -139 KPX R T -152 KPX R V -10 KPX R W -73 KPX S E 25 KPX S e 19 KPX S S -57 KPX S t -88 KPX S T -31 KPX T lslash -190 KPX T Lslash -229 KPX T U -57 KPX T u -69 KPX T h -114 KPX T H -76 KPX T hyphen -146 KPX T period -126 KPX T comma -126 KPX T oacute -146 KPX T Oacute -101 KPX T s -139 KPX T S -126 KPX T o -101 KPX T O -69 KPX T A -250 KPX T a -250 KPX U t -38 KPX U T -31 KPX U X -63 KPX V Odieresis -94 KPX V odieresis -109 KPX V o -95 KPX V O -76 KPX V hyphen -101 KPX V period -120 KPX V comma -120 KPX V I -50 KPX V i -88 KPX V a -156 KPX V A -131 KPX W Odieresis -87 KPX W odieresis -103 KPX W lslash -229 KPX W Lslash -248 KPX W H -126 KPX W h -146 KPX W hyphen -114 KPX W period -159 KPX W comma -177 KPX W s -159 KPX W S -126 KPX W i -88 KPX W I -44 KPX W oacute -152 KPX W Oacute -178 KPX W o -133 KPX W O -107 KPX W Adieresis -152 KPX W adieresis -131 KPX W aogonek -166 KPX W Aogonek -166 KPX W a -219 KPX W A -194 KPX X hyphen -101 KPX Y O -44 KPX Y o -88 KPX Y Lslash -152 KPX Y S -126 KPX Y hyphen -95 KPX Y period -114 KPX Y comma -114 KPX Y a -208 KPX Y A -187 KPX Z y -57 KPX Z Y -50 KPX Z lslash -88 KPX Z Lslash -82 KPX Z i -25 KPX Z I -31 KPX Z e -31 KPX Z b -38 KPX Z B -38 KPX Z hyphen -101 KPX a c -63 KPX a m -38 KPX a h -57 KPX a hyphen -88 KPX a s -101 KPX a y -145 KPX a t -166 KPX a v -20 KPX a w -107 KPX c s -57 KPX c a -50 KPX d z -44 KPX d a -73 KPX e s -38 KPX f t -63 KPX f hyphen -76 KPX f period -120 KPX f comma -126 KPX f a -208 KPX h a -50 KPX k o -31 KPX k s -50 KPX k g -31 KPX k c -76 KPX l t -139 KPX l y -76 KPX l i -38 KPX l hyphen -76 KPX l s -63 KPX l w -95 KPX m a -44 KPX m i 31 KPX n a -101 KPX o y -31 KPX o a -76 KPX o x -69 KPX o w -95 KPX o t -152 KPX p hyphen -50 KPX p period -107 KPX p comma -101 KPX p t -95 KPX p lslash -145 KPX p a -145 KPX r y -76 KPX r s -88 KPX r g -50 KPX r t -165 KPX r v -20 KPX r w -73 KPX s c -25 KPX s s -50 KPX s t -38 KPX t lslash -159 KPX t u -57 KPX t h -82 KPX t hyphen -107 KPX t period -126 KPX t comma -126 KPX t oacute -101 KPX t s -101 KPX t o -88 KPX t a -218 KPX u t -38 KPX u x -50 KPX v odieresis -83 KPX v o -69 KPX v hyphen -88 KPX v period -88 KPX v comma -101 KPX v i -50 KPX v a -125 KPX w odieresis -20 KPX w lslash -146 KPX w h -50 KPX w hyphen -57 KPX w period -95 KPX w comma -101 KPX w s -44 KPX w i 6 KPX w oacute -76 KPX w o -44 KPX w adieresis -111 KPX w aogonek -152 KPX w a -166 KPX x hyphen -101 KPX y o -63 KPX y lslash -126 KPX y s -101 KPX y hyphen -82 KPX y period -95 KPX y comma -101 KPX y a -177 KPX z y -95 KPX z lslash -120 KPX z i -69 KPX z e -50 KPX z b -76 KPX z hyphen -177 KPX Oacute T -139 KPX Oacute W -88 KPX germandbls t -95 KPX germandbls T -152 KPX oacute t -114 KPX oacute w -76 KPX Aogonek W -101 KPX aogonek w -88 KPX Lslash Y -76 KPX Lslash y -38 KPX Lslash T -101 KPX Lslash W -156 KPX lslash y -50 KPX lslash t -101 KPX lslash w -187 EndKernPairs EndKernData EndFontMetrics ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1691062243.0 reportlab-4.1.0/src/reportlab/fonts/DarkGardenMK.pfb0000664000175000017500000023372014462707743021764 0ustar00rptlabrptlab%!PS-AdobeFont-1.0: DarkGardenMK 1.1 %%Title: DarkGardenMK %Version: 1.1 %%CreationDate: Wed Sep 10 17:07:49 2008 %%Creator: jonas,,, %Copyright: Copyright (C) 1999, 2000, 2004 Michal Kosmulski %Copyright: %Copyright: %Copyright: This font is free software; you can redistribute it and/or %Copyright: modify %Copyright: it under the terms of the GNU General Public License as %Copyright: published by %Copyright: the Free Software Foundation; either version 2 of the %Copyright: License, or %Copyright: (at your option) any later version. %Copyright: %Copyright: This font is distributed in the hope that it will be %Copyright: useful, %Copyright: but WITHOUT ANY WARRANTY; without even the implied warranty %Copyright: of %Copyright: MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See %Copyright: the %Copyright: GNU General Public License for more details. %Copyright: %Copyright: You should have received a copy of the GNU General Public %Copyright: License %Copyright: along with this font; if not, write to the Free Software %Copyright: Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. %Copyright: %Copyright: As a special exception, if you create a document which uses %Copyright: this font, and embed this font or unaltered portions of %Copyright: this font into %Copyright: the document, this font does not by itself cause the %Copyright: resulting %Copyright: document to be covered by the GNU General Public License. %Copyright: This %Copyright: exception does not however invalidate any other reasons why %Copyright: the %Copyright: document might be covered by the GNU General Public %Copyright: License. If you %Copyright: modify this font, you may extend this exception to your %Copyright: version of the %Copyright: font, but you are not obligated to do so. If you do not %Copyright: wish to do so, %Copyright: delete this exception statement from your version. % Generated by FontForge 20071110 (http://fontforge.sf.net/) %%EndComments FontDirectory/DarkGardenMK known{/DarkGardenMK findfont dup/UniqueID known{dup /UniqueID get 4242151 eq exch/FontType get 1 eq and}{pop false}ifelse {save true}{false}ifelse}{false}ifelse 11 dict begin /FontType 1 def /FontMatrix [0.000488281 0 0 0.000488281 0 0 ]readonly def /FontName /DarkGardenMK def /FontBBox {-23 -677 1915 2296 }readonly def /UniqueID 4242151 def /PaintType 0 def /FontInfo 10 dict dup begin /version (1.1) readonly def /Notice (Copyright \050C\051 1999, 2000, 2004 Michal Kosmulski \012\012\012This font is free software; you can redistribute it and/or modify\012it under the terms of the GNU General Public License as published by\012the Free Software Foundation; either version 2 of the License, or\012\050at your option\051 any later version.\012\012This font is distributed in the hope that it will be useful,\012but WITHOUT ANY WARRANTY; without even the implied warranty of\012MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\012GNU General Public License for more details.\012\012You should have received a copy of the GNU General Public License\012along with this font; if not, write to the Free Software\012Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.\012\012As a special exception, if you create a document which uses\012this font, and embed this font or unaltered portions of this font into\012the document, this font does not by itself cause the resulting\012document to be covered by the GNU General Public License. This\012exception does not however invalidate any other reasons why the\012document might be covered by the GNU General Public License. If you\012modify this font, you may extend this exception to your version of the\012font, but you are not obligated to do so. If you do not wish to do so,\012delete this exception statement from your version.\012) readonly def % Copyright (C) 1999, 2000, 2004 Michal Kosmulski % % % This font is free software; you can redistribute it and/or modify % it under the terms of the GNU General Public License as published by % the Free Software Foundation; either version 2 of the License, or % (at your option) any later version. % % This font 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 General Public License for more details. % % You should have received a copy of the GNU General Public License % along with this font; if not, write to the Free Software % Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. % % As a special exception, if you create a document which uses % this font, and embed this font or unaltered portions of this font into % the document, this font does not by itself cause the resulting % document to be covered by the GNU General Public License. This % exception does not however invalidate any other reasons why the % document might be covered by the GNU General Public License. If you % modify this font, you may extend this exception to your version of the % font, but you are not obligated to do so. If you do not wish to do so, % delete this exception statement from your version. /FullName (Dark Garden) readonly def /FamilyName (Dark Garden) readonly def /Weight (Medium) readonly def /FSType 0 def /ItalicAngle 0 def /isFixedPitch false def /UnderlinePosition -420 def /UnderlineThickness 80 def end readonly def /Encoding 256 array 0 1 255 { 1 index exch /.notdef put} for dup 1/glyph1 put dup 2/glyph2 put dup 32/space put dup 44/comma put dup 45/hyphen put dup 46/period put dup 58/colon put dup 59/semicolon put dup 65/A put dup 66/B put dup 67/C put dup 68/D put dup 69/E put dup 70/F put dup 71/G put dup 72/H put dup 73/I put dup 74/J put dup 75/K put dup 76/L put dup 77/M put dup 78/N put dup 79/O put dup 80/P put dup 81/Q put dup 82/R put dup 83/S put dup 84/T put dup 85/U put dup 86/V put dup 87/W put dup 88/X put dup 89/Y put dup 90/Z put dup 97/a put dup 98/b put dup 99/c put dup 100/d put dup 101/e put dup 102/f put dup 103/g put dup 104/h put dup 105/i put dup 106/j put dup 107/k put dup 108/l put dup 109/m put dup 110/n put dup 111/o put dup 112/p put dup 113/q put dup 114/r put dup 115/s put dup 116/t put dup 117/u put dup 118/v put dup 119/w put dup 120/x put dup 121/y put dup 122/z put dup 196/Adieresis put dup 211/Oacute put dup 214/Odieresis put dup 220/Udieresis put dup 223/germandbls put dup 228/adieresis put dup 243/oacute put dup 246/odieresis put dup 252/udieresis put readonly def currentdict end currentfile eexec t?clZP'0*Zc2NQS607)JVۑ\Jiuf hhTs/υZ8^R @ qk/Ʊk P2Cו!{Ys.BQLBz[$ ,sh騏6O!B|ZSO ۏo$n{ЧL򞻥hsGd/W YNZ S$ v D|!T/Pf#"v"jMh_ d'orb27orbJ0F" ' .d!|J5:\i3]0f:|~)pw!#gd>j:ܒC us7c}'%ۿb4reS w?6500qFg&!Gn.=% amz-bۍe+? [w?{8R t1iUƫT7FB;zo\icWwa㸶v[y}`g|oB&/sQPL/Ny.r?12WϠ[D>x"2 wtjMrg7V |G۾_20[L]wA`;FU3E6HMA=Lq sȌwUnGㅮp9nPJ)0cHQb;Oh5@t/m Bw(Q`s }o kJ?_6`"K(oU ?=z `{FTNkD}GJGA1cj>iM@b y VpÜ ZFuݧyBGPHDuYoŬ=7'Aq(ɞ>p=6@1ymx;2݂*T+@6%sj e Φ)e^H~d!0B{-k;ߏ^W.̃" ҡ%rsD=ly)2VX;gbִb\s}w'qWO$HSjk{sXAܛfsERqaAIߓI3">Lڧ ޤ gx{c,P{>`i^z0gKW-;#9*9,HĄ9vƀӖ9Cbut0զ}#*؜܉>ODqnMi*o;gLX#hݺYB>6:3&&"͢X#|: ˺1̖E>8kZ bHZamX!(rb'ّ$nFzzxC cUxӟ{.r3]Zv&g0|d땫jAU"nұLF =k= :n-Odj,23q[OjW{n; >t5,yqWQ4]` T 4~g!{цsn8JPF.T(`izUbKO Ĝ;+ zD@AKxJk-^A/Y"`VIl"*kϲ:McK~TZ?Gc9.92tj\Sz>:߻~LƲw0r6E%{# и`t`KuH)09S{"o;Jԛ#V&2kD%!;]hYJ6\! ]Y3}2Hs| #nE#$i ɳ/4QG(QN6d?&nS$U7 %g9S1]+Ut DImdt;1$L7d:Yr=,=%NTʹDP4]6; @mUҵax.w͚;=Om m1wT&Fc _ tNيݜ (gpt;qX<-4( n  ~!'f@SԳƧv}ɝ~`}DtFsx/8eOC`e@%?W^IHQ]lh?ƍk$0&X)iXc߁8y]91E=4)ML/ Wdd=K"+0i!f)<7j$0 6$U ӏyu@މjCq>Ci%eM+`#VwsNK&g NfNFY}iH"&#GUj[I- =Oߍ5}~Y@rfSEgHLdp*~0˲xB%a/e CzQt/B6Ct;1+KZHe"Y?~ΰSFDD?^uGK|Rf3_o=K%RB|/]fV >9l; ]ܽxy<XImXVciϹ ly=[}L߃%xa j9 v|V2*'pf 6ߧwUpMdݱdNoVB?H/3_j ɐo;@lvW1.(r4{kL$BrDٗ2J깙EձhzirDqA L_e= )@ބ|I@͆s]j7 %R̴h[7_зm|&uuKrRr;nٽzp1sb;RtoJi.~Yy'Tne ̊Qy>k~53EX4ЌQOد<:f`y%D)\LG/hۙ$,SHݰ:لJ Tt`/5=~Y'ʸ%퐕@ CEP8]Hʦ=0"D f} $S5ųYԦBfj m;,W(>@&} #%Mp-e?u^v^8)WOX|R9uAWQ%'ˢ xr*~7I-u";[츘א>WaҞhW `Q>'bO$dH :-rݪi+ʢ6u?#~-: Yu!s`3]`&]9~i:+S2|㗎 %aSNVo#1Fm\B[ejЧ_UfRx:+#tu 2'iaYluB @(B s`Lމ7Ki șwX)_ƳK kԷl[_*.y|,Q&7ֻ&o`J";9 Fͣ~wqњl۬R`mȓ@(6A#y,DDA?Nة:.O)HFxCj7U[W| dJ#㮈َk1@_ &WcE|wXЩ(~F:ZZVXo% XPگa*a$4'ߕEP~惛(9,M)NP?Q;8MzptoNFеV$'ũ^CB_&:T?E,cݺr5:KR9#($>>-_( e|MEoLFtag % [#ܼþEڒ0R|gƻc)-qɯ6J6D'DSGK'+FYOx%dme5 <-d5.y OMl'ʆtbE %? qHhV)uJskfGLPC%K =X% y$EYtq#-܆JO|Df&KOkc|lU7/̽n!,pu75o6yYrÌELOs:fAdzQv]8C8QӑQ,;Xb,si@8y .nW)$(BxG7Vݒv`\87#*bsMx1 QJlK`E'l%uD EO:4`3 %^*a'!lt}G&#.z& _+ !=0F$SȠ'Guc6;6zNҍ/'EgQȷ?@;w( J}Ep=m)Ww!(!hy]}c<U.(p 6H@1n¹$ ,l#c} %{1V&t`@c#RCZq֥EI:Q%lGJz}I iQW9H""f~fiMw5PX>٤~.p3ǀR@Fa=@ Ȯj(7+:vX>JCx' אd6=EܪX_1UƆi>SjaZ: ћޒ5H`mn|ns?B1Q6;|¢;:oZeShpպ2ۂ` lQ Ox(k|'<{K҂ouIۙ2}DÂA|F:"鴲|OvELmBȳRRN>u^S=fYo!2mZ-Mo~#KGW|d O5-]g`CtrhϭzNHV) l÷II+]- GfX#豙g#zr'1:a-3vS X6M a=6^G/_)ai}0L FXnĚ`I0STF .7Uha()^c OMO^*-q+f*vKk' Qf֋!m I& }PEzgԥ!;UKfPUٗCDDIAF؞}1r. ? ۴}ѕY'}m Z04Iu"g䁗b ׃%-x Ň_ECQ7CU]΁)TTxX4y'J†˦j>1.멹-GJ_YeVh茽5hd:전%&e.QAL4w47RO73B9҂X*+7v:%idOF x-oG4gٸc`ce D O>ʴ^P}ߏC`ݠb c< mgi׵4|f Nv`TӢwJ-=Y[4Hdq)'pVH~N$!T*e֚:.]?"Y0pY)za*ws:"kDN;zm/yE dSg)};?K`Vh47 gR0}5ɘ&D/u#F@!74Jm FMTkga,lē;^vX~?d{k,S,>RATw{E R3C=Bx/CUó MX*\_(HMY! M` u_d>l,CJWμ [ (v ʝv 3K,F&[CpU(Ua9.7\YY z38|P{+b<9p V{xi 5'/2]k a r6 V{.PLA:#M / k<4Z7S˚,&1ߥ|z .hʋ2b J>ƏQ%B=`JRgTFgo Qs -b_dD-LJ䠊KKw P Y)FVnͼm'Ȍ#gg"AxZ ̭\OXL0K0P9\D#L<`c''nMI7nY6cMl__N Tc(EYmc_B/7`V7^`|kzۚ}ۄR;}! 6\= Wuqu? 8idUR3#W!~Jq*u%}ȋUCe˺wN!L,G#8'6aއRA*) Vn٫{W( ?AR&)rJ?'Ws3ۏ.-Ś ך-.o^d;[{Гs\qFZ91O( ]. OEp"vvŧЍ~!*#d"7]au8Z`6 K,x3=Buym5K>ދDMg d !d)o;Ԗ^d]m7Ow4:iA#칋1φAT*v~]N]i4 Bђ-E% C|˩4}QddƢ;qpJFˉ7;^sj2 <=K%ɅJ \K!KZ:K!,ic\8WkQ'Yj'#b4w?L5i^%l_ kB֖X&]>F; dxrKR{@{5=(yCT 9LUccdMh?ݘGme>3kQ]Z.Yo/%1Ԃ٘req\S^¥]fW(kFm!Vw ltsr0*ʰiY/dy'ܸRpE%vGPӐ , }ߠRF5yy qPލ蘥!S#2sn.rZqs f%)=?=j9Jn]㈷u;5BՍt)R&v%&j>jNjO ]zc;5NzM=# ᫁$#mɟE/ea:D4o'S[W"=zxgj#tiAuW.Sd 9.E!v³k'ʓ;fPPBAn%I-U@={>(/qK|Ʃ(% ``dCQTnm(*c9ܼ.Y>#.P.-MBc&eN^^XP6ޭ]s˭GBc`15@u0%t Y!= shD΍FH ?94lHkI2 HycnqekT v=YzKSYo7u7!ԽZ uKI412j^~8(Yp[ ~Y͘9n, O| :Per35akc"?4"xJv/p=]-VEc kFg"u68 o#"0Dj C<| ybZr-% @Y(vն#vLZXj d2!vgTPfc .My)e@Uh WVڛXPyaqU%F(j 77ɲ423ѹtf! Y|Ob^*4<&E6Ytx؉f.)5Sp{Cd,hrs4ԟqB lb<*x S) /pR_v>otʸHec0A\NtܫÔ@Xi 'p";)J8,4v~SdZV>(}El7dB;Mh([ _rk~͏[[|)-#MP  &cvGߝv.MVjsEuQqҢEV&VQue$(us4.x d7^q]fE_Qoǩ4-e=%2[l=E*5|)\|Ëd_@Y0x1\RefTh7s@;_T^z#ցoyOc$@Pv+ ]D* *> B*cMUִ퐣&Xw5*ٜzHK3ȈW U52|O~n;15%3 ۉ-EHw |)M{ /]X(0&R y_ VmoFKdh+ k%fMr%ԙeD2+Zj[nbq{ <8f_ e]("W:B&nODkؔ}zF:2fȄﺿh_,( C7O|/zݵ_ҊE;f~0S4t u`˄}IGAPdq}^v#5\05/O"1e w|Tń H<9?p|ЎAR~?4C_%d-*m@C=HgCwL <_u o%}&^{[RBSX}9LN ^:ɇ6$ҢN7;+ep9f - w^ /izm8eJ@AR`S$ׂT=4b_qD4,~4*E~(Ky<>vw#@V$r\3ˡ}pp(TY+*=u6 j ,bn~[]]1LjF٭DؐBhuqlp€'|P {nc;dRJ-W3.ѻ"gc!@ jmx /'6Y5/ V=%dŲ7 tu ΖY::[”}Uc;BS7+Mk̋/#r |p=MC:ܡf'iHBnw Ih8铩W̲ګhT?Kѓ,b i EXkY\bXHx/*b9/DsB2('tV'jp.%}G1Vҧ (µo<:CJ\LexD]!zDCΓ&cAL^UƳtGV)[J"ōD/!kB<8 .T2tEؼK9Z^HNOAf/Pf{4\hE<TyeW@>Jſ,A!y39G)%ۺ|lÉpQ΂?y(/+䨐vm6Bb^qV?+8F~9?cnB I fՆg t Zm]1R#"7m OCD <Or?A(/HU0g`;^n<X9j&`cjΒNt۪:# Yf&-S64}y^έ @>K8"C5B GR p# y2%ST1)gpb_sH)体׫H߱"K gy*`d!h`.ŏ>B^O}|d"ET7$*AWJ4]%O~'jpB~ KL.}<[{8pGW6+,Fl{ 7f*njf`sB&L,-69ݻnX}^0́u2`ziL[(W*Q'In)i3lq}S+W!'4?=]0*+6;{ /,Mqޭ5x1tLD{3-Z~'?fmMqaR}dj҉@̈́6&hXם`yt2ԗr4L[ɍc+ *ߦ͹DO|#R6/[I~ŌWeerX^ɂ!5Gף_#bu=J! |"CHr0] MIN/(C0BJ540m˓gLei⫳Z{T"AukZR-OeTtCWZ$(v>YR_&PMhA+L4 PR\7{8z=kh;pe51!jebxw0;WA3'B\ҟ{$ànp3C2GHOR8oi; D]"7d0 8K5\o;_eH>vn>̈́Qx&uM)Xds s8W+d`TjSB^NGXҌZ戭sDOJ^)4yu_n|=rܭ-fdI*C[ DTk%)Kry7Zp!W쮁> 3;:ð(lu;\WKi]lx:v;&p)oY"Z6滙GVsJCY:AfPn @У7IGN:K^xِ%|2}tJ(R !,OGI>4x߃p*k.܃(&6ј;A%׏hL0&HfwVf JwR/a՘Yb0^Æ1wKRPbk4wH?l9;Hmd|BUǙYi MGq~xv*U$_35tiQwUMB#ۛ ,#hVVH>=D~\C;7+K2Z`V! $Ĺ25 kthD y˩Ma.JS>QM@COl' O>Io>*t~c<0)>/%djEr)slrc͙]޷\6Ϧ }QcNQh'F~3B CŸqF,=4P>M}(ZwH!PNr{#Жֹ+=zA {>LQ0qō@)/qUZ|~b?43c6\$] (7e7=L8&w)2w+4\"FF{ѱx{O7(b>~E/ďc7Zya CnpyzFe|ţ/!7Tɒ=z@2]C ZV^cx+@Ny&JΩg=XxBc"+Q6%:l Cy0rfO]*%ztܬX |;c*jV2\+a"yGD2I.WWT}X_ϔGd*u^Lt#t.( q ˹ +{,8; _I%@%K(^'tå*{_sIb^~IM Tf=6?ӨFy\b635 oFvakb!Gjd2eLSf̻L;Ve_WBh559FaݚV-nĨԨ^HOr-!Dc;6Zo:څn\;`bg~jT~5%/o)Ud2{pi`u,'ٔQFOo/y`+\ϱf}B*Ǭv= zy:ieCBs:8`C>zI2q8x[ fXBWX2 ̒I 5ۃyI.M}#–A Nx:5-# I̪@eiVv*e0ZkCR.k!>N) 4olW}qUO$l%侣z׃der7Z3 8|0157Peͥ%۱!ݜ!yMlU5S`3NCO!)D0QV~[cAb S2]nb}'8U 4`Mw)֋!]N?AbM\^^Ip4'raQښfE~8%O5 Ƶl^<Yz g3'Zxճ_7.S7r0I YPQ}CS I+9 i ʡ:z6@5hֹ!/\v}WQj"aakh $^1-T+pepjq!׹UGd_]@<2Gde0Lz>׍ [4r1gJ)84s# 66g#9_4 ZrfN\6Y>(jQ~uԕWAhzKbAvG^X#N6l!!~u8;dK6bi[޲ ~]|x=RSKNzb\^N"(w.P| ҙ2$8of+̀vkT  Q}fe O֑*Jyl AZ(ci5)z+|,jm`u;3BӊX #eVLJdI 9ڪrg5iK"D6Zn\BFE Q6D()KQaG[g\/&׳˰,!ơ0w ?UBƌK?'"NJF*26G"0ǹ̈́߹-.-O5Omm__hNaŪ*%)ǯv+ܱOj? EfovGjc!;s5ߏRy&XnaOUG"f>#U"(zF ^|em} bZ"SQ_gĉ.H#P'wU5Ee:z#<]QĉE\W Y@yd7e[$\ ڢ 'Kdy)l.?1Fq,5X!:Wڟ>@ e rptA,Y aQnEb9^N&Ô.A@ X w9`TK?Upu 춪,`IGؔ={Zvkzy۪ru*Jx5C:u3 5WMVt-j?Eln$ΗHF*|ɹ_a=6EK燩selw蜀U2iBs̓_x8ԽPbLG ;%*gkf9-]D㜔,cVMB{~cPR0Ke딬+E&= s=. 8;64h qEj)]zQi"~ܜׅ@\&5ʔR wYb'ĶE ^ρ h6ׁ=F5\oI#yZj|2is:$20@ElU@B'ҜΓZ[(4L͙*FX|d[{} e­Y:r ИΕ={a NU)rFCW.bUrsvDXYz۶ݾf5xuG-]7#f9A"_WUa 2mXjp \-+Zi5 p '=W!X2.ë$d?!i #Z(> WrT#saY8_. u,wKc`![-嵎9"᷹Ɔ? f)1:;.4TS!'J'FC=753WUp^:dӫ=LQ+ҷDu>}u1N2<TB[+OÃwMz/Oc_vy,cU Y&ZuU^Ԣ&u LN'Zx5s֑͋L%QsUfHܕc5@fZӽ6S5:5 $3vG ݕ~{ 1Kt_|־Lsc-3j 4@cdMBa$D/1}=)NHx"ϩp>@VO|txtaG3^MpY,Ӊ\gAnࠋٲVJ&??>epQ=beQ2+>}f 8akigjjLO&g)|OyFfޓ'1#O|ZeLJ\E}Q3kC2nIT inz/mbáj2pU\q~J[ۼMt׸dDIԭ*x^ܓoeӦ)|=Z.!N r,x% '!1J>k2>†Z23h`-0 ^C@9kBhY=_^RzbCqqt1QczGH6'9\.Gl}-\:W)h>?k&EH'y)?A*>%۵xФ|b7DYGnE ΅A;^ajGxOd_&.yIx60=`곽th|OhK&t<.xIh",q4tcj-rbOBwOBA\Mtbtf`}K1B)Ox9P T'fOb1w1Ų)AdW'naI+ǍҢy_mޥ֟ݮRYŕt$>YmAVCcWsݦV=zzC6ۅ~;C]DmB$q3k#}4% tރAtE N&LcvJ#x.mqr`?L " z$*XfI8@v' tMs+WOx|}طu~b.ډҕYmjҕ#NW&)'s)*lbz^F˫ p42b"cM邇Q ; :ݔ{ezhuVȬii5(j EPUju|Vxʗ]z{G>f·Dp[L( }:I1dEYoY*H&@Nܒ()T sAcɲjwݣp(Tt@.ᘚyH%٘2"3ѡ3ؽ/whь׈HOx!!}9ih jΈ}(fs"@P@$E)K>o Z f47HPF遤Y_\cUPI\8%b|Kg=QyB-6E 0\ &F0Ami7{7Rk80 uO5#=@H.hJ Jz&~\J垮lV{Pԥ*7qMd}Jjn~Bs haXB=*uy<\-gyfЈ/wU] !.Sk%oF#Y닥M{yiIw UJ1Cݨ׏nG7ٵ[V(IZ8Rv6d&iλ,8FN?3]%Lsޕg0K ~BT 76S~eȭ_݌"ONlS>&~NJ9)ZϓXf}Z ʿ1[P4GӲ&XRȚ's=z2*& {KRpOxƺתIZeE#/LV_P,z'UC':|t[rz̈́>1Ef}A=҄)M5; -%ok 7>tq*&@Ѹ`4>&Ji0X"᷵W ]DcwԪ i@(x|4~ڴ3?,wN("_UEn;y+Is,)O684JVKAiPK祓Sˈ)O|=L3M{QGo۸@Ÿ@k!/)l `|V) x@}Xyct<Q]{Y4#-\bۦFLMm/P'&5P -mmp78Y4`vp=ud?\}JH!O::U_6/q~Z%rETRC3IeI頒f,/]cx&eꈾw$KZ&.ɑ3k7^C&+֘*\%4sB*)F4 X@c7w*lvXzD\'z"2ޤ4$YmDf7iJɄ ᆞ5c%榰tz[4G0 bqtlT6"vO\;ABv4e3#|(lL3E/[-icBO hMH8<65ħ~{:k:"ᭈKɛ{X4ֲ* #k@&`IxK/n[iBLV}}WAW2P'D|+Üksvr$6ߎ su+gqu8ָLKwNg8@ζ9>{T4Hpry|9~4de֙8~F< r5VQ|E~d:6e HҭJKRc 7_mH`qUwpj%QQp !.ȧ3eq\}mz +hNN35g[(,|LsX i*rT#(=iJuEUA (apWRkvn8Iwl^UQ3R4%ƒj+8;}摗vY%Lv??+C,] zFtĉCy^<`CYrEM6ZB6Q=.7G\% t^Dw|2"kk`j O3q8̵HN}-{῝Nh LHOG^Ƶ.ti؟6יM+[!]j@4Ʃ[q-JO!h7Ѹ@!Z~)37(157L*a'JE Ь_%!]`b*Q"R `=uxPa%!x 1 e$)0Hee0p'l`۞|cRؐrcszU's݈M{a5- ›ViTZ"$1Ot ~O3+f:lcQ^_I"T #:5A 4V&t_&4wN}[ ?A\47YmǜP&qYCV g08^3t;+e!ٲZ|cІoMO+LP6\˧*)Tb^seOv?K}d7-ت Aj%[)1j9Ћ㟔4G=ŎS)%l fkF#:\/m;wB.Fd 8xKU+U(Ak">mʑkP+/[lٻ'ǐnJdZ4@Ļ[R}v`﭅Vx|ØKcܯzd`i'oܪ5}#ʏhRbl0žLJ+x9י囗xrl>2{W=렘 c#N q H)%թ#RVq7]R$ICP8IKSĕy-F/}Q8 >cXla%o1y#QQ,W:m,vFL0* p6k2-U׬|n8<Ɠ&#NnXNaW)![ TSn 3+\ q' 8`F2J些q gh %RiQ*3 =#œ:nEՒ3g֐m4?Jsj:J1#|krf .1͵T;jf8,,SaOv;Zq?/twe8Λj"@>#+E@6N\gCM0>B^p"fDܻdNK7ٛ@s.0A1}F/{JS!y6yݎy{ U03 =E5}^= PZ*S?m~Nf7~d+xv>f}bstDxE`=UY9Ao_jP5j%ex'|8Lh[uj)Bpnۨ,B׋z$#dտn}UhUVTe_ujkG' HQNz66fHQ{)(d@Ÿ%_0ⲿ%1HyO br.B8oZ+Ye!Q@c&iO-TvBv6LLKv|@+dރ0~ys@x\t!ʫ(g?)e|AF4kp1!wT]hÿU@CБm1P+|"%j҉pHHt. LG@ x:aQ#R.sjLq˟w4ьu)Wt0N;tV1T@`hPl+ .uL0_wѝ0@@=fn۵ģѦՀ@y-$[O+-Ei9~~kћiB{)(I5>LB\bȮw'>o.Dxg*G| :Dx |T'LS[He~G M6J̛Ϩ]"% q{N?\Q`$}ҀOv Vy2ob6 ALT d5)uE>9cG%O.}WnBgɯOP1)]KShΌ:7t? MϯΕ-C+w|is"γ/'-I(Oi4|+H0:^1h,1V)Dž(sZJ\iDA8K`711zby׸ aEy(ۑN+Z1"CEB S'{ӾEà^5JIr3r]'5=㏘>lTh~گl& .ԡ %gxd: [4N$=ыG w׼ߺl"f$z`?6#!pi%Ԅ=ڨ7{RĴfٝ*ࣇ -,2.Qsϭ~Rl]ʣnf\MHw!#5gWFMXGnhWz{+"G@j[Bw8n ZYP/ XcO^w`nnK-/˶ɓ=myQ) +F-wϦ y/E(.+amN1qKuiJrDȕ)*;2ԝ!Ph|N'1D w"A Տogv}B_pg:0O#[_qS9Na(B#sA+ԋx{XóV;Wvt=h6eo |Qd`pKL_GW߂Ca+AHXʓe_yoY4; 8yRuI;mDt4I%gF3FxlìシޞWZݢ)]E% w93%0T}]^8LݿhKȨωF/kC-..[a,K,$tOėՇD/z<[VK hl ,tC4wTRjueĈ{bf($kvoJCo qۀyS#Eٱdp>j瓾w?mߟ><a&1WFS?~>A~{iB>l[QuIl{wfv™ඐ]5Lf$xa GOڹ{bnkc-ծґb Fh k"o֌9)3,5.iib柕0iF7iwOr%k{uRљj;r1Gpdƃ+P|O3μSBSC71An-|wũ ";eٚ HM(P/D7tq|E0EΣ0@qne73Ss0gJy; ArA$@/O"ei B~vH] >h.K0ZБH;7@lW14}xJPx2nR~"ֽ>JE9qp9UIR0WfLvpD\@-M5Հ]g u =XEM+jBM`U`B=]P0.[rzD^ĒtGU RQ_vTKhs'7 AVLkM/(}ziQ(w ISad_*M4 иhR9S*!0.r}a 1>4uѬ%Wt?N? yzzu&BI5)sƺ=ӛ;1y_TϥueKP C"zM@ְ oA\9'͢bቊҀ_W;8>^L;#@]( Qӕ+%O4`1hORv0Y U&Dc91.qƄ %OF %N:rm:ȉ\z2NХs[pf$7)D) YN}84iΰ_ SZY* R}ဌ1 DEb $-uG2~i{v@|M6k[fN><ӫHV|46E֟%:T[gvU7gB##ch!4e{To젲X@)GeHZ5.-2/#/b%39X{ .o[:S?gI\"r/yNOWeSî}=gL0|nvx;ʹ{tylBwq;=8Niț)z Q~-Vni8|QG% \Vpeet8:c[tʴ/NhY@WT]D$RN< ]ڞ|:~mx*܊o{$\ڠ^#kug acFRtC4J@M;[|zGCpsX|h?i\JMz-{Iz#w-( }\ OVأ -`}3͚Gc F{Ŋ,mǴ/ cÖ\!`}Cb)F)<Ϸ?9t\׈& LЄ0}13&+ %W7"뤽=K[:6 P揽ex&Md更l(IK9 Yg^g&}P*ԞhNϢ/(rN꾀o3*jNib2yD_?'hg2F1iJtQɷ\%PsIydtDk_coay9Z 2~y3HiQ NP[P=QR{}Yk2Ѕ8Xj EI%;^[ּSm f^q", 0l*sG}Se j? +m=py!'0o5% К zKy5܀[LzK %퍢-n tPE8VQ&~߼TbHW m|pNڴm5p߄IARv,kSUtf*6Y4pyjىC5 {qǯخRI kzEkv0]^+`9OWUҪ'yȄ($?7*mnpmӁIe0zY8:P+M!r4էćj_>AxCW1qvn\vka;Q4fiJ 7aϝf=Ca"2+w֞.S'2!W9Qli*)-nKǿAjZV5 L{ Qe;'&&6Jf\*Ç q˘uDu Aw~ey s=kt;׈JN)ˉ$i9ڱb@rP7^șĥLj6#c1~Ă +e7wC}w:ӄq!ؑY-v5^{@ LBQP6n4Ñ^]m2bނZxWC\pzpVG)h$zPɈ4%~}a'KŻ ߶pAK {l@!>!//ͷ^lw:AUA$,쭮Q)kIw[w&,gA@w1 $^;xik6a4||5M@ z8ȃW 7$Q*9Ew4[eh HTޮyltm}:&s3/f&"SC j;vr Dj1~p\!o ).BR_cn@LE}1O ̦ I̋7)طW> fŒ5$5IO"IyIt׃:X'8&xўRAZ: ]cNu?nj'2~'Ikx.ȿ-@E{faq--CU/R(UmjyXQ1*IiBL~ZNc}Y 9r8#&G1~0: j(ۿ/t+cGB>>zQr<}T pf}iS yi}Ӯ-FRJAHLq1n̬\;DYHFP:iޮ#XM Fksȋn%f.[[Y娐( tDq'%A)O|?[K/kIUӸ{"eQ,Cv y/;_JOdv"|W^`쩥P07HJ 9X5f:fܞF ~ ?j1[=x13-^HOhvBF*G<+/0seW/#(&;cjU% ݫk.>AFio="q([b׆G˸ }Rwg eL]1fcW`˯L%+\י/Yk 'p"KmEPø ̑~`V5+YzXLA/ 14HS+,x}[}jx< 0e+6z^{=Zd9piꯦpһ1YA{@A#i~!6:=>sڑ|_;tx^WBָT}He)">ƥ}+Bjp6|~aXA9~ ]C$[`GO9^}ѰF̅ݰ$6KɍcC޴@pG6/*ɟOam{z_ގ_y A7 ZG$qSUfS`!l$ta׍~:~({2xDf\POӛy(EМhnURV EݓSQPPP0H,T~~C|֦kE2mQ=zrd ^qv|Sm2_2ȫ-&?wÇǬ-\dޣ-ǵrlbCsvIĩ]g0z{vw ~tJlITkVvKq}]* q!ܾaį7-ƍ\1V.*am,yaA !QD IG]<* ENeDprh|؉:Cގyߡ %Χ#b+/]cR0kOֆr=_>qܠfk3{j.H8Y"+>9Pk@VbSԥˁSd#D K>!Ct(6Fp\ `TyiG4D#]x@Fr?3\<=XZ~d [Gys EG4[x$Fف6᯺ 堮`EKuz3,='™G1s\SII#i{}; W'dD@(9\]OgхɉMDld&;^D T dDZ SLMa ο޾~i"ԫ+(5fD]TO_\ vș3`ۘ]M"vb`A cLd:I ϝز t ?4ͻZ/EZ꺖]nկT<ٜaV-'2 ${Y:$>ToFHͱ1fs)/rK@̺@A?"P\EJض`6TbBsf{ * L)´ vpU>F}?+$ם|m߁G+ߜϙaPoLAjZ;=,2pF_rx2śO3Xr$T8|v]nn?.cmך*zbRnkK}́:fr4.4C׌!"p|- |0*BGvHC4<σ\OS,qy` hciګ_%lr$suWV_+:T}]dCT8ғxYI^1Dghh!vב~ŸS156 :$M<0aR"]:b1"I/*K3QTENyec߫s[?۲PľmZY:{·3_}q6vd~kfM3Bn8+hRUII<)uIE$IYp)gʋLM!i o|Exs&2&cχH[I)PYY%KjhQ7Nx AUQ8ryucώ 7ExӧU;$ՂTz]>%Vd;jx2/rFQ>KtޥdCQõ 1ۋg }}z_ r_L|`^WY9:aqj\dSTpb-*YA0jr.׈11mQ5i9=.i^YY}06g5^oOܘѹquc w})* AbxJ_Ɛ~"E׈M'9tZaڄo 5' 9ɠŐ!"SLG_-_}f*V@ S]K]0Ny+0aWeuk>z} 1YCyo,,|1FVٹ%),G h2{Ms{:L]}z(T2cJYoQn[\>]Ʃ˼[ɫ^҆P%g ` $t\JJõa6WkWӃbk' ne g ^ 1Sp̻Y4vF2]BYSU1XxNycP=tY̾`Dė8xo@fq$ɢym{&6?K09tp.4G:UP>$t3.tSY[08o?nS$^$?d'np,oU$v}4ј9 IO8]k] (VN|P蚄4,d3 rSs/ 8tɪf\z`PZ\n#)>? ws\8[CdivӺ,[ٻWSu7,늷?nI`Yj<2nΰP 5>VJm=qF3IZZfN.g/C /wazqfDO9i~fΘ2qr9k=G dA!g tTJ DY8|ՌFpAwk܅.}%!$3hÖ}HbN'NTD[}.$Yl}%޾O_tO#8$!EjC.ɮrkX$A'vqF 7x8tۊ3'mYkM[hp17}tja1v@?p;2yp?1j~,'SWXgg8HkˑϊI;nt[s\Bx0Hl>}s?<6L?1Ggs{>'`yոt&Ԥ@f$?튴Yu4FD#瞏ފ5?VQP.\gkL_CGL60}Uq67$yl3U:\L3+Aߐ>;mh;$%XP"tȉ)uIo biHϫJWՅ=[OOw>{$oug645i{HY%]{R̐~.ɀFfyHCB:+m)+S2%vک:n`$/ o(/4g b5/c BluȡMvq5ZpCl1Tfy}= 2''YF gz!+{`FFfHVhgO! у F%ݜY3E`/xh!*04}E*n+W6\Dڎ< r@P݇AA?&3!ZqԎI[.@0|$ Σ$Q\YviNzdV|kܺ,z2 5 E$ܪ.HХ5rV'0PqGmD>8xy'\F啗2xrTŒeel*#ld"a"o-7Yݏ>XQSSD)ak፻]"}7bWOM! ڧn Y`(u?=;ZHko(YW@&U P)E^[?az5{GElŎ#`C&k."^*a[bNtUCY%1T-j M{eg^%ETwS4Y+DȭlLv цL<IJҙ/t+hssB_(쎵uثqFd|2u5'O7e"UW0=~]#)\ͳndHwҘ}IӘ6K}ƻmOZհrs=@:,_I _ ٵj7JbLcq1i `Pog΁6't}2UQw`!.DV9V4Ϙl.$'[3*/,k/F(1RZɈVD1_ F>"/\n$R& u 3+ZTXl(-fϦhZFF9Ň9 2,:@w-q7}#g:pQyfr`Txn ]#xSі+LefkZCGiedLEo#5ץ7m+ơyJ]Ap/z%D-`JPP:Vp>O m?{S_E{J@<2 }q)Ҵ̍8\ՑYu?|f* }ʙCqnP\VL]IאH< @ggIuC꺂T ?T*X;:b#.՗0HW$Zt_ 0 M8D"A7ΦwV%ɠItڒRK`6Ng7˜@ՠ9KWO X w]Uoˤ>^#w8!{8 p XohPvτ3DRKk*W\B/_ Er0{zl >k9?~?f,;6~=V (N~1JӇNݙ>z&~wQ佀O$RU5z3s\;3 >4lm?WDF@Gv= Ff$[2 j-9$j.D QNjcŴ3}2rLm/E+%YQt=d~e CwAX$}/N|%ϝz_2t'3z^Ɉ5Pl|sL,')'eHlˋ3 5H0_ pT-aڞ+Tr%m +@ިxRz6ܲ@cl]5IEе1(O U,c7鿯0Q>?]@=(y"|gv=K!m_'BmQsnRd P.2Y`Isv7֮U@m:t|ԃ| qډ=,^ 拴js7xU]; ̨[SB3"bJMi7.^h)uatJSf4Ma+<atF:;3J:.N4Njޘ,܊]:c/RT0Xt] 5tRJo@ނވiWUqBlHsur؟N5MA9**xs$#U M8h D-Ȯ"<-}W]Us Ma`Lz޵C-cO7*n5--(Qrx=L5u4*FчJU Ձ; qBPI.LF֋-FB1Ks^omm8 -tp4/g$[w ?G`cRbWI 39g|Q:c&YۊT܄mdC~/:TeIsjiW s")[SSI gk$3ΥL0=+V=6UVDٴ3| ݣ0vER9W =uoQ}X 'ItETqKӑ[؆˔V"?WcИ.u ut=S9F4S#.MȞ(tjBd]]g.c|@kIZ'k<#!=3Lyv*X܀!G()Qv} "C]tZΎQoǢe[ˬeB7-ks2K`Hkfb^}y]Jȩ2tSOd>T5n3͖wor/ZCdiR*TBp3'ű}cżv^ddeux%X\op.T23{Ӡ-FmX5QҞd=up"Cu˕i*򿫴RHc@S)#9XN{@tYEqs#ӓowdMDPfIePo1 Խ/6,̠ JC }Hfv|,(>rĿ=l}RS]Ba&yY턽ΐ+S~j—P: .t<㢩!g]uvJM>E*b%S{v hTqh;տ!'c]ƒh(zE*ZFR5Ft1ND#+$jq cp4FT~ɛ苦jӨ(uCL<׋i#ܨ[J.MާLeh_ɜV> TVIĴFaڬ2ww&Tf#n#-Ng'*dxs{㼌nw H`[" $;QD@+uL]|Q1ھz̭h.i `d2ȩV m_]5 ͻNqRՠe(/)@{e R;8`ߐ2,_I+eE-9 #DtGA˅~*~]FKX|9Ư;PNѡJOÄzINfwZ&,vv n),^G~zSWu*E xDŽDE2"sdMFbF)!L&,7h {@W\D*{}%@PX3`cOdsg&/}Lw^{ƒ5ʄU}sGuuhOduthoqS; `hkNGr f&ZxA’=U,ZN(2ܓE-ip2F!?2&.7ᴨZq_;30uP}秊qXkK8)O,H^$ /+%DHD+a%ܭ}vNʟ7i+J]cIjKE$Hg `^ed[p-Qyr4(nj5e-E^8p$E^wX)є@9_lc'OB}r47 :5ܰ$qKiS hv$΢"r Exy8{gmKvҀrqSp4BDRc 9-0""5sI{K n0Mgݢ$m~I~9;<me =>X|0vT·wi>5q# |xj|`G׊{؜\O"P ː* 2%D&dDQ5p, 36XL{"D~ǀ:\퓘R) [1E(k{QyDȩqr(ٶ@n^AP.T^$nao|:P'n4ܔ:q7u'"4di~{2!{j7!3ln/x*qFPJ4iXjJylnʤOnfݶbvI8xzsk;،[=\j,ޞa4+JF'S)*Pha;F"(7U v87խṱ*2Բ l0;ݖxyٍ26˾߈bvѪBaF$O|P[e\b0d؍#&o=A 8I X@..Ǒd. .7Jl^ '6A"=Nw0t{|mkQ+ FPwAb\]_Cr.H8i {n?:kPvS:MS粢19Qkzf_JA|{ 3J[p7L%lཽ%"jc; mg!KO"q{6)r5"6q*蝚#v7Rr:fD)SOUv׾ke{!-7]7!ā΂51 іٜu:zS^ï1Q0}A&VKm#:p`Ő/̨ \=TJr6 U&Vڞ/j](u6.162gc1 +ԕEuTxԮ!ʵBd M\Sf %{RGS\αWRcN>)|4:_IN^,)`ox#pJYfXlOzhk]U8nB]O1.BFYNA  &*C̩df3?PlA`dTnLC=&IXKڋf)@mZ>ạ/OW'wZ:N=':cG vޒ[Ge='ҶL(N<ߌtU{289: Ƨ;Y L% E1sEGOɿu:ph Q6~Oh0ly1[P MUN"c 7A iU(4CZMfrbRn]^U*8 YBLZE i )PwL-)eBJuEgX ѫS-ta=ym(b7,e,ũ$ w;V?ٔӻX$&#R y C3TR1pU%GŒ+`%D84/$xŘPSZG4%M~s\ ` *pCC˧?ؿtXbfAZ*{UE1j.LFp]ј@ tVO2^#~,z7Fk f ^` 2;+dsVŘ֮knu=)|.4D] Ġ{͖SXEV-ae6>,ggJPt,f+pB+1D5_OQ@|ZIZ҆z{Ajǣ2967 Nc(z]̔'K}YiS9y&Ak L̅SOoCiILm`ZmO<-N sC4]8Z6/=K^Ǿ;fl<>k81Ko}|/ᒛ9 wCqt;$l\+ 2@.SrE̝ S<]tzkńz/5r'\=sϾW2 fK}%n/pPaZUC4vR-(8B$/9NYʭ}7&JҋB|YJ"_#vR_(6K']:wMt+Vk#f*]VjkcU{l5@Ij q-mwUGjeW4KэS& y-(6 8x|i-%LBƊLGȰx֍TњQm@ݭ 4hm󶈖M\Ujܟ=6]۟P:'WCjJO>^ma仑\kh%s\0U+!H#\&'5AeJs.jmzsooڶ?ՙ(;vx.?/c4#AL A_P0oLض6#:'U+-R,,BIJ#=9(Ь{KIS4Ⱦ]L!N!SiVxc_uϖsP1e S/U`t"%-:[,=kF׷$EN@@`EHfzb{&`ҁz*L G>,$LYܣQDOVʠxOVW$tԖ![ˋܳl=^?7 L (QEz{%_c5h<5 nY1.1?3ѵ %'i31*6\[0|SzrEK#kΰ÷xJ3(b- 5J"6'.yjlLq'ro:IpI@RTai-m+HٕFJx`5 EF^!N`MP|5CHTKru% %' uY8xq029*A/D޽|^[( S V}#7L(.B Vloc`t%{72k*}`9ChM #0a-@LY[] I1K_ qt"J-O D5];?DIBE˨V7b[l,,b-۴ fr(Hc D6qc+RoXή/3M.pUTuGמ2 ̥&iv1N5OʿAyJPw5s`]3$G,?:pޕ^-^LӘ 4w'^6v@ϲ%f8 ޼aiy7c4[Ȁ:;y5Q[`Lu "wf~9zOJ:㝑Zry4Chd b`ފ Qޭsop)]pi]}Y0td5Q$kzj>N˴ݭ6özš}^YG|I /bMȇQ|[;Avo2D-˜8l<+9DWhQdjVQ||F =.cAlsx)m h.ܚF]1k_Di{_NchvUQ{WI?BOip~DB=P('=oM,κ27#op3!lfRs[@H8 `_u\{߀mU!~gNA gVR,( `̋4,Ȭ<ށX9Irn+4DpP1v[Hpݍ>3RC!!LؽoPXX3'CEzWUF,I]( t^zO\[Rh,IAeOF/ s5loPI"E*s+v;م'Qt#"8(jC@΋O YzEB,W"`]BU0"@G]1FxgX @:E@Bg\fs7A`f^T?"\Gi4&]ln!'}oS4w"ATnT9]QYFtfZWyϔχSj~Wwb1 g]Ďz 2d/@^ Z,(2zF [ .ߜMe!_U3 ؍`TJDdGH@p6I PN{ue _trʇ<@;.Ѷb'>殤`1 F.ygɆkhQgVw#N<_U})\oe ~XG֯7]1gC@ xjv. k/>a= }WxڗN <)pD;*t~D1al0DHpV% @LLF?LJCE,uJ$6?.,5~X=ZBk~5V+k5: ?`يb5~߀iL{M,Ajw= 2h25’n&Q] fw㪍&^55s<&pٵ$. NょZP:ly2 C?E01ҵ _|@%|vIҥJIz,G,> H~[|f`wi".yd=k;:VCmuuoN+{)13>щ3?* ы)$b܅[;՗q-VTEn)+8{U8K3h)"#K3:fe&/OhRk&jS&=d7ڤ5E t{5"oX&Qx,7wsz|SŏnBc)A#^[o [&ZAF]Vo *e|󁊮QTELDв??whBNf=`ëj>!oP5M[ԃ\yyw2E8 VW(zLgxɚ{sZ,rR [h7%fޭsr쒪( M`hh!`< ?1Tu=YF3ow,* y2.6/ 癔zcs/Ԝr>]G3`w&[xuG;.KFA}+>]] zX y^'z:t+E VUaZ<D/*@99g1چa'ЦIil.3U6J NKS9ehhЎK8ᴌׅv OShXs`bZ KbO܄Bو^Ng#4`Ʃ&X(plXU@o4w;?h{ P6R U=,4gJߺcAHʞ`tq:`ăo*9[>R@Teh[y^:Qy@H88+V总%aO!%*śM @6 r-7['="M6!ޯL9h!E Bɫp]xU뱡"ǒN 㜁&Lʬ#INHz݃B^L_sjX;ƍy ֖ßna NgDv"]7+tWNnWQüYrIB\֡Mpl7zWS9(q•n7X crhrf!R)כ` 1#[ow)DN>Yr7/c~]AjO:pLј*NWPEͨ𹉇NIK_/}_O[Sm٨\G65SA?(@Gf߅W+ڝ{l9Rbj4)8w+) ztؤ)#:+_=e 39*CG\tf'T2J[MBn@ᅦp!q}loKvcI7 9~CɊL t(2,=jgGOZMۘnl80.ی^m/D<"%E 󬂑'ʗorTXРF%2t0^8b\ ^W qg%xƓvᇨvafPc ~AVR5{yRKIY+ߍUہ2gO&Ͼ94l"Z>o0ܦ4MI?rT٥ځXcɰWT$DW _ձz?jUT OIպp lef?x IMyS%911͗BMp < ݀h**,AvȯC|$dfٻsXp;N!k^|Rʹ\H-a|sq~\4$[@)QZZy `Kě홷Aݥ;Bpdm>|1kbNpާ61xFCqA岖qeP&e潚ٜ5xG;?6HgE,sHYH`{ZѰ/J\\(.xJD32^3Go4Hp!w*7gA}PZL(S6)^w!m9,펋,u0dkQ }߯[NEGUrƭ< PIZ|0V,ԫ ^` y;*%=B'\%&؉eӣ(p2Rsy,A1k sqR"F. Vhbl7_qh4PAI47fA# ^Lytt⼈%ݢNMhi!ujsm%w$=|eBxlȰEhz|SR Qݿ7k U^?LTYc( obmȍ Ẻm5ԇ[.MqCOBnQZӂ'?Ҕn{=a >U7m}n{:}ݼpW;HI7KŦM2\ ))lJ\XڻmAj"bX+nq8I f<6\ lIȱꘔn6ҵ oaY=WGW#[wyb *'vB8:'9wmT^X29Ev9~f+-j@ PS(ӧo_? sxmi|Z19 _kӊ!RtFVNAC)#{XCCdtfWJ5rre0n'ɪZmài/87JxZUΐctEcWWQc@ؗsLvO0p0:4MO~=Vto@=黙yZ!DF^ W#N,KN'# v.b4`m7Hq xx0e],{' 6-CKhOXǛu.YXFxyǯCO8sR"d |9޳yMiϨ/Z27Ns;ڊ /ĵ2$aJE^iZkMrk K MQ M.g+A Iia#_L{lD(Bb{Knnf`@CpZ}xHP2"#҄\H$T sSZEŶ֬'a2"=2Eqkb kҡ|'3aբTHbcmş*0:[QŞ4ahLX~6#{:Y%S^ F =(41,ƩL胑JK=ry,:a(5楷rl+E-~Lj~+4^U[/I3 1;+>MiH$!f惓Qgk~!/j5 `T)*X* U@KtQBjQ+DyMlg 4oD3"0 *NՔ2-j-ڪr#, CQof?׶GNEyu?Y Dj"ORX W}ɂu;$gn>v2Z&̀255:9=4mpA#ZL1ވeɚYby[=pmzhzZtdlÚZ!w3DF㹚?9ںI] ,?[u= v`C'}mcf&t?S`KKrT*}hDk-#%1Y{tR>ù<S lIi of݊K) R^L{ο-ї{ԡL-bͱ_v6bO1L\!OCZEBR O @"b˰ uY3@4 ap3 lVMrnU&PŪtβ@_ bz`g?D7}/o1T \KBꐚ< 8:c(M(HY4| >e7CvFotC=~Wk/G;@yuԺJL HU8 / "߅$>:@yt{%U*^uf͓z[ZZm| }<|"7L՗uVq}B=dB<~UR3Vn@#QOhFY?qKk6_ѷn:ϒO F_Ra$JM</-*P_u/u'HU"lmTɥsi|%~ihR4N-J5˩pFmOG̥]q J՗qt3To.Qԕdh FFMPW9Aytm/T(_? Eb+ 'O(- ޹ ~8yqӰn'lΙMP'SOFX;Ӓ9}2VkEpwmpg"$(r=CAXf jSGYVMMH-0v{!I)C )Vajna'2ڔZE u{ NEh)뗘V$ \ "M0<9RKN*%a~L\ؖܵvp aUJ- 0qC?͐>7:ku]T3IU73ޥGՠ֔ vQ8*q:S<߬+Rz ,[3M.oGI[5B8TuЯ^%oLLK ГAfѬ,86'kv`"kXoD4M?^ y zA mlR7Xy]&wreR>+x&]8pv*v4/xcb)UU+Ή TW|Zv blXLq ld֑a`5éBw= ӀsHW/z1%ᘓ[e8@3 )Bv+ee.?fƩ\[t%]&o2;CeP>ub+խNymOߝL3=ŒbN dLyom 'wB K1@sM*#3!Y(?͖`|mP6M`Бcvz P?m+L;S%qUOY)fJ kj:QXk<+AdU6c@6k8Dj0pfPnY4?,DytP^-9g*iN&1`}@8Pp NџEM%qkr)o ڞSѶ 6S"LP[ƈM]7aJ+>3z cDi2JQu]N<옑[c}Bx&ezRN4l}.6tkSu.4o:%qkn娱$=9eBdbCi`~쒲=lJFUd¹xO 끳\B(mx'Bө~#7C,|BEϹ\q9"qM@a_ooގֿZ3aR_,K M1 Y,_~!mb̿t0C~Fp4xsb,\ u_Ew5wnI;5B%ꆝO4vҰE"3W o %-3 }$jqR?V07H$'D[DlaJu1IMI*!3p_~GuBvqZ6Sbh?X;yI0<e;4d~4ϔSL>u4+ámđ'[}tkr:rG4̀E ad &upV]-oe=`uIؑD]EH=l3<)FNL897E 1qܐ5!M1 `b7< td3_Vb;j3Kb #WKm\r솒DBK|LS`X|#@ZY{sA!TYU(.[B [Mћ۟XτGgVy,e:ާ qm?=v3+~0G#Mڌy?׋V"@y6BH{u M9aӇ4"EB&crJրDK[g0)r$g$ށX-Q9~ ?!4 U %3ŽU3ԜY=.Sj'5.J> `[X{7 {mDV4aq_k0vHl#DU[+kj@']FjjhBשClu4r:ln'[YT̏J-K):FWC9cP:W|dC xGCEj hve4o/f1pٮ'U<63LiUpzMvŠC`^΋ >%9!rUR7/V|_TBx"&c u-쨱GGx#545 Id[Y&#v mUV )<=آnu-l[x-|-y]p>Ov!%]>R-Q׮%5Ayy*"a;INiU乤xFY Ȕ\L(t{؜\)Уe'J-£˧Ju7Ni늑oXO*Ku& >HL-=R P "p9ʞpͳE4(c%1.;JP2O:ۓ皿@mqYU>AVEl9 BFw&y^d2"BDdX8V$ˣZyZq@8gro<5Azt̓l=K)ý'01~KY-2])߾*b!JoS4gg}ng.UFpbw[F @OfyIu6dNN ֣nV$p,Paa-EBd7P(/Mw+p4'(ɥf^DF (\> +Z?هy bRR">a RrեmZ,JKBP:M#8F(fGBQʼnTWQUF_URRAPa9Rk^cZ9,2ǏdHm<~@kP\H̫I!Ä7t[դas_=X#PRdg=#Iڮ/d ,L ufA c <xŸ5kM"g>gF3IPvLxq|ׁzFAO{`TNs2{6[gv!.o A7a,*hǃz6O8{b([4GW␡h*48g*?X`U.kZ>T S|a=jr:}XəJyQԟTR&2EH($2cFOhbpIa}+Y⎜m̂׉4m2J1MCi]y֋1!Bl^e9BN⭴v6;-n; *m A`9 C,^a-E{L6#"L"IJ }2)[/vj,\W,aE!Yl+qHUqJ]iDJ"/?dۨPDDb"d0ڸ0kR<^fN_[C`٬ uwR `9""#մ:(Cܤ};Uc%չm_H;X9X?H2T# C) 1|c+urZ%vuN$jᑵUKMEn3r}Z(9w/!ui*$DkL09]]),͊/%<ڦI0^5 wQHn]EfP5!].7Y~!9}f L[?v>]v5TV$k_nr2k' F8oo FWۍ ^7J!ٕ|~@\BU%C$HEgbaPܯzcE2tqS؛~1p7YT}5ʫ)U~MFlRmtj"j9yas )~r3C/& 8畗nAElRs"VH5Ώ=6/Rڅ/;Z+ `e(g+$k՗q!e|҆hmmRNBٗoi t(m²F>kk)#V~7à;= QӺ O5A8Ԕ=ÊAbn eݑmpqSQ$C 5{r%k7(X猉]oE7ʢ=nG/Ƒ)v4\IWі"u #&As^x]8MV3N !YP`|߮aVJJ rB@5CnN(=Gd%Si})M3nj"m(D~#%#pCYg:ê?In}LffyDN?׉uss0~R[ ltDu#L7fRI5cuYwᵽg.CEEmw`;73:Ϻ/]xU3;F#֫Ejs,QDq239!>91te&/њ`. z5r*0WW?ҚBvוV4 CH+KPX5)OV ԇKR`]q 2 gQW M'X^4sZ )b|1@}Ev_401W~7C8fIY@)i0x\JTbmP`d&&G3"̧Xle8պfYsnyd_k\FM*Aڔ-,rVMFH1CXy˷`.$SNnQP3,(SRciuFsVHlipE=s@ w*kE&cT6 ԋ7%5cxةl.~7JuvKs4%pǀ|y$ DڭKm%*^T/竌w03Ijr(\,/ FÍrGǂ9h9 :+xu<L;\˒5,pVQ$Mn0`u3&NpO>d,BSёh KyO9uТ3jeҦYH?aTXHs~ S?`H\142b|.IǜGP3ɖuTY4|9{e -RW|Cxo&2g7ӈahՇ|_ngw~SW~3=`5tXr+C+ZZ?%HC?1_\mW: N0XA5X4HTuElR& 'UpSk{ eJUXdض ݌~k0x ~t4Gyfh:PJu!!];du凯.hf;f{٢M(͎p9~?Ym64g JvT6"wJH#?QЀ9 R[<~+|yⴐ9hƬ0:IZS4I![@W҇wu%q/u1rTBdz H9W \{wfJUemŃ J nwVhUJHt~AuU̴1C7Vt|NBn?!j8ڠmc'$LՀ Sj濍xdIHlxSYwzW)4G jg] # a.~bu"}\J.ΩA" ^.3?/(ZE#>a 43'64/FsHuz QoR PqB볂ֺ% vӻڂ"u8ǝ̕&n\tTXtjOcr`yޒYf!5 Z n%Yy.H4anҷg/]HOAaw9zU@3]GE+ ]BF=~z.,?&"WFS"@0a?B 0,0- Rs*2w40 q0ɗGiB--j_cO%v>W2M˃1a8*^$SrСeC\{!Qq0Ph,0h`9 ע,9L1ˬu fWYl7r_5]aq)y9BF!#J~{ JY"]'y,e'msble8'@+#ڰbDK񲧳.b{Ivof3zԇ/S#$"%}7Y+ixQN/ē.n҅*}@ӭ+x c] {)d@+ڧ="d. B4Q#ׁ-@xdK;?e5U1A8Rm/&ރPRCƒ54$9{Nϐ6TOwp Ϥ b# L8 .ƪt€8o8+G`-w/_9[DFר| S8|@j: 7k L!lsc#ADIR98l6'2gVC>ZyF~rގmHKg4$.$ښXznT[AYP'}$N}֭z mōv3b}bTXHB>΢sBehoҜѐo^t\d#$ !& } nfGTC== UњIXA xYv%=*9L=1ɢZ)TdwWiEsy-r3م{i,_N4 y8xoKs9eT[ } ^#ꤰy) J# t~"0R< uT1_R¼cD<g芊6/anI Eۼ`~`1HE Aj6jT3R;=ɕ2j"K2d`lkv17_"E;{a#{f۹ : P^0_w]xF3W1ѬYwN9ìlW)(ˤv(pJP4$gkg+4rfaam#Ƀܰv pkDOx7G%<ZM<ۘXO݌EB+٬7D<1v`TCzk&N&h%n$oVjwDuҝvሽ7wGxP%c 1脊9RZXވb>ֽ2vz3;i?"SX+ğ](`N3=^Y{OHħ?^g-g~Be@QWa@xɌ(՚p`:K:-jR "ѯ,]v JEX6qe6h7iާiPΊ`ADe #堄eX#P,4`(,RۻӉ7Ө5f7 ֏\)܈\dmd΂pVmEpL[]Q i 9?ڷ%Jar`?ro|zC0hIwzP:!djP:9;Q25_.ǖۥ+=10}W Ts-${G|2VwAN 0QP f `_Ed Q "X_K@:kTA'i)MXH 5SbhCN>ub$X-i}UTzl˛:\V4؀ ''aJ:#,LwYLң;m RF("pG hn;\(6p>q(㮖U8C*+LHjD:&^` RliJ@?(}q|C~cʐ(&_5"_!iu ,9nhEœZ>dV &09ҳ7g  >OJ,\*?}}dJP)cн_G[ס^-ug;-ÊC8JVcrJrf+h,8!i!.(-}%vwxg*_ ڑwW.w\3#;2gbr]^M(凞Mv;cSsq=Zr/ArhrOX=d\qK6訶x:PXc{z 1mw x;;}4o9({. ma= a5S|FCer7GU%.#>"TSj#=J>[@NI2Y2AQ>qŖS%ULtzvY(y@L|d:Ridwu'Wָ:6M&8 #l4ysF{ y~;+G@yyse5Pǩe"mC7!M{%*ѾSWe; <ۗ|"4L*p#eJo+*qLp}fmgpbP/&G]cقq1 # td?}wuY{y>Ȥ?_Ј3;mX!{v}杮(O$jQ2Rj0cb} 1G̮ؾ }~"y4ȫ_w8[3ѫγ@w{譑Ĭl4-\%Pk39C kZFOޱG>_AV-}O}!h%huǓF퉣=%|ı0&\ ǛgDh/lWKr-vXo1LnAeD2ev@3p#v ӭW2fY̠*;yfd6Q1ӎOEE_WߗM'am0j@DAMMeE=,G__!"t^u"y%d }9q1^K1dO,Xm-4nD-'ǝ3Dl6 $ {:딕W&ck_'l\F08xjXݯ]LI)W/Ͳ͢bepp7o6aoP g*sfYZ /m( B#(x" T{eK10Ӓ3{$LWzmM:m?hݝsfExj4\0eSAϚCD3e_Jmj}$¬MtRږMBZSTM׈M[}LsrZJQM liprPS4֑Kd't*v1|^Oc/|] 0r!ʺJZK#2sf?$>E>'f&1N98q?Kc%TMJPV/^, X7?I=rGStCqHcŐJ"M4"bYZ Bt!|{qkĴG&a=9\oQ`&DNUQ*ҽV.y=UaEMc6 $g_2~J1>CceG8e7jN}[M nO}{y)u^%VZ 0Gk@"p0HX`ՉKG %7 u oƞYY#|Sؒœ1}T`G6wxqr&"봢DjS]؍qP8}Ug!"gF+?nFzi`F4Ӳ4ݏeի'nOv":37F6i$KS֣ N9 f 6Cٹ]7*w?àf,`IÄoE1.i1-:nXO6;I):_[y $z x8zr/7Va@q#o4ZB*t DCY㓬ŭ̓/ OȠ\{hաA31`8f9D.٭}k 򠶙k+ lt"ܠ'@g3)t) ~LY%M$?$e|$2dEk1 4˜H0X--SEHƓ:xF_JkGO Q*gU>\/x+fco-Rt{K$p,KG+k:}';nJ APv6JO%Bݹ͘^,@z,CZv 0 P* X Um_z2oq Dj\gD 'n_'(3, e ABZ2fڦ²"{@/Ip؍(EQRͶ|,c9SF9Hw_xfkO?!L+MV 5 hZ JODKd% :2- "5h|W (hoq쟦'oOQnGerޕhxm5#oIp: 2:_t:TQ沁(C3S{_6ۜ{l4l+K*Oz(F^LdwƆBM,U3"r'EK! 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 cleartomark {restore}if ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1691062243.0 reportlab-4.1.0/src/reportlab/fonts/Vera.ttf0000664000175000017500000020061414462707743020451 0ustar00rptlabrptlabOS/2_cpVPCLTъ^6cmaplXcvt 9fpgm&`gaspH glyf tA&~hdmx4!Hhead݄T6hheaEoL$hmtx Ǝ0kernRՙ-loca=maxpG:, nameټȵpostZ/prep; h::_:: dM0l   p t  &   Y &  &   c . 5 `  s 0 & {Copyright (c) 2003 by Bitstream, Inc. All Rights Reserved.Bitstream Vera SansBitstreamVeraSans-RomanRelease 1.10Copyright (c) 2003 by Bitstream, Inc. All Rights Reserved. Bitstream Vera is a trademark of Bitstream, Inc. Permission is hereby granted, free of charge, to any person obtaining a copy of the fonts accompanying this license ("Fonts") and associated documentation files (the "Font Software"), to reproduce and distribute the Font Software, including without limitation the rights to use, copy, merge, publish, distribute, and/or sell copies of the Font Software, and to permit persons to whom the Font Software is furnished to do so, subject to the following conditions: The above copyright and trademark notices and this permission notice shall be included in all copies of one or more of the Font Software typefaces. The Font Software may be modified, altered, or added to, and in particular the designs of glyphs or characters in the Fonts may be modified and additional glyphs or characters may be added to the Fonts, only if the fonts are renamed to names not containing either the words "Bitstream" or the word "Vera". This License becomes null and void to the extent applicable to Fonts or Font Software that has been modified and is distributed under the "Bitstream Vera" names. The Font Software may be sold as part of a larger software package but no copy of one or more of the Font Software typefaces may be sold by itself. THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL BITSTREAM OR THE GNOME FOUNDATION BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM OTHER DEALINGS IN THE FONT SOFTWARE. Except as contained in this notice, the names of Gnome, the Gnome Foundation, and Bitstream Inc., shall not be used in advertising or otherwise to promote the sale, use or other dealings in this Font Software without prior written authorization from the Gnome Foundation or Bitstream Inc., respectively. For further information, contact: fonts at gnome dot org.http://www.bitstream.comCopyright (c) 2003 by Bitstream, Inc. All Rights Reserved.Bitstream Vera SansBitstreamVeraSans-RomanRelease 1.10Copyright (c) 2003 by Bitstream, Inc. All Rights Reserved. Bitstream Vera is a trademark of Bitstream, Inc. Permission is hereby granted, free of charge, to any person obtaining a copy of the fonts accompanying this license ("Fonts") and associated documentation files (the "Font Software"), to reproduce and distribute the Font Software, including without limitation the rights to use, copy, merge, publish, distribute, and/or sell copies of the Font Software, and to permit persons to whom the Font Software is furnished to do so, subject to the following conditions: The above copyright and trademark notices and this permission notice shall be included in all copies of one or more of the Font Software typefaces. The Font Software may be modified, altered, or added to, and in particular the designs of glyphs or characters in the Fonts may be modified and additional glyphs or characters may be added to the Fonts, only if the fonts are renamed to names not containing either the words "Bitstream" or the word "Vera". This License becomes null and void to the extent applicable to Fonts or Font Software that has been modified and is distributed under the "Bitstream Vera" names. The Font Software may be sold as part of a larger software package but no copy of one or more of the Font Software typefaces may be sold by itself. THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL BITSTREAM OR THE GNOME FOUNDATION BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM OTHER DEALINGS IN THE FONT SOFTWARE. Except as contained in this notice, the names of Gnome, the Gnome Foundation, and Bitstream Inc., shall not be used in advertising or otherwise to promote the sale, use or other dealings in this Font Software without prior written authorization from the Gnome Foundation or Bitstream Inc., respectively. For further information, contact: fonts at gnome dot org.http://www.bitstream.com5fqu-J3T99NR7s`s3VV9s3D{o{RoHT3fs +b-{T#\q#H99`#fy```{w``b{{Rffw;{J/}oo5jo{-{T7fD)fs@%2%%A:B2SAS//2ݖ}ٻ֊A}G}G͖2ƅ%]%]@@%d%d%A2dA  d   A(]%]@%..%A  %d%@~}}~}}|d{T{%zyxw v utsrqponl!kjBjSih}gBfedcba:`^ ][ZYX YX WW2VUTUBTSSRQJQP ONMNMLKJKJIJI IH GFEDC-CBAK@?>=>=<=<; <@; :987876765 65 43 21 21 0/ 0 / .- .- ,2+*%+d*)*%)('%(A'%&% &% $#"!! d d BBBdB-B}d       -d@--d++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++, %Id@QX Y!-,%Id@QX Y!-,  P y PXY%%# P y PXY%-,KPX EDY!-,%E`D-,KSX%%EDY!!-,ED-ff@ /10!%!!fsr)5 @@ <2991/0K TX @ 878Y P ]%3#3#5qeM@1<20KTKT[X@878Y@0 @ P ` p ]#!#o$++`@1      91/<<<<<<<2220@   ]!! !3!!!!#!#!5!!5!T%Dh$ig8R>hggh`TifaabbNm!(/@U" '&( /)/))/B" ) *!#*- ) " & 0<<<1/299990KSX99Y"K TX0@00878YK TKT[KT[X000@878Y#.'5.546753.'>54&dijfod]SS\dtzq{---@A$*.U# jXV`OnZXhq) #'3@6$%&%&'$'B .$ &($4'!%   ! + 1 49912<0KSXY"K TK T[K T[KT[KT[K T[X4@44878Y"32654&'2#"&546"32654&%3#2#"&546WccWUccUVcbWWcd1Zܻۻa ۻۼ 0@      !         B  (('+'$ .  .'.'!!199999991/9990KSX99999999Y"2]@ " ) **&:4D ^YZ UZZY0g{ "-  ' (   2'') #**(/2; 49?2J LKFO2VZ Y UY\_2j i`2uy z 2229]]3267 >73#'#"5467.54632.#"[UԠ_I{;B h]hΆ02޸SUWDi;#QX?@Yr~YW׀c?}<$$/1oX3goB@ 10KTKT[X@878Y@ @P`p]#o+{ O@  29910KTX@878YKTX@878Y#&547{>;o @ <99103#654<:=JN@,       <2<2991<22990%#'%%73%g:r:g:PrPbybcy #@   <<1/<<0!!#!5!-Ө-Ӫ--@ 1073#ӤR@d10!!d1/073#B-@B/9910KSXY"3#m #@  10"32'2#"  P3343ssyzZ K@B  1/20KSXY"KTX  @878Y]7!5%3!!JeJsHHժJ@'B   91/20KSX9Y"KTKT[KT[X@878Y@2UVVzzvtvust]]%!!567>54&#"5>32Ls3aM_xzXE[w:mIwBC12\ps({@.    #)&  )99190KTKT[X)@))878Y@ daa d!]!"&'532654&+532654&#"5>32?^jTmǹSrsY %Đ%%12wps{$& Ѳ|d @   B    <291/<290KSXY"K TK T[X@878Y@* *HYiw+&+6NO O Vfuz ]] !33##!55^%3`du@#    190KTKT[X@878YKTX@878Y!!>32!"&'532654&#",X,$^hZkʭQTժ 10$& $X@$  "% " !%190@]]"32654&.#">32# !2 LL;kPL;y$&W]ybhc@B991/0KSXY"KTX@878Y@X9Hg]]!#!3V+ #/C@% '-'0 $*$ !0991990"32654&%&&54632#"$54632654&#"HŚV г "Əُattt$X@# %!"" %190@]]7532#"543 !"&2654&#"LK:lL>$& V\s[#@<21/073#3### %@  <2103#3#ӤR#٬@^M@*B$#29190KSXY" 5Ѧ`@ #<210!!!!^O@+B$#<9190KSXY"55//m$p@+$     &%99991/9990K TX%@%%878Yy z z ]%3##546?>54&#"5>32ſ8ZZ93lOa^gHZX/'eVY5^1YnFC98ŸLVV/5<4q L@2  L4307$7CM34( (+(I+*(I,=M<9912990K TK T[KT[KT[KT[XMMM@878Y@ NN/N?N]32654&#"#"&5463253>54&'&$#"3267#"$'&5476$32|{zy!orqp ˘s'6@   0210].# !267# !2'ffjzSb_^^_HHghG.@   2 99991/0`]3 !%! )5BhPa/w.,~ .@   21/0 ]!!!!!!9>ժF# )@ 21/0 ]!!!!#ZpPժH7s9@ 43 1990%!5!# !2&&# !26uu^opkSUmnHF_`%; ,@ 8  221/<20P ]3!3#!#"d+991/0KTX@878Y@ 0@P`]3#+f M@  9 991990KTX  @878Y@ 0 @ P ` ]3+53265M?nj @(B  291/<290KSXY"]@ ((764GFCUgvw    (+*66650 A@E@@@ b`hgwp  ,]q]q3! !#3wH1j%@ :1/0@ 0P]3!!_ժ @4  B    >  91/<290KSXY"p]@V   && & 45 i|{y   #,'( 4<VY ej vy ]]! !###-}-+3 y@B6 991/<2990KSXY" ]@068HGif FIWXeiy ]]!3!#j+s #@  310"32' ! ':xyLHH[[bb:@   ? 291/0@ ?_]32654&#%!2+#8/ϒs R@*  B     39991990KSX9Y""32#'# ! '? !#y;:xLHHab[T@5  B    ?  299991/<9990KSX9Y"@]@Bz%%%&'&&& 66FFhuuw]]#.+#! 32654&#A{>ٿJx~hb؍O'~@<    B %( "-"(9999190KSX99Y")])/)O)].#"!"&'532654&/.54$32Hs_wzj{r{i76vce+ٶ0/EF~n|-&J@@@1/20K TX@878Y@  @ p ]!!#!ժ+)K@   8A1299990KTX@878Y]332653! ˮ®u\*$h@'B91/290KSXY"P]@b*GGZ} *&&))% 833<<7HEEIIGYVfiizvvyyu)]]!3 3J+D {@I      B     91/<2290KSXY"]@  ($ >>4 0 LMB @ Yjkg ` {|      !   # $ %  <:5306 9 ? 0FFJ@E@BBB@@ D M @@XVY Pfgab```d d d wv{xwtyywpx   []]3 3 3# #D:9:9+=; ]@F      B    91/<290KSXY"K TK T[KT[X  @878Y@ '' 486 KX[fkww       &()&(' ) 54<;:;4 4 8 ? H O X _ eejjhiil l xyyx}  x   @]]3 3 # #su \Y+3{@(B@@ 91/290KSXY" ]@<5000F@@@QQQe &)78@ ghxp ]]3 3#f9\ @BB 991/0KSXY"K TK T[X @ 878Y@@ )&8HGH    / 59? GJO UYfio wx ]]!!!5!sP=g՚oXS@C210K TX@878YKTKT[X@878Y!#3!XB-@B/9910KSXY"#mo<@C<10KTKT[X@878Y!53#5oXޏ@ 91290##HHu-10!5f1@ D10K TKT[X@878Y #ofv{-{ %@'   #   E&22991/9990@n0000 0!0"?'@@@@ @!@"PPPP P!P"P'p' !"'''000 0!@@@ @!PPP P!``` `!ppp p! !]]"326=7#5#"&5463!54&#"5>32߬o?`TeZ3f{bsٴ)Lfa..'' 8@  G F221/0`]4&#"326>32#"&'#3姒:{{:/Rdaadq{?@  HE210@ ].#"3267#"!2NPƳPNM]-U5++++$$>:#qZ8@G E221/0`]3#5#"3232654&#":||ǧ^daDDaq{p@$   KE9190@)?p?????,// , ooooo ]q]!3267# 32.#" ͷjbck)^Z44*,8 Cė/p@     L<<991/22990K TX@878YKTX@878Y@P]#"!!##535463cM/ѹPhc/яNqVZ{ (J@#  &#' & G E)221/990`***]4&#"326!"&'5326=#"3253aQQR9||9=,*[cb::bcd4@  N  F21/<90`]#4&#"#3>32d||Bu\edy+@F<21/0@  @ P ` p ]3#3#`Vy D@   O  F<2991990@ @P`p]3+532653#F1iL`a( @)B F 291/<90KSXY" ]@_ ')+Vfgsw    ('(++@ h` ]q]33 ##%kǹi#y"F1/0@ @P`p]3#{"Z@&   PPF#291/<<<290@0$P$p$$$$$$$ ]>32#4&#"#4&#"#3>32)Erurw?yz|v\`gb|d{6@  N  F21/<90`]#4&#"#3>32d||Bu\`edqu{ J@  QE10@#?{{   {  {]"32654&'2#"s98V{>@ GF2210@ `]%#3>32#"&4&#"326s:{{8 daaqVZ{ >@   GE2210@ `]32654&#"#"3253#/s:||:/daDDadJ{0@    F21/90P].#"#3>32JI,:.˾`fco{'@<  S  SB %( R"E(9999190KSX99Y"']@m   . , , , ; ; ; ; $( ( *//*(() )!$'      '/)?)_))))))]]q.#"#"&'532654&/.54632NZb?ĥZlfae@f?((TT@I!*##55YQKP%$78@  F<<2991/<2990]!!;#"&5#53w{KsբN`>X`6@    NF21/290`]332653#5#"&||Cua{fc=`@'B91/290KSXY"K TX@878YKTKT[X@878Y@Hj{  &&)) 55::0FFIIFH@VVYYPffiigh`ut{{uz>]]3 3#=^^\`TV5` @IU U U U   B     91/<2290KSXY"K TKT[KT[KT[K T[X  @878YK TK T[KT[X @ 878Y@" 5 IIF @ [[U P nnf yy          %%#'!%""%' $ ! # 9669 0FHF@B@@@D D D @@VVVPQRRPS T U cdejejjjn a g ouuy}x}zzxy  { v } @/   y]]333# #V`jjj;y` Z@F      B   91/<290KSXY"K TKT[KT[KT[X  @878YKTX @ 878Y@   & =1 UWX f vzvt        )&% * :9746 9 0 IFE J @ YVYYWVYVV Y P o x  /]] # # 3 dkr))`HJq=V`@C        B     9129990KSX2Y"K TKT[X@878YKTX@878Y@     # 5 I O N Z Z j        '$$  )( % $ $ ' ** 755008 6 6 8 990A@@@@@@@@B E G II@TQQUPPVUVW W U U YYPffh ii`{xx   e]]+5326?3 3N|lLT3!;^^hzHTNlX` @B 2991/0KSXY"K TK T[X @ 878YKTX  @878Y@B&GI  + 690 @@E@@CWY_ ``f``b ]]!!!5!qjL}e`ۓ%$@4 %   !  % $  C %<<29999999199999990K TX%%%@878Y&]#"&=4&+5326=46;#"3>l==k>DV[noZVtsݓXX10#$@6%   #%#C %<2<9999999199999990K TX%@%%878YKTX%%%@878Y&]326=467.=4&+532;#"+FUZooZUF?l>>l?VWstݔ1#@  1990#"'&'&'&#"56632326ian ^Xbian ^V1OD;>MSOE<>LhN'$uhm !@T   !!  ! !!!B     !  VV!"2299999991/<9990KSXY" #]@  s P#f iu {yyv v!# ]]4&#"326!.54632#!#TY?@WX??Y!X=>sr?<҈_Z?YWA?XXN)sIsrFv)su''&-k'(u3^'1usN'2'u)N'8u{-f'DR{-f'DCR{-f'DR{-'DR{-7'DR{-'DRqu{'Fqf'Hqf'HCqf'Hq'Hof'f'C\f'F'd7'Qquf'Rsquf'RCsquf'Rsqu'Rsqu7'RsXf'X{Xf'XC{Xf'X{X'X{9; '@  YW Y <<1<203!!#!5!oo\]u=  @  Z[Z10"32654&'2#"&546PnnPPnoO@v+..ooPOmmOOp1.-rB#!Q@+     "  "<<<221<9990%&&'667#&73JDFHAMf fIX⸹)**'# 32!b`@!    <<1/2<2990K TX@878Y66].#"!!!!53#535632NL=ty-=))׏/я\= >@54&.#"#"&'532654/.5467.54632{?>?>S8alӃ\]>9̭IXW:fqր][;;ȦI.Z.L-[.K''PGZsweZ54m@''TLf{xf[1,pE3!   \ 104632#"&3~|}}||};9 %@]] 91290!###&&54$yfNݸ/@0-'!  **.  !' $'$-F099991/990@@'(     ! "&  : :!MM I!I"jj  ]]4632#"&'532654&/.5467.#"#:A9`@IPAtx;e\`Wqqs`/Q*%jd_[?T>7;[gp/8L`@6EBC?2H09JC 9 $HE301BKL?gwyVpMI`3D/IC@&=>:A$104G$ 7aD=0^* D^ J21/02#"$'&5476$"32676654&'&&&&#"3267#"&54632mmllmmmmllmm^^``^^⃄^]]^\^BB@zBCFInmmmmnnmmmmng^^^傁^^__^]⃅]^^! "'F >@!    b b cbc91<<2<<903#######5Jq7rqr/B^^sRf1@ D10K TKT[X@878Y3#fF)@dd1<20K TK T[X@878YK TK T[KT[KT[X@878YKTKT[X@878Y@````pppp]3#%3#^y'>@"     <291<2<<990!!!!!'7!5!7!}/H{};fըfӪH@9  B     <291/<0KSXY"]@gww  ]!!!!!!#!59=qժF՞f +@< +,  )&  *&& &,+,* # )#3,99999999199999990@*WZWU!je!{vu! FYVjddj(|svz( ]] 324&'.#"&5!27!"&''3>_'y=_''NOy;WfNPƀ[gX@CHp@CpDfbMKYg[KKX /@- !$'!!0 $*0999919990@     $$$   $$ $ ***///***55500055 5 :::???:::EEE@@@EE E JJJOOOJJJV !"&'()]]32654&#".#"326#"&54632>32#"&1TevYR1UfvYRF^_HDa^/XZie7XXjeߦ~᧯w .@     <2<21/<<0!!#!5!!!-Ө-}} T@.B $# <2291/90KSXY" 5!!@po V@/B$ # <<291/90KSXY"55!5AǪR@F  B     fe f e<2299991/2<2<290KSXY"K TX@878Y@(' ' ')((79  ]]!#!5!5'!5!3 3!!!c`Tþ{yT9{3{JD{3V` M@%  !   NF!2912<990"`""]3326533267#"&'#"&'#% )I#ER2bf*V H<9 NPOONNh-)b@'! '!* $$*9991990K TK T[KT[KT[KT[X*@**878Y>54&#"#"&54632#"&54324&#"32IH7$$0e՘ݢe WOmVPmmWKt,>bFأ[t}t{w; ]@    91990@0QVPZ spvupz  Z pp{ t  ]]!! !!5 7AJI3!wq@gg120!#!# }/#@1 " $ #" #h#$9999991/<229990K TX$$$@878Y@V             ##(]]#3267#"&5467!##"#>3!i/7.%7vy"Pµ)6< yJ\:1fd.xo@E}/%&@  & iji&1026732#"&'&&#"#"&546327j Pd@7*8  kOeD=!0 l9TA6?&#Hn!bSA8?Ss;)_@3(%%  * "(kl"k *22999199990!!#5#"&5463354&#"56632"32655P,]uu>DIE~bRhP{@p?Dq[[""CO@Mr`d.@  klk 9910!!2#"&546"32654&PXγгi~hi}|P{ݿܾsN@@"   mm  9991/<20%!5654#"!5!&5! Dz?1/aL"a*>w؍{o{3>@C'-%= 4%:.-*1 %?47&%7& =&-7"E?<9999912<<29990@0+0,0-0.0/00@+@,@-@.@/@0P+P,P-P.P/P0+0@@@@@@@@@??? ??0,0-0.0/@,@-@.@/P,P-P.P/ooo oo`,`-`.`/p,p-p.p/,-./]q].#">32!3267#"&'#"&5463!54&#"5>32"326=DJԄ ̷hddjMI؏`TeZ߬o0Z^Z55*,ywxx..''`f{bsٴ)H +@<+,&  )&  *&& &,+,* # #Q)E,22999999199999990@p(?-YVUV jf!{    { z{ {!"#$%{&%--&YVUZ(ifej(ztvz($$]] 32654&'.#".5327#"&'')gA\*g>}66]C_56`?`!*(Ou))Hn.Mw834OMx43N $@/  !# #%" " "!& %999919990KTKT[KT[X%%%@878Y@ ttttv]33267#"&546?>7>5#537ZZ:3mN`^gIYX0&DeWX5^1YnFC98ŸLVV/5<65 b@ <2991/0K TX @ 878YKTKT[KT[X  @878Y P ]#53#3+e^@ 10!#!^=} *@    91903##'%\sB}}`s-Pb;V#@@   B   !$  $912299990KSX29Y"K TX$$$@878Y.#"!!#"&'53267#5!>32&P,`r<::d/4a/am"?$Ɨ5dzɏ!!J;?@.9*-" *19" <-<<219999990#"'&'&'&#"56632326#"'&'&'&#"56632326ian ^Xbian ^Vgian ^Xbian ^VoNE;=LTNE;=KڲOE;=LSNE;=K`8@91/90@cmpxyvn]] !3!^DC?%# @I    B   o o n<2991<2990KSXY"55%-+#-+#RRH# @I  B   o op<<991<2990KSXY"5%5+-+-#^R^  ^R^   #@   1/<<220%3#%3#%3#hk'$uh^'$us^'2'us ;@   299991/220!!!!! !# !39OAg@AժF|pm|q{'3@1 . ("%4"1 K1 Q+E499912<2290@%?5_5p55555????? ooooo ]q].#"!3267#"&'#"32>32%"32654& H ̷jbdjQGьBN5Z44*,nmnm98olkp݇y/10!!yy/10!!ym '@   1<20#53#53ӤRӤR??m '@   1<203#%3#ӤRӤRլ@@@ 10#53ӤR?@ q103#ӤR՘?o )@ r <<103#3#!!oA#u"@91990  9%-=V'\^N'<su+@B10KSXY"3#-\^R#/@I -'! - -'!0 *$0* $ $(st*(s099999999919999999907'#"&''7&&5467'766324&#"326{r%$&(r;t=:x=q%%&&s7t@?s9q(&%%s>v:@t8s'%$|pprs#G@%Bon29190KSXY"5s-+#R#I@&Bop<9190KSXY"5+-#^R^  /J@(   L<2<2991/<22990K TX@878YKTX@878Y@0P]]#!##53546;#"3#JcM`/яNPhc/J@!    L<<991/<22990K TX@878YKTX@878Y@0P ]!#!"!!##53546JcM/ѹ{Phc/яN9;>@   Y W Y <<2<<2122220%!#!5!!5!3!!!oooo\\HF103#F@ 10%3#ӤR@m '@    1<20%3#%3#ӤRfӤR@@q L #'3?K@D$%&%&'$'B@ .(F4 :&$L%IC'1+C =  1 =I 7+ ! L9912<<2220KSXY"KTK T[K T[K T[K T[KT[XL@LL878Y"32654&'2#"&5462#"&546!3#"32654&2#"&546"32654&WddWUccUt%ZVcbWWcdWccWUccܻۻۻۼܻۻhm'$um'(uhk'$uN'(uk'(uk',/u`m',/uXN',/u;k',/usk'2'usm'2'usk'2'u)k'8u)m'8u)k'8uy` F1/0@ @P`p]3#`?f7@ u91290K TKT[X@878Y3#'#fJ7c@$   VwVv99991<<99990K TK T[X@878Y'.#"#>3232673#"&9! &$}f[&@%9! &$}f[&@Z7IR!7IRb+/10K TKT[X@878Y!!V)9H W@ VV1<0K TX@878YKTKT[KT[X@878Y332673#"&v aWV` v HKKJLDf,@ d10K TX@878Y3# _@ V xV10K TK T[X@878YK TK T[K T[X@878Y4&#"3267#"&54632X@AWWA@Xzssss?XW@AWX@sss#u@  ' 1/90!#"&'532654&'T76xv.W+"J/;<+->i0Y[ 0.W=fB@991<20K TKT[X@878Y3#3#߉fxLu @   '1/90!33267#"&546w-+76 >&Dzs5=X.. W]0i?f7@ u91<90K TKT[X@878Y373xu ?@   : y<<991/900P]3%!!'79Pw^Mo;jnH ^@  z z <<991/90KTX @ 878Y@ @ P ` sz p ]37#'7Ǹ}Lɸ{JZjXjm'6uof'V\m'=uXf']@ <210##    g@    2  y<291/220@(   ]]! )#53!!3 !iP`P5~.,qu('@^%{&%#${##{#({'(#&'('%$%(('"#" ! B('&%"! ## #)&' ! (%#" QE)999999919990KSXY"?*]@v%+("/#/$)%-&-'*(6%F%X X!` `!f"u u!u"%#%$&&&''(6$6%F$E%Z Z!b b!z{     {zzv v!x"**']].#"32654&#"5432''%'3%F2X)6 ~r4*!M!ü޼z&77kc\̑oabk'<su=Vf'\^ =@   ? 2291/0@ ?_]332+#32654&#'ђV>@ GF2210@ `]%#3>32#"&4&#"326s:{{8daa-10!!ת? @M    B   <291<290KSXY" '77w55v8vL57y5yy5 ,@   |]|| 12035733! c)t'+n^J@$}}B ~9190KSX2Y"!!56754&#"56632 "?XhU4zHM98rn81^BQ##{l0b(H@'    #)~&~ )999190#"&'532654&##532654&#"56632 \e9}F4wCmxolV^^ad_(fQI7Z`mR|yOFJLl?<:=svcE`''5 d?''5db''5 dsm'* uqVZH'JP', /uu'6ou{'Vs'k'&-uqf'Fs'm'&-uqf'Fq$J@$ "    GE%<<1/<20`&&&]!5!533##5#"3232654&#"F:||ǧN}}daDDad10!!dHF103#F1@: "+ /) 2+"!)#&  , & &*!/<29999999999122<20K TK T[K T[KT[KT[KT[X222@878Y@z  1Ti lnooooiko o!o"o#n$l%i'i-  !"#$%&'()*+,-2   USjg ]].#"!!!!3267#"#734&5465#7332[f A78 ʝf[Y`(77(6bbiZȻ{.# .{ZiHH"{/ #/{"G)@ dd1<20KTKT[X@878YKTK T[KT[X@878YKTKT[X@878YKTX@878Y@````pppp]3#%3#^ys@B10KSXY"K TX@878YKTX@878Y@ %%6FVjg //]]3#7Ju@!  VV 99991<2990K TX@878YKTX@878Y ]'.#"#4632326=3#"&9 $(}gV$=09" (}gT";9! 2-ev 3)dw @B10KSXY"K TX@878YKTX@878Y@*$$5CUU//]]#ę1w@ 91<90K TX@878YKTX@878YKTX@878Y@ //- ]3#'#Ӌ1@ 91290K TK T[K T[K T[X@878YKTX@878YKTX@878Y@ "  ]373Ӌ ? @   ] <291<290KTKT[KT[KT[K T[K T[X@878YKTKT[X@878Y@T /9IFYi       "5GK S[ e]] !33##5!55bf]my9 j@ VV120K TX@878YKTX@878YKTKT[X@878Y332673#"&v cSRav 6978w{zf103#  !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~>: ~1BSax~ & 0 : !""""+"H"e%  0AR^x}  0 9 !""""+"H"`%^ChVjq_8 (Bbcdefghjikmlnoqprsutvwxzy{}|~f55q=3=dd?y}s)3s\\?uLsLsyD{={\{fqqq/q999qqJ+o#7=V;=3XyysLs{{{{{{fqqqqq9999qqqqq9\3 'sLfR#hd+/s`N{H?55=ZyyLss/q%%=V^33 / /9% qyy\\\\;LsLsLs9#LF+o{\3X3 q=55^5bb3sq\+osfqsfqqds 5?+   !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~     sfthyphenperiodcenteredEuroc6459c6460c6461c6462c6463c6466c6467c6468c6469""""XO!nE~Le  R s  X : i  = z /Eu)pP@"m#{CwRw [ r !5!B!!!" ""#"0"="J"W"d"q"~"""""""""## ##'#4#A#N#[#h##$4$%3%S%&&'K''((X()_*%*\**+z+,D,,-P-..R./0A011!1P12H2z23F3p3p3}3334z44445595g55556[667C77888J999)969C9P9]9j9w99999999::{::;;^;;;<"<_<<<<<<=c>;>H>U>>>?a??@:@K@\@m@z@@@@@@@@A@AVAkBEBBC_CCDUDE*E?- x$%&')*K+-r./2934K57D9:;< =IQR&UYZ\bdg9xy&z&{&|&}&9 999 K$$$$$9$&$*$2$4$6$7a$8$9}$:$;$,,G}G  @ 2 YYdhd@%%Y   %Y%&Y]%]@%dX:t:2  Y~}|{zyxwvtvututYtsYs}rq&ponm @lkjkjj@ihihYhgYgf\ fedcdcb]ccbW%b]b@a`_.`_.^Y^]\ ] \ [Y[KZYZYXYXW%VUTSRQPO%PO%NMLKJIH H@FEFEDCDCC@BdB@A}@?>,>,=<;:94 9287265 6@5 5@43 4 3 211}0/0d//.-,+,K++**K)()(' (' &%$%2$#"#"!%!   2@   @:%dd:%:%K       @d:@  @d++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++, %Id@QX Y!-,%Id@QX Y!-,  P y PXY%%# P y PXY%-,KPX EDY!-,%E`D-,KSX%%EDY!!-,ED-ff@ Q/10!%!!fsr) Y@.   :UTS 991/0KSX9Y"!!!!iqlhE^h@VS1<20###h++=P@6 Z Z W   91/<2<<22<<220!!!3!!!!#!#!7!!7!F+`aa)5E)6````5F5`hh7 !(/v@C# ")^] ^][* [!*)#"&- !&-& - & 09999991/<29990#&&'&&54$773&&'6654&T;]1`x=ҿ+,+eX1?w93TdA7ckI-+&7=7 "%/$ DQ=07VK39q '3M@+e .e"a(ee a`d4+%   1  + %49912<0"32654&'2#"&54#3!2#"&54"32654&Vo=>Wn? ֝ k֝ Vn==Wn?hWWUWꭍ ꪍXYTX9&0@[   0'0%&$''0:0' - -iYf!gd` '*$ * 0$* 1999991/99990KSX999Y"]@`  * 9 K K'[ \'bm n'   &0' ' +'+0;';0III H H'J0ZZ\ \ \\#X'honki i l0$]] >7!!'#"$5467.54$32.#"3267m)>Z7+xJTv{ֿ.[e5WOVd54&#"6$3278{hmpe_@PMRZKN=21Ū(i@,s ^ x s ^xsw#d`)   & /999190K TK T[X)))@878Y!"&'32654&+732654&#">32q~wh9YiŖ1yUl7vp%s%%)49kYYraLP,*  @;         : uS    991/<290KSXY"K TK T[K T[K T[X@878YK]] !!3#!!Lo556`ARJ'@9:^]]sys vS `  999190KSX9Y"K TK T[K T[K T[X@878Y!!>32!"&'32654&#"j7v-,_0r}t;ol|Tt ѹ12/HD`q+-fH 'r@! ^ ]sss%d`(  (9190K TX(((@878Y@```` ` ` `````` ]"32654&.#">32!"476$32rZPqX6VQN]|pxG^ἔYc`f,,ȵ31ک!s 3@:vS991/0KSXY"!!!'f-<-F #/t@$ *ssw$sd`0- ' -!0991990K TK T[K T[KT[KT[KT[X000@878Y"32654&%.54$!2!"$546"32654&ufXwglkM&zt3f{YIf{YtSauSb-e谠-/yŰwbDTwbEST7'@ ^]s s "sd`(%% (9190K TX(((@878YKTX(@((878Y@o o o ooo$o%o&o' ]73267#"&5!2#"&2654&#"T5WQM]i|qx_rWQqX!-+ȵ31کa [b`fT`N@(:TzT91/0KSXY"!!!!-iJChL`}}` Z@.   :TpTz   9910KSX9Y"!#!!h;լiJu}=@|{29190 5<'@ o}o<210!!!!=@|{<91905511Jo!@I !:!  Y]iUTd  ! "999991/9990KSX9Y"!!!766776654&#"6632hFWJOHQLPs>ajLP9d1P}f:=j69=CB:*(wf<>M+\j L]@5IM-.* LF~*1~!=WM -.L C'7M991<<29990"32654&#"&543273654!"!267#"&'&5476$32!"#"&' jQMjP'-ZS}˅v\`Kvhm⎇bxroirg!ґTXɒV^KSBTEKnWSbbRMl>ɰH]\Yv{ @A     : uS   91/<90KSXY"]@  + / ?   + ) ]]!!!!!uLZ+?+ h@::S    !9991/90KSXY"2654&##2654&##!!! 3gtQL>ebeLbk#A h[;>s~vKHyn՜JJ@ uu d` 991990@  ))]]%# 476$32.#"3267يrroqty>`oeF12J=78IDIN+J@@!  : S   9991/0KSXY"3 4&#! !! :/""`abjq.#EQQzm\+\ T@/    :S    91/0KSXY"!!!!!!N9s6g:B7+\ O@+    :S  91/0KSXY"!!!!!N9s6g:{J9 h@6  : uu d`!  !299199990KSX9Y"%# 476$32&&# 3267#!sƳrqw;zv8p991VoGEC=87GF"+ u@A     :S    91/<<0KSXY"!!!!!!No8n{{9+y+6@:S91/0KSXY"]!!N+f g@%  : S    9991990KSX9Y"K TKT[X @ 878Y!!#3267N:N9  :S  9991/<2990KSXY"] ]!!!!NVlR + J ;@ uud`! !10KTX!!!@878Y4&#"3267> # 476$쟗s? qRn{oja*k4s?=QE'la_[+{@H    : u u S      99991/<9990KSX9Y"] ]2654&+ !!2!.#]dL3o#9ȫNh'p"a\?zvJEոXsoSR'@;    : uu%d`( " "(9999190KSX99Y"]@9 9 9 9 9 99999 9!I I I I I IIIII I!YZ Z Z Z Z ZZZZZ Z!m m m m m mkkmmmmm m!y y y y y yyyyyy y!< )```` ]].#"!"$'32654&/.54!2R>qiGoƹɑ=zJ}e.y87ZP39'265EMLlT7= '+%b`@:S991/20KSXY"K TK T[KT[X@878Y!!!!`9NTg@:     : ` S  91290KSX99Y"!3267!! $5467N ih$A 0Jba$Y;q@':S91/290KSXY"]@%5)76 ]]!!!nj5\+ % @J        : S    91/<2290KSXY"KTX @ 878Y@j       / / ? ? O O YYY      &%#' 637 0 BB UZVPP  !]]!!!!!d.n1}L2B==+o @I   :  S   91/<290KSXY" ]@4  -$ <2 LC    '$' * 79 : DHG ]] !! !!nyKa  +yx@5:S  991/290KSXY"]@  D]]!!!yy)o 9@:S   91/0KSXY"!!!7!08%:-<F@":lk9910KSXY"!!!!Nl--B5@ S9103Xƾm@@:lk9910KSXY"!7!!7!3+ +m`@ S91290##fg--10! f2@ 910K TKT[X@878Y#'fx#{ +@c        : "  g#"g&`  )#"),9991/99990KSX99999Y";"]@83!0"C!@"S!P"c!`"!"!"!"5":#:$K#K$[#[$k#k$#$#$ ]]"326?%!7#"&54$!37>54&#">32QGn}XsK8}{oa6p~ SQ=Fy)d_ BC.."Q?j @K  : ii`k    !  9991/990KSX9999Y""32654&!!6632#"&?cX_.!.huRkMH[sw\ifk+b]ρd~]L{3@ ii`  99910&&#"3267# $5476$329HCފ~TI7Y[ibmU=02u21ډgqnJ @K  : ii` k    ! 9991/990KSX9999Y"%2654&#"!!7#"&54676632uaW_ti!RkMH[s]hfkXb]ρd~]J{'H@( g$g`( ' !  (9999190!3267# $54676$32%6654&#" q7[Wg `Ri'9mlDC0/݀dx|(Yo  P^spfR@<      : igkz     991/22990KSX9Y"K TKT[KT[KT[KT[KT[X@878Y@ ``pp]#"!!!#37>3R/KE /1Ѩ2%7CO`N)Fuy+@Y+* )'&(  :& &g i z&i)#! ,99991/99990KSX99999Y"%#"&546766327!!"&'3267"32654&XViMHXv7i:h^5UY!T^Z^b\qdy\c3 !65fkhm?;@L   :  k  %#  9991/<99990KSX999Y"0]!>54&#"!!>32)q GAol.hucm VH9O@Fa^ N?X@(:zk  91/0KSXY" ]o ]!!!!h.h9`F @:     : gz k   ...9991990KSX9Y"K TK T[X@878Yo]!+73267!!h.ղ-?e]+h9`[? @A      :zk   91/<90KSXY"]@<     )EQXcwpvz  *ESdpus ]]!! !!mhug^?6@:k  91/0KSXY"]!!mh?{+@x !    "#$# !$#(')&$#%$$#:!  &$ )$z" %"!$  &$ %% $# ,99999991/<<<299990KSX9999Y"]@#     /-]>32!7654&#"!>54&#"!!>32Sr q?6gls >7clh!TgtgnM1VH|#7@HKM8?`_`w?;{@N   :  z  %#& 9991/<99990KSX999Y"0]!>54&#"!!>32)q GAolh!cm VH9O@F`a^ NJ5{ )@ii ` !)! 10p]"32654&2#"$54676$a]a@ZVf\Vd{joincvx~dtxVj{@M:ii`z !   9991990KSX9999Y"0!]%!!>32#"&"32654&s-h!RkMH[sAcX_ b]ρd~]7\ifkJVu{@N:ii`z  ! 9991990KSX9999Y"7!!#"&546766322654&#"isPkMH[saW_Lb]ρd~]]hfk?\{@6       :  z   & 91/9990KSX99Y" ]@#    @@@@@@``````].#"!!>32%Z4 fh'GՂ0!/`jq{{'@9    : gg%`(  ,*"(9999190KSX99Y"K TKT[K T[X(@((878Y@i j j jjj j!````o)vv]].#"!"&'32654&/.54$!2{5i]js@^Aٮs}6atqr@dAs=2473$ .$$9:64$( (X@>  : iz i  9991/<2990KSX9Y"K TK T[KT[KT[KT[K T[X@878Y)]!!;!"&5467#3=n3\=H3Ӣ\1>& .(@!>{s`@M    :  ` z &%9991/299990KSX999Y"K TK T[K T[K T[K T[KT[KT[KT[KT[KT[KT[X@878Y0]!3267!!7#"&546gq FAolg!\p9P?F'a`#Nm`@&:z91/290KSXY"K TKT[KT[KT[KT[KT[K T[K T[K T[X@878Y@FVffj]]!!!Jkn`j` @F     : z    91/<2290KSXY"KTKT[KT[K T[X @ 878Y@(I   %% GHF W fh xty ]]!!!!!J'R)P`%`^` @I     : z    91/<290KSXY"KTKT[KT[K T[K T[X @ 878Y@N  (%)+ 1GJ   ((')+* 65GEGFG G G kch i  ]] !! !!t#8{=#LbF`@C :  gz   /9129990KSX9Y"K TKT[KT[KT[KT[KT[K T[K T[X@878Y@   H]]!!+7326?R;wʠ%qXa&!`6ρ;J<` x@,,:izi   91/0KSXY"KTKT[KT[KT[KT[X @ 878Y@)&/ ]]!!!7!1FC1/`fZ0@g0/.-,+* $%&'() "!# : 1 #)*k110-*)&#   19999999199999990KSX9999Y"#"&546776654&##7326776633#"3+ڳ%[u@->'%+Fg!vrPJ Qtm{{<(7XHtWZMC(.0C410#Z0@l+,+0,,+ :+1''%,'%/k1'&0  /0+",%(&01999999199999990KSX9999Y"32677667&&546776654&##73233#"##Fg!wsPL !QtC+۳']t?-=%%mYZND-*2D3z{="6XHuR#@ o o1990#"'&'&'&#"56632326j`k^Xbk`k^VRPE:=MSPE:=K{k'$Du{m !@P!!    ! !:! u W " !  "99991/<9990KSXY"]@2!!!-!9!?!Y!!!! ! !(* +!!! ]]32654&#"!!!.54632!M66MN56Mh+u9vuZP6MM66MMP%M,uu0ML?Jo'&+\k'(u+m'1uuJk'2uTk'8mu#f'D#f'DC#f'D#1'D#9'D#'DLo{'FJ3f'HJf'HCJf'HJ1'H?f's?f'Cs?Pf's?R1's?;9'QJ5f'RJ5f'RCJ5f'RJ51'RJ59'R{sf'X{sf'XC{sf'X{s1'XN; [@0:S    9991220KSXY"!!!!!7!JJ!--#/dL @  -.-10"32654&'2#"&546HdcIHdeGBz0/11-0|D\dHHbcGHd3/0xDCy-03"a@8    i i #   #99199990&&##667#&&5%3f{94p9K@ YG8HU77l(77DX.рJm520h10"#"#}@E  :^] gsd s  99991/222990KSX9Y"&&#"!!!!3#737$!27;G}!u-@34?-!4.\%({ F=3?@F@1:4%  $+1d@$7! =%+.47! :=(!11.=070.(@9999999199990&&#"#"&'732654&''&&5467&&54$326654&+Z=P^19Z96T_0f=Ma0Owp42S!PUaPXr(&=22)No{:$X6++?0/%=6f{;)\5Y>=V@[8=]'` 2104676632#"&'&&'535II245633JI326J235624IJ336633; c@.  :S  9999120KSX9Y"!###&&54+Ӽ9fN?T7@^&% %&%67734257:5,& % 2gg2gk`667&%)"/ 57) ,/), "/, 7 89999999991/990KSX999Y"6$!2#"&'732654&''&&54676654&#"!*5f =TNNJ18o4Rd.M=C<ROfuZڰ0I]H7H+;[L=(A7+/e?1CFkp 4Lb@8-*+'0!5 2+A'*,$0-+$!1837$4-;6-34GM299991/29990"32676654&'&&#32654&'2#'&&###2#"$'&5476$yWWWWWVy{WWWWWXϲ##NOM+i`)Gok&: 1mmllmmmmllmm3WWWzyWVVUWWyzWXV5442wyVpP:NAD7nmmmmnnmmmmn1IH@(  2&>7,- 486 -9DJ21/990&&#"3267#"&54632'"32676654&'&&'2#"$'&5476$+9o9q~r@s.A>EyWWWWWVy{WWWWWXymmllmmmmllmmf%#rs~$#WWWzyWVVUWWyzWXVnmmmmnnmmmmn'R v@>  :   S ;: : ;:91<<2<<9990KSXY"73#######5ww㪉LqKBMPf\10K TKT[X@878YK TK T[X@878Y@ ))<<LL]!#+%Jf7;1u@99991<20K TK T[X@878Y@*    0000 ////????]]3#%3#f111 =@!   o} o  <291<2<2.990!3!!!'7#5!7!^P1}`@M  : u S  91/<90KSXY"]@ %%] !!!!!!!!!yw9s5f9A7Db^++ (6@D(76) ,&# ,'#,u#ud#`72'76) 2 2&(2 7.9999999199999990@             ! . / 0 1 2 3 4 5 6@@@@@@@@@@@@@@ @!@.@/@0@1@2@3@4@5@6PPPPPPPPPPPPPP P!P.P/P0P1P2P3P4P5P6H].#".5476$32%#"&''3267>54'&'(zR**nkaXf--oj\f{'zNs?a_\t5 /B@#  $'!-!0 $<*<099991<999032654&#"&&#"326#"&546326632#"&+vIZqgLHw+tKZqfMGzDaƯZcG_ů[1CDeOMeeCCdOMeia~q~n .@o  o = = <2<21/<<0!!#!5!!!  bb '@  o  <2291/90%!55PN '@ o  <<291/907!!55%  @S  :    S    9991/2<<<290KSXY"!!!7!7'!7!!!!!!:RRA'o%#pH%%h;`LL LLT\`&@W   &#$"% : % "` z'&%  '9999912<990KSX999Y"!3267!3267#"&'#"&'7-hVRfxh'29b-Xc>XJ]`T u(INpu# LROO/0;R)8@'! '!* $$*99919906654&#"#"&54632#"&54324&#"32;'#S0@eID`IFa~q9WzC2EqG Ur|tx)w 0@    91990!!!!5Bl_{Nw@??120!!!!)JD/@    991/<22990#!#!#"663J'7: Ddd>Dǜ3,:@ *# - *(&  @A @-9919026732#"&54&#"#"&54632jciRA@Ae '&>ÄkTF54&#"7>32/'\p>5TVBe}MLXU#bK=9F,4qXT@}LFod ,.##z3^u\ b@ d   DD 999910@,@@@OOOPPP___ JJJEEEXXX ]]2#"&54!!"32654&Ϸ*7&XcFCcGMѹLPKQ7>@    GFG F 9991/<2990!!654&#"!!&5! #~˲˄~#~zx89xz#VˤUy9yǤ#{ @J@T7@5= ,&A A5&%"g5) @G=g/)`KJAD76 ,:%&D5:@ 2:D2K9999999999912<<<999990@6; ; K K [ [ k k 2?0@B?@@R?P@b?`@?@?@?@]]"326?>32>32!3267#"&'#"&54$!37>54&#">54&#"QGnuh9_Ղ p5BuK<|xr^aQi%SQ=Fy)JIMMI-\/9mlCD0/ghif BC..  P^to$+{@@$,+%("(#(ii`,+#, %+ +" $+!! ,.99999999199999990&&#"&&54676$327#"&''3267E- ''[WdhDa))ZVemD`E/J;L~duw..o;Octz12pL!@M !!!:UT Y] i` S"  !  "9999919990KSX9Y"!3267#"&54677667%!!h VKPFPLPr=`jLS8Fh3P{f<=h69=DA*(wfK@/91/90!!!#-3mV?}' 4@     991<290772+Z%L1+Z%'qsqu' 4@     991<29077%%77%%7u1X+#L1X-#^ y@=    :T     999991/<<220KSXY"!!!!!!%hKhKBhL}}}{k'$Du{m'$DuJm'2uV ; !@8    : S   !  "91/220KSXY"]@ ## #0#`#p## ]#";!!!!!!# 476$3iLqkh9u8g9A9y7`Ѐ;/1J.zIFJo{ 3?j@:+( g:i g4i.(`@ 1 +=1=17!" @999999912<99906654&#"!3267#"&'#"$54676$326632"32654&`Ri%# p7:Z։[Ue@^ a]a  P^un9mlDC0/NRRNcuwQQQQ(]Bjoin@ q9910!! 3@ q9910!! 3X7 f@4     : S   H  991<20KSX99Y"!3!3X7'ը:'ժX``X b@2     : S H  91<20KSX99Y"!#!#T7ըT8ԩ``X9@:S910KSX9Y"!3;:'ժX`X5@:S10KSX9Y"!#wT8ԩ`V *@ on IJI <<10!!!!!!33Xˁ#uv@A:91990KSXY"  9%-F1'\yk'<ud10#3 J=#/@H ! ! $!* 00   'LKM-L K022999999122999990'7&&5467'766327'#"&72654&#"ϙљ0l=6l9ϘϚ.j?:l[\[~ Ϛ1k??l.͚Ϛ7n6?i/ϙ\\\]~}'@919071+Z%'qN'@ 9199077%%7N1X+#fb@c  : i gkz  &N&991/<22<2990KSX9Y"K TKT[KT[KT[X@878Y?]]!!!!#"!!!#37>3h9h/KE /1Ѩ2%ܐ7CO`Nfb@L   : i gk z    N&991/<22990KSX9Y"K TKT[KT[KT[X@878Y?]!!!"!!!#37>?#KE /1Ѩ2%)7CO`N;@F       : X S       .9999991<2<20KSXY"!!!!!!!7!!7!JJ!-X#/JI/!X-!<}`/@:T910KSXY"!!hL}5@:T10KSX9Y"!#T8ժ`  b@2     : T H  91<20KSX99Y"!#!#T7ըT8ժ``q 5 #/3?Kb@7 eFe:a@e2e$a0*`42dL1C=3'!    - ! 'I 7 'C =L9912<<22202#"&54"32654&!"32654&'2#"&54#3!2#"&54"32654& ۜם Vn=>Wm>$Vo=>Wn? ֝ k֝ Vn==Wn?魍WWUWWWUWꭍ ꪍXYTX{k'$Du+\k'(u{k'$Du+\k'(u+\k'(u+k',u+k',u+k',u+k',uJk'2uJk'2uJk'2uTk'8muTk'8muTk'8mu?`0@:z& 91/0KSXY"!!h`f8@ 991290K TKT[X@878Y!#'#!f9@"    91999999990K TKT[X@878Y@(         (]]'&'&#"#>3232673#"&{1&"4 ^$C%5"&4 ^"<T%E<+C>=X,9910K TX@878Y!!bw%TFo@  91<90K TX@878YK TX@878Y@   ]332673#"&546WVPQh"͜F AFGI|y;-1K@ 9910K TK T[X@878Y@  00//??]]!!11y @@  KK10K TK T[KT[X@878Y#"&546324&#"326wxxwTABTUAATxxxxATTAAUT-o#@   991/0!#"&'732654&'%"1a3(Q&BL4X*hs 9/E7%f@ 1<20K TK T[X@878YK TKT[X@878Y@-   0000@@@@]3#3#ɮbfxoF@@  991/0@IIIIYYYYiiii ]!33267#"&5463G41-%R+9Z'joJJP"& EBA~59fP@ 991<90K TKT[X@878YK TX@878Y!373x `@6    : S    .9991/90KSXY"!%!!'%eTi N7bh=iJׇ @1: k   .9991/90KSXY"KTKT[KT[KT[KT[KT[K T[K T[X @ 878Y / ]!7!'%hfdu` NˑVDˇRk'6uf'Vbk'=!uf']T@ <210##  m p@:    : S      .9999991/<20KSXY"!]3#3 4&#! )#393F;0""`adk}3/#EQQ{m\Jm,@c*+,+)(),,+&'&#$#%$$#'(&%&(#$#(( !"(:,+*)&%$#'"'i i`'k-*+,) %$'&#" + !! -99999919990KSX9Y"&&#"32654'4#"$5!2''%'!%4f4d^@A[Wel%1W$#T`R#ms (j\tdtx] l^tj^yk'<uFf'\+j@: :u uS  9991/0KSXY"!32##!32654&#N+ WSY9BP̈eb׿uOVN\zRVVj@L:ii`k  !  999991990KSX9999Y"%!!6632#"&"32654&shuRkMH[sAcX_b]ρd~]7\ifk on10!!) /@   <291<290 '7NNNN3NPPN) @0 OO:  b     9991290KSX2Y"]@   ))99JMMJJ]3?33!fۅ9 41Z\sc@!  dP99919990@ 55YY ]]!!7>54&#"7>32y!\nPNA:DG$SElxD :c*(..,mdOTRj(t@- #  #d)   PP& )99919990@        (]#"&'732654&+732654&#"7>32KNP>!:w54&#"7>32#33?33!Dv ^nQMB9DG%SFlw=mfۅ :a))0/,mdOT I 41ZZ(+6:@r*6,6)+),,6)O*)-2-+O2-4O2-3O22-: #)* .*0 9#d40,7`2*)43+5:.120/-8   /-PP& 25- ;9999991/2<299990KSXY" (]@:)+*,(.9+:,9.Y)Y+i)i+         '[)l)]]#"&'732654&+732654&#"7>32 333##7!7#3LOQ>#:w3232673#"&j1!$4 _%A#5$'5 ]&@!% @8) =:`:910K TX@878Y@ //]#hG@ 991<90K TX@878Y@/// ]!#'#\3 M@ 991290K TX@878Y@//// ]!373N3@  1290K TX@878Y332673#"&5N QOHj'Ɣ<7=6}!>@ 9910K TX@878Y@ 0000]]!!/  !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~>: ~1BSax~ & 0 : !""""+"H"e%  0AR^x}  0 9 !""""+"H"`%^ChVjq_8 (Bbcdefghjikmlnoqprsutvwxzy{}|~f+7q9s/) R3 ^;JXf-T3T3\1{+J+w+w+J++3++++J+J)+ub1+ f#?LJmJ{f)??R??V??JJ?X{7d)7Z1{1{Jw++Jf#f#f#f#f#f#LmJmJmJmJ?????JJJJJ{{{{N'?'7` Z;)L'3X^'7b#LVL3}3u^1{1{J VVJ''  7VJL}LNLfLf  ' q1{w+1{w+w+++++JJJ?=Ty-%5HJ7+\RZJ)+JLJLJR3 +`3N   !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~    sfthyphenperiodcenteredEuroc6459c6460c6461c6462c6463c6466c6467c6468""""iE%JbG>lq  < _  Y F M w mEK?Hn+McIgu$NLNh W !{!"q"#,#n#{$ $-$:$G$T$a$n${$$$$$$$$$$% %%$%1%>%K%X%e%r%%%%%&.&'''(3()**w*++E+,- -D-s-..//8/[//01D12t23x334+45'5L556!6!6.6;6H67Z7v77848c8899"9/9E99::;:;;;>u>>?#?i??@6@p@A+A8AEARA_AABBBCCCCD8DE EF{G`GmGzGGGGGGGHpHHI5IqIJ J6JlJJK` R79k:;2<$&$&$&$&$&$2$7<$8$9u$:$<$F$G$W$Y$Z$\k$d$g$h$o$$$$$$k$$h$h$$$$$$$$k$$$$$%9%:%<%%&6&&'&'-Rfpgmp9)gasp glyf4h)&hdmxEHheadO$6hhea. $hmtxy,kernlocaXz[maxp} nameYͿpostx<prep|a!\::N:: R^0p   t t  &   ; 0  0   C , [ `   0 & Copyright (c) 2003 by Bitstream, Inc. All Rights Reserved.Bitstream Vera Sans BoldRelease 1.10BitstreamVeraSans-BoldCopyright (c) 2003 by Bitstream, Inc. All Rights Reserved. Bitstream Vera is a trademark of Bitstream, Inc. Permission is hereby granted, free of charge, to any person obtaining a copy of the fonts accompanying this license ("Fonts") and associated documentation files (the "Font Software"), to reproduce and distribute the Font Software, including without limitation the rights to use, copy, merge, publish, distribute, and/or sell copies of the Font Software, and to permit persons to whom the Font Software is furnished to do so, subject to the following conditions: The above copyright and trademark notices and this permission notice shall be included in all copies of one or more of the Font Software typefaces. The Font Software may be modified, altered, or added to, and in particular the designs of glyphs or characters in the Fonts may be modified and additional glyphs or characters may be added to the Fonts, only if the fonts are renamed to names not containing either the words "Bitstream" or the word "Vera". This License becomes null and void to the extent applicable to Fonts or Font Software that has been modified and is distributed under the "Bitstream Vera" names. The Font Software may be sold as part of a larger software package but no copy of one or more of the Font Software typefaces may be sold by itself. THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL BITSTREAM OR THE GNOME FOUNDATION BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM OTHER DEALINGS IN THE FONT SOFTWARE. Except as contained in this notice, the names of Gnome, the Gnome Foundation, and Bitstream Inc., shall not be used in advertising or otherwise to promote the sale, use or other dealings in this Font Software without prior written authorization from the Gnome Foundation or Bitstream Inc., respectively. For further information, contact: fonts at gnome dot org.http://www.bitstream.comCopyright (c) 2003 by Bitstream, Inc. All Rights Reserved.Bitstream Vera Sans BoldRelease 1.10BitstreamVeraSans-BoldCopyright (c) 2003 by Bitstream, Inc. All Rights Reserved. Bitstream Vera is a trademark of Bitstream, Inc. Permission is hereby granted, free of charge, to any person obtaining a copy of the fonts accompanying this license ("Fonts") and associated documentation files (the "Font Software"), to reproduce and distribute the Font Software, including without limitation the rights to use, copy, merge, publish, distribute, and/or sell copies of the Font Software, and to permit persons to whom the Font Software is furnished to do so, subject to the following conditions: The above copyright and trademark notices and this permission notice shall be included in all copies of one or more of the Font Software typefaces. The Font Software may be modified, altered, or added to, and in particular the designs of glyphs or characters in the Fonts may be modified and additional glyphs or characters may be added to the Fonts, only if the fonts are renamed to names not containing either the words "Bitstream" or the word "Vera". This License becomes null and void to the extent applicable to Fonts or Font Software that has been modified and is distributed under the "Bitstream Vera" names. The Font Software may be sold as part of a larger software package but no copy of one or more of the Font Software typefaces may be sold by itself. THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL BITSTREAM OR THE GNOME FOUNDATION BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM OTHER DEALINGS IN THE FONT SOFTWARE. Except as contained in this notice, the names of Gnome, the Gnome Foundation, and Bitstream Inc., shall not be used in advertising or otherwise to promote the sale, use or other dealings in this Font Software without prior written authorization from the Gnome Foundation or Bitstream Inc., respectively. For further information, contact: fonts at gnome dot org.http://www.bitstream.comf3f=ffTbfTfmf3bq%fHZfm99Xm=fuff9{{X3fLfLJ#DDf?;Pw /X#/553X sf+j-j!f#^`3B3\fy```{j\{`bXP1L`%!JJ7{'}3Xy9bsA&%$!:$#"!:"!: d}}      Y    & Y @ &  .A@}>,,G}G  @ 2 d۠d%%%   %ё%Д #&̑ɻ]ɻɀ@%]@%dĐ::2  }& @ ]%]@..@   K%%%2 ~}|{zywvwvututsr}qpo,o,nmlkjihc h2gf2ed ed d@cb c b a`a``_ ^]\\[Z[ZZYXWV@VUTSRQRQQPOPONONMLKLKJKJIJIHGFGFEDCDCBA%BAA%@?@?>?>=< =< ;d:987656%54554 4432 33@2 10100/ .-,:-,%,:+d*d)(''& %$#@+$#" "!!@  %@ K}K%%dd   2     @   @d  d++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++, %Id@QX Y!-,%Id@QX Y!-,  P y PXY%%# P y PXY%-,KPX (EDY!-,%E`D-,KSX%%EDY!!-,ED-ff&&/10!%!!fsr) @ <2991/0!!!!h33h^h@1<20###h++)K@1     91/<2<<22<<220!3!!!!#!#!5!!5!!!`aaE````HFR`PF#*1s@? %$ + ,#,, (/($ +/ 2<<991/99999990#&&''&&546773&&'6654&}osy!dede GUNWWP-.);?7* "*/(BE5;CBBDCB '3c@5  % ."( 41+  1 +%49912<0KSXY""32654&'2#"&546#3!2#"&546"32654&3GNMHHLMGֺ%պպHNNHHMNh{rs{{sr{ؽ۽ ٽڽ٨|rs}}sr|{&06@Y     ,-./+0()'%0' - -! '*$ 0$*$  *  199999991/99990KSX999Y"']@   ' 0   0%/ / %&? ? @K K K/K0ZZUZ Z U(\.\0X2_2dig`i i d&2, ' '* 9 5005@J I'I(WW\ ['ggl ]] >7!!'# 5467.54632.#"3267577oc%Xbi*([k^PMU1ABwCt2>FnkmFDےj5j:0.;6"W/wGs))@ 10#+ @ 29910!&547!י);: @   29910654'!)?C)9F@(      <2<29912290%#'%%73%JLLNLNMXX "@   <<1/<<0!!#!5!    m9@ 10!#hduo10!!ot91/0!!h}B/99103#mb/ #@  10&#"326! ! i||jj|{j@'&@mstm (@  1/20!%!!!T[nT HH5@)% 9991/2990KSX9Y"K TX@878Y@&**"""555BJFF]]!!>54&#">3 N!IFuZzz )~B~DiMLH+-zӱ(L@+  #)& )999190!"&'32654&##532654&#"663 sqlg~]^rl#!%'%%)67jcfi[]V^*) \3 C@ !  ! %    <291/<290KSXY"!!3#!!Z@jRJ=@"  " 190!!663 !"&'32654&#"v,Y00{zaSl 12/FFuv+-# $7@ "% %$%190"32654&&&#"6632! !2eeeefeev_PB[uEgჃ-+11ir E@%91/0KSXY"]@ &5F]!!!e'1} #/G@( '-0 $*& '&!$0991990"32654&%&&54$! ! $54632654&#"lttlkrr|כc\ZbbZ\cvnnuunou)ž)*ސUY``YY_`j$7@  %%" $%19073267#"54! !"&2654&#"\RDZ9$@ieffeeff!++22 "vYN`@<21/0!!!!ii`}}N` %@  <210!#!!idiu}=@29190 5<'@ <210!!!!=@<91905511J!H@'    "<299991/9990!546776654&#"6632!!Bj@95`VQfy]N^@D*i1Rb:4\.FOCB:*(ǿbY9>K-o Ml@: 40LM3 30 07$CN34L **)(I(*)4=N<991299999032654&#"#"&54632536654&'&$#"3267#"$'&5476$32!#?iZYjkZXiYثY|:;_tZked~Yk}٘~~On{KM'{zyZGOPGKɝdIz=;bɵdbg^Pag}}IJ}|b~ ' @@     %    91/<90KSXY"K TX  @878Y@ / V f  t   %* IFGH XYVWhifg` t{zu{t      /]]!!!!!F_}))}+%R P@%    !299991/90@ ""/"P"]2654&+2654&+)! [^^[tutuH|B7fPNMQsbcaay$ռmf\;@    - +21990/_]%# !2.#"3267\j}Lu}jksskR78ef87IDDI9.@  -. 99991/0P]32654&#! )=TMwiffixjq#ateeta 0@   21/0 P p ]!!!!!!rg +@ 21/0 P p ]!!!!!rgfK@%    1 3/-+19990_]%# !2.#"3267#!ʥLy}|@   221/<<0@P ` p ]!!!!!!89+y=71/0KTKT[X@878Y@P]!!+f= L@   991990KTKT[X  @878Y @ P ]!!#3265N3IO@UZfi ]]!!!!mR+ff 2@  -7-+10@ /?]"3254 ! f°±hhgddjk 1@   - 299991/0]! !#!32654&#1pzzp_mddlffb@   - 7-+999190@,  '/V S f ` w w p  Y Y YXj i x ]]# ! !"3254fgk-¾lkh\@2%       29991/<9990KSX9Y"]@66EEVVPee`]2654&+!! !.#yiiyL'O}@f7q^?ZgfX֔-XspR-'@*% %( "(999919990@Tp)9999 JJJ X ]\^^ Z!joooh o n!t t t || |!  !  !(]].#"!"$'32654&/.54$!2{hYuӎ⏏ |~[ {78LP@881/20K TKT[X@878Y@ ]!!!! `N3@   91290@p]!3265!! yy6= '@'%91/290KSXY"K TKT[X@878Y@,  GGHHEJWX]]! !! 5N+= x@J 6  6 6 6   %     91/<2290KSXY"K TK T[K T[K T[X  @878Y@  % :?:?3 0 0 @ @ @ ^^a          '('(%* /66220002 4 6 ?IFHE J ]]ZZUURRRZ U ] ooonhheh k n i o wwx v x   K]]! ! !! !=qsnDD==+o' @E    %     91/<290KSXY"K TKT[KT[X  @878Y@X  /& <3 _P      ++%$%+ :55: P ejo  ]] ! ! ! !omGF@(%:: 91/290KSXY"K TK T[KT[X  @878Y@, %%0@P` %*5:0 O o ]]! !!TTu\q w@% 991/0KSXY"K TK T[X  @878Y@ %)69? FHO V_ o ]!!!5!s8!7@210!!!!mB/99103m@210!5!!5!m`@ 91290##fg--/10!5۾^fN10K TKT[X@878YK TX@878Y] #yfxX{ %@*   # # = ;&229991/9990@L/'= =!?'M M!] ]!n n!~ ~!p' ! ! ! !20C@SPc`]]"326=%!5#"&54$!354&#">3 pq[QeiH"ӆsUst/ LJDMm)f]ˢŸUO..^ 8@ B@ 221/0O`]%2654&#">32#"&'!!syyss{{{Ju uJf稠b]]bX5{7@ B ;210_].#"3267# !25IOT@TWV/X=202177\8@ @B ;221/0O`]!!5#"322654&#"hJu tsyysryyXc\II]ɨX {C@!    D ;9190/?]!3267# ! 4&#" q}K"=w`h3f~~CD015:“f}un'`@    E <<991/22990K TKT[X@878Y@ ]#"!!!#35463L<27DN`N\Fy(K@& #& @ B;)221/990O*`*]%#"54325!!"&'3265"32654&Ju uJhic^[o|xsp||b\CA\c !655@   G 21/<9990`]!54&'.#"!!>32 H.pfQnVon#'b])@ <21/0@ P ` p ]!!!!ff`F =@    <2991990@ P`p]!+53265!!fͱ>fLf`\y @   291/<90@`;IIZ]X_ogvv{:DGJV]g`ewpv|]]!! !!fNNK- 1/0@ P`p]!!f{%t@)   #  H H &<991/<<<29990KTX&&&@878Y@'0'P'p'''']>32!>54&#"!4&#"!!>32DpFNfo@RgphBgthmVH wkHk`_`p{5@   G 21/<9990`]!54&'.#"!!>32 H.pfQnVon#'`b]X'{ -@  BLB;107?G]"32654& ! w}}wu||u!EG{88V^{;@B @ 2210O`]%!!>32#"&"32654&fJu us{{ssyy b]]7\Vy ;@  @B;2210O`]"32654&#"325!!ryyrsyyyJu uJhw+c\IG\c{C@     21/990KTX@878Y.#"!!>32/]/fE}*(/`nejb{'@@  6  6% %( SRP"M(9999190KSX99Y" ]@^ #  ,. . . . . ) 9; ; ; : : K J J J H w w  %  7 ?)_) ]].#"!"&'32654&/.54632s_fcKa?o}ktijIm?c=0035+. ###44:90/ x@    T<<991/<2990KTKT[KT[KT[X@878Y@??PPP`` ]]!!;!"&5#33q>\Ա%N7>`;@  G 291/29990`]!3265!!5#"&hG.pfQmp[.w#&)b]`@'%91/290KSXY"K TKT[X@878Y@| 0@Vf  &$+)64990FFII`x$]]! !!fgGw`H` @J 4  4 4 4   %     91/<2290KSXY"K TK T[K T[X  @878Y@ 550 G @ @ _ l        &$+)*+ $ % /554;::78 ?GIFHGH YVV[ T Y _f`b```d ` upspppt p      []]!!!! !H\+\yy` ` @F    %    91/<290KSXY"K TKT[KT[KT[X  @878Y@  / 3< CL R\ bl sz         2     $++$ 4;;4 0 DKKD o       :]] !! ! !l{{l=#LbF`A@C %    9129990KSX9Y"K TKT[KT[X@878Y@ @Pet $$$5586699EEJJEEge    9]]! !+5326?f-f)Gp[S `6:K\F` @% 2991/0KSXY"K TK T[X  @878Y@DYVifyv &)/ 9? J_ ]]!!!5!uNN`f$^@1 %   ! % $  %<<29999999199999990#"&554&##5326554633#"3l==lEUZnoYUmutWW10#$`@2%   #%# %<2<999999919999999032655467&&554&##53233#"##FUZooZUFl==lmWW͖tuR#@  1990#"'&'&'&#"56632326j`k^Xbk`k^VRPE:=MSPE:=K 'k'$u 'm!{@S!! ! !%! !  UU "9999999991/<9990KSXY"K TX"""@878Y@/!/!:!o! !! # ///  /// "+ #EKUZ` ` ` ooo``ooo`fi `#tuyz{t    D]] !!!.54632%32654&#"!}^_}vtwM66MN56MJH"K+uu/L{6MM66MMRfo\'&sk'(um'15uffk'2Nuk'8'uXf'DXf'DCXf'DX1'DX9'DX'DXo5{'FX f'HX f'HCX f'HX 1'Hf'wf'Cwf'w<1'w9'QX'f'RX'f'RCX'f'RX'1'RX'9'Rf'Xf'XCf'X1'X5; *@  WV W <<1220!!!!!5!VJ#!/dL @  XYX10"32654&'2#"&546HdcIHdeGBz0/11-0|D\dHHbcGHd3/0xDCy-03#W@.    !$   B$<<222991<9990&&##667###$4%3NMMNJAY9S: GZ,lm*902i2/  (.##}@@!   <<1/222990&&#"!!!!3#5356!2FMvqu\'&} F=3?k@8@1:4 %+1@ =!+%74:!=\.!\=[.7[(@9999991999990&&#"#"&'532654'&'&&5467&&546326654&uc9KL ҟquMKUfs9AN$ˠoqKATDC{AF''1/CO Y}u0)qI)+2(FJWh33oKL2CbBO4Cj'` ]104676632#"&'&&'535II245633JI326J235624IJ336633;d &@ ^^9120!###&&54$\fN۲h0j@4.(" !++/"!(%  a%.(a_ . 199991/990@ /2O2p22]4$! #"&'532654&/.5467.#"! 1]EtkAJ8s6HX7bFXT`[efZG NJ%94%@uH9/D7'1Zt2UYnm 4Lb@8-*+'0!5 2+A'*,$0-+$!1g3f$cX;eX3cGM299991/29990"32676654&'&&#32654&'2#'&&###2#"$'&5476$yWWWWWVy{WWWWWXϲ##NOM+i`)Gok&: 1mmllmmmmllmm3WWWzyWVVUWWyzWXV5442wyVpP:NAD7nmmmmnnmmmmn1IH@(  2&>f,X c8e XhDJ21/990&&#"3267#"&54632'"32676654&'&&'2#"$'&5476$+9o9q~r@s.A>EyWWWWWVy{WWWWWXymmllmmmmllmmf%#rs~$#WWWzyWVVUWWyzWXVnmmmmnnmmmmn'R v@>  %    ji i ji91<<2<<9990KSXY"73#######5ww㪉LqKBMmf710K TKT[X@878Y]!#f;;1\@1<20K TK T[KT[KT[X@878YK TX@878Y3#%3#1 =@!      <291<2<2.990!3!!!'7#5!7!^P1}@7%     /<291/<90KSXY"K TK T[X@878Y@&W ] !!!!!!!!!{y}sfb^- +@> +,   )*&& &,+,* # )-#7-+,99999999199999990@p- -*'&!/-976!9)?-GYVT!Y(Y)jege!j%j($'))68)KFE I)Z^SVV T!V"[(j ejlaf c!k(x ]]3254&/.#".5!27!"&''\4SM3RJJgfqMLhfqs>;Du1:9@q.dkKMscdOOq /B@#  $'!-!0 $k*k099991<999032654&#"&&#"326#"&546326632#"&+vIZqgLHw+tKZqfMGzDaƯZcG_ů[1CDeOMeeCCdOMeia~q~n .@   l l <2<21/<<0!!#!5!!!  bb '@    <2291/90%!55PN '@   <<291/907!!55%y@B  %     nm n m<2<2999991/2<<<290KSXY"]@, $+6:FI   0@ ]]!!!5!5'!5!! !!!!N9:1k$! %j1`BV3VBT` :@!  !   !2912<990!3265!3267#"&'#"&'idfgdh!'!5]-Yq#/YJhT utqqtG8 KSOO/0;R)8@'! '!* $$*99919906654&#"#"&54632#"&54324&#"32;'#S0@eID`IFa~q9WzC2EqG Ur|tx)w O@    91990@ &#)  ) ( ) 8 ]]!! !!5 Bl_{Nw@pp120!!!!)JD/@    991/<22990#!#!#"663J'7: Ddd>Dǜ3,B*# @- *(&  qr q-9919026732#"&54&#"#"&54632jciRA@Ae '&>ÄkTF32-ӅhB:Yr 7^YUWO\K=4>3:rWT@LHt8;##uu 9A  @  uu 99102#"&546!!"32654&B7T[[TS[[޾ܾM~tt||tt~7F   @  xwx w 9991/<2990!!654&#"!!&5! #~˲˄~#~zx89xz#VˤUy9yǤX{>@B8>66'&# 6-*>;0*? - 6 & 7 3;?<9999912<<<9990@N>>?@MMO@^^_@nno@@@2=0>B=@>R=P>b=`>=>=>=>=>]]4&#""326=>32>3 !3267#"$'#"&54$!354&#"w`gpq[Qe^waGMz =q}~Heߋ"ӆsUf}unLJDMm)JMOMOf~~CD01kdkdŨŸUO..N) +@> )+ *& &&++, #* #)B#LB;,999999991/9999990@@:5 ;75!8)?-IF KGD!H)[VT!U(ikfe!e(5:)EJ)U^(i em( ]].#"32654&'.5!27!"&''XK/w}HO0u|;CDG"jKmFElMpD)A+CN{8,,eP~--^!M@*   "  "<2999919990!3267#"$54677665%!!iAm@84`VQew\N^@D*ii1Q~d:3\/FPDB*(ǾcX:=L-d @ <2991/0!!!33h=^qd@ 10!#!LZ n@*      %  @  9190KSXY"3##'%`w͑%hN7V7#w@I #"!   %   !$2299990KSX92Y"&&#"!!#"&'53267#5!766327.T*Zd!)AD.U)Ycu!3*Bs_sM#;C@!.9* 1 "9*1<-<<219999990#"'&'&'&#"56632326#"'&'&'&#"56632326j`k^Xbian ^Vgj`k ^Xbk`k^V#PE:=MSNE;=KPE:=LTPE:>K  @ /91/90!!!#-3mV?j' 5  @  y y<2991<299055%$'qsq' 5  @ yy <<991<29905-5%%%!$'^ #@   1/<<220!!!!!!hhh}}} 'k'$u 'm'$uffm'2NufP@"     -+ 299991/220@ !!?!O!_!]# !3!!!!!!"# !2i iZhsf / F& 0ihX^{'3t@2"  .(%4"1 1 +B;499912<9990@/5?5O5O5_5o5o55F"]]4&#"!3267#"&'# !2>3 %"32654&w`hA q}~~HRՂG"QRLJBcw}}wu||f}unwf~~CD01QWTT88RVWQ:/10!!/10!!X +@    1<20!3!3!ddXb`Xo + @  1<20!#!#!TeTe`^X@ 10!3'dX`X9@ 10!#Td`V 0@  z{z <<10!!!!!!33Xˁ#uv@A%91990KSXY"  9%-F1'\k'<uh+@55%10KSXY"#3 J=#/@ ! ! $A !* @&00   '}|~-} |022999999122999990'7&&5467'766327'#"&72654&#"ϙљ0l=6l9ϘϚ.j?:l[\[~ Ϛ1k??l.͚Ϛ7n6?i/ϙ\\\]~'y291905%'q'y<91905%%$'+Bu@&       ET<2<<991/<2<2990KTKT[KT[KT[X@878Y@]!!#"!!!!#35463iJK:k$7DN``N'Bl@!      ET<2991/<22990KTKT[KT[KT[X@878Y@]!!!"!!!#3546{L<)7DN`N3;?@!   W VW <<<<2912<220!!!!!!!5!!5!VJ###!<}910!!h}L@ 10!#Te`F + @  1<20!#!#TeTe`^B V #/3?K|@C3 2211 003%@ *$F4 :02$L3IC1!  C=!'= I7' -L9912<<2220KSXY""32654&'2#"&546"32654&'2#"&546#32#"&546"32654& HNNHGLLGֹHNNHHMNGպֺ׺GNMHHLMh{rs{{sr{ؽ۽8|rs}}sr|ٽڽ ؽ۽٨{rs{{sr{ 'k'$uk'(u 'k'$uk'(uk'(uk',duk',du)k',du=k',duffk'2Nuffk'2Nuffk'2Nuk'8'uk'8'uk'8'u` 1/0@ P`p]!!f`yf6@ 91290K TKT[X@878Y3#'#Dzf\9@  @  999919999990K TKT[X@878Y@T              ( ]]'&'&#"#4632326=3#"&7/$&g]$I)=%$(g]$CT%>;+@9X;E10K TKT[X@878YKTX@878Y!!vPF i@  1<0K TKT[KT[X@878YK TX@878Y@]332673#"& cSSc FFJJFw;1*10K TX@878Y!!w1 C @ : 10K TKT[X@878Y32654&#"4632#"&}M67LM67Lvvvv7LM66MM6vvvo5@   991/0K TX@878Y!#"&/32654&'Z:7{0f42S!:A+->j/_[ .(R<fE@991<20K TKT[X@878Y3#3#-fxVo@   991/0!33267#"&546ō2&;1'M(7^)s{6CI'1 \V5myf6@ 91<90K TKT[X@878Y 373Dzx `@2 %    <<.9991/90KSXY"!7!!'%s۔#` j ~@-   %    T <2.991/90KSXY" ]@ut@ P ` ` tp p  ]]!7!'7ho}o XV-k'6ujbf'Vb\qk'=u\Ff']T@ <210##  !L @   -. <291/<20@X!P!`!////////OOOOOOOO________(]]3#32654&#! )#3PULxhgghyk#ateetamX'(@Y&'('%$%(('"#" ! "! 5((5(%('&%"! ## #)'& !#(%" BB;)999919990KSX92Y"KTKT[X)@))878Y@6f!/*76"?*O*oooooooooo]].#"32654&! 4!2''%'!%7l4uru| uj-.N$%3`ox#y-\8 watr`k'<uFf'\ @  - 2299991/0K TK T[KT[KT[KT[X@878Y@,0000PPPP]]!!3 !32654&#=1pzzp]mcenV^;@B @ 2210O`]%!!>32#"&"32654&fJu us{{ssyyb]]7 10!!) /@   <291<290 '7NNNN3NPPN{ 7  @   129035733!9 41Zm]@%   "@99919990KSX9Y"!!56654&#"56632r_9=4I;>TWKGeD 5P(2>-/oHyVZ(W@ #  ""#@#)& )99919990#"&'532654&##532654&#"56632P\fQDB<_hkrJTbZNP4{FAWZ`nQ$%@;@=/3--piE`d @     % @    229991/222990KSXY"333##5!5#335733!9y+ I 41Zd'@   %!   $$& !&"@ #%# (9991/299990KSX9Y"%!!56654&#"56632#335733!qt];>3J<>UXJIc 5N'2?-0oH|T I 41Zh 6:@ : 9988 77: %.1* #! #!$-*$!#917@$$8'" :!'"4  '4-";229999991/2<299990KSXY"33##5!53#"&'532654&##532654&#"56632#3'y%]fQDB<_hjsJTb[OO5zGAVZ-D7#nQ$%@;@=/3--piE`q fk'* 1u\FF'J=k', duo-'6job{'Vbf\k'&fuXuf'Ff\k'&fuXLf'F\$K%@"      @"B;%<<1/<20O&]!5!5!3#!5#"322654&#"FhJu tsyysryyrr+c\II]ɨo10!!ot910!!h}1r@;.*(1.!2*("%!) 2 +) )% 2229999999999122<2990%# '#73&&5467#736!2&&#"!!!!3267_pKXbXMep_Qc-VY2~cTR78 87NO{v$$ zzOO;@ 1<203#%3#mN810K TX@878Y@ //]!#3\#@  @! $  $999991<29990K TX$$$@878Y@\             ##+]]'&'&#"#465463232653#"&8- (kW%J';'%'kW&F#<2j'<9j810K TX@878Y@ //]#yE@ 91<90K TX@878Y@/// ]!#'#f4߲DzyK@ 91290K TX@878Y@//// ]373f߲DzP S@  120K TX@878Y@///// / ]332673#"&`LL`=<<=w*10K TX@878Y!!w  !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~>: ~1BSax~ & 0 : !""""+"H"e%  0AR^x}  0 9 !""""+"H"`%^ChVjq_8 (Bbcdefghjikmlnoqprsutvwxzy{}|~f+B{s/) mRo b\}j331 fwwf3ff)u 1 =+'\^fXX\mX{'\RVX\j7dH)7\1 1 fwffXfXfXfXfXfXXmXmXmXmX<XXXXX5}''m-Z;)L'3u'7bXNVL++1 1 f VfXBB  7VhJLL+'3  B B1 w1 ww)fffwV#j\\!X7{mZHdHdHhf\jfXfX\Ro mw   !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~    sfthyphenperiodcenteredEuroc6459c6460c6461c6462c6463c6466c6467c6468%%%%Nq] 6 N{U?u<_O K G E a > *2e:\u#p|$Z<~*Z@!I"dqjw   - : G T a n { !!]!"""##$.$%!%K%%&H''n''((()6){))*<*++p,5,-8-a-}-.B..//\/////00001161U1t112 2292233v344-4L4~5*575D5Q5^5k5x5555555556 67667H7k778'8W889-9:9G9T9a9::::;O;;;<>>>>>>??????@4@T@AA@AuAAB 79k:;Y<$&$&$&$&$7a$8$9u$:$<<$Y$\$h$D$D$$<$r$r$$$$<$%9%:%<%%&/&6&&K&K&&&&'&'<6B<;:6B:S9@p8}76B6-6B543:20 /-,+-+1*))#('&'d&% %2$ $}#:#" "!!    @  @:%d%%A%:  }    :-:-  @d++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++, %Id@QX Y!-,%Id@QX Y!-,  P y PXY%%# P y PXY%-,KPX EDY!-,%E`D-,KSX%%EDY!!-,ED-ff@ D/10!%!!fsr) @-   :HF 991/0KSX9Y"K TK T[KT[KT[X @ 878Y3 #3#Z2q1qe@IF1<20#!#o$++/N@4L L    91/<<<<<<<2220!3!!!!#!#!7!!7!!!h$igP'RT$hggh%JT'Pf8T%aabbND /`@9 $ KOM+* K#M-*',+ -#$*  '09991/<2290%6654&'&&'#&&'7&&54$773Xfs_l""VOT;d;tS"\jX/d,ZgT\ZdFO.2U -/*>D$~ #/3O@,W*WRW!W*R1$Q0V40-2 '  ' - 49912<0"&54324&#"3264&#"326"&5432#ሟ躈HNMp~QKk\LMoQKk纈.ñ ij­\dkjí]dò   ` 3@T// ///:0 /& Z&%Y)Z"VQ 0/&, % 3,3  4999991/9990KSX999Y"]@X *: It      % & %&+)*%*&6 9%9&6/KIkxu/]] 326#'#"$547.5467>32.#">7Vy}^n-gjj.+ExNQ#KF|&EKjXgA[lSUڴt._6Dz2RZ$$/1d,VXOzo@ IF10#o+j @ \   99910#&5jLL\ZəE)G#N !@\ 999104'3 KL\ZKS7=JN@,  ] ] V    <2<2991<22990%#'%%73%g:r:g:PrPbybcy #@ `  <<1/<<0!!#!5!-Ө-Ӫ--@:bH10KSX9Y"K TK T[X@878Y@%%55FFVV ]KTX878Y73#!ぐ@\?@ c9910KTX@878Y@ __oo]!!}w{Q@:H91/0KSXY"K TK T[KT[X@878Y73#1jBj.@:F910KSXY"3#mf#D@d dV Q$! $10K TK T[K T[X$@$$878Y2#"547>"3267654&e[]g\\L7\murP7[ku}QOuХQOѥd T@* :ddFd   99991/20KSX2Y"7!7%3!!J#sI }HHժ@,:eY dVd 999991/990KSX9Y"K TX@878Y@( ,,eyuxy '4Ucv]] !!7>54&#"7>32{#7!qn_%|`rרBu]azDA12Щr+@+ d!KXd+KX(dVQ!g,!  "+ %,99190K TX,@,,878YK TKT[KT[X,,,@878Y@aff*a++]]>32#"&'732654&+732654&#"Dnd跡~vslR^c%^d`l &$}xL:9%%43ˢhq^g))% @;   : d F   991/<290KSXY"K TK T[KT[KT[KT[KT[X@878Y@$:  +*) :89 6 f yu ]]33##!7 !q!CD^'7f3`) @6  :dKOddFQ!   !999190KSX2Y"K TKT[KT[X!!!@878Y!>32#"&'732654&#"H._1{qPZg%\^OZը޾\@E --갂%% *@# d dk K hj(VQ+ "+9190K TX+@++878Y@`z{J J JJ*Z Z ZZ*j j jj*z z zyz* * * * * * * *-]]4&#"326.#">32#"5476$32pӁr":U>IpkfFimbg%N)ﰄ:&(UWӲ_AF@:dF991/0KSXY"K TX@878YK TKT[KT[X@878Y@ ')Zhxy]!#!'V+D /c@#$d dd*VQg0$' -'!0991990K TK T[KT[X000@878Y4&#"3264&#"326#"&5467.54$32˛gtsqxگin-qrD_ttdz+{Ӱ"$lŘZ*@("K"d kjh(dVQ+% +9190K TX+@++878YK TKT[KT[KT[KT[KT[X+++@878Y@FFFdddd ]?32#"&5467>32#"&32654&#"Z%:U>JpjgFhobhܲMDŽp҂r!&(UYӲ^BFvj #k@(:HlH91/0KSXY"K TKT[X@878Y3#3#91l2### @.   :HbHl   9910KSX9Y"]]K TK T[KT[X @ 878Y@%%55FFVV ]73#3##၏1@^M@*````:nm29190KSXY" 5Ѧ`@ ``<210!!!!^O@+````:nm<9190KSXY"55//m!@F  : K!NZHV  !"9991/9990KSX9Y"K TX"@""878Y@ t t ttt]%#7>32#7>?>54&#"11fjkyhT8NojTDm`Ph98gbTB^\{^\YFj9LVGBw4@Z@3 5"!4;or!o%5o ro%.A>  !"4811(A9912990%#"&543273654!"!267# 476$3 "32654&EW)\']RǥUѼhAiāresJLƘIPG0'}rW]rfiGr~wߜp~fy @@    :Z F   91/<90KSXY"]@$ *HIHGWhgw]]3#!# !>`]$+7 l@<:ZZFZs    !9991/90KSXY"!2!!!2654&#!2654&#Zг||TjEƃX-z՜ݨvlf>|aYVS@ ZetZVQ   99910K TKT[X  @878Yo!].#"32$7# 476$32)`}^32.#"326^NƟku)Z_Q]joIO8WUGG^cylۘ-7 }@D     :ZsF    9991/<20KSXY"3!3#!#Zwwˋ#d+97%2@:F91/0KSXY"3#Z+f! K@&  : ZvF    9991990KSX9Y"3##73267V5P!?%󪚾7 @G     :F    991/<290KSXY"]@j$%#675HXkixx  &&%'787=<IGFYX\[hfbbzxx~~$]]3! ##Z{ u7)79@:ZF9991/0KSXY"3!!X!^Ө7 @Q     : F    9991/<290KSXY"]@  )70 JC x  &)(') 2547 5 DGJCI F XYWhfw *]]!!## #Z/B7ž+7 @@  :F   999991/<2990KSXY"]@P' ?6H[j ")&5:=7IWY_ hkw ]]!3!#Ze+R#P@ ZZVQ$  $100%]KTK T[KT[KT[X$$$@878Y"32$7>54& 476$3 ^54& yl}9<^>OO]]``]!!#!y ժ+w@<     : ZQ F   9991299990KSX99Y"@!     4 4 4 4 4 444]K TX@878Y]332673!"$5467=˰ .˴; u=O\#W2@&:F91/290KSXY"]@0*(8GGXWgieyywh]]!33+)  @I      : F    91/<2290KSXY" ]@ ()& ;;3 KF     ')$)+*(- & * 6756 6 8 KGCH G VV gihg g yx 1]]333##H3J-hE  +# M@I    : F    91/<290KSXY"]@ )+) :8; IJI YZhhh y   ''()())& ( 8::665 5 8 FFGGD F H YYXT T X ffehfggfe e f zzzyu u    I]]3 3 # #s7u#h@7:F 9991/290KSXY"]@:(9IIZY{y$5Vj ]]3 3#[ʉf9 P@:ZFZ   91/0KSXY"x]@ w]]!!!7! { =w՚oR\Q@!:oo\9910KSXY"]]!#3!XB0@:F910KSXY"#XmD@ :oo\9910KSXY"!73#7X+ޏ@ F91290##HHu-o10!5fk910K TKT[X@878YK TK T[KT[KT[KT[X@878Y@ DDUgv]#JњfvT`{ +@d  #"$!)*(+:+(!!o (LK{LzQ +"! % %#% ",99991/99990KSX99999Y"0]@.<<O[[jjzz 2C@TPd`tp ]]KTX,,,@878Y@ !"#$+ ]#7#"&54$)7>54&#"7>32#"3267L}"Q9 Zd h] Ѹob$dc1Yc..''!Y~yXd״J%@M  $#$#"$# !#$#$#%$$#:! L LQz$\""#% !#$$%#$&999991/990KSX9999Y"`']KTX&&&@878Y']4&#"3267>>32#"&'#3uU7:CsW89FDpwnHgm2!/SOSmQORm\iƢvNTdc^J{K@KN LKNLzQ  " 99910KTX  @878Y.#"3267#"&547>32J%BPX6V^L]#PY}{TN500>9W}..!!Ϯ%uPR#^%@L   : L LQ z\%"&999991/990KSX9999Y"`']KTX&&&@878Y%#"&547>323#3267>54&#"XJ{vpJfl-xѹtV8;DsW5:EadǦ-wOShabSQTkRMS^{ &@$o KNL |L!zQ' $ #$#"'999910p(]KTX'''@878Y@,oooolo o o o$o%o&]]>54&#"!3267#"&547>32{65x\#cm}yNy "z&,64((ͯ-vJP.i@<      : o}\~      991/22990KSX9Y"K TK T[K T[K T[KT[KT[KT[KT[X@878Y#"!!##737>3d[/Ѿ&Oic/яNƠBV{.@X"#!-.,   :#,K L#Lz,L~ )"/99991/99990KSX99999Y"`0]KTX///@878Y!"&'7326?#"&547>3274&#"32ſ7aH"DV$MvvkGgq) \vI/LUy`+,*TX\ś)sLRi`e:4V|=H@M   :  Lz\   '%$99991/<99990KSX999Y"0]`]KTX@878Y]#>54&#"#3>32u j_ y/wFx \/HT^Ȧ^m$RH/q@*:c\~(%$9991/0KSXY"@ ]KTX@878Y3#3#w-'۸V7@A : c }~\   (...99919990KSX9Y"K TK T[X@878Y@////PPPP```` ]3+732673#)%0-vE/l[3-`GCHZ(H @H))     :~\   % $ 9991/<90KSXY"]@>6STThi ::@ XXWWiljyyy]]KTX  @878Y33 ##ww@"ju#H/U@:\%$91/0KSXY"@]`]KTX@878Y3#wѸH?{+@s    : # L& z~  #) # '#')$,99999991/<<<2990KSX9999Y"0-]@-`-p-]KTX,,,@878Y#>54&#"#>54&#"#3>32>32/dZ{dX{۸#KszT{\+>Zdɡ%?[eɡ`bgrv|!OH{@M   :  Lz~   '*$99991/<99990KSX999Y"0]`]KTX@878Y]#>54&#"#3>32u j_!{ٸ%Mw \/HT^ũ`aj$R^{ ?@LL zQ! "!10KTX!!!@878Yp"]"&5467>323254&#"O?cN?by~h@/3zVW˘CacJV{%@O  $#$$#"$# !#$#$#%$$#:! LLzQ"$~&"&% !#$$%#&999991990KSX9999Y"K TK T[KT[KT[KT[X&@&&878Y`'p'']4&#"3267>>32#"&'#3xR:9DvW59FJ{voJgw(s-TPOnRNRiad˦wOScb ^Z{"@L  :LL zQ~#%"#999991990KSX9999Y"`$]$]KTX###@878Y%#"&547>3273#3254&#"VJzwoHg|$ չ:|uwW7:Cadɢ.xNTbcRMQNRH{@4       : Lz ~   $991/990KSX99Y"O]@ T ][__]]KTX@878Y@@@@@@@@@P ].#"#3>32H)$q۸#Is:߻`ah{(@?      :  KOLKOL&zQ)  #)9991990KSX99Y"K TKT[KT[X)@))878Y@( //)X X X X XX ))99JJYY]].#"#"&'732654/.54$32#IV;{Yv$eZ? [?((cUc53pa"$46tY`;%y^b@>  : o~ }  991/<2990KSX9Y"]@ gyy]K TK T[KT[K T[X@878Y!;#"&5467#733bwMUw>=`". @:7!`>u`@L    :  LQ ~  '99991/299990KSX999Y"K TK T[K T[KT[KT[KT[X@878Y`]332673#7#"&546 h_!{ٸ%Ny c1FU]ȩlbkZ`@'++++:~91/290KSXY"]@,x%75IIgftsu]]K TK T[K T[KT[KT[KT[X@878Y0]33#ä`H` x@J++     + + : ~    91/<2290KSXY" ]@5 ED ST gdvt     ,&( ) $ 6=768 3 6 LHJJII H F [XZYZX feeddf` f v{zyv v   =]]KTK T[KT[X @ 878Y@.    ]]333##/>7T`{{`` @H++ + +  +  +++: ~   91/<290KSXY"]@*)&'%&)) ) + :865579 ; JIGEEGI J VVUVXW ffffefg f f vuvuuw v   J   &+)& 6886 FIIF Xihh wx   ]]K TKT[KT[KT[X @ 878Y ] ## 3;d'w`DNkV`2@F +  ++ +  + + :  } ~ 99129990KSX9Y"]@f& 7 F v w v &$$)9 9 98I I H Hwwwx x v v yy  *]]K TK T[KT[KT[KT[X@878YKTX@878Y+7326?33}jMlC9úhkTzk7ZX` @++:o~o   91/0KSXY"x]@xw]]K TKT[KT[KT[X @ 878Y!!!7!j!s!Kk`ۓ%4@f -.-..-    : 5'- )'.)o'oo'\5)(54.  $-5999199999990KSX9999Y"]@K      % % % %%5 5 5 55H H H HHK K!K"K#K$K%Z Z!Z"Z#Z$Z%%]#";#"&546?47654&+7326?>7>3M^3 yoIQ/UaNG- bq=> /G7.OgKB&5?9m{ D% 2-UKm{'"10#4@f -.-..-    :-5)  )'.'o)o)o\54.  5)('*(599199999990KSX9999Y"732677667&&546776654&##73233#"#N^3!xoIP/UaNJ- bq>>~5F5/OfL@&"2@9l{D' 1-VJn~&"1#@ `` 1990#"'&'&'&#"56632326ian ^Xbian ^V1OD;>MSOE<>LN'$um !@P !  !   : Z S " !"999991/<9990KSXY" ]@8 & 9MW  ( 98HGHW[YXX!gww ]]4&#"326.54632#!# !Y?@WW@?Y69rrIE>`]$Z?YWA?XX%qErrOz$Vu'&7 k'(u7^'1uRN'2TuwN'8uTf'DdT`f'DCdT`f'DdT`'DdT7'DdT`'Dd^uJ{'Fw^f'Ho^f'HCo^f'Ho^'HoH+f'Hf'CHf'H'H7'Q^f'Rs^f'RCs^f'Rs^'Rs^7'Rsuf'Xjuf'XCjuf'Xju'XjV; Y@.:L F   99991<20KSXY"3!!#!7!5Poٰp\]u=  @ V ,-,10"32654&'2#"&546PnnPPnoO@v+..ooPOmmOOp1.-rB!@[     ! : K NKNLL LLzQ"!    "912<0KSX9999Y"&&'667#&&5%3z+I>#/|YBS#AM54&#"#=& Ů*01wRL?AG|/N3aCԭqd۹q޺=%a(H%'^Pr[-NC+RoC~%NZ/8L`@6EBC?2H09JC 9 $HE301BKL?gwyVpMI`3D/IC@&=>:A$104G$ 73D=00*/D0/J21/02#"$'&5476$"32676654&'&&&&#"3267#"&54632mmllmmmmllmm^^``^^⃄^]]^\^BB@zBCFInmmmmnnmmmmng^^^傁^^__^]⃅]^^! "'F >@!   F 4 4 54591<<2<<903#######5Jq7rqr/B^^-f10K TKT[X@878YK TKT[K T[KT[KT[X@878YK TX878Y@VV]3#fqfyF@99991<20K TK T[KT[KT[KT[X@878YK TK T[X@878Y@"@@@@QQQQOOOOPPPP]]3#%3#)''>@" `  `  <291<2<<990!!!!!'7!5!7!}/H{};fըfӪ@L  : ZZZZF Zs  91/<0KSXY"]@-   GIIIGWXgfwuwwy] !%!!!!!!#ʚ!X!8i!>I7Fy 7@B78(&# )562'#Z2Z#V2Q8',(68),  &,5 (,7,  8.99999991999990@$7754709 &5&5' )765]]K TKT[KT[KT[X888@878Y@>IJ J7YZ d j gu { w) D6C7WS6S7`6`7w q6q76767]].#" 32$7>54&.5476$327#"&''-b\>A u3c[>? ''zm}9TZ((vp˽LZ<=mr-W,DCpz8]PUPMMcIbTRc /<@- !$'!!0 $*099991999032654&#"&&#"326#"&546326632#"&1TevYR1UfvYRF^_HDa^/XZie7XXjeߦ~᧯w .@`  `   <2<21/<<0!!#!5!!!-Ө-}} T@.````:m`  <2291/90KSXY" 5!!@po V@/````:m`  <<291/90KSXY"55!5AǪ\b@]  :    F    9991/2<2<290KSXY"]@85ESww  &&&::GFWUT``v vuu]]!#!7!7'!7!33!!!beXX` 6 ̾Rq 9{3{JD{3V`&@X   &#$"% : % L"Q ~'&'  %%'99912<990KSX999Y"3326733267#"&5#"&'-um  # ,P&BK8i]lV G4]d  TJPNVFh-)6@'! '!* $$*99919906654&#"#"&54632#"&54324&#"32IH7$$0e՘ݢe WOmVPmmWKt,>bFأ[t}t{w; [@    91990@.UPQVPb`g`e`tppupx V pp]]!! !!5 7AJI3!wq@77120!#!# }/#i@1 " $ #" #8#$9999991/<229990@ ]]#3267#"&5467!##"#>3!i/7.%7vy"Pµ)6< yJ\:1fd.xo@E}/%&@  & 9:9&1026732#"&'&&#"#"&546327j Pd@7*8  kOeD=!0 l9TA6?&#Hn!bSA8?SR +/r@@ " .,#" ,&V0 .- )/,0 #";);0999999199990"326?#7#"&5463356654&#"76632!!RLAsX:`kж]dFIODPPKS;F{=@pABzdFA""|x7{R 4@  V;;9999104&#"3262#"&546766!!catc\z˖&%>wPns֗mvⴚD?jv`{N@@" V  =<= < 9991/<20%!5654#"!5!&5! Dz?1/aL"a*>w؍T{ >I@T5>3*# I?>?o3o$K#NF L' K>{;L| z-'Q3JI@C54?  >3 C8*? #$ ?C0"J99999999912<<<99990@2; ; K K \ \ k k { { 3=0>D=@>T=P>c=`>t=p>=> ]]KTXJJJ@878Y@,oooolo ooooo1234?@AB"#]]>54&#">32>32!3267#"&'#"&54$)7>54&#"#"3267|6h]-V x["dm8f܄9 Zdfob$"z''Z\Z\.i<&,64((sqvn1Yc..yXd״ '1@B'2")( ,%" ,&",L"Lz"Q2/&2 )( / /% /' "29999999199999990@DJ H EGV%U&X)kkg%b&f's&w'p3I I FFU VWWY(fh%uvx%y&y'y)]]KTX222@878Y ()]].#".5467>327#"&'' 324&%]:O?bW:VO>aW9V'[;#"/)1~KzV43V7}D|V54T3%#G'&Lf!@I  : !HK!NZQF" ! $"99919990KSX9Y"KTX"""@878Y@#dddddddz y zzzz]73#"&546?>?33267d21gkkxgU9NnkTCm_Qh98gbTD^Z{^\YFj9LVGB k@/ :HF   99991/0KSX9Y"]]!#3#73yZ1p1eH^@ `10!#!^=} *@    91903##'%\sB}}`s-Pb;V#@P !    :  M ooMo!\$  $ $9912299990KSX99Y"&&#"!!#"&'73267!7!6632&P,`r<>9J{74a/am"?%ʩ.czɏ!!J;?@.9*-" *`19`"` `<-<<219999990#"'&'&'&#"56632326#"'&'&'&#"56632326ian ^Xbian ^Vgian ^Xbian ^VoNE;=LTNE;=KڲOE;=LSNE;=K`@91/90!3!^DC?q# 1@  l   991<299077'%}'%}#RRo# 1@  l   991<2990%77779'c''`% ^R^ ^R v@:    :H     999991/<<220KSXY"73#%3#%3#111k'$u^'$uR^'2Tu^ #@9    :ZZ F Zs  #  $91/220KSXY"KTK T[KT[KT[X$$$@878Y#";!!!!!"&'&5476$3xW1!X!9h!N{^+LInӵ+F#Ftba^{(2A@9 /) )o K N6L|32>32'>54&#"3254&#"x[%cm/e燿LBc6c {7h@/3264')ncihXulpq.iT"z嘗@acJy@ o9910!!yy@ o9910!!y + @1     :b F   991<20KSX99Y"@1     *** * ::: : III I YYY Y ]#73#73#၏w#၏??3 @.     : bF    91<20KSX99Y" ]@1    %%% % 666 6 FFF F UUU U ]3#%3##႐#၏լ@@ T@:bF910KSX9Y"@  **99IIYY ]#73#၏?V@:bF10KSX9Y"]@%%66FFVV ]3#!ゐլ@o )@` > <<103#3#!!oA#u"@91990  9%-V'\^hN'<um_@:QV10KSXY"]@) %86EYViexuu]3#/^R#/@I -'! - -L'L!0 *$0* $ $?@*?099999999919999999907'#"&''7&&5467'766324&#"326{r%$&(r;t=:x=q%%&&s7t@?s9q(&%%s>v:@t8s'%$|ppr#@ l91907%%}#R#@ l9190777'd# ^R!@b  : o }c\~  (%9991/<22<2990KSX9Y"K TK T[K T[KT[KT[KT[X@878Y__]3#3#'#"!!##737>3۹/-hd[/Ѿ&`Oic/яNƠ!@J   : o }\ ~    %9991/<22990KSX9Y"K TK T[K T[KT[KT[KT[X@878Y@ ````` `  ]!#!"!!##737>%ѹd[/Ѿ&{Oic/яNǟ;@I       :LL  F   .9999912<220KSXY"%!#!7!!7!3!!!jRRnkoRRpjn\\HF/@:H910KSXY"3#2F4@:bH10KSX9Y"73##ၐ@% ]@.     : bH    91<20KSX99Y"73#%3##ၐ#၏@@  #/;GKd@83W-WR'W9WBRI<QHVLHE0J*6 ?  $ !0 ? E* ! L9912<<2220"&54324&#"326"&54324&#"3264&#"326"&5432#s织HMMo~PKkn躈HNMp~QKk\LMoQKk纈. kjí]d ij­\dkjí]dò   m'$u7 m'(uk'$u7 N'(u7 k'(u7k',;u7m',;u7"N',;u7Vk',;uRk'2TuRm'2TuRk'2Tuwk'8uwm'8uwk'8uH`O@:~$91/0KSXY"@]KTX@878Y3##۸`Rfd@ 91290K TKT[X@878YK TK T[K T[KT[KT[X@878Y3#'#fP7@   91<<99990K TK T[X@878Y@  ]]K TK T[K T[KT[X@878Y@!    ]K TX878YKTKT[X@878Y'.'"#>322673#"&- '3}[%@/ &1}\&BZ7IR7GT}bd@ o9910K TK T[K T[K T[KT[KT[X@878YKTKT[X@878Y!!V)H@  91<90K TX@878YK TK T[K T[K T[KT[KT[X@878YKTKT[KT[KT[X@878Y332673#"&546rTVUnt HDCIM};D/@:9910KSXY"K TK T[K T[K T[KT[KT[X@878Y@OOPPUU]]K TX@878Y3#d' @   10K TK T[X@878Y@   ]K TK T[KT[KT[KT[X@878Y@I44400044 4 444000444OOKKKKK K O O O KKKKKKO$]K TX878Y#"&546324&#"326џtsst{WABUUBCUsstt@WUBBVVdu#&@    991/90!#"&'732654&'$"+V+'O*32''%'3%.#"3254&DEOKTRLX:(| G`P#+W,ufvdt|xet|k^ȃm_bdCDlhk'<uVf'\^7 q@= :Z ZF  999991/0KSXY"!#3!232654&#DB#3 qm|rRѯhsV%@L  $#$#"$# !#$#$#%$$#:! L LQz"$\&"&% !#$$#&999991990KSX9999Y"K TK T[KT[KT[KT[X&@&&878Y`'p'']4&#"3267>>32#"&'#3xR:9DvW59FJ{voJgw(s}TPOnRNRiad˦wOScb-`10!!ת? @M `  ````` ` ` :   <291<290KSXY" '77w55v8vL57y5yy5 @/ AA:  V     999120KSX2Y"]@  //??OO__]3?33!w摍 c)t'+nJ@/AA: V C9991990KSX9Y"]@ )),,]K TK T[KT[KT[KT[KT[KT[KT[X@878Y@#699FOOLLLLFYYjjzz] !!7>54&#"7>32;:TF7SL@{@BrnT.V(6C"${rY>q!(k@* (%V) (C "C)99190@(     ]]>32#"&'732654&+732654&#"S~7}raKP߸@@5p?{abV\fsRR8|=iVMr^Hy\R>?lH@55''5 d''5d!''5 d\m'* 'uBVH'J7`P', ;u u'6du{'VVk'&-u^f'FwVm'&-u^f'Fw^-@i'&(% !"#$  :((L LQ z\%%".999991/<2990KSX9999Y"`/]KTX...@878Y%#"&547>32!7!733##3267>54&#"XJ{vpJfl-CFtV8;DsW5:EadǦ-wOShaR{{SQTkRMS\@ c9910!!}HF/@:H910KSXY"3#2F+@> ZetZ)% # )VQ,,%$#   &$,9999999991<2220@o o ooooooo o! ].#"!!!!3267#"#73>7#7332!S`G5 7w mf'^a 7 8a@gbe^{2f7{V`34${7g1{Go@99991<20@"@@@@PPPPOOOO____]]KTKT[KT[K T[X@878YKTKT[X@878YKTKT[X@878Y3#%3#)&µ10@   ]K TK T[K T[KT[X@878Y@ ]K TX@878Y@(**)66GGWW //]]KTX@878Y@ff]3#͞Ln@ W W91<<9990KTKT[X@878YKTK T[X@878Y/&#"#>3232673#"&#+&"6}#{U#=$ &'9 }!}\79 32mn 6.mn910K TX@878Y@ //]]KTX@878YK TKT[X@878Y@ tt]#R@ 91<90K TK T[K T[K T[X@878Y@     ]KTX@878YKTKT[X@878Y3#'#Xמї c@ 91290@//// ]K TX@878YKTX@878Y#373՞ї T @*A  A  A :  V     99991<290KSXY"K TK T[K T[K T[KT[KT[KT[X@878Y@)+/--/ / 6Fy]KTKT[KT[KT[X878Y !33##7!7Zw7Rj%%`bam O@  120KTKT[X@878YKTX@878Y332673#"&w NLVlw"y=67?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~>: ~1BSax~ & 0 : !""""+"H"e%  0AR^x}  0 9 !""""+"H"`%^ChVjq_8 (Bbcdefghjikmlnoqprsutvwxzy{}|~f5D=`3=\wjfd%)DZj?wy}7V)7773\7\7\?7u777LR7LT7 Xwy{{RTJf^^^BH9H9H9HHH^^JH+#u3yyV77LRwTTTTTTf^^^^^9H9H9H9HH^^^^^uuuuV13 `'yL\#hd+/RRNT?L5=ZyyLR^9^% % V^33++% y7y77\7\7\7\7LRLRLRwww9HRP};dL# +{33\755J5!!3\B\7 +Vf^Vf^^\oLR5T1+   !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~     sfthyphenperiodcenteredEuroc6459c6460c6461c6462c6463c6466c6467c6468c6469""""zF=r8<90 9 % F  | * r 1cO-0Z3t1GZH_ V`W2 f !{!""#$%m%&&'O''(E(R(_(l(y(((((((((()))")/)<)I)V)c)p)}))))))**M*+O+,,f-8-.o.//f/0411v112:23h34 4/445o567 78i88999:$:a::::; ;;)>6>C>? ?0?R?@@AAEAB4BABNB[BhBuBBBBBBBBBBC,CpDDYDEEEF.FoFGGSG`GmGzGGHHHHI@IIJZJKIKKKKKLLL!L.L;LHLULbMM0MUMNONO"OuOPPPQv 7k9:;xzϠ޲꠸۳hgE9/OK]0k?XߍEC+4>85tUY]=PeE.C⹱5M\73ֶ7a@&{9s" beq[&i۵>c4J( mri[R^;4h둔 eѪJ"eKwa_j{XΐA;F&_ZTm1q7oۛWXc=},F4!)K6 m~24yn׾)y~!-@tWpuaX*3$\Ҥ.O%xt3f"&T&jt$ w@ܡgizH! ZT'9˩G!.! E1j63X7kqșEjA=40Dkfks: yGM+x]I.og7ԃB19|[pU.,dգu=_"NNAHoce-e~TIf`xC M0l)RlHf Lu2Ga hYIq3X^"9'Tm6H@*> S}qFjߐOs EhS. -}Y|KjMCT#ݲc%#wS $}U84сE%՛{)l Ywu~Vk5FHgɸ@%$2P;M]rjY ,~(_=N¿6-:.QRfʪ2DQ?vxЋjl%(hX̹G}X[ 79G)v5ؖ&TogA"ݨ ׮rl.i,{/%:`RRAjńK23eƥi ݯ5BM)U4#ywKb;>J|V܋PDϖn+Ujȋg%‡DSs bM ø?U^$@UhTw$hht1(SZ?jlP- Vwbqy`kКLΣ.[4Rn^ 3]JQV3F"TYbݮ~9ls!u/nf̾x 7!.-R$;Q?Ꮈ}M.?&Z.PG-LdBd7 xYɚ_!z20ԴDgC6"@dd싍"Bb p'Ϗ;U, +i΁p\\̌|tv82ޯdV:PD);_%w Z0jK_//C ]%J3g xFD؎g VcS;GmouFyQ oh/sf`յ [No h͢ӇJr?Jh{5ێ3/eK5WabX; llHD_zaV n(HKv0jRaϷ<{5O H[iaKz鸥a绐q{y*rf`2Rd@{"mD/ ưhVNPvS Wy6Z1E%"T0,`OuT$uj49#N 8ffxFKhѧ8Fpl5LyƟؖ%xLs/W0 Z:&,y2Y2D -Vgh43^TYm"ն]թ %L"?ybk@gصU gmC.`Hk;R"igf-' (fK(G^|}%A!};?A8 hc)'F-:ݮ:^SĠd/xΛx!SE)y`Ie@"jzTUmpr1=D~!m RX"q ;֠q(Rޑe=yc B$[6c~ qR)m9lƤWt <)sa_Bm~W!rX_4Z=LKר"?53aݮSpٚS\D#| ?_o(2^4wOi"ɄؐL(QK0O2䵙F`fk&?cIeU >-JA{v: tݳ֣PQK"3B+J%V]oL=ҾqiGnFGn#[A@,%sL59ZnfIk}"@!7Na0v Q2*=L#δQX])N2sd87/ޓ|]%k @{@,:TcA,w?.kS7'aNN˫dfI;nhtG H-rmh,|wO]crcϮG+ ZrG3H<:u;3q h} Gm+4$>0>1EpR~EETŅ_'h8r⽻#ӿԭW߃(.MpAybKLeRmvRFO?+K]+N L4xxZlځ5|mAwK T;{`MŭZ+o0Q{F|1W @ 2e:'I=Ӆ-hrn/%ϐU1ta=~1diOfB-6nx˽r|](bխ6 N"4ӫAcm8`5fQ^ݪFu: w^ԪA_s|6ZwAu sYJ֡J SD1' `y`{_jLo.ho=G,\m !o"!NE}R > % EwV x"Oxd7MiI AL̇3V Gf-Fr|pi d~o .Rk)z06!8, W#ƈQ#!d@-<8V#3 W+ZWe_3V^ښ\Gݖ.RXSGW ]9g3\FLA<2@X;a l(X կ͗xg0449ZjB,oMɌbfBGoHZe/+Ї{ǎ\v}\/;ka ۼ6sWa\>RΒocǽD#J#QFxPtX[j|!&l  1O0 M'nқ0'b" ""tV6z:(h/U3cQvH_ӵ.]pkrU/sZfZ,iq-6l9oRX?1~EQ$@1CHp^gaxro9? v1ʕ#3o6Ka@#<ؖfU@-PՊ OktYZkfu%LlŞI"+yx}h'B_pWjX˅%3[ ]e;UwG;WK@ N0T('7PE]V #F\ZQgIF+]~@rjM ɈĎ omfΐopM8Ct$ %UC/ݖϴ固c'ާ#&X wm.Wf߷ 4G >迿aw0O Cd5 =B*d# 15t6yke*dջ{$})kD`ޔ˰ͦOD7 p/bYx펶o":]M`,\4@\|m ᮐ՟ɖ7ҹ#-m5Q}LMUG?k z,_+ʨXT6Tưa.i3>NպZk?MDHm@a V,]u:(tHgAٝb^w!4eƝX"RWPsYVp{OˏBK:f\ p_1?F2qsDbGG~vU*/p ~)s@(uƅPs 3d"[&hos@zI>aa1:-Y شwdc%tCfq/7I}6?}Si9-+\`Խ"ySYh!s 9jYDNQ6ʕØXiUj*x2ODOGq0o; Dfn,/ jY>7nزy]4 ꀋNEQx)P93ٵDizBqHMj::=0 NJܑ%?UdYeY`ah\xB%i 3-*6O3PLy?\,⏊xTlMH!Tw"8BEn˥_'DGM#-WE `ȯm(,3yfb= RUHϯTjTxߞ܀в8p8v.Bn7zML3yd%0)FĊ6HT?*+RnQQ\=>Mó5kv &ĕZ~KQ8]Z/ {𶼸5NT}߬@;hk (J}a;PNhQr[2d4SP3?1N u-wItu_pr &\`uks`rl p΁Hs%?GȀ{JUX{kr=yv6|?I&Xb02,!M|ݭ`z2 l5v$ s} Jc$x>] eS._"  ]Z+8L)&ӝfG.\([-^oz*mEB;XOC/^=?+JH Q5~"36J:;,7fk2D,J@{,HtcػS@-iIIZe6ryT0w8 Oೇ8{<bv?Ơ"@<+^c+gj$7 c+apUqOFp_h3˅^w1dco R+i'] Q~dgb?1-:v|c oo[ukN0VvGP}1F `"]J =y.Î[ mBJe~*yx{FIԐA|ۺDA׫/7$oq3ՙ_׾Zed6iw=RjB?mfȎp#x{a`m: Z|>Үݥ]"du#*.1]O‰ H~BH b@l @ju?K^3- E Pc& cap?d~%/2¼iA\jGW.8)ṏG4"p/^8@, #JuIE`:eIQr|Pʝ4*Nr{+^Mc.Yo몞WWASύ( "W7R:IcTx0M"}Jۆd߱pҶZ0nU?z5(IhMK(lԞ:=56\'7}a>B~6 a5&G If;V*Pa8kǠTWnܯ{O6"|ጨ4n ,]qpz_Tg{^Oc9r)1/g:Q>!"V/.rm0;VfInɳ5ޖV"q9s`YKy!B_%\*|3E𲷒yΚmY)gʘu0=.ϱ+,p6>+ +b>YYݦ Kw?@8M={!WJ8b?iǘס \:2@ĕ'KCEcx #hfYi!(Q*RdfI~EG.x, H@Z,tpAN2a+ærCڂTPz#ր{r=\EPfth4TZVd͛D/iy.S:rg!>YlΕ}eJK$kdⵘxм\R^|;(^ 2%ZZ]퓍游_^ʬ%x%e"0礧Vݲ{6kz,) P'}<|gw'ɶLg^0j>["m4L05zrJƁ-Yd d* ;POhT88"$4/ޯO<]!~u˾xf補)mb]hadDtty=B,7 ^ye-wU!^v2xzQ*g߼_p`" Z`Mwc4$-F  $Go\wvuzesW2õ Y!/E_ď.FW9GV|ΫQ휕bN6l*opFV_0t{%DS 2#jД.'S˻dd4;5sWݲjQO@[B@HP;>O~pg ye(a{J.y%pɷ2̻0BKN 7ط IBKs0Ijsf%pjvzb#\C>:ʯvk{ 阧$G?e|Ґ .ڥ)FNX==A{]QY^Eh( Hz%a̲?q6_?gTEd䊰+!z u24>Q2CO+)+A=ZEH yk"wv.յ;/9 c÷DƗ?8~˺'T UN? 5׍x_mON: 's zo}ΨKç=ǝQgsmw hgK9vdl775W=mW]9" k" WT[6`\?Ee0&'wwRt(UcيX R$a<,Qc!BjcSu4LSv+1֕?ĸDwԲ=m& .83FϬ~z #쒽=6Zam +YuL~ DD`|Ѓ6t%۠,ͩbETV I\J@Ʒg 0eaTç;=|P֊E mrdH~[n]9<ͬJؕp!jkeAfhÑKxl$|T9귎WTA~6!Rɶ [r qzr9-X_)<Bj/.ҽV|<1"ˊfr;?RJ sHV͡B ~slӌjPDEt |Fldxo;5TD֐Y&# cie?Q[I҈La]Q,MOrJ1HN-/푠{fe14,gVؓc]|Cv\Y1%7˅}gGgFԞ]Onb=؋:ѧ-p9KHG޵], >Mxd(Geۂkj "ŊR X*m %TTKhx02&J ;5NCOF).!%$hcK`;Jfb[[^~"S9f Ml/xWC닸 YeM~[߭ !kvrbK/^]*Y@]f;xi)neͽabLoew$[%ˋB> IWD÷ Z{|2̛OL t 0]Le7 7N43W;v$0Q|Cך/4.Is C?dnܱpbHȯ<,v:56FtF7k<_ôDZhw6!2zc-Ee84p(Us R= 0uRQ[c*9AOe&j*4tAxoJwkო$.TX`; |~{-RԄ.[h:כyV7D}RqʹŮَL fi=SgHz@)UdhZ^(F&u{K`k_u2N<[5 $SYhŧ|fӵ|B#"Ul[}d=2E#s}dy=o=äZ/"rr18pCaW nv2cɉ3b^@ }bn1wwSn<FW63B N%6omx,W:BUS7TvnPT>Rp̎=k-VƠ\X7֭۹o¢,SY-Zaw dLs@Gܙ[H>4; >$KNu!#{ab26x6Aܞ4yJ,Rw(IB"Ğu;d=b|u7A7G|iLƣ@?8^~f?SoVs63F|& *v }Nxcb)O#_6#Ȁ"G&$QoTUO÷IuYc VCR-FC՝ G#rY(Z%-qY7tlɽp3LE%;agPqmie;8IDK6Rj$k9cf"bÿor|Ёq7?J/CU (Sl}p`x!|i;8~+K+;^7D^(DLJ}4RjwqnM)ɏt׶Qs3:2ۙ* 2e[ip{Ugז%VWr b kgzJ'|=oZЋ)uܾXBSъ_Gvf"?f8-@7:ml@oA,Z6OuA 8iz~9NM}Qo,7AkD@#ùyungA4p8E15Hg0>{6Ikr1d(+!nɬuZrWkmAnrWRmnLm)vOi>DP:MP~&m0 Z :sT5uovo,Qَ[jM[ݟd75:j)vEG٤i Lp[[tN6ġY4Z>sɔn\z62#1?9=W$ώTnUtCM}hq]"c Qʵ[Kin;"N !M""vuy^;#OtQ 9|:s29P3Ya7COsd<]c A]>miY IN 5lYiP(ŦVwvT/s 8/Sk) ݰ؅ot\O2kE'U ,{,u|~[ =()'ot;RIw?g0-Y#w?e dޝ jqW%F%(][@ H} 45Eu`Kv(3\–*ï4\ A?3?j>8|LjV8iwW+Gޖfә$&|cRz_JbihmRԋ+'})ebk-~!H궾䡬Ŷ9@E A&8* QܓdU3Tr1a4zs}1IKBIa:0Ly"` pq(%9KJu~mE6s̍%l |nn`²3BIR_).ЗoIjVv3<8tWOƗ0LԤojC:8pOxEjL~K(.SP%/Db?SBC3hU{g?W겯|iAŢQu4`wE4tGU&dm䯦3/aQ{>WyRQk:pm&W;$&a]o[U~tb@M/_sXFP|3Ɣt4yƅHh>m3^h-u0b^ѻny &=&]I̿vDEwDR ȿw:R=vs͂g>7ظrQ2OEւ˃AC[cN0Vɉ?[87cqH (&/1xCԼŇcui#|%ĂYJ,: 5\ .o17ċI #q= PM)\:,~} DWjrŷK܆ײJh "W!K+o)bv2ğwVn`QT <˘hzOAQw-`&)'abލ zG,"SU|%/T)T( ͲJrIu;B[fy5BH|N>ב :3"E/\ GXWs@7qR($Yz4I$r!|(5RV_pBBhyӝ#La~. ?} ċJd&C'[5Ч 6b[ψve1o`5yߵI?^ oAu1e@zXu $^th` z10& qaB=D&&-*bgO_P,;:EK~]ibZzgl/diB3'>c 4H^|$@BW668؜fu6P݊KK9\ SvØq"no N3 ݼ}P P5WP#5S{ڻ*4=u2j׻,ihKKm"kupSMl| ?x1AB:B[ȻI[ȱ|qӱe}{(E 6d0v׻AX9ɟB+lTji B=q_ƑMB.%zqc}I~8j?愃.`Y#=yKdTn- %nIMi2 Ns*u t$t36gi/ij l(>LMvPs<%=Y$ mQ^/pG~X&pX>l0[#VB,t`*TE a2^q>`09:I ŲF\mg8\ FYT,+։4@Ӗ4YQCG4E*]Ԓ3c uc̹'l'? D?CsB7&E retoZ#T&Dž?5 jW77)׌äpjs7$9Pie^6XXY3Mc jܰ|RK )檦9inb}`C {hH8j8Fq3<RB ڌW @9 3yaf|3|5TE[aDǑ}Ylpnd#/Affnc5/G]*[*deV헨6eH|4 O>惮\nJj)!*T (6*(C[/E}e,HF[Z~)pX=hAٝ,%]P4 ;=)TKRA$vc[b9 w.\0|onl_ t8* `دlDǀOGF7лFg ӪWSVm /w`&B0Z|+ [Kyq ̷Td/uIha"iXtpZd2a;h-6th{jifӇ[WIx~s2'P 6\)K,C_1CUf5`1H?q'@txZWj|G͔L,ave n#Y6hҼ~3%[Ke1AcyBj7tbxٹ9h>e o*b1aw|A=h޽!gnX.2B02y@6X[xƊGi_M> qL0w.\!d⠀ozLuУ{f=/`S|߯G:w*c ݠh⥕]4vL{a%uhiֿ"9R?Z9a}CfX e)Pn G|W{t<1LVò-4&WÍߟ`“[ MDuvڇx58 AiFHGx*< uS y'x0s\K.@q]>=ŬTOa`WS<+9]zT9EdX8!MǶZԄ,#CMR4uvc Sy6Z{+Qb캄-}zVJ7ۃoA)zJq+yUCf|&_?u=U{e 5vqvh0f-58'e[N+a71-:2_3-W*ټA8O]u3l+V) QO[~8I%7ob0S1 8&#~MxK+ZH`}bνvZ3Mrk `k /z^] gb2KF_Vn` |1itAř0c\`M^%Ng1TA5E2)[htEiJ^M8D.נ{w$$rI+&[ a9"d19lpM-hi3ޮ/~Ue c+ =uoN46̀ -kȮVyHwBڦaY]ܖqP0LS. K=G'-Նc/Ʈ>-&f"GÞ~QD֮LQ)C·/95=/e1+z&/`Iq| "$InQ4DB\u3:* N» k%sJ¶;%Cyςj%o$-f2fB]퀮vw> EeÅ fxJz zwXd I(K>fxȝQz_ɩ1'?f8{ G`/]}e9f7Dvn, _}U,'`7ֹa}B0 -#ֵ"cUO9a#`)E(&KJ.le0jA)*nQAp'Q6 D%Dfr1~k*5V$A-){_!s@]0ei%W+P mE9 zK`s]Bj.jI޺.DNe.[̙Ԕ71m^`ްۥ^3ղXpN1㖽qdcZ`͎[u Չ7G4#`s`CIPHjV6ͦPýy. "-1C>d =`We$aCU_7 ^gyAb<ûpc<-)H@q@Ju~y%pgJ+#m~WsH J͏%lV09y]ԱGT&IHO%o6?(-C~mh,rr <؃kƪ.swc]\Ӛ13uB֢2Q誻ת]0:Jb (eA]vDqGHrXWp#sE5r& 4Nbm(.^ eNؙƹ'7+Ky]IiC#"mFHp^ga F 膽UIfܚ+5 ~p[Cr<},,۪(?1_1>WFfJfK3d /n xO8W1ϓ=/$(K_(žZ_}~Z&xێ3园ژ0胪5?<̎+荴-KQsX[5oMS۪b_SY[9Xji\<8x_4G툛R;?4-Ic!˹r`jjIxՖE>s2 0QhZV~ Btz}c2NGofͮ/$qChZuGe+7@2?$ٚ?6{WN'g^s>N熸 yxVVcٲ<$iYI ٗj' Ɉ+XP,G; "Ku8y-`BsnRDžޘQr٤oȷ!Qڋ]253T?ƺf+'[ŏ/eK\ ]fϓ| ҬhW(*ҜJH֥$+0a_UJ^TBmzbDzHN-\'L7&kBQ0J'\N(Tea]u=9s6+bwu9_FSF$A ֮Rh_=+prfMeߕ31uϙ=l*Pa񓀳3im$ `i,pL6BC\?:uMG12-Hɜ#FADžKQ蘫2~ vr.ܶ%g"ӯ?_#h-ġ*(5ROƚGlhtfykN}lNCC8O**yF2:_EzDZYwhw^&fe}ZYn?G"Upf F;[UU6:yĭ]۫'~0L}PVg.j1A-2aITWOT󡏀vߏ-FVJǥYCNTXvL1@sYR;GˬƑ3Vb73F,UhT!g;Py2T@NѢ3&`I-vn-!`HS c1nv9~9ex;mZuvNdEVc~b jMYɂ FDY VX$XɬzƎ\.F`u,QԶgi+Kn뭆- xY.Cu&=.^ w?c 8&$ip@(6G(gM`:ͮ/]'@e= GA +O !):W1_\ATBnpՉ'+zj;MA"~v+w!6k=+ײYvb5Pðy"d9+̠_!w`#nʹ`;аxBĻ؋5}9D7h٭>R?a8jTo+cN; ,#l]GO6mہ?4]l.@` /}RV:Be$7[dH񍖥!6η P+(EnJmv£?bhICg +tn@;i` X^8T_;E/-\tnO"IF&E JQ4`e74vIT;Ӹ38a!U=N=`m37UA$GQW(  'cUex&[I ųe},КuY.]0cTk9{_gi-cá!Gí(ѡ1EÂϋeT6ŊY*B.WL:C^f&0 ~,0iM?йY"E"1xz`]fP}nufU rKxnVb+i ,Vx̦wC70wf*%㼺\KN4bp#k:uR%ꡙ6T徃CV`9%"rs@zp^{jXUȐiIШV~y#o ?ƭb}U~dP~Qm6eI [S0W=o]哚yn.yfB@^'k; sgn4q' )4Vs_B9Ri % 4"EtC7V_%PӋMW+l]sMMo9O=Ms&gD^Lw K BchԨ`p-3C^QDMČGDX t 5W&qƹ'نȘil';OPs M@${aRSLQn y`*84/0{_p|]k`P>8K{E-{bWM(Ÿ8}џQ\!_єi-pu!o~\OfX:!>_W= M+ (5IeRimJK;gz7׃xPF`H갺ʞ(d[-9V‰)S&y7͕ySl(x" Geom&$:$nqzojB`HҺ]ˠGHeUb}rF' Vhkw8=I`Qw3 V|di}~$5?{䜿X'/0~?HJ>G2eNM";- Z[Gwn P$4{kwoFq8G7PK9"މW|JF*6EP[ Lt٩, RgY/ uwm@'B#z7gD6feQ'Đ}][t@ZLڵ{z˗d[:L* _ݙ,d>Ԁ>& Od4Wi6Rl CaWZn'1RNV!1 8u O7z5w&V]6JJ G7u֌b<&lF0j[:z۾(BzacJsxD!55Բ(DW:` ]Kِ 7/:at*5KrrA% dRXO]PϢ[7Pu=/ZGo؝r̩D|B"ib}e"C Eu&!4JGQ_ׁo@ETˑL*.EwnC1HD!H~\zM1 ܏-qJ HfOW,9 7"z"?݋ұ;W[s ĖْwgxS+T )ZEVMҝƗa&Q!ne'Cv7)!?wwG{k$Pi[e'EJSA6P@)+<40\?n6v>щC$U=:^HqO秂f'u&>$w͂-.c PZ9.Lj|i4)ew(=}@Fgs p |3pY~ Qj ST(;:1־Ntk4ɔ4)%/U`=.N6KZ˜FҔ_18S_V^4YU@zSEW[_m"[͇U_孆\cmo0&UA˱ m4n1{p sNѤ<8z`{10)V&7H.8kbVOB_.C"] eUu 8E0-V:ߩpu܀m(Nu<\0SiҲƲ7å;2"P|4NL#ԫmKpQ=3EE 2V+&c#4BSм%bUfje߯ Tޯ0ي% B,!9@yXzK7,g e}QS&"`LBjmf8P;U+ ;P[l=}3[%kF'leEQ,eOfJ=8#Q76)ɫ|ՌHGefoiߒyl5!W®4 kzLjQi2vKN0}v5unYb@\궒х SWV$ eW"ڱ\ZҜSL$MhUiTt޵CO41<nq*B3r93Օ%j]vg;z>T'`Copr8wM7 GԻַ{w~ mmO֕rRoޭHPz U Ƹ)ڿh)UdFO6Zr2kglxϫngSZ>Ǎ{b>ᱶF9w-O no-VM{4Ǭ' +Q5Hx@!yrm?Y(mko#' DFGH JnޥZ:̓->bs3)%kp%*u_y8SHoՐ$d|o!ٮ^ŧ%?}(0b yΊLk%vl<ӑlboU;*]Z׵mQi,\skiy2t[~ݤH@N{q u‹qjVnxYhذGX򢪾Vɘ['r4]C+R_ |[Doc^/gv="B~֘ډ3?C-X98V `$ˆ &JoNǬ/&3û&K̔ ؈ƛ 6D޻(_mg3;;Dg*G/R&ܻфF=_ rTdSPzm zzCU|{ZR|uAgb'ڦ>jgL3H"$ܯрl@8PbL"H҈Z\K-{ϠC /P)˛K,flrFxtV0*3!nzU=&poEqO ˆ BwV979Z+3%H&b!tk9f[otS7k aJ{od ti[. Zxm6x]@Ғ2^YM1a5 }G5ʍvjŌHaTӡ); #\Qȹt=4Q"rVCFNBڕ;aD2ɬs[K:;iuaڐbs/gř,F\8׷y,˜|IUI"jhvgگ`HgD>X,1g^b-vi[77.`Wgg']g+onUtqq~:I< hW'S`@6Q沫XMO7\ɪہb }H)iչ}qU<7ø$9s;MtcmM&a.TEJR42yu\M0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 cleartomark ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1707393948.0 reportlab-4.1.0/src/reportlab/fonts/_ab_____.pfb0000664000175000017500000007633614561141634021205 0ustar00rptlabrptlab%!PS-AdobeFont-1.0: Arial-BoldMT 001.001 %%CreationDate: Wed Jan 27 12:58:23 1999 %%VMusage: 29118 36054 %% (C) Copyright 1991, 1993, 1996, 1997, 1998, 1999 The Monotype Corporation. %% All Rights Reserved. %% Arial is a trademark of The Monotype Corporation. registered in the US Patent %% and Trademark Office and elsewhere. 11 dict begin /FontInfo 10 dict dup begin /version (001.001) readonly def /Notice (Copyright (c) 1991, 1993, 1996, 1997, 1998, 1999 Adobe Systems Incorporated. All Rights Reserved.Arial is a trademark of The Monotype Corporation. registered in the US Patent and Trademark Office and elsewhere.) readonly def /Copyright ((C) Copyright 1991, 1993, 1996, 1997, 1998, 1999 The Monotype Corporation. All Rights Reserved. ) readonly def /FullName (Arial MT Bold) readonly def /FamilyName (Arial MT) readonly def /Weight (Bold) readonly def /isFixedPitch false def /ItalicAngle 0 def /UnderlinePosition -100 def /UnderlineThickness 50 def end readonly def /FontName /Arial-BoldMT def /Encoding StandardEncoding def /PaintType 0 def /FontType 1 def /FontMatrix [0.001 0 0 0.001 0 0] def /UniqueID 44341 def /FontBBox{-167 -250 1006 939}readonly def currentdict end currentfile eexec uL^C\dҠEyioL ,Vg3E%sӟs>zjJӯ# pZ aMQ :A̗A[Bj:lRMݬa(4jy.!ҳ IޮCӬ 'jJ-MF ix#rxDe3S[BڔJǐ(;hQK@ 62=.ژ1WY{8 xGT͂%ɆHIj!"ž@+t:]݋>1mTFheIis^4Q>VSX vy^mJTzMߊ^c.;BY)Xx FpWch lj@Ezivi=8T*7wgsXeuOnJe 6Ѭvl#фv]8x,\SiZd$,K|B6]3Wymg<W֡Z`H#[ MV}TK*dIz_ȇzSy8U68 iNb4mI\7Unm}Ҏ"7ry^@Q*GPzbzonrS+'Ϳ°|+N ڦS{x-Q'K9π~_gRO3LK/Yz_k%ѩ ݛ[͝F5W`/ڴw>OҡT{YW+b:YeM!N}fLS^T$<\]0܀xg* x:g6P|W@F_ԠF$̵ݽtnU5;,@1(R~EkhXK*zFmUT2sFaPRu} 'm+8Dy]DC+z]f2=e' EF衲Q:mn?@?,Jsw>P{rʋ,rҳ@O Y0!85YLmcp\w~"M Lw!眩+.y/`Fnւr^|lK,{}|;w:nå5o?$ <~ ,>1T(/(49b,*HGw{j4,S1$?\OfV^.j/%lZ} O=;cw\iVlDO^}٦JvG zXiuА^#\qr3NqS8DR[`)} -XͺFs="45ӽd%Wr ePiԛ﹏ 62qfg7,z; `Jp(a ZM90yH 5g!Sm; Ztt 1)nzƚ:}ZOp9LrS'\OY_GT _P$#86 xwQMB3F ul6ڋ AEm'yfƑ)B!U/zd#Y%mڥ!JxMZҼD7QkK7{;lmr(|E/Pb!X=d2YnOEYvQq%ϙG tx_vr B~@6Ǵ3w;d6\Rk]af)$m DҰLu9]=(O&1UezRcݫF[' ?5AJ݇{^ Hʾ-u0WV .$迦_NI rqz?:cJ͑mq=Vk{F mٲ/Q{Q[Q~'_wYOHoB\+L2 {b*3>91Dkm']h>ihL5

FU,>VuWʺ,1I_<% lb'z Zo9f `A#4^d = 1@xB }n۬WU)\hq|38 0^4aP-ʘǏ^#+1{`b ORɣv996YL`C-_KVm>J*H:|犏OkF_%q71;*H#X(eW4,(t#w^sE*_z7H?w_?!s@݊:7'4n. ]WbhkU2Un%Z`ho|( wlsnyt3"8T_WQ#!mOLi:2 Brီ]ܷA翢uc~.G]P4'q<Y R]<r·Rd6-.AeqUU'츐9CrӦN.b}Bd l1 ZŖLRNJ$)ggUsXIx,$QLAa{%m^mp|+j3.P@ӝn\/) t"Uc#y@ hu<,g ,Ԫ`ٱ 'ȉ" ȊNq,<9zώeh<q, ܚ".<Cy>~k% RUy>_GS H.͑;O$ۭ nhfN{9xK`K'(MEW|4#Il\hKzbddSgf 8D5+b%p#iUELBX (>H6oZ֦ YIzh_ݟ7 "̧@:B] !+^C!,Y[r64D;6cY8^<ΕAqS6P)+ ,PnU:MO؇7 TmoB+~4VvWȻ{MwsE@W^T8OAZW٪[njS! ƭZ4iAOF1w D;Pr?E:,:y%KT(.F2Sc-\W`N{Bet`?"g:W=pu7m>ŎC|j Hp8| `Γpq#Si/MD|P|-Utq-I"';;M#cӁN$ -]@(gq=#(S)I$d6!GǔM=g{ { \Xq㭓1M`-yq#j0$]6'Ht"Ӱ*߈".1]זg7umCR_\DTݰƪH!uT]mye.J_+FeǛUud/: TD.II'-֊>I3m7>RPMaˡcP@Z&5 DL@)xY]OױGB[a0 iuuIuNz^~rC /:J*%dzhҷ[f7ĝdH> zzl]lahX4(ú& 5s0' _Qb2 X"S)A8Bn K[*rNH}p,  yM68ʮuCPʘՇkCriVKڢk &tZ7 4;톜M ϤԘ~Nq_śNUk$XU+ʍ^YWpoᠧ6W)̘w-У5F;+5jAKʭd9xjo[20)J6f*g\zGM\ Ϣ4L}6^~⟽4L&%3蹏@ufg1D(>ٔ^2\ ?߃R4+f+"$Or6!0C䲾x0je(a<tLOSZ?$]yQZzꁗ#LR<;2(JhgqHa|nH$fZT~\tFLCV }L\- V95Wd~\)*{,`Fh OM~B\6ɛTȶWO p…s *@7zYJM5#QU[<<.0CCO-59ѿQU,:*/P> Ee` Dv_;)Za{'?ѳ1!X`y<1*9\=L7O_ Ӣd$[.W&(fJH\ʏFQN>T-BĆCpF>r i2!bj.؄~< 4*fR2B "S<;@f/Jk0C+q51O[P"9?OfA'Uֹ}he)l4yVRU*L:5=_J8qqT mua!EG QOW3MfB.L;<Ţ40z wE ȸ?=㏫;-bQm̶9@;-k%;1 Phu>a u9.dVrJ.}P)Tj/n@!kx^OQ"|}}W> R:˸KrLD+϶0'4wr9=-{w9v%>CGvh;!w$yg+RV/[0Aӹ)†W"㵘+wp$`zz%K-^F3 Śhra0oRq28+t$6> F/p TeIiHc]G О/5V)g#5t DMF*Ŕo r>CœfKiyřA"@LeUxM:E$[ŷ]4Vj$JhkS ļG#kV=A=y2R9K0cNJH) )T`(~|X.Z7^Sin! R̚M@JK-_+)E4)G"IRs(;tJ(Βa@~B ZK[ q32O tn͇ȑ<;Rrx88U] (5=J7.ż&ڃ8MJL%X!/ kqb4"ae2 >ݏ6JUgl?!mT$f ԉ ~$%ſPNgV -@a BiWBڼ:Cb=%J$sU4tbi|'=r-Z/*dMm:7QhY+< rk- >,S1nǜ':V()=FJmb6~$w""qJc&R6 d1+ k j5 dy_4f|;ZROgfN&=yȚ=Xs&@!_{Su6Zr;a^0x\w1MԪơA4c[!TdezS0u;Մ:!on"5vRoѕ^CҺ>~e;Q9h4Q&y#knCy F홋8UDY0V?:K/Y5T8ځf DYB1n% huZO-rG:4YL|]clcNڭvժ;#S}U }_pud839t RDJ=o.]onxD绵 V<4k*E/buMFg8r[D(ڸ0Vֈ-- L ̼=1}yH{8 62K ?f5gыA]ٔPKhG.~sJ3$ DNq&p9d^E{}=ГfDˀ\PXF'9r\(u YSﴹȹEw,KW~?q sj mF2U{U2حԑZ1LIP? xp%+UB|z<q_-mz -& #arm ~  p8ufW!K1C)z]}MjORaduX+].K>vK=}d{FECnrP;^,&754/~'fJs\<ߞ#b"D0AH>)vW.'nzO- ^_#omGp)G$8``ϹA?y_["rB9O ;dꔝNs{h(Ssߩ}g_<\kaQP-Aj  ׷|Ys Wڙ46ICdT I@=Կ!:X+8Xn.ҏ'cm6eflp  'NqBh\q Ăz}{PRXGI}7-wXʀo/:x7Hk&D\FVEMܞ$XPvɝ7v6zdGښ@ ؾP&gCoRHWk2qU(>[xsl{ 2 a/ 08ĢܨeSlHÙ-ӹEp⅏$h{ .GNT:嵌o]!Ց]&J^>G%1s5X섰7o+<}?N?ƻwzdTIW9K0ϷJh*勯ũEh|m/낎j"8,3Iy)E4FE7ɂjyƅxo߮rm,Mb9DI{z0-Q~FDo[>)(Ev 7./5/~K^QPele"݇ZQ}>2+,U4,(N \agKgn rsF!I(Bc'zbKG7Cٚt`[E<7ݶOVQRAwYM3Cע}X~߭rՓ@m9,utjڕQ2g3`֒*/`[K1UU^npyN 9NiB<}wM)ʗppS.P'~֎ḩdqEHD`juPZPycRhUlRuxfp (} {(D3kjo\mVgE'=01rI ,zM]RX(|Z@u u`觇>Ș}HJ=NG s!gy12 |b9.Wcu Yb%}31l?!PhvhlRί8*iPׂ:xsu[p1X,BMfcS$r-v Cy7R]_ ^ %Qy!wUᜑH|ך̮Ō``ЃՆ#hGxWyxfUlMГ?qiaqiTŜ ߹u1Z2N|/V]js#nb[2BW[m:JU HAD\#A3(,yJQ$!ljnB2G[ojӝ &h'f#Mzqj|`Tp+搅`}d,,6a J+QA jӣL#_$%Wm+]hՈ^ɰLNO")cwts,lHB& ~J?xHK 7.31aaOt^_fBͧD:; ~$ɣ&w'%k6қWGqO߰!qЪ$h0 Rڇ$Y8 /^q.&a=E+#NZ8yl^RD"0 .V=em.ij;HHOBN"-?Οote=izXe 4g d @}WE:49 nb* cSY\"/c=iyvΨ7}z&1+ }7\Z.\$KZ q;bU όltϖ7FYmzK4/Q U%0\x&KvEv&d~]^C ;Diu$ݥ+o3k:0W;"l $ >L#<| CP,b| Ey U9GkS#0Ҽ4 ^D6kJJ[oGsoi? 6z͋eѾ6?8ߗ~N4ENBQG+u@iyL* Ho#A|naf ' flLo> K]{U&B!/0Γ,@+XE#A!pj\NHdB!]yr>k<=EIڸ q ާ*M| $t]IQSק|*>6쫠oQ=kA EOPNU3}"K\cH=Ҟcu6l"@h G}W6K )%t{Z~Kgx` 9Ko@Qysș_:~+!u> Slu|㈯Z2"Qhx1GvNJY*e"i.o~* *,5  SZvnhG0;GQm@D~1 _D+ӭK]`ug? p}P*xȓvՏQoޜ2)Q\vŏ!Wgp~qUYeW܍Չ,UMxa WYmZKd[[A$H'tUptE>˙/M]X>37$Ǽ%mՖjX.SnNaܕyBٟ:묲,UwE?v5ÈwaK0w͂Fa=qmɭ𧎘qɤۧI53W| E"2U-&~K PQ*JC"땾3G1 i{Ng[# fsY9xB! 7eFY66[b/ vG2H7Sm2<LlGDGd-)KϿbC}B}C/ 1zytۘ6#yxA\W.:(`E ZV28^jV@ħloh|g\Ĩ*__T> LdFLFLlDDDz#6UE Wqk-:`$52 N]~/EsO +WTGG#UzJܿSw|Y AT塘g,tN؅d&nPǦ n w)e&ni M܎qn\grY#ئlyo71#d}5ۣtAqP=Ա}ܳg8T eL99ZT=O+^Xp5lQ ĎfVd1tG4.PhQ R_OlE˺t!)7'iuWTxiU+]Vh0jTnjgY (Sy0tω}igM_stj#?%}<ɏw@l*YTU{lr5$&`D(}/&4(NX{ITs&yvYMb*ky匨1xv4|=m–:\XEU*I*YzWݢʭz1 {Ϊ/,J @,Rw?e'Bқa@%_dA ,=qHݨAyoZ RsV_+s 5ۣW[1Iy ;,ap2bBc^Dw$@Y("~'I^*(n/]+4NT.\"B> ߺE b~n ZCU)@t"kkI{uY+aYbs ^ȖLɿRl{mRVU\A#4l|z8XQ6]Y6^񏐅.aDr+SMo=rX^Gz>Fu:vL 93{gG 8?GԌA?AAwp Rgq.K #y%Q|vWLVl$vlinm!k`1k~+{2 kÁ>.] @a! s/Ya[bzNze]ku[*`'\ ) ETfz&L!7\t-M5 V_榫sJwry{:ݗ$wmH$NDs~սOX.E=ܔjH+ ^e̸֨1M0~x2]]<*Pg;NI-vKKUjG،!mC, ?8! ֖;҇:=@"(αzy+mۆQ}ba J>M,B٦FšZJVAfمZzrN k氕^!ژ-+L|%OxCsWM(oy6tMg+}&)acE&AcW~e*˪q^__N͗%Jvˠ?I1W O0y18x8?\U^Œ 5G ʋ&$0;j\VdRo52d}ΈDB4[Gw1=>&P!w趘x2[#}G-vt+f4 &l% BwT93Ճ+]TSd3HYEZC6X!CjpՎ-a`+6y6AgeH${4UǪ`T5 ·]@m\! *+K2nƥGpnc7! 4<1@noeDwX%2oDV`Mڱ=@j1s*#kM/w 2,ɱ }Pnb$*;Yz.Kqp֫ݚ&k'}3=]CWETr+<6Ŀ[`PfNn"K28 4 :K)%f !;N1.>,f eGCUyij?(&aX> ;As5+CIݐIҏY%Fz9GG<\xy:(↮H+_0kɕ7L C0=`!o1@2$"uZJ-P(-h\tAgew!OndxYs˲1+bf!BEǰjz Eފ2O :: 0}Dlr q G5xd bFPK;j~l#~6F'$!c// S"''Cl\mp?O JYϊ d D&`z݊r9CP뎭`sRC *=JI܍h_ W5t!̨{8X4Ώz4*2˲ڦDpos+`T&"ƽ;$qQ1ՖۨT ?92O/bar È=L՘-~]~@9o FS> V|܌;o_:-~< /)۩ui9BU p׎23Z8a~נJèir$csx8pEbgmCI3~;1VX.aJ|p ! f׌P<}ǛvW3۠z66$iZ|O9\*2maʏa"eVh,~os+gʕJ xɚOjM1؊эeGd/>+")DLBղQ/=K_YfX M>\ MdGMXF ӿap۬b#)9zG ADZ jx{,}P8W--~ ت1Čŗ|)q N&~qC=tJ9*Rl6>P8 ;ZFuaoЩb1 dF>gЅ@@eJz䊱ydHW^mo_MLJM7d~*~b@|ikUrKTD jI~"mvrn=E DeLӳk% HV->$YU/~2D8e\c_y?Oʐ#,"qW,.8Ɠ'wR gT$[R]6!Qžs?'SIa3mB^v |/𶒞7]iz.9fՓph%=b@!JU0!L/j\Y(ۆ(3NA.(Tӛ^'c= >?x泼D#ؼULο̨CǮ95w)LUov blzK9A%kӗ dE+6 ig% 3 + E`bytaqZV7^cs Sn!lEƒ Ӂ箴bVJJh?ϐ7Pm!baDOug(Pc|.w@ǏXvfXuĨfޱ3z2]Bjܘwnг ۦP:m<݉y :p@̨j@9^n4I^GZlNT1̒!̖ʙ'k+ӢV+-: V0tz:Ѡث\-o MuϚ0hy ?6o 0kC|~}R/5f]4~jI,]s \4j>>?2}H[ cx>59ӈNצ[i|&+œ;k\퍃z ~YI7 ן` < $6S$b^7k@yo[l*ݒaw]n0ٯQCAlzrVr&FXu Rʢj$/C@b+7W2bTXwrV?T:cɶ|M68tB?M(lQQbS[5C쇠gV{$~ι{AK [G˪id>Ixdz ͤ'a, ZRCIYSๅ>t<'{Ŧ/C߽$(=dq+;WO_ DBv}&@D9)' O۱ߒ^j8qؼ (h,IiaH5Nc\;|d*0ǀ8u1~Uxxs6%i)/1{pkaP*.&w6z!P5IՉY|H@TÛLrg+'/:K~!pQGj՟ßreU1X]7!CV3o;p_M,47 tdED Q#i[oɻk>w`=J!'!P\JǽwDSz|:OV GDŽf/>fօd8I--5UT5a:Yĺ=k2kf"W2)"|д>E?½ypwf#au@ftFy<`ɉEWITY 2\eSs"<ŒS5!%8{9, n*V|+ qɼ%{|1aZ!YqGE !?.un2b`Eir-'s(ٻ&C"^2kugHoŐ\T2b I㴙rMR]@j{J'ԒMjZA&c7ξ }vjT.ډ*|!'콐'X>f ݨݞ»c Ybi@@0`J,)hjL24ljjN: )BfC|S`oA[Ԕ [,=)ssiGzކir (;/;^%֥ͮy+}\|"(Q~÷Q( P"LAC/\+LpՁv4N:7\݇dw+'чR{3bDgW3=ŀV 2riB´hnOc-1kZ̽Kl~Z&!YJ[Beϴ#Gœd:c(O+Ѻԉ/*FhœrS{6rPTNl/1e˰tvB\.CBxVcu/#!m>xƠئs1CѸ@h cHM=}k[FB`2G*24EM" Xk ?u*WIΨ2s'?kGxO9!U%t xD)~g&xj -SraW͓Pcr_|1 xfbHf0sh8EP-t>LRƢ SudǢ#g_"u U;KtGLϹJفS=9YW1%#slr   Hk MUsO$mk$d,?&処 ŵxw⧌MSp1Nax[Qz;,?EHu>< WD@m-Wbo^{ U%5>[:PUE"_*dG60+;Ic" sq.#jxOZeF[;̳-y+xJ `/p"bB輒[~ө,m{(DKnA LB0-/3|%eKkDG3V*Vml)ʒ7#>!OMϻTE(2UCHs`z4\8~]b#siPx{lj`@J,lU)a59%r؜p`p :c>eZCj;]c`sm+5l.ߚe' ^ᢏ$m7Qj뽲FLIDKw gLXՅZ>:ƂapyDTg.D@Kzawbbec{`ht2Qi0C-Î&k5'̌srˈ}_8 R;.!嶭QS$i+v".2 3 +O=.6.F&[j,궟k=DZ 6`$LrmǒӘeX퇋z7#|*h{E)[/Tꛌ"A(YYvtƽapoJƳ3e"", mr\\6[=C*5ga? M୧h$qX:Iq]C)'; gEQrй(}l(İp+ܲ+BT=Lb3n?eGTJV9a=4JU-i2Ǝg.Ani$'Hԑ)uSU6T v} 3jQ%:{}QG^BK>4VӮNcNm%ޫmđ_ˑ֤ʕy;߂kVsD~ļnӿk3ZA#F:6dB^셔Ugfzr'mni^|͘jCY QoK ^n.aziU RYg"<Z%W".T rI$;LIAjK$M =]qXR.?,}2"\hl W4$ ŧTsaڹ.F&{UQWXM;Hfݍb(PV] V&8^IseVCK : pU<*뮡+i-* ;WR5wyg.E3i˔ whtD?6Q1y5B%8Iy o]KN~"XqMdBΝ9Vg?d:N 3 ,U6rV|*5'!nJi <*X'&ݾR-/Lc*a'4'LFD5iH}Miqs?>PMB>CKE͹lQsi C@*?IOwٹClTԠ+7 D82W[*:6*ׅr 3'ZSb*(pOyIמRMVLY>a 6둗`-Hɴh3:̮Y^}ϼiZX߿zVDkVe@Ot#Q>#Q\@ZSE1 ᐄgwt~`k碖eOǍ<ݟ~~W(ێ#h', ^qmW< Sp/B`YAtŚ҂ hZw' $?y_51P֍S>"~67r}Rj\ݷM{njAb!L'[ĦiK"{IYcLy;sҪ$蘿7JԳ':@'rhqlAeΡ;TG(^GoREb4j˦_xs)Hg L↎̕#?Ļ(!ji $KHek>Ν}*|.G^e}\U!Kw!]ehk)E4{Q8!WLwDcr%hoe}ئ|fLD2kK1-A`^DTԡBϳ^k<սeGjpa9ڀABѸwy/9v5Y~Ͽ/ƅQu\'܎']qUi2/fsJ!ʬU5Įg}3~8A;ۏ0\wEݶ_+\M6ocF .-↿oK c,d CEleznc`jg-v29>uqcī7gm>{eFhewHead8nПo{1Ssmś2G/H VW=R砵+ˆ4Cnd'nVL3C56Ѐ-p̘*;BnyO2 `op(^PZ^ދ{OYp?3fnR픍Ku?6^eb K`BNcI0_X ʝu;!Њsj.S[WSZd1#"fȌcb)pv܀x@=RNruT< >mmd sqYߝ5+= =A;CcVH_.!pi sZvVMɁ1]S,F}r#>, 4-˃E5+4V7'd17+BL0{eTy>Y#!C`Zv $92(i닦~:oK\T޸V*a^qZSrKyVId5kV~3l%YwEű1)Vn*hx򬕥^ԃlI@9oT`}oP(OEGƑXh𹤻*b_<\ K F^-=G/u!(~yӎu(Gtv]B^fZH1u.~. >Dϐ,طwޝb]M=Հ_bfR5~0KY 6Ev~}*<,&`)I B9`TYAL8ſA9D5Bxe7И0pۆ}vvU&Xv~,6 )"}z .eQfYd"le@\Q%z,?`KEs{ǃ&yinlȏL+P1]p= cÕ#*O3K-vzEL"5L?:}>LXZF0"9)ph7L  +-;T0! 6M+vѵ:o0+v5WH'4^QJi!]ma2q]sjt 鹀kJO[M hsSA7toJ{4#_,r_KG|2 QO"#ֽLR >),#thrgjT s?0K2NVyMA'IfGt]EX35cSA d^OO;|?.&ˎ^$W2x)xC Z$X$#2ٝB)Gg*F:vn)1ᕁqBN6Q\³^W%ܑ|HgUdq{o{_̀-0wEj?;60 9^ Zt~`ԫƈ`33pd%4Ys 7Cݑ_ Ԟf+ )`iy{CF;)5ӝ5K.)gI~;7& ?͔=Ѭwq@9SB$Cbg2^Q- @? j/ -}|l_Pb]Ԉ-*Oo5cg2isZiQgkuk !`Y!%%'MnJFC*Vj[ޗɂH b]9cVΚ, )UK|oi2{6OڪR @Ǵꋁn`aLNL44#qFiD;WY`m ^d8Ai#H?t=€{ZF*a=d;s&ݽ ʈd4 O&m{Dw߮ I(Fʾgk<~*nDVSKRzg;:<~z<퐀Hp`JEkp|݉@%'@RhEs=,  9úڑ@:@кI@\ǰC/Ӯ}y긽=F5XߌL#mL2 lʶe8C~GE4TK\ITnKhKr%9Q;.n2]o)Av&jsDX0ZԴipm%Di c*jys2IV ;zs PX(@UښF:3qe5% ɳg'r%g'W,Y$gpt i4y@j11ZvYCaZ yn,i+lyGnh;/vُHZUd5}2Q Mq2Gq'31'Yʲi-9w(caHq,UBi4$Se06jMFI 7JڮhH+N 1PA?e#fHھ: ĴQSrjZ!R8b HO~Xq9lUZ[b7$/b$7e*A1A\ ˆۄm9LU2~A8Yr^FZBU>4pWkРRh 5EJ{oa<0ǧ2,5}J:ZH5a&N *bסELfO1ܼٗdN%)C*H r}ˆJN>ƻxs7u*(Yv=(i ˈho6jz*TD0 9aø= ֚<з]Jz+;̠bIB!]-h5B|@O_EOԇqy fg@nm0zl@=2aAsRyorJNHGKj IG;u֑75ɉM])p|)M1c ,>)BƀHJI۞]|_]eM|6&+2O_q]7)ߔe{Hoc&Y|axQAMŷV+ R#30qM5 9|# Hv}ްP7M\o7Sh Fn, m]?ZʼLo2Tg\d%\fcǯa@tU j{gӢRzMC$A>`{gqZYZi ~Q@G%|DD' %Bb r].Tvnyw;սPO^']jH$<: 85470)$J-\n9bIdׁ {jXx0q-)TrML' e,DhvxQ6y@rSs?߄%MRZϴg@ǦpoӝhѼK%XGL9&=LkIW * Ӌ`.g]AHg eTEΎ@ykc#Fu`%dCU-9wEjEW]ʨ6Aldov|aJШ Wsd{pk'I `d:s takWi_!A#΍RJÝW[[oy8;4"XOwW pc1"h hD}9iutp 1l02[sJHESL~1٧ur4_w:MgBC\qO~ XqնU{>٧Gėj1=`kOS9[cfq`β&}z8[qDb \18EFE`}[VVskSYqln$ょ|ۆZ 4,\}76q)vEjtص[>RSddQ_O_WiZÞ:mQ]Ui(]g0tHeH}bwre Y'0Z"Iy0q@%Qp'(Z i@͈ϑր>m8LZxFc1`#r gN*b}Ljp=S];smz7Ygȵ4w4`N: oE:̄h8/ɇ[{sSC_%Pn`~$,qh;hKR7Jl< > URhՇ4|$'A$LEQ>ӫoU>2d"@=(r'9BNx65RO@%lhb֚"zoVnU]ʅj>NN0U) ֐.PpMsg |RvitLGFP/,6-L%.g96wyWQ榨%}N> cyS(fѶ. b.w +X~wT>A΃g"bgi,|fڙWj!>UWzhv 磞hBZ gX#: ӌ͊/?Rtpi?( &3J'Iy6DaSsA*{.x4mfNUUN;y?9RKpx{Ǣ# vsyEf7@`;W P;Ҙ' sRr(@GBB8-(Fa\qcp}"ޅK ٰflfi[6 Y@tRAEv4*IktgO -\.YFEM(DY g(&R8uU63<>mvQn$vѬ2gD9Vg'ě5Q3У>gQ=/[>) @'#p:79v^~k 6>+mPjسʬ@03(Z^NYrI\s \jI01ϥA|AmtGH2 )i)>V)8i)[XkЋC4>!3]Q~*æ&>˙ZQsU9!s 3BSI ƈ:O Mlx; :DJ+sp^ Z 'K4p,w,?DcSBM~ZBNgYVěFz o14 yGPҷēf?|<R^fު_MZ< vxɝOL7 ?Bw垟 -nzP$/@wF,C+b\"Xx'uj8zY# Aۘ_!Ų᳏BkčA ZjCs:&{`lVB ug'*<)yc/AîVJ@ /଱sWf? UG*;hǬjL"b '-/AS9_:0SFf]tXH!Or-5ݱ^h 1F0Ùd%Kn<@<l,.A:OO$f x!aC-? l͔)D18F_5-d&2_]"w/R0J?掎"a$ u#,v$yK SL8UXvBFjDb|p6LˊTH?)RΡOߵ骜d3Q6 * eS:-<&vavFKfx[7|%ƋIG"n}Msİ iDIj|4pSO zT'}̇~qB'bP bT}U%+HN@ =w$p##l0}nܼqE! h/( Ɲ<[K8G+wMXDA?Cu$4.jeK4`|{l mF {`dT)SG@%~ L=}1E>O,|-\CC-)~5&o4D={쎵JcR6n7c}IpDƜ~KFZ}{'U_JKvaotH.XAۃ9$mhMuóP#B9;̔adD-/Bs[$l8'ͷk{oZ[~p;e"U$!5r70Dnff] ^"]6_y f u}]\'8r|EPK٦[v͛߾(Zr7ѬGjڵ1pCFp&ؓ}tӅ=LǢ,^n0NZ- ~2T r̬U-m[4h`w%$Ni('JȀ).Oh9u(k7]*mF.0z4jJٓVj"AVEċP]kMۗen7Ҫ<7Kl%d3HfDf 1ܸ/=qx}k>r/09țf_a$An~P[ 3#dŢG[|@ VwX6 &H0ws3YvRRcJ  *eBG$Iݶ^e_D,)z\RZ2cRW#nj] =+x#g)z?Z+k\bXfY?.ŻbZbu6CehwtaKb2ueտ^dO7@Uy =}*]"/HbI ]( jp#6; Pr߻cPCj0`rҠn2hFt*kI*r=39FDGp9 x$ >,%PgOiuO46WEx@\D̰|zu?wwTTWL %3`c,sÕW`.\ZxLkugN{K:(Ѯ?Jf?> 4Ry˕%3́HQnMILگ,Gpǯ{sYƍEYc<_T̶We| !}i:~?UyZ6v U,tvטdZ%Q4]XEX7wO:BdQ't'7TȴgM8F"n ^[  xJ.فQa5&eR#M i8we9rg&)Hb^ P*DxjfS; e@jfR?Y2rC'Zp7K ;ɏDEh-$$Y9[]XB~uoEDԿ6H )jٟˆ@BQԋ9M^ۉ=vF![Tph` 9ˍgMG+>Geu 醶8-7`XMC@LU˫>!TiSFߗL<ѴPAw dϾrgI,U9) 7 `բHN\UkVy=$]:6U5`ZP̴Xegok;Tm`RPOS5fD?!ګtm֝+a!sxݠݩJQx .&Q{\sHǙE0򚾨~(L^bfc8 DkDX s)o|;%;WNs_^+ 8-MEv2A/ UK`&:J6lڟ~>܍Oim l>MDA8 n#>JrӻYўge5O@.lE@㗠1˩!j"D$6 f0/qALS o[ȏZ9lsRPDH9A߻fGou%jWa#NKp%m #RIm4u.W%AJ;vg߭E cӈ(Zj9#; L[rO/k~\Df(.Rdmci"|_].}lǎO>ƒqbhh8|i"jم5^L-nm q=t{l)Z#h|D_IL|C`,,y}vPb30JM'lgUo~T0*JJ'%p6`"qrnES/ó8ﱴon5pF:m v_+CSZ]c7ܰM<aZ9!^-GjG w5Prtf{qc7SZʟ2{g9'. nc;wK7c^ac'=7NPܛ$, UOgBNSpӏ3_LF4'뒦EĻ"/n <#3|J jPwp^}0.4!1Zg5Yɍ*H{k}澹~k4^a.XqR\mA%8S+|KbKraT}،+yQ8xQϔs)gn9"$ۘ0ghşJnBqbp=&v `G=gS];zEMm,!>)g\ԱV&:S\dSoᏫ6X$ -dL46>QcC!/kVE 9?@ <5V]?uDr焍μj%&CSL11ltw)>H?I@>nK%M?޽}z; d{5r}jRre0ˆ|c~9DW%`jOmb1E;:J,}(G^b6Ѫ/LUl\hP  X&.n}%iڋwsԇ:Or6W6k~box)KYiבm|6s R;/}؋n 6mu?y_ g.8T&[8Ttr" >_c-:\@NkM__x\fߓXcyl?ă!< [4=ى.D)漼r }c>OhO:R0 AC3qe#W f+R `pCpƷnb\Y+.#kq@S8N5GJrxPnV =!w) Yƨþ |U9KMjߟ%bGB,Y/wc+;I=-q "F?*{h,n KozK>G"$D@]Ɏ_s30%G9s (Jр`peo-$2we<.bcdbM \}02Wo>*'Mnۓ;ǟ=C&0Q4~Th+\wFɑngyLC失cʀ<d;TE {_g ?; 4QХӾ<ų ?zzߟey`Vql8O( [Y<.x-X/`Mi )u4o,ӳ3jBidiNhEYKX{>{0t=ZQ|FH'0qRf4M)..C(b?<_~N-D}wUnpQ=d w[Uvrړ1Q38/M+e` i{` -a00; ޻4ۚ$F0׵%{捂މ{:TKXZ'B7)Z3+LI^sco )`Z#D61,NT99@S9efMo@T+OcBEx\U-F=%)4&U0j8@w{qiʃU͝=>O@m /6#-H\+W{~áT@ߎoK=4?R<&n 4ʔsf9zgpf %KxO^譝VuX, Zd{UhE\ǮC畇1NX[_B0;&!A^`D[mNϱ +XlVEje*t*M6t󀔴OmZA}hEeЋm_Nyɵ-xU7kWdG˾M4z=*(Q~[BjCZp_)lA*S-5fG,F5RE,xcd[-N s<2'1++՛0թ3 J̽`1ET?n13iթTDk+?"74vJgjSh9vW/3qL5#;_!Kn0b}Awrr8ReӃrM9!juFpkLs 8 "37¸`M!lBD(C~m= S #2g>4( r#(UJd|߀&,E{ᢵmH@αw\5. =i,s$dYA59\-?c{#N:nf98SqP&x{Α@؈uɰtٙ(pa[jPtO8ylJ/NC|&|ZDģMH~Q+G*NuW}FrOEx0y7Z 褔0Yp.j" fd_cqҼ2rɋ vyDdTϲe gD- t%t5} QM1Cv <)_(RGE=>ĦӰm<آ*MSjil.bXE@oYXQ%F0'*X<U {oE5mxGu&Y,7[Wgr3xAM٤pS[VF|m7 "vvȣQ 1R-ұy_ײW 2b]~bR*%SҠh0Q]2gkEKPGqj޵S䇂oa!Ӄ:/\7bXuC5K$#;^f"LςַzY y מ72kY`:ݜd fj5Fk!n̺Mf VKpozO{/m z+hMt#*xs 9p1t| 'zuCH.V7)MVA/gU&_hޅ}N=`4cmĀv(I2mMB$mA4MWl/PU7!4R\u{Vh*#^@HSNH>]8zO=S&pj3!y\R7jkn$LA+5jƍEt;0)׉aScQ0/xb8KfdFDUo0:W_(4PYXe哃b^4SN2UxkXǹ{Mv@rm|ֿ z拼V]>uEj2d(v/Cܛ [! p Fbi oDaDŽJDk<=(]ߥ-nBB Ѝ`1uw7 ᵻ=*tTm)ME;J*Zbܱ>HدjI8]FCdHJVLMxרdʞW+1."cRO4"͇j,llZr;h1]ں1L[o];!;qh!d*;FcJ*X[.dF86n͵7V)I[I,u~ 2l8DcĶsfE2hAelm#]L-#Mhۜs~-th:AB`I)ɊlnԲر2؊ @ɴh|s*!C>.Gh{R.QN\ ڟx@2ւA}].J)p$:a&K|7&0Z&G_.co..YZhY$&X(*Y!)×-GvmCbP*ȷ=֟w2oBG_)気EFDɣYTEF /'Ț(?4= 9޶&Bxk d PB$Cvz`n_ 9pjg7p9s|Vj A{QH傊L+$Ar+6EKJs $j&uBsw?`ߏXKp2o }Ø ΤRtlM+C=.@5-0bT;s++5jvn 5%Z!<[1aBJy§| N3e]mmvJ_:bR \] AHPOF׾7 G!H8k"O;,|%)W@oع7h- 9L@V'wUXl\^mUq&< v„YVВ)Ĺ!Pt~-c" Zrjᄒt+^HõF+e?:Z=?~l5\#-jX|^"lP!GϧKUy%}]h,{t*yCv+V~6ejr^ܑ=ujXjT'P:/.ʈO1x $l3dmʜO)ڹRA,mwl?RrmTcuՁBc+a,Z$hOfyJ0&UHnR. e>4tmtkl# F$^Xs1l' *9lpsfYiS~;I':_(`K[v΄Ɠk,o@^uCcb#=A9~x51 ;8Z`oUTνfs$lk2[|BLfu6+)qY: <|-d`eZq-YtǯFB5V r)Uɘ#F$}@ 0(-A5#b4} lşɯ@CRԺ$];4TiJw)anܔHWZ\z.1:U*j1>Z yZ:ι1SQ92-!j"'8&.4ni˧Jc· & *x1k1w3iwY"uEBluYur4SۋhWg 2Pm_X'hN8aΊǴ<[e*c"l!?CNlxڒA0Fˠ==Ҡ=/x,Mm0BRiGs V!7AQ+T%~mUbz&cYUwqCe'&Hk@Ech<= 5C\@fYGNw3;4+-_^퍺`&ТՎ$C"(]| ;2MvI2xgLP;ih-zxx\ KJeKҵavX更;6/ CXFْ"02Ƹ `5O8U\=;VmhVI4M ~䪎ˌi1[exo)(WXiɉɞn~U }O |6tL C 6[e2wKZz'L/,J)%; ċ5a0Uzoj* !*wF[) < ˣNVZzD67r#J~g"=9zbue6Qb@GiXrDYK8w3~S)ra1ӜfԄ{X3_X^O 7f*y̏oǕ@|!{@b(5.#Ac%f{@XK.ܠ*="l}l<bG69z3jZ Xu+A8D ib':-B mv jpῖ~P|#:܇Z+-&A{zVZ]H3To `\ l6 "7|2c-?DHyˢu0 Q_`cXj4pye׏H]y8BC/IUʟkI:pچQ/>@UIAv9 -~!U#<^Ȱúpiy\_TY5u2@~*rcEъAдƌ$o?2c@g>[)]>i|{b[fK5b̆`1&BeL0xu%僰{w֌FXKI/zHK6t/6`h,'5MuDxw)BjhKVBiDtM2O "OͤÆ.cٰosN'2EZdopa?WDt : 0ھ9A3A*$ 7(]C1u'**ȍ'W_pT I^ A+MP>?m:DV:'߇ERtfYEЁаI s.=F5kw;uкBns 4˸pӫ^=ՙ"]WF kgDs.YzWF)<:lf@EV u*q#=?Q~!:&Yl$JG^!bCE3Y>!T%`c2Q^f`"CٵM[,U:[`ES]3cgNy!d󟀂V_Zdyo׼ǣ )S) 5J=_b!Kk~gG+&gHs-g 7A O:K} fF޾!HBR(H_j'ɎmۻdI!j{!!8\Lz9}k2pWIheR뙒қMhqp5g<ǫ>w%&8GV^:t=+&h0Of؃/ोR8^ D=;RZiϻv A2jԇϯhCqu zhãmc5[#o:jǶ U[yc&m"ƗlCVZ]bG3j}'1?y)]mW4>g<ō+6rm&t- SI4%%e es99zvU^U,7Zz%Z7fbG)Zzն)-R,wI RZfdбS: D[^jz HX/1dL,"Y2Q OVRoBdS/c3Ѩze>Ύ0_)aori]UjSm0<>Fy8KAXT,t|oB8ZNEJ[$nt3|빳DZ2( c4Q1ضEMEU"8WQD ybB54l b@W9mέӤvkCv8>I2P`]@[aM '0fxDgk+s9L.jQ)_en 䩫v@MV>Ԁ?.׳{3gzWgJ$G,Z% k{V9wwН#+(UM EUXwQ.JbO4a07p都%nG Ԇޢk0ܟ^Yh 4}:Ӑpm9DaAUlj[zX_e$)XTO3zݻ| _H:h䖩: fpXOWBΰuA,e7m8ɧ#ۂfMZaY٧Ui"(Xţv$.xuA;;McW6íީ%(˗̟Qod٬˒Iq랸氾#er~ݕǨf:Eu}E\ه뾘$o<"MT]*`&?ȷ'`J|$T*Y3 ڡ v@<ʀva9vNݡ2LPVŰ/8 />^HX=h8eS;Mؠ=ҷugCjJug Z:oKJ ʹV./ "F]<.) /-䝓/lGP:ƪCz˱ %Is:9jēRDI~E'YiG&C11. et;HN0iVJޅ1LPNoU9klH?ax2TQyɺ A9=A&Ln`v_VeE{V3dIZr\:W>~uƮG6U+p|6N;4[C`OS~2m_Fq_pL@@pc!$Qiӛ˚@Vr2V}aLe.p_xOĺ5+y;MzdlPrMΙKH{ojBFUŽ7_ԙČy[j'B__z)ʫe ySRUomcR*h@9y WuMS{$W>Ω#Yi&nY®Iұ霗J0eˮGNs&Nptcb SxPJLXM bXNw^p^%)smyt~=Bbn''(IhI w3 2 s MzLrcMgY\3n۔J&NןR uQ魍fE[e]7a CG_{( 1+Q׫%ImOH0.~< `XƝ!7UobYWik{ .-*_g!sH82 }`uԙsJKdaR|iowIri]Tmb. `ո`smo)+ .4Eb+&Y-A2 GԢ$昑='q#ʓR]mu6 " g`+Ϻ{Dƿ5^tXpnŗ"Hh #sńD`A|OgF6pW]V;[T>-*ga^+vpէ  {Sd ҦcX\l5bW(cf="jx"Hhӂ\T2^P@)j,O܃RnB鷸L(rx'eCQz +ŃҲ$AR+(T נQFI%}6Ë׉[<^Njbe!t)ITaVy}!$yn%Ce(4 sY)]5oMm"I: Kż@#2ppJ5XQܲ}.NC?3G&juބݲu*1<5^W ^=!.z>[5m(lHC'`lXp!?N]zgP8 G?Y Ȭ\e @8gSz\r.v_=k5Z{Ok 95&;,Jh!3uU^wQ1I/M Ès bk(ұψ(>jElrw>IMjrs2Ⱥ4;[j,g؛1d7ką!/Vp/x5 A vb^k:+1@~VP+\p!B""}ypy `Tf =|"݁i=Q0w#U~'U@QMa$&b~$<EM҃QZRmW۩F;C!5!5qm3yqŷ@[#Q QZgőA10/1TjXVYI PoOpC~]JTc3i %,WzȽ!!+R!tqY\%NVZ(9ZLTwCTJGI%Upawn:IrO֬Wzod>0W*=2ڃfda񘦪a9.Wzn_ a"!k?W~3k=;FtG+hӧ."PMiZ=uK3a!ݾ oBLQAyz\17dL$|Cy%݉vl la?~(/Bxi1H>ܙ'^n~tc1#̉RPρHDv\o|I'ɄYثb2p!ǝ(]Gq2 d`?lIAF|8W'q,>dj &P8X:,!a /vcl,9{8@ Mh{2@ש%tnqYKtAr>,=Z87͟{ #m&ϭ/QL]~a;Sfo~*ڧ{5_̿dRٖz5jCEi5I!e\.i i9VhaBQZP*uE%M4e(9E=]حrH']n[:PkGRgxHU;Xk4j֡+NPNً!W K 6VRW*r-seM}91}?}hC. FLc1~T7Ezh4HS!O/<U(D#i"KXp-#DCکw1z1g2غ)dLĭH8_a"g$DH$ee;my:h1n&QR{O&@[d!5t;a*ր:$a4Ӟ/m˾RW[Jk\I>ɢjpdhd;V4k#lltRN5>,wMaRki/[u>gpqC1q$Wl|cû(M*:$!?65%k5?)Hؽd8z-oU#B _a?헖0j48z+ +q,>Qp Wg.(C w!%1] Rj9=ЮߩK5ˆ%w4X@_NCqzT\>$2@iˏmdv/!z p#VW =eTt¨T=;3ϚWDҫs%yII 'NH ^oQ'zPx ^"K4)]n|{pP|2_>RQuh9@?E,w$(®NsX447 j[π)\bЄokuohR$'g=85RYdNB0B+.t{ T(`[vjݩxFc8RB P2~>yv* 9wW/Sxj>E΀jFվ8l \6Y1u .' .bs1e sj1o k,t!'^Y{XH$ypE'}hD\H}Me#`XM|OjN;Uf&#=*U&/zXs -s_~zK~,;:8J֢}͂fzqbDZٯ?T "-OnQhZs]͉_*0haXSg8sjU;8DŽ,ľ7i| {an% rc!="ӆȺEP*㹖HV"LV6?(-Pݴ_Нn9rN47.a77}ܱJ# %H󧄳fIaUv/ ϑcs16Z,&tIKvVXQ0dw@S ^o˃bA+1ZL9<@z7ؗ**u1tUZ dztb<7]4>j: :%Ndeb"ڊ:@F9ܐ$P'ZP-:M,`NĻhޛQp/o a}`1G푡u7rDLzS_5KkPO [ǎL%[.7N/1IzIay  fwaL]P3F! @Ý,V-/+kv_ H<$}0ʲ2PjR-xߝac`XPv/I/}~"V|oS#&~eKO` Z,MxT]~{6J$W3QhwלFLzX} I/_8CPm}>)AHt=*[^O %c~*n?5b֝TP'wc40VcMS`oR_O,,us_:E@6yPv~)X̩ Vײ@0]'J} @ӂy 7h8'5}sqs":-pEȯ  n/P1TkGC68ҠwxcR*HT K"T0ip GˊՕBO S,V4&GD$zY"2jH^zFY`7osBʲVp"ɬ<) ?5eɘXEu/Վna3"kjYnSeYo&QxU5nMݝf'&{Mhw[ f~76{-l<İǻ+l0Ias3~XŔQ3I*aŹ0K3q&Uذ&@ S?~QHt|o ;e>sZqaҧs l bϵdMбV먰X$sSܼ2{YQ?A# 颻gLZ:o:"6ti=!;tvIa]JHO)di⹃hh*]Ŭ3_K1õ+;ڄqߠ`Ck\# IKh+&IoSXۚTEsT5u$ o , ‡vbCyh^C[VfKھv~w~GlKWcsIFh/o> *UxnA&xvyhp5sk 4FUe6STPkScQ&i+œ^Kz<7LIMxii2}>ȳQFgǞMZm=#G샺8L8MxbqE ( 8j**O)NiHwzY_BQDXZ`f=.L -sV=4[BQC#ThOZ+vJnGGYC%!C1alz!9Pku#Z'l|ia ŧ(Z]λ`UoF1xySc  J!0ŤpM|bUb#}Tw|Д!two*Mގnsbc۩A4r#"Ec(Nǥl9*>  3^#eHF=C$~_~W>e0W-Ȓ>Z|~"vdK,i^U\Z8Fz]~e qӌb7ppY_rT?qYI~ݽ`H$QĒS$c̔"ZQrﳨx!x͈nC8It=!q)Rڍ&zXLHr?&b0LJͿ.i2ڸ${K}خ^b2B4\(;D'Z?T(w_)'Rq XesYktsdQKfs\Øo,#cN* .)(R=jw_.oQ]Dfˉϯͬj0{noC/**o^́22]" w`L, ֫9[noJvH]2kapN:0%L6/MP:A&NT'0<ܓ}ߩ_YВ/!\]~0]c`YތH 5âx "uٖw1?' S؋XjcuѢ!ow ǩBiNgEjf|tȁQ1I4MC1+i!RLB2h3Cyc&Ae&{ä5uIi`l յ^3*ӏ$\=S]hp?8?C5fd%_ m^]꯾e& 4a&[w=$-,_d́6ip5Tkź9궒љx^P#4;{ʕ7rekmlhi9f ҕKUSr7kWCʎv5 3e(Zt=E[8]ʒN<+Fp]rDYPt r58lK5dQ̭2c;/byS T7ߔg@Nk֚=: ~UrSks^q)]4Fbj6.=rhv·e6)۩"ڙ8rQJd]KeJd_iбj#i&%/pJq(+a1-?=KN/r1ͺgLUQ|qG.g^!&P6Gw`!({xq;?` /cxwq@ͦ^Pu1`hr1 yd~u௴,=Yk.Ÿn3}VVaxUYh!\Ѻtu{ZcHJX5`XW0[;1Cz0A0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 cleartomark ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1707393948.0 reportlab-4.1.0/src/reportlab/fonts/_ai_____.pfb0000664000175000017500000007656314561141634021216 0ustar00rptlabrptlab%!PS-AdobeFont-1.0: Arial-ItalicMT 001.001 %%CreationDate: Wed Jan 27 13:00:46 1999 %%VMusage: 29187 36123 %% (C) Copyright 1991, 1993, 1996, 1997, 1998, 1999 The Monotype Corporation. %% All Rights Reserved. %% Arial is a trademark of The Monotype Corporation, registered in the US Patent %% and Trademark Office and elsewhere. 11 dict begin /FontInfo 10 dict dup begin /version (001.001) readonly def /Notice (Copyright (c) 1991, 1993, 1996, 1997, 1998, 1999 Adobe Systems Incorporated. All Rights Reserved.Arial is a trademark of The Monotype Corporation, registered in the US Patent and Trademark Office and elsewhere.) readonly def /Copyright ((C) Copyright 1991, 1993, 1996, 1997, 1998, 1999 The Monotype Corporation. All Rights Reserved. ) readonly def /FullName (Arial MT Italic) readonly def /FamilyName (Arial MT) readonly def /Weight (Regular) readonly def /isFixedPitch false def /ItalicAngle -12 def /UnderlinePosition -100 def /UnderlineThickness 50 def end readonly def /FontName /Arial-ItalicMT def /Encoding StandardEncoding def /PaintType 0 def /FontType 1 def /FontMatrix [0.001 0 0 0.001 0 0] def /UniqueID 44340 def /FontBBox{-261 -250 1059 936}readonly def currentdict end currentfile eexec vAJA aB-1a܂IN7Pq }K@TZdG$MS. p8}֎LOn/ |OPٙyr=žz⽻I ~veC@MZ*Ħ`z`_a=h<6=AE6\]lVcĤFSWpYLAc iiD4ܞpLpKpcJ'o!XW^)p6(/Vmj乧B?oHH}v#@k,2-f K ŀs6/fE !j*$G '\ɧjr? D&L,,m!XCMq$xXSd̼8`2Ⱥ`8I$$QG o|],׍ބ`qO^Bmd%ܴ" b eµ;[8u#vf- V{:nETzәiFR3ӽN2z+hj:507]uX-$*ڢZr}:cPM;LeqDPUri/Y^WL"z.%8LH;֐0?/V-sKDlBW;AKaY9ٗa[w+1²=}H_3arWqJ(1$`¾zSPP13lAl.$r)bd.6ʢȅyF|E `v5O`TsR C=:%VޟiHEMH{B xcצּYq}!gCª7#mbW ScBzDrdSȗS+o$ڋ8Zw$22rEP˽uh>YQ rSoOUֽZX0'.2Rr* (i8' :{s[;dKf7H^+$β;WNyiDsF@Ln8pEdO96ܵY`jA+f̩5a0'G>&fh54`,^"M /PYf7ݼ4gXV75So,v1ym7u?0#r[UN3rz֪ztK٦gYd] [t컓ԁI /E u+,|Lެs00+<*v *9ZYsbr2le]dF}QMG%VUϯIF: P/\MHp ĵhGesϧA5)R\o+':ej2U(ᛮb?Ⱦ%J\py_s#- 59 uFްK{(>yrs7E}{[} D~\1]/_5vmVS Wsd{pa6YWS>ш*I'iu}iP< s"Uv Ϫ!z {KӞ5e5.uīQm Pș\p1UZD Gd%{.TmN2#; 8-AA*[q}L,20w4NcˣY>r֫s~O"ape˪Е49R݋,eYs@y?aq-xfpڥڶ!K'$ZҔI{@:cZt{ʁtDcSo963GzO t tS$}i6.=e}6! v8~Cc]C*E ɀX:rÎHPľ-`$l'| (kuyoeG^ҘEd%D@̐Hg,/R)^Ւinv}4r )>D)xKڐP\.IE]>M"R0)SĞАaxDwast 5SrMKC ` DlF Xr'RWKkBz7/jO~RA990{y8cVBХd@Z}D:C&opx EePUd/3?I4n1Q G#mGb"JHb y[!u۠ ң`-L&XӤEJHT)ݶ=TYfK#;R߳;hV=hZ852<4i=,aMw<1R)/ю6W[8~G\.CPP!"fEipotƣ`<\n, (+yrJyKT"{Ff#Jȯ86v>Džn@[;b W,M[9{MBF @*QTL6lfѺATg`]"s̗(n?e] &/.P8ͷ(V["E%:$i#%w')Vo,~''=;z~#;z} % ‹&?J1%7s J U 6oN=Ѿrxl*3԰!Y@[m4&B|gTXs( m mutCguU,"^mdsտ[60%HV*2}ʐ($oE \M/tٸoeP{Rp&[K d+]4%JHy_zM}Jw<JB0ʾImdRMǫy{ 7"uyMu`/8Dw2^6 +]=?G) ^3MyR`5;qKA S~ !N8@R )Zg28|M#FfB|G߽xQlb_7aLEjh=+9$U)Xx%Q>'?#\T;57!(3@0mQ8{ڣka4uVeL )تuT -G0ɆUEAa~*æ&p.-D ݜ2/)u /j4/yQޠ߂4Iܬi6*9O Y_b(mTTv ηyK,<~4ip+> #u.?h_^jc"ղl:lDq5Y1~eIiER՜FQH6)|vx 9RUӽ ܟx^j_`^OR(aUzOoWOєIntzHm8S)F ւ*8mq,m)*=&T8V0'?@̕&ok8lmh/S:VW`-H'>ڪ4 )0\d/skYAs?! RTѐ}(}S_@ 6j X]$RԤvq1`!uشO2pUCF\=' @v}COBa cΪ{:9&v8Ȱ"by̞;X{'jFg) b,x{8mTItQʕ6Cr@zy 0s2Hg0ŹN_1 .TR/(;A}#5.~oOM1諸v"3-K)+\k.}:4=%217.ۆ6O+kyv\haAc+~~<\m7ܹ27mT}aoNV25BxTOd 9+£~V}\/WHjP]'S=Ucjj'k-(_Ums 2 ozN!raBLS@?hk,V,iJUmH1d=$hW>߼G X5/3%< 'nnZrǙMZyO\㎄ CXpZϟ\T7@ e*l3yoK=*Q2)&IwTBLW1dKϑCb -o #P7KrC0x~5;C5$qIC38쳈*R-A96JafX:(4359; uFjC>a9$ɓ5J8AAp;@`R)z1dra3R !9x܄e# PVu`E+L=Sc\Fp [|?7-&'b⊺`4gXټ8|x罻XnQVq jb d|J)2͇RpnJ/ j7\@+ \ɗυc:A*>at6 \?Zp SplM=r=0Cm_Wu2V;jwи^ gQyp ,9iv!ȫ";V2"#1bu΅Yfk-2:MNAEww˼)҇޾n)B , مA"a5ۿ=ΙK εW1.敲DZkqɒ&;OJB0F"3F3m0%W<`7EgzqӕLKpͅ`AH=ςޡ"6Rci{Z!! 4~BK.Cꃍg~lW˳WF GUbpk̈ 5>kLܩyu(@'jTׄt]) '-0 O)wfMc4_|,FY*d]tlgh+GiPk,;HA݃Q6)};́T6'ĉ8ũ UKb,Yح(VE|j#uMPA {5PB?NkaisqDUuHg73v*>+96MT!ힷoOnQPP2P@5(8~+e ł-> jE9/,eW/ԯKShfudG B)o,iZV-CcjSV/o\w!m~k 5Zuvyu1ڱH72ے҇jՖ}rg Jj۲ ߽nSI~NėCXPM Hrr1Cq*tE?>hXgvE8[)Qô]Ū-Ftܤ{2uIĩ,F1ЋOaq7Yq# &4ct~?$8D13p2NoJ~fad^wp}f.GjV94" x!fm}Qy\+aԞ>g`4.U> N8('3Lv=Y:A;K7΅73vN=ξ\c6/n:JCo@XPUO?=H@R>j˵1̀t~8C.QJܢw4{[)ZR|zNR7QRU#|Qӡď5,~}HKhmN(zZ/#&اYCyiu. rM\496X6]`rl*,?C35)@uP% q̙4"ׇnRC=M\Xܬ|xtsN++F.ճvͬ<m̀8FA}t&OêƱAbVQB]1X{:LG"2(5FI>[#⋮~/ȞtB@q =jie?2Ȫj6/ >c̺cԋʜlWգ>pUA8xתAg 4#ퟩUy`t8QI uű#jK]ux‚H`: Y1-hH1}-q0$(goG5b\*}cY ݨyEWN6|V"C2'ba 96COV=Ravx*-9Xh$?iYkp:OMhg kjEKtY8  n~ڳ+E ]mKk\n{ڎ٪[FS[^6ǨhtdL,C [j΀ ~7(.wPn[{`md/M.ShqA{ t~û _D./as+{ \T f TAU^OnlԔEf$1/CHLelQ^,ceH|z̅ډz T Ð ^[4ӡN'..f!G1OtJÄ=%F\L4ͱ4amsSNg3Wumz;Z-Q7H^5qҎʫ{ zsV孉.5ȉI83KqY!pHc|ɩT.nb_b/,ߊtȽșAq=-&Ҳ=c6V!JW`쨪"(3OC<'hZ0P,L+]W xߍwLC"pWQpQ6(DZ39J7ƣEHgp0 P׵.~e4JD2)ZEU [?X1H b|0O1ύƠ>f]WYM `M[xD# 0^`K{rݲ ǺF^zd5 KF}+]^lEh58AWF}C#L s b)=w5"C(Av3 sКȐ=+'̱]{?dC;ʓIΩsNNUƭ#QW5 Kf_,D1hfJ7Z[AVKh&r32o' 38rM:9.yn6+;}*ah5@҉\c/aV%&JBƁ0IEXDpVh˜]Um5KNxf G n\zJT *9F)jl=;wGsRL}K3w, ^CH`r%Z@aԪY' n(jN=16!iu7}u$Jįj&(޷/5iVDa uO~B]O<1uHƷwMk~;ݷ$c)%FRȧ+~ٔ&==TL>:nwޜvT%M_ՋimٱUNu/GuJ2 v-)uGǂ$YsH坧!کiF2{CWRE@]~{U:xRu)( ݤsk5'#ӑa0œ[bÅNF=M  R$dֺ,x0lgR¶ w0V+&m`t4:9IIY|:V3XՑ̜$ Fa \l˦c ֐z2ZS܈L:js~f>y@b EiXw YesZ9y$I&k_*o4Ul.&k?B = xQz5|FR,*x%kk=A ۄ_kY}g|d7n G'IG] yncD+k@7cg*uCMJͲĝWק}\ b&s8 Y7_&&!M \Ek|Cpa[Y1iОC..~ &62(Eb"M2F,ȟ{6 .b>vy@Y#'@rqfIU/Roǘȍ8!3O~+x- g I[}S,gjgk5x'QWW4N1I?aIDbEGú̢: &vH-Y4WXLu_Н9~MI.=] zc+~Bx?|ׅBW?Ԇ4ՏVC!AUi~`Ɋ ]zus(῜ Ot\%A6蚥y!Ub+.KnLֿ-L$BIY-crꇤmpu.hSz>qG]\?-1P@h9h*.إ9ﻸZo0jkRe*s>[^Vm܀*{-*VN󂘖`PzG[)7_s9L#eCX7 7 ,2%0m=/e#9X~Bj%UzȼDޔ׼mjiM[A (I3btieWaLNՓC݆aMosJi)YŷSW0+48:/+[mr()l/QmپD3nGrf/uUY {$I*缭w'JUL 嵠̢'8 ɡ'6>G+Q ˲x]Ve$Lª~6Ili^Uz!Ixs@ϒ݂v %ܻYZK'~lZ/ }!VcehErۼ{eL5vYC&dG:lBu}/WnȇAjfG2nD-gNh.ڌ'V۲g#S킏DGDԔQ+kP; ?_dOV%ۥH \Io)kʒtZ%X@rQ3PАrmw"DI@(fZ1kTV0 릀[4.Ek+ M) /$!VQ1)ՃYa%:0J(~ED#~ŊBgԴ59{WwDV +w&b(1j giY 0uee"[ʝ V!N8E\WP5ſ$=JOYnÔ 20q_ Ž`P"tS"I]w%bg|}o_cQ_F4LpGEǡQ.Al%V}ea9l%{.q{Ԭb+P?6՜x?V$o|1Ğ;~гـlfaĠk_Y8] S&p?j?Ӣ64Xwzty›m:tM6 c"|2J 26p5^GA4%hW!{ HR]^0t6y#m2,cuq/?g\&c EP*u5PVDb0"& Ed'wLMIXoe x-l ޟ}4h}*ƻxlȾ0j-Q.B3 (Ў  4w}v$W&[Z-pON*t H K[$:\DŽ޷f[>S(mj)Fi8reϭobdrڻRß)ӥ?%YP,y;2VaZ h(=e\Y{ֵLxXd phQ֑X>羕G؈gGSXGc=f08GxC81$zQ`ky yXCsaOt]YDX8{j~q2ܔ4菃Bc{5m(hI5pH`G~p bץmiY :#[N^2LE±{; K]DJybԎ-iMV+zv #0 =$dg>)t"W+0k$#M)dkc1'>._8=֫]Ro$耿Cm}Qs ŋ`M6g5ǿZ#U8\JA7HNW .$g`С;nԡ&ZmQs9!XrdB0n&ò BZ hP U.%YS\7 ZAt,PZ x2?&Z_] +8¤?us ~=ZGXg-r3'eH" .s1f? NN~yq?붆;Y@R;HBueUdZ.8oԺ&W BZjra^f B&Kre>(P>P'o9o-2{Ņ(  ;rxzx ,85~.ߨ }v2SSl=S}@reɈ;o&U24Df.+4:(-c.q/iJC3`@612'u?AK@ < 2mlVT\Kr?ՠ,Bӛs:慩2;vi^}ދ,O3Bu^v  4 r{uV c:VjLvi_$ZKĨ{|Γ3m$,e`z$zw t|R!HkIG哲SrM'Xulqq1Z;- {A6^D+l?L[X0u^Cc`͕?{yY;PK~OQGgExD9G[n FR+рRաRiȗP!Cz:S5zrYuߛ^l킒Z{yÆ9oz!`\方Rɾ m8:i;BfY}X_J- fAwQh pc|lkw4b8_g:[H:5&Hӆ4jn2}F 8l=<),cϵ ,ŷ˪DƲ%&tO# Gfq~[=w :l4D畬Sz["T{+nwW\i#|9WNtЃ㥝O6jŊꚃjCG,Vx&9ym0eD7{A&鵑D^m/uS;yiNÁgtٺ {/uY;IBLqU%dGq?7D3apI2nPQ\vpX)>vJWmYJZN*ZAdjhKvYABuϢpa+ -.GK{ /#4 &"%~Bu J$L] DC @G6~T=,U0dLJ8-gl_;W^a#^oam%>u5O|lؗ!ӨY2 FUpAp&m~ӒbҲoRüvSR5M'G iLfՉ8N@gyxa'?~ڙ;C+4g\= ^#倧B&|:I}MԵ]\ 8Q\bV%3i6E%ˆa2k(V:J?-_h[TO3Jb+WF2T֙߈9e Xܧ_PQ}8J Whypp2 ܩݮ1܀c @No҃ڔ O&Q;55c*cQ2/ϳ@W3*,,"~c;uAWֈD( ' NPsXS֒MΖ{@2. mz"̚_ %&F\^ x6 ^a( oxI{«VmlQ >u[ %UL J {ƽbg!DRx7p0Uf-Ft>$z}fju 4&@vq+)>`&t&,׎) 7Q!fzsiƐlEzt$$51P0_!(RߦÅqqj1zSf+Q`AnFZTW/-vQ{=)zVf(Z o%2}˟@+S-/ZiJ2 E{oqK+ŇP,eۜMۂPⵎ臭 yvd|ǹۙ`dCw1刖oqc $-afFǔ]) z5`MY"Ǭ nȍ A9`)Dl f$Ȥ'wa~Z]ƞgs"ȣ:yQ^J2WfS%i;oS:c,θMl$Zt=`D4K 4XK0_iH ) _%boW ,NC!pbHF4fB|7+@*xb-rߦ*,fȝ2Zt2hKzǹLxo^,=tvyy({+N< 8P38dɕБ sNF,=YRi|ve5C6`g/#o?<$>3AJ7vYҚ,oym'ۚ5oJѲ/('$|:MnxNW(}'B>k K"chV,eξN˻C%aE9Maj|Q±Nh"rK:mH)g#.v*P Me<`<7 Y[y05 85MpbH-X+4erȑ `6$ȃ y6'Ք{i\2\`CJ_\IhyŝgR^HچL59b qsw YreI*0_A|ѭO[>dAO05:ۀCW,L]ZJ"s+}?c+EGL_OA&Y!Ua;W}E5@Cs<ڴ|{)OM_s=:ÕrU^/\ 4/6K8;:Mi<#]=:J{4t:f- r>!H7HS$W*¢M԰5^](؜!u/%] f U$}897!([k (9_UOo?e,^EjGYzTߢ=3/фh핢4tvT՚N"Pqxb~ lK6礂eMO4_ӭ|ggQKuec@$D:^SOq jȦY>v7vUٞDێߍǕlε=%&%5BF0Ylm_ptn4^o ꃬrHabW ws*G[=z2b\\ZEAZThjh!-*v<֎Xvjl*2,]Mؿw :] IN#Yy)-:''nܒDQ7vq,dSAg>o.WP71C^v5]eF3tb*o9ŮCJ vk=)jY":lAP*wIQ?` h[s Ϥ*F1/]l1ǃTŸ\-'I:-K?U %(?siz~N\戩t ECZRG%9Tl|>aocJ# (g4mt)WܶVZf+h?ȥNYsϼa7D0Ri=nqd vwa wx/ -ޢ>Bv([]q*B͕C.VGP=~ y-Ye vkh9+1OeE"I5z žQ ƹJEG. t(6u{4<3*OζQ9IѢ62xdzt rʨk=\hT5}ǟ1S~W7Ja,k\1,8|ZkX<128O=# PK*AI[$eN 5MIv{F 1˺_`U.J RSA:V z+Z93{ }PL hKP+1qBr;NtPfٿ R#9wJb9b-aBarVY[11Grg~̃5ǚ~=L`5k^v4QeMX u1It &]+\;ʜˑgGnȧDs_~U)굋DwD z1r+=QBLan;~S4KAOu l&^zEOe>hRbm+?WLB%Ws0J M bP'"t4ˋ3i>j戴Ґpy[s'd%E, Rkj {Bbu0KǻALQaTn32%0=l ׎X;TuA|z^e)W7L,7q_8$WTx-)$}_YgJ06i _ K71/Gˡ54,Nr;_Ɏ5]}mHǗ+bl +ҮZd_yLlS;{ K';v˅5拢Tb2$0N%(DW<fBa'w9h8/YJ}F5kZ EcZD5}98 ,\A!>fyC0ZE=\w^XI]D̶"tieb›?}M&"8<,oiٔaƀ L%:9́#W_WR<{|= h-K@5ދA갡Wy NͭrU(]ޕ[0rdql.v _? ^䢱: cF&78RpÉL%$1ҍuLK9O%WQľnieP嘇/q U@(GD^'HY3o?nҌ0x!y&#'b OL+PS~ZRq4(jMa$!g9AjNdsX:_,~:L 9mOMgĹN#J-teS|r?FX2f5`Y Ɖu/BVou,'nPfJ~o-5T*bڒt7mY X5-f6 C:r`~`~v]IU񻍿}ķc[ \" " KD%4+W5s5=_JQ|rf$J4wZ/VI`F{Ɉst{AJ6|D 25µ_$Km62Ac|ߠX:9c| G> XxGkV41>ǒ54=Z=5^̷'U@*V~ctU+5C9t ,&Z ]6.~dE9ʶ?V5~O-=oѷyfS`b탘Y-~3ڱkXt/^k зm >swmjE&ժ؎o;&J5S:P!96 M:iPrUw],_֕7# /S7&i0ڟO)YDdK.b2-M>J8zqMwO@lqVBy">:Q2'0I*1*GQ_~u:$W֬׭?v*H00Eq 1($J"t/TNL'!BsQO)# rFJFv(T[c:gd}4?8Gc gB9xP?֫o[{bj1{"㷗[c?8m )x4S4[wzͬ}+9~GhӢU{8^p$q,r)465jMUg+>N8sˎn(sgleo2ŒCjyd뀟}f:DZ3=MP/+.0/4o~ V)K3;=>{E_fphSr1>{ UnXDsRq%3f1wn(k\*ki@,~7@!# mY^@k'44%nmzw1nRM3-Jb(w}'fpa)Gh;S1/ȆR4̾*מAڌ~67ÁIoPc}CV! * %"O]6{,}Y#*K+TCZ<<ڭU# tGfHBU!a]#0+#*cGӪŎR<ފ A<"ΰ?LYrU:elYtA1Z^ds7,LJFXr~ \:굌'}Bd1pOQ:% ycX޹ b+V a9'g}ʙnsl8^&Dp~lqJu*vÛDItNJ+ 5* o{J.&z/D/I+iI S ^6ndѼMB&4ŎM2fx-,qqm)%zN*1SvXhF*xR/y ~(gm{ۗX2Iz޸^J# "hB toj\j WEOC!FNUh0Lן /&^no(ٌ3a$'1?t[gNl]Dg]¬gcևt+k?Uiϩ6bA g%7(Z\ZcD zu+,\d߳T7?y!'~ `w|kArQ|!b+s˫eF2h5]K{ 0Db]F/;2"TDl`A--Ly~"}A\\n6{xL[k|;$5.~PثD? xV/+?b #p?N!(o2'\jq!h]:mQ%ݧGRuxqd`78>Ӳc91˛;]@B*4Π)g?>yp4Z".MY'xG$:5.6//yyvoojǕ3`T3ϗp96V&i;Ɇ*%tQ:f'A{] cHfYNFvY ,m30Z;/Q,2RUo DD@xSoR'59 5JyYa}i4~q;ƈ?}۳È-L,<ח]bEBœsA\8 _ĔZ`6 R~~*;n *Pl}5TLd+ oWpETg1B| ;ܸ $+qVoXLw/Rn!J Ph.jS@Jd6WCA>.@t\#f%zKF7+Qe Urw23m+Ѷ<TEjPSAlk4ja!C}MGc[|碋'*ޟԉ9Φw+}! %>ƊϘƞ5S2,X55L]$io6L9ˠ9Â=zr̢E)>4!:@3Kt>woz4OLVPvSjMeim"b$#k CsmJq*^*vH r@9u Z\"{7JXIͣR5C jZȉUY[yREґ]sS]\SWv֣(}9l{mod½T 6.Ųtp>Mx4-TʤZ /i'jiFmӔ+ koGGt}/cL,V`eS٫ɲ(t쉏&n(TA"^Л\#hb 4] }#YBckoOk` ̳Z:bthЙ0ԅPź#4 $'4"I1ҹ:q@wTb%7,YW;Zkܔ' BkS>} 0X (/,R^sFHUڜ|~Lnjhdvz2]4Wᨹ{ C! 0erzڑ6 D%w]Y ș*@A϶@u͢*`V3m@[UC׭mJ J}Ev-c4,r\PG >FUǸ,e1Z\q:qؘ0]0]h KR7~YƢZ/?@xSį:C/ T'tl)+ V0k{%ѻp.@|q z$,Ű  SL#J72t {?FӣUL@M*U"1f vgpǼw4'[LZ\@ܼ V)m+͢ }A޳.eY>z8⨤d,mTWB6(*%]̤hOT(ND^=IRəPGLfk#g 5 g Lo'{nDQ1!W ƾV$=s# 'K)MCNu&3p8]8Wk,~-:t&BˮaCW*^+ծUI@XUf@s fTʸyk{j{lkt߂|ŏuMSݞUxcc0\YD R=YpN-ٵUU9gٻq ydټψD:LR~m57U|>$IY/Rzlh(T%8A^)}$h4C)Q̺gyF{vn 6 `l zw1d0 Ly^eYi3]I;p? n'HiQJ91%+@KZnDrj=v3Me,,eY*^vg nBNd4v3zJq?y _G"`rdCG͵|;$č{QV$GװXOv M^(rҬ+MV O])I5 Ղzj[({6X>}ohtk>T! 3] 7 2QGO\sl@Ŧ]D lDjF P@U`cw5o2֓FD&U_r䩅Gxnߜ)(s+DKRTpag#  hh$~f[W͔LOϚ/h.v1f} I e{n1yPjYf4`:9JZ'\TcLr~ ;r6Z8Yp:vC3I'0.L`+hj5mQXSҳTxghh?.yu3@+YKaZ"fANǐ}Uy2#1w8|NSU"-e>U6 7kip$]]VK&ў1Lhv%h[{sG1mÁC0F<ѐpWVuy) IRM·m}$anjʼc7lzMPR7?@aOKuMDgEGjai5eR;<%eUGc+Q\p4',A9 c(bǟ ZZsj&[w7kYO ϲ Cc4B:iQ :QYɠ&y{O/[Qi="%BGx7#i瓟qCx `A%q90@dWhAw,᠜qOK_J^ (!'O)ߴ֫1%:3‚tи㧜߹vEe.Ƒan846)V޾^8+>E'#+l<9ߦbQ 6ZBhHN[OP21"@t"7ۮȜ*dz;QҡPY_;&W\9C&jb1}Ŗ4䓀;rZɏ88@CO],L)]O /ZdA%n_1gIm#)wO$l:PhEYS~A+py+dDZY)oID˷~0FA@9ܻǚEgEf02?&Y$U,4:֋ѻM",AFZwFݪ5p]r lr "DԍmQ̕FOGɮ Dzبdń7;x La>QuR@?)/ј%h00zQZi&eyҡEK*ٗ$ջ| pSMIҊ znj8ƒ}\k,Z>mʢ ۻR{CQ0= 7kgz>UJLڲ?1d je ezgvVKܡޭ'.@fEE1m ̜E31"&JCIT"e/v;Dd=8~d7g@"I P*;C\(C^HeC-"AWQdʙK82<ɖUgDZ<:xbR.aC S2_[ JD< \F .UaDa$@$g< .=ʖԣۮB~9R=_Or[*鋿OJ-DޞH4PASwk9@6ohB7h&Xk͘x$~G>8壸=/[Zq(א[z6 P◡]SWiSk5) 0e=~t't{SZ:zт, y/6a2X{!f!vow6Eu9CYM,hGAl˲P6v7 .*e]ܬ0ؿߧ,-([ʰxOA"gjX|g?2C!f- sʋIfI $BqYUnmʋ05vl~_Mhϲc['I. -=?Agі4tRe[:X~*s(v} s8Z5nN~7닽OXԇ/ʚU\+u۩i{j:܏FY0vuDP2#%畀g~@1?^ݫD#n槶 -/!ne"u?(MWY"u j4ek.<`q HѾXE##e/(KòL9u̳"hRRf(@(6 nz뻺w`1J 쇇=?GO'[d"|ELI:RvѨ&F&+ 'a}JGr{IbÀ0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 cleartomark ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1707393948.0 reportlab-4.1.0/src/reportlab/fonts/_eb_____.pfb0000664000175000017500000010506114561141634021175 0ustar00rptlabrptlabZ%!PS-AdobeFont-1.0: TimesNewRomanPS-BoldMT 001.002 %%CreationDate: Thu Feb 4 15:35:30 1999 %%VMusage: 31834 38770 %% (C) Copyright 1988, 1990, 1993, 1996, 1997, 1998, 1999 The Monotype %% Corporation. All Rights Reserved. %% Times New Roman is a trademark of the Monotype Corporation, registered in the %% US Patent and Trademark Office and may be registered in certain other %% jurisdictions. 11 dict begin /FontInfo 10 dict dup begin /version (001.002) readonly def /Notice (Copyright (c) 1988, 1990, 1993, 1996, 1997, 1998, 1999 Adobe Systems Incorporated. All Rights Reserved.Times New Roman is a trademark of the Monotype Corporation, registered in the US Patent and Trademark Office and may be registered in certain other jurisdictions.) readonly def /Copyright ( (C) Copyright 1988, 1990, 1993, 1996, 1997, 1998, 1999 The Monotype Corporation. All Rights Reserved. ) readonly def /FullName (Times New Roman PS Bold) readonly def /FamilyName (Times New Roman PS) readonly def /Weight (Bold) readonly def /isFixedPitch false def /ItalicAngle 0 def /UnderlinePosition -100 def /UnderlineThickness 50 def end readonly def /FontName /TimesNewRomanPS-BoldMT def /Encoding StandardEncoding def /PaintType 0 def /FontType 1 def /FontMatrix [0.001 0 0 0.001 0 0] def /UniqueID 44337 def /FontBBox{-180 -250 1008 889}readonly def currentdict end currentfile eexec sh[L4 *ra}!y[RIW!"2aC':6 @5MO*El(nb-4BC@Eu[z@F<5I襼z.!ڷ%r+IX^v oh?" L޲1A C۔3-]¿YA;͌*b񈇵][ šq.:R3QRྠ߿H*/qZAXqȤҵa9?˃ʻ(%Z-3L+qP5ׯ=Rt.8rsK&k|b Qy$A>)pkwA/}~8V+K^Ҋ{9 4D{%oZ,PL;`B?_ '4I19Upl|hV֧>ȑ~G5Y pU{1Фex wu^0ȧL3sfDF> rBaiFB2<84~<l-ҺrC|ҭ?iPp9?94cch3vQ& m').Qq{v;gS<1l77v#, ~਒D֠kazXOP+Pyw(c 5 }Q*@h;T+|9|)%'e ]8/m:ۊGo"@:yfX))l[zЀ0s0v nvr;џȞ8*D KQ\ؾ?; =\6רU H Cz(&FMT?mx ]U&%~!?5.3-ԳdU œW(-P4׷D7ftyKuD@'#!vjLP|޾Y DME m'gAKRF|MwY aVi'V&Aa`y“0i#Hŕ'rFJeyT$z.xӖ4p6@86II&A]Zi oGseE< ^,%I͒`D=4@?FuY2PZ[~6@99n;Xuv Mz'*FWx%9Z'vaB}Q suk8fPJEGd2V8e[1 Cm_M٩w-Yyc0<1""(Sֆ.e ryNkcu Iyu %syŭ 2cR9@ocv N)]R`q h쿸rYx_.@`PT _0AWga-6síE.yo-qC 4?~E1*O%M*XGSk@i؊0;=\GA7|FOBEDQ $9[DZD\ 22(Sͭ C0)s5 8Q2o1õ7`&t6 WՐybcP(C3BEr*8aYx]`~BzM̘xGt6ΐ |DĿvLf8Mdy5MY{}!gKh.?qVL)NBRX4/+Qs"-Z+_^ށU)r@sb|% Zfc.tz3:;9.L\yGyӶu\6>3< l1=<ͣu>ã I5rN\QAZwl+[ui<%߉18ki)|MHJ(MTh41!~1- xh!c",Q!U9>oJt"ƿnpT> H/D҅NZd%4O(Q'sY<ւ7 8Xiw2t^{ -~-'%f FX%ɱ` 5Bܔg.7sg^7gj9J+лOҞcC&qK0C+A$3M2mYjE7yw`a֚lԩ.|h.)6݋yb[Klz/2^!XCJm6s~n} c!eXgdw D ||um;A>7w/e-="rc@gTt|>(AhpXE=O%^ ??W*l܋bJ{OgH[=dcm$=oO\"̮;|Q,,eLn6x̐E/?5yYWI)}۷U뷘LGɿYۉ냍ٴnz/\HS{gF< t6RiN:{Nl6xf|P@S*qJ餄jӪ3Z}G1h vy&2qŶ,p`x7 B2yUw#73? ia.Xq[|T :[ljݵ;OF1q!q#Gd>h@)ҷ^m |K?JX$Qw`?"gĒ8xkg2k9)^hi (mLΆOd_#c/ƿeWy&l}^X{Mܚ;$`u3r#ZPcG yaEn4ITO֧fyrc; 1Fbj[9# >|.URߋ0skT3j"a 囒9"e!I+5L-]/)@\e6Fq9߬j\:#0jk2͐ ǭ PҲ=Ӫ)._A5Y(C' HB[;[idMr 1? \EMsxm mq|j|01sY4ͨ(fvárBR58n|E/w0 <$U]&e}d) DZe~@@[nE4%&/C$˿j5Rmt,xa+,Y§ߧQa_R/Y&7ę t x ԫ*F%©1x\MJ{X?6unz% [i :: {) ^kEc BPl @lhZ5<5u\ [esQ[`Q#&E$ TYO-8vOam0ǀmte}SdōM.B䑠;nCᇏ`]HX0Ys$#S"0%+]d?iEK1p3WI,Yz=(F)LZ t"jf?*͌9R$_zE2isR`{o"5z,~mf\]) Kmڄ&~%y+PpB( &He< ~?2 |r5ԬC^ST C'HG_=T[}oR_)yGt5NuGCOe2,6&`O{LKCeT rb-VR]먰o|iE!eaDk`D"TTy! .?Ҝޢc~ @%Ox'xoYU0BG92tc;20$3 48c'd'h|*"2O}߂^!UnokCV `M-KG]Uot{(it^iu%m;g=3;}3G8%5` 8V4pO9wPmE'&+02~XH*~IJ(6$e#_d4T'FR pslIwE|:2&=LLԆ0 )oH|b?l:k\gx+=-[=`ǎv:dg'_SI ̉m$o=gK`Q#{(Z=r FNf:a98eB005=,L~fYިu[Ob6bT/=B5Ԉ0+ m }ךmrfR:t.@gf{URx~ iV0ɹEGʀ|AhuDf]Oiރ,c[u|2-?I]Xf]C~X>=&$^}z^/Vha܁=}6u#5D'jbS(Ls䚡Uj׹L@vV3HJ.$ ea>o赃X~7tB۷GI~3|Sr؆+1WU_ﭧHeqU ywT}hZy}^EEdVk thw!Bwo:RXN/t"LDfwf/^q=U1V}oHkR?(P9[05Y0",/s9"),M4Ryg$)yŸuѥaWBLX$>~,l'|.':ʪ>6@9O([j*ןGwS{"nf kDK#ĭ6ٚ%0YxA|9ÃX7.|;ǭ8;֚W@*7 LO,)~@:]( P9Z_#c%^r'|["=M;}跞rAM|JcTv TCا^^^R`&⹌VNy~h0AGﮙMW^I|Fu*%PzuN録>c{u\39wpM2A-_"Eb:N-sEdѩG+Jy"/%^; d:DiXHMVMix݀$ZM2g*M?@i.mߗa{TD/jp')+:/&j,(qR7]m"?!o(*K;ؗ^!faM8L1v\l9}oQ7_`uY(P8l~@Ȕ-Fn7+[07w@u4Au` !F3m_:1ל{pŪ4uwػLfoL0kŜo*{լ o"a-$` tp;/zO-L~18y G׷=,EM02 K7KɟƮ-q+5:.>| Uʨogc,!a7罺{^ƀa 1ȅ/Q +9(-c#fM elo^ MQ|d4niS 6C6}ꠏcDna{]E8l 5<~\&4{QC f4q< _gd MsBO>ʼnf JYes]6lN&}K_u&?>4^02O`fʙwk[!J_l^Elm/J "ʝ[Kk7X ID{/ xbz2zø$yQ==3X@BK ` kQ?@X.-QP.w̹qtCC2޳©Q=SBJ""T5D.;<(>,AyŏbSF`%AU, +6_}nxZ?2 h$o^AAhT郞ˮo٩mZ;?8>#_ ſ<9$8ldB6 ^*9mHb܎f~ Q/OX./y޲4yCõ60%+5.V8t5ktwMTz]sWKO$H"]p(P4xDGM).^$ϡH^sL*UL[ݿd0bx|JNCAv`5Ij0gӍҥ[#p]El3b^!E*LdWOlNh~M} XwS[ȃN_GLrIpa 99.5[Ќɪs$=5Z. }EtFavkdmGއZY'+HYpԗ۠_gau I_/v和ϠC_Bcdט2-a cKp@WHWŴ߉? 4P\L;N؛i(`?yF`ف/F'@GPIJ}<6aZx+8Y2#3z&TS/$&e"kƐ9GN:4|WOiЕOIK VqW) S{Vt}H?jr쓻G- yn4!vH#We (8r#>Z=ny}[%#3+8|Gn@v#sZ8PeVJrN$uJ^heІ(jQSXA49@vvb^Ef{_d^ @r*,pQKjNaε]C$JեĖ%?nx*Ͽ_~ w?C $@QRRzud$p= R}?^q5vfv.# ODţ^ܹG̪_ q,z^\z`g2^N߶#Թsn 2_@fvb :^;w!,P3œлYcÆUj0YqJ2?rA^tH9Nv)V`["B{iU^Tw]R2mO{[>G 1leX >4hb̵5́Shfq:|%YȲK"EF,\&rO0F5#^O Z #ErIͪrd_ _.v hUM^Lmq=VHazeNLJV`Nq/VkH8{U=58) B;YQ0}22]΂-/@}Z+C&Xͷޭ"9LjWUOIVgt}N#`*HR` 6?tU7R6F$W}&[/WnP0l%V~9 G(-q!"sR&_\.C歠$ HHRK} >C#5];__ݸgV4F$ R q U2 ?ed`JxF`\@Pj5O%cXX UNt=7hz㓋. 7nH|@\n!\LeObZ@KN1υAt4"mo9g*)'(0b!%IiN$FԪ$0HM{&vM2Jb1:˝w+&G"6 'gFo# OO ܥT#ĦnH%fm`@MG#V3.o×,[J$lD6=6ص qpRd#Ypƥ[76pmJa/yd.,ed%:HODC>wL~NP:ܞFωQg w).lDy8 ,4&&XIM/M e ώbe!bsuPW~X rd\"g}̡<9 PBJ=7KHU >Lq:'?ݼ~uy I9ESz6pg|Y/xcF Yq|1(ُ8a&aUY38g K?,|5J?L8I(!3XH_}!pLU*d(<\ J}ƍvaE ?_Vӯd,$^ +b񂧠'L&7S.;9E(ujv@VЏPyӁAzx{VQG $?tgm$*fEq,c4 {|&iCz;s  VfqVH^y##;)IV8CvL=_+cZLy'oX#B%y%|. KOpखs"0á:>sAPB1p$!FDlj c U;2(#q@,^z #ijlj"LFb]?.4vA/sXSN!6@DszAl))lإ_ke|ƻl ѱEңuJQgHcàASnZ5Ztd N/ɺ^ ]zӿpH){.d?R!G\s19xqI4'Lds(:,6j}2J-!HꙃW>;U`hԖۻy߉F8E:m\3 :?D?s3䌗̂%"\s>FNRv΃]Q8a)sX7F]Hr+z BZb-M9~#;5!ZD/DC2NUw1dcnNAdZm ç&Gm6|Q|Xʇ8\4~G5J/BOn}T݌E1~ ~X,rIؗ0J/ΑY=[lźR2P;tfb7U H{)،.Rd\# I~f"律zU4m[I)-[<@2MSN5ٌ`9'# aœOSJ^@Ӽݖrr=эs14Uͼu9S/Œ$df?!&D"\.5X/kY]`H/4[UML'fe<&I0F[ TSCGYF:U" v#|q='MKa)nǻh0D~T e L)iYPz[}p%~JKKT˛NL,iUv aWJ܅Y;:mG+MOB' 1cFzvw|qQYl|ǖUUkju{QHBq.9*crӧڗgvAgBy~mn`ZV؁3>n,irtPuH;wG3.˪G쑠@ B}0WQr6\ # V}.)I`"λ]?Pt]e^U\^g.sO>ϊ:ߤg}-63'`9<QcGujc]@1_7#AҒ3j'"]T]Y>!I㣵p̧Ax BA{ۥ#Y5]G@3QOCqX[/W`K牓Ӂtre=f9_WfY7eTА@.QW4 V/w3<"+R M֛FMdyum;BҦh6i@U#k1)|L7d Y!͔ sޔ+;p-Cŋi xΚa i}W*.4w1i_=)zq$>[hOKyX&յtA>|ed/k-HC# RI&pE~qk]JlSI2Rd9StSE9;]>T -}Re ϗHgB'Cn*چZ  wPiZa?H(eQ'Hޢj+8À3RmC9ӃY޼)n@/b#m.SR+\+4iͶ95Պ^wy;* ȇ3u{[R-d$ uGkm:D@@|jtXqBien_ NG[.U 9茩Rg;M\& :2?1U)}EH= 33_r%q-4<8G* @96æءC<`̓ /IY$<J v1UREi(ҩs^/f ?)En䅬/H2qS\cgF%Yd:YFb !+'FZW:k;wIhP0K%?C9VփCqHt=D9|3}Hb.mt`a@'tHq!C~eE:Te&pG%?:ڼǎsOCRpm+#s;sJdwȿtE3Qp0o- )OPp5>?i$4ByXhlFu\kB9+:XGiN؄8Eif6JRE 8[)Mo S'u>zr=(7cx.03\i,:}]^B$1cA[Z*4j/ _Т竛%!{;F9'1ߚj,!˨ۡg2T3l 2-t2 ږ#MtT|a3AN/qʢZPG‡=-w Yg% i]Պ&g-d9f75TL}k-f谗> 3U^;(W U.cvSO'=[.j MPW?j=F_Z".qU3"j-D~g_Y- -A|+JT x":do.2wEd{/E >/Ec5lؙەsWA~|ع1ݕqNNs6B`yvdEX\SH(gMw d[浨۔***Kj<{7 VvhFtd.%"R(vռzc?FN9*_@ֱǜYt+̷Cb?~3ɗL;|=9~ZYAg9݀aT_MQf*uD=]űt}(ˉqV ] wjR83MS/V#Ľb䊥ńMiQP RA4\.Tw؊P44Y·^Asz&}1| W@lz>Gq %j)=k o!M5-8֬$i;76Ϙzw |\ZKV&^K(Fii/=B5b)b s7VC;]]LoZ'Sx诘 M^\MVZJAvԣm;OFn4@_5ۍj_6u 4_,G3XƓ3ƺ[Bb4_(˻m]/++PN~cиrAU U 뼣mhgA)Ƚo `b_i0?؁_1? )!$tF3,Gos5o~Ӂ,|$QhFi7ѧa 1VU#I PzcQqRwn\4H)?br5$/5Bٜۑ'"%5˕4ڟ꬯PYGp`NR'hɰVN?6F C'|7U td[s)_1u!88GWwJ3F*ts4̑ɋ+HķC Q]xjnx$p0zZH9j$#x`N52E%= T~_1c 6ʋ3#q{zw k[ 3rwe&"ֺjL+3C\ע"S6n߰sbF;|1MsVm#=ct`GEX65Z$1e!$I#ҁhMhY[;DJ_ r" ʄe O6NFb€嚌?f0?W.(z-nhPL棅ﺁ,'WmYR{Dk88)^k.ehW>i&xkcbeWb%)I FE'_O}ξR*>ۜ:&}7VȮП ϻ),,E[~0?M{<b(A]vjpTh+ Du7%D4i^=>GzpYB3~Diʃ>3SJUHqGZT&r!u|@KǑ.vw}$ o)rE/G[/3EtY{^#X9"W.uSv3oy <Ɔy2ܕ-X\bb:K}f :Z/(AyB}߼2\HHYnr.o #oۅPDjBv3*>q;FԔf=ص]&`ưɰjSD3gQ A[_T X84q:4<-`g%[>57b'*i] 8k"ݶOXj9ݚx\u 4#k*Yu|!ֲ; m|pj;ZY}n dB–X )ܔ"2+]LjnQDh9`&UDنcu(fn:'cvF|K/7ׁ,r,g4%kX8QDA&<՜n8sV,HmUBw' ENVt<* CFq]2 MGC._I źISO30 ǠU7-_EwП E=8)3hAfAwۨr˽ؖ7 Idؒ=ymCdsFpKeƿ`:@v% MGm*^#^!/'~=_OV̮뜡.*%HشsV{3o'PUϔR/\Vm&2Nm#0O/$B P{\\?}$]9oHwa]f.]ʱ RL2M ?ͺ8C间0p}>yFrTɯ)䬖TqeBl&;5ޠg {'h$snmZفv[gT !0ԻGEdfU(e/oH˔+;xk₮OT YEJ8oŠO\'Qc4.Cd^E-"ItN'?1(0h< 6UKRyTp`h)tL3GQyHiI5$>*#(>9P/m[5u\8}@ nTe49cwâ/\oG,Whl YJ,4iYD `Hp2R$ Wa-*8?MX>z"Һ/;zNGk9ǀtD pΎ.A&wV>c$L8Acͪk s)nHc禗̲[U^)I};;@S``pՑJ ^3 }q]Ϸ|Fg9 i#42ԄDˏl\) МbWi~y K#_Xno X.k)ңZnxBߌ\]C 50.WR"wj:8-qfԯ$m\ :r<R'QA~c`_N\-c;&MaJ>(r`F/čɧ!lh=iO=U׻o53%jrX]Ŷ1p 65;jݠ0} Ka RC4"2P omkx`%??E7;"+&h e|wa7 ]_1dfN܂ܹu Z,sr'g2z q,H־$RiUA:7ۉ׵?sʘc=߲%dD >:%tå ; g S _̛\W$M?:OOzohxQ¢qQK|> T[˷P}mbC~$jj:4I21(AqbF)@އQ^ܢM_(l)ؙФ2 Bs GV:?=p~A4)*'xMށoj[1VNWUI+DA~^!GtxZW9Q(,m^3MmuzOeK'`iIbD @v6cqb2W 3KO{j`UYk V(I{,͸~(>JTiyt~B35pr;/Ch؅fӾ ٷM9iMzCP:s~ ksn>@~B'Q4iZD} $W?uWckzm}i ݥ5[0, qSU B(m\*nGqgHB]gܯx%\B {$eg2 1+Aˬ)ڦ]djl8Y H TF^~nѨ:D93(vLNؤHXq=\],LȚ䆘 3|bOKTx` I<8YD)|#wmD\,6gW@Cm<(۷cފT(܁՛3bN=+@sa0!]I1y E*]T4KXXb {n۱e^V,VvĿm׃3Mc_|,}p|zD7-${5>i8l04Yd @ .*};fXjGcΐRC2sϡƵgCi,hy1ӌ[z^UƮ`N5c{Lyu/d=oKq֣\.[@+CrţZWaJLh'WzYX>(}֌۵KfJ$\$.nތpE3Ano6w5c%u!>11$ ?2*]FrTEtG ?TogtJH4}amPAHUr9BjC@E8J)(BFm9ٞdR0:P1Prr:db22Fs!t*meU\uG}ĬP&4?#[_wLE>TnaΏrrœj2G Ds YEu+Dkʳ UˑLG]%jqǝ]?qӸkKAJ4;xֽ|!G]<}ACghrjVb#*tSQU=rlm|D H DX%J _5cƠ.ZJ!rX󭄷$]/f31fL~CvMs׼vH`ݚp%i"B*z9ɞicgDh[/JWI觾F۹~:`''YD˾v|gzT0`ni]] >l}Jd#<؃w9}B-w-hDh@`8:('>i4+t#B//O@oF0fK)P ueEd\q+zE`[> 0vDk`%mhe[QB b;mW*v\t WuUx5|j$tYA7/rPUp_ګ(@BeʪJ u!v=\͉.vajevκrfhKQʡ5`m808VI u=J|μ$wbkъ>*f>rWb+Et>Vs* ]ğ<%mBSA%o2[ѫbc&K+J%α [wPgo % H+ýEu)&..tm%5ee 5qC&@Za=xQv zELk3$Pծ,5t(U_:' q@=ĖYJ LơnazH~ 3Bd}Fޏ?"<29J/U-g_v^ׁWk}.!ˀyvՕ3ӔݸfzRzu?h8FgV*!mR%"tneBhbn}!WB7(@ L W2)yn%) sdEY+ K)SkM:9QO_p(s~{f\QV"'FWd(T$*yhcYq#?(M&*q.q|C3XdCC!d32-, ²j%6Rq[8ywosbUr~l#ȃ [Q.-X;&,aWGrTkq{4pqIr&3`QpzA" S_1jd&VX>Fbq" zˢ]&p3ۙ6ceQ*0$p:slG=Ƌ^nј!u re6xT󡖚H ^u8;R`qyq%IpeQ=qQmFKl ~0DЕ|hAGf)e`ؽy <@bZa,.ZZ:K mN@z:.lgJ]˨r{ f)j.;k=R {/-6'j e U<2=Liiv]t>8tt<ڿw TJ(G0S%ܛMeTB-MFQ65KgAnD23+HtYlC\cP_D'oHQt]6zMLJ`gbpGЉS Z9#xդ>W* jF%&qDXGA>is/kKV Bz^V0y&X@'0gGRvǥ_1i7ohk[FxKddؔ!GqGL HDnyjV }ߌ@918UE.϶$(+E1j.8l 8[ϼ|VGtz$ߵ-ɪ-h=FD 3{XH5&~hg1oU'16VvCl8R#y5e+)Q 9XDUhh~BG A6xUݮ%-G<юjt,ɋqٗD0Ze'xERS@yKSKe380,A(eyB E@[ TTp/YC \דyZaIYcoJsۿ5K.Kd~vy zPQ [ QSTD_X8d|XUi+FfycgaW[r8q„݉(O*?\Zդ0ɔx[|ʠz&[8[Ug$UTe4, 0j$T|V_bm^ݹF+go5MǕI ~i<+`g{bbɝ&?x Gv \s'C70O3abV\KK(ۜEFun*4yz(|+|ho닭󅚳閻X:BtA}20jA^#L )}zT?f A 8?yCMrG Naxq ?+h(հٔzPẠ6ՌgKDY5;i,[8M 갋{3Ђ pY.|iv̊r֎f]a88;A/֛o'>t$}rH!z`$Z,w3 xn6,R.iUj03 l)*xڢbNKw Q~q,m!UW Kj}G#e`#Ag[9~Gr$LR ۅec 9%`r0zim"t? [" < Q#j_kGNM /kjY~0"vdgB' 3`uK:,[DP]a$TܯiGbP^Mv*zc#yH|w;w/uZNYe*3v[L2PT' h{I\GpSXFv'a[Yޝ-VN#W*Zv ^~ɑEo#sG6ht("}deJC8'3OY#>tPM=!M%HJuK ^e'lK+OW#HkZ#4q\j& /]Rzݸ)&P7bLxk.B.| B[08}Oԛfi\ Sۼr>䊚cy~1Ϥ.xg#ߑx@,N.H{Q pxIv( vLW4ߩJnEy @Tɞ@ŀ 2Ijh 9#Tc7+9g|of~ʥ!eC=z,(G[enA3NmWXq3>F]d ]~Uޯ\Q)_fɼhD#8 3-~PyZOIR+P<$)queXG(@b:.E"sR&"=ގJ o&I끳Kh?}_]BϪi0+\8%eKEm#K*\$P"~Ϭ]gMa`t2/`zNcmNHRq=AM_эPy^J7r6DB~6VIQzD7ЯOCYš~d>KGl\VE eG#o2w'|8˴-()4\zIZP9h5d\==7ep|۰]m{~]<+A+Pƿf^(ON{`ca5:+J/գN1ajJr(yk ˺.3!|>IiIޞ~DW֦ /:5fd*G͝MoHALGEc(i @鸝N[lZfy d\[hޜIX>AR`حЦS +ǔ_ C/0<;AW3'z^37")H j+lryQ:>Ι\WB97u,.,HZ|_8hݑ=h3u{b΀J慪SԠs#4NA.]Nz4WM3ǥ@]h=DR OmYvl.,XAnƦ2H%"$t-s vQJmn ̧_̈O+[>;c2_P}P`oc9N e gJW~EtM[uk `ד!0~,up3HZ`QP 9ttM_REB֨.U#=Uܨ%Aa /,ǽz5a&{=p0qˢc:AM;đ?:z4Mb ̬葱.P؅`A'lpS=!ݤ=„rhޒP!}]Zp'Ɖ  ΨvVa؏.E_Mp;j߉jA QoMpׁ5tB}=5ޣ d=D^CN%M=W!Ifxg ̷qɍ"[}hdelRdN2>r_3b~}u~'I$ւ~ˬ,o %r b44,Fد9ӣٚ-fңx3Zh,UjI#!^0-f|HDI/Y.D_M& K T]YHC3أ XT1pn-WryXtvO~rݼ9GbJ]/B d1l#pen?5o!4 yDc 3KwݢAO48w9e(2Bj*;aJES8{YƾIwOd$`^I%(J柆ٌ-x8c/4zp}D8JN܄Wb50wz7oZlJym 1\Oz OxJ`Oa+PX.KEcy%я5'TU|IHݶdT "Մ2g,n}nnu))cqۣ~ adU9O0,TDu Sٰsyw\BhƂ 9 Вt IDo=!à_ۿ >bj^T `㠠P ž|uD 6CGzKȥ›z !|0&jt_mx_ Q0IizkSh "mR>^_)[,IؗǞ³Bl'm-$\wg^(3]*G5(28'5Osbћt\E.;lǚTyjKVU¨Q:?:HCn`"\3MxĐ}!Sµ =@Pw@6t wiadm]FĭLGRF?( 7}h kZ@eݐ܍|S o!> p<]h /Roٯ̍uv\eAfO/wMgN.YJ hs?5xKX+kAңI%ִwEKMOCOZ@ 7 Y]8AeX.Wd>]s`aRk!@)H,[T[MpI5[(=+e1 Ţ P.MxT+ ~ٌdgP'1>˙&9$aTVZǪoƩH4Đs#R8cQc+IwRtkŒ~̖^!op|{zR7s Auz \-ӿ0I9?/ a:mEkE-xt^M`%' 1\-WhD˅`x;BYFk4ͱ!V~tÞO= ] /Fw)¾M. =a:̀El Zo*H-]{8Z`)}Zb!jx)E{\&U\4k}*C5Δ] =-7 =кF{̷|$'b>Hey&3w>f)*6;5e SUU[GقJܷXvV:x\0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 cleartomark ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1707393948.0 reportlab-4.1.0/src/reportlab/fonts/_ebi____.pfb0000664000175000017500000011321714561141634021211 0ustar00rptlabrptlabo%!PS-AdobeFont-1.0: TimesNewRomanPS-BoldItalicMT 001.002 %%CreationDate: Wed Feb 3 18:02:12 1999 %%VMusage: 34422 41358 %% (C) Copyright 1988, 1990, 1993, 1996, 1997, 1998, 1999 The Monotype %% Corporation. All Rights Reserved. %% Times New Roman is a trademark of the Monotype Corporation, registered in the %% US Patent and Trademark Office and may be registered in certain other %% jurisdictions. 11 dict begin /FontInfo 10 dict dup begin /version (001.002) readonly def /Notice (Copyright (c) 1988, 1990, 1993, 1996, 1997, 1998, 1999 Adobe Systems Incorporated. All Rights Reserved.Times New Roman is a trademark of the Monotype Corporation, registered in the US Patent and Trademark Office and may be registered in certain other jurisdictions.) readonly def /Copyright ( (C) Copyright 1988, 1990, 1993, 1996, 1997, 1998, 1999 The Monotype Corporation. All Rights Reserved. ) readonly def /FullName (Times New Roman PS Bold Italic) readonly def /FamilyName (Times New Roman PS) readonly def /Weight (Bold) readonly def /isFixedPitch false def /ItalicAngle -17 def /UnderlinePosition -100 def /UnderlineThickness 50 def end readonly def /FontName /TimesNewRomanPS-BoldItalicMT def /Encoding StandardEncoding def /PaintType 0 def /FontType 1 def /FontMatrix [0.001 0 0 0.001 0 0] def /UniqueID 44338 def /FontBBox{-174 -250 1045 869}readonly def currentdict end currentfile eexec x$XWo "͓mRǍ-;\gqiRЊRo2Bv~!vِ0+I?o0# jҍ=W:*5eQb]#C.ēg> ƫnXf\ÜGfX|=#s,?T6lzA T31?/Ŭ6^NL~VR;.J!Ș>TS- DsulJbox/ŅG u@yy6*Ddo{繇bdZP E>Ux0_] y5$ʥlhWi݌&}eB:"r'`gFx?aw#LKi=ֶ+“AtW'uk2CC% ݭ- R'0XE[z9Mle<٧4;|pI~!_>eI LW^J$m )D6tR'O,+R WwOSd$ʗ}fDۚP_ٶG&:w]j`Ch ֝酫iDE)a'ssIIY)q,}۟4Sl[v%7-we%l3Lz\_Û߾;o~}C]T(BOIع*۹N`-m$}Iͣ=TM3Sg (ȫ*<7CU=:94w|m3(Mu^ $m!2@kYH}Ln@r NR~iuӸX{jk8OhF_؋y6bs#ƛnT*{%0s&L!A3eCfn.hXpUaoD`+Tr2g?޶c_{U䆋>=Ao{b#D;U(a~Lj֎#[bz5ZWds+@{H @q"LBG.}EW`Dπ 2}1 bs@V `hk2DOWĵfH gs8Dr?ѶW|tD=b+-l p0 WLjTEYhbN{W$/J/Je myzt&Bݗx?Cm*k-z30QG  2WTek*n9̊qFJ_xN^5JzD:b@BA{*al'.N5uQӴRTZ1C({i" ]꺿}jJY|t2$'Eerdg$_h̍{Ñ}[D,`qMOAif$x-yP/Oua^F򸸦VWя+^lKYIyg_c*ؖ DXǷ;SbsOGiGcyfYEQJwl/(lߥ!^*2[y ]쟤Q:y\pq (PEtiu# h)W Q3T1mܯ zbS˶VIGZlQkNa$[[% ܶ~Vdy߉UR`'8IP;̗#}~FIg}6Gv4/>4]kS7:-dR~Z,I^0r $AesKxe xwc1&.໾!4(^Fxe"ۀ6s.#C*]OG˼`_  ^61]4b"ʑkw.>}>bk9 $<;Oи.wäײpXt zR6x,:38 iQu~v`$d܁pbrsZx(r79JYE;;DbE;ncb!WBuz .>܍иQb-:JM$|#v:7{miF0g뤽j۱n2̻#c:P2nEGj/,C9b5|WEL[cd 19 [~;p¨`(|ZG zTqW]G2i,vby[,N|å辸]kT!N}J@ˌ7y1Lӆ7f~N~&UN4tȧf*jnXys'ApcqAUN]oU݊?+k s/I>F3㴅< !VҌ4˷)W47x0oiIuC5Hcj\[w!_M¢ȃ g3{Tc"/]n̫FBL§G&2kl T& TbCF4؎4( NH.aS7k )x|'LQG@.gY~˛G#+tP L.=-i࠻mw2F1eA> b5V$Ikl)YDQ2 H.HbnSv`^} w:8ؓs 7U7 x+{ü`f)ޭcP+ZaC5idAڛopd9En * PP& }]Wy- uϲAvyvd2na帋  \sYɗ ܑӼj*>Q,_Pgp>?Z[.G1ӵ/uXY9׳aWUa=zGª G5`IP{,"i..H-' \r]GGq%MҫD3Dz׌D[hԿ>͸R(Kc/ʶth9jCB#ܐ$P:l P" Ϗ@E^@ҠOKY,}D|puAQBfhܖ6%݌-,}UT&p9 lmOnWICr9=")ikz80ڳiGԝVh %C zW?hPu%Tʲk <j#2t?5% P6uurMݪȻ0?[YW(,}rJ,KE\,B +%-N.7)`RQ-fdq5rɎi ѣHhr@IBZ=N,).-r|xMx v6!˥U5O:#WԄ=vMKjFA{C]ՌS‚ز'1˾#h! ,;[#IK9gK-wGd||P1'3ow\kOLI(;괪:9ޡ 눿nd'4PKEAd! ֢?ve )6dIH9#Fwu#, DR<s:6Lg}t0,ES"Ә2E4S:d4/ނ2 +BإʖC(S~$ͩ&H|1p\ՄysycbXQcECAw겻"Jgΐ) =9]0^̙! ?ɌGLtW &))#svŒxmV 1Sa+jVH^1TMk`9ZM1{P? w4KKԴtHN6[ '5%X'-&:Ѹ?:s? tpfٌ4Ԥ1 ZX%dɐG=IJq)HÀ Iyi*;_}Nl#xbAx \Rf[EG C99;ur(I9=]P6)P=zyo~EJm;׭l MX ~<,H6-ؐ(јbǘށӆ(Tzܷ IF;žm<0ńwzj t XZKn8*ڶ6EclYwi&PUj3K3 +K,*lGsq'wrxa?M8L[_Pm)}5 rISМ]~܇qNIz:0r%LK}Q&\}?WQ-^}xs)aA9w&h^]0[2p!BE M"äOT8iV}.fUhqn}~DiaeU{~(.`j|q3$!P!#1"B5H̄{_Zp#zhV<;=yZk2q:T1՟,zA蛵Qyٶf*?' mIyF6J㸶"55Cr R XŏiU0v2xO:L|/E N 27#zoPX[OڠB,AG5JR#DHt1ַ}m 2cXF~D Ej"P.PğNP5MJAØX֖~3tT6P}92-zORn QF{})Oғ}& XXS5~ ]R%UiO1ZP {6\䕖6\YeoX*x 2_oVMdT-Oq'C^ վFX>u$LK?i[zr3ٍgɚG L`OTrb xY=#h =@ژ*:0F_ Lns@ WoNڃ4YʅJp„ `E? OChsN/x" ~K^vܣ K&> V cD/" 4N hlG%RO5 uTӆR-5[i吢-׌>ҭͱ44cM:I}fŶ2wAK!A;\npZXR^,%~amo"HC\G?"4A/#N.:c4 cä߲[IՄ>E'y7YƐt [&cw@ G-bɂs8i`| nW߈j_xP0IpzRJ^N1*I;31);vEy-p8n?mhm?Ҭ`=8;!4p0_UyGJ!ֶ2~ 5?w %LbzC+[[ 3I" gג.V̈́N!ScYE4)J*+N_Զj:Pz&5fJ[qK`զ]܉F2{|=TKN!CcIJ[qm&'ثVR Rz{_rBz5`6R) k ytx}, F<cL&iDĀ>[IJYZP!@:ك RBwGDBJ|=K%rwNt3URia]`jofnH¥7 0 6S-yv*KMpo6 l/5qgroR~E{-iAg(vߖqnkQfͱN~F% LƊ]d9[Īb/A&WRjnSP}9*Q;1D`BQU8p13үB']>x<@tH \p:O4R p4WpΫ;KG`@$eR/$q9+q1sGv#zjjm /T4#B:tKLnzрr{_7*2"n#B9͂}fh+"il.>20/{qObk p6ԗD4dۇ-cm[(j6v L" u܄鱽Lz A(tjwv]nFd"l &<ҋ:iBAKg^ ^:tEȗw\h$=]Ӏծ "D݅򽸁roJ9#l_i<I$+wGRJ0 ^^ʆ=4ƕi?R 㼸=?MiAz!{-eG-K4?7j4P۪N|~03t#QqXt&ߣRϺ_eţL5)mMk8cY||FDiz_z!Yb GҀ؏Ilt%JY?@{w2}\ x~EPSjXă|S|` %2=.ysBn|2A# E1(l)K΀c σ B,!^u[[䓊z&y/ Ca۔ֱ%[bPvfA[/M1F65j-8tCt!>{$r!|X6~2 Y)l8z"O?eHdMK)j._ZJD>۵h"a_bI-leubJ=bvAjygͮs^#ך"?prhHŜ)Ag 'aUW|$Y(7Ƥ> Ey^2%{uFtV\`@%zfq M(8$W  FJ3S\<(`AC+d97u\kj]1Q^5U"1z >=ԉfJd*z ^a8u|C ?>kzՐ>v7apJ]j #~Op!њJ55q ٕSvPdU CA.N<[ * @]Fv>O :6Dftn0:5@`fz>oh ibKx2'.*>8D"b_8ۖ8xd]p#,)]$ކ㝮diIdW",bO}8w7VYWU{фYkysF{ ?pspɡWhO3;g83vS.e|2v0傭۞Y!:q75Kb)̟EC㖚W o\O"APpnFrJ <ؗ !h"_/!߳#T`005Y4V@˧ w n:yj[ =C *3iT νzzۙ:g{v\22 #&2cУ7FSAj354{Y+U.6wPz/lvCٕ tëeDq0X:P_P'OrH$?YUW{֖/3<_OsC yH俫oWGu|2܁]PG/|ܗd*mi%| [ Q }l[€"{Iwt@߃FsjmE{VNjM/JjLNʍH??A(Sbƹw X+X`Al> *뺦iVիf쏋ke* ,cMoNqz6ZN"N?DX $L#}C"7k{mU0$oG JYvVGs?CM;xSId,FǖM;^z_ܓ#w'QqO8mAztEk&zR8SbsԠ *D*,!Ə#stq!Q` ;&Sʲ۰L筡 ,n s:Oˈx*H(qzVZE':n .ՖÓ?< ##z,d^3ϞXST'-n'v.OtW5s!!PA9z݄u/ ;'f))%nQo;ͧFϮNNRf勛j%JU9_[g_I3"9g4&/eL`& n)}9S~Y`FR6}fQ] q>Qho2 ;-^T.!ԙׁwVTnE:TwR#lw-{#TyC|{ &BP%^ W >BG G~d7=!`CV#Mqqy7E !Iã*i<ƾR<1@\NM3$΁}o{Tw1jWʺ1|n&5daH PFFl[l | h:7rd増]4׭7*SAڙ ?+LNthvDž;9<-G!>UKWs4oը ˜ ޘl2 F`Iv7q2r˱ie8t!*.Z/k`VkK g f?Ҵ ٨/=v@J63ް fE f. eȔ\)(CEb %'9HbҭǏE$uT`kTYuYs 8J8FJϮyk{<#On@Yt3w_Wt3_n]%ts SzF.^vkBRPXunH[,e5@>t'0~Gs*1(cA)ҭ_*ZKQ E/Q,]Auy-J~D"n)TNɶ pgvn8dm8cEgD?ެ K;VpPz)Q$V ށ~W$YM'5`0iVU8sWu*Bkk|?MIC]A? neJ=Lݮ.Ʉ:mn?$%q׵McH]h<4s;ɂ=Ey:/d*:Htk{qM_I?GCi"0ҥ27ܺVc Ǖ.]%tGBTYkP(^zB aմ{d G11N`" k؜0ěmݨ*Vz܇bVlM .L:Io8&C2{C+(2xaP>7.qȄaX+ڮrj])?#p(Rƛ } mKK͘: ~r6m] .(SCs2Vt_ ݁H 0-Fļvzz}(hli͸olEtDu?!7pEE-<~!M_PY/-X~Rbe>u2`"HB{B&y*4eRYgu=j˜tr(>sUGhliQPpEO*k$iՓrrh3lbW>HZg&vODZs GYwTo{EP]i*A)< HK(oHu:dž`g[3أͲ ߍIgvMzYz;):,"{E 6x=⿏} OI|"?t*=>PcW 4{ ; "ҏ/R;2W-JBa;/nT~s!͢ߖ;6|_\VgF 8٦I2ySwᦁFu#ßgNh^LN_tU\4cҧ/pTt<`u|DP;͝-yʉ6 f0B/'p P‘cJ~(=ӫBU#^F^o?Kbo٘A+`WB#  ੰh)/U[Y- OuP3gg^RPLnWV0ahb4mwU]Տ`.6.:ƹ8.1!i82p>&9 5/5Z%\R/K_7L,REX$ W72-hO%㓛_OEqX\g[wB=QEYb>#6FѬHLJ\ Ͼ_b`5ĉfӄIea'7)"vK􎷔W?r^ kkQTV~+22@FSprG ijnrP/!+n?67[N^'lB^EWObL@d"T8'^eU(Wg\ n~ yXtowΩ*{ h\h48xNSЂƗEJcgF*hulG4^F!PN)\H(.Ǻ O*gEcv@̢타04euoW)ꑵhZ9B |ܺ[VRR?3kMkvT1LM7e9 #2_+Fqܧ,+mDd@zZ~xşF%Jn`WgtPTï#]t~f/NwL\wI۞&qbBkEx#TfE4loh!˃ RokI@W۬|yj-wʴ?lPCxp]H7*I ʑYXvv]0{-y֖δ̒mr+k}Y sqȟ? fё 5.\g=WġRj$nOQx"|Z1X~6 ZGh @ ^Ǐr%[sv0M{u\xB*"XAM x3to)$ V5"˝1%&c]`FRhB6a-YÊJH/U],:'Pb uR^:ֲ3tt3PY`:5?A3xpMsԞb!(K!Y0P#`5!6?(# PD;CW3 3efM<籮/SB[I\O[Z@\1+Be'e ;4^ܩykGsW.#vt:hhぅ8 55F̲LH}Tԩ!R[ 駫 rQ.1oa0[W0ReG}B7$՛Rz6^F ،l/*OJ`ِB5|H W F ]7AC'Pp8ߐ=u]@VՂ" _DFWYǽetk7O^y,-]\pXWiQA\Fd{_ѧ—r 2@?_#_^Q bp{0%o9t槞_AT3cT2 8 (0v,2H$:$ԃqkQyZS,ۚlC~ =|J4m8zoH4}q|S2pCj^|=z@ȽI 7O..W0,kHع6jh-Ϗ{Rx})6_)Ŕԧ9A5_(RVI j3+PC*Q TBTaKGeZZ2uY(XMÎn*8`Kzm^Q(<pcwDkƕQu܁{VK[0s™g*6kmN8࿇oWAd(+Zqn H @ep:ެQ9~{C1'rQ \kuK (I%&Y몢^aTZ Cr:[Vs)߂ڏ Q6]J] WP:&o v xvtTS"ĺAqӍ98$NDA dJlRz "bh.537o{0IzRԨ\?6O3|SOؔ}P92d8H mH|6&ذ=vj<)ugrfɮ |QM1*]!D.Fq4IN^Δ夛НY1ف'uDs2}s)du/ sKkm2Amg(O'U F9t)cE0ڠu]wʊq^IE1k(5]D˿Caٰkpz!%!+4 hY't46ԶAح)̲d+ rhDY CBA}:"Gֈ'%I>L?y8!W# 868vT͚l]?9En'uXFbs29vI+-UkͭGh;8l'3uEr(G3EjttE5[,i6/DXY Vv%ubk{K0_J Xcڔ+] Uum\6uuk1liF8Ӧ0z_ef?.e'L]} x-4}>ZpE bEn&? 0aOϘt=ɘ9ĠkY.9Ϛ4TUsEY:?ϣנMYT@›?KƧP pr7%@g*͘E^b%Wwp Xi妾n:Š2V g5]Og>TkQnvvnB'i4N ğ|AD{XO\5xˊ!U'o.zU_yTW b|хrYg(=k hSyh)3GLَg,RƳ }Nk1 q3uA;98*nN#j!L߇-`eDr[!ʛ S.3NlTݳg<= ˻ @TUb]L!c) evR;g%cbi\D;U3|4F4L%e&yy:G xSj'lZ>O*{pkÖ|,خT1.Ý1 Uv)~$JqnAR&P2Wxq׷ 4r+o@93 ?T 3V`:-#_cdOj11Ar?^5lc>rbeypM఻]tiyuõhVș'teWYjӬK4Ȯ AHRsKxV vƍ.^ 7ɵS~KĴYQ*Nav b_t86сz3>3ݼ8`ʏnphuuE@hxRGk=DߍWP?93g) qs1)M@YwO:Qb:iv =wOGyJ>N_%a;qA+SaH+G!Q bWnJ>w]@3Vؙ$^O;U0IkMlhA*)QY nBZ|X’p]TMY?WucrOT3{Yy X-'1^tN\ ;ߣ{owxdQZ;5NѤ^ź sֳ^ԗT-tpۄZWbpn vee=ȀD!`Uo{@ߛpbҸ(k4@l]Ch#U\ǵ}R߇n%=ge;2yy[/aT7aېejE#AM-F淪Vw!qũvǾjJ$uU-fΫY+J[:(D`8t}ϩ/[o/'o$B+>C+'9t>-UaRڂgz UR 4Wed1ME!EV<E^`FY/nH˄X E\NVś_Q4n#="Xfp1gdE*;UOY;`{.,+-YJ7\B_L"_4hek$q|p! tQ:5#>]my 9 [V@~[y$Yvm-pxDYa~_Efan8Qr;*Utlt}n~eT.wN"]*W\|%v%+ !jok%x޿'phZ (⺥`=+5:~=G/N z/iPc*<9g^9a@PBj^6/R+"7ܐC]t5hē 1^ =K3pB+V"h+rׄ+U $$],8HH{Iĕ{`5+ 놴oTnPafa;{&? |]m\#ߓN fd4C1 SLvmYkbwN- c`+WqGTK=ykMphH(Y܆CP#>ʺ!#oaAc3HjPv|]b5#o1{UCq`+>` odTJ/1s \ } IS _`K)GGG'VsiݐkQy](OҙpF3yjO/B>l\:T)Ϣ2Z8\ˎ Q>Hu;ff[p8xG+ D@ਇ͓~|ı" o5>oXdPTD!*C/lj(H 㖉(yފ?(:Ѳ|w ,WxcqSXWz6{+AG9tz/lE&q_jr&G3Z"E`=j9#炻ӕ_M/Tc?@z7(zim t6.X/g4xp( ڿ2~qT>~yWf&wa\DChj՜+6'dI#37EK ua!P3IYT΀1ϞgZ~;IZU+4ޓk锾JIR%,ޛ}!B)~DC` I wAd MQĢʐlޠ ıY8cȺԭ)NT|I "UViel%FAG$ZHUumYw-gD26o3krմ[EWZ." HIidjND#1/Zf",S'WJu0Gj}X41Şّvd]^[c=Wp9+ ltc|y UGjFdV=Np؂uɭHX ŵㅕg茗uo8pf@Gj T9sE@.;}Ltt>3o*u- yv1VO#SpȽO3|Չ C5A„&~\eA(FqmUfEh/J$6GʺLjY5n98c"V!J\€1uw ?O`11$qk5~JL'·8@$_&_EXt=n믌zɗ#tR$// ƮuGm 8ɚ"_+縰K9&"݃^GL3ͺ;앢j%2q[S MWP1 yq0e5Jev02܂gutߝkڬ:TABz{<w5K.X||M)Y8Z>NX:TTInɀHn6;x3L PT$]O_# {ӿ$7K;|;5 uSJr6-ݑi[E|yLmX}J#mXI{꽊GC* 6{FxL|߫Ǹv8p dts ԫmT7GD40R0]zC>o XytJM<=9xV?)̊BK\o%#uޜqn+I:2D5F-K#]T`@!̽]DG~2i?}8:Eh #e\Ó뽸˧yB˕JS. !i6߮iyIK]*DٴuRM(m3bcziA^ۀ< &=rHOJyQ"H{ByWWB9}MؽB@ꓳ^0A_dH?-+_8sGX塞|K9:hMIԠ #$(l_ըV[U0= O$v @5CA!|qvdaG^TnڝTG~ e 6+PX-*sXvY;$pA)8&T29ǜu%\ɼΝO>ULG.c[6t.b% w8:,u/ahDXy<<) ˭14-O2zwpE|+wMqm YvvPٹ,(E;t>{Ʀ\ pL瘘]0匝<ŒZKhP"cX&IoIzhkFekw5rK79Ԏg:JIӖH*ҵ;T@4> -P:}Sh ѡz~/DT gq_`C0&q7S)S+/Pc͎#W@Œ53͆vC9T~3%ff"-0~r򔶎d6k {(x1PŇD'w1b?ærPr`v>;'z7 ̅{,^+ CWK\,G4%h^4/U N.ɟRֱe-Wf'W.鑺 ٖ];:".[>EvzgR+/& 1SDUEtqP쎁hI9pʒ>M # L+Өא `3g}[Q6 s8QHLvOő+9oɓ˄#s#. p=L%^FhN{\\0w}K,5s2Z}SAVɔYd]5*6._M*L~kHc7z]j)=,r Rսv%W`cZLP`g^v]Uf{*Z|  lfЬj[)s@Xv?xGn>6 J,a"Nr9,z7x\^Šo[`ZMd2FbktN!Nq䍉4O@.6K&Km>Ӌ 43e(px>G˅U'+ֻƲvn3[6}:w8]舃rQ[]紱HIcvWJ:%mC=U VU=鏕an<^lFv`Fb|q,! oVQ x|z'Hf/Sj ctE'O> FX[vM\oeO3ٮMq }ǖa~ЈӢS9ưDgDgm*xQQ[O>?R:uY0*ګ*ۋ4U95Mw;0ځEQ%@ _ְ'6QLK].`LŸs^cz"ԠaRbXs;'X[܀s=f!~e9p0M&rciljo7$l7z>]P'ZT%ehP7T~AkPM4HL06܋8(w W*=4'C"Y72f4,A~6X8s aM %v7[% d8+ج0 6%~F٠Oj]cO~}v^[j6ĉ1-~چjҷ 0>Ƴ-}kFp exg_Fr:ח ޵*e.mt#7lp\vxWRq(f.JVOGsW%<@;O%B9Zi1]0% uМ SoD\6p݅rADOz{q})~bq n0J=th#TM,/;n+0$54791z^3T䋴(h+2_ Ӆ==usj,D6M`z E0~l 93OSʶǰ7}b'Z%k$T~A~ڊ aÓ%^-3G) }6WL dg|2kf6UC?\Z 2w"}_^.hnbHέ9.c3[KybL?t# irB/Km2=rz#⏛VMqb ﮍL|@:f[åHv hԓc6w)SI@+2YQQ^:T6Oͣa>rѵAbZI@qQ͚~Hؤ0 Jm~fzcE=._ rJÀAڊZzQ Ybs1jwPjf]CYr6/s 9A6g1338(n4T| F:76@}]#t`薰~ȍE2JY:c'#U,`Q*l,[Chfbs ֟G2!rof4 u?Zh;XI]ngzjB\#,A5gbnVڬ φwtr W-MM0 o`eYz<IA4b,4@-[T p8Hz8 poII|/bϠ'3dlSkSg HI6c&bj"\u6}kN1d UH6+!3duPn+/w/R+u^0lP!R棾%A T Kw|\uG}`9{}tևDNbP:s>),\e(X4cJ:3k"s=..#K_ rx @ vbzBj4v h~AXwR zX{.`N ˬz*nfPv}B\dC"_ERFt@v⑞ҽ"$[i[}?yUt&x> C)S,ƵЌTTUCg1&sv9QRʰ쉋 (Ҙ8oNoz;`UvƢr0BBby:/51:3GvLaG͂OJwxxe^QF J[3C6r8 lrM3&:ʜO5}j;@ȳzB usk%)VfV OM7E¸, d,m௘; QX}lj-K5\Yw|^1. AU[12dlha~Rgd +i׌)^P fM?#08Ò2OCҎi%΅?\;D9]-WAL H[<_3d$'TX=Ň*[eHz=|;guFnZlqu5mCT U Z9cPс;:t~(7y4'hcGGY qHWeGI i>Qi-dC@J+Fgߛn\߃&YQBY/w}FEֺh5,Lc K)~bg]$Ӂ2;6'Wwjl" %;"i8374O'YvgYy dB@H DŇ;[P#yRq6u Topb68{Yn?m߷uujo[:?\<35FC0zsrt9l$,(Źno|+@6K[0X4_RS+m9Cxx^*,+L12CsM8" Ϥ;@DϭLgT!ʳN(VZ"W9Sk ٍ89R9x}{ h3CͪΜ}kr='W]'d5& ϿXB.p} 7*E*LKPѬV"Oб-"oa蟖0`O=,BMv:?lXkcg G,eR]8N{0R\ji>vӳrMXa5T_/QuXE"\kXB8o7 T!ɪz;ԙKEK؋G;e0kr.hC!I̢+#<Cm2wBh'˟~GI >V><4i(QSKNwx&kܳSuP2goW=vb?7(reŖjfh?':"fdf@YY2WA+^^9ٌ?O  aNdgD=;A5LPJ#?+jr{V˙(8&\fկ,49Hp|fZ 6aFjQbQ$[g❻(DDqK=jOC.ضӾ:IX- }hݡ#Fy`N?חg ʾ&}gx,T~ Ŕ֌[ϛ4傇 9 ^u.M+-lJKp+ePRO!1Tޒ3,9} Ț옌iaP(Nlp{'|^6؇/M7UrnzoW.􍸼dc@uËrv-u' } j+<&%pAD͟ DA񂑶I+_.y+lÁ"1(l7G9gdwAlCjlp2x yid)!@w9CmigXC (u YZvNUt8/H )eB5Ab ߟ@N[ww 2t1; KIx\(ufƍ%D;rkւ-@uiEgN*w&*;pH=гhCВqEwFMvhXh/&Ecofo.A04=t>ւ Zfg҄{T}t2ǩrGoR\U&wAT3sLL\vf'z;,-M-Gq-dd0m0+w9ť:SAji}Ԭ@ cÊ/|T2k.wMk;HW9:s ϦKy-5lu`$gE2ylgH{Kˈ?^vW-F}ok |&]tdգ[6Ȧ;ZħPgsRT6~ȱԽc2zRͦa?:u9+_f1)YR9jmK\ ('ubnVӤ}L5ٌ~Kx~KT2E9f7X$MK]5m8jsiE71<lDzs|0Բwɿ-@>K߽%U1=\Eҙ2w;XC+bH 4h&j@;ǘ]NoQ.oR2&YSsJۥ%˙ 9=8YB+BcH Xг8Vyˍv$<-gmGWq~@骴I5xF1I CߍITGiPkqD:hYdQVshXD ozE^XKvIo& g?܃Ȱ<,!p#/ %!NHÂ]=Md (2_JIUe#FOk<Ԙ wX3Lhs+qA{R~G\A,f;:S\y+_h)pxYI O"Covy}x*9w4jEqu֜ i,[B$n'8C;hSլVt(2iM5-IyobȸL/r*@kW^IxZqA-hMtу~qJT}O yVs (AQ;*7|Lc|`(5͑3 Ex[f;mIhD\3ݔH Zz4]%[PS&!Zw:3'aCN%SCV,Hɶ5țt 8+Kas4ז8BoMk^*|Ѭw .峸&ux{!܋Iͅi@fZd#s3e]VRCgV3 kLI⦗ls͵OΡ2fEL_f[ЊVQ05b'HW[qP ;Dxsn6~FrcgNqسX0|d"3{mR'ޘH%OVw<+OQY%BxT]+$,(" EY.E'זh%Gtj}⸂זU+£r0&Q*?=?#i[ ~'ZgUi"Fv$AewpE8"~Q(h/#jHsOӓ1i+ >92 T}jOsr'"\K1;)+Hf:&Q<{ofBy@p۽SofKiy@UIo(_- 7-!»#WHHL hMZ?<;֎;L]4~ [ƅ p@5@+9͉פVd+&l2H]jXk^ppK[,`1qSX*ӣ)ʛs{Npֹ7^R9n $2D"cݍqjW:ԒJ`Eΰ(" VfAu,AOm{%١@ .1.Y1A|Z(:~YoK   AӴ w?,;ؾdܐXJﱯ?7*@{bȒ ΐ0\[ϥԘZڪ#*a`Y t4Fq0YWFyf\\y 0[ ?(UlNWX|nhG lJnL.E\\čMϥTܥVF8l1X+Neb@ƒ^ j{Ҭ_qdƳ_rSK7A#=%3&~`=Z$Q-4{>r*'7 & zCYrW.oO,$Ȅ=m.KiOƂ؈CIrČ\<* gka^l.r^\+[jk& 9Mᥞ “wM{4Ôm>U ,h- E|P(ıGX3EBa6T=Ou%2^4;I`60o4Y{߉I'q8-Wpߣ]|+Yv~*??'8#LB>r-~tpyn(A苃1 jЬycj;3U^D8#5fpcMic쥷-#^sNA6Cr6AC?#&7(!Lb+7gQ eP BKci=&،79:*0ݺ9E_ȍuhRdmX[ &KGL"oe\YU1x6}r{wIJ,q.;^اc9nPפ?t <9QBŖbTv R*g) q28Gѥ2,<M6=sF(M&,&OOB M4g!oU+ǂH\iKPL9kaFj(Kxa2(`1D+X{2؋T&qpf9nX F9 3Iav6}iw>NʗqkЫ{ESZ;PgᦏiD ū'^lע{O2 wl'+G y3& z!:TTEă HQ?/¤)X0/Q{*@:8rL8]h@JVݙMeɡDH`2a\ήbSھpJ|'@GO4H7`t`|V@jO-%7n1GL_TwרD\`sO8iIUo+ȧZ]~l1Fq:bŞСj400/Ğ )4Np[k.ͅzBԣp(X9K2ބ#Z%,tbȾ}%`ت!mM}2[mdnY1t}lQyN.ȴO48g9|RdtQ&;H#!֐Pgu [Sn$"<;F<, KHM6rQ} ű%bͦ.n෪WXXM"쎵JcRRΑm$KνJj,(@0jdAUO:zIbV3sENN8b=7K@1F[Etd0I9j+':E*xB>6yG|iu,̰XD}p2jzdX!p"hqt \r]ڠȸ6QxD,Mthp#SU-]j]Dh9c|sEOc\2jpq2y(GCgYPhb@cϳd ޕ?`_6NmA^Y(TpK7V`FZSt|;v6T`#NWlj+?DKwDqJV 缏oƦl &- . Y<4MBT#`Fnc%LӼQ-ǟO`N&q-4c{ +®\0 oAtrf:k{qO:: pM'O+[Ƨ)_wbomYIcLR*,cVcG?>D߶!0G76mQ86~!KD `o9<2ŏˮ)KWIeӰE>''_5z~/nQۜs$T4˜k3 LH{ 43 ˼2ӁlǢegJG gP|8hdw9e<F{#, &WV1a]A,Hu i\Y@8m8J*&DE)t,Fvn7+ݽ -}ͫVg{nCҗ1s.V6՟0X,@qe 18A z汽(yT_1rWGU|.)X|y/B x#}zKihCywQ@Y} +tQ $(Γxr_^pGEbGk){D,nTBCb"`Q/"<[OXfdC_Q8kwhpNbՏh­eHU&epQ( Ř"pVMZeͬZ;@ct~l >_odHn7N$DXV^a9GFVd^<$~Y)1u,JY?~4wyBb-;xk-ԡ [zF{Zkxk 25[Q8;c[쨒pB1m?m.ۗ$Er=XL]Jڌ`(Vn:!bAeso\ToMqi@:-S+X8aK&YE+}DqONEhDr]EP0I_JWK{C^|icΨ# f ,g2YTm[Ƭw^#yIZ4Gkf?( y[] 'և!Du!Fp S~ֳ} -#ƺXhOZ;'&,HX*N;g Me{F4֝t%BFEjv9?GxA1ă $|)Yŕs1U-bz& +.pŭHLKĠ}8G]xJ(/^᝿vc5D I_F1 C0SקօjA5SĽN%ttYTǹe63v .>p|c4] mӂg`biꛪ [חDӂ:]БPhN fpFu^gA!wL_ gd(-?5% Q T8)JyE)G84W0 qPXtvڣmXʁe˒ޓad^i14ɉ`ԻQ`'3+?V/*GG.2O_ўezRYHvI͠T"5>U]et/b/i;J"۹dxܴ(CnO,G poR%Vkq ߷(﹚QxJPG]|f3I l?oзJ>X R3VZ7Ƒ*/GǬF};o7/k|"D"w"f82N\͌}+t tdCQ cŕ`BdkmRC0InP>bu0wǟ$=e,R9crP7$Vc`7jc$ 7Tc:a# oX : ch-jaV!/ S5PLAM^oI(,!<~.{(q`V>MQ/n>0?(yƅYn]pb#<qSB}Nn&[8.RA\d O=(&XYsxeC֗d eNY⣓z;y3*E˒쐨%Raf?Ϟgĭ6&NN܂'FD]g|X[ a R4t09hTfmo^rl鵪j#.}Q#P w5d2p\D'_I|O?>Xt1y`ȓ,`*/ T@Gg$w%u(;Bq Kix}Oc;Id*kLzPEF"W8o`Hr.~tt+yi2de%9#gucҺ!Zdknk8t6^??rwt^'pp9cp>+=ABK*Vu0#De\I>f\?<קqVT:N`iVlI 5yn4fi_oޖIw:l0⏘ )m礵䏏fBr+d\IBd_bX*6z!{W^2<2Gl `gӡvb3$\yqdX$(X1CRuxT:rY>2`X]zSs;Yv姬&U!ZdC`!w@9t.@X7DFcA_@gc)C)'\4dµc`?oh*tژy$r ŵY_sԷ۟ګF#P:㢞L-&?:<[@:+mwdknm)sUD=-|Q[`:[FڃIcKsv#Je9LIj,Z/cʐ/͠+/8}~0Q"5a&'!{NBxuSq¨^u-i1^5`1V$KBxݻzrCr"V? 7JipaIx%`>]> /ޤB慌FZ">v-ax"t2D̟suS _}MҚ.Ø%e'pʃ~:֭Em5Y+pEj@\v)4|`WoBT>i?oƴ+:p ZR,=[~[Y{y}53W_>:_(>^-~rRCnԭ_N^,5O'靵B{.Gb Hx0Y[/$Zk"ruqۂc9?=ֳ/K673뱻3GQQaAv# ^indN+ͯ-J0\ Xnj1[$:[l*L!Z`,-aJ>;@4MWfAqTj2MOa1 /EkXujo )2JqtAcZG6 )\)so/~(lzj#t:NUZLislM׶[,orav!XAiUٯԘ=C)VK }{ڕ o:5%~LXiǬ]O=-yőp# |(P}wL)#09I/gѲ8O 2zq$XP|arTMl⮲ߘlhH5 Ҩ Ę:r.!`\D|s5; m"c04Y+z ӥt@Z2-&F<"G0N̡0gV1t~1&~59wiiP [(#4$ lIfЁw% #D^ڂt NڡqnjNJ& &˶@ƆL`ٱ4EҏDd?:e!t EyAOw'OƧi]?H_ ǩ dh_eo=S3El8+kTū*k'A^JpqG(¡CT~\]G]}STwM :d Ւtħ"9V̭?{]3l>@..SG;d5oAQS2{ FWJ#?Qp,Yx&f2R8'a6mfR^[.GanyM{~Xnulu6ӯzs,`J7KO g-V&7r(E^ n;sbвMI艙(,2jys)W5VhB<Pt>M7۫]joG_PGh![@Z(bOvt8 gC.> GpFk]bKlM X|{ƌ5%oe;η:Ӟ~>/N)@,h:pG{[ǭTI>);{Sy@,>jHg[w7gׇOw VUQ ը4 Km7l|xgY8ƿH"ƐjCkYӌR+!Ptf%Թ:O%XL2_^^#EoTȯjԯ3oU郩my *y:dʳ#:Iw&F4[awN9r Q DupN=;$\ƆDC%"`#qfOTd6;N Lz kK̨l0 (_^_] l/5` L0vz+vج JOni/gD„,Q$W&#~GԄ>Dߖ)5| ~1 AOU1a!/ԼvzMHXLomV|qjQ9"ʯ}K6( 4lg\Њ'@Hj>uxBnDjQi(vl72IɗԙZ&v\jcs8m/@sb/agT}^f'e)z!̱,7e:[nX8a&ӧ4:,rdXq?p ҄cN@ЁAlԪmס1:E"HO5G:ގK2iS '輴K, K~N"\ tp2OլQ9z>1bo9E @Yr6M[2[QyݞH$VUrYp\=#̆o 3k|~ ~4?;)>)TZh؀zT {ɧ3d vZ f [ůJkjLX<=AuAӵvS(* DQ[;<}b'cedUJnrqX^AW?Ww린o]#GxgWß eZড়\WniXse~L"3VmO4iyH0 t ap"(2ʂ@qz * OG(8P9.v'iY,op{eǖ:,t A#vX A9Zq`JW@:@uo"37n>6>rXH81MG&I[In&[ d p[ϑ0> ӓ zH~걕}gQ^7>08s&c%>ki8-T0e^(6U[eН8H)Le.9O 5@z{dc=wXN-ށU@k[Bj.(]o[̽C[A~3ө=Տ.U^{!X *|.nr2a 3էK.2FxNf?()F_Gȋ~$= ӝ)8DbƄrKj9x'+KLC%ɺ}UNj0,SXC_~GQ轙a8ɘoRwQ\kmIIwBjw+۲la3< FIݤ: H[hz~[:! OfiVJEwbf?mc}__>ؖ-w+C(:O0M'i V@'H\E RPH浃 [7wF?Œ ::5V)fcAnͻJT ʇ$8+ +)fkrfLggZ +Mb>@*~f:OG,#p)=[m3HfQ 9hp2d@W< ƁG @&W|PUb [QJWM\ C,*o ¸՝' %s"_~Gupc,&Y[ۉ1/ nS,G\p? k]|ehT_>I$ZbXnm:&^Jvߺ=aVu[Qp(q d95CÚ5EGpYOh$LLM4ZNIyxT~OVwX$X/ӆfϭ5mQMgokk,!phsZ:yKwu.51ҽ`r\"r dUұ>)ڥh-aJE;-VY䙨M4zR'hL7 V0}XEJuhe팕ˆ*7"9d8 ŵuF2N+-$zeG *GBS@HJ_Wa0`,ld7UF6g;_Z5lpmuc#=])etEy?>A0!IGsul&qs)ejMQH<_썿&x[&i3mЗ6`:(Z>%t:a·Y(& %QI-JYa0DX {aB-l^ӓwqMZ'P2&gq1ÎqSiU>vM֕up H rEhY4SebYw5nݙ  VXW4 e3vf4J$gN{Eg(wI$9V0NI 9 VF&$*q,v5,6f:Ȳ+IPOɴg`X揑 XM!!&F&Z=6֝lвhUOiM]?n"os-hgr pEk44IO/7]VV2t}V yuLY]N( .s*_>1S?S>y PtWI з'}րK&]Kl~$<_YG+!P;` gV{LW&2!5 &<vw/[g嶇?_!8޳Hd\}Pnmj{|F:`r;!gM\'ss=+(_Q&;ah  Q/@\Ԟ/A3X^d7%s7,}=6]sXЉ`r__]MJĹDM1ktq뼃[R(wmc\%o\9t:сP4&D_F^$wFShZD]GLǜOl})Npj7S%]:Q A~:aw?+0bE0/a7~gf%:hO>m|ܥco̅lh^)500U4BSXb<OĈ8r$ r xg!~ǹ^"oNE*$o'b/#@&~k Rrx3h#IgOd`46Aց!ђ M{yu[kCe طrHEIHS͒W#>>cʔf`r `|`nE`ę㌂zGr$+sr ^ϾP3 یpnpψ`'CvXE|?-洨?xxOÔ8?_bAtPe;KZ$*(nYHi;S j/-3㹽/l88V3$˰OS]:,& k> i,K9KFAk<)t>fin.6@6Q-Ҥ>@BهP/U1< vey\uv'Gd0H0w`A 0M}-Hf` *&I_"qySf~fj.sG4W,!<~ӳ*bG%Gcs[02ƻ O> J6Eu׻D'wgsN>6@W󕐑rZDF/2s7M,I$+9mP]ۭ4nU8P^?lץ?\ql+_ \8LRJk3CS4^JBsfhO}1%(i&SmL n8v$ \HcF.t‘!>{B<DŨ Xd\}m RRw%U~=]\17W`} C%;^^K l'jfYSuyj RJ(f5tҫD}ED,B!BzBn])f{/{ I$R(=6үkiL 2zX0W!GgԹț9NҼCz_W 3W8A( 9pݡc겴um!t?O@+s>KN;v!N{)fG([F2=ƀ^B;% H)^8Nu۾s I}p?~Hqe)5~,[C[$$޼ uS>!J*Q "Gg٫Jh2g `dlow8DP}kB{*FGr9^ٜ,3dcj${8%6}ő. 9!]UFjBbTD8oS9`sM7 GkNlm3 ô+ҝ.;: M7ƾD:d M$eiqB( 0cb-ɦ%ԽҚgk968vj:-ۮǕaX6ѕj;xV ]v,jf&cYEeB,qvO2{v/I+Yf(uoiҥ8x_ TR*360ae gF- 0E@i[UcVI"Ck?Cbĝsީ[' ߆0 iGFѤp|3dLx$mɔO"a=B +" &U۸;B9nXs5! `[QHĬJ'eOb`LD a#(g("ln?ƄvhsZaa").t :a[+U:'Dl Wr|eEK#[zEpթYeet=UN֨f9,|T >r#:qݟY+jo;\I"+dN, Ʃ0?jb^pH1ֻ-x()"9_Z)tXxw˼E4@@p\ݓ%T_C`%Fgov>x쪚EJwn0]X2#,B7A[+DF6-,T)6XQ[B2Ao'iV9]۷'PJ_uqz*"ЊW![uMx(΄á:t Y'%-,B3Ǒtf3X[^bR}J~YEuPe ᛺S v ʕɣZLfٽB$ϗѥ׬$&bBrDW6hq YP27YW%ٛ/%y#`9d; UmAa_I,IHfKwU-խIҍl6s)_G]Nxԕ,9m6SDؼѲ,ԎߡQ,¤.0/Q]Bj9+mT𦐐GGr'ܳ2,sg׭#fl񨖿_zr?Pf3~NwZ[<tu C\G%9SIZ{M2UnO/ Cuu2.?Mv?(|҄JWUeH tt HKGK6~dnT|5M‡惥$),3pe_I4:c⾈y˜.UhJJz'm<#OϤNE0V%)f y~Չ HðmɱMspj\a0YtK8hE9݇}5}ZϹ1A@[|ڙdPi^ / uXP̞&یvnwk+7 c=Pt!% wOh3lg5+ip>shT- t]CH(h7]8켓2z&*mTJhQE |S|Gt ʷQ5#1mj=cC}Z0}Bv;p ~'^xktr!u2Wȅ8JG.:B9sRc\+q^ %2r>^,IAO\Y7CV1 TU/P6LM|M8ɧ'4/6UH 0mkc(nRf !vq}st;FC:N&OhٮfT˔ ڎ;V(^=[MVMvYnҶ%2gQ D0ފF=)w!#p8P|j|i,:u05,72'j0kb c7Jҏ;οʭɗ;T177|eE5^ٽ.'z>59Oi6N,bۨ+ToZTd߬WzC̑m4Dz{XIi I4hwY n1ZE"$c/_s FUp==ޚY( =598q`dym0y{~w ='nڴ_1U'ΞۙEWwWp|?] ɏN|t1%̯>Z55e;4(v)A2=!wogZ %N:&}%J,C)Y48NaRcZ(zyY@ԒV(O{~7G5K^NjBJNXK'@tю#(ų%{(ROI(ס]ǧAZ]>YmqLvi8τ3j=Ox>9vHz8iR+vl& kAh4kZ*Qٕ7sLbDR+! 0'n0hACmkȌ[%)Wg̨У{)rin@BMҧ 5 e\uZg;!d F2w H>3^fϵqaxprw iK{t@Ě!ҘH F_!|v;÷6m"GB|)c,#f]NN|^d2ؒCYR Rf@:"pWmNǼtDř˯h-"]u7ҺD7)wH!jR8T/߫q)XBA8 b2 C,u (qB#m|ڿg -2ޟ6h[\*$Z$NinbUSReROtA?zev̒'W.pZ<~kmkSOa_ {88*y=C)x^Sc E#\ {j&ѓN $X SA7wdaN\6AW5 DvLF$H:c>MKGya"Gȋ<Xâ aN8PvBAuuѠW7 RV:Nwc5d^`@f`UE sDS/a1ҴQhZ\1P,K4+ :p5 -h 1)d#:iWɴ\Y1n7bk fNsɡ,8`xcrkzW"Y6$7v(Bc &ل~)T)=y9\͐km¯ ޱdf-9g4|"w񹇋v ͷeTQ%E{KIqq?GO3zN9͟/6 tD+qlw4v_{D#/Nu< {URnq<~ PGCCiyL9^ GHBޏP? )h| ;ݵT0ٴR1Se 곢1Y$Gݬ|+*=X]FfZ.U߱$JlF)HCqJS݂Rs' 7O\#:֌mK;٠?p|27Eoi0fj:.eEg6L4;qŜ!&ڥ!^=iZlW115 a{䱿,Q1R3Rw⿾ 6n%G$ּsx֊ՏtV< ^bs.[ZHО"; b@@O+D,_+Pk:oH\%_'aSP+G3@Dʍx7Vng&ݐ-sz:a$U_o=Fsg~ 8>W5$ZXAaMaNb:# !Lڮ]/@1ꙡ&O:0+:\>Mt!У!ue׋nbm Ыb3 z'82/_>5-aIp'i8j[ ֢-x>l8|(>Vy:g^/ v~LDx"\n%#MnQ=xo]CCŀ^q  < Ʌ9]8m{jۂ< @SX,#,/FGEĪ*KUܴތd{ӌ=@W"$.\6t+WpX,61XT)}\xW=j㻔/^*Z\dJPne7Xl0}C!gG-_&{-4q%G *y8#^] M8?:" Z9ǁ^MbDPmjmwQg#Q'oL1+=x o=. tWMeP@׃Go,T5Bϙ x\0׌?̕~f0K2fϼ]Nw(8KϾ00Ũo:D*trR`-A"Tiȷg9r<\bi>,pi"lN:uwDO_doJ٨Cy),K;-|,PݞS ?? n4ig"6CyġUV>z셄}F()CYWH),5F#b_  ۶˅k^`Up}9goȔ‚8+; W#)Y,JEQz/qIyo% C>9r{|@>W*eBRڥ/#/ĂdIs"pie*FEz4va3~,^5'T'y W1{bcpV`z2H0cQdz_!gH|fܰ08 1TA\9~+NJO-4 \1ToM)R/Iz^Km$%`廞l1-'h?{/:f5Atv"s-}q~A)URF OraKV@K~Տ+G@wi\OGV֋L*%ؑJɁv )1 %kTѻ.@icӉcmP`zBΖ%lzrT9+n .qFݎ+X$6 -Ƃ5!7W |É4bOK,m@(K.΍*Ԇ}͌,LbHJ?M̴X Q tk݉ c HMmrvtƈAlD^Cf\ 4>|}# !Eˁ5\jws<R=P}߁qm9P=2I7okr:)l 3=25j,竨 тV4` !6ܵf] `-Sx2ewŹOv׽Y*vȌ /cA{I/rӝwxUunHԠB鯕;k㉽"gS}zq*ίGDshٙ%(6&luǝ+y2lDJ-;~}Gr1zeC5c o4BB,:oʅ>>2"'KݱS|zsclm cX.V(]:а]ף:? Κ2++#\D3Ř֐]RYEݐb< "<2ʮ^"%ֲIZ$sW 4ofƤ 럹 ^~FV$`E~ou FUN៽e&7W,PڔU!)F܇4vq1- 9q >V|(NK΃?g{ Y{g8rDπN8_[GGpVA,D@J([AOL=ЍUDTRc9:a9z]+STbX46/;_ICd|7?` {a5sk%S"Q]*0r]tK4ldyaa +|Qkj zr"*Nٖ9ÈbyysG0.GeLϚi?iC_>J@p GmGOQOZyjOOܸ$;?_Nd>!Fڨقº( %x?iLn!,CeEQmͼMv+K 9t_|?Ŀ$a7UZ;ZU^b DZ}M h_Ry\Mo]_tgS Q5XY`A^K+o!}LCOXF> LtD/hJYRDf}d#)AMRuv!qfiY_ ߣsQs̾#Ҋ6r{] KUa`|c$/sY~AgN;3hY'9^˻ՔMdq?ʄ#kV6~{i8@)Udb6]+пpO C]) vC1PռF&1Tq48n0ủ5"4KU}$Q8ܧ/n&,>#KDQ?Yc;V[ȋ_A/:MuGZYAa9{Վ>$) Xe7jIZM]M/4-U۬q0hx@ʫ9%7! N4REZyFz.D4"i%}E NmbǠG[J?`z;E˽LR~;"h &EBNR1P)7i@" &"AbF'G⫵e*.u F+W>XTl済b6Ā?OD}DV8%Z9Ke@S +U#X's.$m :=fUѾ|T13kRi4]pi&R(?\8 UynvQemPIce+SsTwR95Ca4hM(p5<|<4w&Vrk€®#bCS3JH2#o$,vb4]6W?\csJnM_.LJ_\Y:D*X+DM]P_sNx/>QόXǤ&z  +CQ!Tj9"!"{(V8R9A/vb)ӣs,0ҥlsFW[ma}ɧlU[ HT2/b=F xScnNuPoWmï#xT.ܳ ewm9He μ. e䃨V7]#쓉Ex?ClZX4MCO>w0wN IlȾY|Q\8moU%ޥw"}ާp!oz}Uz5#q&Vp#Uj<"@p!^*yG$h>5e`hdzs'hG_1a.q[f2V> p4+M KgwxO%[_Tw^B=w7I*nYO&|׭d0"yk\lSnѓwbp&5W`$!ZL-INĔXt>K&8tQ9a<0AVO@W\Ò`ޥ7PPL0qA[yhl/,io3gNPW9;h]q|@n"t@/-Ɇ`v*rvVYf ՝bE^]`,w앖ڽ|o3ٔAv %fC$Hvy~,2FDFb5L*YwR0p){LM{\ڮz\YBԉ$GY ^&8L"Â'&P" <̟O }p@ފFD^ T,I 9ս \^1W,%hϮ[ȷQ:QOv= 2|oڡ,h *b@ 鈾F۵EvuZYϊB_@_+E |U iem}'7>Jo (Y1a$Q)BdkC!_=1۲_[Ntr@l^ s DBiv}!nN)l0dشWIcyŋqj9w.0`US whwHWXB*X=M,-EP<&LFTh]T:4.UjgMkW*EC#- KfGIbysZ $h|anse,uTӭ0nɁ\AݑB$o@Ś'zhbݛKR&8 Gg,٥w -Tƭ*fCSj ?qN O CQpI+{zcDz̃46eピcz(>2iC("%`-J z qlQӻaTH!(vN \*\2Iݸ5| 46`& y#Q I0s(~6N J] Zhܨf{Wм %Ln~qB=Cj$זy",0ruW>Hr4Ȁ0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 cleartomark ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1707393948.0 reportlab-4.1.0/src/reportlab/fonts/_er_____.pfb0000664000175000017500000010506414561141634021220 0ustar00rptlabrptlabJ%!PS-AdobeFont-1.0: TimesNewRomanPSMT 001.002 %%CreationDate: Wed Feb 3 17:58:35 1999 %%VMusage: 31909 38845 %% (C) Copyright 1988, 1990, 1993, 1996, 1997, 1998, 1999 The Monotype %% Corporation. All Rights Reserved. %% Times New Roman is a trademark of the Monotype Corporation, registered in the %% US Patent and Trademark Office and may be registered in certain other %% jurisdictions. 11 dict begin /FontInfo 10 dict dup begin /version (001.002) readonly def /Notice (Copyright (c) 1988, 1990, 1993, 1996, 1997, 1998, 1999 Adobe Systems Incorporated. All Rights Reserved.Times New Roman is a trademark of the Monotype Corporation, registered in the US Patent and Trademark Office and may be registered in certain other jurisdictions.) readonly def /Copyright ( (C) Copyright 1988, 1990, 1993, 1996, 1997, 1998, 1999 The Monotype Corporation. All Rights Reserved. ) readonly def /FullName (Times New Roman PS) readonly def /FamilyName (Times New Roman PS) readonly def /Weight (Roman) readonly def /isFixedPitch false def /ItalicAngle 0 def /UnderlinePosition -100 def /UnderlineThickness 50 def end readonly def /FontName /TimesNewRomanPSMT def /Encoding StandardEncoding def /PaintType 0 def /FontType 1 def /FontMatrix [0.001 0 0 0.001 0 0] def /UniqueID 44335 def /FontBBox{-167 -250 1009 878}readonly def currentdict end currentfile eexec ‚ĩkg0 Pcv"_w;2<QXz*SA{vrr*U5oA8 !ڙ-Kݛ LRXK|Yfxj׺Pf t71k:sFGD KǼ4Փ1#hmT{pxy7.#\J[dzٱ.J-HA6Zx<ԁnM(ߊVي*޸V5&zZG =B#Ja nj[j=w"vAm͞ug=,*H 5('2ed.! R t| lz̫qw³i#sCoi)Sa%1ٜS*p EHG##Kd-0y^/U}܏&ؕgwɏߚǚynzY( ?o&L아kjkVQ/"Jcw;ay$ĝ^&}ٹ{(vf)/_\a3"v!!rFKypSƎM3Q.E UCuԲmoϱFf 2o26 И#t_Dnmuo#50t fR/y>0UYxBAiq{x}oWchO[sܦo7(SˋNLhA,ڰcS6 [Fj ƬtX3J_2Av k飚f+[|P6GH$E?5EFFpn!/+~I)m۔%R0(I:j$/ojUC۠φ4xnȐ1`UȆC 7 o8#[c'G>q40e ҅v62s:`NG@k[.2*dqĊ9e3nA𩩿RQwt aѐ$Xk r)Iluz]/SΊP:2|. <)#؋9;@aoH/YcߵdCSZ${;tl;}&[ldktij7Ve)̉HK4)*Ud<۞Xp9Z ’f^pj*x|*C1 8B Lȳ"h(5i?O0A]I!j >:^iKmUTywy-?ңd"0]o rI})gF 1}0r6)C^=X>VIx ]n&$$Bº9ׇ^$W%-5rr=_o+EmC1:`HB1 ,i(2V~:sSL-Y+;M,0<\̭!j<,26 <܃9[7< d4,;逌\u^t_.I,\.dgT6L~۵,!4BS@MC0 쟿fPV^f?+jc'IR߭[azOAGjz(?H2Pk*jUDCH]jWKܮYne+yr:W9 @oIՙBT,w*Nj #HlWrYsԱtB-˼ĩ'Y?aJ"Cѣö~rȎO~ar_˄Rڥ,A QO ɳgiQW8w3N5ehg'wN|Haz>EFxEBl@ A&% !s0XJ;:[Et;xAaTyCledd/ġ&#KY׿<05V`GhLG6p=\KH)/.b6 p=hz|RkCo;Եm ɘњ] s_ ]!8U7侨׿ n P] 񡕾 . #=c^D[u@&K`*հPg\J7{!>6@) *rՂQm@oH#-uw}c0'"Ҭ@_)ηRzu LLs\9*hFV0hB @VĂHH̨K8^)8J퉒^ėYWBW}Ib_%#|> àʎ7ާ je|e;hO;3QG|l2;Ң!_&rLN;h̓OmLZ>Aonr DXǍe.0/.%8>F@:#eFr8&ъ~-Ihšdj@fW -;MG96; cFe;CXl[}U^l}qp>P!ToGIGsQt2B6F3渔V>l#VYz0_oeCbIy[٣JtyB ë$ڀOI H'z+sb DӁT"x]ր̖E*("j֘7%EOڦDGmkD24ք@M aDS34:f[=-|3JA @̘%M%!'r{R(){b|.A(H%P(YLy Qxr[.a5rq܀(fTPO%}@@#͢$\oLU4% V- ƛl&7>n(?"-"Mv_ @X;y=W"f? ;P!\_Dm_8vtEvYA1Rb (hH̀kԩdk\KZ) N; ڗ+;}rwYGj7A]a|/8fsi ]Vo"6aCB]C'g5o0qMc*ؐ?[Py\ dq+=_sVf]3PiVDQ`^2հ-+qeeYw=J諦W঩x9%-?LH0L|f3nrH0ycЇ2jڔP)V̪{MdUileɍzM(T4kE _}2Pgo'"..oR_T!]?SA\獵cb3pUd)[- -W ^e)IfPF2,T4{5[^oc'fQ` ր|Z ?*_b#zoPJE si]/2,svd G .!Wi>s#3擨F2dx![U#u&S5^q?ZYb]f$q{f>(؝ʾdrI>zi!^>`wOX73*J?e{Y4[Md?A! n ,"),C~kv*:p̶.Ml}e%˒9$hR|;č\.6&h"> WCDb@IlFxeN=z.! KJVM8պ pM'O+ "rcڡhɖ_DR>q sy)Wi}PuPC5J!VrO ZzESlܵb WMidիn H6&hT {=#(0Z$( /mm98@7ਙU-U;β=u:Z=)钶,LJVYmixu*f5-dϝ#z>ѱ;O $|b22kP3b%:C=Gm{3 ysߞ_@B5TL:.0^ VA$E2Bi8G s|?" 4!t ]—y1N0*4a cHDp3jH. w&Kпc">=Mej.Z0: ES%6(i~ŏnx!(Gkدwi4IN4dX1{a>/Q]CBv*8.LPZ\$_jv'z.z>o\ 3e n*,U6UģpI[9݄m!C4ʖT/O˥قo̤5\-9q=͙>bGZڱaVssmZ?}d[j'ɕ{BhhV \\Y }^֗[X0%-:PPwxI{*T;WQVڜ~}U\\Ig T~nf_f4*+JJbіl|S,+\<1§urẂau L? : $\o{4"xEɕ) u_O0{aUde[r1 .`mwX{z@u˵F.7Q5+UG4= D*]9*7Qyuj3i0%G30B;x̗0XIX Z ' i#qx}e?' ԣ邨k.V>$PןP # :#TLteٚ8AŸO}1Yx~_8 =-OcID>P Kߊ{Ѐ(V,KwRДڣ aGTsdʴwVdn Ggm^z++voY*'WE=φ %e3Ř0wRUlxhfyޥ,R ;=o+\͋E"Er.Ƃtra1uQoSf|s 8ٔSś?DL;n],щ/%0OZ&x3pw -du=R.U tkM7eNgПrUZiJ}m[/TN؞5=iP~cՙZOs\Vc2?-1l6X ڴNσ@)0 p!_+ʻ0gYv׷u0Y>m*i Ub kUH ֌S8 cPN~ ѻKF"X$W2(TXFj2 LCތvhmk "{s'4vET{3 Po}eq(,M w1}ڱvXoH7`,s1˯.͛^QDugX񘅘;#H;O{sf`9*`H?*+8KdªGP% 7?+ h3O\\D5F1-.O3nԇ(8~V?[Cc7q}-AKtImѭVEFjM_<J^^(rE&S] yA#'#F|-FsR)2a;wsrLǛQRa]Jo6Q|#UO l%X ;V2i4-QlB^EeIxs{ϔcxxQt 簬:8WCN#`TtF=J[+OI䎸G 48g[>D%Vf<?  }=|MxPg..0k:IR౨k|CJn2E7s(KϻX?EOAthZ_£,J;5yTĚHh^fP5Kb9/i =36A=u"pz83Oml2(Wkm6O?$:AYrٻfM,TPEN+s[Hj J@aRs&>lc ukA]K%ᙬ}t qR\N׌jO}=)fA=>y *T6ײe1d&[پꕨ]D^oiX Ĝ˫bZ?`C@Bi=}H_!`h.4Q qt[H/chTjZWm'?S3dzEJ/OԾ4"s}ժcL}Jqu*%Pˋw7pauBPu "V+hՊhU5 wPUS踿8"eD/DjZF-z ʯDGݽ@F;||\Ğ*uX7N)eI7%s^L6,%h|:5bNg/ 5Ļq(%TL>uԈ0Tړ#*0xnffR/2ûQ _+0ˌ`V':>qۻ@^'p۳CBg>q᯸ 5mWaX.X Az38 b%o,sc9<̴zB18ާ&<zߴcUJ:Rntigo}G& ¼ q-&(y!jeSe)HU=%!Ѯyoٲ! 7J|uV4+Ӑ,rxMo܏qV ehG*\4do@xjeD@:CӸa+1ֽTE%O1Z,7patO37[&$b9ň`»fud6a }ma>ƙuN_`;=!vML7Z`2xPQ__@A.fj2"1NMLz_LA,&h`;}؁F*36x\,Yz+ZY;eI'WP=]I?SO =r*&~Q|W<܍I"[ձbTbˬ2$I`k"&wAEh~N{Gn= n˯TQ/Tl1NO^nNm3J>`G48HN5'x$>㸍{o /lNYR+$oчbm]O]uГ@(% }^֗[X0&K D0%oe򭮥AJL)=q&S0ם$Εvyj#dv'[2+f 0`|!9Xp2)u BH{''U*ahRԮ-"V+{M6Y2(:YZkDiw|龨^?,e.YY쬎U6K[9șINd$oiw';^L |~/Mu13ļ>Y_Mᮥ'# UV;T!1ehs;èOCj9;IRâ gIy\Яn_lYjڇv4!˩AO|; %a'b]:wU~М-6Sz^4OHځqj[r|jOE6 ϾG B7.I"LE:dl@KZ}MPqSaB^fXv4q7%)a*1ߦG]9C~tU^x!'zF꿯D5 F2ئy}mF@n5vCykxS<4TxqƋ׾@Z8>|+9,!^ C=/{ lR}ڡ{ bbM46 ?㌿ٰ{yj`sMgɧ[:]5Pγcy95,ѶfS#5&h=˯~5a|$O! Fb.KlŅ Mxʷ7u0@Lӓ8RT;r>x E:C0T00W/xwOb:\"85Fkg)4\G鱆7f>\p^VoNn>!񯈰)[}jA: * MX"qMa>'-]ųU;# $]~L~A#^/ԲFJ]&7dPrF((ugni*t|Z` !kQJ>vM.9X9GJK4q@Cri-jv <5)Ȉ?nwpbUiS!@y $yY(eԓRu򧍱<%.6Ѥt6 j2cbNdIQܺ>Z-)G~ēp2"k nF;}O'l>3c8>9U%>"|/MڑCB&q?_ej<O&˔ygʰDh2Tqjr# M}Dz&p"RuR {y:)dա ?JR?PQ2{ިE$Ow Vzyu}C` }{R3E ^<آSǢ5*8ckW%6oFZB=;w",9 =YP,i9%WJMUTz{j !cP@% \>.vZd2:sέ21vRa}B{Qz<㟪c VE.Zv^Y0Q+軋BRhQ/k[9\ U&SH Tc9Ҋfy*|hvа XK 00]m|VBn4U1_n Wlر믰*}n]A~Tf?-Ġ mJo'f{ٺJA^Y|L(D Kvj_ * 60*|'UHZkq%%ɄWgwCS{uj/m*6 U/hijvŏ-rŠTk9uG:zFBeF}0lgA{ Ut04SJ'FzoCM E*m:UVv8bZ+F~}蕍Qnq j/OxIJIe}ڟ r?/T ģCSz:13jffP;0ƼA1j1"Dn@M#ش^SU3>X59wzZC1{T=|(Yl1>M#C& @\3=شg ̃gwy/BT Qh;NR4$@XC{S%~Wha0BXñ,s$___EFxw3w7~܅[l̻ef[lثrّuϱ,ˌP- 7dB|mT( GYQ b0ᓞ1-4!6sނVRV#B&N.ggSI˸llhiEzZœ.w$;7Yt)!.<"źogڪLm8$3mK$ !+ۍ刭x*0qz7g$V\س`|AKCl圴 լ3<=@{yGr E,B5jLKs @0ت&^0Lf8[F]}#3kjbefLdKTz4}wRX4~rj#\3kzCM8AVgִUQ"z}w;$ yeǬW2R5s8Me>j fI =sC'W 0w/.MwwFKX'\RN dq,WƎ+w\T؄AJY bn4OR>4ө#!Q>df%V`vɢCQ>$? 1 x'\/bҰR'95t8 ,pCnd˜ɞL"߯wţzi0b*FFQH (>IU0v-Y}.a}~^EKCdYIqfʀKמ_HvO q'I~m~6C>a4vs&3&#ʍ`z{CU)=MJ&%8K7bZu?3\l4)v_wme|\&g$7gQ Eozy^ׂ|K604g9_,ُn7{eG6l X,8PjQ`lQ}Cy$nUd}Ĉ3Av*Aw&;Ȃ-Yr;f Gk j#9nTnxz)-&eXcl$R6×UbHaӜpTy›Y7(*p}4FjM26l`=-͡2~ݭUh1c֝ S4sN d͗<Qd\wR\G3s҄\,ǜy c a]ːd~?d1߆IK^hqU`uQ۝@!dKfK6:*(_ﻼ꩙Diź?69=oU \FQP@pa=(Wkh%PK,nb`,z 5 #t]Pypg{>wgy B <Q1&D93P(㠪"$ؓTOZ)E.wrnݕĪ~#BPw0뺛ad1ާίZx~.hzÃ9_&o??4۾k,nTc|_(VޙI,@4楄Dt@B.6s B!]#ז-l~Z5xkLt6K66l});,!#B, %]ȣZ[ ;BG :.bYf-dRX2es iza:q 1>e"°2޵9sʃe*A+(^c4=]15?̮a$dӜs;P7zjz5*IDvgfsYj퍞%?@l)*n}TI~kS#nwY0Q<. w6@L+o9{k+b(ڼUuUIg,aA+Pބ;y0^d.Dñu3&7+~4f%w0uvz.ՃL[~ WHLa {mp'ܶ):W0GLФ$ԬZГV$jL[JO'uebi"$s}WD?Z GՅZzB]blOH&IUӽ]k4AS5N jvby/{ Tb~Y\*"xJǟK Z>bL qQ(m20EN4L6uIre`@`6C?7sqS@#z!N؝@7[KZ!%9,u=ǭҾ -(+*lgw&3<#xУ2d+^k$gxW LSYdccy SLao11L1 `_%.l!LCqmz<'ptСdh>C$D[ĥ6 ߋ{}l[„韖,ZH8>K; 7=ANe!>!U.]TRMš{ڽ>2 2ydUR;mLf+, ߤ;ԗ69KE)Ā{ΡL2;Z &'4.UW2k=SzAΎ,"ɀ^C Oxm\>gS*QcU;_?}LVNq؁Ckm'Y=p 2}LND?mk8^x31y^Ȭhydlk HbtffܫJyjLA"#p8FǨ6\FUKy>^e${FշPP0l2 9ZPɒu0etdEwpX[+RQ&|흒c@f?cM)nKpF@Yyl`yqbw[><+M$ez1`^(@.{;Cc霔0>?nmjH&j \ߝKL7Ͱ\? L:U{$D] Uڽ|iĒ%2~\=Suвou@f/)fpƒc)No*RR%/䞽Kq&2 z!X#?y䪊 eL!&c3>rp|;.ګ!&V6kkU&u? =nVZid%Mib XS(Ҁ PP0ژ <$I~_NUÒ7/VVؓ 拟;C\+Ur.~W(\Niee\`#T?T'Be2 ^f67vbͫHn~E?;XG3j=˽B>mȎ;Wü'݂RQɆUw{R7Pߺd;' s]ƖaUx k -I=PGn7 gX9M-/b |}h T5x<3GyRng+U,?'sj F͎bHIW>En[׊6~'.`SR1\:;![#eF3?­Ä'qS⒉+i*̟6w&Z)C]ց JO ou8S>>lvі0Ji:^@~^+]%1II\dvAX (TW, ̰|aE~J}O0RT56/e\_->·Pi'Kh܆D#>_Xa:LJzmAN&,|nT3EVٜ.dU`1^' 1Z{Q>ilw.T%)-}s5lC I&7%,&nlr9ZH$n Q0TV}WHWVXn^x&N) KC<,=I-A\LٗD|&پ5%7xNg3>4uJ`^'/)+H~z8^(\Y?'34j‚ֈ/n5`;H;pHcL]*1,%G-uMK~Oցw5TRUzPHXj|w啬Yܛ~ݾ;26RTR~;x ׄ>kW]O(4 stVk?O:HĎ nK{ 6$H/nUoM1$zzʅL]Tx]+nTlHˌ;cD}YIXdeƧAűg@N[-vRz: $}Z1`R/+u-i.*Ŕ4EZg Ü9,X5A?L wzHTie]_47YhUhw~z7C'I&%ǁIK[`Ų>*57,fO zQ>:m΀4P)6#:Zv.cƐc}1S-vM6aWOCuصō.Ks/ܑjDt3}, Wx[}G4 '#!@ɝ]7]#`w{ <\ͮ\^Us8%-/IInbQov6IIXC. Y8pW9Cf9g]z/) {,$[&Q_hD7ݞ u?"h⁽^SL`+)}j~e| A,HM̿-@ ~bDD u>%ѕܵa}:YX\7X,~}v7Ct#:ҦZ];,l6BgUĊQ R]eS N |{˰ߣnn,(S |,cPlB ۪M}|\MUԤ(9/ŔsM1Q`#f1}Й4s EVXIcce7\KK4_P$MCSAXXzI[=ȴgCɅlб{*IZEsǿ0x ji8anųszhǹ!,S,H,9~&Ҡmc̙"cW]Ϻ%vW b(9V6E~Ȅl< .g jz1rSԆ(c@n=w3=@~u'u9F%IU_lcQu)d6'0-BpQBh~ ;r'74sīm]*Vr,aɊAߨj&sN lP֖ t G5w"xc"~QW}%J no%_}C!ɼ;{Jcz x=yee'ήӔ7gEH.5w_0a U;(8qcP4ކĂDSy۲V ;'8J\uYu;A.EH߄ЩhzBerq_DA$j,!T]W*<@W9 F45g NԲP{ RK-B(mrn/? C>*)`;[Fc8ΖnRwl(!qK/I҇+@-toӗjԜ >X=ԃD7 eX:+;@pȪ/%ŐY] y{OtaP e^6[_|M ^u۴G:ofoKv4_NY_d^g?_ew|]:ZvJ2˃w ,/Q"Ua_w˲Xc6#Hb+z5ќNuCi`1Nb'JZ+S+LOJFOynP2]2]1>:m.x K>'N>~Öìqb>$bUEIf+9ﰝY@*FcrNܵyc>, _]NOYYV8tDeIwcyF>$L|*k\|%YW#.&sOVt`y#Wi6r|#{5H?ƫ:?+QjDrfۺ:C#UNQQSF{.Cjun,)ϗRo3vxU48Qٮ1W&)e24^jMEP'^JW]F}IjJGM{׷8ddWCgxDBH%',ɔO=[?c~O݉3RG1 m{k jw+&~^p%qSy}k!13_c*X-Y`fE/ABs8БzՏ WMuFd0YK^_CuON8Aގk>WzIzHr7e>( %Y( ==@b4ぁx]xSCeLϰAIQ 2[%@ c ؟Dxrg2 Ef&:*5:DLM/H/>VM zX#aM(-_\㯉ke7 p3 Uư# K4 .b2SyC"4xvmޞ3!ZLv*q׵8bAמm(A7H9.0ETF2>~ -CbGq}k=΢MDiGLN(}zWePdvfMǥ~6D/BnB_uE?&RtKJ71kPҎQ{5!ދ!d+Q>"Ь2IzjV.y&}G)䌭ZG[. &}<@y(/r, [%Q}0mPU!qL,G%LG&h?-$1ܖQ@{Tv8wB59AMm^6J}bMڪ>G{*\RЁU+7D~xEYhbŠZ Pk9Y+C޲yWh{φzA;`LBlI_e:x)$Ԯǜ`\t0$ӡzRf(wRKZЌ[f3q tm2K BEfcx^mjD }VH6GT,_Cp7Ph(?&,(#n#uNӵO!BۑT@ׂMD =ۑO=0:sڣ!VhՄ9iih,]99>3voBrt +b>o5|hn> q@Xz! /#IA*iQUɬȪ3§(q47DHŀBWy# p͢KkG؇څ Cd^^}MEVoMly-|a%MTAC!qsul;9K&AV& m:vrx8Z+N(V6UбƔ洦pR(+8**8!Q3eo[b< B!.}(OjX+{Cv/ڣ/@&,Bi)hZ즥)]N/թe+J,.v(%PI`yk@TJ%3ڣFGht M!#,*<|eթۏ1 D3kŭ!iS*"JJ JDXXڏ|.:7g6)[W } eݜd"sN\4qKP<4vJ.`)E<;BڙMuМ8ag!ofO!+G+nc'^ֿ&FYɖS|Z}b'*9M0z#3DДE3̛RBu'HrypMۓ~!GNj`lOvP\2v[R( ُ>sw€ޛ΄g!2qjogD̟%g6Ho@ОݱR7@" k޻}<~T` }pZ $'jB,( d;3Z RvaK|,B;Afr(f,pMLl|ؑL56t&$+.Dc%})u o~i2[~:+/Gq@@qZgo4sݛրof';P ɫeM׵ !*됸i_(Y~V1an}h8Jb91c";~(95'PXi]a.בQbR w" 9 W,'q[YeR`ϱS',R 7`fY\LɁ=$e0蹒&TǶ. vǐBHr^X?|[_xեl>E%U41{nJgh4pR s ]`Si,PIS Yr+toEg֜ b޲Ъ@غ%ӿƟ:Ј^D-ˊuܲ/S2mqy”qAzdJ=NG,r 2 +%k͎kUa̖[?c?m=nTƓ<{+ 0Rɘ)3 /JƊP0\ː)|@Hg`@=8L<To)1]A{GA: Hԗ䄎p'hω).G{~WۓؐrFUy24<8J NkA*7З-l64w6L5hKK[̪ZUy'iyY#CUUѳlfD-C1ID}Pr!~!z8K}g~'` Iv)Ģ4j W7T%Bcnh|w)'L%J>nhg/cy p{t5[m%{X@o/U4 `x-c۳n-䬰Zʪi%tXVZq+$_Ҁg#>.#g-^Wa IwRp4@c0$G$ u!$\K1[z1;yn)k pN]dSy$2(@7eɗܬ?ox-|#{+WW-x%1=\eE<biࢩXm|,,^籲7Ca_t[~cY${)-)j1K(Ё9 {I.")dPسRq aTJ# < 4 љ;⣛2K;jLcSu3B*Vӎfhu~Jq[)?`9捳S4oNjVm8Z#˸bQdsxx4D79ճ<7`k{Ek н=2k8{{p)dM.<!;Z>dh=z[ 3H[,-f˰)G)RYֳ7C8(gk7*Mf5Rݟ0!ZˇؔgX@So2w+Y:&F?uNjG $:iz( cw4LV5O<p00(]Xx D7bZ˞=Α4hZ_n7sHy.e IrjGЖ1uMY$|<VFxq_7$US/JP충8A;m/KA>u K )W7ې,_rq)Ɉۙ{XˉΦ~)VvKaCcy7<K T]12-^r:$3e\4W] A|d$S{N Sy>4g&,:~Hߎ; iVfsnt<"$¤Ы~>%TlJ) ~_HG4=i0fi:;A/ KٙnD qk[vG^9Zux o\jJv#m>|e J_w4ڐA*oy;̻q=T[D+?fo]Ô٭3Q ߶UB]6. ehCdOq*.9RZ'jd[> P2V| GW#oV1 z8m{ERԘ-Q6b'7\ Щb'ącHөeȓ%KxD=4A&5͖/AYus;GG2`W c\=QC9@v4H)_ƚ鲭{m4f}핋^!Vx?FIqx{A׹؁NV M 97"徕-SV^d}C[b,FH[[@pU~/::ԩ'ziUG=l6#H54vnm2@T 6m^؃Ѝ7 W/R#>+{圶CVtj.&ܕzR?Q_t PNQ'mK`g: iF2~NSֱ9*oqn_w0ĊR8R=lsXd֝H 䇶|xIX4'> iŌ>ُLfnX~c ~.DW%_IIKKc]Tsg&0T])B+W`>b@=\klpG~'¤O'#HNKy/WkxS%]+AҐs:8(¨ׂsw =0AIc}SfN ̽ f`%1"#\V[d!oX{nʧL" }c&};7~ \flr-Q0feA>`Rz{l,r 'H2Wp@O;#[x+ڮy3z<ƹ[n C:/QkJ_6.G4WQ&^PQK Ce\3+3F~iW3d*(i Je</grWxYt C g*FLXA[05ZP-iܣ3mC?ejS<o:7ZcD CD0]6Iǀd&U=}Zݥ$G1fl۬d\-VQoPuȦVfZ^J؝:5.uxܴ̎"tƓ'"v[%+H 1(&QS)5󍉰C YDW038BxLkz{򣣇U] -B50-Cm9mm#vu'^r6"~ڎYf܄M+A+T-sͣo%AʠY qD*>ϳ<:-@q<?e;fISS%6azHp&Ndq,Wdפ|)~?p@Jʗ zEk}60Xұ &ֺ3Q0"W )چX6R½pt)\Y,l6uߎ"QZ/B\>.zw;ʗOw;im>}=?]Q_%G2y,$*1O^!:LRȩ∨ [)gIHw|XjdzżHHN^p"¡0 XV7('$UZ*] 2|NV"gi'4oVHmAAL)H%Ɵ0d!^ %im مM2cs:1a<xIp x 7JYH pQ|FUC o@ĞhzBs /T 4 3.ǂڐ>wڟS%iQD=jPzazԗxeT&0&wb"&rЗ;ÉK_ >:l+D!pi.Ƅ7ǧN $@Z\ZT2ӗ;$)ŊpCFiKMR1aRg=ɬB"| _rI(brs ͭ:d^PNu^4`\Dgd30=E[&8 = / kؗyb\r눅yjut{7 &暿;ݵEW(!T}g0t.!m"OF_*+vP;?xE08>Y '&Xo[ʗw*>8jA܎i#(Ď Ҽ"sT4~ǪaKlySZÍPkfkV [67 J`HzcĆ<74#a--Z` [w7ΘORM4M6C?|(7ART#HI} Q " nݺeh]_ ]Grz=| )M3@m ~׹peQVn|7t@'=8IT"Zc4+Gn&wJwX n}=]d -Hj$‹Md[ SU}`Ĉ̸ #,bx6-)-!ÕнgulB|@$dK^+@i 0VaQF3iQaEj0lw.`RLy]5|F#oulRJ۹UO#M ,_{S=@W{=G(VqXxRtR *ؚc$ӵv}.cLzAK t`$4D|~%II\qA^ˎkxQC 1ߴD=~v1 +aʬսAGZ.!(t,̐rߴ);x"sy=&(sυȔ\s&E 7LJRQY ښC9# =ո(W'Xm;kZ۩U_H2FvLoH46+ը7ˎktƒah㫋Sj%9wFli k1<0((9,>/jZPzMw76?DDw{1*WꝪ1KEdBlڌJsi86M0*5Գ:~6s4"6*y2t$9b7;j06t_JQg4Sέ|f[_~|&~F͙д#v:yI2А&ea,`gTҵhpP'.˻pq$o!ejQ4rV|L҆%f12֔~OcZ-8%(OMSR2a-$J,cy?6 ld2CLzq<%y'dA)c!sZJ%Or !h,Ñ^(A1*? 4%;ja'[yZkWXBS}>?Śߝ:yMLI uq"h iܯaWzl9]W)<)?Zh!llȴ!򓖢tna`B7sBgbg0}YAs72 RSc(ps: *:;,ualNڠ$(?E搂BZO CvY\$a7.2P҇rAw~F1ՓjбZck~p7z_;um!75z4Uޒpf T(yZ{rA_NS]:guj|oS;]s~CSRq(z|Uۘss/lm,F#QB3_0Yؾ[0&pUPD%YX[I/41 >^Xŵ~ع M?1AUo6. `DB&/|1zoO]Ret/uINql~Ab;H޽?IÌVIvawOɾyͪɥ8_9 ~[*41I z%B7zP=^/=̵4T9jE-ܟj^A /?.!Wv5Ug*tgfqAx Sok$xW<Ҟ[)͖ \tQ TM7y% t,л-Y3'}))ȋ(nk,P=tK,H~E9bL%?Jm,z͂ݢò6D>Яnٽ P=6\Ǒn2dB9֔lN]@7zUh9W)`1'}`HEwRYdrOx/ AO`{hSvt*Lzw|^hwӁ1_0`;rAtdU i G%bY ?GFmy/[7w/kMy# LHׅ-9cf]A)ɑ7l=2 .ia,YUx{bo&~RaB3A*cVKUT<ч#5do$݊{3g<}}*E[I)}42&+QgX;bRG/Qڜ/!pl`;iPkt_z8gbj^".#\0Q. obLDy(GNO'?B޸.:0 {2'J 췤a7;IBL{ʈ\nɓx/r5#M o71SAy9S '+o9Aw-HuI->R!ӕJaSb5hG%Z21g|kaB}R߼pq̨S@0G֟pHt`\u.$R_mݭHYr(@RE5Du=7 Y.BAOv 領J#4vJ1ݼq `֓3ȣRQLViBXg[б^%^?,dmw<xcQ4bSVۿb^P5`"oCC~laUIDY̚B$vT{s*~w5 AY0 +TT`Ƣ2iZ;!JIm& pDvDggʟSWv: D, 7Pntcm;c6kdǶ\c"l@ }иkj&zMa)Ubk)"?dX'|'.B`4׃<|<#/֙:fӎԉqa79ǥh]ƑCT zҤe4$?b 뚚BkB:<5W'{ltGtmx_H#㎪kn"!='|%;n<\#f0SnI]R4fa,1Y(|z`xRMJX4 +dsr_ԭ\r-x)9 _>QF(q6HZX {"Cb#$m0;/,.v|Ѐ@ lz~<'pʼ\1*-Fv&b#2W)i?$ײ|MqM%O)=A4,v6'2kY8cM`jeMu8\8 &ηl<:%MWѧca@v2^+K f[Ύ!Ov%Dzbi=11F3EzT͋Rc^۩[݁<*lP' d9tIMaEӆ>o(WC/R2"=:9a|n\W a00'|#NZ!{&Pn5 * v=`\ܨ/`]}IoT0ޝE|b (Yg4 lȼr?@Iܤ 2R{OˁQЙ*H!J,#庞G<>1.63,1D-C_/U>VlaYNTLˆ,MW|2΄͐ m`uWM|2sy{T[M[zp!pA7tcѻ Rv!=غ<2Rc<g!,Ngbn}]cWO;A#0bh k_zvNL1?VA*>4G QDJsJ]+8MDx_sm@Y2a*?K "(;ę1hy\i@ROl#7o7nFFՐXʧ {4$7t#C\vkߗS8~]q:d.r?څD"Iʧդ<Ek(iqc'^u T:TمE4 x\\oX\ε$lvr<'朤!aMizd!}{ =ۧmE1F0 1+T8 tK*ڞH"urd@ D(o`dzBBz߷52 R^N;z\qtvBXe y+.̀6]UqBc G6e`ސ}5'&pv0!p!jRo%.2\ {E~%JhX 9F1gTW3k?gd3?=i5T.$9tgZdo+uICv/A>a4ՈN_=52Bċu\os`䶎Y@"_>x?B溞sb_g4F+pgV_qk4#s bq~NVfIͬ iso~ -/̄ I#Pi+kr k|CpDfgnD,X/ĢFqYƷ6:&ـ w8;,ٯ}"a57=Qޢ <+Ql̽-wspmU/ *&J*q~)ɲt&fmXYlXĘ=\P GCxz9 ,b ל",Ԡ ƆuY7g1"8=2w٠]=˲^>)xE;~РF0(+>˱l iU J-S0|pͿҩGxIS M'20TY9ΤD;D0TYRp prvr WǓ_Q, Ig[/~O9vrQwE{1G*@7+ zIփJꖟʊ| P܈ثKǫŒ/0~ J7[9@OEýԮ.[_v8IQ^ӨsZq vIz=i1t:<;5qztஷ{ G;^M+HbDZi 5Ϥb~5N>beQn|i T4b)!vxo$O Ÿ`fT/?JbaUn,g*K G2X ̉P˳"!1N̈́t .dso-񓆦%#5ކ%S64^.['prgH 7[/FGn=J&MN=zZi5w5\Z愔; I4H]a&q:?&kbW=N9sD$ 绋|ysp>t=8&'r=h&PTFWZ^_␈}GNe;yB 9O'Αe(p@]%=N zS19r*7LmňmND ;kJtv+}|א ǰ_3ZI6՗PW%&EZPʏ:v(d,D_QL mQѥl(D Gú:鴧(exXqGˑ}. sq#q@>ARFÍ=3;\t[V_T!lR˓ȡޗ~ph|(tw,}e۱~}5.L"k]\LVVHQPDP:Vd=>3~Ǟ OuyJ^-7[5Q8e:E# !+6c aVR )Ѵ)$k#Ǽۜ]E2׬$؈.HjsF&< VAוXu/~3<%[¤Kx]"n d9\W;cr)LJHKQߗGQ ,x0KjZ,i+D 7w-1$ VuۯR\w{d\;G Wu<6Ǹ 5Nj`PDm]m1y&}fރ57?!h6q+(HIdosXVW y-ᛞe(%ۏ}m# <3Mv JA¼ʒKk+س0K"0.x Xz`DɅZv;}(CsE:& |!qťQj`h~*[fֽ9608ד8Vf=FDH޾U oO}5eMXXúZRЩ_lF:c. 'WÏc@)IoGPSmqEp3LU>B1}h5|2mRnB ռui q%% wx@_:8Lj8QT<WTB ߫V`ܹUs54Lu83 ȴ|n7# ADOZlPڎػũ-[Wǀ0̚bc>ŰE±QN}gKͼI20c..+I%=UVe81SM:[$9{B.}dh8A!Uu6$9@jR-DsvaPW{־:}(#Kv!ChfIK}xэ2 k4&.AGXP J4Чil/?Q@($0G 59CM`U JeJ8}`MNUA4=BǞ!Y{I!wLTfЭE_-`Jng$疪R!CfTkb}~#;֊xwz2}(CS)-Ek&/F:ymO4(mTpf)i,X!Ϡ=[ރ:HqCjeC~;DD[QEXs^XjNkiqa~M׊x]]H `t஑Uƥ_K:44K>9P~ ^5T Pkq'Sٶ-j@ = {mItXdo;ɬ7wi)3 h m ILۋwe3٪ZB+k408:6j)]7:&cM휰q5z*/R}K?Rhv^n9Jt[VUf?ۡKf`gQo%`__O=imkQUj]6CP%E_ʑ,9w@F X71fM!m2CPm{'xa#ԃ׎BὗmPIkr ٵ-ռG(?::q>kZPDc䧮'tQMf[=(݊X̜Н( x ŨAg1]L)-#r#GC+;hWk?1_9ncA(IMI%<SAM"m@yOy ;ӟD~A$ уWxO Rm *L YfJk}P M1%nA{ͯH$wːӻLoys}BވR6xBRoax8 r'--a)`{$`Ҍr"uut?#mXs K|4I !zm;@""eu L5} !SNH)75R5=w\[V3&|,gX%t&9kH?HAY>[Ma*0ߦ!?|{3o]Ӛn>ǍRҳ ɍBZz~]dn 0.ЧLƄLsuBdR." }H| !i)>63 y!L>n,=5[QĒB,ѾkQ!NM!UGn%v7}|FZ')rhɼLrbPU R31ᵹ赽Em+P[7joY4oYoGw#kB`DQ'!douSE`s’A7Czg]8JBʼ*ݔ.6FCRMnF NĺH[ SeP c&Ec%j;+ߗ彄=NVDu2XU݊̚ˆf8Osr? ,"bYmf\c tIW#DTQ21 3,ի9]oO$@顭G;+g̱J!6$1\k(A^pjnEfSTmۙ/B^k&OpkN_`2\٧rDbBؿBÒMW6Jn"18A {sB5%ހ2Tb8)M) k%ldŠ:Jg9 [0͑Tz͘ԩ |rav+"`, 1;<ކ `ŏX~^SbS{*Fc,9~L%W^ub1$ñ3`c"P&;){m,S<­U9"8/6]1cusC(U!T PYԉ2xv\ WހdˤXe:gV>=)`UvLe,9z[jD)^_:$iN=U*X p]Q!Y~~i 7J cJ}lj]uf ":ޔ?mF3` ;4ǯ$}aZf賍,XbQi:m\1Lk0ACn*4m0µ֑Έ1> !aZ ڈRX\S8ӯ>CZF'0#r]ݡ㨯i;0x ulfAN([' 0콱G(=jݎ{v?@42Rr~4Der\SNɸS٣Ⲃ ݵFٜU`mX֤ިPaVrs9?!<-EtԗGmN޶tBw(D>k^?C h = T;Ee-s"2d'yUͲ{\oyVf 4o\gYRD|rɀt ^tm`n/%#0xЬ/jr\@ڹԾ (𿱞5aAN9qs2ApoWVgLdg.6n# 2ʨ>eߜ">RST-qkm U0iҍJh^3x]BqtȮ'=mD#wVx qb=ꀚ+'֏ @Fä ?@S Kh94az Vƛ/)Da]u)fb_9 ;8K}oDGS}޻ը^  u~` Sٙ۩ꇯ)NpA+h;;l~|RZRZгSU&C 5Х6!n 6!tuoGp]@2+Y 1PSn}_pMVf۟l"6+LL s{rY㧛ѿ@ %lD&D3Oa%NB_o>\"*3K(vU<% C?6iL?uM MmIfw {`| OC臆{I0;.1as#j+Sy$;_nReSǭ9KS%+ ]QsEkΕHh1uеBnU/ey8 2DS:9%2LD @ Ͳ(\#ѣ;hf8qƻەaZ'gxMHծ7 m>#"VCHn:gMC@N3# <_ @볢p7 };=fzDiT `x {:/ﱘK=_wi-Tl+M ؞b!L5d E`)~g؜Qh 18=Ht:=+S^ۻ7(UN\j9j"Hсɗ5 z ^0Qm߸b靳yi5obszH hsەLK !c*i껜XGvK`gDJ m7O,<%lID$J8=s%!1Hb./>AQ/3K- (Gv ۻ9 [ّk|<^cnbgl 2vpc5}@Y-FkZiiN4Ng*;挛:<|ۑᗮ0NKQhf5Te9>)j_F[ѳR:au"z7䑫J4F3-J'ztosf+(U#sPIJk2"P*c_mo* AdLx_/VXȞAUJ]SM`Ie ܎@/uH .f[d߇*"+I>*Wl!EN%xS"BO e.X_B&T'24HF,1xx]VYmBX{c%SX|fn}v&\G#Gςt v7Dwʕ0գ @ 0C ҂^[Bƾ>wq)Au xEUD P +/Cr!]'31FnL ݅ *D}Vݹ5~K{Bu+\TfŠ+nu):,C6e_WiHee߭-6utgYdjL]q1{l1Bg+:=ȏȀwS?uRPSBoI6@zHU24Դ beR s6?]kְ, gA/uG5) *_H@m [.Ags~ >oNr%lqT-e"MZ [Fӥe3=Wilu&xeGb- #C Ø3+jH*OMKY.]ǝ a|ްsԞ ]c+1\ ;k)y]OCaaQ*$\Wkv Sx4:`4Hr,sqe 8r'U?at=.V6qgCpC"ke 64ug3uD%X펩LC>eM|+T(O䜫Yo^\IDH5򓲲|ezx'.Okoۺ$:+ rdeTV=L.e|BTS98@Y3ɥng·$~Xlvn>o@%Elv(^8^ ɕ sV5s["[UB71] `;? m2ZvE\I9|¦.e\Mb#őQ ȋXU &Q0Ƿ5}&2P=|jVvDKuCE`1/K[W"_1Tx8mOVȰQgJZ߼t2[5Uf)fMW(:ut# $WIBo*w<nL_6ß\1T4EH>l"kUCYFF4s Nyovl@RaO_ y= G ,J)T| b~bN]88NwH|J` FoX5NyT|ZpAߔ ̢>Ç5CK=4@D%JfđYo l!C1ҥ߫O/>jҕ\;ZX#Ѐ+hu6JEF2Qr\"7Q6ƴ+YV &\ncSe;ʾ)/`Wr."/݀Kq d7ˑ%X)T>YGvu/4hm=GiBV0t1%P/AqoȬ$^0ikVYຽʪaB߻j;H}PX;|*o?FkݿAʜŨhms|' mէi^(wY׷c⌵K7e^C3SW88z'o1̉˥ن>ΒL-ǡ՟(B=@inJ t_{^9eu"r3Cv z [v 7eLq˩_{:$ʙ\>V li?RKbɻ'9&!Lߊx/TBɚNGw0یp)mg4WJUM3, D,o^@x +"fRGs, RPzfC07@QxQ2X)b*bۚ)&Ƙ qZcv-x@) 5vIzL0bAu=8PcO֒Ii_vB)p1T/QQiYiOĒz$D"eK2bՀ. ;Gz S@}۽f0xxqS0};{V]!l<t]#Yj2 XJOgE%/6hҽӉ =BKU/sFPf|=dR-W/> xoA!FyoNq f췄\97 GO6;:s"ghͿ`wOȋn[;2JM򚻾?t4叿  sk?}oV$[[5o9j}{LsG]XV0K}oT&vM+ BR .yYHN!vvB6ywo '!pa9Pe=wucMYVNKfMYڴOg)^Mi }Qkn9h${_I|fo%e6aO},Z£Q]Vʝ!f#.x{Qdeck./o$~\eHY^3؜TEb^ri;\2Adx5j~{HW[r;ă(ULlOdqR/`g@UzY =!%pvO"H1z]qąjLz;Ƀ{{U"(cd{P'گ, u7ӻ)ffؤ3#1S_RҢҸ;t޶& Y`շtZ_ow`%'R>5њ*ul5Z Ngk"lyG.tEqMxd3V x.*| iu[q?lsභEuğ_`[Z{dA%L2I6OW@\ ݣ$i M.|mL#o爫p%@JoԶW7  R..<\OnVb3!H MԉR( ƭej+X pM$9TQp)5$ۣp ^\GۦUzP616$QV *bt4#T"W}E*`ShE<.dT;#̌=jT$f` 3Zl*!fQ G IӐ܉ o/{==T֓3k؊ ! ŧlZvQ6v7BvʏS؞ڎ!A+GNClfj9D $R}-w`<ŽW+4j]Y4SY|Ct `E*< kY.B]HІ=?Zl~\2>i3P+x4AV*?P|15'$WY'sDs Ӎ'J0Z[ \d &Jpׅ}@AmOx-j=*ؕIĽߧsm# #2av+yzp{K-΁"x:I"Ьm,O–؈sb> Y. ZF^uR*F>M "Rw/kAėuU}:۞RmK0? @!$uO aŌjb\`{Tέ$h-U&ӹL7p> C : 64&b'*aU!=\X]ci:w$k0]VYo*h.eѢXETWR&)d&s;LOw/T ߝibb.'Kq^wO<ۺNvl"xl3n ֗΄Պ::'q7M й OdimjMWmǵKNNQ81u#w*<6>hȃ6ͥ,$]BBT*Wʻy!OP:OQMY4OذxSq\|hOӊBh=x`9RWgem$*pFx^Ax%[ dQ5D@0 P!vL=;j0P&H9Uyӄⅽ3V[WF.BX aJO/.va ><$ gkyqGZJ/ O6BB P> vI֢|ڕ%pTGn 75شnzai.w0ut+e xǐ% e.7PB-!y)=.AdȵPV1jFCӏDH "vT,eکD."U%βd~2i9S,vQ,8I!ڼ!ONb抇Cj:J]8ed,Ok!7Cl}i|:OMrEP\Jabv58G\$x?+?]'0?hXZ]2N!ݎfd0+^r(}C e}qVلO+D5aP(ʧ%bU]*Yۦֈ[\ghOD0 աC-/F\x,,Z.m-Id1=JTY-{u{:oy <ͫ~xaydn>B5!duQO>[Y$pͿqJĚVDokUIH]~y\=/ѓ4C:LҞ <ՈqlyN;6򐹙M*>iP)l!{dYfAѼrNT;c QW$4 "W cC H ?.\aZC(%!4w3 )U{0vʖ QAs*XmKCPjO;HѲ ;.( In7tB^ge)HNSE60ܶb^m"r R]-5Z#Y\Y}e. D'lʛ}}OʎY=.h(nSi0;ܗĥ[* QӖM- U߬5'[ 6IJ jZ4'ːUdXy ׵[0_ vXX ܜA4)'t0@TAܖJ&Y׉sOՏEK^d9ϧ/&Fjβ 2KI|ޝɸ|)榤fHg\1;iAxG/PgLE9EBupb8CxO8{L(`T2G]ȃ|@ q5'e! V,W@g)tU,bl1TT(W\ЌCbi7@ƬISk{JƙE$qJE끾 I~ou-W}LKUηHpYc1w"i2 9OZ047 #AsZ\cZsZ `Ks6<ۡ·ĘМ$dOD//jy~j'!2z|I&T8#ɟšo8& fHM,h[5GcرN zd1Yi)>1[ jN*`2QAm6F{Y6EC3̝1]# mK-=,zҷ-w87`ՙ@ߌ1uThYg1K8ʮR2E>¹i%^&x9FەPh@FqN*NC3#D9ZoTygpd?2)X0#i߰R7,<鋖%Z]kDAjU{yBvFD wA4):G(WJͥN5" piU:ϝ{ݟAS]=%,ͶMzF!ܢC V>A7& [ABr:`ma5WovNFO w|ǀ۴7 )$c1SZ& _f,mW%|WFjij[椰3̙O7ql#8+<y5@pQV q]I%?[L@!zv"J|ƪ F߂ae%TTjNO@;ɯ]|atb&U\}TmDm\%Z")?͉LG?Ab^SFUr\ρL\~4ǚGzȦ<ܰryvJ%vBN@TdVLg]/Ct_>ŴIO ,Zw7\@]~W^x/@eSHV)v`q&^#iâ8#nqT[P1wh2gpA^/~(ܷ~܍ H<4. M1jO6܍?6Ȗ}Q `!ۗPLpJUsM T9j &=8X Rfu&Z.JY~;\/*ͻMsN2]7&&鹮lr;_ 6ud<$q bߝM&7U4^rɞXr.cN.[S`bKs@(5gХ^"oC!ܤHH`F:r~Up2a@y0GmӵS[|4я8vX/.E] f Ѡ \y1yFq6 I%O</cgZ 2 e؇sLUW EacL?(W'gߟN`=ڈ(,"^-c^gyEuMƧ{IQxb֮Q@I|/~Tݽ&5`?PU A=-9l?lИ@f ڊ~)ܒt;\nk\]onqY&wyQIdJQ "|!EU3V49.^l @Q PBIiH$ d|bwVPЬ) j;xAqMmXYƧS$hK=Zyz18yY4dC4v-:FrJ'/.u[(4k!Mm-l:(Fmn<Vv@!(- +A|bK>)///=%la`1e Xf,9ʯ—vQ)GPH7ꁙ=C=]0⼋]1671 Y7o&kH閡wv+I{3a܈- ܱO;;K{ߓZN-PJ<]-*]NMYDzd@mNP> Wou?1--[czz Te,+6di${JUc=%|4# qK/_H/,-o~:fx򲚡VlN!2#wZ4K4i2뿒0Q&bwCwse,[0T1GDTJߤ%g O4_6<O^0B6+ `W!V㐡`Su]n#ܼWTk4n ȟV3)גr[SoQ]h1eGsI?f-tn ٖiU`|+z|nV56-i|ik0K6 x?WLC]B0WN7+*ͅ&zй5W;g! ւl=İ]a͓)Ive8i \ZqXfSk~:cHD\jWN(~)dgZNNYY4M/Za3̕h]ij^TQ$qBPcOj@FDIұܫWTA.6RĴF$ti6]msrk~~ؖHM TdJR;@!W,N\ݖ b<ZSo-2ƿdc>(~pيo;qqfO+5aH < +m8gcgY췹bæz1^ p˜d32O;3ԸoDpD v{}2C%Ckdj橭QFsDɵ ٚcvܯouo C TRAb%7~g1L"=¨?B6ѡD8H~+`)Mv:E vVNNO=31yW՟;hn^:V|+wjL'w:sF3M#;rh&((o5_xPJ1;! Md#׿A&Ry5 Pwڝ^mFiW;Θ8 ܇R(X t4pRV)y! n7_2lRgFP祦P:`"#u :#)H㔥|sO< cC$3\Eu)e&i&v)ޥZE73}:Np` IF<(h(=1wux\fjdvJԪChlw&.Pn0WBv Pao[Bޑnq^BYn  Yҧ2Υ|n>a0_!`e6"rNVE-gğN͢s HhSd-NJwuއz ~HPY(琠=xi1鈣Fj&w$ȳs(JwXue%(!ly':d=ۥej=4Z۠9>lg5-װ*&~ :V|JV%F 0۝_H2Ƚİc󘉫ab6.@^{KRt]q5ӢbzE iz[u Y F'i|Ճ?W+Mx[CFr%zH.Y`Fk:LE;QiE7sX8fڵHFlfkϵkcq́J(iχi6l: VXWf˽ vzYg @Em9zi~qF"P-Z؅h>lJ yy;wii 2`+ WT1zu Ԑ́bڌ8>z nn!&x?MR;]u@!ݩ^LGPNҨ['-DZd)tţ9x w'޷zɯ U[g pV0ڣG;\Ӡ,~iǐF-r 9BtJ&U 8$89x(]6(0=,tS$fr zw2붾OVQ GJ/v, Tq1<d#iO1ύ9- [g9kK=3me&.'3!*c=ز5C5RXS"%آK -ޜ"WחgbbcWȸD_B?კsv/MT- :pCۛeF3_cp匞/f.f"lwCQDAÏ%vS-۴#\$ 6E#Qaa%j}!Ӝtr3*1-T-w/O(EC/rX;@( `)a聾yuV4c%LW#8jM9oրnj"饏~Ӳ#%j<Ȏ\r}&™_cִB`۰xreFlF,ngy WGɢMM; !1-Fle.JGK׬vU=c{2ݨăun-F,KaL@1Or<2vp,A՗*ELD;go"7g}zW5!`KlQ^s'v=da9[ :꽀̹g50}Sٿ/\։_IQn@$c4 y|>i/WIQfhm[ҍh|Q \jMrvZEtFy*Yt[9ӃK 1ZYaP]jwd+/a; ]-jTWX,ߏ:ӿayewBظLs d'fm>u%1sR? w%ΊNU/_ OZYM5}v@ؕPX{v=@P /n!ݖ^@sM|z ;Wb[gHBMM\GRΎb1Mzn z&h^|ꙪazhvX_p؜ƀjq`Wn["TW{J 0ܨ„]#H"OF&yF_&qTˑ?R͢}FN:"Ig=ڜ|u^} DS^|[g#"#fJx)boEp(}޴!a܃}SGfsn:-/]ƏB#`S-P5l 5!5(P\vDyd0+WK2~緺D wdu k|TyB!-bxFU;Zj"ۀp ~FQY"qk&me6#(t+AQHfn Sٴ pP QzjF(@^bqؒ\ZnN 5Q_#7mZRAZ6R/ zU,w1{>F8yX!J\0zXِ'a&ˑQ^ב|?nu,`H,sOB ~ D $0 S׵EY׆HAr p-Eu)Qӆ`qۿ'Nj Ě[7 wX0vl#îz_Н|x\w3 M~ktj6YeT:ir4 Sb܀{hE 7-3Jd'φ%y"%u8 NL0Di&PJVK ^R)¸XZ :<[AQ7B1&g]=F,=73BTU-BIlGIE<\ªlL9<.,2l]="ĴR#;9^hw>iƎntEBПyh=qxq~OTk)L% 9YDSwXw8jL,9WiLEe{Q7wF ;$f jtJ_+raȹJ iAAiuiDcZвgedzGԵ4#byݚ^NqG#r5}l!WIH~촊`{]*q?l<'bmH90K,tkaJfJ|Br^fB)? C=XO@/ABÕu]ZZBp4ZOCQt2hU p>YV&0־kpXVͦ6xGy(XLv)3Tn"Uq\E˾c.U$=-PRL=< PǦs 芣 +Е 8١ʷ}^ECU p&Jm{aoh1$X[h9rʦ;SM%w/ r൱זpN(ΞKj'BYhvZ˻2g}|=9%n5s xs53 0n`f"RVc7I+& _飏b{2GB ޻.CW:CN0`eM^ D;@[M⠋g_ CQ5 uk}@w:j$.h,^"}Rl}XT5WJt8j{B̔ҡNSSUB7M,OH |OiFn;IT!218[QXy=qF2 k/yM2Wt9ŻмIʟ"!CPLK~Էi/?q)rV,pX"iJm*~/591Uh0{#J9`ik>Tτ #y,̡wYBV%F={[.I&)߫FUhqZ㪮 >B4x7Ʃat {hK 3{I3˶kT *dN9̟ NK VR=xCd B;uo.ZTT5r0[stiFJ:Aeoeqw$jp·Pdhk5]J>YQ~ju+8Gz )_#TmwybqNs$T=K#!Q?-Z 1h"X\}r\ 5IWNpX@ޖ:.DL6η#t\X/t0!]#UE|%d?`JAX0Ey=á&kupۮK_M)~;_!v\8L3KZ">"HC*!^,!-7~CWx^bx Nv տsu5\Y)StGm廤_'OV“gSdlᰌ{m[PT1.<ϨIwlXHoA&MM8D*`^k~5xD8}HbNLe`"F|hهq)=_SY<DzKѵ 8eJ;QlPZ'&ygYQ04 zփ ]ԧ6mFd |hT~ 1cNCӘH;F9ȝ"}'\UBv+Qu~: ]zȒxPElyP@$_Z]ȵGZh>t?/6|qEvOKyz/ ܅Or(T{/=ς?[O[ 2lJƛRepsũE uHXx oBxߡ/'Ѷx-ٚ[PykdQ2B(g @O! ޜNKи^*x["=oƭR )z`X-5aՒi>XG kMG L`&di_ 9F&텥B TZ(;3ӑWũ6'VF3"wy4JuRjQF~}/#I0(ZO}27h?hjIfF=/TXfǙܫĔ5v !+Iő7AbV,A4_ +Y%iVTncqr$1z Y8 V#nSx5x5Ms|Uј m 3j3=?ZjYY5%Uljl "Gipurl"^D E[ax] q\U b ārf'g3R#B@C+M Cf^ *eN~沆OJ/T+A{IM>!а~MV/Pi{20Gw``0a>կH+%/iF3P:if³FhHKR٠d%5Pf|;Ś<)2-.8JȠVgNjT$cym CX<;/=&9uUAl΄e U20wwj?H^ ֔k-WH轛WvvLɉ6sI{_ E9vM,9ĖM!ض@wFn_PtR1^7q^F俚RD[&X u94A2]׳n-]ˬ2}箟a~YmrT2lqYFMkrD_s]^*WNG^ÒB&P8b/ <6~Mc>m56J@{N&OFNl⦆w3+{=WR K YIC+Y)~ 2: 9ۋK[ݣ"s-89h;.;HHxr; 32x9tھ>W)k$>(EI%Ch5%)w07bre5z33)O(sHm<$t(>;XQc0=aO Qɵ<5O $Њ^!?:ʳ® ݅Qb .L򖾛&a~V qot+"a*} v f9Z3D=tև"[ x. q o^bTPh%חlUѢCі o F>`< iD+;ŚीDj2n2 /^Aᆫœh2 -B;)\׿\Do'6\y}nfywfq+}ˮo٤O>"ȴN>*9P<|ru1߶0e4귊 4!c)R {Ǐ5Ry=8/$Ю O~j2O~l+.Lqb[`K0b}XHfЀ}ZXn2 Ŵ 0ō4hÍ^SB~F}RGk%+#oTau3]`fl7!ŴM# q=G!F4(@ 4~)94? *aRt%V|gvuv\١lsϦo~坧1[8pMuy9a鍩AªG|blCӃgY HLΛGOzOB}Ix./z-d9p&'С UXf6ҤF܄#:(?bI5eRRWCl {YZ~= ?`m0S,}DK6PnP4sxζ͘@4z:ַfޭkwvgoam:* yx.ZB#؂LsS3R/SV#'|@KV?s&2=:.WVo{{6='p͸iQ}f:iZUE UskflRxD.8Zhw*H.V\Y|ihvcV` #śH:KKl?!jBUcP[tdFieK&嶡G.E 3}ZePD,7!td$[ 'cyh̨ɫi=V-*aoxph;'k">-2 2Xg[ȬoX؞Ԫ(!Bh*`Jd];i[yq;ړlz_K$wP*iu#_P;jXm KIN.mGڨuC~iD!mY>Q߽oi3~'2PsL%0uwv)Iij֯*]NaD(RxkIO?5U .v8G|ӱ_rA2SQګTO5ނNȽU,3ȁ͟(ϙ?VCe[bDtWfrzAcP, -fU%޼GG?HO2#/}:N{Џ-xʚ_[J/Qs_Dz.=a8o X. }h@r(l244*7Wf2* "V\%,8:N"Y~KT`"7\iXvpsJ2f^ԧPvQg2iU.h9v E#%@Lg1 oSr_Y>Rj;FXA ,2(a'8\4.β{XD| 0@<r$ƟB2N͐V?]O1N~A:f1nG  oX7tﶠeUW*]>Y캱 AngjSif*_B(:4w2n{>N ~CD8O|0nJGt`ؘ\ ا-q._:;gk"r8?u4h3̮C9 iދE#VCGYdkmng=} Z%OXFdbWǦii@TMIMGJlJMoUwo]\gQ>bv2IN~c4t'QУz"ή_R&VH〛p#Zp0ޅX+q%m"@a{$SI 0oE-˪) 'FL!l+rLJkYe+0ٙ‡]μ؃U.m-}E8GO/e"@T3^#fyyߪk$LH|8{  1{5`-FT2gdv\fiH Fb}G޿'lrAڊ%)HŖџ- k`kfJaH 71}|L)n~j G%/wUpF[C* w*}%ɂI  _s7fUw9 !5bp/<~&B%zp m@p~L )Nl$ybff`2Z&s^-t06WG?w'yJ8;ܚ:t°)@]7 KeS}VIY }TY';.}+Mco}2y8p6+(FIwyk'9ՁBh?[uW53n66Y oɺ]놤ivs~EOS5Q6:sI.3i}_Ibci )5n<ظ%QZC8DA8FUY$*~9zξp9 _l> %.c7yBrU1]33 JnߑeU;@ vL~Jiљ+5K"oS/sL!Y  QNSѹ/]Nqb:0Y&,8Rs60[~/xʪ?jS79Xsf,`^9RD}|iVߌy/ k4`,9)_xVX)ÌI@p=bm ݺ-R~AuX Y@qf$~t`(h5 Bv盳Er"qzd3n5I﨩6;vtP kCED&菫À\goڀv݂UCmVO| ֤H:\SQz EIWn:!xiGs ˳Bmq f&hѻlOmٕ@Oאt1EÒ' " =gl/bT6˸ W?M&t>e/6 tR%g_6WdnO;×2\@ԫzqkt?Cs.ؘ"f7vtĪS'g'0[^IeSwt+wCtZ\S]JNic#}u 8L<{8t6DKQ͜z>)Ǝ2w:V=ϊ7V]?˻nwD3um]p@iD ]MxAm_m"\aϦ`^<3,;?f=W  $KC},Ѻ2fX}"[(_eXݗK mNJ\ XoAa3,H‰~?0j蒳d!|^_a2>:ڒhoak9zzxWy΅EˣMbx7lXdr6FZQd&Ygaݗ1KV/t+=\ká* b襉t\b>d+{kIdh"cטfiM:vZ&v}[W?`1-Vtؘl m]aɡIwQ+Ī'q"KzMĊ"F ,KUfռ2`a!!e4b J)e  a"L炢u}Wɡ'32? Z׊/γ14W؎z ɌMhC?`oA݊ÌvDwse'઺~'~3xw)*}l间RNJُloRI{Zѵz0z:+;ڨWf۪{ɜ_NVd:ҵ1fҍw\a(L$jִ ëEy 47ȋCNpϿɾ.EB7bx/ϹC_bn'>TSE"¬FTCN <&OھIaN䕉OSkCr$G`ػZMAb/p ~߬?4!@wY1aI ag$ͧ쏠ݮFT\x<;J.͇4-qaS)\ta>Tj{9:fa~-C>>,ti j׿ bk {="(uҡ}Fu!gSD $@P9 mli9'g`FY=-Xn]k1nc! >K6%uQS,VAX;UY&1.Zj@|O/ȼM)F&7]G!uFZ /%#' iSBfKYS]"]߇1&>˿ѵ}&;@H-qڜt}(\MY~A%Ig(ҫXGErXLL NZp:8͍jޯ;% Y{ Rw`N>z"X\ !X\N&p0î>Dlqڀ$5 SouF7 -W +h[IVqGX4y68\>ϣ̋9M"De ׶X- qqi M da*鞛FL{FE⡫#WT*N92" ق!f\j=eFٗhd,}*[ ^h~z(m)GS;ԯѵE2Qn*fKUUݡsvaAiI-!i1 `M]!M.;3'XOɪϡNV&a!+4qY~7O ydJ(Zoh|۱Dy`|({g(]Dٺw*o|:훀޻)f%W媮Y%u Gk5$zd5@w 2ے~:\3mZtHػeTUJqVNM5m=ۭx\q4$÷paN]:L  D*M=NM[:ϏiT/8C+d|p2O:ǁ Ey$!Ůĕ,~ 7g!Dx@H1o;K:T.q#M1֯3oGĜ:VyǀS2̚rO͟=b/Z oDǭh(j_Q6CN¥LE3cu`H$P0%3.sx3Mͱ-. ݖPUOĢ|g^oq~_ 0pRn{P(DfytY '_VB?J* 8~W uT0UUeaKj4㣹q/:+k^0=gsLQcq}؈{)O՞?$BwZ N=F9[uptv_wA%'˘G+Ʒζߦ5-jChĞ ^t>_//9[2#C6/weVR|mWp,)dmh G UwD"@uPnvSD䇁*WWa!cTlݛQ5xl3WI7ӗ%$0N,0S%Է07H>i\\@"c>t?xCn݌~%"S\;KTs^2Yn{t}#q9(|5x]WE6ZN'=:a+PNjq[z_63-J#a7%/9@λ-N&T_^Tb:n9h`FRQI/m!>e_8`bwރӺ_ gRHzXJnxUw,_Ch.*r9jUB^"S}E /*mH PIkNGSr*Ɋtn>WRH["~#gҘ 7 gMq,]oMP]z&?'uB=rG 4[Y$Z4?K$Q]76F\~l=/?Q];?~1OWհMrNoOBmC \eBHv2ew=7uGx *p.T橲] XtF"WXdzMմY?- bTF oaȇ s"/[ˈ:N[oКM\Tݎ1B#O^l`0첫Ƅpbv<"0P 꺫P1A_껔4s` qڭ} NM:NB ]@1, H‡D΁MsCqU~-ÈBkSGy Be!P :xF25Ȱu׏j~Α3W(SX5H{WyW?>G2hҩu2aio! x1)|@Viќ)o "khazaAb>jwpD#VeSށ']aWXe-ˇL^a61&uS=-@!A cgj^՟[ {OHgʺz<6&F6n+c3?_gj"U?zO9 NhO)iW%r |WWRٴ݅b;HN}֝Q$ْ $HJMl~,^elI )񚁱!`Xd,~jJL8:dtMB&IFNQܖOx s dv{Dn;!vUHZ2'z`q]%R4^?n,lY LW㧉vuxWl0׸;+h^ ipӣk1j>Υ)K-3͚e><~Ʌwie9>6"QFX\uwWdUkQ0,3 qˏp[a`жf[X|r!}6 yh t!-/:x'%DRA$0MY!. jvy+%W%rwKa*||G n, ދVL\=-č ꧁Wc$$a:< f/,U3GCN}UR$щhi5PwL<_U7f &ת̓%nwaN֫sr2%Edr-8WB"cު58H],.{ d3&YRITH`Hn"Ҥ_e᎘_^c~&kRĮrr"V_ b ogx'ү:fuRy>FqGB<2MᒛBϭp̤4$aݦTD-]̩bZWF_K&Bh*fzNJ:ѕ{G !B] \O:R͢&Y5n*jQ? WubYU`CBuIiӏd_ͳ}A1<\~z+GHYQHdYCM/C;@Sw2;ABpwP3*w2%s5eIUrVcrU NfiT;KS9l׼Z;Ӛ㉿¨|9D|3+:q\i} YI[pO39hnT0l@#$驨?fu=ʗRdJMq²sKJp{ښ"/Nd6ȃ"_5E1oZ$@&.瘧 q4U&z 5 \|(∉v_noC<**r)Ťxt_Xqr|;+3t"ko} 8LBASUOp0eKVb;ƺL` D҇+YoHe ouAbXjTw֟ GˀڭBޛ_E svW84T'sqjK ԺR 8{D-שGNAtTc,Jgu9a5%?zX )-@]m鰫vJ(жlIK˖ںM,IAd<ؙ}9 R*R\F?::`T/;R&xϨfL`^[V8 YȫsOIF:eꛭ=wLcqԋ_)},c*8ICbښUDžjd]5dlm["ZAU:^S8JBǂI}fW;.'}݈R a&Lp\gAH `;F6aFiVERlK" !_(PLt1E|EvtJ=AGU-|khHmŶ5 7%/& E!5Q Hyi QƵJdُ>54/g=uATC:{cыA6NZ +Ȭ[(H0bņtTdeťÌнvsnꘜ鵇th?q<|-8)KN\G,NX>A&ȟԔXcNПnʒĔ-T;wYs1]5SFo5>.NDbܬs+]Ew M&_Adl/ʖVo}wAi,߉H۴ M6{nU=^ePlF-<ݷ:>e:*' Qˈ}FN)/y ? 446Ho9R9$P_htberB h91r\atAžULUCvE)x`Y+ⲲJH솎YEX yzpob\cR&m9b&6d}L2PVϚ~Q?  ؘ+oTc:qa8QW<. FZ.Ow]_3"4"7~OU}V=y8Q<NU*YCڅ*r2-57bbxG.5S)Nӗ5>- ~⹄RPhDճD$xK_A\xsA۔[ǩ&W{a}y%ijlNЈE;T_?L7BdIvXyKB*ZvjuH}IfnxD@bPAxzW$mo O*{R&g]wN+~a%o' ^bצވb5,b-hlHӟO y,"ٴV;ӁSp4C||'2Z`c.UAv+hJ!Y$ʐٝ)5#+-xMա8Ddߊ@'8Ph pG| [=\pyTKKd] X}_:&9`Xq6BJUT׵≱6-R@֋Vq<{5R5rXK--ˆ鐅T,!&ۘݾkCj] vƿK;T%#dtJˊj.@jwzSJW#x  MP!2uBv5_t2a| \E1y1ǜG1Fsֲ{{cEC{5K;Ȋӎ\"MT[cE i&7dPfD?:/#Ҩ :roS pgJ׷)<)CE\r쨑 ÆڭVybvnteN}<8ɼK} ul3 nhg,\ m͢8v^ZF;'73 'X}Ee!u,z lYn٦Jeդkm G=`]q*b&f*B^#Ɔn"f:;oY$ybᗭݼc*|Iۈ}8۽,h x@gy~yzl'[Tsun@ B˿V/+dR(m;ԦX $>] K;w1':VƤC`;*jRz6o^k v-%¤9=3Mŕ*wo'7(uZ~kts~ʬ#R]6Qu$0:U3c>5@I|Tj( a@ eMZ W@Uk"}糴+^<~CB]n#u$Gif_=*5f)m39.L"ʿC]*.3WBd&^mm޿Ѱ`׊K*׹bi2ȡs.1CMIX"X % GW?vE~dYW:lYn%4=tHu\[WLRx>se:Nʖ28};d2u |6c3~Ѩw3qy*M큹]d'Mx]n#r] -U%G\"suB5RĨѴ@G TTZz7K拿mZB8[0udX#44& ֽ`*X=1fe.Iu(Boޑ]ܨH׷}|Hq.[9.BEܣR)1[ߩʶl?Nl;S*3[3ސ#׼rHmIUᄑ]O:cUzyӧ0:V2|Ө^cMsBt5 8ƔgRGp'eCt bw՜4S6z0ЕݑSt!}/HO۶mj%Z%kc1EG}Z9D'ڙ&TFCQRnCÀk>Hׅi|8/`wTT":93zCQ#kE6:轄|*AeK-N"<;1ZЬu%iAu%+CYc|é%8`<殇X+;Fa,Qiex$.O2e=^4g!pPD4fh2x`*qkn Yd 6ƎrDuukփTGV[4w[.i|Zl\A7мKtylaF~!jOGm?5#D}NllIdOm$H%aQ:"LwO 3$w:'̓8fݡ~X*{],ZMxoR~H ,nGHV.~/Q׾檇PkU>BY(q9KcuB;{֜y ,T h{qD_iRF~T?׃qŁvlE oY\n}XVَrN[ˁGNl[:0]pHhKR%kh K;5Š`E6d"@á撴ȩME!VÊbECxOx^1WƱ;^J>W81eZa< -9۪!bfT&@mGm$2`5$*%9{,MG Δ_՛sʦ7=` N+s47>DoѢ6lri21ij+d~jOcY#kEB轿~&ey媄njO!8zS?KƷhO{"@MWh * ԃM]7߆m|ׁO(P)i3]ï*I컼b᥃{KnPTdVY5ұMVb%yPk)ǸnH; }NC@ FA"I$Uzf*TcK6=ug .tkc29ݼptv$\쀗̹v_'䖱;-j{2 {BMwfIdW<ƥcR.|lpc-yQVe+ n@ H Fji]m95'd ǠBWiWk@.d#iꄅr'4mfnk%AO_!ɼHlS>[Of22NsOSݪ0:ƩF'jSQ?,MJ(<(n5vGPӱR21B=z2_pס|grCo+Ç54~,l*6דYG@U̕ &9MK.VFK^!wK|ROyݥnr"V[+'=xiDz M<ɞa/N|47NEs{ ]lrM\ &7̞ ,`u8$X(`a|GMI69/>dʢ€N8EO-D6M`fAP|"C]93!\-F zFVpP0*bJF\I]W%Ƒ{ v:&Q'{Iʒ3;q$6wӦJxwhnbYJ`PKԤ؈4_*E MǶ%lV~+jPeXҐk&µwX&k2~G} ·Bʳ!?aI z5bCPxؒd_-Sˆf4oap]9F+N x 30{ebE#"9|;ýIps3{S gSP {Ӷ{awQ\xAa'g$]>R%.T1q{\ZyX>fUC@:3Ad\D$&Ҵv%tJga'.匸NQA&TЮ1L7G"UxpPzBʛH:iu؞O~R_Z#oY]͈JwܦBg 0aAeff#؋,˕.rU'.^5J`]`D"'8-B4zo |}#f臿`ċ.."I;wى*M,n{=ݗiBjA {)ʔA?q +>)ARw Z-~׎0^zHGw \wث#;;&pR ~93H$!{B2 Hv9}g2=>Fkz1;|Μ kL>8?nŅ>f^pmE!^^xz"X(԰tST 0.2Up(\.N{TsSn4?(-5gHZtΨw#;U`OU{>N~^vdl_oH#yy:tBٻѓX$Fa)nAZM~m:fjeݮxX<Ҟn;_4̳|f̦foDH4† $鎤˦\7H[ɛ>)w0jFAel{جHV14w 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 cleartomark ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1707393948.0 reportlab-4.1.0/src/reportlab/fonts/cob_____.pfb0000664000175000017500000010525414561141634021217 0ustar00rptlabrptlab%!PS-AdobeFont-1.0: Courier-Bold 004.000 %%CreationDate: Wed Aug 26 16:51:37 1998 %%VMusage: 32181 39117 FontDirectory/Courier-Bold known{/Courier-Bold findfont dup /UniqueID known{dup /UniqueID get 44053 eq exch /FontType get 1 eq and}{pop false}ifelse {save true}{false}ifelse}{false}ifelse 11 dict begin /FontInfo 10 dict dup begin /version (004.000) readonly def /Notice (Copyright (c) 1989, 1990, 1991, 1993, 1996, 1997, 1998 Adobe Systems Incorporated. All Rights Reserved.) readonly def /FullName (Courier Bold) readonly def /FamilyName (Courier) readonly def /Weight (Bold) readonly def /isFixedPitch true def /ItalicAngle 0 def /UnderlinePosition -224 def /UnderlineThickness 52 def end readonly def /FontName /Courier-Bold def /Encoding StandardEncoding def /PaintType 0 def /FontType 1 def /FontMatrix [0.001 0 0 0.001 0 0] def /UniqueID 44053 def /FontBBox{-88 -249 697 811}readonly def currentdict end currentfile eexec Є]NDZDlbe6lZA={`o5o?M^."@\,-'[1Y҉5QW ((ߕmCijm\udtSrGݐĂb@uipqYc7{#޽s֌1sZcQ0H@٥(!8@ 3(vanQVz O /;j~Uz0D%7fHjh1REo(O`od'"%y) ?> k焮ww:[ڏtz> Z$ҷ6 qsK 3dN8yDU5r lW%]-1Qh>oX*G'!̋FFIiɧ2Bvyl# jfp^KL sS!&UUֻҎgijy]76~ ⺗T*L/.SV bۊM^}5>ϴ7|CDP)t<龩YeY˶^ζc̲8ׇ\]@clCoAtctsF94OھTH,A1NL75lAy<=~Ec;/.7.gWC[Mըt+T%W<ޝLg& VVF.ꇐjmә"|(Ԭ:40_<&O+"(b[}ca^`f)wvMC= qwFb 5Ѭe$?H#m^qۨ1#^I9544Ci. 2ySb̢Kםv{X=(;⯕<\"/hw#d%t:!?[?OT}Z܉&zMk@V.R^#~Yݑaaz6;ҩzf_󇽄ٰQ' ԃs͖D[ԦZ;+Uu|} ;~0"?~)!rOGȰt`H\j#PK }bN>$fLOaq( 3y&58PzUXfy0}@a ֆ}ba2_+~ fwvΟ,G{$flU;qɛy!;֕1dz-5r }+Cś?>*~9Ҵ N|4-a\P柠dd]Ր"~ (-2{c+Ҿp0ؠSd\sI{lf H^(i;;ߢ_J- Ewi%l% ^@Dcl]KhCc s~[XMF+EDL<X]¤欁E?K* ,G ! ()V̌+H&${eB:%e-oL5pNy~>{pH B21ſXqnjh=%&>G_ j` +>A}g㧯D̃yH+5>18?_1{wArT~UF lϒ]QG%C^tϩeAXgͼ(#>zhͫ0kUV5% G]=imI\.sA8 u5ql!RCL.k39]5Gdp< KDuQ|'4]n-=xإ{WqX"fjڛCB3Ο0ΚCٜWx~e/Ni3k dwf* np qaEw3y K ^|RTǥ /f2. b) ڇ{e5E+ٲ2~R{ńBF<u{n3 /3=,x=G=@J2TZxCn~q[cQOO9<:Yqn־Q)`'BW$tވޫ`Y8Z.dk4ᐙC nLr]]6oyI@?:heVB:X| 0fxp ^| dmosi, 0E _;Pp! _ aʀxV:IAՀAr̪o61EәU}#= t{7OԟKf>HKrb80Ȝrr*]w 7x ߲"d+ Ňi],/7iQj~6i%.%^|(8}I-|O;-M4lWEÇ'?`GFkZaz4",L,fM A;0@$y8)O='wi_XUv8Q7d%rO| V-#N CU=*Y}~?NxGP1WmJD))1n9s$Y<MFͮ(5YR# T!D|^hHVb{q@N1olVmG议LrmWQѽr:J?×򻴬⢶)L5W + Eގ%߳P)gF3HG }c}ۮ+Rˈka J[DwqQ>)s` 19 e=;֊v8wu [7wŸUHpc5,qh. ~Y6UPt1=*k AVf|Jѓ[N6ɬ-<+r:W]ᑰ?:Dl;Ovvii#8jl R"qWN*_|r5pη!=0W;ɳI#+--Y5ɈuHc18J߳on'76HS0% WFiϔfo-cF$ r ,5*C.D V^I"F`n6TU=W7u31 l5u3T!Ol4lJLMUU&.?Y27-.7 | <#FP5 7HlYm~>r[h^D2Uri̋J-e521 vيgi#__w€wb=0{!C?LJ6 bkl>9: ~А e7lvTE:ھ\ @H{6NtO.?[h'⾣Wj)')qQ}cAW 71|ה%Y|$'!pcuNgDh k|bhx<9g۰p#QSuMzMf,P$#.uw ̛\FE-9Tt?r`Rxk4@"v[ V٫rQ#*Q$DUÝ zzCx`yO/j5%B<쨕OǍ]jtsz sQ'U_ " !;Fb9M٩ZJHk;fpu뾒(xbSF0g7M:pjb]vv 4rjMkFe0~q*{5+4;v@b"a膒 m }_FahZjPkqb/X"R> xTCeKf7m'}ėH] '(Hb "׳k$pW;{NC2}'dF7w `fN2sd#U|`w/$V+5VŽMbOΪX7o9ԯ/xsL݋E"tOjWGS?S\ʪ@RZI\^ KuZ ݷx2vC\'|ɹFb͇~qfPmYD] ا=D߸넁1ǰO'rK 1hmGJv) f]hTe5E+΍BxJt*SaKh$I>Ub˕)8oNgPr xS>StS:u_Ƚο$C9~.5 cZ(ksL1ĒXaeseܝF?q%?_'URGغX,ڒc <xTKraI;0ntקx6UoYHΡ.aumeNw/0# jMkz9ؖh!)y8E偍`5yӒ*?u3}=.3[EIJVnMKΊ&>x !+J)(ÀY9 *PvaOz:֎>h7l!Ln.XLm*0'Oyϟsdtc}/U*v4-1|~$a:;T /z00MZh{CM,[5xA pQ0=.;'ITy^EpJ=ݲ@-`Yӭ{mk\"6nנ`/ξF,. IZؿ4y@ˬP,/Va8}1)(6!Z0}5{z;ǥF݇ a٩ZɼU:׻]Z IV8@!1 /{qSLܠ̊s)b*._ɵaq!qəf ˻䗧RKy^ K$c;$^3Kb4Z{3@֙q4G~?:!le_؀[^V~#%wZ*9w\v+ts(#1O}r;~ >(Y3kw-Ƶ .kR3nں`e 1EW`A5K\P!яU?(H*e$$Ll E{{av{mdX-{dNsz+@+$ajI@E{cc|5ePbܖFF<.xw|S&i8wY{kigmrer^l7FIB\W\A&E?SRl8GT>.Z6%8dӵ⼰2^ AZw󡥳𤊾)#I>h)N_A&բ [4n3C b uzKpJ\䠾+$ PvOHe*.,.:⟗"qabY6Bp.Vnb5*'qy)0qQċmֿ3k{z*3c[ҘK׏eضGֱ U^1T,@I k^ө?a=tG4l~ƀZV)pw,⮅D2B&W*}W;[NUZ "}0,n?zN(<=+>3Ƞ!r<Mo3 nsGIӽ45Z.h#0.3Ԛ[thnhKι|9 Iģ LT)~;%˕뢪1-Gӳw ufK0UU.[$1CdcjH w\]aN]%no0rĕ>٥G} _>l>U9:j4 ǥIZz@9ZDբTҾrQMǨd],|2)=A'3Heu3#{DD1TAf.ʦl`ȅgu6z}6 >5?z丁_ c&I33(+@r]Y2KJmwn9.xe^Uy84;&"܍}q:֏i$ZOs8 5?x&Ukk]5U:p+,;,殅_0W$Ez2|Is/7h&C N{߁?3zf@Vo!AM@5uf!L0c$b *wOV2Z\T# Pwiw|J 'ۢ1-tM94M[uı%E_Уvoxm^}!b蕦pQ PCV4ĻJx|MRxhv@Ziܳmi J蝍P,7Z*{+^Z-q}?MQ%?;&4+^ vj.yŸ12p\r2 )c\KU~UɛRgF}$ZH'*e#A/ x ӓl[pKaϖ{\` 0&1sV0,_ce'|Vrg}'J,ѮYi`>ۚ&q?.V:^]1p\ p5 Qx%!|(btFBeA=K4X`bu8 (pb'D nTYi{ ^#̼Fx. C44WA7dX:=uLO<_r!Ic=G ~~[=8!WL,/t~u.- <4d9g$:JUMuQʜjv9/CLy.;! =4qWN$)lK; {rEOuQꖼ.8/ wW&Q {.8 z"w6O'._"|c=l@S ''-dY I \=fj Ln O;TT q$l/_9.٦΀^ hw쀈n R𼫃7#k [|BΊ2FuE&ByFƊ|$]})>34)WK]'Uws7n}Y''1Hs1_kU^\9b|V'Z]ktLmH0RU֜X̻N/cg"[zThK5완aݗvpWikbTXЩ 9~y>oNW>N069~*<8sσN:_rO[uY/i(i3kYSI_sF/ЈOM&iioDȜrrR? bv 4]hO0 eJӰke!+2ߝ- C21kX2 qִ.(CTUIVU/u/?Ep%ix6"Nu:Tn_7 7 b3hw6*R|d7Tp~罪:Jk'83iY̰frʡO9V$n+]{eŕp A%4;+Eghe{|aFpOdx}@=z8kCavyiylkSaKUGsO9GH|1\ҝQ:T[ИyQ̓mW'I-{n)8#U'.Pxy[ͫ74]`>T}R6٘0/KyݧĴO/{l}2w.S}XavD(37偷#!t@ mnxT10-f[ӅD 7=iZGA8.:&TQlsL4]ǒg)^,ٰx10uQ#H;M5=~=He$@D׀2^1eg(œ:il4x**|1i/Q7ԉu 9\Ghp #(6B"hRr_cUJ a9u O5A|1,G]\Φj&ip ;ʘX5!C]zEhqYz6?(Q.25t0j/?@ |8|=ZutŇx{xn}' ۾4(+ 1wyv@{U3apC:= o;wp.2'wL  pOD(Ƞt0k8>:i٨y. TDkHMEn ,F 5 Jځ(a= > Qd^Cr.j\ef l/5gä_y3<ݚ MC۟\*M7> @?:On4!+nHI~dveOw 1Ď]Yus( SM }Co1bm`ƫHE(ۂG>uԌsZ.aV+]-͈?h*|@Z7={TmGJlPl rMfu'Zű()77CH]h`@GăK 'k(ϱJeq{Y>^f*#1w7Ǹ.[8- x/zº[K4or2268QaWioAe~8 E`w-4 xyPYBd 2}{4vMs|ڧ&]@ hіyxX(]3 ѦMK5w ~"A茢*ѽ3=5쪉qS+z]=$PEa8, oKW@Ȏ"Is-p&7Ζ Ag㢕6%G媈Р6JmrׇqU6AE3|BZ++" m[|o N۽$@-TV,VR7RBH]ųG9<7.D(P|[U˅Uw.,}Vc;u 1Ť^QDC<rfh#U$2YFx(s$y.XG@8-ڨ$q)P` R6۽cJ㛫(mut͸>_9iq,J^g!LܠiZ)!Lй5/(d!‘W; Ɛ<eR0ʦ!B̌ f|( ' 0:.3a2_RDcUdi"(nyqYE/Wi_#h?b>qq#Ƌ/ٖarщ%\>DblK*ON+KAgL_0s&pFqK+W):q@ a0 OWUvGy3ŕ=UmB!y.V/Z S' @H% 9@h],+Y4u: W Ic"Ujvz>\duu/7~MC^OzE ߌoKO/ˁ820yKf8rM yE.@V:? BOó74iu/ANa2РoX솎4<&r30Zt!/(EkVb+^;Jrxo<3l5W}(=}ja3thB~,2a`(uŚ䲝qm@RG<ר]+^Wa$̙)si?6lPoG,oq6;Tcis4Vò},>:.fu MFtzv 4XLKVCfSY!gK dr=wq^Ag7P#ވ^i-lVY(2xI+~xd +W՞e EdXl.| +[KkOHIR1:]qeLqvU}+<]hK1hi@H[̪.` 4{:l[E}"qU13uq²ᙯt2]DqM< AUEt;[=iܿm˧Zhڠ z 9wmOuPKeՅh 4Xt(cEr95CT+YÁϮ;wjG!ܰ7ڍ^/k{G68f"<tXK &אָ %o_O羕z1aQí=dx%A(NR%@[˂=5Hͮ$'=V{.9O̶%=Ň E\"ll=*~\7.9F3gr `MreePƝ_sM9A v]Cq>5'K(7(B#d6Rq9ӺFE@WĴH*t  b/,[Y՟1"R E!u5oxyL}ܘO3VBFBʶ[E}:[+RLS1@[cjM5op45)1EKk>8Dd6yBq&h!K(e @&uǐɈxz^ϩsHw]ǜā)id__aт̖_( h,Ɖ423y\hF m!zQ~z#%;)#1Oq7@J7 ?hu|N>pF#(֥ICr샘8DXi BZpj3_O:GIxZ~Pbs 0>sv(x|ammٽ`5>$~ף̗[m0r=h6NY9ȃxUP[Vܐq@F>ׄ Q Knɐy49O8яV7*H N2-ևòS ?wv},$%tbQ/Dx1[+pJɱE'ZG*0'8.=NEe ٍ G9|Dm-DthWb - !6r /@(c$~K'fĭGlOvY0'$Sڑ@;6D Q JM8J_X HS |hh Ś^x: NٙzeH;.6J[33;^{ǻvJ/r+IL iBj:? v!%G^CKv¾E]+;b?ZxEuf0e t!)j-먖PbN璳A3zO1S.A^W/ᓡ")Xۄ{ƔAP39Ͻ 5p X`w]f>jB0{ " m~/a5G}Be +QcBB52B)R>J5 eECH#)ϰka*E>}@қ5-e`:펀25$/|7s21nuHz ?LX'c޵1V| i>-h˔ xt&)OFG&4,SvZW(xÌ1D1gԂ|뙰@UDh"fK%׆eQj0MiW|9JaJߵ#FJ:`\͚=TC#R0q0hQm(X0CM@%WM`NVF/Z51) fms"TSwS־ G>lV7$'c,_'Yt¯ie?̢0{FNlbB1|J8~Ω"y 6OtAP".󕐮ƎH1=U'cR/|u =UIW=VtugN﷢3 KU$ɢklv X侍RkHoMpvJd)Q9s5n&CmQyн꺃6N19  oQ@8GjݧCR 6Qo<j\5 ʥ>G^VedߥY&xC V`㏘6z5^Jq?/hN=gɖ#cgߺϫ4@Ka s#8MZ'W{a j-UI" ѾЇe~=O;Sִa?t;vw On6L\B֘Z?tQB>0ZLI{\vUO&> 3zDŽ~]6 r9vm(O0؎ْL7C P syljܥ澖 Ge)o: ~Ycԝ:q*IT?Q_y]N=yCa_8ިB zrK˿\nBªGd'zp?x(ffz}N~:mXVfP?]eos1KD[QK&_h\zAhK+R鈈l?Y-,8Vk $׮fP Ē{%9°LޣڿIJr>SYGT7CkOw b,E82C_]&SiSsGg*$?0V7.=C Qe΍fD(60`V$qb\#IshFNhŃbU;k ;./,u{{GqNBwf1SI;ӐyiFTu#D"j5\fS<>KoʱdVΥZhz8xbr~oq9%?opn>,yZ9ڡuӑș|_G)q|Ο=9 (~P È3"]NJB:!<|{>r@2 &Ϙpuu) 3$0{o\*hf!ꥐp-e̞[VmpSL+ f8F΍.fg-Y͟p]=g]kK5T) =n_4HN}֔.еhTE/v-b'Wyv(*Lj6XfAbIM%f[{oUdJd 6U7*þȕNNNF.$s]д=$O5 DbYcp6ĵl 7Ye ':V+E2 EP]+2G~Y0!EXlzעEfI> {D^QkS)ËQrQxv5iO6`NժpP hX;9[[V=k]60Hi7;sp6[>ݍJ;&ς ,ڐ+P|*~"FB5SA.w i}$F|SUL ":: 2 .HzXum 2F:(X>;^!3Iff Ϝ ` ./X-Ks#6"Q$3F?DIEVi m”<$p>%lHQ,>շ qRQF'pz(1`yy@7Z*3ݎAVApa9$:ڤLhNw"Nq \Ipً!M]\Y3]_p ZPykߩ}4dI!>C L_bR{HA-‚{k,+\_er{ Ŀw"\8`:2"_o(yJ[#e\ ~$9S܂ׄXxĥ(IDcqrjf)ثcПU+#v-Fyh[`3[^yM3nM)aq}‹RqPQiBZ=CsJ kr(is~aH>nFң=tzK%r!i  *n1cmg)iQ2v[z -pGO6O-,4ހBS'uDZ')GSTQR 3 E j?G놪 P݈$7N$D]\qe:̕3J(^@_Bs2k!ٿ=8^*K@b`UXnV:Y8ξu Zc/JA 5tYlnԸݸ@'_b-?7@8 =&)E<QQmgRY\էN`(luhh:pW<:,Sjɰ1DmPL#2!¥+L/G4DPkN(=Z*:7 qUF 0)T~?)̪mc N݊r@[C N_,#Kuvٟ!iTG)ɡĴ(P6^-nJ#5TەEMz \E(A D}osmQ<"QW\Ll tj!h.$Ũ6uEeƝp?jrf pV ߤ˼0`Upɪq g<5@rٱ.bbqKe9s\/3tK+JM1#t`s)aznKfPS &_/*5Bؙ9V5ubh 9p_8 +->ʴUZ@Hj eEs+3vcw";kkxWm;ʱzB`6r=1~\ 2Kq.v"A(y1csId}KyqNqj]1QeuGISiv0#kuq\R2`>VkrAF7R,bG 7:C_YvYpz! ǫq{@ Xԅas|0=e8{{Xlri6> pfjwXa=rn#4(`m~⋆XiY@ً;IVq3D5ńxF\m|5)&HWkUyAk(ثxq;[Nک(JqsOs&hA1?%p^~ZgFe;i3.K )ZO$o&ĵqV{,z-'bݶen; l 5;+8x/&0K'ZOF]B99$w &;LQw_ KԘJY,=bz}kz]iTMGCe^;:9 ǩd4v Q57F |-9,9|S9yʜSV~uا<]S 埛" s,OJctV+?}]R}h1Yj|6wrډ=¡;<*{w&u+1Ad;ǫN\ptA\2ZcX-3P7|t+ @˺jP/܅? ҼТր g oosq:T .t? FBlώj[Is|εNq%@L?bUc$ 4 siФ`u7-\-o~3<$YQDƍ2٪|Ny׍t2X CUs>3@,,zzV\\pN"jW-5 bF kv6@C&W䠥9܂qϗ 314yTawm(@A",*d8TO{ᩚ͓/s+*C#~C֡C,eUn=[LmLvUrV⹈;c.I*9"|$NLչ[5\c d3G `#.2vqÝY+("P$ ]ކm_RWOmd,J2q.%L{Ip*B2DB@<Ngq>es%6)hكP9fՓ:ѲY~0~_U!C|ѧCxq+Z(}xmjrHb-KOKdTU1 D2Q!OGORqs:Vn0Wi#O~Vc;7RM3H 1 *%Mu 3bV=Ӹk7xEȗ@*l4YcTT?̹iƵʐ5A;2*`aսRƒ&NL߄\}AQwY"`8l[!+ ]Gy)W΂Nklpx}I+!djS^:KcY| Sob81R9/U$Ka5;qu̥QD֩0cUh/Pz%{ۉYm6 VbR6S$*8y8OKS7i:(+Jbq3,XKuRDgT `s{ZD(%ygIhg򇸪ڥ WE=`grΦfk&d[j7 [mN✱X;s_JJ3C)#N1{5vKV:ǯjOKDtSGu6 ͚ ȥ[8[,ԶQ)'a\í .{;\˘tk#/G|]R uLxpXRM5ȡ~pQi>h yɩ8I !Kz\NQ26rNΚ0="*W:*[%l7d<Jb7^3 ";tH@/Pܬ{EBi2L=R4CX;^ujd{G @.w L*W%>/L 5DCFB>.%BpRw:g۔Ix,A'9JwLDd`GwR:u97(kӌp&!sGy/5悴9SV*=`SM=g`]tx~@tN]οKFHY/'ߌuK9#,aA?Tq좈W#QJ5MWk[o:yB5 =I@Ko"?lm AS|7e;υD#H2%xʾ叾4B 5gOaJ'<&- x3rL:'m7s)8u%:5{+l,ʥۻV`꣸b b-.]ZeTRBybh=wA{I`'Svw'otJx/%A^3|Юr1x;pBK:PpCz!ō! FE6 1U9{irV.}vF5:SYv[CС6o~zwn-4EԻ:tIK^X%(߽s"Ug &ZI&*cn^F9G:~[!{m׿/ xa+bH¨EyRM+\cyˆ570f]\gG;QSm~G]awI GҋN@ Ƃ$3W7 m7Qlb=AI _lP  J.!ޚC%zT0m)_'qC+.oGNrY,:  ĚG ,yhҼ~xY}WEG*r!6'DXT'u9UˤJZeDZJ,“kߒ a:TQbW1!_y•형0j/ncfC&4VoB# mg [`̀[HfoH`C+ D/6/8u/1ЋTT\9gLOͿ*s?ξ"<_GxX:6 (Q-=A h&+xBm{iTӿ[M 4 ɲg{aWhZ!75ew]hǛlg!nuFk!5܋p|>inXmo|:t CBLl\iN7X=ˊE}+űjQntOOF 6*FY@>nٱY7Yz;%];+<bk ')X dسesU|S)]ho>PV=T<kڍWbvXPr4CM66ĺOSmn֢ij'IqWK8B^䙩AB]y5/< M^!>TWqJ-7!JzVhlEmO/KqS?s>EXfY޹Ͽp;]iRt-' %KzJԒa~qŊV%G%jД )=ŦV:ji50cmdpÔ*Э;hX,):&;".\0,l[ln*r;VO^{͇M|3h a;QHD|Pf0=Y:vW\^m@x"k ~6UE58],yFZxg dlx6[7A)o]F(='0ATaŎL]-OuB[05CS >Ob `0s8vi畝MWv;(:˥ [S *o8|PH-*YCƕB=zbOZ C1POFhM8X"UMHj(y0fuv};^9WYaԡxmxH緎uqz-#jeHz=AL%`{1Se*jؔ!8^TN+bTM5vA",j;[dGD1x.nHS(Lm4^7ˍyd\"hN0( ?\UA;JGCi^:ٴCnA^=Cټtg[H m깤4l _I]qf3BD#C)JgȟN:1g1pLVxZ|N7HE̐JVtȣJ|Ώ_v&s96рk +&=:&6ߵo'1<[N#,, (i;/o ǰIFWҷt |ԓЊtIϊ ^bLꮆeOY *ϛ!`Eh|,.%f笄"p'BrLyV2&~Jq9r{K":[/&蠂Gnb4܋RUJ7d@?+&S}b҉$݇zf`Ϥ(\ݷj}VU':I: en(/d,y[%18)2f4 \ǧr)wOq7@JxȑwZv}xՙz֍9V }K s^c\p0[>R,ыG 9mvW,|0u4禲, ":EeݨHow _/R!RPKR\[ GƆpcؑJZvgj*ƭ=6zqټ(UuR%ꡙOJ6BM /Oj`(t$Wew\|u"V1Xw A7mlhѢ⌞q +MyS ^DAբ< !N;! m!܅¸}ȻuTxDOS,?!u'ٸ6iɟ Fi G7;҅h)l\*+kOx( 3΢FdI.rقO e3VԔetgN`Zi6Q _QPi ^OpeЀ3v'?? ,yEhxǵx z4&΍XɆncWKvx8hJs/}įJJUm>R[Щ؆$!GXe\BKO W=JB/~Y@'95n=޷[vḲBr'boi_szI_f?I5E,iqd*S[wj|43-g2ߑDg5Js^}zE,>伬$٧[AVO^&ͥ5/wC]g5>*m1|)HOT9vbY)+Jo 6d[y֕.1 ֯o9#6Uj0w !cT*`啩hg.v=+)O SCO1]S xCa}݄ vS'BzB{P2rшty<4(SfXhAKg(Ec2O VFw$Tà!^"Zx0aF|JY߼pN#wȈ40ۀ\5Pey˽X?zyZo@p$1UotwJ7XnQ tS׏eSگ?4>c$[;]=(hڌn˘݁WAcO'ME ]ǂs';V + ]!xݩ Hh ]sPSlVCt*6/:GLb%U3ڹ!>λr"Օj?c q+uRk3/=iI!n=Tѝ oﬧ:}O)JgR[^&P_IIX4<Շk-%-$2~;e`'4+EL<'T_/ćКfY}ԄYu v/L=^+qev+pW@ZY+- 'wQH=w#zk fmH9;`&Wz3 gnbygUd.)6_]af"R`˚^ H_=|H❥<čp)KB(y9%,%X)6.hj:QBrĶNL-=oKm9~S[ &Buznۥ $s _N_G9O![O6L8$٭h/rz?P2W^1EhD4tr@9ɰ`Gl(5ۨ2.a$$,4gCo.Smvхo%- ERc7>cxɦuK;sLWe#kLU.#@(oq![lq+X%os[ 7!h56mul܂6:1 X UcBkY4/ysaԣh ͻs/Hcb$c@hT[@,0Pi>r&i{'ؗ z ;\cWgq4R){iu9"up:s].2ހ,ctS,?!Tce`gɇ|yE.I^XhGUP^Z-q޼4&CEIBds V(CO2:'_q~鳴j\ RuyGĿJ=#X*%2xu>^w+>5J*p(T`k{@(>7Ďu|bXrudT~cqwy$$i8Vog~ ؊~ku_Tn&Ӭe|W}nw(~1UH<3nNջ6Q0ہHX lfwfXn_`,q>DYLv=i&'B-`S{ ^80UwV8miGudEatMsn\v;഻$TU"r*HbL]ssEiU❭Q1S*9%[<̀;r|2}6.ͣ%:Tbc3͹ICZe"g_5l٘SEa&Л<]1glY+x!ʹ#0hԛ#ONuIw]:Eq5*`9Z:p_Ic % _[Ս5۟$1Ԥ Z?T`.w7ocuː6JQUCr#pyl)i|%dXmaA;4ڌ25ي3C pZmk8m>Jў{2Qs)PJ.s[Z@=\ׯp׸_ҧEH7 NMKyG!T5Nޮw:~GbBG1)_7^YKa:BdF_}0YaTS,v=css.\3Ә=(G/"?!>sO:dX C F Uz>"lvQU:ˏvk_:">Qbs@B"2Qܗ!SE~ԧ^}շQP{aQgFmH=q'D-lp9@2$pm7Min]A p- %k,w3vbv ]y-hY=>yq壾Z XkS2\\ZGal:8aC(=r Hk+3\480rprqX-{=fKA1[r{_%eOZW>a-|4᰺v?r`Ck*ҍXK7PUL#܎s]Sqqq &bZ@M ҰCt\gܐqwғP.m v锯31?Z8Gwd+;]`DF*2%GoļPDlDž$=6tȁq{ { VOu06; 0T3%˹B.k˷A4S-'p{'Kn*n^"DTѪGn,sܪvMt.iXǓk")u͎(;D0B=і7-'($'9 R[|>m>]iȺKZG!Fzv˅H m#@O>dɖ?i0a.Gפp̴@A5 uLyLBy5MWkEa5aLFn[:+S/#m@ ᵃM],5ڽRu0z&>V]I!kN;/ vyU(;]&? oTZZ`5cft7yU T~oՙM*4f*,bcĶZTR ZRRAG!=;''GBHbm7#iYXPqHa&e~!gZ;Ytn92mdi /,$#'?8M蠰sp`q R0v"ko{q !WT.qP7O@+;MQyRnroO?lLy$3;ld^1$n}跍|Ƴ@Znu}Z'XK,v OHkeQ[b!,uy Wת LVm_pSJy0yE"r*WFc0ZqydL Z:pǨ7'{G8 Mu`=|RIZcTa[wpD4(|jT7) D ua̿xRe3]sr:F(KVu?c7C`8+3מ+Ta0G*Qw0H99,kG4G~EqjWH#pQS?!t񧠰+.q22 {/֞ 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 cleartomark {restore}if ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1707393948.0 reportlab-4.1.0/src/reportlab/fonts/cobo____.pfb0000664000175000017500000014254414561141634021242 0ustar00rptlabrptlab%!PS-AdobeFont-1.0: Courier-BoldOblique 004.000 %%CreationDate: Wed Aug 26 16:53:04 1998 %%VMusage: 11931 56737 11 dict begin /FontInfo 10 dict dup begin /version (004.000) readonly def /Notice (Copyright (c) 1989, 1990, 1991, 1993, 1996, 1997, 1998 Adobe Systems Incorporated. All Rights Reserved.) readonly def /FullName (Courier Bold Oblique) readonly def /FamilyName (Courier) readonly def /Weight (Bold) readonly def /isFixedPitch true def /ItalicAngle -11 def /UnderlinePosition -224 def /UnderlineThickness 52 def end readonly def /FontName /Courier-BoldOblique def /Encoding StandardEncoding def /PaintType 0 def /FontType 1 def /FontMatrix [0.001000 0 0.19438E-3 0.001 0 0] def /UniqueID 44055 def /FontBBox{-88 -249 697 811}readonly def currentdict end currentfile eexec -JGA>U#T.7r2F>8B~Z?[tH@E|Z_Nn!9eN2lu áqeV4 -]Z;:''oI/<ɮ ^G$+N[ƨ۪ͪ)N|1aE_23= }pHmMkCXh1(pш7Gnט6ɮlOu6bꕎ]Fx Zg] jAЁ>H냃){:o Ngw4u1Nmu".6Nv%zw[0<5|6zoqm~Ba2-Jadw<qՄh?jP'田i"08iz* rtC#aQ1N2b쩨V;^yL;M9[m D#Q.ko6'X>f@uZSҡS`6Fs]BB? sNW2mL dB-5TLiEU2.(վkPGc]V~6Q^ét<ƭ:vi=sfN i›QY@>9O_@J)Of!1a)oLtR7lDMK \p晙P>\a ,O1R|M!WM@ߒ-jU͐VɌ %{NERpYZֆP:l6LI -M~A@KKq$ODT۞i$d=|x7B/b>OU,HfWWϔkB\D}F$tWn\&di`[.+R{ ꡑ|h_(kӑ]^ 3 &9El 9l;cd;#V?8>#΀Y!{.3rh'I.zҜy@-!D c{ՙCEzk~XOT/.Y^2e+2(9|P]i-@hnV~XӨn}Q.u-zQ"[cb/&Vc3xz^3(g)fDYp`d+*FRM@#6O8/>0~KgAngd+]1ߎ1|l h" AIvG}yHUNBaTS:1 Vzc4OkƹKYbQG\d@D L l7s#װ ԫ%t V`TA϶+A%hfrm<+>bA%p}^F{EW!h}:% @S`cF?2w#?p>ڙ&B#Cľo'L&ο 2|{2HncF :}Jm%ŀ&m H-3YD:P_I(Re㚛Oj/rVeZ8X֡p'~sðIpF,jru{Ft\Bd!dn7 qrDM9!μzo HOyr=)9MBwdTl.bz8 xkjSν j ЮbqƨƳw9BӦZFlhQ! SBtĈՐ*8ʰqP o.NѼ~Nz}2zelԯ碻F;.=F:Rjp;RzS[aNHVH:n݇m#/X8rTHG-j{lEu6z-0`&m>Rڔ]%Q1;8]jGܭَCY>)NOlkZS}Mq4l&}o\::jVkbRh}[%Ce0 iC; ](PFƕ^zTTQGsӣXHCwl7ntWZjR#l8U@mnPzS&nZ)|T“=2\ȅKGz>fwC]EXixM*(_3"&}()j;Àq@qqzƠh * 5 1:G'*$ܩcc59Rva"aXm9~(Pi;t>]w>)06aoS 5\?@mXi 4/ ‹ɜwn_`n?s"{~ VyLMۻ&/gGH_HZ&.hgg 6 @PB|&=[ ^.I,Ŏjw%y"aDěOFXJ ’]jZ""{+N Wŗj4#e${gOZa% Anj HzbZ[ FjLI^>rhSR1_viR}`-!"i Ֆ~"C`ixoH6@#E}%.7kPR\؋g0ccy=YF!UrSc +u- 2̧5Bk\\iX?&w`v$ د a)," Iײ&E~Q -•4 ^BԏE7+b!cDYΨ^C=l쮃i),}f-+a ۭ2) >NY.gc2agL6&?֋U>ב`P*¶* cct>z,Oa2{zw'IEtUmVTUazW\,5^ `/CQ%K(&7tOgL8DjhpB?01rI ,I+N-؁R5Cy2ۂt;I9etOjW}~nA`YI), 1qӅ>"='vcnOt_ӸJe&tf %h^˃2IVhRT1qOKS~ s3R5F|uG El I m{U+E|=9&@*`P(?i3:4`M$$5ԪpsF33k6WྐྵDd~/ +gE 8@_YܠUIPIBtNr,TLf1|ڞ >9p*(WgG5qюT1X+0-MAx'J=K-BQ!]烠>2 aL~\'X[5t(<\~ .Șrt49hh>Lr@"P_$ڌpOܜpZ|y)S Pl40/0SҬ'!k#lC:|RBn$p +g:G'~k3[$<2~Xƶ>dW4"EΞVv"8ŤvUJaԀYMF E1k|V\re-V},(io>#? dOD¯#+s0cNqEƍhqGF%^6s\q;lm3O KJl`vh- (U-FW:1dzo)RF a}d85$*Z%YC7,iոUt,Q@G&;Ԯ67a&oedW91qCnovCb1J*qC+ p db)HVdM|6 ]Ƀyq,L1Ro9]]Xmҳ\B|v/M] °xnRoYVg{N@Xm܉ײb< Zt&*~LҝW:Ǎ㔨/nG:(ƳǛѐB^ V.>wqKb)O0Ixwy7nꁷhPw5X5#3}EKP79`\m?Β%)K^A_ղ-M `z9j`$>QNMpGFMmbMpPA.BJ9<U %8^(z9oJkrDc۔"EVۏ]n#Fh:jC܌"IM\eYBI_4 ?,5/}Xa11v̓sNc5feR]Ze*uuJ{'{X|' 2[U 5/~0Bh{"}D^飵b0) 1Ņ.e5-#ʼn ݿт2s`ƈ}Jxav=GkSedc1qh5[[O0>鋊cJ㛫D ErRLa:9D}ǟ;vС!\D[J\㹍 Ǥg=„b*~1°ӿn:;@60&>]C N:acnk| !FWW燸 Ueed5E^%hh,4$`?_eL0l,1fTlELU[Oam+S \MyR&.x^'r鬰tQP7I¤#dn ^.R$ Hrѷ8= >,H CA[+?Ҿn~0elu4wrh\YJt@ NӺX bz47?/:O *|UU*g;֔ޢ`_U5?<ъOiZmp/8Q5ȧNW}0.Hs'ZrlAw(m6z{,S#EϠd(bP>wAs8!p9St\j ;`nha3X~ffA@ a8R>+# Q2!Q g .םQ/C x3ѯlZn}[1@= >3HE^TW`NM{{p?1IN]UO=;^]gxFap"h {5(VgNKX!e,bf iҙmMy$ ."  2O,wUfNer`_rʂ8};}&z@:䲬{MiO;j=j2}hx1?hpOآŹuRhafΕ7y(4)@I+fB)igwm]śwޞ]g|`1*Rj`GlNZۑcN^)W_GEq{>'OVVKv ӹ闄ii` GU3ͯUZ,dML-_ύݣYd;gߏzqz :`k3;>=2', AZKaϼcP, ~IU ~Vp7WFn&tB(Z|"mx>ix_zCkOaao;U6"@RJKI^ܻDo) JO9 ĈeJoĬB\ew}<{y6spFS I V XjW9IGK1zWu}7ġkZH´)5 -Am89_͉ o,-懗3PUsz;e79/Io;O'p~]R4(TAe0\ZìG\\gy#TyC}Ze|×qiyP(%WyzԮ0XfuʮDnX6ś !(>t N0k"͖)YO*`F?mjsNȏ=KQWlD=?|`jx~M}S ZS?Z2Ihٯ{7`Ï1IU齒˄hMyP(YXh5nbej.\'5)Mt3@todyʣP=w+#LKx4 w|ʙ"Nf)Olщri|jpU7Ͻߢ] ~F&DΩ(+|^/wu"u6=.B-i߂1ZXDbX8jw&*V* q6T,?Ed包͹o_tk]ODϨ&6 JEPZY>s؄} 5J6,SK/6y+" K>F"lE3vV\ ـXUE4/kҐZ)pBxЭF3xa&Idx:1GNF ஆ=X^̢<I"fweR;9,Z&k?\Ź<JPG qgnKAH^Oi+&Cf*^r{!R[ׯW2r{z)ԑt DP`4Hby CÖC5\(A@Ԛaz.SۗAzC T3VxY ipg7FA/<2.(^[#i. TzCǽvC.l g *Syǚu2S Y$ĕ:?IFٌ* 1HFғ*"C+q/h|EYGQJnbitz!8Z,zp0-@GXԨDЖ:"wsЦ'3٠ oH֯xB=kW2QaWx9/eu:b4Y]܉xV;j-|!&f<7#Yb6t|&oC^WNB_ ^RUMl+96=P{~Ѐ%sars_דxv,!+6Gz%p-4,ТQai h"pUKYHq*|B"|D ,\F wsN'V#b(`wq<rD,V٦A7d LfCAz4`˨~PJ76=MSFIⰖ[v7?yh C;="hi_  uj0 E%|0H;zj+T|ZReTcnG) kPɴ^Up]$|S[ׅNB[_!Vo6vP":UmV-A"SP\lhdsy :'rh!pcr:R& ){< åm !"ѿK Xb?u*[^ HQbG`ݻm4q!kVDÇ, 3A4%=] ߎN 9*.v .k~\,@7ey4+Rq|vK&֍[me%{p 33}]ֽqH:WN 隞rvgP{B.3°3!no|V:d~W9{5:НAJ8 AR%4EJhՃsV|b0ow[M@tP J&jCV,P(錛6)ί¹EK,y~U79КhD}Y7_׵6 XA8IŪh.e:qYQ<\\GK" ᒯƐ9eX< jeʃwb{M,wJ?67r:¦8Ҥm NzY+}`(1oJ-g#R9aRv޹^zd'_An8gSM^WZP {dv^D Y߲X*c!1~AMwFIYMmv`e߱/h ^cr- XfGƕe;6{(%y*l Z6 Mt,Hr1#^c\pׅl@_r6i: d!&vq-CEA*4ڮvċL8R& *( 0oɀY}zS2K;+Ib#1O\pLK`AW,Š߶PAC;Y$rb2&Cq%V|h[G,(TTdCWuʠpxsU*NsGh{K%~w |R6و:nʡhaZ71pݟ:NPfT(be 4a{RBNɤcoCFk}x^=-imdOrP䏈f.+pl 2gbs6,9 TTsgďrIQ㧘]e=W_]&%s%~;l>zbJbf OD5kj)l/qJYȈ(Qs'yTwm9!']ôi;)9nSG9{Ȫ=X1ش`օa('[ir>R|?3DF,m!b D m!'|sZs8ial6QpPoǟ,QB6ۻ-Sk N5.;W5BWSQ΢P&KxЗc{5Pͳ 껕D,?SUh]r#'v[v<7>`!Z]Cw+FZM-!_86yTJ4A;oH`PNf|J֎C!ez,7/JWq${VQe %hDV<Xh~KZd+8x9 @༩Г jV׫x N ݂7r윂wt0GM8W_Y*EB=2>&FmMN|_b\j-5uƁz2M왬rY5HIm&r ߂DTѪP^ECKw\M\zAdXG˴_pY\`7өh|Pe]kFD0sOZ 9ż'bFn޵=cBnEmhE3z~p |U[(ǰuHaɳSC47ƒ4uۏ{ Nn;Ќܞ#Am暙Dt?ˑM%ҚO>Y32UVucА;*XDܲ)ꚲ$m_hn˂dKno ,D8Uk%t47lj-i֯   _ܙ>*._RbA6Gs埣՛r` 9r͗#m$51{wܶHWL*1A߁f -ˌmAMŹs,BaF kcJ6Z~+^cV,:'yZu+{5.*+3G]B+5 y^LvQD*-yw+=f/JZ4BujN.@}Dƅp^=>Q9?ic5F!ӷPU`8cogZ)c8IC59AV"ՓA*4Q>gvLg?`DFlN~B_pKz}iV[BЇy!1'f&Ӛ4Jo(#@fG=LF1٣ ?e2 2dqtBv [rH,4E0{ҲЦ|KO-B>0jVҥg|o..JK47IgHkALxI%pԍSA&_8a4}+\8Y' g^D8@ySS09XQUZWVc4"2R>}㭨4-9ʶmQoBEG_W@cr7e(_{iCQ 1rx3C廸 1>ܺP/qp0EZz0o)4#bYIOAmIs1j#Mk iR4i?*mlP97Wn_M\)a Fډ^ԎNp2I-W]R=)F)z97dzL‰Brs%n[3YO); q<71@<8gfjʟ) S_~ZWx)mP%հ:;(F⬹6UrzѠ|RJϧK@`ϰ"7gGR&隶-6O *m5 x>.k'"΀+`&i^Z9/ "cIY@k@~e> DJO|m)֭<"2ka%}di9Nd!}y~,11à 0Ϊ|$ܮz벓b H s>?5x<<3"){!لz\~ed$aU̘ /;(Ģ2-^TTcky١P%4 EO΅ձ7#~1o)R&u 8|dՆmN -!!$&OU+;JF1< y[ ^%:^jC ;>ٞ_Mnbdފм;7'ygX  (4ʈ`aӳ i … #9Luoc.@u(4}S摴6HT*0Ksq;wҭHQ,Ȅzx*1owNA8S7<~Cmy#U Z05|4eD3Q׸˯ґiM*.ޟuOo$:c ehF-hF<-CIq!/1(v [c3h!S7J/M>S0Z4g n| ^}\t5׏çx 65^K9hEewQFYYM+cTl{VcV^iݿq '&6f+Se4D@;0dh&RJg+8 Y6 * ݪ-YݴRWX[ .HpRN֧&OA4puPZW=;\JH۽ Os!*rSٸ} Ld.r82R?PqU'FhLj#ı\㬏as&j6f<{utU{kJ!cBeqY|Rj20T8Sw,@PTٛB\E38Ɗ{v$dhX,!{Wn[!Zx= -{5yXcظor5b`gEݨ(Wu Qq.BB'ЊGDTӼMH>gJaQ!1s+sgKNPjs-=#dsgs˜T“>[9}/oFa0EF~lUm'a;\{VOyֹ|c?i&S|*ƭ@8yl/P+N:ƆcDMTnӇOw~CdHc`/AO,-ן֛! d[Ru_ mlE{~Ķ5dV\Kꭉs(ϝ6Vp# `*a*)^TA8aD2fQY_59+I1l J(2+: A\W{nKjh='6ӥB/I8V%榵˗K{C+wjf[rܠ-sX?|d# /[Δb1oYuCvM70xg֜XF<ͻԗ|ԓX)چ3D{.ݱ#a0s^bݫ&Y7ױ|p*ko]pv(沮7O[2? S :wa':R0"~_s4P|'3J*pwc-S!8q(KQ<үD"BᅜӀcʶBLBUd %:uFNkk ^/+D$qpiOͼҌz϶hGf4Vo,b99C/v"9:Z[gcvbergR'eXs>gj>zOĦubͰ2ar6JNl%m(Sk QĿHIO蹯Q^A0K`Dp@TM2t(Il x `{3Z{3@g+ė2m_\dV?rpRjLr.Xyp3&(f*!^;!1IDuM&- / ڕ 4.MT[|-dh = 䒪مv$ Z.P@9%w̯6+2|KW} ~#h{D!YuI84߃Uk  .e~MJ^|P'~ЖpOD(|%o5n7D'Xk؞A岲O &as?oɫW0^3TӜtZW?+ !0 *Mg"if`(i†Z(_QhYi&e2YZtT{ްJ'o&_trV͛(kWFu BwADSBz p-/FA]V.*su"S<JR߶Eo!%)jP:Ki;,t6-U7<9FoAq*9dRI8<ƳTKbZy/j**HkN-@FX"qZ!,9n#yiQdIf&aE-īt/ B>Bؓ| jҸ01R{급t7M԰/2(!q@"u2pPw"'A;"3a阿G^0H5_KUh VH נر|P?@4(pD]Uі{ܘvF6%fl-Eb-wRUQUoٸD&؀͔KuP=hrPֳKc>0.kgD.*Fa']@C\$xz9q^ztn!pN—NwБJ)_2Oi!*'/Pq$Acϛ-Ģ:kWf}tYA辏^W7o0IEޣ /\EiA7 Ȃ1Agm tbѯ=>(SyP^`#VT4L SLWj 8OeCq /9S1DZZP͎㐂՟aR95W^8Ћu XT@NsA)o[gV`8J(y?n'?e|}T#R$V#xfi?!}1E);! },)w ^u} ~LG B7$ GX%:+]<ŹRD~S$ HixMO֥Bɤ-UF )bmcY9+~?'epR\M׎5ycear|S Jڣ@jNR'Q7#( _d961_ϱ%a8@ 6]FC %-rkHANK2TsD#Q!YC.oE}ܺۅb_Bτ/j(Q*X+'?28EZ,h9Uq3И8lW-qXTbZ=tgJˏXj*a cX ڱWep6k޶~}qb['1HKР&To=T8xU:J; 5)Z` h/ ~`l&CbBOK{MoIxÀv#}^%o}kSGDT%Lfͳ$n\kz`v=J_XT>V&d_{{^% -BNd;.)ی¯)ˇהߛ 8?m+,D(o"ªf2c GGL~>wG:*#(4+^6#Š G_C"n)QN{FNQcC,Ӑ-uAjoBǗ ;a@ lSl)-0Va) Ye[pqT_*}Ϛ,pd!/}nV=2[Bb9v=fC~5!HPZՌS),dgEqf{5kjs"{9ԅb 4S.(d)69(;0ocǝ&YHVӾ Kԑ'%?^BMΤO+tnE%c6iql%-05I!Blipn(Ë}sɄ\uT*#%Mc4_uCQ\W=%Dq@ZuDɓ ѐ(1*Cr[(.qZ߯kPҐxtr̻C7^-'Uu3.z l4UIg[0< so Ԭ@bOj] Nޯ<VQS)|I `¤Ov z`´Q+?hJ|d>VW8[Gw*Mpo˓%x,~Qy?ךJZ][vU߳-t?]?D c.Is3Ptixk9yx]&> _ Ptgf[%]Y9[uUq]\G˕n;ȁTxX^dweAĽ̼sāԲ\A\c) ߶=OQY& O" BhtlPD,|qHO&#iTo=5mz@dͶ~,予@/-)Aff EǤX?iB.nخa``n Da. j~%=;6aoM}p!' VL(NJc;j ]n)JZ B)ѿB[7̅0ͩXs=BVP yۺm2؛rz#MǥS7WV b%gߜ!0G75OظOØ3/[G.TM^ѐ5~3+<BzcorS ~MBC֛rƙnbp 7PQhHL1꼪A#wSBQLaSs.sPR3d[1 OqeP9rLojlrE^EefLusL`]և<AfKT}Ztւ?IK;o+δk]=UBLXTkD](7Xn].JݯuL:4ͣ 3-•4 ^G chn@uL ">#}y%?ʈw 4Yo{Z?ŃBU15Z?זK1#s1Dљ E?kuq}\,6H]j`+UD\ՊG $|1}hopqlۃ<,[l%%Cقm6!{)#5(;}HlmQ,$L ~:4ґX pG |uÓ*~_Nj:r(N|_6KmEN1 IŐjz@:`Nsdž` xr䇐(#)2ݟZ;nkB#u\5wINusre,t|310[ھUQiJk=J`ܱ`G%c4}!s /An7D[$,NER8Vέf+K_`MQ}ڠp<#nQ$U&9Y6?DMot2Vi %9f@Մg|w~z:&DWfh@qF .c-eF j5e6;LiZ5MA8!a,d\XZOH48~Q*<*qkvYG_$"_"&f58Ijwd5}e(vur@ٙdta̞uE95eY[YM q~ö])L4] a$Kҏ;Kd8A\{3G,]v43xO"SsUž!{^zrBVޯ|u }XFv#mz9ؖh/u"gE87#Hxݽ\po&WeEJ7QID'YdPp@1HRijJkΎ|\tS?jy-QoFw?L1u0hac08"ۚH#&??^ݒL_.7tH3y@g`M9wk%5AA&5ZJd7ng8Z'̗pٔ$(G.{p-^Kp+:@FDr`_̪繱jYZǬ(60ٸⲠ<ózbZMox|.v4p+H5#3#zQˮD8jT6Yo{Zrvpx؏ݫ[|\4\w4PY{+du }gŀzC̎hw-+4Oq0ĝEsXg4.+{<6K(P8|q)m+/[!Oע5Oj|p6Lˊfz}X!Hڇ{WӅ"o9gj>M)5g}c܊=& % *Zޞ&),-JG`2a6Gկݭ|~ʮ xRZ[þisCFGjLGV)W\kLf8ߣ,loDow,Ͼ+*^1/~KFZ#ˀp*߱EFC5(ZEzWt΁u \$~%pOhBE%}:Yw sâ)agf붢ņv!,Oĺ2H'ei2휬6ޔpCލٴP5;GՁ]n W&~{6p1*^]ۥ4 YZlqͪ9(iNVNB A#!__D7*7OH6{AӔUDHP^SX&Rs q{z˔ њr How+d|z$c7Xנ1~ ]0,u?>'X0u+9`oj+cr]P;f϶htXPBNO#14ʦS>u1F@ ]IGx5㉐AHI}nTXu*jWA'vB/ F.c 2wF`bEuTYLݿ=fxZ- h~@Nz҂U/L$NCE2.خO~ZN)1o$k/)e[2݅YpaXB>[4 8,,Hbe7P\4#bHNF{WPSE]> Y 4li2yՌDW0k;ڛ 2Zg3mbץ YEW@{-5F$noE;; ">x bt2w,]~} YMO#%1*(cĆZ85㦃(~dLWnn\Uܸ&+K)M|YIVG{qYŽ@Õٓ<}BՏH&>D.G~݉дCmF!6ou³;Cop 9Y|lmHo'!ٿ#䁲]S}POռ@- o*/a^|_Zz_7YR#+s8C`#R2hk#T?cRb19az.Sۗg-"sK܀NoE,{N*I7lzEuF%|k], 1}`[~c@0DP$+[$^LJ{V&Je8="R—V1in̤dA"D0tpFR|Á>ȶT\'X6~x! 9-ṢrnV {싢1-[AvG26pv牚ӾD'x7[WCOZtXfhl`ʹk|\YZ@9!L.(96 } uM dv\aVSd7Y~^کDtƷZ.L^t/>r[NWD-7p*v~:C| y+e |훸^bD\dw(}pzV o.2@o"KݷxX't흣=Fnoh^з [p?z h|>`!cw;Tt(h/Db u)>ĩK?OF~ȱ;ܥu3HPz /y3乻U x sbRq2 N2(jexdjU;lRl.tg3&\xVhwD@^ ̧c*f9Nd# \$U[܁MlCV^~vi3DQ|"YϞ+ox!k:Qu p]0~&rZ D--Mgz& V:dJU hW5di*[6vVT`>H UxA]j=DӿرUn­Y\ _0AV/ZD85]t '-\-=1ny@ I)<Ϻy ާD/14{!Is)U V ^Ac r `_qL9qjrY`<=p6J `LZ0LԞ{hal[غa(aa:w3`f D*wn+} Ѱ֔{cy˄dp*뀅>6N칒vP)8?!sN~RKLS~8cQp {Q2߰8.oOB="OM+U&.Lv$$.VEKqfMypj\- Q_ }+?eUKaޠx9 <lMU04=d$1U3͑G}~Z4P}ߝ :^-G"P= Z,;Y! 4%@jZAn6xPsfؠ ~CvlmPu~g8-惙LC}wk{5/\Z׿ XHXn~C_:|zFh=p7PJd]~8e !ji S?mr<'@5 t@w6騙p5ڄbz" m<5]"O):fO5]A%HګټќvŽbp֭O}/"twZ|9f>;_W|) .xZC.X7Ê"P1Vİ`!:_jN@ʱLGzCt^\~*)dv ~'!b+u[Sp[w??~Hz7%mQYtگ5BM)=SGcz&w@6쮠C+3yQr\q $wҵqmIwaM%Tfef1%Lof|*L˛)PҎD)k~ (h o}zVRgr"? \;7pjHT3a+V5Gȃ4uۏCŠfNPtrK\++hVKi 5Y)1KgbZddoĸ3PEl6|lE4fꙚKb4*x;pi%B\x9"t_'Qu K8}1e\8E `OIZaV}ư+W= o|/shK|qb-Pa|wȱ;tDָUuƩׄ`MUqt x2^Exd|9"@'9`pd]z~;kqgCзge~5`pV5ЈfNܠ6 +N>0I@k\| E6r t)H)TcY1YW" >gsYRz0j>+_hL-t8 9oF#}@MHV U]{:ϬJf,|Ϯ$vVx6 XȄEpexsȜJ*fL^uj ;WЍl+#!ӌ,R_.YrN IJ[Q{|DZ٧>+yMu0J%ٖPʀ JqnIT@ǐTy F Kx{Z+Sg>`R˜Po#[4|]Q+j M);H_1)Hzޱu!hae-AÃ'$f+L ʢd&)70䰙-4K@~ QUSVW7>԰aCcEݏ+WM5:SNV`4Cm7y C4DR C9y@[OXTFb!7&$0ld^K$lPؤykPgz>4G RI#2Js54Di, Ƃ|@Y AnJGֳSm8%{DXC}HWcm*Ȑޜ~\ O g,)Z ? ]N*$} 0 I:ѻ>FF`;2DŽK.2 f^g3;[͡t)7mSX'v*a'߬nRiLzjii޵Fj=L@sqr"-BCMo ѝ$[m70pVɽ fv߱32f^|#XWP[}85%//Z83]8wQ#s!Jr,0ʕhTw)KūhYj "[zdzt.,2|bj9m+Y<k8/"l YU֤]Vujj1yOVߟRѣpYxԌ$֥U ~p?1ENęc~)OyPCb6t&šA.Ԕ03EX g8ޠP@ 7EnO].Sx .O-u#I\%mxX7&V,a@*IIvW#4V[@kA k;ֺuќT_sEDG}5JMFa:m/QĠ.~Lƅl(d!alj(2(^L#8UVX %jtOЉt t'/0"C/q_ $Ob,;%(:HKxh}pͷ< _Օ)P~V{{!&j*#-gy%%+=l ܃iVXbI".: mU4-бSj={lL %_m}(PcJ,+bL)> ˑȴJ^rL)VJ>A1+m zj X}ؚ}?Rj7gFV| NED'aOQ]Q́1lڽMNw6BCJ ~8Bz Af{rC?}> lPs59nyDo3'3\DW*W0b\Eԅi Pk$G9i=y],ldk(*uX`N&< u0Gؿv`[I ;Hf5  ?~z_sv`o_U(\]ikGhe<݉5z" \^79z}ջx[eH,4VCB~_)#󡖚H-]J \kIs#8'-Óa~lCKaU6mG者)I GL$`|LuPjpqP,rj) 4x_iƀss5Y.'=9U x\֡BpB ixF+dWϕ9>Ӑ%?F?F5k_e{/!Gh.T]L1VnͩZh/xLjTYK&o1Arseu} nJϨDX,ZapVg!?帟W }C8q'٧8G(b<ġPE̘y#1_~ KFiq|]GErFkfm̍.JS\Y6@VcG%} t//,+u+ˤh)y.B0*4&K> *`LW<~VFa6_RWD2tM[vQt[׍QR%p̍!%%̯PbB׽nՄ8M^x(\IAf삛U/ tS3k a-bGD9O9~(MCqB7ERhaҷAl㥛ӐCHX7c؋ű"Kz@&m Y41 SRYHA7ߛ=>qh:iGxV=}|c cF/ [ h ;?t%xc/)ǴiY?ɕʋ ۱пGmJ fwv}u 9픂^\3;G:gBjѫ!1nt&ÐBɒ1'¿rS3,ń-'vY 8%r^VK.b^q*<6ϫ3fQ_/?:ývy?ve9W8Kl'vNӗ B Fs⻂Xc7y_^N*"v :bA8tgFkYxp"Z>Jr*'yZsưfHS߂4: )u-P2wglcC:9(;ƯgV=OE$y'5se R3wp݂|^ӈ\(<9>S;oDŽ(%.F§sNNMU!3u{qڢ+,#+;Ii")"+jEh;LBN^ xMةqu@|̫Yp_ mNHy 1,T%0 D5P#L!NڬLZVOu닔JP<)wUN㰀Q2“-)%YNB 2%BÊpl@i8-]t-& ' HtT%رU?r' ?E*hΒP:QLk3r36+vA:PAŀ5JoR(j#>@ޭ[]L>L} h ڇ:+(1ͪa]iqP,lLj\Id;аyAaf[-VUץ]w@3GD5DF]\Qt9[+!@K֝Q ̠|sT*J@O I6xrNPb bo\2 횋gs9X3m賒#Ʉҩy/N&8Mq盨JNޤ s~vA`ޯi\` *Сh-QryukqC}pz$LCe4[q F3DsZ~x#+ĕ. fX^rhbmPlР;?8=\yo>11GhPR0G䁷/n9@6ʁxdH$z5t^X偱m#Ce:5fkK)&Rc*n)1< N2<3&;1}ڐ-X4|q ϙ:Qs.)p緻r,, #RHC鍾X!;OTjZg੉v';BϦ5s@)L?u iڅ R?u0(*NX8:dK,a p) cǂ(~.*r(OKa8Ǒ^Q c1.=p UwL7z57x|@M{|a[f2al`FX;".ՔSvV9IzFSYևØa0d%=e*a%GVURI6MOןBjCDxڔ?h< R0"5NbS~/kYڠ ŲyD"1dOigwB .e"TVr3pCu(|v/}$F#:z#xX]Oҹ%a$-$ Cǃa\sNߖ>:0jt-w5 u7@I/۠sId}5Wdz+&'شŒfk]G"iX %/@IUp4[<|7))+:%penp6h_جFJtD+ UWw4Iz*#2 GlC԰MKmBԢ;8uAꨎ칁md[F$q^sI)=0:,AkU[O"f/%?tųʌ`ҁ AkvJojW&֡`9*zxBqE!w < tJx7WNTEzƞr"OJ +/HJv!V0^oDsa yr`v2qނM\)1bef+0&VdI+3&4+K)֊7FZ{oR< :YF0'ݫb7Q ~gC@MoXd+!޻n}T$%qgJ87,xcK5fg)_LE HwzP@YδJ,iƫ=!lC\j2bFX[D ͪO_8zaʋRz&^?YSZ rc~6t H M0 ۗ$Gso{Q ,#?BH<1 1DC%\} lL0^T,ݤkwio$60CW Vj@rܤ ?Ob7zER'K{ӥyL6Y&;[^w l[R l`6cP V /q7;  Υߪj^O2|۵T]*D5(j@R%Жs;E\ʜ4咄<\qH @ߏ傖oVzXˍ f/MYhb0A=)ng O+=෭T SAvKBjFhc{OO$b|9(C*B;yŤTo2vdI@Objy1:Q, D6Ù3f1["Ȍ,F4u=C35ܲx+UgH$|wuJSIl #n?~9"{g:Wu 6 &Tv'ϗ@)@eE,pAH0_qs3\aɞ#^S#:3Z O{[fC+mǪSw 硇uRBe$I t`R)S䭣v 6C-1K$Y 38G*$+z?H$%tyޠ~ #cCXqJ)g_hlBF#JroXҲRe# Pzؓ7EBpAש3z9auaVt +߱ KBnKI?ڞJ:DL&VaEp7nT `9~ُ2P X^ sD]$gТ7"wc}vH,n1ņ[Z^,±TR6[ޫ}s7r =ίMNT 'a iHf;2"mk u} )@9Zڣ*]8m#D& -f4n|H$ In[mЀ~蒭 lkqq\<)ˠ(B6К߂~{* ynUSz{02kV3n"]zoOkGonDK9nPZXX:W1X1# ܗCfM;DlVN]˱K;.xf0{,"A܅}t{ܬ߬e_{uٮc0˵jǠi0:pm!3Fy4HAfV90lhf w| egR\X*yH ~O=3~l.vp~my+桱`H )vJ3.+l0Y^s;}5ccf+lҨOQB2sH+dzA4xeF|YHQwDt[b̯͏wJFPƭD˝cUfx գ*PL3t(}xwg^Aݗ_*2#9k\(-4N<#nԲ "kU0PX } T/0RfhMr}a_h-28HSn.ϛcW~iok~ȅ͑.<*w"u?6 k<*9蓋  #8m%hw -`^=eoن%<:d]B;880wm0]Q>VAX6v CoAKXC_cCQ5>k7~ pKگ(pF)^1 ;|3ɄR"ĔeM.Tʁ Jҿ"ueo0BBRpv5pڿ_;0 __Dʢwm}s}'%_] K,ISquQ"#h%b:1un5J ]ݹ?NզD, ~t  F^9iS2j{zS, IS %-[y#@[}ӏBxU@Z1ѣdy´o6۝23[K <=auB#*h.dgd:/x:d-N`9}| W4وq oJTtჍ9FFc^R#ФNj]j[|_W"Q^Z`1tbc1/!a*hSU |եz5:X`Y/z ` .uG\J^ 30~:+@lBEVܠaw/ߌomS/+: 9%1]Z{pMB0rnЊ9XhI".1>Kq&-}Z3dk%b4}?Yl2mf[FŊmvQWֳ*+uZ;na~eYe%{-X>VjH:AtU`Q]J k_$wIS}yGڝ(6F؛.p݀~+_xak~sO u)b0:f#s*8tQ5^dCƌ>6lEqj9" 4W? _Ycm/Q2ǮdVف狹)~2f%8 Q:q(+ SNmƦiċBa.7ɸb;1ɖEbLnAᐥ,%w͟|@BԊjmZ/VVQ ~ş`fqJ]ă!^`GBC E$@W?48Gk+IEL*3 VfDMQ:;~>)WovЏQ౉F\N$ÚYބ\P_ʄCൊWi)b+񽡌Q(H}6ϙ:a'FttmSVQyYgȊvD?:‡N^ NþNaj+W~4=𨀇o,׎2+*||y^>+uAQ8Lh*?:eS!qM.v4մrco܍4Wf1ұ*7 0ʹ~ZôO -wI}KҬlעL`1>Ƶdq¨̋ۦk֭ =C=-k&S 7UKB<-T@֭:5nH~}jL@],{dVy@l[hDlJO+/;E⽐`դ2OeH.s醐i2iv9a6U6}ݿEW,'Z˳^HNmUd{EⵎToӅ2Vt U{x, *\ R+\G')'[ B٢*4?wu6ˍdNS)ܰ {3&ö n&%~\E=/vdcL!]H 乑]D⦈F3@ hK*Ci>4.IXRGDAK飛 tf9bH] 'ҙqZc <*8F7 `'n JPďՅC4;MFh fuEo2:'2`̕7"9܋"՜a^: W_t9r3ĴUfr4\频:|q. ;;̤JNEǁKsvB4kg@aO{!"ǔ_vلF6淫J!xpL}trwU0Pa:9lh@isL%kr] eT$e֐k_Z& lT!;ؖ1NPChm<}Hsj:{X@%v-@|EA )t[iW9*+g~ZP|yk95DFKK%fAN(4j!0 y=֒fV2puFCAۭ(oϰ3G)h fʐF{閏+MX%ݥLp4^Pr7uKT$xg~t׫I?y-R) Mm8&qDZ4g&XrQû?Y&Y7C :_4PH!~ ȭ$uJ{~'eFs*a#G8| N8ht5„fC:1!)3|21Ɠ]x B1>pcw~~+`^5x},dGXz4uhJJřFhE4b㲎i볬V( '\m!upy ~ߒ:p iWjun?KuHƁ%W,f{nV̮dHb E˙5A` ևX,z2/0^4#>|8C՜H>)@R]hx39y%vԞha!j|VVVfYm/h=}gē ,6-xkҦHj/xI/Bdð!U^I@ #BA)JWg/)޺0=f(VcI(Ceg>Jqmlh0)<-N4|b3HM EiJk&}|HK6, 5o,>tc<7+}159-ٱl񟽎?RIʒNgSL$2FX5+R=Ru7'h\dH1Yʽcrx@2g@ȩ1bpY4 `R< />]k?%b/@#52db#_ĶvqI Twv2e#dz近͹<=upwvuC/$n ˛# -UGTQGVMD51|vB;ux Z"1R`.V @!k v%2 x3;봸ugQ*wiŨǀi4fw U&Qɛz F]? U!?/7ɼ&|Q"Э7'h823ZL,UU b*ڲ!W{U`vV;=oW~jթV$"הz>Ԥ"K%.e2KJIfܒ te_&s"g4^qZ2 tХrؼz -m @)cPmtEB}|G7DX+-"HE/gg>[ԣLD ₊Vo`ReXNRTn 9z^,4[בdOdBRPFydOva8Db$}!cAxC܍(3MB ؄ao((,ˊ L@>}ag(ZaNa%^Cja$`^ϳQu3+FAC~!%=%4RZ?ՠ!9(gSŐEZr42o6Q~X;J 4 T-e{-R[@ uؐ \薟j[S.ScʵQ.o/`ɮBe6· _9Ɏl\΀Q w.Gϴ75b*>F}TY5"V(~~N0R8`鰠.ɞ{{?L D5rl*ׁLr`~Qɗ2$PƽD)bwCs>:yYE]R*``k<`k!iv}H 'pUt~ټb01^oWj>4j|bv.;vF-,XlmVϠt̽!stEk~ fR36=.L٣mFRHT܊X,ɴPLG@EhBhh[u}O蛥$ZEw9ޟ!RVB@^hg_g~HiS#&EI{8ޡ>Vੌ?.S]p+̜mL];ɷ:dE?@=tSx, }BWtVh1+ @w0cHM{[Z >h=DAxjohڧbWs3A-o%l%`$cLX4Msڋ 0JYw$$XϬդB;։K&ikh:B=>V}>> 8>-ZUCJ^YlhEqm?PR>rƢmU49Y >eS5Y.6;R`{0zKe$D'`:EUl$F"U8_he}C)Dd1Rv8V^nwgj;7}o+遨F{UVln\ 7rf0'i.i5s6?IahU%;W`?E e݅3 g{Swlc+B7yGnxKSF>?J( Jp#I.ˀ.EdZn߽DmsY!A=@53< >DDR}5Nktnp}rg/P~!$MwTA$^IA{k{q[On-FP&Ǡ7y5rz1ɵsS pehm,7gt1)/!uNP¼p|Wry⊹I~ZU^oUY Ł aȓRp6<91_^45o]WBj0ƟP#z08ę0ڛW {lhE9kӂ.f3K`1zK *O|;kj:L '7L˼MRT=h1Kl)wcxN*9t0~bV_F XHXn~ ~;v^*5>)"cw2j)ňDH>F#: 4@ҠRT8 oӻ4kU|? iyMPJa˻v֥P \B(:9 :,s;9`#gGK(Âл̲:Uhؘk>59) ޭi\&nahzCSdVp P Ry3(<V-T%1g/&PuYەRW@E6i"6++ Z@(%_.ONN Kl'*DpDjfO:=PV BֲbNX!6Ŗ˚dg3I![`Eˀ>&QV~)ujO1 `$0.H <9싱/ج 68rpC) AFr6QBDp0aAODe6 ^jk*! gtO{ܼ~>l{&K5i~eMb1Uc|@9✀˨ {P4vn NF[.{'ws24zxU2brc0GMZ' *JTSmr#|u>N2@|Z[W7B-^sq:BN0-Z7e]U{338EDu֖Y<}DQ[!azGp =[UEo n٤a=8Є^ 8'!K ş#y AT<\_!%X'b$B5jkߙ޺~_=mrS[`cE _S`˷!bgA ֛=^<xGx1_C6:AH蚝^՗LӨo_~[ fɪu0l|Ҝ8K]b O.qD6hoK]}s mǙ'ϛ@]#"|;rr9cO1! ٔaYX&&ů(걜.42#BDD4nY%AwXӎý-F4q!A n2c#r[}d@N%}UiI–tf ^ #ӸðKtlRbi.VϤƨ3}g/yv=O'|I"QaW(lA+!bXJ,}Eu1CE&'1蓗SuLZ8>ڣV D!Gc^?岐0'KʣK3DZ}Q0a2r{9nAP9tsw!$T+>QN!VVZr7޻RD#1 Cƽ`8Ӕr巷8N} <Y6GP2i@va|`yC8&;G,"odQm-/ /^%F3;|X !w@;_d;Z1 26Υ5Ú5 ;;p?zzl0Q4]פ׽xZGпne#FNx >L=S} n*<殆8~x> ~uc]@P#IbȻz%Nrk*orPa&Ui0 d0D9L6i)g#68/~::O32gzG}`XmXm Y۞ [E.umlL스{hP " Pz7бS=>Ҁ)`U>[Y0{T,.rݦl MmXM:F܌ovhc^6v q{z Ã|+bHlI54£g|싈Qob`+354+cb0Djì&F^G{Oe[\v%׷DjcÕiėSCjz$yh@d"sbDv rH9mƦ\'Hw:#=9Xu<^l".rTW |1 4 hqQxtDK(lݥaUY\0%̄C}(R.J>cæy_Yqtːɬ6`5\Uh9]>Agt[֭PƆ҈Vʍ@ ;l5v%uG|Pr>B 7 Ba~+,Pȯq݋j._n$Sy5s}V$G*.\Uc#Hi8"2 _n?s˜7Le=DՍ,ؚ:odEdו2#ǧ4?H,oQ& 8z~"ؔ#4~Mؕ#`jf^ŠZo oȞKy߆$xXw%?lRYYat I ֊ ؉cn+ jh|gQc_,񼓉D|Nx8.9q8Gil-BlF6SI3% ~a2JV+ ,Vy#ވ`rM#R0Cm1ג{?C8n@Z2;s|<^[/7.'f-ƧZ"=zf*iNE[*ܗWrBsNЭSx@z8x/buuf+Wmm92)6d|h@cIFk4" "X֗qBW߭G]@.o (,^3)}G:f*1% {gDǫt73뵯jS}~pPKKz6š8Dtpز>w;Jm`pڊ9ȟFNh@DN; bŭhi4P)f@RND/gdӡ* b VVN7jӲpE-e6µtQyR[9HRixks{=.'sE M/'Ȝ 3 vX9K92uXﱡ1+oǕf9tˆtlā=J__OfCgMfBM0Pk61z23:3Lަ@h b5,5Vu[y\:1)PJu^úVZ2(ƏU9Kxzos!v଄V̭hOr}񻪧C;1$q$4IT[ֆԶd,%gb!52'6x mu詡:swQu+MFÜաn>s ^޾iזQNG{yv4Bc+h;y'E$xq] Qw+̟(bW%`bԤbm`1~ g-ˆ7irW21pk% "@e|9E恹7"Yt\,f 8!.]#;|JѶX?eL*CZ"+([c I},ŵ?%oTJ4A{?r.L0./ u,q [DBIibݹU3//&?`J5đ2E%ǕC]u A,+ƼlC/ ɉ" bZ|"y}fmmƖD`;d0f0XnObm)zn>-$ BX.D5aG  b&'Qj~ d@%nf `/p96 ҄f}7l~rոrޯvx2V~=%L@@[XzKL1 UGEn~.U]Lyp;ufȼ0=}⿆qή4m?4wFAq{O^HO_DIWNܷeڞa@W?IztGv{4ۼG[YUy=sMP, P4FgcoaIH0Ivb.N l޻D#˶"y.{|H^i 1>(K)үvc \=9jZ.&D^6  g')G3|mJG;Dzx9JށFCI[OkJb"Fw@Hc1% fEr6zŹv~Xdtr@_Kյ5Sq6q^ڼx zpC!6كݱA`vȧ."T\S ӷx VDqRFߊ@mTQj*{ ck0gAGTb87ſZ9ͰFrjs% sbL=]?< l06+V2܈Čbrl!)|n0AUIEۯ,`u[ܨ=4P| RhMŠ)b)}XkrlmAO BJr?)PyeyovY)_m^7QGJPFeǞx˿ r s%5JUn>l4e=eƉ>psM?V58:PdX0ECD/ZAyƧ9{a%m|\+>]P`ny~vFR$~,\pjR~lm-3Ha5#9j$Ei/aQk7_v3SENdDol\#vs:qv}>&uiGC 1VS2G!U@. -FbEfCuDr M- ұOtMd@{5]e)Oy2|PlĹvOt8mm9h* ۑQaB 7)V{JO%Qn^:w؈qG ɁM"Xm{~}t3}(7usf&iW h?%7DG)HzL Qw["~eFc ɼ&fgYtK99=#=s:.*&{Yu\]A=1M^NJUӂ?x/>q/yL&;˔'8PQi&^z Rk˴X!gXעӏ9R `GP2k$-ؕ,Xg 6n.!'i&{'Ueނ(*rRKě('[Hԡ o3pjܳl{DShJ)x2|gX5Iw{C3/ ð$} '۬^2z dS !7>A +V#a[JKl4PyPH5 r&}ܾùWm&}լY1O/? zۈ~1gR1lRKï0:=7}\z$,tMDr>Û ̨iK$aK/ҿmRQkEg4KkAyn,}X$Z{7_ t5 M3HH?!#/YIx7>fPSDd=PJ9Kbo|龣%?b=SCLЉ_m/Etoi+/wzWfLXj&ռ!* @ou(u(jysK,f$GiAȑ/FSV(~TU5%n#Mi-:ajO꼶T>,pD+x.)R| sݽ" ^l3 EEumSU `v@dZ/-h Zv#ϑ"hb^7$8 Xs z::J‚a_=K9au7= Z _4t%L-*1 LY[+c5Ec4hlaU] L$7 lV/K9ـ54k;`?$gHB2m%@&`xmHi%iؖ\Ԝho)C̄*h 6-_qb9A,Ŋ'*t8Z-]Ű"T藁Z\N勤 p狚éf\rvƟ>q姚3ek E }s~o,&+~. ܳ@|h<35 $y9H>,ء&T')FvJ$ LJNUe4bv&z\;͝v$z܏ ~h[V}m=bIi>QohǮL&t[&4b'G|fF]Zo_8K߷]1dLr3(d  (W =AVT1" o6d T<%8-3V5kg*vl3 ~myj> dk]ycĬNjg U*`u<~/%srmd$)#*y`GyD0!#^j{ahM]- Cr`'g?@/Ē;fPbdӝB_NV,|'#M,4JTz֒te aK}MN̎Nɔ C i6ŪYp%Q(٧W?`T ~#42oϛ.L9B8e EХ oeh;pQM5B K W֤;2#E7$cDl0.Vu{:z'dj/醙un.*d2wRh}C 9Y/rqg8EXTp '-b˥ƢjSv[r{/*&q9#mc TRWbykƹژ9##j@&rt!& E^8*eSj.X-5C<xe#Gm?2^& m5IWmbL9\/7 ڐISLtBv(;ެѥ?~.v)1 wM֔BwPL:Yn42aiW͂'2e=Hψ`$n#xY*vk,:,pVɯrf<[r╱M!8!sn3S) Q4a̡(ϳ':b>_^JH8.]4Un"5L匲-!iZ,j 3ssPGV,/2n=x Tk%~YYEpI5".17'JOhe7Ld:w+A()><2yf-\P}O!$>ZjVuWL/%t%H .g˶L Gc]: {) ;<ۿE 8ԕȗ`Dw%?V T&@Z,E$Sdk0vɴ1(h< Pe"5h}[E݃mJ%}TIEے)"8 _ !gZ_{,@t c$Oh$QKΚ u :pEᡖ181U RL˘k n[@PH =(pF>Yf$5Sba!=:+Q(.ZX̨$H41tZ)GqC"g>ʹiqG{HqSLԣΫ.&Q󤆄5BHiku^ɩ:Ak$\7!X,R"2iN-={ShpaGt:ݴƒ%Xy1? Ut |n(zjŴ|6(ŚdYURQ-fïoֵuLntRF9RƉJ+q eFV$V_AWb9žl𼆍hIp-9UBhXE2ghSRƊ%?E񋍞 +NAL=|sl[7ٵ/Li3e,ZNg})T e^Wշ7N6l=^mmĎvY"ho/ y{8o,h'N7  hl7.GqC[:5h% I:>=j ^ݻ[E",@t%hW;eewCF!ͩuw %q#lJƘ$Ħ͎>"n0X5f8)UMLQ{"xcb.-o$Q>YTzOADusf&7g[naTr^)@zy@ jN eg|>=TCay#y:x鋴/(^d_Hom^Xðzex$Ic0r/א-fޥMԭc #O?kFY6*UtcCi:b2OYpO0aۇ̎Ѡ8Y9z:|s憎g~cM91QT<؜ Pp2 n8ڗjr;ؠwBe -D!u"\'"Ydps"Nis:8Fѝ/% iIM$?smrv"K36Y-{vIKN%nTuJF +ɏ7hA"UMZ*}θo$/`we MPk9[$pD(:B8!v~0N5Dn5Bﯸ`xAR:n"F+Nٌ*.vi8$wfɐ޳jI.$OѹL $[P]j5ʃ"F ƨgSH֟ԥн[H;&0J뙙NC·YG,5No|[}UJZ>Z-Ls@ N@5>9wjrj/80z4F)89̀Έ]_< בVORGy@ f.xH`hj௘;Y}jb yĒꐯ̮jĿce/{08tx8tى&>>!o}$6$f *2V 0 N ]dw4t3dԶN(M26q&\/ҹ3@̭hʕmV\l?]fX) ^$`XǪI3 sw^ $Ypacː >&&sF PuCrU,h=deoYr~-Byf8^_ͅcM'%ݡh #e:CPƢ&T&Z1mbcX EcFzI Mueb[p^ YX[7T$z[[% Θ0A`]2pDw1#*+RyNr,8k}'DzYQ60U)ϰhW'">`\nvlFt?|H՚НE4VMNf+>e>owh>!}6$)a f!V((usis{h<~6) VQ] {j٬ {| G# -x<5 n sXۙj}+CGBzO'c "ߖ)]9;Yѕ$3/}$()%ZzB*i W;F?z,bJOd].l,mn:HLN#f)(&7}Sַ* ۗ 5FhV􁬗nYNnDnH"R2,!dO©zː>r4[ qVy Xt<% 8[hՌN#`'8hsP$Dʾ}Cg*h1YotJphYA43[lA tb%}_v5ǵ[)e|a{.Am #!P#pãXB\)a{i9cd0at+oWv&ىFA|?adտB*4;lG 4<<@u_՛P-\p#g?U!1BH8|TZ wW'#'k qC;t (J@GR&SwR᝻_wHc^zrG]2YZwȢr"6bB L=^?( t&ъ?;KE<8mVdL͌Û3Z?Fi+x&Vf#R*+0ȀQ7 Á'4-fl;k5\J;@ >'H1&Qj|ӖNJߤLe,TG$oCpMY=:cF nv+O lFSTlݜN47h}4t<\)ka72XMHy0E Jߋ4hS珅±فl.{JF }+})9N>& Hbi2Uo&@eJR"NgFSwd_ _E8$.#Y灲өa@%Xh$ܔ>ɥnEa Ъ\e"JD#=J>Z{2/ܓ.+9K.rg8Sq6m2ev[#&YI@UpLaU{z53ti>xx08RZ*Q0Z`ϲ,% {>8R6h{,-7-c{X4Il'[ CF ō,ʇcc~f"F SW׻:c:709wP` @>@P4?x?p0cݼ}c<"HsR)6&Ϝ+c3|B.Ȭ\LX0o*E"k4N'$Y'Rs ϹՁ2N[)E6#zx>&4D⪹i_ U'EM>&M&.F,`\5T[/oKSR;ֽ[`AGj)'( e!SX6*~с+z3;ZΟF'~#*!75e mQw]5XJ/zcjȂˬWUK@3)xx3Vb}..WkH]0úɋh}uOQؓO,PQ "Kmlarf[Wrʽ[BI*qلq<a"[LX<_Y:5Ђä2:QO;n"fQYM~U*[SHGx =T^$g:Aۨ!J2_+Ћ1%/N!5c!D81TäѤE)#TN+ O5*Qum=|aZʨYGD!FzĦ%u1}LsBvJ$5ҷl2 2HDNDDILGLv 65(lm !Ĵ+z8mgFJnXp_:5^܅4ݐ1"cnݑ]'Gsw#V0l, ϖlM(ܻ!^H~kJcY*gҠİ[;{]+H; iAfH=|sluFՃqk[_Ř"~$?(}z>+ yYV䌠nƒ@6p0֒R2xvj};DZƤhRF["0w=䴷`<S鱯c(j;ppyLޝdl*.D|U&wTR2K{P20v98Kg+Iiu 8ME/;9r?K4NkRK +jWwҦB맭xCȚk[tL ˃@q|e z}7܆nWHx'Qg`TWwA[Dլ]Ol⯁NW{;k11{L6l0?6`Hұl8'<264vЕL$/=K.xe>zUw;1kpz;b} gC]Kq]}Xˈ,f6|Y~vfOn-Ꙃm] nʇ\FۘO Jn%фo' -|@2F @r(:c&@d"ghMǔb;ߙ< ϴ7`/5w"|+v>\3(떹Ӽ94uh bZ-{?k~?hKsjbl~^Fjk`l=!r;nQiu /b3}B V ˇ@&dq:/%X3-mciIt=4Z"p}Hg[, J Qۜ9y$wUНidP%@Y6MYe2 Ql ty&7~Ǩrd؜xU[ BPnc/O~N.ns{e;P93|7c r;8]nj Xa :R[@=O&2L˔gj9]r,- 9A>Kۄ38{xKwiPJ :%DGգl&w;-49٢|g8->p=Y#;88Q/ev?Nf*i@} Vc(C+Kq֎OJѡf5-ij=v\I5vC|e90̳FA]mݍOf+QicL#4=F 9`5_\EhQHAx*ѳV4¼T_z'X6A >2l˕ԷZ>OuEgT*ewJ^!0Cz!\V] ( /* LEg&Kb%:EG>}Ǖߙ+:RD9 a2@Bd.Wr=8țRZSNk?8>Ug gtMtyjiF@ARhP2~wxq$rEd+pV,DSW#l:;~Lfmćiʶ[E}:RbTa_A8dmghCDQt';mz$٭,6x''rg52D҅:#6zAtĔPaS[^h09nl)R0wMyp. :`a W?KJ61-5EF FԖfE H˞qlh2ne.KK-4i6unj.fGE3{}f_ݶ&\Vgȫ2_rH֦~y,^.\"jjw,6Ev@:E=fb6p῕6Ye*P- s:TL2h<ҋ 1HlzkbS,Z&5@4lwQV( čSI) &4G/q"Tu1ߎ4+{@yX N 򶝊zy $NE7,_AfK|u g T@zK|\5m7R :%8D`Ѵ2=~PXLJ'+WK/h]Nj#u7]u1?:9Ib[FNbQm !;~iM)^͵ȭ/_5.U>1и:wr- vl\>&S N'BRtZ;fg2mxw2U/?`^%}EGN04hKslIx-;?/3 |D/U:On+!XH\0!XB+< ޲# ']d:-!tzV[Մ^Bm0r'(@gKz8ӵRGEǖc*߇8`!zhdY %u蘭`ܨwnٛ 0WLmNͭ,fcigk<v>N^g6QSg:QvKϬ[B6n1w!7g\ŏl\_y CЃ&G/z1Bod{cāL*_x;t.BCKj$ݟXeIY}\y.hK/AWWu vn^T)obMJ(wƁ??zF(!릝I"A+.L(P9B:+QLBfr}y/XtDoKf Z"kki̊+d Z"N EHqLPn1ڽ/a JfS5my!mcЧ0qN{!jsިJ1Cz+=Z[ڟE#gjCZsG!آs>keC {<8k+vϝ8Ob'UC9M!t7p1Զe:s#˿_>%ZtSisy3\dj![.7B$ ahTkoPԤz4@ p1-p=^L0aՙ-N",̭1mj2^W9cT'1yyM>k}<0$lCB(ꨚc EWk7p~/C"iyFU4Rwc-J?sXa2U0Q%irRl[mLBSRijI% %A^',&΂w FV7\ T\SD`RRՙʡrD^&׀6QsP@֩:#wܦ'4Fy yi9(F[PfgTTSM/ D B( ^762ߕ! /d5XVO79)R|D̛mRruZȈ:ЄJ Q=D2T`srz {i)h!w2WfQ? 9g0z%>A+As[ZL}h&t69~נ2^|_ЍMPؗ/^\9y4E0׺ڢ:0lz#Iv7%'\Ү@We]^VWMigMY?b\#rJx섪m $p_> d4iabDca2@e S/cՌ4p"̍)<h=A{ e }>>v{ x92[֚v΀[3ЅXe/H%HSfSM]_T] OTR^x# }LO :RhoBY_叐l;9fЫuN ֏58&P>0˭aMְ#Z>I24ayn;ӝ|k= [o/28pOLYb|5i+l=ZQcnS2z7iUHX ._|zb03!fo6%j8Qr]JK^V*#9]28@D:+< G. zt?B~Y+ܼpR][?$ŋdBWUu&78_.Y$~ַ{5;6*n300;F*KPOYw 7 Jk0jٕ1P_LZ<ՌGcK*\f&eMϪMOkQ9<I| #!Ll,R -, p%hZb\O?Di/%=õ<?)<i=ľvBjd䪩K! $ q=g;e3$Y *uRn \G;QkΥlC6%$ωW+'o\Vݐ<[,/hʷNg |0pn(>a&2 ^pv{S%}Y( iϳ+bToP!>Bīt?|ql-'(d90H(L~Z߆ggЪU*@!1 <@@[4Fn.}X4謻69X3$PϿ ;nmř8@TYn'zN ͧW YEB;Hg~ڳo6o\$Y/R9ujݣ:Rg"-޼yK"a@R5=^IAscUN7 g҈*D^D" i=grݾ6U͓j>ᄁVf['3@=ݯ]]Z6e]czj6}d8Oߌ9ZŊ)t;m .xY`KHmY+x5"ybDfr; iC+pSD2 k8P O~ydr$0&d;-ŇUihr[VuDwCIy݆ F-G6ԅƜB ~qKJ<sNrbyOCnԗs?„fߍ!_#hfArj$i*X;do3FindIDa/kw=4iU-:< ՂSv~K:M7kfw.Ha0/ӳbjS*J vAD$vK\+pѵ SuìզxY9oC ']w{KnЏs t 5_ F V`!Ľv-\QЯxZ-\#YA]XxMrVEo0NdlTq:EO~)PQhV_|b3T3bM$jʲ+Q\8+>>Ua;^Y(IK`; 2 I]Ew ]sfԾ%;pM>*Ot=6k[kem=KEA0Ӂ䚶zQǘ&{raÑFgk^mx #$i\a@qAD?t0HES]D$ oD;MRF`c `o!aKf-8&BR9^] we>e7RY ])6YꐸDSaeB]G^4 Whc}G6b%s&")kdp .ːyanbRJ٪7$2bWJ1׷6UI l?-`A.yMU 57ΏİB LS@bIO3pQ-Q;DBl>}_82O 8,qYO hOuCr^ANWP?udݎx#8|a8sF4-+}glR }\HCA̩ߢG!AsG)Y#^ZYFǼH9Otgf{'"A9spo \)UR nGjnPO@"h ,wGQH![>L@= =73eAikwA}<!H}|g|R@fAEn)kgS>@nY0&}$XnI rźuUJ [ }- I/z9ۯy nIr,5,eDYH#]fh$ anm wtNԀڨ~0tN ũɁY0=bc54f:9!&[0\JZ$U4U15Z6'EoRfB@lH \Y;TKuhpvb>y)]D*4w}󫮢WUHB EC5"&6![" fY՛Ps© jR17G,Z-:Ɵ}M*:;뻦N/z/.`c1{ȵ/E%RծQE:+ٽ_U{E- gn%LW5`crkeURiRa6I-3睯/OI*Mc V 4pYJooD PAݡ33 M9ۚL@ o) ڎ_ 1S+\O#C*S '9̠dU)M.,h.*ӥn6MVzMXa搉ʰ2 L/X1 &~Ò$4hj`5L\`P" jaJ2sPBxË\Ӕ* *_Fl:k|V`wɔԔ_gS$8j(H9zқI%Uv[[*8͗ .k==9(p"%BRp>39s}GNL.]~}<'r#$1Xӎ=BqOdWK5#eK:g%2knBKʴLX;R vRU6S!? 0tD$k'lkPDv}m $QX;vŔ E 3B3.HA-cd,mnp;e $0:$c36΁͝%[pSAk1:CD199oƟq?'?Gdy쫈&U 8!QOWܲ@-k)v>G20Im%N\BAl~.ɠuZ/8Ju #iU1DMd E7jAνN΂nJzlLJ3^t}EM61&,&=" -;E+u@Xm+CԴaNs&¾ s!-ywfo&t&2hS3? |Eb%#'eU>]x=bnOXPWDсDj`>ٱVm,z1)Ȅ^e ԉЈp*?c4O8*UGDyQQΆ^X,Dujfgy]w+;==c@XH`.6/N2k>|}lIANO(ڙБVG`FJ\M<@X>:O% hQ, Pl(lxqc{gy7Sߙ8x$N%2ߪඞl*f'lws?)ձ,K^W pX4ھulGzoMSQJ9x #]7`IgD-!/G=n9bIH}\ "`SYݚɟUtZ\g׻UCڧyFq$n!tsH!I  (k9ޜfn tz%,;)w7AqJȢïٟ%>mPU-|'@F%X tc6HԜltDI=-yvG v+6Kc~p?8;A9 +2h|{~O)?B+9^]!}’1*!m{SC=$XΊ4coӑz˥h"taCOX_!n1a2K\$)o#}i }~N.zfOwѸL_׭Vy6DkF_ 1To.:Z⋰La, *rmM(nzV L?j =Q-ғrRaM8CSbV(MM)Hp˯K-J[8~\-9ܭ_r4TJ=]Dmr.qT ^0gktCڰV6J*:OsSFտQ,= MQaϡ|jld 0]5t+QNe*d ~+Sc\ŏ^a҈z \jڍ$v8P%"> Φ%]hJqI`@cv]X~|ʉ+x1@T+CP*)\#!.ꫳBS&? O qk\/ZEk(i#"n+{XdA`gE$4 d -7 Rzz@Mg:%!cűO ˶vX^)e||RCj$Su9r8b4i"2 !W _wC1x8DU1i큥V@MB6㼻~ f#w?1TP*b 󩨿5 $G|$p"vySKyp':-:O";p p)1nṷbG>,mKh&]Yۇ&P*&?^pcjba"f%'媸g_c#lp0g@{2 y]6",r(Ixp|)TTqc(Rg(_2n֝%P\9/ SBD5h<-ySKqɀfW^|`2x5p-굼⇿I#~u ,?ݼ^Q6NXZ%@UكAG%I2۳^t{eir 42[4Wؘ ?Bm1lL~kY$8 4?+8R4=6cwn4B{ցA͸6& A/[JҬWonΖNLHAb!*Elt!}z ZƽeK5V{}2*ꗸ5D{sK_:4V0jPfvRI]ҹ~"S=2q4'WqdShיV^V~ 22ݖ#1l$|<b/VKRȔƀpG$i\6HEhḽH4VB06VI%|*#E&\ w4q)~WKpt2Z*ν.v'&+WP(=i] o)o_sSoU6Wpm,z>fshnзqԂω{"?^.MSƽT0;[g<;tr euiH~@ojd6Gd3 C}!t_LTӹ]t6+?r_8][gq).Ww`)gDM`t#0%23늗+mqa3+=L~2gFsv+ᐔ/NtTN蕿`XX9a|!QTSjyw&jgP䆕!VƯ,eMk#dg7O4Rn!ّ14E `}й8ڶ3={?z~wI S cU!u t5 H ^vzn$*Z="gU{ \ 쟣>$Yog[|*vJTK >1#iU-[93OP*/4RG4A+cp9:{o]Mjp薢n4v.oH:p{j( jB˓ߛHr3#+ 8^WW|!w?1_r,K:&F55Hh˓y<=ev dǪ3YTzM -sWjYC =E R9{3jCPīC2f~gxdO3>-pX8lHA9pqiݎf֑' `̠,aCFJql'k)˧7GETKh4sDX D "Nc#2+' f-Jq0׼Hs9wU1exLIIE²]יV%IlY ,) IWV_'t}H8Ĝ 2jnj@pAXJ8C*;%[NyI;wf-яV6TucB4-8&)VK54E LK|{(FR-Vt}3jG[0ASܑvg0:\>4mCQ\Nߤϫi8DZEI˄6(P7f\Ml.K/\[EМn&,G~)ŔO7-:6 x;0)p nw{PuгE7 ]̕wIj7 H䤾q̍a9z1T0P@,xIcm]Q'X(G(hC`=S>)ײz~Ug4o'[f:9MU;7eq26x#D9vy[aعNSF@LC.jd6^0Lx7'H5БYPȽ0e؎YcݘE(*o0,o&yc=-$)GԾ;6{ h#)C{1\ ףr_/n< 6?gߐh;q2I%(?S8P GTW pu,CELhE,(EKNNV lG\Ө{KjnCe:'0 4ë/d+ɏhm7;MQ_Nr7(hZ̯25pU\_ ŪJtgVr΅ǀq| 5A9;.T:K)iT~OD@Nwb](1FSU8ߑ\Ly&٥ CǕkSN4ZUr?v\xjU1B׿K UH֭en yiDlQndSZw 2ܠvbƱ d"fD9HdQ;3h*y\hY yi&5w->ˊIB00^񋲧+Q}/TǀZMT1J}z, r_]%2!0sMXE ^pLڴTnIm>["3pSi'L?0;JyYfBj~j[ NZN2S ;ٵNR,R85G72Ɨ=DTga!vP4 ~J2R~X= Caf\sۜI޲@ICVI LܸUmVAQZ'$o:A( (Q7bFA28>%'L]Ø#yV_#l0TAoM~ǚeO}t6̃ Ee`-03Ik 1,rv3ٹNE"G0%_(h? wʘ!32^dpf_{cJ:X`5OIpH^`WsX…B̽,+Da;k$᠆x$^o~/Jqo~s]ti89M!)7ZDv{uW^l5+EZhTz<]1 tw} )E헫rEQ?+a2MR  c~fziL|a(W,]ZUFCdHR`[B Í62 ?3!C:_CW,_J.a]#٭s gb`uW\4yu`zWm*)(D{bџ Jwj T_e'PQ3;C~ gw-]: :,4G/'sΌBo59k ;j*;:? 4,36rfyUe]Ll>(;E:h˼t/ݓLq[a koTdr:uɯ]( ϡ(摲|r5`B-5DKHzsyN5Cy5=G=]&Re(ʓ#DhXc2ʻr+hu'@ṷj5>f/3 Ř$A4d-p4cewG-9\S j(e{{.o]Miz˱鿢猳.\`tfU;u0e 37&_-R[!޻ݝΤLyÌ+h51/7Wؾ$/UҠeRJ /nvFԆܹzPpNC}<^-r|$~$ MDlh2CA&RhMK@v=qdm6tOPG5Bǹ8]2c{ <3)go0 ޓJ$pVO~ts$ ~Kt_.M }"?5'}c{tZn2](% v)K_'|@_~,8V<` [}mg+ Gn政_*`D"Pr} g-QYSdϿi5" #:JlA%5^wN|@}P<Ȓo}W++YnK_9Ù׋-^8ȩ']eElZP['!5)^i)g\Y/dQ b[sX ?%ӟhn:L>)Yr_-`")볓U<vv7jBSQquc&q[]UDFI`z2.( t~`!s*6ɏ6AxyAѸ oDa)?"C{|m}W^ޙ Lvemv TyFqKq&ж Vw[å0[۠.=?ITX)t$>}>Scn+)SqVн9sEbga qQUwMh'Q@0vPԆxWu{MJZ//Ibm(h(hjP:B%ғI| я!}LR==<# Nߩ0e+qF#j5V~:ԌCy9.âL^{:|=\A^{)6eŬ6Ń6r=94̦Tr8ӭ `|W13)չ \,v5shQ,զ;\Y+Ͽ"@&Bz6 Fht갚 |0ZS & `Sal-% w:vb1!ro;c| ?\a7%Q$n s\&˶9&A)Y<&\4N(?,KwuޙfdEA@$}i .(qC`έ $c!!P8*ȟe]cJMӽJP%nklo=6'Kpa0Śnk";$:6k&W1k, <2a%ł\Jn} עZcr%dٴкeepUquPhx cګ0 9(D"YD w1 ۶4-j-$-i=j1gT8.Hc0jMov)d`'t|7pCJ[mY^Vm0t}y)7(:BִGz_#}B? `hk֙"/P=5"X'Qm,[V>[yOU ?$&%I( A } s?!ed~ڥddL$R2A,o51ѕ3x*emǷ1` 11%螺I:r2~2rb2? *e:f׉zᤦ}m Ibq1Whs<{푁c {*w}B)$|/"/wF€8gHD]r"2Ç6/ҔoTU3ztf |T=NtF3Xet-^EHcR[}?=5#TU jƽtqpe[t>%'.qa3JRş4^zYmϰ9#|z!Oz!f^⧈ TM̥`gCM酬CerDo4y8,F8$s$i,|DN6?cz)!:PlOK?{q cI@Gnj^j2]%\=6*(ݲIϜj=#Oͨ8p?L3M%P̨kx)+>%Nti\ ҫ cdⒷ zB&b] n{vnQd OY:\;l!8# J$N=b=Cu<|DɳDy,f"#U4,8T&3!O8w_#& 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 cleartomark {restore}if ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1707393948.0 reportlab-4.1.0/src/reportlab/fonts/coo_____.pfb0000664000175000017500000013652414561141634021240 0ustar00rptlabrptlab %!PS-AdobeFont-1.0: Courier-Oblique 004.000 %%CreationDate: Wed Aug 26 16:52:22 1998 %%VMusage: 11074 54655 11 dict begin /FontInfo 10 dict dup begin /version (004.000) readonly def /Notice (Copyright (c) 1989, 1990, 1991, 1992, 1993, 1996, 1997, 1998 Adobe Systems Incorporated. All Rights Reserved.) readonly def /FullName (Courier Oblique) readonly def /FamilyName (Courier) readonly def /Weight (Medium) readonly def /isFixedPitch true def /ItalicAngle -11 def /UnderlinePosition -224 def /UnderlineThickness 52 def end readonly def /FontName /Courier-Oblique def /Encoding StandardEncoding def /PaintType 0 def /FontType 1 def /FontMatrix [0.001000 0 0.19438E-3 0.001 0 0] def /UniqueID 44054 def /FontBBox{-6 -249 639 803}readonly def currentdict end currentfile eexec #BA ^[3g^u^ts |ըn6Ցrl$EfGt-z\:[c<\تnВ/k1g}){uQ|['ʉsJ_߹L>Q.@Xܗ 8T&{1;Е7ʅ $gGc9U;|MY%Xd-8 D8U_ (Ju3̙\fA]0~+)(t|[tM4v"+P- lRi/@瀃,WNW׫ dkkU* yXO('Mp>ϛn! 7R2wV'^PpD]]1H8g{D9`[ Ńֻ:mAUDOP! t3 8_$`=ԥfwOa?cܙBX$[lDj\7z#M, d~Nk{ 3NQ!ITm{AЬYze25|3UIđW"խdE%q&/j{kI0״M)O ){I"x_^>ȎL֕bdp 7iXڐ\1Xͽō O}zDi֍#wκޕS4Q/6}"MFU\Jgvb5OS 1Q, TlH*˨ s=!Љat]E2brF*.\ u-C-(&>%h ڱ<?t4 W Aӕi0 "cg1VZ浆r"qXw>ػH Z\?l\qqr^i*B +#ބ_ ZEZWh۟3!oܫVWnI,uWCL!cW65"a =`a 19]Hcq}oRHs>nK=VN+ ۥUr@FDq-V:A B#!:cTo:5 -F&>~ amARY 9EIi.ՑoL^.V=෠^ST^Շi{m:PQe{})<ƝL dIRcma0(R]A;;THa {=YGV7>iCAs)ēsr8r,8'dX$da˴ arMi { ճhS ly4pfkZYʉ/t+5љPd6?m,(l~Q͹Ϲ!D :#nShCM^פ*~MK˰aRɰ*͊I,ZT^=0is4aR/=C< 䖂2'] d'3tn0ncq22}v-U= g~q:Rذz4OɑTiL>4^&M.TT^u뎅熹+ߢE Xp|;Q]B>A1+gE!0Dm{۾LerkVc+]p3Q8fBT F1 hpN"} $ }Pi*ް=TՔƸMٌWIe{׌X\nQح4L@b&w +܈q܆@i\+|p X{|sn%m{gͣyKX("߫8ϑÅYMchUG(,wj>>=9(9"OeIGH/di]gI-R:y\fGN!k Ї%G6Ma:ZDgk #"9Y,tJ&͐lu ۹a++7|ΊKK"sy(Ys&3H0&8 GgP|<o$*XLc[B#DK3D~e @殅A1H4p-S9KS2IIzңrG`W0Kѩ@!րJ.i޳ׇ<'A[@νвn/؏Wf+'miCܰ/U4p봿 nH JFbg*uҼ&L$z* `݊Y~K7X2ws(X>)D[Ldv` "ÙG h( JkExlH2L ؂\ I(HGs?۶ Č}ʳu2f0:|sCE@S{F Ec( v*0t.;ESK?h_AJbdD2N&fI9Kϭ(Oքd4br3Tmh}9l>NIGf$Zl;LfQF!@_cpq/RԸ ,RA$sP6*T a|g 4[-w37)uKF7z<],+bT߾KsOss |iooźc7Q=dQp4+QP1R,n)An%a<&f`$ɮO"jؕ q%dDmCPBvaovR7<|F[-Je $ᠿu{Ib҇3g;0]/P^44aA b@ưeq{ ;_psw'|rAB̪+sEo$0}hïbn J׾Ȼ@ۈ9}OLG?3 S)&t/^+ ՘6go|s9?zvLGrLquX)LRI& t=>1B##?8Ŏ$&~,sI$;悞 sS\Unh/m-31\2z5'1Q, vmNyڈl^P)bdc9Q=qc{ˑ̂.X4&{V\:dn$ho=S\BBs@gY\0drbC@"L&VNەрtseeٮ}$&NDUpT$!}ny l4v:NH$R4EifpEr2:y@8+bdif!D0*L{ΟJ7Sþ9a\{gI\s~ %"_cXQ{D~շ*Y\!:|mЛ'J65EWPaVxGBPn; 7%LNJ\O݇(L֘MKW8_6B+m;Q1tV\1 FlØ{ .*_Eٟ~-I5~l":8#8Re @ĘfE+̓A`Cs}X ΰPRTǦg!(a- XGʂbx NwtR. q0'qL|4C"l ͧs<w~ޓ=nڄMU1uәrO \CA[5}zr0x?{f/vAO#c} :Qm`.Wxk֎[ >Ljuﱧy{K+Dj6y[EHXDRd K#ek E oh׉`\ïJ^^eE"~1-fމ^Nq }bLϸf 7F~^,!v]ū's\oo VXMfO@fH! ;9y&81h _@*ne*b"{C$bTĬ"O ߓ~+mlJ3}Ȟ}bɑQ /2RW&۹]yæQ5<ۗs@TLЃ/KĢ'Y Ys@q\fZVj4V^.syϠ\űvZi"%EOXW &QoR03Bj}Rc4Hl8ME/prp/ЦP,\jh*#il:fx2["|1yWi G #f+"Te xЧpr Ǔm9gC0<:1 4/ۋ2P<¦|5cL"6vJU5Zto,i܌@OUU)Æx]Iꀼ@Ev]-xA.ihJcU@PkVV_mű^CHGzSün zB޽:x1߾ۺRK%(P[W)W@\T>Zl,HG Ǹ~.t^DK'nB+@B 6Mnǵ2̕Б8ʭYr5#:]D2 lAhc35S2-UEGp:_NtRYz϶BH@bUD. P0Cz/D];*rK̮:xvEl ٹ ߞIW(n;>%:j)*l dSjef׮y̺(IbkMeԓ  G7u͈©tp憃)K|{Iht<*G^͚u6yF_Ua9G WDюPQ ^O1uS|鈕Gs2z DGG *NvoNgc|o) |<Ґt(,F1)zj!}~p ~2$Ma῜.6wA- 4noi!tե/_ٽNb Vx }4qk7B/dOhz,}@(57-No",l)7F ?EwaZêJ垃T W}Н npLyK0vi#hmhJ9Vm*VpqA\i3({yR@$r/ |}EEoHuSEdO'ƅ$KaV`SDaԆ&ƽZdXَi/}xRҔb)8UXpb K2|FږHYU'zߤ0.D|}+YyK;@/f=_\xVrWFܨdn A\jԔpp&:r:$V,qyW eɅ&J40tP5ᚘ!MB,t6bU`#%ܔsſ4T^; Az%KM. j>*{M'uM k,qt8\# 4g" ,q;[n/z* 7^y۠[dz$;;X1ϔ30޾cj_5r٢@WyYiR;H9%̞H)!J1Ro4inf7dtהP1+p?KfcYU kVi8?hэ;f!R-L [(/d[V+^+1>[4mbm3NkWOyb8'Z )>tS$ֱIÌs< "{+~C Kb~>&_(OHBK)R%\q3huv%2ﺿ.W!ϫEyQT "p^Y_MXڂc1ŏǖ&PXEB:? n"w %6o\1wkaT0د$iʭ̀%*zx`9Q+-0E : +=l hAox^{+'Z+GjJ*[Rۉ]qsU gH@\o hL]R }-wJߎ']+ npt\lݐ;64@1$Pѥc&+Ys@+r4x񑠎ס[2mJ=6ÒF0\xne23 N^.<f_Pe_SjG5フ~$p(s ¥Ue,ZZr豻~^xGk5NוfaI׺[ @ قYH7ZJ;܎ר/MإZQ,rEָ| iINf] +aUi[67#vJ,F |A](5'69hFz,^cV;4Rd'Gtx4{?)G6[8é,p:XSTq& Qq.P$W5C]H3 {Eh1" 3C KGóuFs} \)l;HE:O$ZʔpsI&Ɍ"Wj&%Us?}uKGhnhh n`v:0y˸ Oխ@xS?ubw+q'$(-=NN~Ҏ%{ )܆wќz>AWkT<y7R`N%=/`3jZǓگ-e85פ<ow&YoVu\ $}+)v)uT.0KgjwB,Ko<{V8e7$EⲂ;IA"T?ՁPnuuL|t ,}y$snp%LAcSI d|rHRШ('+;C^u{y?\sl0Mn#b1d~O:k#? aZ nLqxFidHJ'lonþ9aWEcĻZVx ~b3rըWmO4 ku ѩv7F&#&{'ѸX _%{]o9+MX@'a$!﫬r9JegOH>gx8BZ4eq9:t{{޼֋[u44äN - D{ Vu~ x|TFb& ,)W:Kcz($,]5b[ѯӊeCqnjW= ꠵ڻWVuX@bZXdȐtxOjJxK#[r Kͻ@DAX¶c"!\-dNq\U|kVq_m!WovJ xך((/m@>z.`2 Ao.\,=2raЃ#8fI?/,59.7=ѕzHUlxӲufϓ28ODc!;sk7s:_cx2剜 @ܢze":rr0 -[؋F+B ~fԄ |x+6JܒP ew)gO<}Nqh2i+~, ,@^@Br55lMǜ_M}yROy-R Ёϟ5g!t#Ԩ/JD/6bLH ìV%KR!Ǽ[O_;ir[4!#cV S:Q%[Ө ߖy'іxRG4nZI/UH1!IZ _J)-fԿ[~P6d\9w7J$: ֳF|gTk 7'qk Ɇo/T#iī5cޱS۳)NحIept#nc*/n¤c~ʐȲ+IQ(0xnXe۫[6u tfYۺD #ĵ}`3SjA>[85ŒdU !FE$Um}[GvRT wa~&l?9Vys:QZqQ+蒿yJV#&3̉@ωE.'ӻ +DwnC}:}_5ߘtIx(pDQV,/hX[2\0:f>VƯtLT؝l<=)ڳQ7o;PAl^f!F,OgWsR@ f%?W-S_:/1ěq?XXz[$"lwɆ.ZWTI̲{]U U$ V5A|U^ +'.w.r` /djy.VA`c+5Fz:w= =^+1AS|nVđ13Eu<^tZr15*؄?JX"PY*uf]2lRۙb'͚^]h8x*u%Ҕ2(8NglO!>RW/w-JrumA XiAGʵ ܞFvwSԅk|JpeXFB5ǜjYq:BN@hXKnD|q(dj|-5\":ُ~5 6]}ށ Sl.6_lWF8"L7=/dGVs>bGTF!"|HP['/R=[=EA-̮c Uaۋ,Xе׽]9lõ!D`d^@OuP[9`֒znps}/dI@ר˟$ٹۣ}$y6X43~\H:XCCcQTS}╓Jۨ-Ii0`X$W܀,ἐkW\vNdL] j>LJM{|'u|&?61TegOadleR*qPȐ\<=;>|I&.f&R/F͆i*yzY2k#NS /0U袚>',.u;S=XH"@&CBIzLbf^cf&v`T @J`qRowPct VݴR?5Sh"˔ m_& j$J%(-{,#LqNNቧ)Y5;X&jTnʫ).k[<|;9"JqHy|sU oK&؝_u;'cXqGR8y6~cZ"5 v(%wo7U[G"X[_f,nw Ozh6@7ő(jdrNcX[ CvB{ i JgEtu.ل*g*# iqXS#O0^LH>p\pYheӦu;FYm/錵H`ɛtKm!m$^:Ιd=EyȒIu#ڥ-zQǓ)%]j |FRB}| j+,"w*'ezšۙN^)a R1o[d[*\t! d;kYʤlg<&i* St܌؅)^ PP(}+@V?:1#gD;$ܣIݥwFqjC#{$ݲg&pzF;[=ya];w$=P'7c ,\74ڣ;sU; dz௶[0 ,ـ#!km$pִ5ÁE2M հ@ϗ1G"y,;B_~d2L VNskt.] Xѭ3CEUzOEK8ihЦ|.崴·[Tuoy #giOF}X򚛻=<51D^D(3r(Ð%L҄Y2=zr޻G62Il |Rc=> hs  J̏?ȣA 'hCDZY012 da+PVQl!n9t(%qlop6/D~=kXljF},ɴ$AwϾg[CB,ՔXp1Z\ P[S\&깯WHyœ`2~m?.Ѷx {Zʌ){68$=rt/ HtgDrb5h/I)؈HLoQ*zc%6A ~ z9%"1Gɫq +wto/LČaKkvRU/xk4f-P.= N!7HYcQ[%H]_\?n}ɻRy {? $&ѩzHyxA[p^Hmy)Ms 0ћR =cO6gb̼r# jLg~v( q@'3Hb_(H&s,+Ɉ{SPN SgU6%qZ^v>8_t]dfzlA2;>!xOJTswkeim.?Ǥ^f,wO\q3r#NϥU5VM+M-Xr!2p`\h b9V8 *B8@Ʈ+ ג<>z72r^-$~LZ sb&=tƇۺ k<[r"QȚB6&,xo-eŢ1o4 &(sO L9lDÞΊ}=UO'WY7dݧ37M-FH}7gbh;RLjsN=ÕWI=ٰڼ'n"BqX̼0)#xMIq2 PC#ݽ' ë-̛1ݙ fLw<1d8ؚOEuSf*MPh<.<|% ( +}5^ylR=3%`ҙ,UL6OaIfw+҉ƙ;q$?.OW3K#ı$oZpXS$b>Yq.t{F"f2rn~كO|oB< ){PS6̶4mxb/y_lԇ?M#I;-qŷtpPZC @w fוxB ߛHY4e7_/E@ٷ wV`0?.ߣ) LI AB.A3$5Qx~.=OMzOA>hIy(rq95w,Puz`hH-G7-|<K8v BJcRh߇|6 irUjKXgs[dYʬaL 비 Vׂva $%lODhBot]j^ vA=,Ubw^9z 4EHcgfZbB̐(I8fj3yQk gTnFe[U>:B) hm(acAN~ ǘA N98 m{ɖi8ŭlFdhZ-m#Y[ufA'1x4@xB  +*irX"kroYQ# 1$[`8EGjkxqfsV_= $ھ^اΨ1%hJKZB:jEY0~]TF@zYSFn0? 䊦|YׯZFƘVOa0u~yL 7Dbϩ"TM7"%:s+m4E80 /MN=1QM^o84 u/(+~?ǵ&FoZq*IH^g֚!{FM%  ZS>^t# ŨJx% FZۡݘyZ1M(SO*`-2Ӏ@lV2l @;OKIp&1TZT_&Q$"F1U>& ؕjORl5:`(?NswL|C0~;&RȿP:`;?ѥazkbbXX)1-g<3LEa@S[]; UGfJ?d)Jy$8__BU薇a{ 04P#zF\vL60)vTnjbk?6{!5eDQu7^J7.E65HyKϠcUHTg07)ElC?,TR[ ޓ$7S ˏl@#]; ]Eg;W0 VY';~3IL~ĀE%QB1GO2 u Gcm)Hh !3]Խ"p#Jc7>rq312=Z9ȟu<-;fB Xbo9Q24E&HڤGW$,R([)DYauudfwi/͟.c*ndN٦?jĈE@u}}"3F [w%4 tN%(?nebIXiu?Kړ|-xr5̍'Y3 i`K43D}%i6|[G-9Ĝ0Ks;rUśxhxx-5!P-.aiun3zV42x\yGqհ빅XĢjO8MOu_,qN^oRDy_.+նf$j)ۈm|jhVO+K@МCg,Btp?6}fv+weQ{*;ߢ}|t.yɿJj`g`ɓp \[ 6DWXn˴uO sm' E4!)4g.lF. K' Ҭ%Ƹt[,vZXX,=-`> -H+0!q͙hR\V&#nȄ|wj<.Bx~iijÛ gAEA*l.#cQl}?[Ϥ2'$)kg(R H7xn+BDgM[(i)7Hդ٫/Em>)ܨZ/勺 AD_,P2" !rlP _\hx(WWdZӒF9_ђ}̉lD<4sg޼cg}#-јj5=RН60}c ^HpȐ9D'rqyvןP #vN& '֙A.)M8:$qNZ L/Ij,Xrna ,12`\,j\G7L*d,໸6ڷd=l{ r#3Af'䅛։#}*4_>odå^xou]݀&ڧ^|Rգd[ړ@PysVl>l{z)8*Bn(=kX`9#;WPC\r{0TYH Vm̒J-[+q `wchux{!DR;˪iM_rǴ!$,1hsZ:{_"i:ۚdjt5f6hϟn ͡͡b Ry]DVSD?X6eqN5L̼7g7 e35 fK'|Ÿ^qv?5J@ke'64"(B/Bl$)$TEu]~%ClN;~6FMvx0OL<%j `:i*sd U6S^' av;i:2 9,0㾁H"N9Zd3e"EMP5y7r73f%YaXG*&DtjŔ"zW .͎׹M(} R{J t`D8U5Sȇ 7T0 @,W%*#h@\ٸXq2H|&_]dN?a[f8w*MCK ߂ꓟZ%P.PF1}~z脀_vR_&Z% k}˾ 8] 7!ZA6Z7e D^Q$*JtG`xlqqf^*ۋm?dyz%K3r Y'NS XJ4=D:hQ(CZNn)$H1OK%I#}⥴K,5J6rG˱~X[xTIx8|2-AD8{Y0d$0gn`7n@Z-V{W If1ZÈAhoF#f u57sy<TpnWk`5PkޠFUguRtp<ی fR4vj_'1&R| LNQe)Bz5 N}sgqEa.CpT6DcwVԫalؚ٩\\ b7qy@?"E1_D{H}Fuɐ)H9q$bѦߵFYcAn^&P1]~nמY`¤n0 jlWQ<|`xf1#$w?Y`PJosefSy?<}V( `|Ƹ~[ 9z&֏4[:9`^@-D\+cMy :߅9 ]f͢@ys[r"ɼxiRA-ǴKV iX85פ<{Ӡ vm&WQONƟTG'S [qV3JUaMQf-vgIz\_xd>/Anއ&f 3yłcrfz>!7CE^oa >I@ ssynȟ5 l) tYN4=CbV88)U?z}F{zeْMB)a=\&b]Z*pJ= ezi6O j5DO'L0r%SYLFf|C6?3}zp CH(fCiQ{t}$[w,c%|%Z6C–:"C<ލ jJt3nK3CA\jԔpp&hS6.^ 뙗Us{->P 5]K>`Bn u4%$?_ťQ}6Ɩ؟E H2ie.*| |eߨoɬݳnE@NzȔo 7>C#|fԗ)E۴=ydE;^~!쩋D; CP"ndP#ͩT)L5*UOɝ[&;"f[yI  ˜m4˟I-m\z[k)n?h2LP Zp ڏX>bǒrPQ gILC:M|MY؀zctZя$V4DLn/'5 Fo$_`t%$F<`AZ R<hSH&ͭV#3&@ IӔ<<%zO5wAd̉X*zݙ+K \@!󼳛Wv!}>:xS0Dw(>68ov;L=>=C" I$Vv=ZrFFUtXTǫ/ba^FNZۤga],T [-obyI`4+jOfArn .Q8O#=}V,uSu\-0gs/enσVR6&g10k6=fٗb`cE#e41_ϏG"%t\Ӟ<鏥S&jtF>Hv9؈MhʷT#~|-tڜ 38AH@Ivb\l}Xd[+5 )"ʉ9f|l)ѾGv&دރ]ycM;Ht Is sRhO o{S_'}(B"^pkY 1e/NA^0S[,Ed&eK M E$l&쫴i`v5pu S; Uq5ޘGvۦTx`&io4hl@֖ 4H 9kgNdƋfHaF- 7(O>[B%u[߇UCf}}f|ĥ2R\}P8AkgXH}Ho;&d ]g*@Dmʡ\޾r鐭\֭rk u0£z3`6b:υaiU^w`.^9{f($\,{B$*DumFRA CIxlLb[㫢w3tʼUX뿘zEM_ O D0~|;_Òбݶ7BEG/Fp׿qƣX6Jij.T']CJDB-%]O15 2ߦ:ܼϓ]sB@2ȹ b!㰕4A`kLzx/Tfoh]]\Ǧ X0ӄCZgf]٩%:ΥT0gӬWq؇tռ: !c{k9fײ|g[ЫcqZ**z&EDl97/~ⴼķ\osei>r AG ҨGb#Nɀ^(hUeξC^5t 'Z?a 3ĥ^̐ 93CVA7</':09~Wp̩!UAbVeEjm6e 5D.XQ f;?.' XtemrENu9D+)ɧ<8iw33ȾQQ;! Ӻ+@ddD `w hn!jF8n{@+ K>0:%8nRZu; T3,uǚ͟rɬU9 /3FW4=vAbysȱzB9gMR;;0$%d E";X*pR"FbE?5'RLe ۦj q4A92C ܛ{261\p[q:  "/(HHb1$fN@~}5 Zpԡpu%K;PYbUoZ-D.뢵1S?K)4OV?XܕdZ9&əCu|8&11S7SNh={+Pssyަ&V|e]~' \1~i&8HҖ3+; jvDY0FɊFH*ܣ!nEvl'|gf 1{+v:4kw" pۻr5Y߄k.i Y]AV;hdo8UݫXXX #]RRfqqj{w|/8D6%exz]zB+>WJC,'v1LɩO݉%@%j3Vrŗ0LpYLhn%k˞d^)ff*FKjXU;gs.?AR !ѳ":;7bjȣ@91I NL=rUS36Sd2~eo_`9 V97!8 m[u-*eMد "pq5*RPW)wO*F#7B{i 򲌎uHܩ[bsԔDObܜko4q\:h=*lJF^Bsp 6dR~r\kbxwxehӖ[(q{'G=A{A^aJ5}@BȸA"I'C<7=y ޑTwkwEOǛ YGM}M4TP~+Bu) bp$JҮu +Vo|.{=}Ξ/}#ϿWrb(=VUZH,|;RidFS>C<bR8zm%Et _EP|hI n6@8H_ˋ%b?u!{(s & e,Ͱ\tSPQA%$0g'?=HR1}*l0_&7_وذdSG6+ gR531h]?*"Ll nW yAn4BVOs$,o 7;ȡA ŧS<hÙV #$-wXp{Xv]( *wiv^J-rF-Ls- h ] M5R2"h M 'Mwu$Ah40Z<1N^FM*v )Q x.E`,IEJu*d,dL EF CUA濪@f^M0c-vwYce#gSjUr0_IJ&;;܁ gj/EWpAdיOBvd ^ݔg7p]/ l2]8u=;,a"BHa }ǎixI W.2׉g|JWSEŶjͳIK}~Jh+:\ňS7?BZwbkV e0o3guBN"9]4OERRS7 ˕b;9}yrE\3~?񈆎T[OsPd]Nr-B d|z8Dm󯣟܆g=S{U7s,qA\/""ˈVq*3p<\]zXJT$`yYʇ!H֑9 I-) ܶ InDDYVR#|)G,u VIpD? *s4KFÆQsJ:"H!wP ծ娱32p^{wdnxbhP{f1Y\ %a<D;D ZIFX Rv#Υb(^H?zԽFŜy8O,:ڕ6G ;Q['g1CU~*Rwszݦ3Da=X[?&mC5!81p!f~vC hVSʙ/ǰHSaɈfÓ]2 O%iCr x "GW^LɝR5e *ݦϻ4L]Z>2u#/G#'셩$S>"5X3d6~lZRBXOyu )n,#Bc3, [BP/P&Fv[4Vz()'c~XHI|.8PHgœOo~]ؘ ,n[߃U WOٴ<~4@x>m+L⒏iΎ^5 YQB( 2[4x>E&AW'wn-Ϻm(w[֠gӡe*()4oC!$%F_Y^iEFzXq|!ۨ uj󉸽ӘRUa}-8MTB_mzFaԲ Ya~82a8-Uپ _#.<Uy6Oh>QՍguտ[xyNrjҲ k+6?')fHd7ѕa˕S nl2Q;6$%jX?82Kw=>+EX <)eZ~h^x6|ӈ\"'Ǻ_gd:,\D'+ӕ7u$RDު0TV Nb~=8c AyOkvLœ`HO`9l4B_c8$ߋEL8y2uY$0/le0 "%@(YHa1UDx8'(hiz~*CEyAB*N 4c~W`THgv3%DwoKv(՘W@[xސ`iHs:(oyJ3Ě'"?ƨ;gqxbz)L7Z/o/VWs["$[ksƳS~ n{W ?n a+ ~ц6؛5w_CxK8ZHYqn1=4;:_igYdzDGۇlD߆1ҏ2Dž4*I(D^,3ұ=bM CL+ug||U׳M;8E6mZ+9̀ ܿf֞d3eE$mPNsbCЀ b,3alW9z|ʕPn)1+Y8#y4"Z-I CAɲZ:5ZMype73@_ |vMe55WC*_Daltǔܳs٨gX:;*nAyj@!m9zH+B9ˊB/=Yd"$N.|~zYw?ʿ~ δ,^S/X ^G~].{N~˫GڧQYXLƂiQAV,";J[P_+!i=| sDFKv $bu'5IS$WӪbS"ƇP{ X$п3B8dN\qI"Kae]`ιm G}^'|7bz!S]@ (> G-Ϊ2@q斋Ƴ:: X<].i|* C'5*>ALRvFTJPTfN9J%7#$#`lSB(G⭣v@abe_ay ~:]k՘ 6=i?uJDƧk@! ǐs&u_rϼe11/hYxΗx qa$ɛ솂ʚ15~?]L>3y< N,dӜs{L&$>'qdx[ak;t 셹6;Q~&:7.f WrhS+tEKMhSKb>U7N_J} yG ^*oU4/ ^,Z+4K&zPpZIyu!?ԮG(5QFȿkOvp܆2%ɶdQ6sS+ZFhCAj8D|C03c>Bxt"g*K98[_rgZdʔڬ[R[JVk\ɩEuAn31ԩ>rC% S5MYfaW~\nB961 #XGl1 a|+I?OЄ?.sq[p z%ׁu*W奕#~EOQ;Dx\#ƳetgRHM{w_6M2B``&G+=ۯ/![U)˛JIh2xЩrD+7/Un|fzqh[t*1Do,)!yb w 9J ҖW'|h5-$8IGrduH=cL;ţT'#;#ڜNJӯGDh#UMg9 (-ENmʃk*ǔ?jJNPImEWς4̧&]v V)4fN(L=h]'R6=x ˨ʦ񺀰b9L,Ʉ|wjmU=j3Uخ۬ELW|tR-Gp6ƻ>d‰-z A;E%oLp7v3$%VL%8g-$|V5-> Ga_u!]֞7.cƙbNIȡO;;6}g^$a2x#S>>GgyMsn/I\{NDK>7N\9}t>1hq{%K'XNkZEH-*o UQ2' ,Ihr"tm) O X.ZH pexn%Rn6i{ kk9OPB;mЇcc/qWo)֡廨-v5.0n`ޠuIp`0:)W!{« mBڭ249GR]ǹ;H=ݿ3T,jɽ"jy:Xq8,0'I,ī:cP]8Mb+Q$er Md~\h7RY$?uy .@oI\'jtM-)h{3`?dMkW@\wИ˂ZICJ3`DL !P:ޢ:ݐ^J5}ta=[-c ؘ)z}y+J3& ?ٺy`.<ӴXV +R罟gk#(te;&Tfg+ppHonGs#= + Khbu|㽗1V8;x + ,L=e.v<]JAr9x(*DDCdNFj\'Fɫ(E7}>;61+Т,7z#+ᴕ&GWGXu. vQwut[OlWR`#U(n(*>CTjRK) FSTv%mյQoBL+Ӓ_@J]CݾW+&DkuMgⷪR"uw/KqE2Oo/]1Od zjPe%O}Mg kÀ1(9">~hh⟟oPYrX(v43=cmfȉw35Rx5f %iJ`Nh 3Cї:%X3X̢s񽵂!0 Z>9mf"auB{J[-~x&/ 0 Sfd\bN×~YmF%rdyvH]iqs{:;*q/,=둁=rvVC4>8 *G~}MXh;)Ӵ?3-h1Plȱ |Ot2ɮ4h7m؀oKk;`VaX!ث|jITt<4: Ggl P'(ǜ7Ĥ@U+ݥŕ=酫.JnmRs|_$YCIwGv[ogz֘ 2^ɋ)ǧSkT*gAcj-+Ө[zu C+D9,Ua/xĂQQ:L RTcŶM>f<0;U'M?Vb3!zVDjh ރvxg%QQl's4s $qqiR P k|Og<-ۑͫE2H4İz<0JCd2&PqMBYYPoL5ĕ}"1!%cd#zBHuk>#f/RP'lyv$8xkÊ>"dZK\]:3ǚMCR@2WW>2=[|Ҥ|LW1iH! j-@t3±w6Jfr\Df(HCGȽ~SVFuQ:T{FأVq"%&N ;ͲA`*V$31a3-C7.~+-b5xAKG=2:Sy-ŏ 1}1USʊpb Ϗ-4ۀ$2(soW2ds i $YqQmP'sЦUu=OMs{K% 7;Q"s3=h5CӺ2q  'eL50*OT&`Bʳ[<=|TV,"UYpH㩁ѝ-GAdJ~9 ut 16UOGQ+8:E(=w҉/[ͨS:/?]N!\CQ1$bwf=V4^ƭ0Kl$~5jl3OP8xKSpXݑ@9bXʏLX}e ;JZ1~ 7/بMLSHk0:={EڰyfB yixT9m\#qg֨M]F\;nZoJ^^&u2̑_`op@9H vrx^g6k5RE (cWDֱ) |BpU_/`:{(6U,w'3\>Dd}oV|w!{f%6@t`:렾SX*N)ˢt;FWhWTt4j7&"̜d6j=WVZnv';<rN<4 @Z ٢X{_o`t(/_㚫jonmܩ@bZ2'R+Cޱl/%'tH0Eѳb!IwiT&V#D6ApN^DẖtNmC$eU1m[|vYꍧnLOh&V?( g<&'~C&}i1KF-Xu8)D|7Ԭ\uy;Ê)-R"g1{2q=](䉘YҍC bg͙%pod;67;]љ ˜Q8yOJg8JO8>\0ceQL6om=]<(tX $N, U?$A%$wo >7q'R9MD仁F4R_d||<rV^rb~#Sy$e~~.ĺNq 0\hPk`Ĩ5J8E-34[!d[#pj ^{C~C2f=VB~~v8:#4ҧ—r="ZҢTNhLL@:CCtL6,ǻŵsj k]s䡎\>7. kcxז-7AϭxWjl)0++hn7s8Y_KXn6[%r54sURz0-'v]2̨ȓ^cBRߪ^OݼrʵqÚҙIqCE< [A$I6R+˴Hmf؝9Ӊ9C\o h5`𧉲?'0sMKb͜ GR^Rq " k BϫeU8U0p3}B{Mo&mP X@Pe ƹY1ᑏvme]h$9HPcֳފD-)hrLɂٲ wox^xZ#'mn!&>o9_Dg)iң.#UEw!'P#SaF½-¦MH7Q%|_E+WKϜ^MLn%)y&c /?Ԉj$w/_nS "˼/g~D],;N*o&r:0$nC^qh2_@:w jʚV0` (0݇@GY)Ϫfym chKԳf|E^ly\N'*>P2$V?'l Ƀ$XqàKCrT>4͇jm.wSF&#mWfah3*<ia1@oD/P,ănug<g|5Y)qx'C5ΎYj]1idh[o|?ܪ9j` ]{kI;E\f@++UֹIE4/@F` 944DfY"<8iVԥذ7#'U)sWWǿNIᚌm!pH$LyV5Aq 9z!/%哒ÿfEs8zw.<s$cU2CW)BڠW Ѩ5qU5M_GTvݦ5I.jC!*:?]rĝ$Fː͚"HxqXһm^n4IɈ`m8K+I:2DAU? [Y$аP0{Sg`QncʞtZw]wM^'ΣV!@~F{pBO֩speC@3qT(XdB0%Lj} m|^`kpܐjX7~R8<5sa]\'P/A .,ۏULlz4U}3 oyfmtN/ XDhgBzӈ[Fӧؿ@zֺՇ99`u} FI1 GTׂ*%"$*l3 CBP L:MK+Oy 9zbZ'bkG!Y~FI\ބnȭrcƄ6Y~P oܦ7e5ucNxuA06JpsT2@pEs.oMCb&Fؠ~zzJ,*h(˄RbA8宍@rm@᝶V(p,>YWc8 ?I1iY4 r*OQ'C Q% Ie, & էZ+ƣ8KΈ xWhUy%]2*/2U uI(I|ڵ*nr3A]\ pCX%N{ZQlH#䶏3X!ط{Mg {Jr=榶:oQ#ҥ^X44detikE)6sPOx(MrCuIБsG#wQHņq?S@.yՒSǸ-"&_602Mb0^Vd?xEvG`52B!:Ŕd$ |x)vj{_M:)+@o+4 [`˩}&-#* J4v-h;yHJkp9ofB0+U(z`8rۋAHr^?x 1rhILs۹gV,sh[wR(K vM 4[uhkӅ3~ G 6E[긞 M\@VGD2f="~8B6Noc652)CB/ $s=g-Ъ#c˙jV4&۱&=ǔW!^5n0&qC9ݑI!kV}P${x׭OnhK K+E\ ]Ct;ln!kg5~^ʌ ܰ=TWخck>Mq\yhʻ4(#II[ !c[6m2eO^WI5.([eSnB 1'z0|m}C "VgaR|>\gA"$ 1 6D尊c5@P[. }r?"00CYUZ\hlɛY#hSuFR2fYAUK9*;&Q}|9&F}JjщjmBo#K2E'8T e=ì#U`qWӋ^/jqo1J?ݼx'7y=tu,M0܊v84.U(|dW- LЯӤeܓћAc9A&K%O7*Ư"w_X{^q T@H,eE6"]_Bfq@K3\8ˮ|14(aV iՖÿdzElU.5=XIeQ)nyaI} r2PR"t/mej7/}hXeAyJ>|̼⾛f\S3&lve[<89rܾ5 dQ7__yDdɾN%Dl#P%0 1*՝< `<|YhPMCHM8Y{+·q̙ ~lⰾwLn&˟[B#ޫtg%BkKWeS-ML,`_7/Q={jU~[n5@qHjYSMhs1hS4pkgQXz ?uICYHaY8̫JKK7¡l6I^ WđzSS;^$e(AˈgXEHPyScm 9IOWCZGP7@sa[p1.7%?Q^HmqxAYr*{ D#WA\A$.W~9d CђMڒ(1 `vf"X jqg h5 q? ÃŰYD&M^%n&unZ輈7\TI}/0+ 6VbBQ0{gXpvbzf)ΔWf~uBq]F&xD'l:b/W -,yZRmci;G緅NF;0Xc|Ss+Y>6LW|a-0M35m<2_v~*Hh+6+B;"{|>-MmD8nV[bNnֈօ*V40VNQ#sH'<)T_Ճ i4LcI75.~ؚǁF4E;Ru'-p]68%?euEwԔڥxq'&sEKn*𡱴8{ۓ֜^Aom+a!gGHU5zH렲?5߄>b}%zC{6nS.u3sF-Z1cdwF-UEQkEop+b9xä0Gq!X;ivCaS/dº>؉%ӗ]p.|P-#]/ "xY)Hg!ۿ|\V$V[t/xiԻkUhE̖hNDrH6'.JO' L4^K_ զ"Z%aX⽦pZMf=G;0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 cleartomark ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1707393948.0 reportlab-4.1.0/src/reportlab/fonts/sy______.pfb0000664000175000017500000010362114561141634021242 0ustar00rptlabrptlab%!PS-AdobeFont-1.0: Symbol 001.008 %%CreationDate: Fri Mar 28 22:03:48 1997 %%VMusage: 30820 39997 11 dict begin /FontInfo 10 dict dup begin /version (001.008) readonly def /Notice (Copyright (c) 1985, 1987, 1989, 1990, 1997 Adobe Systems Incorporated. All rights reserved.) readonly def /FullName (Symbol) readonly def /FamilyName (Symbol) readonly def /Weight (Medium) readonly def /isFixedPitch false def /ItalicAngle 0 def /UnderlinePosition -100 def /UnderlineThickness 50 def end readonly def /FontName /Symbol def /Encoding 256 array 0 1 255 {1 index exch /.notdef put} for dup 32 /space put dup 33 /exclam put dup 34 /universal put dup 35 /numbersign put dup 36 /existential put dup 37 /percent put dup 38 /ampersand put dup 39 /suchthat put dup 40 /parenleft put dup 41 /parenright put dup 42 /asteriskmath put dup 43 /plus put dup 44 /comma put dup 45 /minus put dup 46 /period put dup 47 /slash put dup 48 /zero put dup 49 /one put dup 50 /two put dup 51 /three put dup 52 /four put dup 53 /five put dup 54 /six put dup 55 /seven put dup 56 /eight put dup 57 /nine put dup 58 /colon put dup 59 /semicolon put dup 60 /less put dup 61 /equal put dup 62 /greater put dup 63 /question put dup 64 /congruent put dup 65 /Alpha put dup 66 /Beta put dup 67 /Chi put dup 68 /Delta put dup 69 /Epsilon put dup 70 /Phi put dup 71 /Gamma put dup 72 /Eta put dup 73 /Iota put dup 74 /theta1 put dup 75 /Kappa put dup 76 /Lambda put dup 77 /Mu put dup 78 /Nu put dup 79 /Omicron put dup 80 /Pi put dup 81 /Theta put dup 82 /Rho put dup 83 /Sigma put dup 84 /Tau put dup 85 /Upsilon put dup 86 /sigma1 put dup 87 /Omega put dup 88 /Xi put dup 89 /Psi put dup 90 /Zeta put dup 91 /bracketleft put dup 92 /therefore put dup 93 /bracketright put dup 94 /perpendicular put dup 95 /underscore put dup 96 /radicalex put dup 97 /alpha put dup 98 /beta put dup 99 /chi put dup 100 /delta put dup 101 /epsilon put dup 102 /phi put dup 103 /gamma put dup 104 /eta put dup 105 /iota put dup 106 /phi1 put dup 107 /kappa put dup 108 /lambda put dup 109 /mu put dup 110 /nu put dup 111 /omicron put dup 112 /pi put dup 113 /theta put dup 114 /rho put dup 115 /sigma put dup 116 /tau put dup 117 /upsilon put dup 118 /omega1 put dup 119 /omega put dup 120 /xi put dup 121 /psi put dup 122 /zeta put dup 123 /braceleft put dup 124 /bar put dup 125 /braceright put dup 126 /similar put dup 160 /Euro put dup 161 /Upsilon1 put dup 162 /minute put dup 163 /lessequal put dup 164 /fraction put dup 165 /infinity put dup 166 /florin put dup 167 /club put dup 168 /diamond put dup 169 /heart put dup 170 /spade put dup 171 /arrowboth put dup 172 /arrowleft put dup 173 /arrowup put dup 174 /arrowright put dup 175 /arrowdown put dup 176 /degree put dup 177 /plusminus put dup 178 /second put dup 179 /greaterequal put dup 180 /multiply put dup 181 /proportional put dup 182 /partialdiff put dup 183 /bullet put dup 184 /divide put dup 185 /notequal put dup 186 /equivalence put dup 187 /approxequal put dup 188 /ellipsis put dup 189 /arrowvertex put dup 190 /arrowhorizex put dup 191 /carriagereturn put dup 192 /aleph put dup 193 /Ifraktur put dup 194 /Rfraktur put dup 195 /weierstrass put dup 196 /circlemultiply put dup 197 /circleplus put dup 198 /emptyset put dup 199 /intersection put dup 200 /union put dup 201 /propersuperset put dup 202 /reflexsuperset put dup 203 /notsubset put dup 204 /propersubset put dup 205 /reflexsubset put dup 206 /element put dup 207 /notelement put dup 208 /angle put dup 209 /gradient put dup 210 /registerserif put dup 211 /copyrightserif put dup 212 /trademarkserif put dup 213 /product put dup 214 /radical put dup 215 /dotmath put dup 216 /logicalnot put dup 217 /logicaland put dup 218 /logicalor put dup 219 /arrowdblboth put dup 220 /arrowdblleft put dup 221 /arrowdblup put dup 222 /arrowdblright put dup 223 /arrowdbldown put dup 224 /lozenge put dup 225 /angleleft put dup 226 /registersans put dup 227 /copyrightsans put dup 228 /trademarksans put dup 229 /summation put dup 230 /parenlefttp put dup 231 /parenleftex put dup 232 /parenleftbt put dup 233 /bracketlefttp put dup 234 /bracketleftex put dup 235 /bracketleftbt put dup 236 /bracelefttp put dup 237 /braceleftmid put dup 238 /braceleftbt put dup 239 /braceex put dup 241 /angleright put dup 242 /integral put dup 243 /integraltp put dup 244 /integralex put dup 245 /integralbt put dup 246 /parenrighttp put dup 247 /parenrightex put dup 248 /parenrightbt put dup 249 /bracketrighttp put dup 250 /bracketrightex put dup 251 /bracketrightbt put dup 252 /bracerighttp put dup 253 /bracerightmid put dup 254 /bracerightbt put readonly def /PaintType 0 def /FontType 1 def /FontMatrix [0.001 0 0 0.001 0 0] def /UniqueID 42996 def /FontBBox{-180 -293 1090 1010}readonly def currentdict end currentfile eexec ruRfљQUWi2v=Zeoe. V@0[jߴ l d*t.j Eo.edv6@"?&m-6buPS:okox/#3Ghrp q:ʹ@]N1!g0Z4)P-rir,X)vͺBN:]Y-9+nʍkϗY pO52Df[šHuҘQksPwiH O VbCjĦ{dU8lNr1I/kFw2#Qwxt^9y}Ҳi0,?[\/ɔ cJv+ )Boj'>QW0-HPRwnO܅a&;R%-xRR%}*/wX*`=)@)IV$9]qAr84LFC\F9=!7VT)Չa<(Z}W6@<>L.>gd%1 5`wPRvETV)}Zo9<"k?=:;Өsg uhr6{aNS-]؍w?Czh bDp}gfZo :5(fY g'qrŪTZ%S tM݉ $tgj>CF\,/d]0St7K&Bu; e_ıycR$SY_P ޴Xwg_/HtGc>e5R7>ڿ*2`{vT%4M_SwT X*Pa0J/99ڒ"WqAXêyQa_moԈ}n5[훭V&LL0v?Go q$lzn5:ŀ0 Kgk-@qw{=աNy:Y2s2 ݽ)vBy+2 g;ʣvO/__˭I $g>6jm{Pl6;ankͰ(=Wob}Ӑj#3`L7/t&ȄL?]s <ϝ)6C~s=puQboe<.Z_"?%Ag+=]=(̓sG|%sq1=ol߀(J+CGHM:@ˇxWݱ&]ڮlAĀrg3i&>LQwg5}bJ|wcZ6V1}E dYbOb(x i#DhTSEu;-}:0D?|zLk HcB'mTp e5*R+vWљȴԒ{4`ASB8`9ٽ/(Q7tB>_8n5_]V&|5l'W3|Zx"C JWZEQRYY3. 1p (#3َ呤G/h FØYw}æ~TfO{N`S5X6?v;t`G#ۋtn{{4(ݾ "^7;pNőow^i3q[Mٻ\33*{]~ZD 2F}[)@hwglnMrp_ @5PzWVnT4k5{"K?9eվ_-]FoH|Z6o #@&FLgVʴ#2fb3ymGbQYR kyZ$.lK,PuXa_2x ZූFyk0gM %J\ o;{NDP1DܧANN7͢OuxmfnUҸĹ^$l!#U.\_{a|)Cvg Pߖ;[w} -0 h>9y?@/~#L8fn3r糿vsx)qy6ɞ]Ra/'_>=q::-llWW˫ܖ#PM Kp bт[5}R6r=E3āƬA%%󇯌/Tv~AZ7驻 5}G&}Fj`)t4=Q4.$ ߢ[a:IkaH5Ϙ`\+ W@/;˜!8g|IaM8O Q>'4u6r*ڥCq {65*H7e#5iҗSLxTbgcǽMg⋞થXఘH_ _M@v~Y.5Tz +/hɌƈIB_fh dNC;=VOǿ-}~9^MvJ 5ː@̂J3VLy> ׾}ޟH露Gۀ{ZYD+/\w7r=[5*i.|M娘08>5^mq.l} w^7AJ΂y:L![t M~3{Ž8+M('Ŭ"uٌmTD|#]lOԮsp7 ~#4D3;z<.|ŕDz0W\\`YF3%/og?WirO4kp{{@0e|9OKFIY\5cJDXh5 Ϥg…s2 &M 5u.ӮA.BIK sp }~hgI*rr:~P2~r ʓN ZV &b媏AזisޟשQ4=67"X eT蒫Hh9'DcNJ$g?ˣ O2 :0f9ݯe'bc;+WöISX_s!ga4.lV~ M_z1J91/uIQqA˛ijZ-bc|h ? C <_\H%JFʹtч'ҥQ*Ԥ@OvRVbY|Cg%7IT`>6MeB'AjY}#K(Ѭ"dl(xf7O{<Ȓs|zҧ䴟%YE8v*i';)/sr Q?5[@.gV[7BwU/POY>Z̫3,BsAa:n!bF Z<W5K6xwSu.qޖF^yb (D Crq֑]r^Hٿ:dz(I(vۥȅcM' ᔥ{3٦fQr9+v~][MBI3]Ny`!1o% ![om[@[zl45G-Ix:^m?$}!/+y-;]lGX QVvGV?@-{HMU68:lOv7*F;Ɣ$+}zӟ_M%%xv&{nAij{*YJ UJͼZ-kF/.Ljkݻ,q5,Շ]ʞ Wsd{pbz*Cg*-o>Y7ǡp`fBBcs!TYlj+2h&A'J(o3F*eIF{hsȬi%3ab(l‡yTy.E_;XGPO;)cG2'`; X8yX|Ƿ]Hrf'-jY4aR(Z>2]H&r}VE:IIז- 1 C!X1$TB@}YkVqW:}ozi2Po(#ҶQrW0B7{HFqg)ɝ-0MnRֈVu8y:84y Nu%蘿fJdaW ST@S׆e̪:-a6R]|h$B9f|]5Hr.I՘-]o棖N*S`˾w^:ӚVN`@pַ%Uuua0W򄄾aTR樆VX{ju(x5tᕄ=:*viHi\#c|XBӸ*8dJm(@BԨ<hI' {3AfI}]lթsqcі;j2zJSsC43%Oʉ%>WL5/E ~5>}ԱY}t.,f@ظ\]Xׯ,7+ 1h]a G$3=5ZOϖ:!ZsyAoZ %|YdOX_?(A*.sxho@DJw uS..+OL- 06`l a0;{ÚxxI$F-#J =4KX; Cf"t14+h8 zf Bsc?UEQ6 u V$ޜB#_w~Am7"Jou(4j@ggL  s'ncG̱IY~/Ҡċkud| ƨo׵7C(=>lhcb}4ˆ*Va(nN3f,g=7"4|W_*qXL ޭqJ{Or_ZMPiw.Nd0m"$ ^2dU$>B7 m1pmX)=Gzj"8Jzm0xg׳D%KV9rB1PĦL,4ѱ<4cI)FHde.%jS9VsK_r^@FUA;ߍ|ַD(7k| ^O^UU?j1NBȣ8">=M!J0!cktoPT3ɪ L~@' sUK&Sb[IףbYDKh&ӽ2Sy`w P[D0سZYAv!X]'Xel3a$V{oԺ$EZUfӫ85HJWO2s:;x ~0/m~X+fIc@1~Ϣ`QVaC*1-Y#uEq:;q{Z~e{ၥEYj}4&-f@M ?1n-HP ]/ҺuHZ|V>ҕWC6uϷ,lCtʒ=D,~Z8}+"B;G /U-H"_:y|YR( &F'~&Ȥ4ԛS4Am,ĎX%SlY[QKt[ ]CZKki7~6~eéQj D =B"s`1)?-*<+2&<]WxL4HMPpy\h"|g1 "j\P yrN"xP@t#~5jSˇ~$=3`s@ ?MMu+I}wF)^8o+Axړ/opU]GV+4^) ﵿ~ҩVe ksv9mZz'mtQj8/́:[|v6r[a_>X:D``/Ñȅsjv*C*ّOz{حr})r/3BLEDϹa|1F-+=ⷃBvdGV+/z"?TN@bqK86b)d n_sG w@#=I[C?TЃ` Ċspxx.:x׀/?g4 /#gwH"2HrIgOOȐz!A&&d eZ_*;ƞ4Opk+LEuao2[XRal^¡ 4Vadyï~v2#,`ޜ'-!:~ljHN;+>6v~#ac v6d]mՑ]0|Ev@> 4& !EhP.GIZ-Ӯz/(>X$zpQ׀ldn~xm$d+GڈA^e~\y_?*@"ե-:\Lk}IH& fΏev5U$)7'{Tɦ9e///7y)TNN &L#`(q|^E|C N5ѸU4|ɊRm‚1*:/uzNXggt""V8yoǂ(Ay} 񄴆`I ]GDY`~s>kz"C'"(iĺ)*56"牟 KSXp^vґ,o9w`<#Cىq `[%J 0&{Ʋ!: NsgdiW{vYV?ۭ8_sǠ Dy% J3kv]ٖ w*U^֬y  Z.ivFaHf e!pQwRi_C)B^E+Z7b,`Աn cy9 ^Mg\\ʵÓ4Y1gm/u'.Z-|ۂ؂S}3#Kk^Pڸ{էoRQ5"/s>%sVZ5xȂ":q%}HUĮLPՉdLOJi#ob4I[O1q7k<2m._^¢6jeR0N]vxv< _Ayv0OڐQ aۥDNC>GTsB alO'K=0OM>16y{XU 6 z\_V6Ўk7pD!D'i Y׎,7p>l. F> :DRW=IJp;L|/A26t:<2/HYvRϪ0?~/Zg 4Or [aeIu^2lkKFd``sS=,Qt֕%lb=sZz1X]WNa2{;yg?{7\msN:ׯi8AT\iʰ b}1#_#P uPSs1 XѲG5YvVf!RZr^]Zi} )KxʅJv]ӦTdcM4q3ߚhn̿nhW6w(9pӹ+ *?)T-Bneh/ULP%}`V^:))W]pB4rZ2_RoDwwxQY )vꄻǕOk`. un2LgFmg! Zp`ߖGe%?/S/ :wfdV>֛0j*?dn(n\2QT~ڿ(GBTYK^O"ͫ=Eb69|QM5 &Q˹q1NZy}P_JB0NTHm<$y+"G8\UPRp.Uh"S2WN+'u7"Esf%wz\07Q+wl.Q\NUPbϦhu 4«X%b4X)ny! >dBf',jO!JEdUu vdz lu>(|v\s? Ìa~PC} ClG, ^KLcN"s(Χ PI^X:\uALW}:?83AE'$yeI1hlw:mZwbc&? ֋;䎥\ Zd Bus Kl}{ٖ<^yFaLJHBՈg.0JΪ+`Zl&wtGU%|"HkX@7Dg{dy4FDr8ZݞA[TPaKQ(Y=# DW8 j0V[a?ۿl#|%ݎ{= ÉY79[Sط0[F x!+2zwV2,""(D sb|w[|l z΄IJ fLsඉ[opC<MQ%{O喤=7o/-\M 7q^,O3$ ]I~ e")] ^rnˀfXx0w:iןՍzbK>D*&nuu rG.2{Z[xX)D32-,ٚv}"9IhE!Sq"{<7`HY*I Ob.q!KqzuO†tm)WUt{yGkޞI$}vB4`IN<Yv͈&ihdzRВGrY+q a"LRoJ!a<0U{$U*^=:wMj%% Yo0Oo÷HMOL@Eyqx/V3?9ɺTW0X=C}VKp.f L m]:g Q\DbzĦJws*Ȱi|S_ E 5!3@Jֵi GODbhFr`,Q24ILKyP~t.䎉eICV s:1Z"HR /QF:$ƀh ԛ2y#13 -u(w⫅O٣Wwݺ\-WJ^İi8 :ڒg=E"_ ńC+/Yt-xG;Ç';! |irPW1?G П=]Ȑ^9mU 5c7rQҊ~:wYwa-N̸|$)e@Nnt"ͯ5,3kj9PըCd{:9CPHz rM5dR.h#.-U`o ,|eb`N$^<+ =t0(!KL<{ S]ph9 +)/*ǕsNзY(aw}5"[Ph)f9ZfD*(*RQ1JXh ځrՏc?Z'mGa˱->Hh'@c'9^U+Q8PڏBS$%rp 3S"VŸ.A΢ ȮB$t/]6;2C]*%)ߩGX GP9&C_{B++#IzMq4Rdo[mnU`rA~lxsGz6K'.6*$I׺ a:P=Mdz*YNfEyd|ò$;ld1G EiaXWHQ1vOoug&ZxN:,6N-g`^ ! 엂 Z>FX- [L4q c|Üw mշڋYy9ʖv>sag>\LKlcE^Bt}:oIݏJ(TwM7T)ߪ7pq8&`Vמ;j G {))iNM|eϸ9Rk 񡜞NJ29i[51 ̌A$͐"\݃F胃+rP|r,2e]nOM$«cvZdo劺ovduc;UKPȐG)41UfjӂbhAt K|asJcYC%C\[&I$?0.dS!PX˂*|skR}NZ. i10Q&_EiV@ *@-sD%3i'nX녭H+rdKF04d6sdu\L_2;qw8%pk=)F+> %= ~kb f |@&j~PV!y Z;|WV4}w]lzlzr] حQ.S`6Ϣ<X֜)X4/}%CW{M)~M܀ڱrB߱ mRJcӎaGN .ɫ=sy=*yЀT998bUDe_?d9EZrP l&XiUfɥ0YIWƅIwhQs$0孮jmYR7SE0vbL=1;Žv.C[2ZzV3@j|uQ̏?31@MN@ާ%h0D#J؆Ҡ w,#248Am2k#еqvߴ9ģGgK nJZnM]H _h=Bwg?@"1j"P{C7c`@y~ ܡRW^Xk_+\9y (CV/n! 81RO C +-&ʕ[ IUȃi{@x*d4~.r7+U:{>@M] 14#Ta݃)Ҫ´{ k!Kl^u:M)SK:|0ΰ6q(vݩ^Tob2ct;Z3`}U6gKP¯Grf7fL<;;dDw(5n 8WpXu13|h’]2}Rkkmm McQh8g}磊鈥t{Y!!&u߱p7'ZZ{ ׉>^Ib+ 3*2ϛp1Li6)M"t @ Ї{^4Ǵ=Ni1r^chdOvLK?|LTvŞ&)W9N.ρ~HM>re.5c 2,5 ޴fv;Vhx$c|mEe\YJeZꉔS7T?IO?53.~݈]=d82rNE&WWW<وձdM.泔pcy><}]kZ,0:ٰY4B~\5ʨ&&cvy8e p LSЋ矞^wtPA #2ŪiéUx! $n5)&xݐ7JIŹmәh6 3Ӕ1gË]2rίOi2&`M6\rՁٔ Ke٠0&b L6؇oJiojzMS_}N<:DtC T ȼq5:җ["յ%rA/}wFkvFKYgS:P]"YpIYlޗgu C^ԺK+!(] zX#v i}R*SV}GDZx*plMQ] \/S,†Ƞ[k;*PBLE_nJ|H'#6-٠_Ǚx pn}}M%W+='\l9Lg8!DiaF}oo8Pmn|W_'mL>f6׎y]k%kLȽm%oJܥb*19 65D/.O*Rf>aG=6\PiqKSJ x.\Dw(E74oʁ+}M̔BgLmJq:l+aNf+EjC-\xs.DGFNk5; 0h4:܀II_:Ȭ9ц"M'y#̗igy[Xu7k3;KXU%&[Weӻw[5kS$uz\F)uU wքZ?ZcफAIȘ@-' ݪlEd_Yp7ddb,Ym9"KqByEp/jU A }Jk 'm/3:x.̻ gy|g :BqT?g4"1!vAgs2$fʗ#Ѹc!27t! cFDmgZPm5 m*ii"i(K߁vWe&l]lg'Mr6V3QPGٳdwfbyDŽNR5*JJE+&lfh)c+̅DI|٫$rIky*nxBdR<>u;/D`q^'r``v Cv$'AQ9CXr2qD(mTA &pG}jg_:p([>%Y^4t>L~$bnYVg9o<:@g(ere[#ص+{[t_"}4>r,m6AɎ"t9Pm5pg8D+>^_Z!F7G)4fW } 8\s3d.7HJKH^zWsx>1ZGc=@̂̀]kkbmfY/<>G?'98|xrz>&vzVe{P;F1Ux<TJH!ӣRs> ߽٠sLQ鴫nOV A+y܃ζ'u#-%cTszH 0ފx7<,[+C߇4)'Z&Ћ\.5cՒJA;ئ 3 9*}6Yq ) BVj>w,n15az*L!pjV!@]t0dKg|(bLZxL@$c!D!&Fod-%JRMtQ8e˻024PC)R?tE~"MXz2O0% ׶Ue9TXCofBwj?bq֡n3* kx+Iyo&8k&Zd#n/|\smݛۥu͵fc i'wt/xYB {$)Oy%fnz9X*4T;YR(%.? %θ)FٍR++dmnvo;gWOKI+<Mu~x[ߠHXڼPB=pyꢸTLF2(1D"uX~Szܲy8ۏ/gB*x Ϯ93(g'3<؟ 0.sgLgx'N64yH)Qrn"y2c^iZ.T}G>Y$;CFO7ENm\oK`*5A|#Nɹ&3 9Gt]d , eڟWmNy.R0R dfL*̙4\O(c>.h-lRf[77v ;#d`bb:h9{ĖkBveCkWB[찺 ᕔ*>S&;k~4ܐz,llFl O,`63%1&C~-PVx;r$xh%/0@Qz-."\Kh3,F|Ցϯ9 @ЃRY.f@d}~_QԈWf ]1>zIp/̿" ]Cݽ7=$C.3(\Bi*eaV.MfcAS/!Rzgrs[h1fo c"ԛWؚdG!G['|lZ3p-|ٕKũwT&ER4y.EDۅ$0kֺ ]VeALsO'+"l| _{VXBP~et0 iu:<^/K# vU>F0A v=A [vr7uu?BØtӵTL0c0j10@_<犮,%'6k .)Kwߧ5kJV%Sx<$pZE=amFM %eB;hg|x~]4~6u1ld@Sz-rX͔+Z6 }5VJ:*%Ib.z%(.{yʕ9=_HAܤ*t/=fxf,$ՖZ-p5K<.K#ufK"Z#F ^j|NS6M#6,o3T 8K2EA8="dWL_uOv!t|҂4i99jKU(W߫_dc#BHޢ߉@{_Y[RbcV>1AX:!f(ER侐Ss^ֆX/y9 ̉H܅D-5Җ* –?] 9I.0 Lw:Bc8U p&Ɂ-`2,b:7E'=oq$-'Ip^̔pqIڹmE+gZ)= ;?Rcf'[ -j!4Ș-Lp#-J{6#%6=MAFn/6GHb~`MnN}* +ݒHgef=G, %>arU|5 AsBpV棽dr>:'ħ#mN*gtf2&TJhHBNj^"K!SC J# >;gAYFGiNwR>~d3~'0@&^A)hN/;\9Dű|3AXqY47WOQ[ۓMF\M\FRmYV{А~:gzX٢zQ~~8!лTqwsh u8 K+ z<7:JKBKJVb v5sg2,|Uq!OT2"9;r1Q ]Ը3ؘH,/sqw1L5zZRx&8F87X˫FGq%-MPتaڈk/T=Z plT0ŧ3wPy͎Pq,rq(N"ʔoRJk8/w.aCJ~B06I8.jKp?k9Z/H gqt!:fa[tw# fu=^ .j'f>, @u1ɪmӵ5E%hO7Oǂ;>E)/wf'gz2Nƿ34)8qFjk&JBxXhgwJM 'VK:t;*)B 0- u*tvڵhWb&izK"5SV)F U)XBBlq< Xڹ㞽 j  kEF: y.(,3 $N:@[UpqT'k7Ac5n9c)&^7%i.2^TG P_zVNՍ5jl1z6'h;HElsqClhAh38a.U_ *e)1*/Ts)ܙ9>uRܘi}t9pr*"0X[ka`a*e^_-3ڽd;[4+^:7]x] %RQ=K9n=$R3+RFעrgē-^3]եTcc4A4F ^҉[Ѳ"&p$!'c9hU CRSOLB^ˏnAÞ)]`=~Y"8L}$|٦LjZӍ?+유h~0- Wf!Kx~M[Eſ2&3R|{DN ‰ %MMIe#6 zˊNyn*.F+H3 ^{ b,.i( ڵoI|i.RФ҇? LH#k\v C-^'\cF|eMC!c"=\0څr=? E')wbuY%)8ⶊ"'vBLym[;ȉV:=JKkKű+x4xTqȰ/hiR6y>B4EB%%=QqSb ?g{aVC# _1DpZł҉ c``+J{ y&#s6IslZF$w'x3ߪK\v*M'޽|F~Yp9=%Njjr("4*.y0Z£ Zڢ$aHZ˓e]8O%kOg3Bhl@97])B&g&*5D ҆f0^sQR7 ,3FHC{NDܝ~$kEam@rYfN<p -ŐMOw܋"LB= 18)8 y?ΰcfbh{_D IM \>>gbt枰m"Ikn{PJq1EؖI7֏ X_Fƃl}X~@cdztej̗mCOI:j#,3G~]+;zCdnX K~%=my*܉v9W˥Y`ό+0qؽb5;"o꫖c[v60jO֔ȁo =HCW, ?dJ k.DsOޞYA˹wӞ5gc-UXu{+[|K-ygj[5n㯠,/fFrAQ,Os0r7lu⩥㉶T[[&|؂G& ,4A@I1E"&Mi} (:Y PCiAy>w/~Y>U׾1`Ug~7dQeI0Y& H)\([Bg]vJQv #?>oQ0oR ԃx%x |IMr$>,0{]c)H_ʦj_4Ϝ-Z?gԉd +30}\n5rA =0խ3^=HK@ aa5NW>Yșsg9hʙFlqxD` kYߎ"q _aj#V1KMLξSQ5Vqm~#tZ֫y3U3" uўGBVA B>oNy8Ԙr2k`R՜..)e#7MO؍/'}?KtՎ܇IOvGt%0'Цܣ`T|?IlgSQP=Iړ򓇴@s8[D`׀Č|Ggf49.1 4-{19n]-ߤvٜx_ fb[췜4yE3Zo^vK ɎS)XK}b>= ܧ!yu[ۧjk"_eD>va +ʹ,DC 5+x:ʃ*'>SF`…2һ $4O|'ۖh|~W7M f7siN!MVZ~mԃ1FK;$.st|\K8 좘Pvْ KQ2$-`gu>xl{Xhr+ g%r['=GGtN˒y똽ѥiCZi1TW =yPqZ@b.c *u/Z&^FhUO;~mI~>SmkU9ju,/f ؍v拸u%WQLʜfLs9O~%!H[œB2 OoF*䚘nc7ĺGoUUAń;;҆fK߁U~UEX,6+97 o[lnyǘ1M XHJ$ʈ_ yUilӓo{^c,70eY;fbݓo(ݾGf}xFtWG幹Q$!S+Xh͔`8A C}{;+#09oLUW<FMȼz?5lz%@|~Ry=(g in;yczx5Yd.1GA=[E[L8KSMjV6r!҄/JlF0e%9>%˫~y窋ID\;v{)B \IY6TUhDbϟ!NߤrF3Oܞ<̚p{k B|v.(fV=ZsBdu4fXrO"fN36 %H1urk9WUOq$ [x&i0.Qf@xq2thPi F"G \I=v2aˢyfiӞxa%ltn@*JڈX7>qRW~~V%1/ WC*E(qD1]Y*Hu7/J(STN!!ۆV\SWih|5^G.~Lg/O]p@,SZeO=]8þc꧋L&p< h}KqFHf#p~j4%TdSlzų,Ë@J@b%}kMs\aѴ$70WYXz @T'v5B|&'i0!yFPLHwHZ}%Z0zيG[ד>]>_@x6#VZFe_<:b4JUNcXCfzK-/ePvwWGM&~X9#*Tf7.`a? |e74x6l۫֝]P17rTOeiNӞu+WT?$R,*%pOyJl/x,* 0Sy A˳QTӮrP2E)@ NIrgW΁ I-G*+tSG> y J:4DN#ږ]PEy*,`R"=J{' ErP۩)𚕿yZJ$yۡ7Ejcm ckZ{?}L:ȋK)8eI|Ye).P6'5G85S{/,*>rQ[$5ESbQ"tNTί-p9nkڑ}ngskaN0aCEaz_ETB@;Jje}9nv:ϤA8A;œƜw%i4tS(OfqTdV-簾zvT+aJSUK33r2;Oߛ랳:SZ %xO %w!U򾕢J+ Pȑ*HPp bzw~\,N  !Y'52f)¾z7։Cתkh<[˴)MIc(ɽeP\R.fu|n'i=ѶY0|Fnxhd(g6۱Õ ŞN_huH KLT9Px;tc@z=M nY 0my֋3P+̈ }9OX_aX;);.nVtQѼ7U =1p<FEZ9$@gF > &|K\\jAqLm!b(Ѐ_і^^ "S)5|wik9Zra4wdWwjW;Mzcd,',؛ 9ia,Ix{x4J2rP,&nY"1 ԋ0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 cleartomark ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1707393948.0 reportlab-4.1.0/src/reportlab/fonts/zd______.pfb0000664000175000017500000014067114561141634021232 0ustar00rptlabrptlabK%!PS-AdobeFont-1.0: ZapfDingbats 002.000 %%CreationDate: Thu May 1 15:14:10 1997 %%VMusage: 45775 55535 %% ITC Zapf Dingbats is a registered trademark of International Typeface %% Corporation. 11 dict begin /FontInfo 10 dict dup begin /version (002.000) readonly def /Notice (Copyright (c) 1985, 1987, 1988, 1989, 1997 Adobe Systems Incorporated. All Rights Reserved.ITC Zapf Dingbats is a registered trademark of International Typeface Corporation.) readonly def /FullName (ITC Zapf Dingbats) readonly def /FamilyName (ITC Zapf Dingbats) readonly def /Weight (Medium) readonly def /isFixedPitch false def /ItalicAngle 0 def /UnderlinePosition -100 def /UnderlineThickness 50 def end readonly def /FontName /ZapfDingbats def /Encoding 256 array 0 1 255 {1 index exch /.notdef put} for dup 32 /space put dup 33 /a1 put dup 34 /a2 put dup 35 /a202 put dup 36 /a3 put dup 37 /a4 put dup 38 /a5 put dup 39 /a119 put dup 40 /a118 put dup 41 /a117 put dup 42 /a11 put dup 43 /a12 put dup 44 /a13 put dup 45 /a14 put dup 46 /a15 put dup 47 /a16 put dup 48 /a105 put dup 49 /a17 put dup 50 /a18 put dup 51 /a19 put dup 52 /a20 put dup 53 /a21 put dup 54 /a22 put dup 55 /a23 put dup 56 /a24 put dup 57 /a25 put dup 58 /a26 put dup 59 /a27 put dup 60 /a28 put dup 61 /a6 put dup 62 /a7 put dup 63 /a8 put dup 64 /a9 put dup 65 /a10 put dup 66 /a29 put dup 67 /a30 put dup 68 /a31 put dup 69 /a32 put dup 70 /a33 put dup 71 /a34 put dup 72 /a35 put dup 73 /a36 put dup 74 /a37 put dup 75 /a38 put dup 76 /a39 put dup 77 /a40 put dup 78 /a41 put dup 79 /a42 put dup 80 /a43 put dup 81 /a44 put dup 82 /a45 put dup 83 /a46 put dup 84 /a47 put dup 85 /a48 put dup 86 /a49 put dup 87 /a50 put dup 88 /a51 put dup 89 /a52 put dup 90 /a53 put dup 91 /a54 put dup 92 /a55 put dup 93 /a56 put dup 94 /a57 put dup 95 /a58 put dup 96 /a59 put dup 97 /a60 put dup 98 /a61 put dup 99 /a62 put dup 100 /a63 put dup 101 /a64 put dup 102 /a65 put dup 103 /a66 put dup 104 /a67 put dup 105 /a68 put dup 106 /a69 put dup 107 /a70 put dup 108 /a71 put dup 109 /a72 put dup 110 /a73 put dup 111 /a74 put dup 112 /a203 put dup 113 /a75 put dup 114 /a204 put dup 115 /a76 put dup 116 /a77 put dup 117 /a78 put dup 118 /a79 put dup 119 /a81 put dup 120 /a82 put dup 121 /a83 put dup 122 /a84 put dup 123 /a97 put dup 124 /a98 put dup 125 /a99 put dup 126 /a100 put dup 128 /a89 put dup 129 /a90 put dup 130 /a93 put dup 131 /a94 put dup 132 /a91 put dup 133 /a92 put dup 134 /a205 put dup 135 /a85 put dup 136 /a206 put dup 137 /a86 put dup 138 /a87 put dup 139 /a88 put dup 140 /a95 put dup 141 /a96 put dup 161 /a101 put dup 162 /a102 put dup 163 /a103 put dup 164 /a104 put dup 165 /a106 put dup 166 /a107 put dup 167 /a108 put dup 168 /a112 put dup 169 /a111 put dup 170 /a110 put dup 171 /a109 put dup 172 /a120 put dup 173 /a121 put dup 174 /a122 put dup 175 /a123 put dup 176 /a124 put dup 177 /a125 put dup 178 /a126 put dup 179 /a127 put dup 180 /a128 put dup 181 /a129 put dup 182 /a130 put dup 183 /a131 put dup 184 /a132 put dup 185 /a133 put dup 186 /a134 put dup 187 /a135 put dup 188 /a136 put dup 189 /a137 put dup 190 /a138 put dup 191 /a139 put dup 192 /a140 put dup 193 /a141 put dup 194 /a142 put dup 195 /a143 put dup 196 /a144 put dup 197 /a145 put dup 198 /a146 put dup 199 /a147 put dup 200 /a148 put dup 201 /a149 put dup 202 /a150 put dup 203 /a151 put dup 204 /a152 put dup 205 /a153 put dup 206 /a154 put dup 207 /a155 put dup 208 /a156 put dup 209 /a157 put dup 210 /a158 put dup 211 /a159 put dup 212 /a160 put dup 213 /a161 put dup 214 /a163 put dup 215 /a164 put dup 216 /a196 put dup 217 /a165 put dup 218 /a192 put dup 219 /a166 put dup 220 /a167 put dup 221 /a168 put dup 222 /a169 put dup 223 /a170 put dup 224 /a171 put dup 225 /a172 put dup 226 /a173 put dup 227 /a162 put dup 228 /a174 put dup 229 /a175 put dup 230 /a176 put dup 231 /a177 put dup 232 /a178 put dup 233 /a179 put dup 234 /a193 put dup 235 /a180 put dup 236 /a199 put dup 237 /a181 put dup 238 /a200 put dup 239 /a182 put dup 241 /a201 put dup 242 /a183 put dup 243 /a184 put dup 244 /a197 put dup 245 /a185 put dup 246 /a194 put dup 247 /a198 put dup 248 /a186 put dup 249 /a195 put dup 250 /a187 put dup 251 /a188 put dup 252 /a189 put dup 253 /a190 put dup 254 /a191 put readonly def /PaintType 0 def /FontType 1 def /FontMatrix [0.001 0 0 0.001 0 0] def /UniqueID 43082 def /FontBBox{-1 -143 981 820}readonly def currentdict end currentfile eexec FF^#ߡ}X(xWhã#k{ņ4X^r Z{KV_-I< BJP,*NC=ޠBGsM"^5'Th\.D/D[W8Cw<3eu*;0C"3"K1T5I:>${àI|n_4{L\r9.h1ev%A63n˯񎋜߯d6oe/hޓ/#4Ax rS@PHxK%$iPW8- VsQ-pYӧ%w%2 Es2h:ZNKF1HӏgKM]%3/hi7ndZ{|[gņ,crVlfҏ#k('xDRunq,!LjHLAV#$t#ZцMEi%XSٸ} Ld.r8`ݪ(T.HJK :~Ly(@F>?Q㴸e9r]7u%N Cqk2^8qKAEF2(ɛc9<-2p|˸"T\Y4ɤ5QT /a@ WC1SFnLc3ly*%u`@rC^3 -RtDM`Os8S)'J#,qJG*ulhs9 (Yܰ K*PɚMA' d%8#4ƹvJsG(}rInLŝ\ dS{]^ HQ+9e _V`, NP4 [ )27fI% auvz16 FNRÐs~z%>-z 6jǑ7f]kJ\s"=nJ &57̃+/8IfhW|4#*y0jgoT!sS u wkJi4m =_$$$b%3[ ]Ԍ0Q5޴eq)iH tuZj׏   ffS>yK,[wQSiLv`5Mv1_4*=3]'R"s@{ü !Y-rQiَ[% Uo(zߖFLSJIJ:&FӰBFAs*K ~So$៫ͪG0k4$_2 hYF)NIk hW.uإ uNGSA#IMc ;t±!?EVm'?ͧbC,8viE2ST'ˁPJCnvZE6Z1hLl "4g'~Լl8 9jA%$iN^h{yMJF3B[^Aj 2$Thi("pW/rqeQX##~Gz[8x$ Y܀VFy~9aW͎4d)6\߃\8G%g7&JC\K1R{?q9(DZIw$Һ+@֊Nl?s k* >6 \EPa qͪ9( Oq'*;q Cm7vFO +B1=o"~T)C$ EYQ9Gǃc^yߕ<0&i^T@[p5 쭠޾-(\'LEGX"qy9^1oiA2$٩SBzɲC\[?Ij[|Fkrj/7_@]BP>!I4 l7:M}V1aB̞wC8^%ǿLdhmW CQ xNIH%j 8 IOx(@藨 +no[L;w>>E-cl¢eEC{ XS%\G#׬rڃ*U R9. 4 wrht:icNU<VgP78kݿh=&ZCݼF7](t%s[[6M쨔Sn*Wtn֫r#S<K&Bޤ3ʰ(y^9&[|2y''[q"!-7ч´dύD:$9/˸29rɗW6ɷwx @V'Fk_0f?"&lHܸu* \3YkUw(_[.8=-FQcBUY daۂw?HٝߑG6緕SЄ RWz+7]v 9N6Ӹw)i#dU"[x@_:f[aYEOe >ѳKԮ ؗë/5}"MOމ9sp"c7J@s~ϛb7_v}P;'_>ZI#[{>^$v ?w.MJ%W(X-/Y>@%E]ԿbI2 ; ΒS*hGky46uY,i!aƔ`=@b T%1EW5Ӗ8"NS #h砏Qo7@1\amZM jm11a'=⢇պ蠮ǐo,)ĩ^ iWC@^|8{Ж8e^'o8uisWVЎu[w$:tE&=ůVk\TZJ }'r6C)x13~dSlИ>+Į 3?ԩ\%0hMˬYqZ3^s",ծWۙ#AR1 TkWmm^5ˏovn [.eK>OիG9<slUVo'L V˖=&'HT~CpJ1iFݛuCDk}y+Lsa w^P7}[o 9Wr&iu˾ew Ko_7KЃK I?=@1NdR+ YlKo^җEهwcvA =& @YNY]vExf qlw;dk ];U+ܛ$?qɛC, ,zCiB1Dib.I˱j~)bϪıˣva<gϹDX5uӹpBNݣԼoR mAGƉfIp t LSewtJc!EF*-+C5NTl CǨ#YWb6 Z SIAkr4d7&V Q9DyQL  J3A1^g*_&x?<e NqXd,gO2 -L+s`a % uNEtX\K![xg7  @GUy 9ۃ&'ڬf(xϋVeQݼN!dhKfx~l:s g}5oe 6@%On  g"_x7Ц|r5%H终]}US̚9";rnK[tO2t|z%_n֞檷P1(U4A0"I>=g1ʒ$G1%k;q˅)| %.Xb Df;kPgsX<ē8ϩq(P Q#lDm2-R3|?mFBwWLcP@`ᥕ"sg$1ޘ|UZ7\,\0!o ⭾R۶:͡ əXwS;wU}#K>^nZW^!*&V]AμQdYpqsM$A ;@[{WSq]ZҬ_PPT,vaR5R·4ǡ_A4wZ1UU:C5u[ۗ1|R6=%́3AF̼8tr0pxJx9tM @֟WN)dv 樄S0zd[b[8l'b_-rsos1ZbZv5vБՒx^{6s8O;RuJP!OIi*y)\ -V[? CmX&T)M'!w_qC|Hq F!9Je=qE'}릱a[_S T_nU!j>MmFo@0!`bG h9u\rr5]i M@6`ӕ} بV2,;p؆3`?Y8JJL\br^ ` J&GXhaۅT3rK]J4ZU`=ӳgk'u0f|818<'ӜUD&# ~zo_b 92z_}Ƴ1w?RTǥ3 $/)Udyd*apEt7tT91<^X̘ƳDw>e`Ώv.~$ilxi*,X/̾џOu|9msBOQ?g$+!]uy. D꧴iaY2iLsנ Kpo(Gѯ%F9`a WhX.I 5Pf)sЉD#40* SDtE,'vU shJrX s^aВ1&LxqY:tWx'XD`Ar MMxxǞB%'z@QZ7Gr!IXw>i2+c :zٱYv)R6,{ZI%ǵg{(PU?\SiVFzx/,XF"w{1Az:6Ɋ61;fwsLyh1kkMVQV}$̦F R^m؜,mZʏ [G#10i jl&dDŇD;a\k8ygeNNILf0IǾTydb V8hKޛ՗QVva7ʼn5@nAV6(AuR9v 0܃b ݟGHd8Bı?@ +^ZE:Q?Q(1XI2e+ e ls`$nekc*>g08|^|Em>.t<5\zqHg'$ȇr3S\ sgApT! a_@_$O\q3sV uQo~P| Nc0 Lb*m$qn0ީkXQ?vhƹ2Sp<* # x0FK{!ԒK`>N,z"fzQv [ DYvtP "1U՞O )"ʉ9k4Aa6=0ma }NrOo1U"5a*mȄV0&n^؆s𨑳AJktV5!n'O':٠;׹fK&598 PP/'m+8Dz~},!_F/BF>m%BG0uZЈL~I5#(J-{ޫ)$^v#Ȕ`U'i0agA1U'ͤ$:K SD􅥵қR$W(#s z`?^M m[HBb^!LNx[\UO[PIظS_w?3,cAkcFpds^o'Ϙ&yD@ۤ7XS& 8+` uΦ"xX_ʃ7]e\`* C$#>UAl* _iu;MJyhw  ѭ^q)؄j!1?4пd Ŵ2>t5i#=.5&~Rh[ FoBLxBB];tNI_ki}kdpgX Y[P>@$D6([1jZO 9` ؖÑ\p#%( mzfU-5T}`\Y*ejk]<)p|IF敤]F^bZ,㋒L{u?n4m>8x#ZKS5f6S9N5jM&SQCʑJt)傇$-MEjIKЛϒS-zo$~<5LkW9d&Q.>i0rb;Z?$jn.h^|l V["E"\:.4Jx[ݓU=_xS:Zv]ʈҼ}ڴ`8ȧ3}D mx/XK;޷2 ]c~%@ -(!.- Bl gn+z~ky ߨ̿n$Upy5*H:Be;u$^b-GqOʥFB/$'nZ 51D?hlSEzKH)N*$&o-1T\3Сu=`!@bgY/,">V2fKofJvE.U1uhV7CS鑲4>S}j=< zQ4`3~ $]#6hޅ*W[$]'Pk Scx z9suǪĔFyBkUW^hӭۊ ѓآHqS>*՚WR{nmuЏrB (!.-: n=7E{ Nr-#w l T-S^JYW)g)jUE !*9,pdWC~ X/XE6B{Z唘w2qWmX&JR¬_8g0X_oDGVdI"8TSEAE]ϯ .$9&#B,t7~H#]`N5.JdxaGBQ4Cy-|,΢֛^uYb4޿&ޮŕ--ӝܸ!ܭ@5lRE r\NE8#f;~G Ee7uAA`~́@hDz8Z%8 xpδxbR)oF3d !cCkxp-Ʉ\TdkTΓ@ J;{>OAw R)yx]!F @rv/~.ox .B𻼐%ᒻ)y5po碖e!~SL&y:yUBb;QDUHAhGͮ1[N gݗX"ϓ2] [ckcبnoT2Oh+%6J+Q@68c[52kDFt+cPjb/}'ș_z:Rgi.XX˙*b@H5.8Cܯy[ H(ȶ[9_rPY ORJ`4AݭYO y8E& ik@ YӹmҺUC~2/XFmäA~Ol:+oͲ |8"{5@vÌe#s CGݬMy^ѝMzEePj"eZr?s,ΑUh2@$z;!W bέ鴰?3no"Fz "Cqvc])-#rS1UTJo]4W? Y搈^on>fW_Lej88,PG>CY0WNplyNND޶/Q.S+u>d}x/,G];$Lr M0Or[<k,;hxq& cg"f; ÍMH|| s&+:Z,cX+ySX7QZB)z?-؟8Zھf%)ǽWCZ-aKDBD[nγfpG.a.aaEUR5HFuزԈ 6:aOؐjўt7; _E)PAљoWYꃩ!=yqZJQF {5ʾ u^ћek*6uy"`Ρ醰{) /hI#M0KƯ[ޗt }_YvTOy͇\"Nm TyǸPY_~4Dv f|iRMyb@K ËC]ĨB'*ٔ ZK]->eL6y+C &/%@ǵ+ʾ3kH|MtL)PjE>;;^y&EEV kY(=쎦xZ.ok*ѿ[  Y{]>NcK3HmurQdBF#=0OZzDkN[Qe 7^rZQjF\ar #"?sdި&/~aELw+ ܦbh#ŕaCW3ůNmMCYyq(/JwO1v1{;LyƸ9Da~h+8l/Z,ST#TP&R۪6.E6dg* Tuu;i茂ЪVe2iL[+J;9.3I_ ݚh]nBf! @(x49AވV|Q)-`qz0/rfQĄ0"5avUxX/ڽ s>>"riG.9`k)kG!~:e¢br06yeBJW0veg1|B:QIR/Ii(7@[EͷUhz)I&̩)>2ʏѾ qH&87;Sk26T$o 0Ώta61^Lf{v(&ji8\<F7 RA?& ,±I@p7!gkՏ p&/ ~ply}odvXS"]N)ٮ c//b1N*EM2}>n 'HX1^Z;bķOv<~33Z "9ǚ".k? mHГޥ QF46)n<:kc®6ՒEÚjf@|=ď\j+b]Ӄ,cQe=ջ|qt1F2Yx_?L8܉;UO<~zU\[Y[#> ^5_P:c/>KVkŏ) 6_E- 'Y;qݥ̸ii W'V!ᵣND8)kEVgigʌ5>)KCڃ-S7:Crʮ^D/o!zjAjW$ 0cAhF7 6W SN}{`i0ȶ/]C7F7[v}?6 +zjAJIn @MTuw;x иtqhHXcHy}Ts\"[( .x"!ćwOj\M4T -LiJI+V:H*B骫zP6ZSs4ʮ-0@[ao\Vu-;..mZ63Ѩ ܶlXH&z ēT hB=9VLlUK6B$=/n<\^re} 8Pmu mTjj"a f^7o)V{P*О³1Y$\5o.lH!snW<.ؿ= 2P4]!/Uu: vCw:ݫ)8bQo|/??@WCt6lcVR|cb"pCEA)aLqkY7SH2<*Uz(q R-}ɨOFbzm./%w q5 ס ,/~-T "@I9D;E8U9]CVP˞ B:Cs/G(ii=VA5W[d _qn'F2qڑZ)FV Y^ dKߡ?9YPl%S7a`p)DPJeVruRdl#56 kU*``I{4Sr=Ûb3Da0lZ}&z,?X=!VK 4<.<\1Ms~lXH,![\MF}q.#MޭI1BXiUZ鳣c jA]-8 S[>CC1xl5j B/ Eum@p+ze/SS[^qS2:`H]budq HlRl% Fܟ6znjHe 164$S_/?GA^ÀiSCg~+RB𮘺Ft/7C M\_4)ʟgk6ΨclHpbSrv'~."igD l`M&őrYg :t:V8Y_DȢ4f)LG_N*?z ob߄i&)̂몯d})yꚘ^D F2G5Q%歋۱y%֞>|ۜ_]za#oyX B]Y&(c\h#/+QibWiPy"Y9NɁ].pzͷ㰇t,!T7oXB#C}}T_>Vb5xXRVl(J>"~>wT"3d!}Xʈ/0^=T‰C?)d, `p"fvhZTL F<Ύ3g' 'S ~~ ؋#;En'krm;(cp0k%+6m_zV=NkFih@RVdE_:CzP~IЬD`옍Z¾W@YH:_bWsYѤaU nRQJ:JmzM}wVA(]=J*|%醶+a ! %SJ[--mll! q2p1+g|VC#i^(݌Ajef_C5AOVd,A I 8DJJfq.r:GTfg kΥA[ˎDZqI\y9XS9i.\vhr} #4A X")*&'k Q&Ȃ(}<ϭ&ho߶etwl?10Ed%TxiV&&I^Ry0&m;^OR>*F<*R3϶}0IA ͂-g7: 9eA h'%,z>Z9R Kan" v.Ln3$|ƪ׫LVN,BWZRIHJ/M~6ڴOauai&Z⸆!ONiWyF'$wHv{yW2;(rQ[#5)ܓ.>=6anvaXv'O OY^!-nDjLF21Шη5ݖha=ͦBa2%ڶyMꊷtC`驫;.^`~v(FjSdPb=mNX *1[p(̞T5g&,ǩ`>r^A ӎ}AI2)ooA6u gKy :>.0{qg¥('S(S. !/eavW}w{3ʂrѧ ˆ+߂U Sֺig\">)wOX2+  !P,J#Uϵan9.M{N[4H}BGmJYTZ[Wćʆ 6 Q$"L.1=.AJ%u; Bzcdƃ])>$b7߈Bn*:Fn!0E<=s|ɵ K$/.8r0CE4ZQ5Xe$] ,J 34.x4x%NGlV)6%ZФ]u.m/}ʙAM +md1Թv},} &j̪tנecpIuF,Wk~ TN;Ey ,OJP1,l>@ɱHHv}:n Fؼ^^ĭէM 埴NFe+XG\ Fj:n@XYXYG <\oT79%:+`Lyo^~ v,8̶3I*y=6xeihDuHD[o|t/t:\$\[ ]B/PL`C4&ϸ'\ah/kW51V"P"',/ U (M ȺH^YD20%yP3jpeL}LI N 3AJQ聽08ՕV$"[0-2cm'Iu/UrPCTvO="WI s(ƖA_stxI vvϒ'>bīY fGN{Q^eFdmPWg[O~C4P߹oҹ `Ҕ\ =:M+U>0r5޴7ZU[J/p*9_n1'Iަ=;7橀I3KXu{;܊D:E^ 6 c߶ѐ{_utrFR`ðˁ_@c}.*&Vd ٩ û_lfv (GOsFn*;6Ưs׈AQllZBD'ɢTyNmh ˯_yү7.ً͎K_up:{м^웋&С3O*OO@ |Y /q`fpf!UI"VxpX4@ Z'J^lаɤPڞoxMZ+%د>/%#w٭҇D Cc: 06/kW3 }{%D ٓK.u?R:*]m(I>'T;┽dbE_mG.g}DAװ&iIƐm2D3܏h? |>fDb7ewT04R>`x3 D[n%KZ|WЉgXnl9cՁeQ$G}|hk"d1*L۸,[}F؏PaZ|cu~4 ?8JX&nm"܌۩X &1!t >[Ք]QeEҞr!|Q_OBeiN'W n{XYċg1osr훧GysB/2(*SZ wX]p+\P"B%dB㗷Ց‚AhJFS$qV@v6HZyW5^.{#$X<ܹ\v mQ> ԁCp.pp%/a%6,xw$u=xAJ'"r a#wJn4dThpRJQ߻z^Hϭhhz _ {;TCd ?I)El㇀D1N;4m} z3`uR|R"gtiE AWT@+lvWȿ ޏ9Wq _sT 6ׅ".K!wx 2Q?s dj:\,u Ф3׸ n0褂cfU*hChttkSkw|y </οu+n(#rAjϑrLMԝ ~L‹pp<+͝$R"`-H ;t&vhib|'^ڹ809i ӟ2RX eiC;7;ض䴨ER~(,Ob}vug"C9+GQd]=mKZ ?Խ4]KY|IS|st VTSIR5Q3\XzI.]U_6ag+~:]4; ?-8'Hdˏzf4]u0JVġҎj]80n}:{?QqYh*Ų&+аs*ă̐D#C hA-|28iYa=3+E `[҉ ]t4daa]3"JzDU{7W Ax 3 (2\{R&wZ~2Z8 X$a)ЉɆݫGwzcƢ"kQWDު4!^tg4HN1uCyX^dzTLm_BIMۗ&uMpvQND$SywQR 'YMƽi)8Z_Jܵlh0:A]kan 2|-W/<:Kr<1S>H"[|j;<Մ@UܛOVM)]&pqwސLBUM:E>;z)~ì8 b) 28PdxC-kETI{|7|>{I`Y`cnu9Uw(˗QQvڃn쥠 1Q!NmB*`(+l(^* &هNZIFo\9=ipPU$\#WK>L)J9gVY04Zz)y`a9ttJ/-9Az!+}c E*0uTMvl+z*tX'xkgӋ\,D3"VR eԡgM b%Þ7G{LT B*R~Eq Vexut %` ̛!{ uf5"禸q?=Uy5}Sw]5Y' md~+#(:3g/eT4kaX=,Xݎީ$uq{/Mc[#"[ppl>X 12iFge82g ̠CI͍,C[uh,ėq&L5ڢBB{_uqnƃׂ<35[gLKm(}L*Zh0 ] FB&&2я> dqĜSr[wk.! zS؄IO̾^X#Sg$ʺ7iC'ei&_H;n $'*%Ғ,sW&Ot&v2dFR/;*`X*͆AbX[!^g?/- rRvԱD3!(r[q1ţd3kPK v*q'o9 TPcl)q1TXw+;8HȎ?T;{^zbc*ǒtVĎ23$myIaaDdV}s/ FSK-'AM:c^H mhW@Ҩ=I.DžG:dJ7ߍIO9GH<b5&؇~9"٦R@}rO\I)G}#ÚS!(BPc$SuykH j}6S{,S1sgI ,>BbNO xB[Wck2k5[{e+5kz=x齋Էm :|_S"W8HK:goOd27@À^(8etͦ\HDZ\yaDͽN>#H ũ+,emwP5 bZ`Ǒn3fkG t ޢ?-*])mHNw$ոbؔzuo λbCgf<5{|=DSaB9wm9a3b RkK!gD_鲱OsOZcґ!2(ppWGf5\&sԁ[oG\.fu>Pt;8w[`pc bʉJRj G+'4g9ÃSXë}^Yt@`ܣEF^VK_BZ0="Oo/N 0xNJom`,אw& iQY-mkʾq=Lܰ9kZq3.⼺M8<, F F``"GԄ{ \o,d"zB_6nsMY: vKiM+{s REܯkB  8.(V73YkcrNˊ] %v X聁*-Bv->+D$~B|[~{vul_)eեbJi,ц=_{XdtJџ0@'4'cUۙl0:9Vp;M[!#݊ךj>V`MPq>htI(4__1~$kfr6,h\`4Ydb})Zcjn ,vg}.U 㰋a_FI%*f5up䠵֥gV qp+MT&{ۉ$$r G268p?V7n;{u㕏 T$ ~/Z57qAr2X#L?m سG 0lE/h ؃gXy.U`S20wf2hhۤGBSsW%TJPE, 6 O֦+9GG(2)wVYBDt$yJjBP 8ޛoc~waAYm=5j4߽Xlqe#v +eKݢ/=QObFA~3nܐM-1ڡcЀٻ=bȬɤRlOTj"f:m$wx_iѼ ;ȴSP"[u70p{e[* Ճ %ۢWB|8šERJYM2耾>\x4l` 6KMxυSaS@pep]`z1z_r*{(Xx*apbؒJ΄tճ_Sz ;j;iOhhm͹㽢9";[ZGY)PLҔgԱUQ?yе~j8ܣ dٍi;|+CUY,yQTdP nz<3`1T,/<ʀ0;z"UܤG?迱 =ԟlp(L 5N -,Qp̼sQ83rw o8<'rrw[Fͤ[lsn=JXv5T[C9_=NFv`uu9f~p*# \~sFní?蜉N\qufO7L979ĨERq~UcթfsH4rAM;?.yEYmbiAN,2)瘉<"(B(>XO$ σOu~mJ ɇaw sX8`rq>l`JZ= bZZoqnpBdpk [oGQ| VS-Mȣo -ⰆiY}Jq%J Quvj(+CTPse,ĺ}୩;1ss "a>q5 8'n摌4EAA9`ޤ7v]ڔA2z ZqIkedҕq)w髳WϱzO&<&hq)¼IEѬ4ʻ9%P{>(-dhF/+/ *J %Ɓ̂W .Ս6iHlVCfk68 dLD2 y]cl] }mGtKCٶr5o\.Wy{(]*\%(PteX~:+,ݯQQDykÓXx'/#'/ !m$QW://b9ܥjD{k+X+,Mnȴ2v&AŠ)Uu\E/ZGxϸZ(ȱPI%Ϝ(?N?:m:~~@څ[r`@,z%ʃ׭8ws;&99vv5,m\U wMƎD YlLU/2%%o3λJ'~y\=dY "!m1O4YI7n-t5*%ިW~o Mͻl+?7c"l`X oh댤aX-rp Tp(LLO[^Ȥ2ZJJ[hCsI^4^~E,T *\>7m~bLE2.# Z; ]?TKO hq PENi˻d9RbEYjLL3uRC)O( A#{l[ob^KG=S5.Nx^FBpAVǴH~.bCwE~/&xέ"WŶwyZ&YZVkZ0l=5oG0pI ,NJǹ0?w%z,لQ1w)e"4LWey?4u9]*3);BWl:hq"ĊB bϞ[Qբ`l7"yz1-D0 :G7A\yv%D} EQ\3֯<:sM2#*Df]۝ψX,*Pպ% - f?wuy8xJl_-{T?4f~R[3k;nm~nMbw r20bo%$19Ý`_#K Y7*5v V)v(:SldGq ei}1#DwZ>ݿV7Zy\|mFKKIiT>LJ*[ϼ=hB}5. ]Q"[GnxC 5*%frOYMj|m[|cS NB e ~}EVp% K!JǡR4_w9ʤL-`)]2RgYS jFצd!^&̘T 5R"d[ Čk1P-A@`tÛ^X7#W -Xpi^ĨI8T W/ȭKhI&~3 ^\փ7"t9o w#HP,iITk'XB†kwJ~8'1=4ǟA4QWzj12W@ղGg>n}3TU4􆳍ej<%l1dq)'lT_HKS[V=WY]^xll 17U'տq7 歡~A6m$e"Te_C3jvqۣ\c0c߷39GF ΉMsB4E1'6wnRL2ڬhJAA%YoBGJU@#@зJDa?4$'UuH/Wd |K1A-չ%k1DQ,cܼF KX>.҅|3~U.zusڸ͉ڦ'Ptm!Vg7;ׯ m'ͧ'cب0߁p(%w^- LN⻓gޙy W 9D,2s XCK4B䘃xg IpD BrUp'>Z7:QMa">N}z`@k;oV账7ŹxlXkC=QK#bM:=hA Tu#Oa qhSqDhWرa~ %3opO5}"\scA!/}oYVjK 02G= :>W旣ebs$'킁M]jGQ:>Z#̃QAxb?F {`r}{f 0+L1BIOSm-xӖo(LͬtVۊon! 2pgN e+dcpJO1A[=r36W)uo0RqqVb6l_yIpھ(R" qՊhCȣk˚X)|p2.dk0QTɊltH?Ob=DReKtf@wKDݸ]dhSQ3Ŷ-ᇴ1m/}{},NYW 4IGcDͽK[|fr:?W^^4^􎵆=wޡg.m~'`ɹA-Xב C0 Owrr.Kϊft XYR[[9C[i<*5[22 @댅2w ƅ!]bMJ1w)sq+[~9"frϓ鰊tx?ď&oR fkHK`Ї3vnXJPtD~'=v=D]= m T,Y섃Žd?nc tZ_<kHP'6CZĥ=у] Z"pI|W])WA2 \{?H ){.N|"jPF,EFZSLv( `ډn'*!nΰӫ܌?,vl"0ƗN-` Po&mS FQcIʜHt8/pH}P˂W{ 4 D@p؇T걊-vC2nom!UKȂfqts:OKY] :Hni;>-eL4xQoZ'E'2yR".&2darّ J3аKdVlFUIRͬ2WENN񳝚*2 ֦]em$? 9\ "|jP3:KCi3EB[S9tϯ:X3K"yWx%U*Α20IX >XjH}~PzIف8HOw%JB,"/7ANVw+Px )$[P>.֪vqk~KŏmfzH2] phwx}A@RPzd-#(&A~B 0H0xGĦڶ/91U kq,ژam(U$h֡9y\Dr?$ `c2Ruv]v1wX^-6]1Zd&=6 %48C .O۟AKxf$ Uv%̐0L7+ у^FEIJwR`wb6Q0K{ T8Mbp;U&G:8ZpM鍣Q_zmEF`-B~$9JBTQ;} 7R'ߐAZyZ `Tp4͑ @s{g* LV'sU go9 Fd}@d6 XNa<2 :GvF$ } >9xD %\>."enaCeqc8@kKEmMQ]2@1:L_r9 ]1E$rn)AIe j`' ©)NCP.tyE Ĝ:a'@w{ b3Wl䱯Yр&1:,`WE̱lX`! !4HfKf hú"htJ́ \;jug[V`O- "_5jaўDPx/{m2e?X^?^Uh>~Uy+4\W. i}h+ӎqBs.hVO,-5zu&4W{ ~ɱ+;݉+F:Igl,l55HyIJ#6hnBF1zuʹلC}I]DQ @M 9^94%M6g%WK^A38en0֏;SgZ10Nbg~(g4a*JcjqD$4pVC_YGR\KLe?G3wţ9Ozis,}-j)ҍDdeEu_UF4Eޫ9EWJ=a4iY>j"-ӎy~S&/msF^A$skM ̬Ҽ*hη:_ 5$J'*'%+djm㽻)yk3bo2!bϩ.CLR.hj{s?} ~mƟR@rVI/9 FgA u{}%0SCѹ|=S-H0$Ѯ߱pҚ6*_ZĨ(Z{&~cNh p@zH*n0eo|7-?p^S=&Mzf$ aw! QSU=! 7euJ]!;u^`{v &BI 36Cś Ϳtk/9̍rhRK:fЅf7X$<0BQ5L?M"U|k j˘;qe~ iK, ]xUVl(-7@H H r`@Ӌu˯E(.'] >|CcS3HI |@>%~Bn7ֳ1֣CQmZ-FeA%8PxQGD\QQ`p5Er{&~-Ƃߚ݁eTOPtjU9dHBsGLH8*Enai5ڽ)bTwF K*Ehۿ'6o;!.G2$||h4jn+(#N[T2(sB믷K `-33ch0!&`w?Af`q M,QSmo6Eޡi!0ez'"\X7oeC<*Iۗ͜%@Y%Ԧbn*8o8BJ<?'DN,=ʾ{n/CA} b]M扑dxE%7 GQOVzn3Y9j40<7ɂ *ώ(*A]ħSK{6U2+,}/ ,fc a((N;輷dEx-wݒ^ xRR# Cp7c=:F۱NT(YYJyt *F)N@5q(bXq鯤cr]InH)_l;X.]N@f!~we 'Goچ[τAuox='1VypD[E2{̣'KV oqO0=}0mFw,Z傲\DF-C$7}e0eCC ڊוk#4j4lpi9˹'%( 4ѧr/IڏO`iQ~;K??Rn9y(|<~U"8y]啨.SK7Y' =OR[&>> /x{KDpjwd!DX"(\IZ$siU1[cڍg%;.Й-߲Rqݓq8'حBP|an#69ZࡿZcI yEu _MLr#ƇdԒ<3@Ņk!Vf`?K #MzP~@=/Q:wBnΔ0Gہk;.ZM@PuqP93os L>~~ëH4%y>ߚCJ:ֳzn[^} vڛO@Z?-1)JwYq!,^$ž"1( `A]HdIp{SOX?1jLwur<8vB0U{0[ <Z[uoPX6uk0Ȳ:b" WL<_ 'RKpp.7%%;ͼvk?njEֹ݆|!-(d&i]gT̖QwfKG@Ƹk\톞G  3wP*KXсe~٥brd{vZG|@QUՀpT)?|.Y  $5l00kWYYP,Q8# 2(S»^ǽty>+Ū\vmH LD/ɲzY/44`Lߝ}?:|D+Z5p؛ ܛ$61GK]A"Ons dJmKg oќ@XDgo,cijArO9$D58w>DtWƎ{ո>Lf!Kaedm+ŸW]";./%@:0 [r4ݸgUDvT,,(0+Ct%QY#vvamAծ#6l8,8S;Tٺ-K~m1v6ΥiYQ es-;tbnlX;A.~GQ,U?a)q]d|TJAGHtf_r^;2vV%Q+v)V0tL/ (!ll8aoe 繇çwO2%'dƘ]PtsmK/Ao:(g:1doE;nRF*1y|7zHB )2=_(V̈́ 9D}Jvv(?WJlvR6yAIujrPwȜ-f$W@.b$xY1/>_*T5Њڑ57VfhlCK\Noym~zGAgfѺ/T5RuS5䔌MI %mF~é݀m@& ̣F.7 FN ^*M}ߜt}6uO|OqN~j982 3Jq=7fD+- oHIUAȎ҆Bm}5nBi8/N6y Ruoy 1amAؿIQ ,Q9,r0-*[j,4d?}ÉSHQhԝϏ吱:8)lC3(֋a/cn$[=] ݦF4I,J/>#վX XRo Dн5 $9FuHt?ҫ8uv08 !_9vQ*,ƬO+1 ) uREa (!wVp)"LZp{CG)363o5pw^RlSt2L!"ft?ω\_3%59X#HMѶ lZoc9%.S2lW H1זi 3POe ᆓxUdKSq`"lpŰ@LUK_/{8ҮS:55@`ǟQ$q( odYܕNN߄&鏠J:A!jwjtİu4VWI\m%3WM)0%5 [f!eP Jok@, JY$QV7$|C ${C@w'ީM +La < Ktg<۲S%p5DNxɊ,xB[JUuout hk9X] H+W@^\x js{*~͝Ց#5}PwγyQHhJ,%4pqma;n ι4;th㱗1gj[ᜈv iXc&9 ]HR%OU_՗[bokP"ٙ.$BnA ID8 i6Mpf33&G1Y5#= ?A[e` nqmu>0d%Mi;XˆR.b'gB ҾD/de1+mXӦ/8Ē~կ~ ˠn-[W!"|7LhR(Lڬp]VSE<ŸmլUtDfA ;* d&$~8z-ֱ| I7$2,-$:3!8 E X<7ܢ9aq/ Svɱz?эm3HZ!2UF*զ)]s7b?kր-U(|*8 ڎj6M $ NmWnp~EXYL7Hfl U4+\WX4Bŀ \_6E($Cx6.%bB6y!h|AF'_qrW|%Pled!bn e #d pr1Z :c)]Z^!6$pijٹP:T JkG ,mu:wg$."vH`t#+S2깇#-8-՝*[5gX/v%cbM, dU)^<$5gc+4[cƮ25T >AW}xMH/+5P@6Щ&i^ Y7; 'n>+U)v)4c)Bu[w轼w+uEOZ&uqh#~IzcB0I" Q Z3#/b錆tR rJΥ8仴xl;8FdyHgX,& 2|_`iteo'n *g9"tv) 1X[OzOfXj"Je&ۗx~" t,ca΃ 9^@ ϵ"7R)4 ' Y5e=qwX#7ͷiz ~Z۲ꗙǁShx0ޖuTb+d~3$8(rtC#4p!#'{ //&my/ʚU\m6 صׯA#lTEy2ޮlJGy}GeT~r*<%*Ga9zު Ld*+&R5_Q;_ȽLǥFA0T3}Tc[3UkpdR4KpC.3r{Znx bS\~B]Sjʡ`9it_Wt]  ?_Ojk{=()_䥦|[$vq5`۬_p2eXurqos@G΄_HX-0`ڢtfr KR1gs5fKԊ!N?4 ن: .[Zh{HT]T͛c>QZ&+>Xy<i\F*krmKQ40{kIǒ8(pk(:3#]:'zE#3wLd~q JX lڳn.>7"M\"JitK4ӷt $E$Ãp1)47ɔҒ%D 5 1q]B yZPƚ/mPpgpQ%,'#_M;W1z8rҁr$8GZ?W,OrD) WD!w|G͆V0*i&m@Ժ; uwWX-!s\iO~.BNx u<~U+ߤYgA@ O.ez^b[P~ر M^'baPLp|;ώR^3=V&=]E㴱wG40)QBg2:D('g!2t7="SZ퇊V*!ϑ`7D~^?qx嵺o'Y A'QgNb#A27i"W5ϵXu]gsZ|VE'Tm42y6f5`Ɛǂd.,VUBQ>Tv(zج"<ȼu;l\g E'=f߹w4  }5$!1.)`*6Nj-\Bz;h C{IC2@^4CE㹙x  xYw;niTCBC$8nbHweӻO QPe؟u>|\yIeR$z.5bKc~nzywX;qR^ヴ4p~mo3ѰxCY-Mo#O2v' t.+U/I5c^0J0GYe!ܑ*/kw '|fV9ܺ~v'nwl Mrj:sA"إ]ˋf;ћ2js#4m-r-fB 6yL 6*@! 6rg[Z[u1;g4sY)ݑQ1 smr9x&U~Զd32g,6O[>+bN6UP&PI NqojT|5KP ]U|890O\-K3%tߪGZt |ݝ>cK'vY .ۉil$<`ڃsMR#I}$5#2ɼ^q7Mm[2JK"Ͽ@(2g/*Ī fJI>b<Ϗ _ƕF)IbM}:4lUݳתQݽSϻ,6"6gx}FVȴepg|S~m`;xB/cwMQ Y1ʒuҝJ@ZwXML[,B t0jLP lo P|>HE8wUа5KĝV8tB͹ܶumn*`<;l/-x8ֽ>XJo_} g1B'xK4 xBelasZzƣkӌ<:< hT.G+(5$IRz>X *"WF>7;zWB4=+u{$8(N/HoƽU-?*rP+_sl$VQvC3j=vV@[q$SG't|(Zמ&c?W,W'NA}uOdo7/8B ,H"HEErEjHK^T+'-eTQ7lֿ:!(5\H< F LDA;)?GY:)ACE1%!"GYJ; ݃?zG WEƠon^>W 2\Lh qՐ5%ܗ|] iC \&N%kOU%WhK:^va7)"Z,ѓ~f7DttO +ʁQ~VB8~B]Ҩ8qwo[Iӭ! Dʒ#I J3_c2J)a|m,9Jߙ@)'gt&AٺڨW^{تWI3);9chf'>(K/֛˲J$aL]_쫗sY6^Hܷu?o:wko'M .NX.3> =ayP _]5Qd4͠/1ж ^Y[3s8e:E6#[!2麄Bukxy'#Gd?5}*GKݞ>A <Ӷ;z;~ o3lU u."v`f=}}v,ƲQEdmO\xYa`)Ux%GYoK/ "F|5ZX)blsc [52m a[N?&)' yNdeF4&LY|pJyLпk:qDԀ]g/^̵kMOy lRM|dmP;G5.8)@jwJ˄kS?%6-Ԩ4[fEcH$)L∝tʏsx92Mco\<ƹޞRݫ爳[n$m,$iDd) X;; ׄ 2H$b)c EP@ՙ!c6Ұ;-T{^N:xIXi Mt)WDi< uЋŤ@h  a*6T^vjF6fECmGk??`Z ujܭm8 D(u7R,0uXe3s P78AS!h^t?a"7IV5vCH$}^ 6p`7w`04R qAcR!͇w#dr,&qxm'F/{ L0_Iڀ=: uxF Ѷ{)RBX+Fz14_t2_hZX)]VuEܑ'1yӴ-Ig*X{ie~kBZ9ޣ-j;H\N\:-W?xdGܩR |"٤. C,:3J;+Dn*[@ rĎGZ-(l[|Вr%EzZ(Hiz+9m"6ȸݼlDNcbRy~i=ҽ'eixJSɟU* {.4P~%M~7ocM #cx1}caI v).ҵa3^Ob?Dpt,us; cTjJm8$͟K;i%*#K`iT0^hNcaۻ1wWupI{$]^}$W˱zOߕ;2W@'Z  ˵JR+XQ ;' ]{>/c\m^Lj274\K!SjBwqd3VA&JN>d zkLI4+L`*ZQak^ +ZV./|gJD[: sʞE2Oi(?ܪW_\$`JzX c:;!9zTۺZ(4?=w]*AֆW,p;~w#*b\d9Sؿ5kF\\܋lEa,n^M_7Զ\_U6Da]M sX} K`C1O~Rz-$iw'*i.oуϫb>e4)tOA)"s5#J9ok n;۸hrܻV,ᄴT-d#67'ɜ$5gGwK-\IL[d0#/˂.t{KiM<{e]!o'| 827Q {8ں'|g6tyJ,C)g[ +>0=>)ɉzGPƿ:W X`,EÐqcYJ1CTz^DÌ0m!К;n7|2tdpEՄSxFТߞ6FN?l_RpCxȄ`D3sN8U,piJ=E")m6T 3T,t|marF˖1@%4SmþYSe9tbU7PB$r9<ye_NV7Rסo?ޝvmHYP%UOK,ٜ* \KH?RqYڟ?xokdTyO!Y)#x7zShvo R.lAe n6YaZʪOp:Dasods5A>D1.WZ{f)g=v7avvԓM*Am߬yF7䙡vx~5_0H Tq1u1@#a 7PzwfO{2Fb27uU[6%VOiut3aCNĻHтlσ(u@uqm!/K:~քa",W q&|QBRKTu_7<0^88"^N! z=I< {`x&z͌풤ꡂ HLigq\FEen(L[y2(0j{66`u{óLnYThSy AimWJDC <2ǕuʑʑiLrڽ_3hbeOWSyx'oN. $2}Cj?5^# r* (P z@`j.b*pr'9cdXqrGxGǝ2 [WlnSkmJu-pK1gaP2JrɃ*"^/۴g!~t^T&C(xb4ҧ7nq)}o/^o37Oֱ2LcO[->'l-]=n. -M*IS\a|(m͠FxA &QFn A͑-\"qZ-?}!,HQjeY<8lB7Rq8ejZ3SQEvuٟa;ֽ|֑ tXl74=$ /,>F[,!Q\2t ލ?$'8禴y6Yuy3=r2xfz1M76K%Gf"8 %O?>2 CT̺X0C(BV&0j4^%cObI7 !#]VKMqRlܬ2 VO}ѱ[ x!"e#COJɝ^ vqyrAfBPh &h+p]4nuBVhK(M2eH yj}mu4C`J\&1M9Ue'bD2ܹ0ImU=AMl0c]ˢCyc4&'>/̉u4hI`'}]{ =o/aix+LsFVGMg#͓C ՙ .܁k69j]vjbn8y>:;Fszc̚?Cr6Aa)iB(k;՞OJp%gWj`A͸O8!HjVA_z[YSI9|'O~eM #dY[ep>8/HX-`^(ATiq=Wh_`2詍3s tqi'([ ބktRzAnxtŽ3Y(7t.YXvyf }`m%X}:J?~ AC*K!]>!=?IϠĪXJ_}:F-g#zٓf=;LLIm;Ցs(v 񂹗78EyD^m}Jp,ޓn:g<8S4]#^!ϣV{b}&áǵVł" G/"@hl=bH/<DgeL~Yj&u5)ުnHHeQ۶+S]Poq)fEt!B)f=/cƷ\h-MJ^A/OV):`GM`2U& *8Q6 3xWw=~zfe&׬$*Ejoi@A.Ϸ Fٙca(n<(8 b?0ggo IsMXUJD$- Kgq1NV?j-!gFiA=3'=x`|aZ? E&cwq? و ԘaV+OVg6E҄8}ow9n$ yEތsBG,ÚVIUA!* Zoݽ= ѡEad4aą)5K(wNhn5< FC1jc~J1&yr_q shΘrڮU,I*SAJ-7w5 U5A#@nYp+9Uwչ#$+/*7;RѰ<|]Xtjo u~5PC̭ldx/U7#2gg/ocq TS$vd^XֽYO㿩N/P37#umTjQYy0X'WNx͋SF`R&(X axd_#"4;CT{=M53c2b:Q9iMwOoq!=2STO9N a^GA#K,>Xۥ'1?/t~,836.@r6@4% x\$/لhbw'k܄saz n:P?BXTqWKM B.Y\90\rWVI)(& l@[*:ܒwoҁƐl*:hWk1'ɚ_$+,Q6?ˠbA9qSx|6 /FS}thww;|v*Y{~Qy2pWuCA۱ߗp+F bD}Gƾp|=jG/I#aF"ۮiODe9ps>^[S\ ՟.(վ^;~&OyRLk$! 4,Fmg>f`Pov$ h?\p.lRXԮz{~8>M|?#oIAEP]G­m=_ tERAAcJ5${Q4- X.}&/+_;H]^p!>/.{Ftd"YsZkZ|'D8|B1̠/Pݠ~CfӅX؁GӂݦLű:󑾜Qz"X6w}2!m[qU؟0q5κܸr!Ŭ |Oq IՀ#IONIbhjVYBڏU) 1.ZV`fL$$\ :@qOjqb5^6s\0E_@>"yW]Wy.2){ %On[4lMm[n7wt$%.%k pnc0عx9'+toJvU{ #OU]#$O#}񤊬 soO"Λ%\C]49Bnҍʴ۔ޤd!o_CעH م_۸kGFUKVQd5#E%y?`з.U2-4X:20QMV2Ḏ^jhl ^!VF='݀?/O=KlH!?3a=h!shõ*^eFH"1y2`g̠[Zz8%tYM ]Hp&pdU=3*fT3U4ocQT%Ur1ja5ySC߅ʈAP,N)E)^Qkح?B⧛'}j`&q5UAj1ox*/-4$UYi?;=e<5:& Zo[e#8vlV: <L{&!jutdCzz=ї ! x@u>-<@3Hz gD68(&":XgX8!'dv'NO]\\g׶8^~wnw$q/sx53M\+rws) R<1#1~b,tUگn!?Uk>&1С:38L?%X󆰑:Z X8q(|R)^p"1adZG>3?U(G0 94}qM>5CPxz Uu[N:,w?+~iI RpVUQnXeRe1sЎ V=leGmNXēr#I~7 !XYni-k1Xk-J8X'1F4bf[izbʅΚEjU }fGw3K`f:{/ՠߨ Ԯ$GAN֗[cUdL@W+,ŴUCS~v(}haGJV]|'§m9uA.u`]\x*R*;Vzw֐bŋ8<qrBS0UчQ[|1R#[PH}EP]-ʵEpѺfy d8q򞥌]ȦfBv!IwƩa\Sex}o.D !2*ʚ% D0vUmMpV-&ʎ3Q\)i̗+`Y.+JC%,k3O H>uIMByͧh}fܱIR,U7I'˟>2ڭX>}yirA֤y F92BHF֩aey=*N~ޕb:%ؙv1+7R@ƢlJt-^˭0P%]򱖍dh =>R!z @tKa1`[KvF%44hL%:?LZXiSt;"5sC:]ld4͜7j{s7JZ0-,l )Pt-Q B.^m4lqg5?LsYc FDl 7YFJMR>AtH$)Ģrd6* ;ҷE%\q3h)B5;vsKün`aCe37{܆dO~Oa%+5T|1A'u-}yE0a(XG0 XG|a+{pDՈhg77M' Z<)uba .}LTAٙ &WXh#:0̈́#|w"M2#-?<ɹs/&`kx73 2׋Gj bEI7>XF(FZ wIY2O~m qU`Kyiy %*Vv+b :By#3eõRɆzXd=_w1?sU{sZ=Yh#5i; 4%ު<ڗܴVavA)P6L/D LŦe (`%²iʼի.4HBӡ}<霞`E>!_unʐ'H'=V|r%Rr9o2@FOZA'H٠E eRfؐ1=Xe Eȅc룭誸e>wfl HXĶm-Ҙ6=&G@&^}x]]ԭ3AIBėz]}m Kq '2<##3p:vNStgֺ["+7(skh֚iB %'fBJdfUJq$R LьhpMr~!ṻ~8|B; @!`eZkq[v&Omb{MZ-"KUJ^/%%)SOz&@?, Ĕ-C-W.#/( Ɓ̸ZܟԽCӖxw{]@zľRЄVvOkS3?=+@N5s;3QflR-zP_%2с <$lո T,A^_ (xBzm5ӓ$7SծT)@.64Yٳ0?,ׁZ6Dzm/n@ ՋG`Ի7-W F5\ V]^àeĬTfG&37.b^.3IEK\$A) 쥯q.>L^9DZR`i$z#XJ2PMRX^[T0BD LVK3Ĉ!{>/5|I_HzMȖ)\ntXn}wylږ'k.ȋ4oE1:~C#@iW%g|֫Bi|:3n :>iӈz𙵑;nZW/ Z-g6ĤĨt P\Q䴶[s&I̾0*үۛ 0%kTO^W[kY5VQAcqHQ\QClHԣQ1t7\[Vk5,Lo,G(IOG,HpɬFGӜZX=ʊ 0(N2eA~p8!.^dITu)6*DP 2n8.JT$xkl{Y-5;8j#B 3|8 4xh \3XLJ.] ,D6&T!iD*sW(pQNMDn0=0=#j<,&>Q+]%Gݖ?ۨP/BFufE,sMA|w0&QdmJ< :FJw D/%%  ŚiFTGL*Lȓ,dBS2Atwy:K\, l 9-$N(3rP3-_ +,G`:TrZ>G}|nN;4x*88lΘ0z'ƺ޽!C%"0:Uȧ!gI)l.ArV SЙpM 79X7DΓX`tsd`LJkGhun#5Ο U_tsX0!Sw&z#hSAuf$7R|QǙ0d/YPf^fyov\3M ҳ2ujs#[싼?NJAMz0xd+1wÄ?TwiyMM/u%bb%׍11p jむ9KcĤi _]w: fD߿a_1Izs>_-֒ !gCtMi}7!< ];:/UT/G4V4 v,*Px)b u o oUWS?)qL[-3?JTvǧc6 ,=:.;2tH#B)JM% d[Dt  !MF#@OybWBX7y)v~ocхJJ[l7Z19YH#yίiQׇolOM1wcxC1yo$4`6̐Aj68('6w#s(ob<+M_=Jc|uPojՈ ſo6|W<${u;`o^գlϿq6sZ״&>KNMe,Kھ Ҙp'e ]Aj65y@J@JĐ팷t׾ݠ B-.U#n`Gf&-4jU7cG(=ēg9 Gk j ,g1Jgm%>tVBMx_kB_eEZRL)Y!{>05D߁{CmT"DS&$ϣd= 0YIƛD!1G1<#*55[ʍo?60}Ps̕󿣦C-Ɂ G@2Uw̪{O˜cKŇZ;,.'B֩S_Bp& r[UZw QHfњp\?|@3E؃mN0be+- .]Mzq6T,kIc|QG_ܡ8!1ED=V Lx,U0UIvmF9{VVw%I%RVNW_ eW.v2{P 5â{יq[*[Xs/ ʹqp?Abw5oI7i6kя fK"y'mX <k<;u/vKM5es",v(&!V&HNN2Dwe#;Wl t5 M;pzVfdB3!>ln.V Os}->#uAslRy orIXp?$DbEa T8b S͟~~(\tϜT E|Ir ~[v ꨇմQ *=ԙHi)Vl|4`U[+%j* rՔ![wQVRWSP~#iP!fpT?@!1}i$Đrnq )3[[YwNɂ,2A'Mdy-7-ίꡨW^W4LD붩{aᦃL/0C;(%NZP1Ђ L샆PزʡX[/@ƆcDM Os GO-dk֦L UL!]KU.>ed/O b dՈ7;+ubeg谌Y(;IK6bsJE8(|}O=~$xԦ/1c,h 5g> @` u9~$X#9h-6v#pͫ@a3(Y.D1"b+Vo/S#ijrWӡ{HmmFA`fVvCzg^`ajs%iMml0΋Wx3!CI5 1?tjB8}f17Z#hTl}>"볘'gYVUM>B]%z9{xαWl`/ {f\7ّ>qޖ_'{Mz@BEO|eD|lT.yy@4z8wSOMC;V .6-5ZۭNV2cFXu )V9kziB &&Z$ѧLM?hgd1 ,v\K\GybPRbWe8Jk3}#A Ґ%e6l`H먯.ō);'^VB[=-sKwtiSsڂg߯$mgOs`^>'^}3>F*CVI*t-zH쏧wD1;RѰRF=JfhwD-G$^1>Hg?D VeT0XL>"U\K;+É㇕SBEM:wcVt7&uwZ^) !rS  q?eB[ =s1p(>1Js}8'ixoZN w P  4N9Eaƚ7Ҕ_]^r}Ȟ=y3Dj7TfQGUǖP=dby%@գÀ] "iUh'dY9ci{Ze5oIRs@+eTK @GYt7.1̦yohRWh= Ef?xjo o cjLVhkߑ`a̛c/W(Y0Ȉdz sFpf):`ZXq<̡TkPr#}۲ xt[lg3W~Þ :W0Jqmˀf'sz/6IeWs8"W~LR>-F=g ۂW`w/}p T2κ!LtNJBӤ>Mڛ Ϲ~[%^*~;%6NPsyecnE ,bV{T)CêԄ,OB(Uko"1YI%@DR)T>j(S>87+ NGlJc`b5Q\{&$i!@^Tܲ}χep3Vd _WUϋV*!=KR[l2HPm)=)|l <*d rQ5mk0'ѡ<8|J+Tm՜J.#3C-msԠFQQȥ_nN>%.Vg>}Gf,W>L ÊQ1!En-,d7"ꬭ!*T0c.tBw}$f&`W{\{ [Ӵ݇9gpmmCձ(ԉRFQRU5 KZ>IgB?Eт& e%FJˋa4ǂ t/6ߝSG`ɷrxfҭf 0srgq2o\('Jln'~ruʸ_ &(H+L:$@$ɲo=5>FaBo[4/j\!HH'җν$O_lr{Sg/g5LD5D 6/hݰ,)(c1Eee`B>s/IJfHhKtIVKwԖ.|Z=ʎ?Ap>'P2 H4 %*´stܫke%L}#ښ[9jT8X)[56wٜ<" ;Z NۢA󩤴e7+½ 1g}qjĀ7] BܮXD+8Y:N37o$ʬZʳC[.Xʾ"M9GĢ󧯐 A]v' J3BvЕ^i;+Rw{߷" vmDԕvhBBo)Iob x&bLNsbK$Y n<@:T4M|uϟKo]q!7-!zqT_鞎C/0wGY ZF n& d|)d7$:/ +riN vV{Ӝ"`̖i‡7)ِ][r'hAH*SD,p|Uٽ,\FH -*Reٽ:L 8G\cU0ihv} "zɆ'pUtZWLRq.Z\nXɣ1˽PDߑ)yW-+y0I1SO[xe!zňǼ*P Sl MN\H/tgcx=.o M0kHlЈD++6XWS:X7okNG~iۉb]3sӡw4oQm)oE \_5Geq8εەW|cNZ|F&2,Ar9,3z)6L-:A1xHzECx\x{h$\q3kXe)ZFZw ;tc+r;7 (G;kY)+]׫X5r,آy-Ajtea8[Y@MPqQ1q@uC9Fd20 ]-M/NH74"ȧG~WMk(^LSRT"5n] #lH=%3X)95Aÿb(qXn`=[ av'5lg=MYW<؃G:>%|.RN/զk_cvwUպP׿xFe}'"^Wt&LQa{ƨ" ]]ϰ39/+ѳƏBT/Xf|uX,B7pFK̐Wp,4rop{7 U.uԧɘFYQI7 x.98LS\qH$͈ĩyj6U: pU? 9W?a- Ie5×uhYAuվejqEEg?"ؓfPu.d&+Y*AiķFbyAMtsXj?sj6"vR{s6>ddFs8x7~[@ /. sp˻HrENU X[jQ\glXa;ڥ I{cc$፫l2/,q3/5h'Vfn7ٍw?@ QmUl7@kdTo;w$7fM# Vİ(&]:ٻ%M9 zjP'^w5@ϐ$MBIvZKڥM.Ir \!f@mƬ8Q~^)Ǹp9ug_^_G3"7c_0ށp@ NSK^GBV=]c-nߴb&E#잤(-ƲyOq5Q U Sڱnhl2Kh,*43fT֤lZC‹Y]|/\bˬZ՚mmd>2IĨ0Jg\O%`_;E6Ƣnn8jGߐQ;%!!qfXk(ǮS;3?4S/g`MTB"u`IC+ˎ^yj|ߍ Yy/{^Y6_QcEPKzy.[RD}N*w{]d἞9ڋZ9;FXk3g>Ffu~|:W.|!@"$w4'~؃8y)~$V%2Vj=`ynj9ݱkˀt>|Tw=D,WL! r@cm$A%UCdg(`yDFw3j fՐ>@ >B6 Ĵ $V,aM, .XFUiFR.-MS߇,Ca`(zT}7oYht<"hSp)h?*U8P}-Kt$ۦ:ib/=}҂اɾۇȣ-ORӘ"؍kpu"˝őt-ZS)atіpgD%P'aǤu>m!qP%%z v^d,2en5FE7x.:6)jj_oL}2uX BTEueX2sW^ъITaFJb/MS ɳm=k1 T"5rt P}φh2MZ3͟h"3:L 43e7E~, h$/E0,U p} hZQ@ $Jǟ<=90xJ|Z/Ʋ)ց)[rИ9sv:2,>)7ŗ5KꖃolG! yvRϫXeBYZRޣx#&SOIj&&7tGk Q3^> ?oˣ瞢3*<k+~|Ȇ_mW5߇E<)vi[#lf kOD?|{f!0CS#"E:( bܒb|.#qn4gtdVÎo"3Yt+ MCS1Ƕ@%rS}ܱ%jH81uq4jgJNG0ojKB"w5*OQ:͋.8At+w؁PFeeFGڕ|!cjg.r/ki: .Bu-Vl>P\AϣjEq1ʒTm786ؿK |!L k:2r`]G,g^_=,?he lʂ *O+"Ęiu*,'c2A\Ud`T̞n!noPgAuvdnPRvg[/\ t앙[PPšhG|, Zo}fE7Jh'}R}֟5""Sihr%ux ,%"\n~1^ Q/@Up->:+!R7Ō9;LHԍuJVYwmř"j ]! OvV9]xk UG)\PfwmD2Ba,(g>%Yy3/h8 =)?CJ=)-!G e y-g_8nEJ1J{0+Ѷހ9 xm3؎) TY t7bVϳ/M*8Yrndfr{ݯIbw 5pX=w<*a[ez 7D*++#ق8b7 3ʯDό7.d+ۖ1GT8Ѭ@!v?ؖ:΃Dt C9~{y'45Oy0OުQ=D9ABVȉao5K7Mzf9n)z :ĚCd$rM]R"x@ ;H"7Cъ3sFvAܳ۳B \:@ lʹs_;6D䥙 oH F>#*ޢ.~ /e+6:N- p#" $cYt {םWozq-VG'J nNAT:n=$đY#])?khS2aF;9 O s2E!)v}E%#d!\x$xRGl _ As̡q>w+[(h`q9As ۂS}f.`mzڅ m'Fd48mi|b\KYe 1RkЖ$7)bCSB{' aEèŮQ`1F}ǽZG&*7 wWwVOXrt?*9ęẉt\)/8%H#g*,N#Z 0KG[1h+6 @5Jv5j1I=+d.*1$k dgCV06m?!Vp4}([!rE7uEGDTdX0l$E ̴m"iP̭2A94<һ*:x <(n/1P3rYGsԕENQi'vxyŹj8b: Azh`򖃰XH|{DyU&Ud;_^zעP2Z/dW3{&Ɉu7xr;:=>{y,\0|@%:p>ȤrTF[ w3ݷiu^֙ڳVג( 6bTJ`?7ew骈|pN&Ήob*@ȉE$f 4MŹVQY{ ɭ ߯ADkY(2՞abCcS(2皜9,IJBscI 9`K8'T gv-&ᛆ({F ڪUA\/KWasFkh#Aܲ_j:`b/e5xV/&QʏBeDQ$Rn(l|A͞KGr(橢TAcE{Rv7oG&?q5:-teri4vSTc" KYM ձ@DL~egPwYT_=LxgB+HsaM[u$*>U j CehսqpUjT~9[ ȇ)U,JTܔ@|Y*;%eT; dWv8uT V<݄>19x?=xϊIP?'u3WCkJ|nBȑ 0ӞF2HEk1sSJf.(l4#}EԚh3,Qļ4IO}AYFw;ō m Ά Tbmo kuQq v\G@ J2ft?"*&BXRLˀW`;k+]W=N 嫘3Fx/gu{$냴7eԯL^XtI0燾MVAF$Al0jn fQ1HO@q% aѥ)*ȏ'|mub)[zq$Vl G) +ꁉ 5qC|_C="`Sbgɚ1xo3I'? ʳ&dw!L_f|Ss$n]5>Ѐ*_VfjRP0n_3WuhCX5@h肻I)" ĪSn **`>'IƔ!P-{hwvK6D4mRE '5@/cj2d}BV6ٜ9mυQ{uQ]6)hÁ8ԻE TZY*Q]v"wiʋI\aϠt.=nFMKMdkQY!r!oq~?}E'" Zث5[MQpbB䅬]P?hZm氙4t_q8mŨPz1wC>U'"U? 7#We in}nd"IdF&~So$Ռ X/asVY~Īh]@W"0")#=ez2ݖ^V)@&\BxMNrÄ&=9JGjuΙ~%hˆSR YA[oZJv[ؑNN拇pF#l߂خ}m/ZjX~WG/d `j{U4dP*7^SNۼ NݣxO&[rME<7f uφB9͊GvĴ"K@ BaCY䳭w{aU{_q%5%"td?Hqo V:BF{y4qB16nFA?=yt][5Z2 RS3ԅ؈a٨>>?;AՔ\˞N$mz-,W[PL-ujg/L)iZ8]SVwJn8q hpwOm9/G`bn[{Rm3M?C;ܓ@oKt(rPR2ȹU( {`ƵT T$wpC&?wbVkX)1] e7-Ė;2̾JSr. 5,֟])X}xq~A] _#IvQ{SoPWc0B(jP~ LsZ_wΑ!YR$Tnw茱F"!J0+Ho.PR"IU NSAW|[.?Qd:V/kWq '9/4Yͱ'cbKW]eET{=io$izwöiX_.Kzk7,p7}&B2RۚPpe,ޒx٢3׹dָ+ ;={Am<&Gu.POAfs.2p'tάW3Z 8nyBŃ"L{uw|92Nrmg櫣Wf+Juz$/Ts p$j~ Mpĕ[GTP93d.oӵunwʽNva:=4zO%yKEz1@pklld]\Aɰ$n駁]j sS4EUclyQӐxgUN [Lyt.x=)E{PEvo 2u9Xh]tb>fxXoT]*Ush`Qg_N;Q0R;/﯒+/`]tWe6_-Q`\\@bZ}칆6rɻT)a!ڀgmOqZO}G@ 5c~=; \s;VbkםZtժ_p )7IL|(Z (AE)\ѵzA}JTϸWV.Vix(G",.M'_[Jl;Y^{ յֱb8ӽ# G=k^cWvm5r1Ӟxx(uy? ?2Aѥ-=8ﺽ*64CRu{p8P6UB⬒=MPºPlUKNH <- /r)/Snπ:N#D=&ίʅPLRLyV" 2&[J$ ' q~qtovfb(P U nRX,K92">'23t 9m5XDХuuG؛b5rO84) ƊH \M*fWJI`P[J~vte 6X tIAKd?#YqЦS qW[G+kW +YʧƹdPx ,؉SXPFK4*j_YbLs|/YhݘbPF扌$یcM?6'7N ~ uX9Fg6 y%iEϔo6WWJw,{)kEsվB-~8(@qXٽD򢢅߹5:82[vѬ(͗B +cTf -KWmTB9JM&Z`~i W#ߡD&Pa,ۉ>X,Vǧ7Eܞ.v30cscAS绍pA aaOgB(fBuӚ͖Ui`.a~ezIv\zm66kNk86^9j/$ wۦ n{c3x!xR=~O%'x@5BUS Z BwkfbCTC` \e ZO  v5M{T۫">7c'qx;`gݶ}yP? 8B z= 2LE(R:(5f%@Kg{2 .@z"xGQ/3 N~"Lg^jʳ|Dw`:Q Q+ `t94RWLk[hS+BșNlfA!inņ+cx:FZZX1~$'ܰHmi'><| -~pU7/8R 43y E I=~C!7gt@f&$e\(/s,V /ϯZ`\#ql2uPcFv~{Ź;i ,$M<=j[ ":>4fK-jx^Q.0HQ&ʗ<ΛTվol[J.bH{G+CfЙ"[٤W: RM,e!\hDqޅ;(G5_&gMuuPi'rHsJs/Vgġ'yT>qb?/t;SdhcR8NІ0آ9Or X4\yXaM <[-r2fg쥻}+-!)z69C)n5\_?eQ@N)vkUErEWs`W+bL jSrGsXmz+,z (]c薯~Dlq&BDgBSD^ x-g9 }Δ|JĽ2; RC΢a5VĔw!:f';:(A4ڿ9;ykP]qzuZa,\YXDne^,](7BqQ)5ġ:QWO3" Ut-f8<-\jmn)elfiii;F2$ՠ<Ӥ8_K:[_ 쮏YI 11;2(@e2]ZFBjh(Ř9)-ҏb$CL?t\y~w&i2 oZ&#pe)* 7H#h/+e.dXL; +W3،W(_O" 8hq5Gk>- k@OFD o?HY-?zdLm ,Vqt jIXw% 8}$DD WU<05fVkˉc,*+iWi"=V校>O%J+Sa |K}7<\{S։e>WYl0xѵ0ڇǃ2'h*J9r5ާ bYFi(noSVd5Q4O`ꯣF3҇mzF4-D YsԳ3`_o~țc[.OW?! SoSMKn0ms>/HwB\n+[Ո2Ch֤ v.+uȤ4p8g.& zbYs4"jF* j!}[Dhz*uOV;)b $>QyΩ,Zu߄?6 ޯ$gѭ/),UÊ9 z\LCDQGV܃vH/ j,J fu߯YAEͮ3lqYU)^"ʘ!B^;fP'I0cV{[gQ3tyk90{Z~`4b틪p\ζ6̙Sթ(PME.\jPtq[h @=qӢWDj4 bƿb"Zv׳9l"l]_V9VU>M~vY>:4P8$ J1>?c*,` ى g:+u=ՅH>q/ݩD2bm.  Q11huDH155t/EfEڳ#XQk&4Mp$^HAO ֽ"~3\ T m}>K6h1fS.LTݎZs1eޡk3N$P:鸤aHGv@1 &9sS`YF8;s7n7"y-O: SʙэE}>IneƇTRL7O}Zֶv*zh1E쿑Ȟl ^Ɏ&+U-r]a0>P7!<oU^pBwμّ*t" }hN̂+9ESD'9e_eQRz44' :нrim֗崩&WzA۰osqaz6f}$Zg,0ztWr:HŊL*4/hH`CF\*B?O!v[ꙑhj~~kD$h٩ &Ŷ3޹9k,5apb")1VgTh&δ˂2`=|h R>И  Ҳfoe ~B^bC⋳SE>?o wK<,leTc,޾$B޽SDߥd' t{z ٧p! cO}b%aXOi6Η&:ܕ*ZjG*9>6nrű 칛ZZpB!\*)l.?ۉkfn.c+^`چgbMh`}fxաiJK0`+{[1w.5})YQQXo}1ݳHP}S*ֲF^CٌzRMsqCM 隟/}!MK9>J[kI~xqwP2Y^,M 9#{$i&ӈ:ɇ:7 8ܝ_X2 _8c),+Rz3m" &4L(}56Qَ.Y:qY!ȇț Uw^"ܜa),÷Z4T2Ffe#n.KE QX<.mu Js1I(p/&`53$biJpts!S|P ,fVZT:+.ysUV=+PZUF ʆB`J0hDqz8L;h'0EʹF&iwxy4'[=r;XDI5c:~oiENPQa2nod҇|ݏ CbVkp#(_g3SK|j\&~䍸OPM!6kLxrȬܗdpJRɸS1: (:X22Er/(Vs܋%JR!Mx :_҉6s0\hׯ,K㚍\xCEhV\21 Nl#kVG8BxW6iB]*Wݲi*>31;,iق b۵qR{5ӸĐvϟ-mlBKiѡw7?V&-+ >%RefG4Q$YAlNZ薜S:C-g㏆@j=wt@rG: {S)O_YP׿B}Tҁh%yy'3)l2|?+j >b0hbW^i?uu1cj<ɛRDsz Pؐy3I7DA`i8(cJ{e[I@ ,$v@e824W80,4q~T.f=DPJt($N&m*dzE\5ڋԢ9CQꂏ#yBR]8_h ?xGB&0%^Y+3{X$]L5Jϗɟ)4#Y^{ia'2Sq^6[e;F#p6dHg|!E`Z)D_.NHsP+uV6drێÕ%Iq30"t{LxP)NDǖ^Ws*u.yת㜞[YZeul| E᭧^z3TD{R%fDR!0DTX*~ y"a´O^Ah uU-:M3)v0sIS{otez^%RE183AZ6kN/w҉-9 /a?-[&(>]`Aq-!0;V1~3q0+. B0Ԙq=ڛ XN4R< k l ;蘐ǹңv [+!MV3v'y%  Vg;Kryr0UN*n=j._XM"a|ɀXUaݲ G3P7p';9ԑJǿ[*qck wxa0YOL9مu` JҽB9NW^awJP= Ws\óg ^%u y{wNu4T]s4ak~#s3CfS?^d)3{ [7ءT2=bC3\QFJ Cxp =sdngFO-z@=kz ݛCUO͊=!0@PnMϘtR~|m3iɵ#ῼy|ӏ%*PHr @yI ӳ:vOI.KY~ġ2km 4j"w@:50@(rap܃WSdO5yS@ !jL 42_6,SVYhDQ6L^֣^~#3^`Hgŗ6 uM!1:g+_jk!~.vcD79nK.%Os"|:"\%O1(Iz0m/tI5?^/~Y3b?IkTt'bCFt&>Ҕa1BV*:xu.#C!;l>M[`2wyjjX%tw{'7EnHYYl]N;Ae*0T/i|/IjIحcצ?OI`ghTc/}i5?@&g/‘zѸdbhxVh':a}RܝE0N@.n}u弽Q0j# Q N%ҸQ'tSwqϧkt95uqt)8@Ik1$}ې7yK>2AǸU4a/iHV ZE~$ ~xWs`»)^>fM6Ld[΃l@S9'%A *5$D1^V,Mw4K++ܥWݙr<.u#i6W=EBl3psx]5VYc8Dy=;1B,:`?,~[M\ֺ6HwIHi,K/1.{ 4xԸ 5C%cPxs1:ΧCg7 P]>)S6+f0~Em֖핑?]bxh|`2l ք G%zQ#Ǯ0'leϬٲ[~iz.NM 8Cy҈K0ZL`";x)( ,d5K#w9yy&"26x3Rbt' <d.茨ݛ|9oMV7kU AG@ShxTx (ÑDE:DO} }^zYd^?j5#D&Q3{.L h NkM.a>W g#+ⲧFo8&&ZDqZC( Sh~eF2&G~l{x~stE^L`/s:8fZQ Y|Ue` '_!PȿZ0֍#?^yQn70#?Кrr;[ h[fiZ}:gcnK\Zf#+nʸ#~?1n+_vs*&-; bz>C/ӽFR~yNyXJ}\hJ'A_*Kʸvy[$8TxTܼ88’?eafn:aٳvKqUu#!4Få';֒.GY$~N"ű.aMSv:)RpD˂}q}K>+T>R&y*>>*F6} 禮 ,I#ATMNHI#^QSЏ9N$oQVT4i)JsUrmŊF(N?v.Ʈ>¤Zq_ `ۻT$j!%!~Mp޾J|s! Vۜ~q̶I m ؇|x(7| Y\ ܳ{t`zv6Q"MJv^+cS3g JFq$:㰁RpAޙ kD-1;0[4 S#l3a;TsSuŤy{cL,KG EK]Lcyt@{#*]I]SZ֡8EMo6O6:0e-wX|טQ]);cu`#g Iw7c gVnzŧL~bj?Γv@9^ӤveZk]Owͱ!B bH:- ®cl,;5V IFI0\r@:7j^)rڼbH nO}ɜpsLz u0w] `0Z;hZ8)Ьs|"BM?M1|x!u>:_: CԧKPX~s<$I3q XIϦh]CU0j2ĀuAys]Ṛ*OLJιT(6& @dzB7O̕޳0ө?%*-B۬.Bb[]`XFːeB++r|b/AQJo`t%X׼.O dPzk$X5Lٯ+ǏI8L0kxpB3nau#Ӫ@ҨV!kZ)緦MP_2*u\a==\,kEXij\ H~ j} 5u-G/JņVN,xWe/ˑ'Kޯ.Jcэj@՝y:ի'!S$Q-g84>S0u t:A%? \ A;-i/:q5`©DKgDP^ŢHM>Y]z"ZնZmL@4A.P6~YE0 46 :Mqp:l#}"󠗐?Irt-Wڌ<2? WLfn$Nh' ZOZ1DOe><@ j% PFfo `Ju廨7v Ō+lu-9F01!pjݝQ0.jiV4 W")Je,a& PhhECɷl]7닌;7DXѵ'N(%iEo.k>RFKEI1mD϶u5Ey[zCS ឧ ICs C7 /{5DºoJLQ&,U*_62ۮj7@*tS%VElb/)ۦ^,,鲪[YIB%$]`y`,,%ij"D^"|Wʩp1_Z "W x8{=36ؿ27~ $dVd!P > y,qJw"(1D7qu͋tne8_Vp4Ujm;W9Li'E+!6ɫ쾊IiLėF JzJ$H[bx87J05`9Qě[W{Y+qN})V]p1^*|"y3)12vNx'HBͬR?)+zNRE(%]ȣYz,|%l`q 3!^'cDYh',BVC-AU5/xVݻ3B !*-S R ޱ59>;i#R{vis"a1x- Dl-TNld.WPŏyf؇+>UvvDW) !=1=εDۮ}hѩϱ(^ǚ=2Z!3 LжCFLsYg2Aa&{w`U/=B_=/o< x8:]{A wJ\RGθ.{,a`a^& dװ$p.(MK: v~'l;nH>%j"@(衔9(kԊ4W&,,(2r 5+ !p+h35?z7 Q ݠdDɾ[{):f|Hh<\RKb{0@Kt=<%H7-a;*c/YrBUugtqR?y~,e5 p#$HX>}XCș,$r(`C$iϖMoNrZ@oi  HG CeOҨa2)4J~4l<+7ߵA-eIKFGj'IAZīٟ2z-v+`iv@DP~ GU cKK(=fӣ_v.s3PY a\?(I<qP}p>vsE4K% eee~?B"+1z,Av"ER(5N')zH*ן-kJaU=!Ǹ+=A*g|"P.Ŧ2S(4%r=!QƙKcPٷC.`<71m'Zm&ױ٤p6k*Q3F|:Eg=)b܁_;hKBNj ԩU{i:R*^㔒Ƣo`q q'% %L~V2lر"Qw AH 1' ]h|+6>ձ.I6ցơW٬GR{SGM(St@Ծki?^'y7W@§~\bL62Zon DkWRC Cl(ywhUB52!Q>1Bʐ=eՀh r]TJc}qAy}G-#Es :˜ S->2Ǵz[D/Q5.XH[“)9F8$.n_`9WFCMcYm&.]@X/}'дՃ%LHaIgIx"D~[xdr5^pzNR;%K%#:=W>S Ia$[#R,19m? tj$te>{i+(֠jGgTfBhM"$E7] dKdeYHi_JO֟z9nq["qR-[v.tRXJU#BTNv/1L?!o_+˟/ꋋ1a_|5')VMsa{|JT|Fb渊6F.xXesݡ_Ѝ=CbbHv!eюhF% WHy+H}=m84A!9Z&Z'Y6B36~\X݇y8 L78eih.'8zcz۫^k逡܆V_'6; ~M>"~ptfdvcw7"2W6iO VGtF` pM;ko~^))k5(L ,{ppۛo?9gE:0@8LCk륵/ɢB?Je#Ů.2ⓣY-[ꮧ޳A"}k sj&=XPE Wyr^YŇDT/d纼GjPO~N%9z6|D25 \mIx(NȞ5 6&T*;ŝxI(D d@f{akMeRjw-a8P/6ّXW`Zツ6IV$o6y LMի?܂}1Kq!e@lCvHta~Vf1XضOt3Y!׫4*9f֌&$ j%og;=?2ua%rlrkN7@ ! /4B¯yE`uǦ7FlQ 9֛8YIЮ ,qW,Ř=.0 :te&0py;ك3cvE&M[ɬ,J'#e+8 FJj.U VQг^ ҋOru ?*?(ӹ;uG]s\a8ΜT쇜(tlMt^ ZBiQgk$ï'D,+ƗV17F07Gs"4À& _JAu'jO&4ޟrP Ⓡ6ٞU 0a7g:ECB^O ,?@,8`qz M9OA7~4|՞9i5"o|KUj#,>d<g, '9D[ 7p g 9HfO6tl9ǻqnXwVxWn vCNj0z8(@fȲx8e T, .+䠙<h`h 2N" A"7sSeQfq?|806Ú?@N t`Zf6nfJTwԮml!3 %u*l.ԑD$&ZۜqoHQi IJa]XQ}Ui4]1lt\H9DCM#ɟOR`p=/Eʾm8Dya{Íϒs'+p4% 5,Pzr+OK0fT[!;}e6ܢEc Lљh%n_̍cx@yb O} 41ހν-HcXhx-T3{xO b:nCĺ?qM}JiYA}Zv*Y1 Ŀw=@ky)ޗ kXZۜ uuv,H V"^؃4#/k)\M=JE,9F}b̌s4=v{0FQD [L X+VjBW-5zTynz~E6+NyV%Dix4䏲Ơ*"0spwߛSr@IG:2 {oV"M2O9ST?X׿UjjL=vo:g.cvQ*GKpq 磹Dga"=V:\d/_6R蝖R|rY0e@Z)@;6F *`X3)p4ϡܞmW.PaBϤ ~rD$ZY-J}[vH̒z:0{v.yk$D$T-ӏ 6O_KQ̆P\h ƒ0CN+8^X TB>cpb. {#M!̥q2J@p7$L4U}{0֙(2Ә0֖!$y~;.\n3a" n㎡~#YDGs0~7|'x mdk}̢/Fڤ/ U#Qe) 5w*6r uo=4~R׀_ep'sAxՄ>Ւ=,=A!ۭ(M ѝTPGh]st` Ji/dPA vp_\{nHfo6HG݉s8rϣ8lCyن$-??FjD #_S&;^qjt-JsGvecD(s}W lď 8IJ$LٿNd(ĻޥɄg2: HoZa&s2Ӟnni Bx?Y+&ʣ-27ǎVXioLm*h}߼>YK.p& i7dއTJOy7EG ˤ7`LM7Jwi*CCyju+hS{ 䉏!w97DĒ.C gݵPT}؇~R8 i؏ M!ȶ Sh,`*N\dz'*ilRn"/Yw]ll*^os#*iZ(r!0˲kXKL;Mhr˵,@eUd#Z*=pvB˂i!Kgi:x~:<!pd ZYH zm` U+py6acu66B$Xd}V6 ynP_%K ͤBH3vz"tо4Fxk ;`B?;g CF| “Yi_=1d"idrsg<$,c/*II.Oox+—yw0݋NMDXt'E\Tl^"yôntU(vYjyȕac%V ei oSRH+gt./l֋yI}7Xm谼D( Okg7#Hr-DI1TIEKNx_cLMPSW{Yrq~d${_29Rc'vÔ,t-WM+e3I` iUpF-3 o kؾɢDQ $6& zJɹ+~%GL=UDw8F{IDp+9zK mNp 9dVڅ(twZ :Y4gX0 apq,P0L8*+-=y`'BgHL}JbnkS(-@uqx2g|Iߩ*}D[LΉlȴ~3 ϢG>  I2mf~}fm8C ֖MB0eWv ci|ى@!M[!7u2zKAkQ][}\@M$WAcէ|q6jUQX#z1$ϧ.ef>$8%LX3dH4z6cBPy9_YO"4i'H%A~}$h%w9y(%$Ϙ7V"nJGQ|țs:oJm^͙hp?EE$S!2(n.SX"R[uQq|> ا_ :4}Y@anyM1w%v\5>8E9FXX6ͷ!^?Aӫ;2cˎrVb(ECYd_#p8Q/IW;Pӂ v}XORFt51@iElr1RZm7pj/q1/(0[SO]5 eCK#XzwhB5Gb &CRΠ[2`WPej躂Ge_:N. Y=l^zc<$2I4hOz+˖r`ή![~3mp.{R=Ld "g9tXճ T:,y7^m:jBgCO}L1Y[0aY/3pc g> xFޫM99`>>j M>VJݺPO ?o! _V, -FV7\ =xv._qfE3ɽM29^YT܍vq7@3_NaNJQ`GHME\M\tw8^$a9H.xŠ>-<종9KLX%5slAY!H{| J=yz p\ J>Ε>Tyܺ% Xbj*N}*ODF =&ȗRxӏ"aw.3ZCE`R5LĿ\pB/UA ,Gq2h@#М&v%e m\2K n5wd|EwgbKQbӱUB-=D5/U! K#&~^cE `ENG(c^?젤 `rr 8!Jv2 JV>TKߜ!Sa>g}'5FВ:_lmǕmr.cW̖ E)J;w,TXE~ Q$$dg{'kG+t=ׁ=ȗD}FL/ |@0o*WCC<`E-pyǝM^_ <50eHr HO^jrXm'&znM3vG_w\mtFko"[l[-ʚK׆'P4D]a&HJ L†[ }j r!"\KP}j"btfFQ|=!Em&26 hh,W3/RET>a(qhi`LM=hBMtc._FCMS3EjV?fy`wEW2lɄY#82<}%EuХAzt?/ipQLSH-g Eb,vT=EPa'3?:,Ѣ0|An}n o>zX  #Y- 3s}BBso18OGi )oA@W`KZw,RXΰe$m 0қ?C/wDdH:!AOԣGmQ u LU p͟'Ҹ#B|=EǧTA2 9@+b2UX(H]`O>\$X&w4tV*,r;+70>̐#$_<7q\hwmŤAr:r嵲 P)ŸEGM@ݭfX|BB>rgwRZ Q7ʂO԰ID_ }O>"2ڌƣw]L◩&OUk)1/raLNe|}A:]~_hTJaRHޅ7b.[B/6[OcS=9-`Ώs{Rq&,2:Y1XJ-& bOn+Rh@U<Ztc8%ؖi2'{K"5%H\D8:/s(/&CEṘT2[g0&fs(n-N?~T8lV)z U%!X/ܒQ!6_=& û|BBNyQmDZҿmoy[@_.xLu o:kh(wk3h|k []WWeTa%\uWL`[*=xιaTGMҶE4Q}<#@WV3uEFE6oKʧ`Ū:( n"7^mQ{Tk"cdV/ #\*̉~hnC )s+j)e'4uN0id4@8yW_s-j1a__q9S3XB77^xܬWkKa!qNj\@MCr_,~l%O5eщ, uJ0&WcI${<eIێWj9W%ڬ095–~$S 7D:)VeK"扎@&m@tn3CD\{5p` #;ٛ:_Z(%3BS/";s5CkP+[vPuE5 *ZeÁ3f5㋀tPɕFH[f W {^V#I;J fW.k/:xxS`M xf>aH 't)`LRXS2:JkC')dqȜ`fI0 9z߬`[[Cx$aZ7t2j_K@E6)xi\7J}Wʶ۞䀦"*%\"=?sB{"B$$:;Q+"8tYEUxG)n빬-"!h()\vva:d]p@:1դYOwD0W- g ֌2wB|CXqE3ף}F4{ϤS"5C_#m\ywTHGi(@8yWֵ,^Mtɳ.p6SG^kmSJYU`/$S&etaxqA{'SPI5H/]3rS7M./iq?gtε0q!@c&x`2-? nW^UMoTA#HV*I!8GZ>Ǧgm r '+`x'SX8egD_8&u[-\[+C=\9 Z#̺ZJޠ X.K$N@^r䙒DHoC8w/5J:?nZm@ܢ)`\Jv Iyǀtl+[$XT=DqK$Rʄ|^Ihlz/5bd7Le '{'H~*@xFEN+:mDsR8Uعh@2\#aHu:#0=_P }[-A0O`.>ο :GKڊ!s#(ޗ1h0(*.Pem1/lSCd8̫3ȔFQ䖐WpEv>N{a8z؞zeLo%1i.]8增BK<͂6 aR";R,-vqXiKX 7-=rǻJh˫Bn=qz\",|dl±Yܝ.Qcm'#Pc"<ӄapr{nS5/UO6oo$xE%;ü.ma cB/2@΂]AZjy!+S2{:&Lgxˋ/JY 8D.176&! : @9 oEtJm!)GR)C3:U`KÎuBO7lFvK[+& ĭy@kLIF/0/tAH.$ˌw\g|ʷwSo4| TB 1powJ^Shfxà7>aldp g'bs^TbF'v +k#u :>MDғFG7RiG?=:2%yfe Mz0}|Gݝ{Pm7y"f53u#"njV3ߞFgBAmF!!A {̛ը]>)n҄g#DB [:">>C]enɎZRˁ$De񋉴guH\|a5i4gl?p@_!%10Sk:C01?)NxQ}r9RP32-:LVӜXgkVlU#N&@ԴPPthCZQC-~V.q0 1Ck6LJUx=ESM9EcDV|Hl:`4N t ؆nvbY. (˕+*\+,z&K 4R;8O{톻kX.N!?pC#;1gH#UރM)k$AZH(ɇd s(#M+BMܻKf-,AC)^$$£g,׋UADdê!G_RdSXRϹ#ˀٲtST_Xt TU\i~*<0^Z ;?|U5 AO AYtOS&- ڴn/ &+S(ȥP|KxbfKFPH #Skd#ӻR9 NfxYa] p2~q( EjdSpseĭBi~KLȊ1l/IH!rֱ:v9OTU~}Y̬#<Q[M&e;gGJ;.׮_}@FO2N12Cš.f,tB+ID!{Mis҉7Si} ]'Yt $i;9Yf<),R*mOnBm3c!A jwB*m.X ~7=NfE8vRl-d[`tQPl@=kG">svIB,ف8H7tJb%‚ CṚ&qt )gHdԋÿgP}b`}-6LCp (I# M L+gj' O%i9:1\?,㧫\"$ηE>kRC^U3|--X^y E|fX'OXMwjwtƧҹmp0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 cleartomark ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1707393948.0 reportlab-4.1.0/src/reportlab/fonts/zy______.pfb0000664000175000017500000027424214561141634021261 0ustar00rptlabrptlab%!PS-AdobeFont-1.0: AdobeSerifMM 001.003 %%CreationDate: Tue Jan 12 15:56:45 1999 %%VMusage: 87626 100509 22 dict begin /FontInfo 14 dict dup begin /version (001.003) readonly def /Notice (Copyright (c) 1992, 1993, 1994, 1999 Adobe Systems Incorporated. All Rights Reserved.) readonly def /FullName (Adobe Serif MM) readonly def /FamilyName (Adobe Serif MM) readonly def /Weight (All) readonly def /isFixedPitch false def /ItalicAngle 0 def /UnderlinePosition -100 def /UnderlineThickness 50 def /BlendDesignPositions [ [0 0] [1 0] [0 1] [1 1] ] def /BlendDesignMap [[[110 0][790 1]][[100 0][900 1]]] def /BlendAxisTypes [/Weight /Width ] def end readonly def /FontName /AdobeSerifMM def /Encoding StandardEncoding def /PaintType 0 def /FontType 1 def /DesignVector [300 600] def /NormDesignVector [0.27940 0.62500 ] def /WeightVector [0.27022 0.10478 0.45038 0.17462 ] def /$Blend {0.10 mul exch 0.45 mul add exch 0.17 mul add add } bind def /FontMatrix [0.001 0 0 0.001 0 0] def /UniqueID 44277 def /XUID [1 44277 17709 6867 29516 11444] def /FontBBox{-156.03 -257.00 1194.19 910.23 }readonly def /Blend 3 dict dup begin /FontBBox{{-131 -236 -135 -201 }{-257 -257 -257 -257 }{582 1217 1274 1922 }{878 974 890 974 }}def /Private 14 dict def end def /shareddict where { pop currentshared { setshared } true setshared shareddict } { {} userdict } ifelse dup /makeblendedfont where {/makeblendedfont get dup type /operatortype eq { pop false} { 0 get dup type /integertype ne {pop false} {11 lt} ifelse} ifelse } {true}ifelse {/makeblendedfont { 11 pop 2 copy length exch /WeightVector get length eq { dup 0 exch {add} forall 1 sub abs .001 gt } { true } ifelse { /makeblendedfont cvx errordict /rangecheck get exec } if exch dup dup maxlength dict begin { false {/FID /UniqueID /XUID } { 3 index eq or } forall { pop pop } { def } ifelse } forall /XUID 2 copy known{ get dup length 2 index length sub dup 0 gt{ exch dup length array copy exch 2 index{65536 mul cvi 3 copy put pop 1 add}forall pop/XUID exch def }{pop pop}ifelse }{pop pop}ifelse { /Private /FontInfo } { dup load dup maxlength dict begin { false { /UniqueID /XUID } { 3 index eq or } forall { pop pop }{ def } ifelse } forall currentdict end def } forall dup /WeightVector exch def dup /$Blend exch [ exch false exch dup length 1 sub -1 1 { 1 index dup length 3 -1 roll sub get dup 0 eq { pop 1 index {/exch load 3 1 roll} if /pop load 3 1 roll } {dup 1 eq {pop} {2 index {/exch load 4 1 roll} if 3 1 roll /mul load 3 1 roll } ifelse 1 index {/add load 3 1 roll} if exch pop true exch} ifelse } for pop { /add load } if ] cvx def {2 copy length exch length ne {/makeblendedfont cvx errordict /typecheck get exec}if 0 0 1 3 index length 1 sub { dup 4 index exch get exch 3 index exch get mul add } for exch pop exch pop} {{dup type dup dup /arraytype eq exch /packedarraytype eq or { pop 1 index /ForceBold eq { 5 index 0 0 1 3 index length 1 sub { dup 4 index exch get {2 index exch get add } {pop} ifelse } for exch pop exch pop 2 index /ForceBoldThreshold get gt 3 copy} { {length 1 index length ne { pop false } { true exch { type dup /integertype eq exch /realtype eq exch or and } forall } ifelse } 2 copy 8 index exch exec {pop 5 index 5 index exec} {exch dup length array 1 index xcheck { cvx } if dup length 1 sub 0 exch 1 exch { dup 3 index exch get dup type dup /arraytype eq exch /packedarraytype eq or { dup 10 index 6 index exec { 9 index exch 9 index exec} if } if 2 index 3 1 roll put } for exch pop exch pop } ifelse 3 copy 1 index dup /StemSnapH eq exch /StemSnapV eq or { dup length 1 sub {dup 0 le { exit } if dup dup 1 sub 3 index exch get exch 3 index exch get 2 copy eq { pop 2 index 2 index 0 put 0 } if le {1 sub} {dup dup 1 sub 3 index exch get exch 3 index exch get 3 index exch 3 index 1 sub exch put 3 copy put pop 2 copy exch length 1 sub lt {1 add} if} ifelse} loop pop dup 0 get 0 le { dup 0 exch {0 gt { exit } if 1 add} forall dup 2 index length exch sub getinterval} if } if } ifelse put } {/dicttype eq {6 copy 3 1 roll get exch 2 index exec} {/makeblendedfont cvx errordict /typecheck get exec} ifelse } ifelse pop pop } forall pop pop pop pop } currentdict Blend 2 index exec currentdict end } bind put /$fbf {FontDirectory counttomark 3 add -1 roll known { cleartomark pop findfont}{ ] exch findfont exch makeblendedfont dup /Encoding currentfont /Encoding get put definefont } ifelse currentfont /ScaleMatrix get makefont setfont } bind put } { pop pop } ifelse exec /NormalizeDesignVector { exch 110 sub 680 div exch 100 sub 800 div } bind def /ConvertDesignVector { 1 index 1 2 index sub mul 3 1 roll 1 2 index sub 1 index mul 3 1 roll 1 index 1 index mul 3 1 roll pop pop 0 1 1 3 {index add} for 1 exch sub 4 1 roll } bind def /$mmff_origfindfont where { pop save { restore } { pop pop } } { {} { def } } ifelse /setshared where { pop true } { false } ifelse currentdict dup systemdict ne {end} if 0 {currentdict systemdict eq { 1 add end} {exit} ifelse } loop /findfont where pop exch {systemdict begin} repeat exch dup systemdict eq {pop}{begin}ifelse dup systemdict eq { pop { currentshared {{}} { true setshared { false setshared } } ifelse shareddict } {{} userdict } ifelse begin } { begin { currentdict scheck } { false } ifelse { currentshared {{}} { true setshared { false setshared } } ifelse } { {} } ifelse } ifelse /$mmff_origfindfont /findfont load 3 index exec /findfont { dup FontDirectory exch known { dup FontDirectory exch get /FontType get 3 ne} { dup SharedFontDirectory exch known { dup SharedFontDirectory exch get /FontType get 3 ne} { false} ifelse} ifelse {$mmff_origfindfont} { dup dup length string cvs (_) search { cvn dup dup FontDirectory exch known exch SharedFontDirectory exch known or { true} {dup length 7 add string dup 0 (%font%) putinterval dup 2 index 6 exch dup length string cvs putinterval { status } stopped { pop false } if { pop pop pop pop true} {false} ifelse} ifelse { $mmff_origfindfont begin pop [ exch { (_) search { { cvr } stopped { pop pop } { exch pop exch } ifelse } { pop exit } ifelse } loop false /FontInfo where { pop FontInfo /BlendAxisTypes 2 copy known { get length counttomark 2 sub eq exch pop } { pop pop } ifelse } if { NormalizeDesignVector ConvertDesignVector ] currentdict exch makeblendedfont 2 copy exch /FontName exch put definefont} { cleartomark $mmff_origfindfont } ifelse end } { pop pop pop $mmff_origfindfont } ifelse } { pop $mmff_origfindfont } ifelse } ifelse } bind 3 index exec /SharedFontDirectory dup where { pop pop } { 0 dict 3 index exec } ifelse end exec pop exec currentdict end currentfile eexec \+lqZ8$]}8)!ci{/xΦQUF׌e! T ˋӦ+Um`0lVz 6B &NK8YϣE+Aa KCF Rp)SMK5^QbLGZR1f#k|Lipk CR*4b1K063.;8|`"e^Hԏjzw]a׽%!<3^] sSB>CUUi~G ]BXf:g"m&nK^َ*q*%Ys㏚|ꪎm/Ͳ͕85>A/Z:_mM>5Ibܵ&7:9"I瀠2]ᩕkz e#`s~kW҈NʲΆZUIH?8o ܷ*CP!O*?\j!P6!XgVz[niF.}Sid mTwUDCUlr_~kaB:awG'et##s{~7V|=CtYxWeG9dAN^?C1t lT4~BٌF1 ٕ? **ι(E]n>&ʥr*o_s=, ߃ZqǏdX9FEpe/,>|@7_,ʠԤb"7bß.n(`"@͢Ȭxtvz `jwȓFfg>+G{JiVEW{%Xk k1x#gctmevE(x%`s}&m@vML3XVxi&kF6[g1i24k믳HjúXoՔ.>B ïϩGo6|+" G"0)Fjx/bzc2^6hѡꕗxL?"?r^jM0"9h=p\%5Gp)s=|5$]Q.6' f63Q)̙ AY+l%>2'۬eB]VcyU8X01 xVTݪg3s4_B9}E%a‡7d5xY}iMsH_-g'}|N<ƙjŨy)M\s/IAOG}b, _){_ &s",غ2ƭCh@?őr xى*>&NK%O11Lal_ו,D8c ݿLTɭ-zva)&fBc sgWM?7|rw+~"+E#\R"h "mT>,pݚq G>l|;!afH~4/vv4%ˮyuXoܳ(D9z=u إ qMnR{.8e,<|aaz\Gd8<ɱ7Tn`(DGSJdrj ?ΔL40[Jۘy.]Mj=. Ds¸4iYg9Ͻ.ԩqc!H ø$YxpZg$: ,MF%Bx  Q{\;iIhw֟+\-o yB$Nx \9יsq1pnMkOp8Mi ^oF..Ҧ wQID4lz(_*g_Ӎ!6u)Ñqr2Ԯ/-DELqxG?R -"=}HZ1xƭJ%{4mce:,U@^dN:W Z&ڇ3LES^ 3m1/oҞ=Z 8 Y*}۷wwb爨eO'h˜]p"\'Z1N ̓Vݎζ'3zc|v=jio)#uCjlgί]; vzE V5<J7XϠ5_Mʿhvʿ{ dhXp̻{Y!ECivGkQ6D/IoMufC;aa5 .5f͘~Gi}d)9BQP=U$e}|ؕQkSXaa[_[1ujh@B')FR0lз/i?I)PM&{Mç/_ [})ڈl NVj3%t..l:Yìwj 9Ap{arZ X~T6Ω\4AG TMѻG/=ʟ܊'w55WO9-Eͩ(մRԋBD(]7)-|(߽w Yۤ9랔 ?’,6Z9C$9=Kȑ"(HfϊQ+ +H% I`DmHkeR&i1c&]s=OkjA}wiOΕ^|~ }2B!xL*\bv>* PU"_lՍ9J}h6+k0>6!ŏ8C])lS}qϷe:'I}2bA { {=FhVBϨ*MOŶR#Po-m;Q!Ѵt. y>wfnHSN[u+idpYPrrI%!|BKk#T.rcvA1NݬNU2HG vz"!  ڢ>1}PEv^.l`,5l(j[g`پHs'\W41g"&gdۃڲ8NU,-+GǫKZNE^ &+=:34_ ƪ`t%{UjѮEW>qHD׆ڹW3#į[{Z:DSHeN?BElR=Ji;A8=[a 2aFGqC%Dz|}]+ٖJ,7|8rĴ`FVf+tt?se SGX*ڽ']*ז6E禋D |1Ubۙ}ўܗHNw8<}f<ԕfݖD,-,HVnfD-\j'o&e(rᠺR'VMgFp{R,J M(:x$G>#jb׈mL݊{ 8H?\ݽ ,* .B7ٔnJ +m `011̧(oKnHk㎛ÕF0qflH%tIlh 3y0qlO0,"aY= kQ?2(dkV65 \wnv[3*J5ߣD,V6D{j3]}'q'n :3q|%ٞAamTuu̘l ZڽiyhyhšdjA6hefȲWc=|EF[}b  7 R|nfH2\ZzGZ Io\񁛯^by ө`7} %8m.v9b5chVRIλF%A/ZY,`$,ý_C;~.r9yj|4ՆX>nwٔ:PwazAdݝN̻ϰkfAtF,0Kb X/Rq(OZȪh[mŀ%΍0kd`֮WPL %Wr>m@N_41-rf R~쮵NZЅviqq,K*J=*[9 TmC*:k)r/^K?aa̓$vE<[Ɇf|c= Vc\e8Mt}_dY@W‚K/k?zJC5-y-HzWbQ2a!skK#N&9x `v?P=?wj#1E,Z~usU8"v*JXD3Ǝ$H0$1a|Nsi>H:l^^:>/xNbkP&H4~Iu:\Dt7jT,C-҄7+ JsM,=ώ80F0s3R9<8ٗ p#Ĩ'&"uC:t RxQfA_H.E#3m5 N[b>zWz3,N &oPcK#>u^1أd"Y.QZ;[V)ػyۢf&\>̋DF~j7 +6m̓mB;%VD&aYN$sV00R;>7iڬqc>I 9eeA9È*=(1ڥ/WqaWmގꩻs `B:C|0̒qi% !/@j@g,b!0ӠSOE?4J(nJ?]ץ@[j^ g/ܻu{I_=MDU6!f#?N*U'/G|MX_’CEVtQߓ׃UTd5ErUM>'id:SlƠ8O^ޅU|Ny?!{e-izhȕ-̥)ⱝtt쭰&":q܉o8K>KDѣStg9aDTNi['Y=-`FۯþI挬r^-fQ '4ilA¦ G}My"Fm5s ;U>.;+h oK#TW3" Kr5RZa"iHpAE fc_PN0]$P fC^fE c U<*$T buDY 贂ܼNk9¥r SL&40,kan |c`JC"XaH+@6끮5[$ }$?nŖylfp:m p?Ư]g c,lXƋ/Qnq 㸼/E(!8D*1Jy "7et#JMMXXry (-g`bEˬEͲNC2|Oh}w5dO{L='Pm N@`t1葛ZY2U`K\:X!태>I(i+7Y(xDeg yہr./ނDRTcr1t{&q<|AtO$ʐ$CnbCx\bj8|GΨSSUXA/`Β%Ăv|Ϳ!&Aĝ'2ekY* ֍_f,+z^YҨًbwpj|*iP&FK/uLXir?x u icXтh& 2CS2vӟIeڛ-ߖ8(yiA&l^ =0[t㭜@]f3sP'!ż'n[A",yGW8X3雅&B XttA G2 j}+Gu}QaJᎹCwpha֍_)?,?$vi՛]6Ηvs,z*C+c)0#LJ9?E?ڕ߆8y4^f"ģkmf;ZBAO?J'0q絺rw\XgYJ _.iĆu,BSP˨@=kP#&aWqxT$g#ӕ1֘3@d" !C N PY*<6YA؏;xZOk4\M UwclgF.7E"\ T sb3`B'l oc^1s&Lb*hO&ӷJXe3gR:vEʕ:PBd ý!=a麅K:"r{Qw9wX6 +l8%;Q {̋د+ߚ6gH)`:ΈW@mw,|F%n2u3MyYBDk~pաD- [3l6E:¶08gxMaGZ6ȚQlxNʵhqְDXy'T8iU4j<$/'=0GvS-\)F? f)k>'[wNѨ^)|厣uw6 ^xN"$oNw/sON @ceSٽKYF)7C"2$hK;9[9#)wD.n==r>K?t1Vv3I|I4=%U=ޏd^_Lϑ_mCD&SĂgWw3HYgBÂ/gF#*YLao "q+ZFiq+A(@17{5ސJe5E ?iN" COf6"X.fDeIi(TF(E9s5߀k%@V56x$pǐZA$^/¹ T'Ut)TA/%m3N9R؟*kl0,+ݵ#HJ_jQfl_R%* K1V^#2o`É8Vo\/l_V`Msx\@YS 1=l`*H?'*$.:S^UX2{4WxqQM?mKN*.xZE!.a'+0⹒$|͇yFJJv[+%X5OprɅ+#wVTbZ;/i('{D^Vіc~idHHnQކ &ٹZj=r].`9_QhrRJE-])–Uy km]<=] _U;i Tҥ׷$oo;ڻ?rp c͛2y`,jFXL" @p`ZV G;*UAC/Ìe@J Ð#\E^}PnMa8EB2n?ZEL)?Т*DnDL5|s#w/b IjYBiibmǶF Np[3zw1hY(Zjҏ}1 elb% ',DҶcDyhT&~9]mˁW8KˮDh-FڨFg6#j 5aED #1kkqJg:@I֛-uM{M \ޮr,j-(%¾\^V4^+Z8w<A5v%"Viz4 ~Fy/d%WWOֲ|]vdAazW7U~֔`Jv%0fTܖ3'bTzypA>s7=‘˨gʄw[ NgFѰ*Qiq &I){L~Ƿ~p1 d_;Ϯ?Rg㭍6Rr _RC;]K8;!sdwmݙ9"|2CA43B<3SyzR(/.U(EX:􅦹 -T/u4cp0O,#: eoK̋U^'8xKL3]o ;ImI2!ŌVI[(i fí$A S^DacYoqM͟Ż~Da Qs Ly 7wq[G4}f nؔjI4_(詋YޛM^23c oă_ݛb_VQŜaҍm|Rv{ "#j9ޘN ] DvY:nQ!E+ޙuSrZ*;iQ0)a)|ۗjp/ms0"kJ?[y ƑH÷G"[;(pMo4#cfoL%e|H)_@͝SPܥK&~_CeF x?`s\=Pv b9K27V@Oҳhw. 츄TunF"5'Ut=9w/V]4,M2R@%!+ŝ-hҫ%Pp䣍!@3rgýUJy֬_uR\$MR\~NW_%"A\-tkMwaO$^ S" yt$̍{?R/Ւ[0J7XgG ³ΥP,QNsEM甐sgԛ2:w[٠(hefѫɭ#x)ZC|K]4.)K&)OT`)wwUD}$4Q)t#ՎS#xK/*6zA3c8 F$4?=eY}r f10̚LhqCh ={,O^]j~J;HY[O'P cQ%er4pD|6}gw=+'7dq&$@pC}iJh wC]-YOh9nē/Z8-lMQ*X&~MQd*Tr]S M}A :SL2FnRل= D+CDl S:"~Pǣ|PJ`&ZAipvXD*$\` ?SL1s X"@ִĻ";ʏKp:rW3Sxq?$U<_$x>+ >"Z RKX=6?n;}h)'LPa#&V<"&ϯAI.۳ wOoaO5E0KC@)w䬿{"1m/Y]fz1:*c|aS4 Ú N "2(km9T~ A.RQ`k^LMSۦcs*dH47ĥ]NdzʆOA?nQNUDy۔s4K ޻@s`AKrs,2[psybWTdBJ(=;SzLV|JBǧք͞KкV1Y66H4cwU}K /z5 N|' 5-zyhc|qE /S tl<B'5ĥ/ɥ]]7p`(WU ѹ&v_f)N)r`q@+ԥW ͷN{o ,F3GA/6BVպwBwD|s$(pə6Gubo(~('Mn3䏰7 d慂)$"Axpr^[k$JntGU$V Gmp9tևuQPmB`)'LZ?[qkbhBfbz`~meӉyFt j9ELcm??AhvSM{R$-BNE.kWlF Ŭ9ֽSbZw3'd8[d8/tMEE{g ed_jGp[%107KORK2##RIfo}> 'P^LaKzFy-9`p#J/e CH{*K ,k컢sg箥^('R^OFt}sXm;}Z\5:8R'7гCakV~IS;Q4o U5cy 81JRdFq0YZ3*Df<QoH D6}GF?ЄGt.a" HVC!>ΦrWiU&HTY27h֥fH}SŃAv/ a-' fJ:(l ##?_Dҝgo?ӖdA4ct> p^jwm9S8ZzGn$O)p!(pD[`t% ƺEwGrzy@} sc[lع'|mI%! f+|!@__?Fx#ߡ;$&xwUht2 .{Ez=0xxۘM 1֭qWv[ ֺ:y'?3'Wp%4C~$ hu3Q ҧ=tt} +2CKJ`\~bI$07Hr~!_3$r=ȮOTL^+P2 =y÷Xw7ISg& '37OEE`!_ޤ˭Mg>_4s4>#K#*kHJyl>/As?QY`QG燤@ !Q2>G5rGy8؜G@GYl_ #E}CQ}\rfՠE+G%%ܟ i!%3iݿ?ye.+7 tZ%6rroDa?8&.EqJ2"2M3TD}L@bX`u(Lex;!WûQA.O61w w@ҦewNWs@rz&6o):dylih)T&)pAI:P"LG,zL)<QŊ^qcCXxD0 Id˽<.|9x ǷGnh)27oK!*f=PCK 85Z~XtGPaƾ19"vŢfr-n3/VUuyBHڐ 3lJdAO&)r"%.GcRHʏSRey]](B18MQ3aU&J [ro ,' Dv|+,Dqhh53Z*|ZlL L՗iKAZjFad{ N\:sN7ܧ`( '<|=:(-O=5=6Xńs\ vP ^9PG5 6[$ÝRa99>ף`VhPsAw6r }ܓׄ͞~O*.r%,߬n\ok ΁7"00O{E3/o(;|tkH[u( pkM!2rt/匶M<}ZVf6M7F RUFʳrG?1X^[NQ=x I({ܙӅ&9XJt0+.鷔YnZ\'|(ܿ +/r# <޸ve$V4E,@ Y#;)5j7zͷZ hɼ&z25xnD?<Ljj"!,!"}'' $5p+Dθ2pu#O ɢ sl@]E+%C}Q- imMN_FMY2{OuL:-B!&uՋI]B On=/aZڠ hlq<dǝO@ƞ.LW8U:nK7=gZ3u+'d}³jSj<q =K >{_Qps Hd|Y~|fzjS1~Y:e\Nz<s7;D6Q|0DuCO]:b$.'&y22ku ̿n*LXxu-ou0}~H.O fHJzKSb K|ސ4naUslP|l]2$ d"^!Ǹޟ>EcyDOlAtL[=不i⾱őN{dJ'XR.팹jx) qo͠V'V($&7-ƺ\m1z^m*~\+xjPn-?aY ^z-l@e,FB9Fs*#<ԮmЃt#u{ߑNVEF'ߋm_檚R, Ris\K;4A^^ɛr~ꈬ(hpd{yvHe"XEN"+5c$m-QRcj> .Zӳ$CHi* xbk$uuH~CJz2_;޴i+nx&DT >>"j-ۚEMaX;Ou^CpDrht{8~!bz8/ȏ}jhcT'(%?}zTKE}i4g0ζzg*fwS,lS/lazmPtI{$ohGPH=0;G4q$m/;)>@֞ֆ6fϩzfY{"UhBd>fܣK$a'r'ʺ'o~)ᙅc GWí呖~Ro/APSYk+~t` & f'NJ O\js s{m`Qm9Nu_;=,ca9Z>$(obG9//9UK.p\VBɏ*k3B.FחN 4}+K>䇓խ;[¤:|2TsZ"bxv3MkY &TE&T]V$c@KL:5GH7v$"\ޏGqeNLNI[ dMbg,FtMo gNsTjOA nMrfKD?f~){NQuAjӫ E!c7ֲJ>%o4'!ȉ1;il|YPY%OSjGr nl"ې7i^y1'x}OTkZZO W+SkQsG7ۈicL@Q+n_:߶f8M,A6_5wQEwjۮ މPuieV`}6ZX-#Y#R 0ޟg KlXbruYmCx/2vTR I9i0CKr]7vK] w+"(Ǹ5ڭL}Sehz)Ga}mALa&?}=b. o^ixLΈdxUfԋ'̭Ut"VY8F^6.>w'KcOC+'Ѿ:۶B!\|>TT<X ^OͣsS8@`RnRV$slyxm[24>,$zH4!ҮOQ/e+<^NtE|ߗMxq+ iK%]L AKX}`p`--Ɩ=J`|Rܞ|)~eM("'>72L6dy^ ؀"(DFb9ң ‰(}F^JeUBz*3UPƜ˼-y}rgݰ} >^05mnAHhToHN:7IS1^^--)q__*'啼抛}5=Ur 塖*E]>zjbir+ѭsѡW^V/<5Is\-G']QǬͽ(?.!U~P""߾pˆ&gK^zZDiXŞR:~v3xq5{ʝ-Z׼^kY|`h7*Hnl_9ըxyvz` jd;6^O갔_;J)w{hvpuQC6_l F'Vzvӂ})_./ϱkI4QKj>Sܷ9F?N~uTю>皚~HAl!'ItDW8M %&9[d)Ւ}|$~݄VEhʗp?ׂ2ڸL) 1PQW-*Cn8 -1 t9 J(R)8J=j-շ#$%;}8JI#Lds^@a]ٕgxJ l%}ISϹ5˛ ʧu͐W?VHGM"fc#b~aO4lMBP#l㞾mc).e`-1gYu1xfq }!}K,4cqG\sKq9:*SiѨ+I/{}RPS ݼ ulrxb-2>6Cܖ'@Nܵ[m/@uSp֐C̉ ȷha.3G/YXXdb8̵{.[@Ұ1C}<|##{7$H,jd CRW̸&_Oa[x޾)T=E+)ODBURak'b;׊7# 7r:}1L_W}n>Xt>pԏ%sm΂L)R,^|:E sΝR6;q,>eEi ( v;_>)]hSYCi_2uzhD?.|.zY褆tãedwg:__b +DWPۆ@tC^aS>,HA|]ёvfdP#%ˠtr$uc5U:K:$U<5RjP2"EYv̟c]M,V#J֗I@Ogl/-c IN ܥ L#.9mú'rz۸cڱG.rt4"LPYm&GqŨ91oN/Kj>W'̘a5i٫#ɸgi2G~u>=Ǥe-Ffj`ڝ?N/<ٱͿ>qhw'NJGܐPOU㛍2CNzjI# ,LçdqfMY7!&CǗKX%W).zpпw@ޤWs^[dzKUz@~dYbqO񔶅\R: &x>ښ>R7ƙ?.eiT\R#Xo]%8~$fCHh-6<Ǽi;Ns nٓ p1(m3)6BN WG+c1an{Qz1M\-5+DY\DIW4O{tmʷNvĩ#[xsH  :}R4OE,7LTMr"qg l_'O("|ZiBv~`wrr(+ps$:_ a9'zV+jNtdՙLXvkf5#Ŝ9zĵV %]Yٶo~$"ٻBFKXQy*/x$eMNV\ ῙC߱a^۽kݽ7uuoGJQT8a٧'@(<'⼾lhӘwG rҾ. px?{;HWK{ XX9oR}F'۴`*T}NP)~No;cCG{˷=0I 1Mm @w"(X|70JRv,ޗL_#g2S}qSJ$%:o˽;+<uը@q\fX} n!Mou'I,2`Ӳ ""lJٵ\]QJ᪽Nq"8vX'`mf'ӜH5lɯc,LdmG :0'@Ox+ fmM A]Q,[Ϩ ;Q 8ߍjy3vF=1'eQitl;10 \fBE8ʃ<Mӧ]AdA!,=$qy i(1ncd)p|hb0df` 겑zbutEО MR.clE44Xa OUX#~Rƻ#ݲAcńmG~sUS/B60=Vf yOAi k_ sy|d 0 {칎z/s WK+q}Ka5+sVx~8F])1njC5n[)$fTE+iv tdǦC\<FKcF~XMԣV,h=Opu*LX?CIJ…_')R W7xJCvJԎWRyw ImX'ٵք:mS&<'-Kf꛻4r}ﴬ>qh)ACAG(M|ߪ .?'ȱ0PC>-ƃ;e1^m|'ڙ{ X%PTkWֽ;30~7[wFF ^("3{9cVRKg )X %NV 0!@7Q= {4V $dV8Uӌa%mژ"`(xWg}p}d K{Z [8/I" ]{"TWC`h/R+,ykSX SasӢP+,JSŃAv+7x?$h ݰLSNO;|ߥZs/f7iʼnԞCWd1&ü<Aŕ}U@eI'AH'SDB6L8XA2BGp⅏;bqXJ kV5(w݊VL=BRCVfA9J~˸f𡥵Taw2~d 慨iwb\/ŸhSq(~*` Y+ng$OD.g{dyh)OnoxhC)L9ש*|w7;bsqҔa$Mlo0ɶҧ"w/l{rLۦ/2MǯPmX>m1 ?NY1I /8>%TݣѠy5H;479WiH*#j1H>*m&טgN+R[ػ |q+C(o-V 3婽Ӳ%w_Wqa\r=w\vo,h3/J&dS῿E9P4ӍRo6}s`k~K72Vi41?r-S;1Sl%03@lĐq_\B`JP_&ʫl ?#KBrF'U(^qHn)xZ5nnҸI _{u:'/ jە*ػKl WfX.: PQ1yLӀؘe"\s :G sct$H0ܸ3èRǨ{ *Sݹx,fm|Se`{ڦODĀACg` 6?B4]wׄ8uERgGkgjR)?sFN*F[kJFx'uF,6Kq2D?X}U mݨj-+WSnR%R[  N>O>l@ f$MR+Rϡ_Ѿ tͬ ^ImW_Mc!pT n`itX0 qIftm3 8!rLzOVT+ȥ=/,cʏ!;*wVm3][hEE|.#|=W^Rf5@q@Pt 4Q: >]WÛAKMNF0F={zco"`{y8B{ݥE do;#s ("kSla;MWF-GAc>ʓ kr`+Z HLvBVW`=JԢ,݀-T )@H{~hɌ*ad.[4L'S<֋6+H6cSZml%}LX C~l?1 tM^$f SIWgy4v:hؙY8ׁʺ,}!\2;y$ja N`jh~4֪vK)pD.* w?JS!Tgr-#`E۪`Eux= m+(]]:굒HG 6rk {CCZ}u-u}yQKnʤ8Է9 ܔ{?I,PA)A(wxm{)k.(<+RJ J W#L Dn抦4JGT|wJf<^W9: $r;jG[b_M3DRD*Ч'!,TCʰp^Pj[ZlEMP Ez0WSPos^QWl N2p(GRIJhB*)QGD&&% g(gIZsQA.qgu>c/a.PɱZӜJᓒB"Swu0DooӒ}x =׵$q?JHӸs+#b: I53_}ūk|YktC}CЫ$,Fd+a{ƪ"K^A;96q*i7|0@F1fJ" D,g1Hok "+]VsDݺAIJϓ:䳈N1A<2쟐p{?fd"^`ǎq_L=QhυX1 )XIE=q`U9nmqR)u9 Cî<LVG|M?x,nj$Cװ#mӉٮkߘ&ూr$kQ4(ۀ10ÀU G'bypE]^Vv;7g]cٷ8Ms:ɲ/ĽPO &YMړzCӈގϓPh=kMϗ{{Kz}K2sO5xp0>w/7>PZ?, Cz]<^:uh7 Z4F/(, { Z년OI. "=++-٬oEJU%;*yX!V.b.3h3Xvf{c{^z\- $rΉ/w 6ekmuXx J9P*k eK[GGվTt2 % d%>i:xJCO9GH*E+f?K0])vQ-hueuNT{UM x/5g}5"gL6#; vں #u[p'zeDpRCn{JGh :B\G?6=%j𗟙7mIT)w^-/4V=L$sz[l8^kT Y21ٛ%Qf4-6?ÄDt7cW^qAv,{IM-`e6`Ye/x>^"w#jqӯÊK4DܣbVj}GW)Z&alF?NZpGubۉE4[|`w-ԍlXn_Dh]@j\ik:&sc #)FS%wٱsm> *9)gZi]q"}>-wXJd~1]|?4T&4[B:ܚTbN[%_z&yJS-uqsB56c=3žz Rk}#R*!Z` 8uPA9>KK@#N~4!>MHr"*ZGEFFB176FG NMMl}7\*,e,Q UFv0~cNg@cbR? MLiۢ7DZ{PJ@z<@d,E"s1Z9Dq570M~[ອhmMU-/+XHڸ}ӻefW[Dޤ:g@cRp&Wr̀ΡL- sGI"?^瘃3p_$6>]sO' Ft bmܥt M6v;Yy[UOagƄ10aEkfr]!GN= >D˜˟*YZ-L6 c,d Sk]c8.6362Ia[.GVf;w,` 4;]#I<(g"+G 2Bԕh0{is{2Ȓ՘>P/i^m!vC)M@b#Iz!"_l1+z!bDIAJӈ!hxyUym^rXə-,̡ikKɜ 'Ge;rɑV3BTyg2 E ljR.@Ct6-(v_S 'xC)FW\RrpYLL\=$+ތM&2RHFVC\$ veƭ<уj%zBq܆јʋMۤ ܻxaxTQOm]z&U?:GYxCm]d0S_G3HŬKy\ V4tu)B;œJ2Ixqk,`󭈨V<zp0ԁ!^'utU`mpEɀ$t{<23]x\o:b47kz+eCBM)Y7LUqhgHk\ӨkR"bWͽDõ`!As/LL]|g?Q6 M1$h?Q9,`? *TL b NݏS*A껠<썦-ךej3o)?QܠPOD-Fh8"NQ餪~<`*󀀁Ӄ(>{&gsH@·/sF:k^^ڝυ{wu'"}iP^\^wQﳧ@N'k= z xtrYV`'zN ;^A&ܣ_ {j0 ~fDq.L_84$>CaCPiƁ}g鎑:uK!' o@|u׭6%A ?v6 Ph;$3-O7d = A4M#jVMPû҂Quz~8Pn9f/2p%Ų_m/+(woW^TuCOK`Ox, >""֘vS!=Q3S]a~/w닔zhDe ф@[SbSc1\T_Baߴ]RDGű7M^TG):G[`::feTrF =mi%h E 5싟a@j&,8f7(SBx*#:C#ȿ>~iA[xQoе0EIr[x 84K eE 09*.&_.&J;-]jϣxd D>p4@Qݜ ̦XVFA+gA8,Pc^D%EC_2,Ǚۄ͋ᰘ+@͡+Һ 0I{8u+a)\)1,\m 0afZ$~b?=T[d9[0^$`~49ܧc3. A Iu Yh(BE~/uL!~9LRڦ>t<2{99^jX6Q&$=#a+9eʐh~ɷ:^6UD L@S56Sy -'ϝґd/nJ*lk܉OoH`&ncrepٳSHee>¢džc6O&|SiX8v~傑&ۜwBt]ABYwF`kii(VIEߘ1ѡ/{ hpݷ\Qku5_D~C*?{.2SANx-))`e:4>)8Xb2 #xHؗ˴xFE,sJ2>F'`n"cS>|QqA{k@y̮a # Œ] R\4^60+}ӽmyL5N?m3Pف1Wh+WT@k=}g8|քEU5r}Ɛf7\Y.2xSl'mX.?y{U>_GӅ!z_PlbA]<~+4*.g.uWkE#Uy=Oٔ8 DzaFHP/Y\@P;XaQ(w޺-)&rf+{BAv6D@w3XGŊӳ%wN6׷%玿Mc $8l$ {%2ٵ?guG 2tzx%!D%wo"M "}Ә֨-\49,?* J: |_<B%=6?~4Aoo8:'NCV :N$|q,Km4=kE{FػKz/A+}ftR&K[E8 0 v~uѾ$&{zsWA"NWu3K sGeܴb1.w^GT`<gv=EZbܶDžfp ShK=ixݗڞI$cG YxkEnё0 lz>$Ȏ;akS|d3ؤƌ0ڔK*6}}Fw ͜iI2i8Fzƻt+z6 k";&z<ݒӤ`"Y"XüaVcG5ճA _@86$M&eg#УX@~5+"@b:pN 7oaB@"'{Z=2Cm"g io[Z|.e:gh}P dP4ЫF؅ vz1v5j_5ګUmnfDʩuݸyh=\ϧsu6 W#c'zgxf;|9λV̥÷9F P|KAȁ~7\b&}&MJXPGDJ<>f)t#tB⟌V۔q^=h8W.og Pm fT;0n<̒ MW7! jcN<0J9nhc9N1d6VL\KAUÝ\xOi \dI_BCT^%8h9~4/0O1zuL k'b>(bNrUMkI{E!ЮqfԺD^PNJ8of ~ƅ3RҥKbEWښȍy,u#Sl aMDkhb2ЮijrdFx:jq}_|C+,?6>fͮ."s4Vb+Ֆg E P4o:憎q~_S'A~m!*C Buzd/ 7cee5E2dr_ Y,Z>'j ?=Aw ED.I$7n)`O7QN)@MKٱZ4FM`7.!%#qa,:~ =L5=#ͣ}D*tUk3KQUnCcFN~lb|5tf wɰ"0 ͛rb@`ʾ Ѿ]̷3g/%i$ҴAچ6vKhТB vv'4"l#]wLč[ώW?ȿ9Gݖ,tݱVIq~s?i'`6c ə+!?Eq?T@ ̇tz,A[B41$OvkE(Vsu2٩۽Vz{Za)8*_=| α"疧MJMyͫc_geN {e4ѧ"t*Xr60o=B%`h'VDj@0lvWtPFN@Aq@l&4J"wᚠ%|۪b^Zz~/ZOb$Aaą. :x֔?O6$3Gh9"b͞< cobn܂ G*BUJ~zǶIb'ױdN~>t,pz >H̼ˢEn_\[afc|b(tvXn2lR_5ӊG'ѿs.5fU0pcTONtR~%+#._NeIiH O ؝Nbz]-.?S2`ZospFJ|SD^;YTA9(dB"SiF:=rU%t ݫ ʳVhb5Jݱɵ0*g\t{J^q, )jpEZZZdV(q|˯Z|.94o#ѯ?j e*nYh/U,Rxye([m:pYA+{|U?#gօ{C 2;^A::,S!DDoxL7Pʾ;:fy2“2MEp_wa nc/qD-KPFz6>{ 1 dGM4Z':},Nwgv!Ad)1[Q^'$ _.PG4?,Zl$,ɰzXLչ#3?!-$zHZ%v37`}!1sM-"5fFqgj vhUoIէV/E)'+. ƛys/Jqf`'Q,V67hËFMf;j6bo{ )k}Ӛb71K7DUpYTUT}c3@VLChLG=ؑ*X|j^!CjN1RqToJe*✽?]ra馸rMp„iD"/$x R)9K>۴R֝|Wѧ\z{]wj2%⟮ӹ.G~C~3c\r.kcuDm~pn8x_vG"gV]pXF+G}5Ez5o,yZФѥw/yIZavyJK5kt_pG9dD^7V 57gdcMV#oAz k/ħ/,%'O智,]"`)AxE0zmhZ BO\@rX1g3EV]9Ncu[D1P!~XTTEB-I{y듕5]ȿ a@AQh>CsPo%2jbg[4W:XK:8 =mX0c09tʕ Q.2ttO -+epx=b3(-$gUjjBHؒT$sAK_LRXAT%K+$~kIDߝwyOi~"ŲVE.c lk4 ;Fvhy+'כ'?zG}uQ8I]ciPb1TOA/l>J*sd1E~ߏ @v o}ڎ29r/0a f'o h²=ȿѐVi&f-o'Cf.=^m̢CyaPNH0#_ 쀃1TJ`Z:W{KllsBik~.8mSr hۖ]K`tZA t96 SSp=˭p彉TB?EC`,~H g7dy6Њ}6xqZOacg޾b6dݠC3yȊ[y@ V0LOYXoYjNfm3Ո yO;tEIKm#i,1'-kGe%VJ/0b'S;§i8 \4͒74W\ ӷTuOV sM7o-AOX O{BLBO# m(Yczy AV}aMhdhGbP$ C(N𮣂܎$jP̶(tc pN͗7F";:8ykdUg p<ܨOjʏA8F(Kw%+N, e~bPIY֏_!({?|K  h:ORpwL$y''ƣ_Qv2QYy-W0pdE(|dURR&gP ;Mf */܉C2۰ !8t3L=?U9WTzhN[/ ̖sO,jKd> @ǚ3uu8\ _m1ps`ouG\lwcX_QGqιVԴO Jk3M4,*H^Yu |%t^ZfXgK"wS]kDvײ!3$pD(+H+yVVMSIɝ#n(5Mi5[}eI24=(zJlN_kXs.6+szq걉>s]WE ˣ%{?yH''26-?F#ŧl9Tmk]t[n/Mܝ 1Pmk35O%HeuKft7  dX6Ž9 pz//>w'OHG ߢR&1)U܊NI|=DϠO4jag fN36qU=ֻ z)ð 6Thaukop‰LT5QV?G5B 1$XSrppC.˫ %\lg%`/6},l暔׈ ff<7p%\mzڸe3\-a`i@#?J.Lt_BO^1UȁkO̒\8-Gályr}d_>?6e [Ow2g2kA+p9r. m΅Uo CHS(#Z14D NF.􄺲=q_xeR81j[A`_lM0TgDu[ٍ<'W3O/^|00\xy}Z3i4{+}g3#t_6Q%fἸBQD1|s;Qnܼ.lڡFA>f+̂”Cera5@%1- BU()/QAtOoU w;8 -7^/h#aejT )JS-d4$ F=FRPż.,1'rKF:rkĈG?[7ƆH(l(:7w]Ħ<4i\jx?&Rd?$Ayp*Ȗޮ\k׭{?g ,@I`\& $BZ`E/B cxcjb݄zKBy? M'" ᭈ]+X'qowYYBU7|s洰 yRVYɸo̙ҽl<ӃL:@|M 8@ΐ"Q3AQg&iN0|z_DQeX馇 S1xB@;bO6~1v7pvTEϑnP8<'yR6-:aP9X=؉PEkΡtX!&|ӈ5`9U7Oa94H9`̗K$J5$c7*`?wj9&緧fA4&#l=5W"4_.i}&DU覈4n 8 B몼ޒ'tH>"1kӡExzN X)G%=%N^K!S& +"!O|.t0׎"q _\`Ze{m H[we+ 5i,cFpt50;Cs]qDǞ<\+|YR A +.) j\5dy 9x}R4aaxCuw;>c8A- {cJNJ<@A2OO^df1ݤ]gv9,B9!PIۗzW|mI3'9.'*C6%'ߦT""u&Sr wDGp;E^A*WJ)&{=|2Qrr ~`/(IxЃ·> m% A'\)p=f\ɗ1a2(O*Ņ ԰hBG\6w,~hd+f}N0 y̝;?BH r㱵^4 VdCRE0} 93h[ҟEBu !#,S5:" j\F|xMhO5,6Fۀ!&E6)qZO\2VG#ؠYeAIoP[W˔0m!iN $Hc|w()jNe`D榅CpqUF8ܠdʠ*x;,-wbfnɊ2E+|SpI(m,\XuJmh&{3A HJj=WgEl,l;Q)202 ?X\66EJh[ba3-X}]x"Oy pr)n}0's$ư џN,5(8̮h~ ΪJ&5T`tZƚQ(S^CpH0ceFFd![nY! M bXV*">RV3tԷdۯ0 xmE~3vB!Q׃OmɭԙzE``kϭ#_׀7Be ",hlo*I'ngxZ^1DeGQÌ%q!lEK3,r~i>lqNyg2IռŒp|GBaj\XkrHaS+7Z82`4v i_ZbMgn.Y_b$f4ɮ gjWy*i N] Z٫J3!WU6o(/$)=?iп'XCC{)>x+_䎳R}|4]Gj8w;RuLLAaS b3@|IM k>6ȕGgm^`s X Q.x,v zțKgΪ6K]~k>4ysjYjgUMxZ4UeH}c=oDfq˨@\m zKA^^}~22#+v/%semgpܼe/ }ʡ*f`ql3ـ}Ο٩²?J$_#7yo6QJIVYdr\r`Y?/|aCm*)gR7Heeߚg>rk.e{xN sA{]ԕf=| V{f֟]j{V}$hfʑVb\andfw Mh`Im[xΠ o GPܲ/Rwa0 ~lC8|OMmK+ R$EwBjZZiB+2";Zu枙KGl;J/Jr}p̭&&+V6bW0b4jpعYaO'bWE+H2pcrνPS~Ţ4QNvqiZohƧr0aj]&`"UWO^aziٕ@gaiA$ }5Gіk -$2=e#e-56@;⑳ZkOJ!WVړw4_!()մtT>(Ʉ{f<$tGR3[0gM;srCiXt#Zpٜ'*7aCrT~G\$YTC "I>$[,ߕ}~0F r~qF2%}=;FO+X3fdL$`C(lcaG&4..yrג7h.O8=-mQL1cƑ*g՜z{L)g)N/e *Kg,Ơ/Kbx-i&{b+Zx]l:)K4w=́R-9zDޢXN`]^U)ZϾat֋7C2K܊HLqLG4@ILiWHDeqMUT\2)hc$xPg*_A Xjl2pCXGp_ԡԯ*^C`S+n!"d؃qW8mo--=YѱvbjAJOJ {{D$BR@v~z[~[};d5zTiIy$ xl[@l:DM x/hΉ?"Tr6^|D"dMmfIu+=2Fai=KC W)f+lȐq#0 2?H;&YI]6u Rl)[?Wnt|@(/)Ķ &Vs\\xnJ?t./.]6RXE5h̥1<ÐQM囜0|.Ph5""ٻфޥK\BVp6jb226f6Z=dޓx>4̀iUfB+1wcrM5{O)cj_7nDž騟0Ɔr2HM`ik eo*el\"CBBŚF!dMO$1ɍsa:EFKCSiP2Hy'e~A"-'ve" ȣ2 VG_qSe #bOAm}ϲ&aweeVvP'YDn:8_&9"I1>S.$;$d{o>no=#7 ٗ^QMuLt..%P+N)G16Ļŕ>Zd~E =Xަ*^0e} s(zR ]u(NgH U 쨋g( vڔ@>q%7@i0` TR.Oa{N'OZhx`3r?IS/]s5WQ(;q,>ġI =ew`bHRN=ņZs'GXvT[GXg @9]y >7>+x:C_2&&hf'=FӋgI[A6Gy6`+fweʅ\ر |z*?fQ˺ԛ^;K6ʪrRG>=Arn)=r$xWl} Z)%-ve\P^J(n˛O4='Ҡ [ɏ "!MxNjoi~()1ؙ1@#YSFI]:3n©~+ٙ{+W0̯%n߻Uyv#*YOtDt uլd 9 ^e82D't [(T|TvDh߰oxܾI@, Aۥӹ`r*9/ݼo:#˴J%]qH=gmO ;F#p0*f߆`fKd9"˩L=xtQn/<*r?yF{&G)}Q NV7 )ԏ >)p0D R2:b3ʈYb`ֺ&h(eP澊^: 2c J Z8@BB6[:}C@J ڲ6j5.!6C&CΣXsZ 3-y\JwfMjkOI;7RM=K$ژAa{Z',HxWb)sf!QS]Yb.lޢp"yy}m #&i#̊/ ڟa}`tM&¹hMS =7PZ&)^_dGΆp:@QdC0Nx' i9s]=RHu(lv7b^=|\cu/h{2$)nMnp31$;O)h&V%.K/Vy!>%,|kWW4P&1^\kN f`sW>x~2ޣ 3!Ҵć&_8Oqf5:=[þpfv{74<-A.ad^pkYNou?9/cZm3$Ęth$([q9?-2goU]OiruN[ `.'Ⲡy.D hϸdS-6=t޺v3)i2=KX'z͝qQ<"975uQf_KkPQPcsڐwq,I$s-m+w!] /PaXޑ"K}kKqơ ;t_Pj.HLK]LC T#Z)/ |G21-Ѓ:$VȊ<7[Zf3pf9\6{IϙSԜU:Lw*V6h%q#vJ}m bes' XU5a~F~v8> t.*mP/5!o^^WaDeA4GG( |4%f1a:նB з(E\@z2+4BxB#,yu2,C(7dz,0uj"ij3-W !˲\O^ ϣDXTJE8m.OYqxST*.I|'}1ZX>Pd5w`XUKX?PDg:DKBW@QM#k"nz2ۡT3'Xߏw}DC'OYDsr~͹)Ȟ z 5㗮멍+~M%_И,d\pϟ XI,7b~r?yixR$R<J] 4M|ۧ z4 5i9rF :p-S~zYK@ʡ e`HBϨl,^("PD~1a$m'q{߮K>IFDc  2HL:\RCw|0q@x $l['2hz' I*|q\Z%hu]_?u"Kʺ5dƙfLZ'փ=aȅz'ws tm;7ɍ ftHޠ9XB8|H0竷"Wʜ. I2g7 5s10-ta~[ &ag8:Phs'o^y ubT nv~S-rxNr; MgU8Z<>oP(YЗN^`aUv..z⨎ib(~aj`r쬠0G4{=="Ig'#<%P2gwQę݄_Q[M6Pc8swL_wwyk>C0\*k=mlt2C";j_ [X՜s^GVq{auH0cN?'+lӪcqpO*\;a@N(7uzRCsP7|. bkWKU>yfc&q'G^(F)g qPyT}|s LCoo摒'<5hWpYmPՒ,-]( ٬kyt hɱv1gKՃ/*4Y oRYd!KFP }7I$Ķm (珲_)c/wmWrrciHjѫp_{aSA9xk`TEL)}NQyRIUMt>JQ5No  ]E\ lޯk@4rˆnɯb^ i/n+\cv:ɀ,$h)栒M6 (^57!M' tRi%7̤>ۊ.&ԀPamlvh ^?&LAɍ;OVflPJ+|7B>;1mU"uW5g"eEcoCnxYUycHg%O\^6F_++.-A$nrϞ22`f/jM>v`AYMc+@? *w)K9M{uJCP$~C"sK}ɨ;])j ZfvfRce8LoUZF QM*!YMuYe2SSN]2e>oS- .VA'J 2EWc(48ާv!w$Y~Q;"6CvxWs|w/M6Q\7dTbh8gɓG2hnj=L)XXpa*O^1j2H whHyL|밺6j9_;H$n,L4dz 3 NjiSz({T>$DT5 6֧e7)?~ R+sΔreϹp8A P|6KߔN #55S Q ܕ5- Z9mEB׎ysӪpwP.Ŕk-x53-U5)R 5yU̬1$L]W:d )im'()+~XܐY #SCʄTR?JYn{ fac4P+͸le*IU~ ("OtHRe[L O,ZjjɵVm^R5t  y+=(n LgNĵb]cE~(ݰ `m ҡ2LDoQtϘ6{KH+ AƋA~Ħ n_NKOov[9sdYY8 >Ǟu=bsh]ЖiTz{`V])⇶ג a>OIJu;§n6J:"6V.1J~ke#8af;]͔Zt-vvȝ2![hc}Xl/%@2JVw /N|}鯖[Z$DaEAw \{y-uW `Ǥ*Uy>,"-E"8l4Ǣn=&NvG\ ,ѯJ8WXAMq9\e~8FJc?|_yDƇd,9Hq1FL1⦍,;B{K:C]N tj_熉iuم8 1SlYJ߫s2f8?>>}7He4Y!:W^Й}<JrDu:۷$e;w^QyaEK8`(q3;̸$ #C}XNCI<~ !^"TJ2Y<8Fv绣 .YC3eU0;چx`-clXEVˢ }iN_ƙɭ 7;]m]QeJ5Ĥ$3Gh>!2[Jijo>7ߍfus> T)ֻkzښC;˛L_b#ܑtMݡ͵q%v C阧`{öj<g0]O!.d҉:dXᄑ70}Lh=j2LC`]]Ҕ= ûV!ؤ Ⅱ=$B7aiwW6\g(ϕAN T̎Hsv{ %]@. ?Vw6I.nnPi zr_ =^at㖤[H$N-dJo٬T;+^B/uVY~زmATC# y:9%!?cM׹qpҾL [[Q 14t/#򭍈m̲}Q.(249Bp-jsKʩ혓>reC ]]쾑]-'~! k1K)XI*6 qC[DxoFp+=yV`TN3If1^>ij\+L}V{R+jKkVNzyz <r l? q-ٿn Aszټ"/i+%lޖnl V'X\rC-CrYS6-{elEE`MK Rlq+w$:=Y{eBѣ[!kw\=q2ޯa ?8_6Fnid&p)܄ RkjǗaIkO% Y*;rɁHZ2"/%70 7ʀeSƶX#HrzF Z2Fz8#iA6>K=w vp|2y S_~]W 9 y`v1_eTv*iF9քY7S2t*ySBm۟)?͆H{Y3'4Gnf=?on"}2Wq+f8~HF(> CEMu$2ujV OA10.{17TzYBs'DwQn#p=\CTT<;uygk$ꕱB*t_:Qv7_)&%β6_{|Jѳyh$Fm ԯ(gfY[]C!s[8`oQ+gL?h~{ϓ$Rx'.rMD [E(oKdm,N{`B |$B27xMo1wڪ?>f?gnj_A>Qo< h4^DsƘ) A&TaG8-N }/]ȟ@Ť|1^%*^D73@14Spkby?23Tπ&ӉΈב פ@)lp%N!e}'UbcZ(ݛ<}wz];3}PS2IziPwezpp[C)gD~FG鎎D7/r43(E1 c+.rOB⹛H[cLYW-&zجTk։0*gK!!v=Nqe࣪n=saW5Z-6|$lV/-=B! Ic%3z;sΝU".$F=Zm/J-rZu ڇrůDۦy_kW0Ӯ\D|엎VzW:~,DgLoH*@{9Y_c"N`c#Y4kQlmzl *n%0>W[GPN07iݹ9fլ 8:䏖m/'z+%)zl;r%)A%u_0+[,w5q. *6I߮8t0!N9fE1?ۑ6M7IQae8^ gSQC@$^}xn`J cliG-95PT~Ӥ֚'_uU"D,Ir |H:ӴZOr/ēqlР%h޸򰨘Swum,~>5_&IԪ 3Ž#6c-/ ѓ& u#W;OH X޺7w8\JF-4H?kӘLJ[CdT0"9@{x=0M,s$!ߍjDTҙ*w@h:k҅Zn/Rj7iels +[$jlխ,EN,e3B\h-(lҊ_oߎl5V 䕫orټ:@kI+r+͏;`D$.R)D=iN[<}4r JO|~::y ($x` G2GBH0/rjcBVs@,|;#Q~+Ap~ ݫ:cf_|CY+kó3 'Yx~% Y]_5'Čmi]EYI`p[(}G#˦%Z2~尠0^l~z($)غ#z:fq ~fx]XOKtwŞLI/O5| ʃY.֎7Uz>|N2ⶤöJ*I_L\:(ixi(ǬW֑^BA\)&3҆pKds๴)Y?\KUVDl`p y zc+j49IL׸ >qIY؇;??%f)68 xyl G|)cYwTɕ)#nCXkVm%2oصL8.Uyg1h.ںنM|T,|oߵtY+I6{(BF/E;z{qa\}rAY6DDR g7f!DQ\xn%¢O8FZNJ|x!(/KYgwr8}s %D7h#8?D8™>Ì /ڶdxpuG 8r.K7d%n$em 1;ye(=!L"qf"(l&id-ȡ67P&n<`AYT-~^&Rg0O߱'5*XK.K ܢu?aw(PX|G/(h$h3ک?WB6pLHÎX+$ft.c,.|D7EKXݐX,>X4^>+# S'Εg G}F&6 腈!4ހF>^c/6JFQh}>;@$:)dC|MnGB9Dq>g^fG#?rWGZ 9,_7KZEIDViv`r7Wn|L!n<3+8o*%ImP x{ٱ q~^|I\w`2 $C8ُ`e!NjG!(3}><^1Gcy=&<e}).N͉3„eMgzX@oݿ䶸p@Lg  |Bqwm)m{_G`0s1rP7=SA8!ihGM@XWcԢ'G~QW$krhyMj %y+1 rja4ßp}¡t͔2 >5g'$y2՘oc܅M7و`Xoc*sf7 `OfȺ7QrvPDlՏ2:_ fR=EgDƿ?^@eu kv_R\u!zxB^uE!1ӂ@AOZ/7Pp_ sSzYS;9@aq|| ˆ7z$P-3FI[{s [@'f]KGRɶMN&E_݁.gve?uZq ]`_Ð!N 'ꉱE;D\1şt'r0i`>388V'!CچB&BwzomaV59\:Nĥ;d[Lw(=_3t}ƞ;b+߬Q = Tr>V%m!RKVE RVS_SP&č+矾@^2q@#B?*cG (ejb'_@O2 8z'^ @VDÄ ~ƒ}FZ3 \:ەER%0:kAE[ 1Yb]#LyCjE߽F'5W*5mi# jQvޠJ5nG 1Pcl C\g%@O*ҿ $I)٧KK4ZE TMG9r8J>=iW B9 2R6p=XGŮA|O1eD!bx*K2cux;r;'ldBכK,Y _Myd;x_Ld=Z!SsU2CI<[`PX)3T^hcqN8O,,jSI ZR2]-K. |%VuC6CFhdkozѽ8MN!xbڤdL,~=74R0pQb; d-Nj]3dgv'ʲW"3QA9ڝf]LYLXQ0dF !%kt:pCiFp<"!"cE-טm *AzP).<I\$bEB :$" RQLgt䙿 &l׎XxF#mY^hdAJwavY / 0ɁE'~ Z4/0:TLrxt9 h ˧Povέ٩#!#޺F|e6J(d{o+ g-ޞ{2Nq$zpy? WF?!JBciz &"(rAԊb,f2H6IILZvےs3([_E]mj(j`q-fqnrSz X9ḾfYΕf3xj!o$|Vo(d=U2nzOzǒ.S @U+v`{wis3n{208|O{Oj4J~K܏\qyF )~/h3"e0ҮL:HRnQD޹ň+~00ԷY!I/3xcLbkizM+=f|(=su`7tIN?&kYo *mm$D Us2\NACeQiDV r3A?ժOo v޻h=BV U`o`צWb7#vN&ՠ,@[J>;MMsU kU+V:J%aPO!Pzgty(B@ NmC1 ;9C 7 iv|~TDht 1죵 SVGB!g+/7bܥlc6WGʰ~t*,贄1voMs_+M5m tgW`2*1T}fG4-\_n:,h6d2>c̱+|Cq-HZJL Š4~!DmP2j9p Gn["vI<>J#iXL0ּvBKC@f%  XT GG.l[8q?6YtUPCb2E<ȈT(M/8Y)PPJ <3! ;G]`Q 0%8 $uxLH5(*s~Nn* #O=j昣SċBT[Ny/ sM* ^HP- LIAլ(fk0S.rlí7T3 /F[q6 1Pbog.n˥z,sS4I.X_QiPUώ-NA[=; QF $Lmo L]\yf0@{9otg2TM@αP0\/sb&`1|*yX2:y,3a,k(µi C ݂&%9Cn29͌URKt 0LIt{k:Cߵ`j hbHi;ΫcD}جɞ"!V=,OA11,ׂGP}4V$d/]K({8co\VZ@ Qp$%*sqJ8"@spܒC j*A2G("Oď-޵8 ϱ-;+T9{Nʊi;N8fah,L7̓(DeGpےy`F1lȎ!RZ1󯏇J >X3Py8Uj}fl [FsuƭdѼ3.6jwU )CH;b\dOL0jr5C6|\G!@u '{UjRׄTgqɩj~]e #|2µxo\m 1Ǵ8֜ jYt8:|GQ  V1 ?xpќf1g'>vL۸*/XN(`Y?lzd &|ki1wkR8KC\s[H cD N (PȬ^Ut/pMr04s LSqP+s!,t&VN޺ٌ/QWȎ|LܩK7Jo;|o pJe&BzN=OTҵW jjOĨ6d!s4x&Ϭ/89k s;LԽ+75Ҥj;T`yGUX45ǜ{^#`~ R3[2!9T9t2 vꢿ4Т-t9岪X#޾t'GB` )A#Do64M^9Q,Ȼܘ<*I>1nX't^XB}ܟ;!@8MbPuxTy#ȆƸ=0ڏڞ|_|g ߝMOʼNx6ǻ]&ɚ흾zhr's8F;%i<O>-+v2ֳԜ T>SPZ`#ڵ/Blq:$OrmxREe(de>G{9#f2#y*!,,NseOwQr y*QC`Coo<Ue-}5Fd^j[=Jnw2}"A ="9:tYnh6LftĕbAKki%_/Vt6C&7Qd=pZUKg_(Dr Γz 4gpi" bBkML6-~)>a d8 HTG.DtV 3kӋMcbPg/^z#f]l6­#UO"""FywE2>p`Fl-Zhj,!}( (.吾>>>CRvbt6N+k"9O %4#J2YA;cf\מczUn"3`PɯHoutAx”5aMkp" ʂ$ >*$ no/K^TBGzDG*lyA5uA@"Q#$4UnPAso*d+Cfo'+HS*pQlbޭ^qJ> mr;ɿrE,f _w4"y(7Qj&݇< D {Wo,\wS/8{Yأx: r-kZ)Iq(=،嗮ՇB.i?ӎ!LKI0ch믔qqCC#S#F/"6"Btނצ#}^lV4MCBUXO/*['SHIҹ% I ˗fzz<ä|Eۯn>Q t!U5!Ml8O[-8-i}lLfE0ϊ7g0'ҦW< 8VE)j)kJu0!,S2c25rwq/~fW-oG܅Zn R0VxSmoΞHGψف_:˝ $˻ApY{jҏqk_vKr% ]^)48 VP5MbJL(3Dh_zæ{y [jp[_K[ Ga9,[yH4&+X3K;yA'>~+Y13-UkjךiMBBw'ۀAװ-W aT'S=S>.G%%Qnǵ"=3Ul{R*X?gY/ԓ8+#ڶx/D0RSn P Xog9V6}cMPlsM?P.& -׹71"N\ G%aQ[jۅ|k7 L)YFKݳ#{_̬|4!xw!|X Yjf*niь)rپxO^=@-WUu]k&T{-#bȅ\(h:=R>t !j)@a%dYmk40Ⓜ}|/ ./"/3kͥ!\Y+JL=.3ݐ81̶>~K%GFoLf;%b&v:5\)x lEVY2pᗥشRB;^:Kq+ieOkT(Kĭ `Η+(%\{؃ [ؖj?}N٦/0i9@QUU[DwsLNZpGI3 N Ѹ$CqA\3T[0EGA.B=}yMo&N^U%Oc o܆éf5K]ݳXؿ/27OkD@Hr 굾Y7T#)+f7ઊ(jND,cсN$s|a -np !4zߵ+i=)8pUmuX|A@HK{üF,/a#R *=HxM9 b,eQ6:pѸDɂ*u#S`L=QaRܗip]}e2j7ne[c7;anbt>'5?za$MF+1Ĵ&1sű0dtvc`THObYf'?U^E*wRe=K/܏R4č O:Yc'Eqզ^g \Jcg5  jkgۿJiM,}V׃ΟsY%:~kf&?l/%dˋQ ?-$a >0*L[QX+拿U-Bu9e]H8 ؓoSefܰ?:m߱~ 3XUߥ$ xVVaNk'b w9<TKڮ{j5D$>zԵRͪ ࣴW:s+ܐ[xpR_h0 0 C!gu})ԕ'ӱr|3a1׭Ds|E:D=.^02{9X`bp^%?V+^4-91`'~5†8X}z0oL)։/J J4[M,.חy m ţPp_:q]wt1rUOCs1"̃ݳ$ ٬T+& yL*h.[T/S]m g&'ǥ:\i$[cC=-]qt?&%{׌ʅa[lOV)Qfyy_ Ӓc %v۲=w^o³v>޹1J-$P͡\~?Rͷ^=_WjBhA)XzHUn.P/saa|FI&&qJOi{7T8 rYGӷx..`TZ19Nȡxjr3N+0sM xSbiWKҁP-5aBpT-x܈zp07Jz4156ǻHD6;V>t~>&륔/ޛXO8͔ijpm7`QM>ڿpLC"܉,>yP#!'s f*=qnWRCBße!EׁNq2d/Y8LX7i>3o(obhKÙi(btYUz9!zEV8]ȳЯJEwnqM}zOenț/ рrECkR4 >N69na01JGh;P p?b/zJLYI~7 KNR;Mm zvN?- KQ:Suce* `ZR -qW`$PBiMR6!(9 ^(T=Rw< 弗>aJׯ*gnzr#{A.!?6^slaSf>>>47@kg.QlK؆SN w: XTtT8_b}>AX\D}ᤇ QVBjgyeWqal ZKE f3@Z]jiS?>W{vzۿ7p[!5&ʼyy 킩0P`xGOZ'EhX58OBX'}Ly!A(JOJj=+On@-Sn<{ ?(S {]?o1m\X), M $!Q Mdb5fϠ?\QK&RU L/XY)l35XQD r5A29׍JvgJ@>cuȪuOQE̠Onȿ=)_^wٙ gmH׿[ mQNR;5 p%>|Y":c  DB xNJ޾(cݏ\y#T ]g!&~ez :u#ɐtvo /EX@s=5`"lj t@w.愳/%9#Y߲~))%O\F.hE.EXBkֲahWmW\6>Z]zc$V3A^VXxG1x#͵K۔5J͊4. .M;_uŸ#sH4gj"47DDT \s. v݈4g ]YJ)ho'78;˒c1 \XoD0,?V5 7}dk+y|ηf,+PBEJ.؄/lm1G#[_˅; JAy"rbEN𭜦HވYȈ蹵mp D} o#ͩ#\1F_Zx &Z~gh–hnO<Q})E]Ӄ!G1B_ ;*8M [b+ᣥCsԢiry3VKXy:8͏cS5qJz9*?Q#]Ha0!t Ϣ8#sr5zN[uҐRtTB`K8{tPpu8ޖ tUDĥ!\.ځ<@ >AOq W*JPx[`ou[%dzom_j-(T n}Tz%ҰI4!]ST`G`2 Ug^J[ nzwMeKtN ub:3ĐAf\&@A1.Gvr7q),#ZÖjwmp,NOwv(廇ҵ:S6{/Ecy 2+iA2qCwJ71\(`:DK3-e.`]i')yڸ1R u/6 Ps&k <=?[6sj4ZOפ-P,tHty Gm?]vf.<ާ5ӻHyi,RҜ!WOF5w4+ۇ.|5*3p{z~;tleyrbGd @ (ԆQ<*|\5Z{[X2ŒI)F;X#.i1ւ& 1>@c uをQnvMr>@O>n ہJ3pEz(DWJ@"Ket 0}9i> u Q_vF:lUp } s1D?]6"VBt5yM.z0[-xO*AfBM= M/U+vH$q P,|1i%W*+DRyw 'H$匾oK"ao,gīj9Ž|E\@\ȶɃ-jp4PO8y8xWej}3+Bx F(<GE$OɓkLfЄF:oM\ HgAM^C'^zMWe%Ĉ``ƪ$]µFp2g T÷YJQJFYB' ߄8GSW#͹n1P\/} SbA|j` ~Sb[TeL蒖ɁՐR21϶GzPVy6 )F̣\PR:VW ,pnTrC24#JZ,Hw2aX,xC~_fYyx EBPnDnOa8t|ɦTx0)dѩWj(ct#Y?!10øTZdw/VH=.LJu_qRlg :sCn0Q߼dz+/)juⱐǚ(6[ȋvXtQ\&#k!Fk'(sJ/_Ӫ4')N6 - mi/Բ0 -Y09t T?F0m=ji] t_Xk7LGL!bW mk&Jdg(bϾTyu]Dل3ͦ9$#%2+ڧff|jޠA\e$pй! { A[t R2V!XAry4qZH[0x$o$iZZh9$ުdE _xgemzX9W*Ac7ZRx-),b?BuM<*={k@E~L< pWS|Wuͮc]6|" ,D7H+ cH= ϬAOONɐ%@HCE}6׭09Fw: A&0s7嬿 OtbN{cXKK&o*WB(⛻f߳Źv۟h(elQ5q/eC! 0gN`D\K`uCwdCi7dD{nڇ4MհF,'м7F`| 3XFtQ1;~!klUq8eZ cihGǘt+0ɠ[wыd|ϖ?~AXVW'*UT{eJ+S'TiuwZü֗@/m|=ԆOwQ'V4JiMݫ6)n svgS56Ynv0}řۓ\ c#٥V5 aQR/TiF%Yz8 T|ITOA㪴 ~X46Un] @X.[7\?GExCY̚iz=7ϹҎtO/ca\o vN7ix]TCǮ< ySսo1OhHX՜͝-~!]@k?L\`w @3{Rc b@ VP uh5^M.Òb}6MjWDO qs*Qrx9>FX_uK}'ϕ>Z.>5T3dwA 3=دNRz^mꮄռhU v- :}W8]kU[D8VB׏d+VmgjJ*O{+Bڣrn.T (|80ȍ /Z)1GN?kFg5@bb*SJ}LbMo !*z%Yh&leJ)+IϰѨݮ 3_2v;ͬ2MmOZz)\8CVeKmy0_ l42ɴ7A1Qȥ(hx2E#O,ȧgՙ[B*L299ä{lJ5v[H1^|R퀙1WOF?wFё +EvF#$zf.wQM+X9qI.۬(ݟ)#Y+PIF*YDuX컢doKͿh;f*Ruy [K|H4†N`Jờ3.&L !FEUԘo_(QҢܢya We) ,GIQa#Z幅oSj"_.FI l8yu}zoorf4YV-ې4W\" qg,`sX8g&6jay qYh򧟨+H/vrĪ9“90i]Ua!\ cU^d,wtD_\J8)r(d#3m0}nJ EG'NYs"@{ 8:~0U&P={_whD s`T_?t$(giJ hy vЖCGe]&{#$:}:~©{~RDtoH_O%V`zERu3lAzNj1#;P? z18PF%QkR g-s&xLцlZbZt+-!txG4l͏Q?=|&汦UkSL3 >LlIh+@2rLVI> lg7Hvލ'TW/j(=yR:܀XztryfRJRe[vF瑏ZT_n%YD\"AIKOhjpk2ڿw 'yΆ^ <I改Z0ZkXC3ַyOu|#t#-rhkB/x{ }P5%M{%h]Yo0]Yۍ -[8۬@a_)Nͷz"-;]fp4 Vy9J6WN9bu:c H zdQ+JF΍Q.!m;HDQc=H)S-NwtYY @³R;0[׿e X/Nrdnq] rjzŭz'$: FNޮr2KGa8 ,"yNeFiuL4%X[/Yf֒%Bv 7)\ 6H at?`~Psiޮ76 JJMZ ?&'+/ABƮ hP=uQ11sԇL˺U㘎":-EnAYՁYWo}bdhh*.U$ח r }a$LIn`5^ph1Ut5=`7َ&9l?:}doKx˥ZhijfphEEk.,#잪*Mi?U@ޖ?+*9j$l]]9a8L>!I`(T^>K5 Vm=}A0mY(s@.XsBcU,7ލ_њNyTLEJ%hE[$u#gO_'ǟAZIgc5GmϚ-"yԏt@xp7w|bFb uJAEl̗9Z(J͟'ü|!&Kl0÷_eb$w6>s~:(ȩ ʭņ]J`X*͑4~{~9N$}WWJs":5'wXo؇f@ioպ앏y]U:cb\K-GSe4ֽ7lk*vH&tabOWZK4ns_ݻcQ aW Wѣ#5j,GG D\*ֵKH.זaYiFfK C*X Kz d;Y]^lHX@uN,@*/,@Dzˎy"IS[hte]C!UwJ^'5EA2Үg CR# \q" J[xsR@h#ꀴ( Zn퀉 RR(=m3{sqG'!Xz {btSNq,ӻ+pd /L^mPF _ Cl׵ \YJ8'(VJ*G?[5(ۗ#>0?CTPvȔ+kK>hBz  pϢsɴj4ZJf 6ݦ"`m" &x✕RWFV !,}drӡ`X繖`i~C9HpjLĎ8Y2_#@t0?KuəS(=,p I|yRDpZ |f`RӸT3E#m)~\l#a%6TQ^Eyh-1xH|<~}RPIH%R^:ꋵt*!FsaՋqV0r R*apPp/%rߎĮS8]V\7D 9*=Eʍh>#}p&Xr!Pc{dIJ !h@wo9G*wFúuw|u)и;crkx0g n>E`=S {}S>o=<PCVFwCQxuڝ}xPa+H( BU ^r;t,ƱU\ eߗm;թxFOh)[dB K p3 G\_#@fDң-/[3QdbkDleȳm1fT#B;]ҫ, S`9(cH߄wRn00m b(V$ŕ*0DH^3`[)O0P4D|+ܫN!IqeCS nܬSn]iHm|8*6sɦ!{|frW'MF&JTѝ/DŽhvjwn k V!tc+ §'p2]GfAz=4RtY* &*wu3b>\dM~vlm?_ ~"<)JbѻVCTA؟EMAN,[fȝL8fզ<sKybr[ҹwY-@bry۲0!zR(_p3\3|e髭?ᰟ&\WY|iG"%W5- OXЩ،IP:?:qFY?h.Z1!Y/sS:3l:i؋dfvyViiJH,O},69[Pc5j.(J%܊\]NSJ҂ ;[T14FS}lx o6f2%dHlj_NR˿K? @h S3|?I`49B&-h7/ x$tRC\VtxO0 \LLRh~K.WY]cJK,A:wA?X`>ԿHcH*d rwo7#tjdZlMrhg&gL9:q7W"BanBCj(;Po/} :[n۩kɋɡE2ߣP v? {PxIZT]Ue\JhEl;s :T¯t$pG]rI !;oJ CtHMC]p ;RU,/ 8bْ#ҡ.m̖.}72=٨hm`QI\*U+pL9w!%3I@:M|iLe>J-E:ү'H7%5.|}[؅d>C g "H75m-+R{2Cta?C 2ɡۜt |4r0,N{Z A $ >S\-}"2'Uvr#Pdߐ==b:v;nAW ~&v8 qU>]Įeh*vnUphn`|qᬭ%۶紟;g>7CV \f[c%CWko-/>Gܢ!"C?B(,O&~]fr_.dvj+dZ۩uǸs!X}B*I4;=+WՃ-6=oë%c9!%|6]d@G¸Ƿ *y34þD!(u=SzF뇌lb ?5%c*`„}˭̸JU iQ @2ΰV GlF#˒"Btt@p=4-1:̽fb|8hf5fV&HRb >*fn(QS dLmo43# 3M(X}[ANuB1c ^z.Tfw>| Ax C.x.KPV6hU=W)laҬd41}F!;We9RxY>A$g#e&] eP\a\{W'@c"jXdD'S)䘬J8Vh*^ڛ^*]S˖b%LI_Jf[a*䛐 N-Q=(Cw4d듯~XM$cpqm G$"#8-|}[PȜTIGADH ,Q7n@xQwah淊sbz/%}98xFY Ԯvo5Ad$JǦ+|3RBpuTvD}li;ń!@8DCP'dl$L1HbPwuVAg~SPG}"MoZ;n 7,YU+cB73=3;L.[9ߦu;յ߳f`+p8wJlnTs1K+R~g;hwkFA7%yz/EV)*Q &G6u t=352D5MZxz;5c#EU@B6'~cCIȇc%De{|LB5r.>`Fܕ;eqإVi!n>ҁxES/C5;]ǑIkCo`!8ȵ g7?&Ώ^#w;ܢCY$KOl'n楱>m) ʵEO(aH4tYE1?7&ϛR6Ln~PZv6d8c7 J2-e3+bHEj4y%3좡`P ȉ NZ胼r iɠ2:ɥXp-7pWrGu+Y un30OR{7& j3U6nߜy@jkMLQ5jx]Rz\^V f/&J>`o3P),ѡ@tyK9hZ-K`AXE!Nw ujt:Ĉ43 (8=lb&rWrHmwFeS6ɈZJUdE VK34ܚS3䩩CpP~03M_Q,&[jm]Ҥ~*Qϻ]BKh^?͡}(Qd Z,BeҔtGȂT;t9`mYsI5 1a ‹&~;{srڐCyDExT8NҺ]QRO,@5=ڣkH/ 4 kt-\oJf蘒Qead~^j[D˟saY P7S.8|6yŴr pÃJ@pBUc2%{r7N|7S h&:} ;p@ K'@?y(jj[+p,S& \k KA0a>4BWWMƉNK &`)In q>73~C|0[z!kUY_ Ia|/8\ sD3\)4/06 9a+t!EMW"fnXt3G TUB7.SkHL1o"38wD:L¸0v΢нhZ꘴ֱSUk[xO)3.2~_gW"_虣%iۅH%JؑgqNZ˧ =upG2x@M*3KP`n@cx oѴаA aӴ,$FhΊ?~iYY^=\ՔgC)$31@ qG.)6;;k8`"$X5?7թC)dH0!*3iz'K{C~*L]RlU2'`@1#qy>\\oԥu}#jܯ1eEޕnU~ꐽ .m?kӀ7vU{o%մpnaVI#1@W CEةkD,xU,vmZTx ?C")L>(QcD:i7OxHE8fVqB'&`ѝ R3J`p\}ūkE"@ bT1.;cW0#=Vvd)ɢcnO>CտP QBf8R/!7gywRѧ_ H:sbpanc*- m2j<ſK#{neߚW''Ə$1v{=@'/P%v,AISREjGlwżD?Vf8s Il5u4"W> ]O;?G$ "xK2峔DRq=ZaSR  zv_:54BڀI`7tL83dػ :to}*P#(,r `,lR,;[5_$kwi ڈ76#Q=r*gZW &Qw0a<5ӾL@@'YMJ:Z3S ,BRB -sPzyxKQV]Bd-F]]G%C C֤~7SS!NI+?y|VTg1׮r!kWo(XjQ?zjn`ͣF߽cNg1 y5Py<_%ex_>Ј)dtL{Njζ8[91‡Tp R/A :ќ6 76vb\)*VYj[ΧVHo'ZiB8o7<)KJCgQN6]FM99Cv"`mV(q3D󚊭gu3m$.KNSo{VJ&h$S|9.EzBG)`J:s/p=Sv\b2v`̐1!&ԭsoUT>z\#gGA,gn= "YG^]@jĊt~`/ MF!DyAdn&;X\U($ B߱$b^`[ ,˕0Yj!(t\_2bvp', Y-9)?urWw~j*jb]P`8Z5[۬XGh 6i~.U A''O*A=fO{JW͐d1N j\"ZkI5~Cw*Nu vRZ8k溻iGp,p0-khj@['5!&5wڂaRTZ跂0V cv'g{`}j@r=ңrksRА8x!U5R(o;|)w86jL-v/0$xًmHns6Ay*0Vq,#uU$5r>0j miS h!4DYNe01=|tA+1$< AF&c(yde-PĨ,q&XI1=ĵ} !tjb>u>Au<̱1{h@Mk{۝QS Q~ ׳-nٴ77U,|bA>l."-B  rÇLL/tPDWo۷64ĉa 2_l'+ptxwY 7{ƵYE"޾D\Vo"ɚV9 x4n<;[a_ ;S\RB?^ٰ."}]lAf-^)]T b@N\ݽ1=Xݝ O~* $ TTW&'D2E~ilagA״$sW)W` <RvTǴ̉ʙIzD6nO1õ*ˎwuBfw%~UYqq7ѹT{_BkMm$0fИ'gHo(#>̀HlymhrPuJؚ0*1 и*}7bt ~ wR9 9S iygm=l j=RJr}GE#퓑I~Z5q{ۣcՑ5 |'7H^ Tƙ`$ c\zYPR.f0z xʝ$d3)M%oS]!aLt, R*(#ӣzl7cYe~#"O61 t89#ʟ[?|9/0_$dF5{lDDƭt~]~_id=C;J8'}?9)חk)1vA R')xfU0BGSmnU;*$&_|125F#w5d#Ӌ۰}P6bnov/^e' Cx9n.bޱzA-=:EՋ-+OH 7œ M0vRP2 JX<1,Wk1wm5>p8u&}yNP h;@5PeQ=A0M"Ԡ}hp.*;%|ǖV W)ґ@xõ8#' i/Q@a*Sgy ɼu _P+gx^\:`9t,Eikj;Ag tMkPg<9-& \FNv*RޕOmN# &-WNB#%qq F],yt5?~9p(ۚύ o rBY J,;8ǣ[Wr:d:6/a,E`yPe#+(οUe&.W+Ni{޵2p?MstAbpnv%ptjd0$0攐{&|6n 2Fxvm^ hU}mVbMy> 8?CbEaq[ &G@6/3vM ." FS@!Be#l|QYU0 Pd_aa7k$P"'.C֢"sbo0l4%ohvvC|wEr*aBƲYpJh `_좛8$k@)g͓:@ً¶\/d:b[0c|"($]kla5)/vx+:Q .KVU4Њlt 9hhyv5\p᪼A@HnYM< 2/Fhb8\_C؇2H(U-r{ufi֨1KSd 1zCOܐ [{zK&W#|&w!ٛ'^'~\U>/ 6ks]c QM<yӆ1ؠ<B 5QCMa}v=cg*Ūs0 TvKAb.iSi(İ!skp:֬9;z {Y 6Oʿc$^KFny 5mrP3=TOeۂ( J5[7 BM7poPL"M?gi$H2p&njb(U lhO0wé ٲΙb״Jw ŽB>!4/M4!GMި\n 1qt/f V([ƥmB)T80"]Y#.ZGsY  y*6Rd2^6[~󏠕E0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 cleartomark ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707393948.4025588 reportlab-4.1.0/src/reportlab/graphics/0000775000175000017500000000000014561141634017470 5ustar00rptlabrptlab././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1691062243.0 reportlab-4.1.0/src/reportlab/graphics/__init__.py0000664000175000017500000000042214462707743021610 0ustar00rptlabrptlab#Copyright ReportLab Europe Ltd. 2000-2017 #see license.txt for license details #history https://hg.reportlab.com/hg-public/reportlab/log/tip/src/reportlab/graphics/__init__.py __version__='3.3.0' __doc__='''Framework for reusable object graphics, in PDF or bitmap form''' ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707393948.4025588 reportlab-4.1.0/src/reportlab/graphics/barcode/0000775000175000017500000000000014561141634021067 5ustar00rptlabrptlab././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1691062243.0 reportlab-4.1.0/src/reportlab/graphics/barcode/README0000664000175000017500000000331514462707743021762 0ustar00rptlabrptlabSymbologies Currently Supported =============================== The following have, at a minimum, been verified to scan with a WASP CCD barcode scanner (found one bug in my code, two in the scanner!). Some have had more extensive testing: Interleaved 2 of 5 MSI Codabar Code 39 (Standard Character Set) Code 39 (Extended Character Set) Code 93 (Standard Character Set) Code 93 (Extended Character Set) Code 128 (Automatic use of A, B, C, with some optimizations -- more coming) The following have been tested by sending a fair number of mailpieces with them: USPS FIM USPS POSTNET The following have not been tested, as none of the scanners I have access to support them: Code 11 Future Plans, Consulting ======================== Soon: I plan to implement the following linear codes soon: UPC/EAN(/JAN) The following are in progress, but I lack a way to verify them (scanners I have access to don't read them), and I don't have complete specs for the UK style. Royal Mail 4-State (UK/NL/etc style, and Australian style) Down the road, I'd like to do some 2D symbologies. Likely first candidate is PDF417. MaxiCode, Aztec Code, and some of the stacked symbologies are also good candidates. I am available to do implementation of additional symbologies for hire. Because I enjoy hacking barcodes, my rates for work in this particular area are very low and are mainly to help offset costs associated with obtaining related documents and/or to buy or gain access to scanning equipment for symbologies if I don't already have a scanner that supports them. Loans of equipment are also accepted. For more information, contact: Ty Sarna tsarna@sarna.org ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1691062243.0 reportlab-4.1.0/src/reportlab/graphics/barcode/TODO0000664000175000017500000000162314462707743021572 0ustar00rptlabrptlabSee also README for some plans and info on consulting. - Overall framework docs - Finish Aussie Rules 4-State, for which I have complete docs now (yay USPS and aupost.com.au for putting specs online. Too bad UKPost doesn't.) - Investigate USPS PLANET stuff - Higher-level objects that handle barcoded address blocks with correct spacings and such (US, AU, UK/etc?) - Even higher-level objects that represent mailpieces and place the above-style address block objects, FIM codes, "place stamp here" blocks, etc, correctly? - Framework for laying out labels on various styles of n-up label sheets, like Avery labels, etc? - Decide if Plessey is worth doing. MSI-like (MSI is actually derived from it), but specs were never formalized. Probably only useful for legacy applications. If you need it, mail me. - Get someone to test Code 11, or find a scanner that handles it ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1691062243.0 reportlab-4.1.0/src/reportlab/graphics/barcode/__init__.py0000664000175000017500000001337614462707743023223 0ustar00rptlabrptlab# # Copyright (c) 1996-2000 Tyler C. Sarna # 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. # 3. All advertising materials mentioning features or use of this software # must display the following acknowledgement: # This product includes software developed by Tyler C. Sarna. # 4. Neither the name of the author nor the names of contributors # may be used to endorse or promote products derived from this software # without specific prior written permission. # # 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. # __all__ = tuple('''registerWidget getCodes getCodeNames createBarcodeDrawing createBarcodeImageInMemory'''.split()) __version__ = '0.9' __doc__='''Popular barcodes available as reusable widgets''' _widgets = [] def registerWidget(widget): _widgets.append(widget) def _reset(): _widgets[:] = [] from reportlab.graphics.barcode.widgets import BarcodeI2of5, BarcodeCode128, BarcodeStandard93,\ BarcodeExtended93, BarcodeStandard39, BarcodeExtended39,\ BarcodeMSI, BarcodeCodabar, BarcodeCode11, BarcodeFIM,\ BarcodePOSTNET, BarcodeUSPS_4State, BarcodeCode128Auto, BarcodeECC200DataMatrix #newer codes will typically get their own module from reportlab.graphics.barcode.eanbc import Ean13BarcodeWidget, Ean8BarcodeWidget, UPCA, Ean5BarcodeWidget, ISBNBarcodeWidget from reportlab.graphics.barcode.qr import QrCodeWidget for widget in (BarcodeI2of5, BarcodeCode128, BarcodeCode128Auto, BarcodeStandard93, BarcodeExtended93, BarcodeStandard39, BarcodeExtended39, BarcodeMSI, BarcodeCodabar, BarcodeCode11, BarcodeFIM, BarcodePOSTNET, BarcodeUSPS_4State, Ean13BarcodeWidget, Ean8BarcodeWidget, UPCA, Ean5BarcodeWidget, ISBNBarcodeWidget, QrCodeWidget, BarcodeECC200DataMatrix, ): registerWidget(widget) from reportlab.graphics.barcode import dmtx if dmtx.pylibdmtx: registerWidget(dmtx.DataMatrixWidget) _reset() from reportlab.rl_config import register_reset register_reset(_reset) def getCodes(): """Returns a dict mapping code names to widgets""" #the module exports a dictionary of names to widgets, to make it easy for #apps and doc tools to display information about them. codes = {} for widget in _widgets: codeName = widget.codeName codes[codeName] = widget return codes def getCodeNames(): """Returns sorted list of supported bar code names""" return sorted(getCodes().keys()) def createBarcodeDrawing(codeName, **options): """This creates and returns a drawing with a barcode. """ from reportlab.graphics.shapes import Drawing codes = getCodes() bcc = codes[codeName] width = options.pop('width',None) height = options.pop('height',None) isoScale = options.pop('isoScale',0) kw = {} for k,v in options.items(): if k.startswith('_') or k in bcc._attrMap: kw[k] = v bc = bcc(**kw) #Robin's new ones validate when setting the value property. #Ty Sarna's old ones do not. We need to test. if hasattr(bc, 'validate'): bc.validate() #raise exception if bad value if not bc.valid: raise ValueError("Illegal barcode with value '%s' in code '%s'" % (options.get('value',None), codeName)) #size it after setting the data x1, y1, x2, y2 = bc.getBounds() w = float(x2 - x1) h = float(y2 - y1) sx = width not in ('auto',None) sy = height not in ('auto',None) if sx or sy: sx = sx and width/w or 1.0 sy = sy and height/h or 1.0 if isoScale: if sx<1.0 and sy<1.0: sx = sy = max(sx,sy) else: sx = sy = min(sx,sy) w *= sx h *= sy else: sx = sy = 1 #bc.x = -sx*x1 #bc.y = -sy*y1 d = Drawing(width=w,height=h,transform=[sx,0,0,sy,-sx*x1,-sy*y1]) d.add(bc, "_bc") return d def createBarcodeImageInMemory(codeName,**options): """This creates and returns barcode as an image in memory. Takes same arguments as createBarcodeDrawing and also an optional format keyword which can be anything acceptable to Drawing.asString eg gif, pdf, tiff, py ...... """ format = options.pop('format','png') d = createBarcodeDrawing(codeName, **options) return d.asString(format) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1691062243.0 reportlab-4.1.0/src/reportlab/graphics/barcode/code128.py0000664000175000017500000004402314462707743022622 0ustar00rptlabrptlab# # Copyright (c) 2000 Tyler C. Sarna # 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. # 3. All advertising materials mentioning features or use of this software # must display the following acknowledgement: # This product includes software developed by Tyler C. Sarna. # 4. Neither the name of the author nor the names of contributors # may be used to endorse or promote products derived from this software # without specific prior written permission. # # 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. # from reportlab.lib.units import inch from reportlab.lib.utils import asNative from reportlab.graphics.barcode.common import MultiWidthBarcode from string import digits _patterns = { 0 : 'BaBbBb', 1 : 'BbBaBb', 2 : 'BbBbBa', 3 : 'AbAbBc', 4 : 'AbAcBb', 5 : 'AcAbBb', 6 : 'AbBbAc', 7 : 'AbBcAb', 8 : 'AcBbAb', 9 : 'BbAbAc', 10 : 'BbAcAb', 11 : 'BcAbAb', 12 : 'AaBbCb', 13 : 'AbBaCb', 14 : 'AbBbCa', 15 : 'AaCbBb', 16 : 'AbCaBb', 17 : 'AbCbBa', 18 : 'BbCbAa', 19 : 'BbAaCb', 20 : 'BbAbCa', 21 : 'BaCbAb', 22 : 'BbCaAb', 23 : 'CaBaCa', 24 : 'CaAbBb', 25 : 'CbAaBb', 26 : 'CbAbBa', 27 : 'CaBbAb', 28 : 'CbBaAb', 29 : 'CbBbAa', 30 : 'BaBaBc', 31 : 'BaBcBa', 32 : 'BcBaBa', 33 : 'AaAcBc', 34 : 'AcAaBc', 35 : 'AcAcBa', 36 : 'AaBcAc', 37 : 'AcBaAc', 38 : 'AcBcAa', 39 : 'BaAcAc', 40 : 'BcAaAc', 41 : 'BcAcAa', 42 : 'AaBaCc', 43 : 'AaBcCa', 44 : 'AcBaCa', 45 : 'AaCaBc', 46 : 'AaCcBa', 47 : 'AcCaBa', 48 : 'CaCaBa', 49 : 'BaAcCa', 50 : 'BcAaCa', 51 : 'BaCaAc', 52 : 'BaCcAa', 53 : 'BaCaCa', 54 : 'CaAaBc', 55 : 'CaAcBa', 56 : 'CcAaBa', 57 : 'CaBaAc', 58 : 'CaBcAa', 59 : 'CcBaAa', 60 : 'CaDaAa', 61 : 'BbAdAa', 62 : 'DcAaAa', 63 : 'AaAbBd', 64 : 'AaAdBb', 65 : 'AbAaBd', 66 : 'AbAdBa', 67 : 'AdAaBb', 68 : 'AdAbBa', 69 : 'AaBbAd', 70 : 'AaBdAb', 71 : 'AbBaAd', 72 : 'AbBdAa', 73 : 'AdBaAb', 74 : 'AdBbAa', 75 : 'BdAbAa', 76 : 'BbAaAd', 77 : 'DaCaAa', 78 : 'BdAaAb', 79 : 'AcDaAa', 80 : 'AaAbDb', 81 : 'AbAaDb', 82 : 'AbAbDa', 83 : 'AaDbAb', 84 : 'AbDaAb', 85 : 'AbDbAa', 86 : 'DaAbAb', 87 : 'DbAaAb', 88 : 'DbAbAa', 89 : 'BaBaDa', 90 : 'BaDaBa', 91 : 'DaBaBa', 92 : 'AaAaDc', 93 : 'AaAcDa', 94 : 'AcAaDa', 95 : 'AaDaAc', 96 : 'AaDcAa', 97 : 'DaAaAc', 98 : 'DaAcAa', 99 : 'AaCaDa', 100 : 'AaDaCa', 101 : 'CaAaDa', 102 : 'DaAaCa', 103 : 'BaAdAb', 104 : 'BaAbAd', 105 : 'BaAbCb', 106 : 'BcCaAaB' } starta, startb, startc, stop = 103, 104, 105, 106 seta = { ' ' : 0, '!' : 1, '"' : 2, '#' : 3, '$' : 4, '%' : 5, '&' : 6, '\'' : 7, '(' : 8, ')' : 9, '*' : 10, '+' : 11, ',' : 12, '-' : 13, '.' : 14, '/' : 15, '0' : 16, '1' : 17, '2' : 18, '3' : 19, '4' : 20, '5' : 21, '6' : 22, '7' : 23, '8' : 24, '9' : 25, ':' : 26, ';' : 27, '<' : 28, '=' : 29, '>' : 30, '?' : 31, '@' : 32, 'A' : 33, 'B' : 34, 'C' : 35, 'D' : 36, 'E' : 37, 'F' : 38, 'G' : 39, 'H' : 40, 'I' : 41, 'J' : 42, 'K' : 43, 'L' : 44, 'M' : 45, 'N' : 46, 'O' : 47, 'P' : 48, 'Q' : 49, 'R' : 50, 'S' : 51, 'T' : 52, 'U' : 53, 'V' : 54, 'W' : 55, 'X' : 56, 'Y' : 57, 'Z' : 58, '[' : 59, '\\' : 60, ']' : 61, '^' : 62, '_' : 63, '\x00' : 64, '\x01' : 65, '\x02' : 66, '\x03' : 67, '\x04' : 68, '\x05' : 69, '\x06' : 70, '\x07' : 71, '\x08' : 72, '\x09' : 73, '\x0a' : 74, '\x0b' : 75, '\x0c' : 76, '\x0d' : 77, '\x0e' : 78, '\x0f' : 79, '\x10' : 80, '\x11' : 81, '\x12' : 82, '\x13' : 83, '\x14' : 84, '\x15' : 85, '\x16' : 86, '\x17' : 87, '\x18' : 88, '\x19' : 89, '\x1a' : 90, '\x1b' : 91, '\x1c' : 92, '\x1d' : 93, '\x1e' : 94, '\x1f' : 95, '\xf3' : 96, '\xf2' : 97, 'SHIFT' : 98, 'TO_C' : 99, 'TO_B' : 100, '\xf4' : 101, '\xf1' : 102 } setb = { ' ' : 0, '!' : 1, '"' : 2, '#' : 3, '$' : 4, '%' : 5, '&' : 6, '\'' : 7, '(' : 8, ')' : 9, '*' : 10, '+' : 11, ',' : 12, '-' : 13, '.' : 14, '/' : 15, '0' : 16, '1' : 17, '2' : 18, '3' : 19, '4' : 20, '5' : 21, '6' : 22, '7' : 23, '8' : 24, '9' : 25, ':' : 26, ';' : 27, '<' : 28, '=' : 29, '>' : 30, '?' : 31, '@' : 32, 'A' : 33, 'B' : 34, 'C' : 35, 'D' : 36, 'E' : 37, 'F' : 38, 'G' : 39, 'H' : 40, 'I' : 41, 'J' : 42, 'K' : 43, 'L' : 44, 'M' : 45, 'N' : 46, 'O' : 47, 'P' : 48, 'Q' : 49, 'R' : 50, 'S' : 51, 'T' : 52, 'U' : 53, 'V' : 54, 'W' : 55, 'X' : 56, 'Y' : 57, 'Z' : 58, '[' : 59, '\\' : 60, ']' : 61, '^' : 62, '_' : 63, '`' : 64, 'a' : 65, 'b' : 66, 'c' : 67, 'd' : 68, 'e' : 69, 'f' : 70, 'g' : 71, 'h' : 72, 'i' : 73, 'j' : 74, 'k' : 75, 'l' : 76, 'm' : 77, 'n' : 78, 'o' : 79, 'p' : 80, 'q' : 81, 'r' : 82, 's' : 83, 't' : 84, 'u' : 85, 'v' : 86, 'w' : 87, 'x' : 88, 'y' : 89, 'z' : 90, '{' : 91, '|' : 92, '}' : 93, '~' : 94, '\x7f' : 95, '\xf3' : 96, '\xf2' : 97, 'SHIFT' : 98, 'TO_C' : 99, '\xf4' : 100, 'TO_A' : 101, '\xf1' : 102 } setc = { '00': 0, '01': 1, '02': 2, '03': 3, '04': 4, '05': 5, '06': 6, '07': 7, '08': 8, '09': 9, '10':10, '11':11, '12':12, '13':13, '14':14, '15':15, '16':16, '17':17, '18':18, '19':19, '20':20, '21':21, '22':22, '23':23, '24':24, '25':25, '26':26, '27':27, '28':28, '29':29, '30':30, '31':31, '32':32, '33':33, '34':34, '35':35, '36':36, '37':37, '38':38, '39':39, '40':40, '41':41, '42':42, '43':43, '44':44, '45':45, '46':46, '47':47, '48':48, '49':49, '50':50, '51':51, '52':52, '53':53, '54':54, '55':55, '56':56, '57':57, '58':58, '59':59, '60':60, '61':61, '62':62, '63':63, '64':64, '65':65, '66':66, '67':67, '68':68, '69':69, '70':70, '71':71, '72':72, '73':73, '74':74, '75':75, '76':76, '77':77, '78':78, '79':79, '80':80, '81':81, '82':82, '83':83, '84':84, '85':85, '86':86, '87':87, '88':88, '89':89, '90':90, '91':91, '92':92, '93':93, '94':94, '95':95, '96':96, '97':97, '98':98, '99':99, 'TO_B' : 100, 'TO_A' : 101, '\xf1' : 102 } setmap = { 'TO_A' : (seta, setb), 'TO_B' : (setb, seta), 'TO_C' : (setc, None), 'START_A' : (starta, seta, setb), 'START_B' : (startb, setb, seta), 'START_C' : (startc, setc, None), } cStarts = ('START_B','TO_A','TO_B') tos = list(setmap.keys()) class Code128(MultiWidthBarcode): """ Code 128 is a very compact symbology that can encode the entire 128 character ASCII set, plus 4 special control codes, (FNC1-FNC4, expressed in the input string as \xf1 to \xf4). Code 128 can also encode digits at double density (2 per byte) and has a mandatory checksum. Code 128 is well supported and commonly used -- for example, by UPS for tracking labels. Because of these qualities, Code 128 is probably the best choice for a linear symbology today (assuming you have a choice). Options that may be passed to constructor: value (int, or numeric string. required.): The value to encode. barWidth (float, default .0075): X-Dimension, or width of the smallest element Minumum is .0075 inch (7.5 mils). barHeight (float, see default below): Height of the symbol. Default is the height of the two bearer bars (if they exist) plus the greater of .25 inch or .15 times the symbol's length. quiet (bool, default 1): Wether to include quiet zones in the symbol. lquiet (float, see default below): Quiet zone size to left of code, if quiet is true. Default is the greater of .25 inch, or 10 barWidth rquiet (float, defaults as above): Quiet zone size to right left of code, if quiet is true. Sources of Information on Code 128: http://www.semiconductor.agilent.com/barcode/sg/Misc/code_128.html http://www.adams1.com/pub/russadam/128code.html http://www.barcodeman.com/c128.html Official Spec, "ANSI/AIM BC4-1999, ISS" is available for US$45 from http://www.aimglobal.org/aimstore/ """ barWidth = inch * 0.0075 lquiet = None rquiet = None quiet = 1 barHeight = None def __init__(self, value='', **args): value = str(value) if isinstance(value,int) else asNative(value) for k, v in args.items(): setattr(self, k, v) if self.quiet: if self.lquiet is None: self.lquiet = max(inch * 0.25, self.barWidth * 10.0) if self.rquiet is None: self.rquiet = max(inch * 0.25, self.barWidth * 10.0) else: self.lquiet = self.rquiet = 0.0 MultiWidthBarcode.__init__(self, value) def validate(self): vval = "" self.valid = 1 for c in self.value: if ord(c) > 127 and c not in '\xf1\xf2\xf3\xf4': self.valid = 0 continue vval = vval + c self.validated = vval return vval def _try_TO_C(self, l): '''Improved version of old _trailingDigitsToC(self, l) inspired by''' i = 0 nl = [] while i < len(l): startpos = i rl = [] savings = -1 # the TO_C costs one character while i < len(l): if l[i] in cStarts: j = i break elif l[i] == '\xf1': rl.append(l[i]) i += 1 continue elif l[i] in digits \ and l[i+1] in digits: rl.append(l[i] + l[i+1]) i += 2 savings += 1 continue else: if l[i] in digits and l[i+1]=='STOP': rrl = [] rsavings = -1 #we need a TO_C k = i while k>startpos: if l[k]=='\xf1': rrl.append(l[i]) k -= 1 elif l[k] in digits and l[k-1] in digits: rrl.append(l[k-1]+l[k]) rsavings += 1 k -= 2 else: break rrl.reverse() if rsavings>savings+int(savings>=0 and (startpos and nl[-1] in cStarts))-1: nl += l[startpos] startpos += 1 rl = rrl del rrl i += 1 break ta = not (l[i]=='STOP' or j==i) xs = savings>=0 and (startpos and nl[-1] in cStarts) if savings+int(xs) > int(ta): if xs: toc = nl[-1][:-1]+'C' del nl[-1] else: toc = 'TO_C' nl += [toc]+rl if ta: nl.append('TO'+l[j][-2:]) nl.append(l[i]) else: nl += l[startpos:i+1] i += 1 return nl def encode(self): # First, encode using only B s = self.validated l = ['START_B'] for c in s: if c not in setb: l = l + ['TO_A', c, 'TO_B'] else: l.append(c) l.append('STOP') l = self._try_TO_C(l) # Finally, replace START_X,TO_Y with START_Y if l[1] in tos: l[:2] = ['START_' + l[1][-1]] # print repr(l) # encode into numbers start, set, shset = setmap[l[0]] e = [start] l = l[1:-1] while l: c = l[0] if c == 'SHIFT': e = e + [set[c], shset[l[1]]] l = l[2:] elif c in tos: e.append(set[c]) set, shset = setmap[c] l = l[1:] else: e.append(set[c]) l = l[1:] c = e[0] for i in range(1, len(e)): c = c + i * e[i] self.encoded = e + [c % 103, stop] return self.encoded def decompose(self): self.decomposed = ''.join([_patterns[c] for c in self.encoded]) return self.decomposed def _humanText(self): return self.value class Code128Auto(Code128): '''contributed by https://bitbucket.org/kylemacfarlane/ see https://bitbucket.org/rptlab/reportlab/issues/69/implementations-of-code-128-auto-and-data ''' def encode(self): s = self.validated current_set = None l = [] value = list(s) while value: c = value.pop(0) if c in digits and value and value[0] in digits: c += value.pop(0) if c in setc: set_ = 'C' elif c in setb: set_ = 'B' else: set_ = 'A' if current_set != set_: if current_set: l.append('TO_' + set_) else: l.append('START_' + set_) current_set = set_ l.append(c) l.append('STOP') start, set, shset = setmap[l[0]] e = [start] l = l[1:-1] while l: c = l[0] if c == 'SHIFT': e = e + [set[c], shset[l[1]]] l = l[2:] elif c in tos: e.append(set[c]) set, shset = setmap[c] l = l[1:] else: e.append(set[c]) l = l[1:] c = e[0] for i in range(1, len(e)): c = c + i * e[i] self.encoded = e + [c % 103, stop] return self.encoded if __name__=='__main__': def main(): from reportlab.graphics.barcode.code128 import Code128 from reportlab.platypus import Spacer, SimpleDocTemplate from reportlab.lib.units import inch from reportlab.lib.styles import getSampleStyleSheet from reportlab.platypus.paragraph import Paragraph from reportlab.platypus.flowables import KeepTogether styles = getSampleStyleSheet() styleN = styles['Normal'] styleH = styles['Heading1'] story = [] storyAdd = story.append for s in ( 'BBBB123456BBB', 'BBBB12345BBB', 'BBBB1234BBB', 'BBBB123BBB', 'BBBB12BBB', 'BBBB1BBB', 'BBBB123456aa', 'BBBB1234aa', 'BBBB123aa', 'BBBB12aa', 'BBBB1aa', 'BBBB123456', 'BBBB12345', 'BBBB1234', 'BBBB123', 'BBBB12', 'BBBB1', '\xf11234B', 'Ba\xf11234B', 'Ba12', 'Ba123B', 'Ba1234B', 'BBBB1234567', 'BBBB1234567aa', ): storyAdd(KeepTogether([Paragraph('Code 128 %r' % s, styleN),Code128(s)])) storyAdd(Spacer(inch,inch)) SimpleDocTemplate('code128-out.pdf').build(story) main() ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1691062243.0 reportlab-4.1.0/src/reportlab/graphics/barcode/code39.py0000664000175000017500000002310714462707743022543 0ustar00rptlabrptlab# # Copyright (c) 1996-2000 Tyler C. Sarna # 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. # 3. All advertising materials mentioning features or use of this software # must display the following acknowledgement: # This product includes software developed by Tyler C. Sarna. # 4. Neither the name of the author nor the names of contributors # may be used to endorse or promote products derived from this software # without specific prior written permission. # # 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. # from reportlab.lib.units import inch from reportlab.lib.utils import asNative from reportlab.graphics.barcode.common import Barcode from string import ascii_uppercase, ascii_lowercase, digits as string_digits _patterns = { '0': ("bsbSBsBsb", 0), '1': ("BsbSbsbsB", 1), '2': ("bsBSbsbsB", 2), '3': ("BsBSbsbsb", 3), '4': ("bsbSBsbsB", 4), '5': ("BsbSBsbsb", 5), '6': ("bsBSBsbsb", 6), '7': ("bsbSbsBsB", 7), '8': ("BsbSbsBsb", 8), '9': ("bsBSbsBsb", 9), 'A': ("BsbsbSbsB", 10), 'B': ("bsBsbSbsB", 11), 'C': ("BsBsbSbsb", 12), 'D': ("bsbsBSbsB", 13), 'E': ("BsbsBSbsb", 14), 'F': ("bsBsBSbsb", 15), 'G': ("bsbsbSBsB", 16), 'H': ("BsbsbSBsb", 17), 'I': ("bsBsbSBsb", 18), 'J': ("bsbsBSBsb", 19), 'K': ("BsbsbsbSB", 20), 'L': ("bsBsbsbSB", 21), 'M': ("BsBsbsbSb", 22), 'N': ("bsbsBsbSB", 23), 'O': ("BsbsBsbSb", 24), 'P': ("bsBsBsbSb", 25), 'Q': ("bsbsbsBSB", 26), 'R': ("BsbsbsBSb", 27), 'S': ("bsBsbsBSb", 28), 'T': ("bsbsBsBSb", 29), 'U': ("BSbsbsbsB", 30), 'V': ("bSBsbsbsB", 31), 'W': ("BSBsbsbsb", 32), 'X': ("bSbsBsbsB", 33), 'Y': ("BSbsBsbsb", 34), 'Z': ("bSBsBsbsb", 35), '-': ("bSbsbsBsB", 36), '.': ("BSbsbsBsb", 37), ' ': ("bSBsbsBsb", 38), '*': ("bSbsBsBsb", None), '$': ("bSbSbSbsb", 39), '/': ("bSbSbsbSb", 40), '+': ("bSbsbSbSb", 41), '%': ("bsbSbSbSb", 42) } _stdchrs = string_digits + ascii_uppercase + "-. $/+%" _extended = { '\0': "%U", '\01': "$A", '\02': "$B", '\03': "$C", '\04': "$D", '\05': "$E", '\06': "$F", '\07': "$G", '\010': "$H", '\011': "$I", '\012': "$J", '\013': "$K", '\014': "$L", '\015': "$M", '\016': "$N", '\017': "$O", '\020': "$P", '\021': "$Q", '\022': "$R", '\023': "$S", '\024': "$T", '\025': "$U", '\026': "$V", '\027': "$W", '\030': "$X", '\031': "$Y", '\032': "$Z", '\033': "%A", '\034': "%B", '\035': "%C", '\036': "%D", '\037': "%E", '!': "/A", '"': "/B", '#': "/C", '$': "/D", '%': "/E", '&': "/F", '\'': "/G", '(': "/H", ')': "/I", '*': "/J", '+': "/K", ',': "/L", '/': "/O", ':': "/Z", ';': "%F", '<': "%G", '=': "%H", '>': "%I", '?': "%J", '@': "%V", '[': "%K", '\\': "%L", ']': "%M", '^': "%N", '_': "%O", '`': "%W", 'a': "+A", 'b': "+B", 'c': "+C", 'd': "+D", 'e': "+E", 'f': "+F", 'g': "+G", 'h': "+H", 'i': "+I", 'j': "+J", 'k': "+K", 'l': "+L", 'm': "+M", 'n': "+N", 'o': "+O", 'p': "+P", 'q': "+Q", 'r': "+R", 's': "+S", 't': "+T", 'u': "+U", 'v': "+V", 'w': "+W", 'x': "+X", 'y': "+Y", 'z': "+Z", '{': "%P", '|': "%Q", '}': "%R", '~': "%S", '\177': "%T" } _extchrs = _stdchrs + ascii_lowercase + \ "\000\001\002\003\004\005\006\007\010\011\012\013\014\015\016\017" + \ "\020\021\022\023\024\025\026\027\030\031\032\033\034\035\036\037" + \ "*!'#&\"(),:;<=>?@[\\]^_`{|}~\177" def _encode39(value, cksum, stop): v = sum([_patterns[c][1] for c in value]) % 43 if cksum: value += _stdchrs[v] if stop: value = '*'+value+'*' return value class _Code39Base(Barcode): barWidth = inch * 0.0075 lquiet = None rquiet = None quiet = 1 gap = None barHeight = None ratio = 2.2 checksum = 1 bearers = 0.0 stop = 1 def __init__(self, value = "", **args): value = asNative(value) for k, v in args.items(): setattr(self, k, v) if self.quiet: if self.lquiet is None: self.lquiet = max(inch * 0.25, self.barWidth * 10.0) self.rquiet = max(inch * 0.25, self.barWidth * 10.0) else: self.lquiet = self.rquiet = 0.0 Barcode.__init__(self, value) def decompose(self): dval = "" for c in self.encoded: dval = dval + _patterns[c][0] + 'i' self.decomposed = dval[:-1] return self.decomposed def _humanText(self): return self.stop and self.encoded[1:-1] or self.encoded class Standard39(_Code39Base): """ Options that may be passed to constructor: value (int, or numeric string required.): The value to encode. barWidth (float, default .0075): X-Dimension, or width of the smallest element Minumum is .0075 inch (7.5 mils). ratio (float, default 2.2): The ratio of wide elements to narrow elements. Must be between 2.0 and 3.0 (or 2.2 and 3.0 if the barWidth is greater than 20 mils (.02 inch)) gap (float or None, default None): width of intercharacter gap. None means "use barWidth". barHeight (float, see default below): Height of the symbol. Default is the height of the two bearer bars (if they exist) plus the greater of .25 inch or .15 times the symbol's length. checksum (bool, default 1): Wether to compute and include the check digit bearers (float, in units of barWidth. default 0): Height of bearer bars (horizontal bars along the top and bottom of the barcode). Default is 0 (no bearers). quiet (bool, default 1): Wether to include quiet zones in the symbol. lquiet (float, see default below): Quiet zone size to left of code, if quiet is true. Default is the greater of .25 inch, or .15 times the symbol's length. rquiet (float, defaults as above): Quiet zone size to right left of code, if quiet is true. stop (bool, default 1): Whether to include start/stop symbols. Sources of Information on Code 39: http://www.semiconductor.agilent.com/barcode/sg/Misc/code_39.html http://www.adams1.com/pub/russadam/39code.html http://www.barcodeman.com/c39_1.html Official Spec, "ANSI/AIM BC1-1995, USS" is available for US$45 from http://www.aimglobal.org/aimstore/ """ def validate(self): vval = [].append self.valid = 1 for c in self.value: if c in ascii_lowercase: c = c.upper() if c not in _stdchrs: self.valid = 0 continue vval(c) self.validated = ''.join(vval.__self__) return self.validated def encode(self): self.encoded = _encode39(self.validated, self.checksum, self.stop) return self.encoded class Extended39(_Code39Base): """ Extended Code 39 is a convention for encoding additional characters not present in stanmdard Code 39 by using pairs of characters to represent the characters missing in Standard Code 39. See Standard39 for arguments. Sources of Information on Extended Code 39: http://www.semiconductor.agilent.com/barcode/sg/Misc/xcode_39.html http://www.barcodeman.com/c39_ext.html """ def validate(self): vval = "" self.valid = 1 for c in self.value: if c not in _extchrs: self.valid = 0 continue vval = vval + c self.validated = vval return vval def encode(self): self.encoded = "" for c in self.validated: if c in _extended: self.encoded = self.encoded + _extended[c] elif c in _stdchrs: self.encoded = self.encoded + c else: raise ValueError self.encoded = _encode39(self.encoded, self.checksum,self.stop) return self.encoded ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1691062243.0 reportlab-4.1.0/src/reportlab/graphics/barcode/code93.py0000664000175000017500000002156514462707743022551 0ustar00rptlabrptlab# # Copyright (c) 2000 Tyler C. Sarna # 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. # 3. All advertising materials mentioning features or use of this software # must display the following acknowledgement: # This product includes software developed by Tyler C. Sarna. # 4. Neither the name of the author nor the names of contributors # may be used to endorse or promote products derived from this software # without specific prior written permission. # # 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. # from reportlab.lib.units import inch from reportlab.lib.utils import asNative from reportlab.graphics.barcode.common import MultiWidthBarcode _patterns = { '0' : ('AcAaAb', 0), '1' : ('AaAbAc', 1), '2' : ('AaAcAb', 2), '3' : ('AaAdAa', 3), '4' : ('AbAaAc', 4), '5' : ('AbAbAb', 5), '6' : ('AbAcAa', 6), '7' : ('AaAaAd', 7), '8' : ('AcAbAa', 8), '9' : ('AdAaAa', 9), 'A' : ('BaAaAc', 10), 'B' : ('BaAbAb', 11), 'C' : ('BaAcAa', 12), 'D' : ('BbAaAb', 13), 'E' : ('BbAbAa', 14), 'F' : ('BcAaAa', 15), 'G' : ('AaBaAc', 16), 'H' : ('AaBbAb', 17), 'I' : ('AaBcAa', 18), 'J' : ('AbBaAb', 19), 'K' : ('AcBaAa', 20), 'L' : ('AaAaBc', 21), 'M' : ('AaAbBb', 22), 'N' : ('AaAcBa', 23), 'O' : ('AbAaBb', 24), 'P' : ('AcAaBa', 25), 'Q' : ('BaBaAb', 26), 'R' : ('BaBbAa', 27), 'S' : ('BaAaBb', 28), 'T' : ('BaAbBa', 29), 'U' : ('BbAaBa', 30), 'V' : ('BbBaAa', 31), 'W' : ('AaBaBb', 32), 'X' : ('AaBbBa', 33), 'Y' : ('AbBaBa', 34), 'Z' : ('AbCaAa', 35), '-' : ('AbAaCa', 36), '.' : ('CaAaAb', 37), ' ' : ('CaAbAa', 38), '$' : ('CbAaAa', 39), '/' : ('AaBaCa', 40), '+' : ('AaCaBa', 41), '%' : ('BaAaCa', 42), '#' : ('AbAbBa', 43), '!' : ('CaBaAa', 44), '=' : ('CaAaBa', 45), '&' : ('AbBbAa', 46), 'start' : ('AaAaDa', -1), 'stop' : ('AaAaDaA', -2) } _charsbyval = {} for k, v in _patterns.items(): _charsbyval[v[1]] = k _extended = { '\x00' : '!U', '\x01' : '#A', '\x02' : '#B', '\x03' : '#C', '\x04' : '#D', '\x05' : '#E', '\x06' : '#F', '\x07' : '#G', '\x08' : '#H', '\x09' : '#I', '\x0a' : '#J', '\x0b' : '#K', '\x0c' : '#L', '\x0d' : '#M', '\x0e' : '#N', '\x0f' : '#O', '\x10' : '#P', '\x11' : '#Q', '\x12' : '#R', '\x13' : '#S', '\x14' : '#T', '\x15' : '#U', '\x16' : '#V', '\x17' : '#W', '\x18' : '#X', '\x19' : '#Y', '\x1a' : '#Z', '\x1b' : '!A', '\x1c' : '!B', '\x1d' : '!C', '\x1e' : '!D', '\x1f' : '!E', '!' : '=A', '"' : '=B', '#' : '=C', '$' : '=D', '%' : '=E', '&' : '=F', '\'' : '=G', '(' : '=H', ')' : '=I', '*' : '=J', '+' : '=K', ',' : '=L', '/' : '=O', ':' : '=Z', ';' : '!F', '<' : '!G', '=' : '!H', '>' : '!I', '?' : '!J', '@' : '!V', '[' : '!K', '\\' : '!L', ']' : '!M', '^' : '!N', '_' : '!O', '`' : '!W', 'a' : '&A', 'b' : '&B', 'c' : '&C', 'd' : '&D', 'e' : '&E', 'f' : '&F', 'g' : '&G', 'h' : '&H', 'i' : '&I', 'j' : '&J', 'k' : '&K', 'l' : '&L', 'm' : '&M', 'n' : '&N', 'o' : '&O', 'p' : '&P', 'q' : '&Q', 'r' : '&R', 's' : '&S', 't' : '&T', 'u' : '&U', 'v' : '&V', 'w' : '&W', 'x' : '&X', 'y' : '&Y', 'z' : '&Z', '{' : '!P', '|' : '!Q', '}' : '!R', '~' : '!S', '\x7f' : '!T' } def _encode93(str): s = list(str) s.reverse() # compute 'C' checksum i = 0; v = 1; c = 0 while i < len(s): c = c + v * _patterns[s[i]][1] i = i + 1; v = v + 1 if v > 20: v = 1 s.insert(0, _charsbyval[c % 47]) # compute 'K' checksum i = 0; v = 1; c = 0 while i < len(s): c = c + v * _patterns[s[i]][1] i = i + 1; v = v + 1 if v > 15: v = 1 s.insert(0, _charsbyval[c % 47]) s.reverse() return ''.join(s) class _Code93Base(MultiWidthBarcode): barWidth = inch * 0.0075 lquiet = None rquiet = None quiet = 1 barHeight = None stop = 1 def __init__(self, value='', **args): if type(value) is type(1): value = asNative(value) for (k, v) in args.items(): setattr(self, k, v) if self.quiet: if self.lquiet is None: self.lquiet = max(inch * 0.25, self.barWidth * 10.0) self.rquiet = max(inch * 0.25, self.barWidth * 10.0) else: self.lquiet = self.rquiet = 0.0 MultiWidthBarcode.__init__(self, value) def decompose(self): dval = self.stop and [_patterns['start'][0]] or [] dval += [_patterns[c][0] for c in self.encoded] if self.stop: dval.append(_patterns['stop'][0]) self.decomposed = ''.join(dval) return self.decomposed class Standard93(_Code93Base): """ Code 93 is a Uppercase alphanumeric symbology with some punctuation. See Extended Code 93 for a variant that can represent the entire 128 characrter ASCII set. Options that may be passed to constructor: value (int, or numeric string. required.): The value to encode. barWidth (float, default .0075): X-Dimension, or width of the smallest element Minumum is .0075 inch (7.5 mils). barHeight (float, see default below): Height of the symbol. Default is the height of the two bearer bars (if they exist) plus the greater of .25 inch or .15 times the symbol's length. quiet (bool, default 1): Wether to include quiet zones in the symbol. lquiet (float, see default below): Quiet zone size to left of code, if quiet is true. Default is the greater of .25 inch, or 10 barWidth rquiet (float, defaults as above): Quiet zone size to right left of code, if quiet is true. stop (bool, default 1): Whether to include start/stop symbols. Sources of Information on Code 93: http://www.semiconductor.agilent.com/barcode/sg/Misc/code_93.html Official Spec, "NSI/AIM BC5-1995, USS" is available for US$45 from http://www.aimglobal.org/aimstore/ """ def validate(self): vval = "" self.valid = 1 for c in self.value.upper(): if c not in _patterns: self.valid = 0 continue vval = vval + c self.validated = vval return vval def encode(self): self.encoded = _encode93(self.validated) return self.encoded class Extended93(_Code93Base): """ Extended Code 93 is a convention for encoding the entire 128 character set using pairs of characters to represent the characters missing in Standard Code 93. It is very much like Extended Code 39 in that way. See Standard93 for arguments. """ def validate(self): vval = [] self.valid = 1 a = vval.append for c in self.value: if c not in _patterns and c not in _extended: self.valid = 0 continue a(c) self.validated = ''.join(vval) return self.validated def encode(self): self.encoded = "" for c in self.validated: if c in _patterns: self.encoded = self.encoded + c elif c in _extended: self.encoded = self.encoded + _extended[c] else: raise ValueError self.encoded = _encode93(self.encoded) return self.encoded def _humanText(self): return self.validated+self.encoded[-2:] ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1707393347.0 reportlab-4.1.0/src/reportlab/graphics/barcode/common.py0000664000175000017500000005755114561140503022740 0ustar00rptlabrptlab# # Copyright (c) 1996-2000 Tyler C. Sarna # 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. # 3. All advertising materials mentioning features or use of this software # must display the following acknowledgement: # This product includes software developed by Tyler C. Sarna. # 4. Neither the name of the author nor the names of contributors # may be used to endorse or promote products derived from this software # without specific prior written permission. # # 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. # from reportlab.platypus.flowables import Flowable from reportlab.lib.units import inch from string import ascii_lowercase, ascii_uppercase, digits as string_digits class Barcode(Flowable): """Abstract Base for barcodes. Includes implementations of some methods suitable for the more primitive barcode types""" fontName = 'Courier' fontSize = 12 humanReadable = 0 def _humanText(self): return self.encoded def __init__(self, value='',**kwd): self.value = str(value) self._setKeywords(**kwd) if not hasattr(self, 'gap'): self.gap = None def _calculate(self): self.validate() self.encode() self.decompose() self.computeSize() def _setKeywords(self,**kwd): for (k, v) in kwd.items(): setattr(self, k, v) def validate(self): self.valid = 1 self.validated = self.value def encode(self): self.encoded = self.validated def decompose(self): self.decomposed = self.encoded def computeSize(self, *args): barWidth = self.barWidth wx = barWidth * self.ratio if self.gap == None: self.gap = barWidth w = 0.0 for c in self.decomposed: if c in 'sb': w = w + barWidth elif c in 'SB': w = w + wx else: # 'i' w = w + self.gap if self.barHeight is None: self.barHeight = w * 0.15 self.barHeight = max(0.25 * inch, self.barHeight) if self.bearers: self.barHeight = self.barHeight + self.bearers * 2.0 * barWidth if self.quiet: w += self.lquiet + self.rquiet self._height = self.barHeight self._width = w @property def width(self): self._calculate() return self._width @width.setter def width(self,v): pass @property def height(self): self._calculate() return self._height @height.setter def height(self,v): pass def draw(self): self._calculate() barWidth = self.barWidth wx = barWidth * self.ratio left = self.quiet and self.lquiet or 0 b = self.bearers * barWidth bb = b * 0.5 tb = self.barHeight - (b * 1.5) for c in self.decomposed: if c == 'i': left = left + self.gap elif c == 's': left = left + barWidth elif c == 'S': left = left + wx elif c == 'b': self.rect(left, bb, barWidth, tb) left = left + barWidth elif c == 'B': self.rect(left, bb, wx, tb) left = left + wx if self.bearers: if getattr(self,'bearerBox', None): canv = self.canv if hasattr(canv,'_Gadd'): #this is a widget rect takes other arguments canv.rect(bb, bb, self.width, self.barHeight-b, strokeWidth=b, strokeColor=self.barFillColor or self.barStrokeColor, fillColor=None) else: canv.saveState() canv.setLineWidth(b) canv.rect(bb, bb, self.width, self.barHeight-b, stroke=1, fill=0) canv.restoreState() else: w = self._width - (self.lquiet + self.rquiet) self.rect(self.lquiet, 0, w, b) self.rect(self.lquiet, self.barHeight - b, w, b) self.drawHumanReadable() def drawHumanReadable(self): if self.humanReadable: #we have text from reportlab.pdfbase.pdfmetrics import getAscent, stringWidth s = str(self._humanText()) fontSize = self.fontSize fontName = self.fontName w = stringWidth(s,fontName,fontSize) width = self._width if self.quiet: width -= self.lquiet+self.rquiet x = self.lquiet else: x = 0 if w>width: fontSize *= width/float(w) y = 1.07*getAscent(fontName)*fontSize/1000. self.annotate(x+width/2.,-y,s,fontName,fontSize) def rect(self, x, y, w, h): self.canv.rect(x, y, w, h, stroke=0, fill=1) def annotate(self,x,y,text,fontName,fontSize,anchor='middle'): canv = self.canv canv.saveState() canv.setFont(self.fontName,fontSize) if anchor=='middle': func = 'drawCentredString' elif anchor=='end': func = 'drawRightString' else: func = 'drawString' getattr(canv,func)(x,y,text) canv.restoreState() def _checkVal(self, name, v, allowed): if v not in allowed: raise ValueError('%s attribute %s is invalid %r\nnot in allowed %r' % ( self.__class__.__name__, name, v, allowed)) return v class MultiWidthBarcode(Barcode): """Base for variable-bar-width codes like Code93 and Code128""" def computeSize(self, *args): barWidth = self.barWidth oa, oA = ord('a') - 1, ord('A') - 1 w = 0.0 for c in self.decomposed: oc = ord(c) if c in ascii_lowercase: w = w + barWidth * (oc - oa) elif c in ascii_uppercase: w = w + barWidth * (oc - oA) if self.barHeight is None: self.barHeight = w * 0.15 self.barHeight = max(0.25 * inch, self.barHeight) if self.quiet: w += self.lquiet + self.rquiet self._height = self.barHeight self._width = w def draw(self): self._calculate() oa, oA = ord('a') - 1, ord('A') - 1 barWidth = self.barWidth left = self.quiet and self.lquiet or 0 for c in self.decomposed: oc = ord(c) if c in ascii_lowercase: left = left + (oc - oa) * barWidth elif c in ascii_uppercase: w = (oc - oA) * barWidth self.rect(left, 0, w, self.barHeight) left += w self.drawHumanReadable() class I2of5(Barcode): """ Interleaved 2 of 5 is a numeric-only barcode. It encodes an even number of digits; if an odd number is given, a 0 is prepended. Options that may be passed to constructor: value (int, or numeric string required.): The value to encode. barWidth (float, default .0075): X-Dimension, or width of the smallest element Minumum is .0075 inch (7.5 mils). ratio (float, default 2.2): The ratio of wide elements to narrow elements. Must be between 2.0 and 3.0 (or 2.2 and 3.0 if the barWidth is greater than 20 mils (.02 inch)) gap (float or None, default None): width of intercharacter gap. None means "use barWidth". barHeight (float, see default below): Height of the symbol. Default is the height of the two bearer bars (if they exist) plus the greater of .25 inch or .15 times the symbol's length. checksum (bool, default 1): Whether to compute and include the check digit bearers (float, in units of barWidth. default 3.0): Height of bearer bars (horizontal bars along the top and bottom of the barcode). Default is 3 x-dimensions. Set to zero for no bearer bars. (Bearer bars help detect misscans, so it is suggested to leave them on). bearerBox (bool default False) if true draw a true rectangle of width bearers around the barcode. quiet (bool, default 1): Whether to include quiet zones in the symbol. lquiet (float, see default below): Quiet zone size to left of code, if quiet is true. Default is the greater of .25 inch, or .15 times the symbol's length. rquiet (float, defaults as above): Quiet zone size to right left of code, if quiet is true. stop (bool, default 1): Whether to include start/stop symbols. Sources of Information on Interleaved 2 of 5: http://www.semiconductor.agilent.com/barcode/sg/Misc/i_25.html http://www.adams1.com/pub/russadam/i25code.html Official Spec, "ANSI/AIM BC2-1995, USS" is available for US$45 from http://www.aimglobal.org/aimstore/ """ patterns = { 'start' : 'bsbs', 'stop' : 'Bsb', 'B0' : 'bbBBb', 'S0' : 'ssSSs', 'B1' : 'BbbbB', 'S1' : 'SsssS', 'B2' : 'bBbbB', 'S2' : 'sSssS', 'B3' : 'BBbbb', 'S3' : 'SSsss', 'B4' : 'bbBbB', 'S4' : 'ssSsS', 'B5' : 'BbBbb', 'S5' : 'SsSss', 'B6' : 'bBBbb', 'S6' : 'sSSss', 'B7' : 'bbbBB', 'S7' : 'sssSS', 'B8' : 'BbbBb', 'S8' : 'SssSs', 'B9' : 'bBbBb', 'S9' : 'sSsSs' } barHeight = None barWidth = inch * 0.0075 ratio = 2.2 checksum = 1 bearers = 3.0 bearerBox = False quiet = 1 lquiet = None rquiet = None stop = 1 def __init__(self, value='', **args): if type(value) == type(1): value = str(value) for k, v in args.items(): setattr(self, k, v) if self.quiet: if self.lquiet is None: self.lquiet = min(inch * 0.25, self.barWidth * 10.0) self.rquiet = min(inch * 0.25, self.barWidth * 10.0) else: self.lquiet = self.rquiet = 0.0 Barcode.__init__(self, value) def validate(self): vval = "" self.valid = 1 for c in self.value.strip(): if c not in string_digits: self.valid = 0 continue vval = vval + c self.validated = vval return vval def encode(self): s = self.validated cs = self.checksum c = len(s) #ensure len(result)%2 == 0, checksum included if ((c % 2 == 0) and cs) or ((c % 2 == 1) and not cs): s = '0' + s c += 1 if cs: c = 3*sum([int(s[i]) for i in range(0,c,2)])+sum([int(s[i]) for i in range(1,c,2)]) s += str((10 - c) % 10) self.encoded = s def decompose(self): dval = self.stop and [self.patterns['start']] or [] a = dval.append for i in range(0, len(self.encoded), 2): b = self.patterns['B' + self.encoded[i]] s = self.patterns['S' + self.encoded[i+1]] for i in range(0, len(b)): a(b[i] + s[i]) if self.stop: a(self.patterns['stop']) self.decomposed = ''.join(dval) return self.decomposed class MSI(Barcode): """ MSI is a numeric-only barcode. Options that may be passed to constructor: value (int, or numeric string required.): The value to encode. barWidth (float, default .0075): X-Dimension, or width of the smallest element ratio (float, default 2.2): The ratio of wide elements to narrow elements. gap (float or None, default None): width of intercharacter gap. None means "use barWidth". barHeight (float, see default below): Height of the symbol. Default is the height of the two bearer bars (if they exist) plus the greater of .25 inch or .15 times the symbol's length. checksum (bool, default 1): Wether to compute and include the check digit bearers (float, in units of barWidth. default 0): Height of bearer bars (horizontal bars along the top and bottom of the barcode). Default is 0 (no bearers). lquiet (float, see default below): Quiet zone size to left of code, if quiet is true. Default is the greater of .25 inch, or 10 barWidths. rquiet (float, defaults as above): Quiet zone size to right left of code, if quiet is true. stop (bool, default 1): Whether to include start/stop symbols. Sources of Information on MSI Bar Code: http://www.semiconductor.agilent.com/barcode/sg/Misc/msi_code.html http://www.adams1.com/pub/russadam/plessy.html """ patterns = { 'start' : 'Bs', 'stop' : 'bSb', '0' : 'bSbSbSbS', '1' : 'bSbSbSBs', '2' : 'bSbSBsbS', '3' : 'bSbSBsBs', '4' : 'bSBsbSbS', '5' : 'bSBsbSBs', '6' : 'bSBsBsbS', '7' : 'bSBsBsBs', '8' : 'BsbSbSbS', '9' : 'BsbSbSBs' } stop = 1 barHeight = None barWidth = inch * 0.0075 ratio = 2.2 checksum = 1 bearers = 0.0 quiet = 1 lquiet = None rquiet = None def __init__(self, value="", **args): if type(value) == type(1): value = str(value) for k, v in args.items(): setattr(self, k, v) if self.quiet: if self.lquiet is None: self.lquiet = max(inch * 0.25, self.barWidth * 10.0) self.rquiet = max(inch * 0.25, self.barWidth * 10.0) else: self.lquiet = self.rquiet = 0.0 Barcode.__init__(self, value) def validate(self): vval = "" self.valid = 1 for c in self.value.strip(): if c not in string_digits: self.valid = 0 continue vval = vval + c self.validated = vval return vval def encode(self): s = self.validated if self.checksum: c = '' for i in range(1, len(s), 2): c = c + s[i] d = str(int(c) * 2) t = 0 for c in d: t = t + int(c) for i in range(0, len(s), 2): t = t + int(s[i]) c = 10 - (t % 10) s = s + str(c) self.encoded = s def decompose(self): dval = self.stop and [self.patterns['start']] or [] dval += [self.patterns[c] for c in self.encoded] if self.stop: dval.append(self.patterns['stop']) self.decomposed = ''.join(dval) return self.decomposed class Codabar(Barcode): """ Codabar is a numeric plus some puntuation ("-$:/.+") barcode with four start/stop characters (A, B, C, and D). Options that may be passed to constructor: value (string required.): The value to encode. barWidth (float, default .0065): X-Dimension, or width of the smallest element minimum is 6.5 mils (.0065 inch) ratio (float, default 2.0): The ratio of wide elements to narrow elements. gap (float or None, default None): width of intercharacter gap. None means "use barWidth". barHeight (float, see default below): Height of the symbol. Default is the height of the two bearer bars (if they exist) plus the greater of .25 inch or .15 times the symbol's length. checksum (bool, default 0): Whether to compute and include the check digit bearers (float, in units of barWidth. default 0): Height of bearer bars (horizontal bars along the top and bottom of the barcode). Default is 0 (no bearers). quiet (bool, default 1): Whether to include quiet zones in the symbol. stop (bool, default 1): Whether to include start/stop symbols. lquiet (float, see default below): Quiet zone size to left of code, if quiet is true. Default is the greater of .25 inch, or 10 barWidth rquiet (float, defaults as above): Quiet zone size to right left of code, if quiet is true. Sources of Information on Codabar http://www.semiconductor.agilent.com/barcode/sg/Misc/codabar.html http://www.barcodeman.com/codabar.html Official Spec, "ANSI/AIM BC3-1995, USS" is available for US$45 from http://www.aimglobal.org/aimstore/ """ patterns = { '0': 'bsbsbSB', '1': 'bsbsBSb', '2': 'bsbSbsB', '3': 'BSbsbsb', '4': 'bsBsbSb', '5': 'BsbsbSb', '6': 'bSbsbsB', '7': 'bSbsBsb', '8': 'bSBsbsb', '9': 'BsbSbsb', '-': 'bsbSBsb', '$': 'bsBSbsb', ':': 'BsbsBsB', '/': 'BsBsbsB', '.': 'BsBsBsb', '+': 'bsBsBsB', 'A': 'bsBSbSb', 'B': 'bSbSbsB', 'C': 'bsbSbSB', 'D': 'bsbSBSb' } values = { '0' : 0, '1' : 1, '2' : 2, '3' : 3, '4' : 4, '5' : 5, '6' : 6, '7' : 7, '8' : 8, '9' : 9, '-' : 10, '$' : 11, ':' : 12, '/' : 13, '.' : 14, '+' : 15, 'A' : 16, 'B' : 17, 'C' : 18, 'D' : 19 } chars = string_digits + "-$:/.+" stop = 1 barHeight = None barWidth = inch * 0.0065 ratio = 2.0 # XXX ? checksum = 0 bearers = 0.0 quiet = 1 lquiet = None rquiet = None def __init__(self, value='', **args): if type(value) == type(1): value = str(value) for k, v in args.items(): setattr(self, k, v) if self.quiet: if self.lquiet is None: self.lquiet = min(inch * 0.25, self.barWidth * 10.0) self.rquiet = min(inch * 0.25, self.barWidth * 10.0) else: self.lquiet = self.rquiet = 0.0 Barcode.__init__(self, value) def validate(self): vval = "" self.valid = 1 s = self.value.strip() for i in range(0, len(s)): c = s[i] if c not in self.chars: if ((i != 0) and (i != len(s) - 1)) or (c not in 'ABCD'): self.Valid = 0 continue vval = vval + c if self.stop: if vval[0] not in 'ABCD': vval = 'A' + vval if vval[-1] not in 'ABCD': vval = vval + vval[0] self.validated = vval return vval def encode(self): s = self.validated if self.checksum: v = sum([self.values[c] for c in s]) s += self.chars[v % 16] self.encoded = s def decompose(self): dval = ''.join([self.patterns[c]+'i' for c in self.encoded]) self.decomposed = dval[:-1] return self.decomposed class Code11(Barcode): """ Code 11 is an almost-numeric barcode. It encodes the digits 0-9 plus dash ("-"). 11 characters total, hence the name. value (int or string required.): The value to encode. barWidth (float, default .0075): X-Dimension, or width of the smallest element ratio (float, default 2.2): The ratio of wide elements to narrow elements. gap (float or None, default None): width of intercharacter gap. None means "use barWidth". barHeight (float, see default below): Height of the symbol. Default is the height of the two bearer bars (if they exist) plus the greater of .25 inch or .15 times the symbol's length. checksum (0 none, 1 1-digit, 2 2-digit, -1 auto, default -1): How many checksum digits to include. -1 ("auto") means 1 if the number of digits is 10 or less, else 2. bearers (float, in units of barWidth. default 0): Height of bearer bars (horizontal bars along the top and bottom of the barcode). Default is 0 (no bearers). quiet (bool, default 1): Wether to include quiet zones in the symbol. lquiet (float, see default below): Quiet zone size to left of code, if quiet is true. Default is the greater of .25 inch, or 10 barWidth rquiet (float, defaults as above): Quiet zone size to right left of code, if quiet is true. Sources of Information on Code 11: http://www.cwi.nl/people/dik/english/codes/barcodes.html """ chars = '0123456789-' patterns = { '0' : 'bsbsB', '1' : 'BsbsB', '2' : 'bSbsB', '3' : 'BSbsb', '4' : 'bsBsB', '5' : 'BsBsb', '6' : 'bSBsb', '7' : 'bsbSB', '8' : 'BsbSb', '9' : 'Bsbsb', '-' : 'bsBsb', 'S' : 'bsBSb' # Start/Stop } values = { '0' : 0, '1' : 1, '2' : 2, '3' : 3, '4' : 4, '5' : 5, '6' : 6, '7' : 7, '8' : 8, '9' : 9, '-' : 10, } stop = 1 barHeight = None barWidth = inch * 0.0075 ratio = 2.2 # XXX ? checksum = -1 # Auto bearers = 0.0 quiet = 1 lquiet = None rquiet = None def __init__(self, value='', **args): if type(value) == type(1): value = str(value) for k, v in args.items(): setattr(self, k, v) if self.quiet: if self.lquiet is None: self.lquiet = min(inch * 0.25, self.barWidth * 10.0) self.rquiet = min(inch * 0.25, self.barWidth * 10.0) else: self.lquiet = self.rquiet = 0.0 Barcode.__init__(self, value) def validate(self): vval = "" self.valid = 1 s = self.value.strip() for i in range(0, len(s)): c = s[i] if c not in self.chars: self.Valid = 0 continue vval = vval + c self.validated = vval return vval def _addCSD(self,s,m): # compute first checksum i = c = 0 v = 1 V = self.values while i < len(s): c += v * V[s[-(i+1)]] i += 1 v += 1 if v==m: v = 1 return s+self.chars[c % 11] def encode(self): s = self.validated tcs = self.checksum if tcs<0: self.checksum = tcs = 1+int(len(s)>10) if tcs > 0: s = self._addCSD(s,11) if tcs > 1: s = self._addCSD(s,10) self.encoded = self.stop and ('S' + s + 'S') or s def decompose(self): self.decomposed = ''.join([(self.patterns[c]+'i') for c in self.encoded])[:-1] return self.decomposed def _humanText(self): return self.stop and self.encoded[1:-1] or self.encoded ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1691062243.0 reportlab-4.1.0/src/reportlab/graphics/barcode/dmtx.py0000664000175000017500000001730014462707743022427 0ustar00rptlabrptlabtry: from pylibdmtx import pylibdmtx except ImportError: pylibdmtx = None __all__ = () else: __all__=('DataMatrix',) from reportlab.graphics.barcode.common import Barcode from reportlab.lib.utils import asBytes from reportlab.platypus.paraparser import _num as paraparser_num from reportlab.graphics.widgetbase import Widget from reportlab.lib.validators import isColor, isString, isColorOrNone, isNumber, isBoxAnchor from reportlab.lib.attrmap import AttrMap, AttrMapValue from reportlab.lib.colors import toColor from reportlab.graphics.shapes import Group, Rect def _numConv(x): return x if isinstance(x,(int,float)) else paraparser_num(x) class _DMTXCheck: @classmethod def pylibdmtx_check(cls): if not pylibdmtx: raise ValueError('The %s class requires package pylibdmtx' % cls.__name__) class DataMatrix(Barcode,_DMTXCheck): def __init__(self, value='', **kwds): self.pylibdmtx_check() self._recalc = True self.value = value self.cellSize = kwds.pop('cellSize','5x5') self.size = kwds.pop('size','SquareAuto') self.encoding = kwds.pop('encoding','Ascii') self.anchor = kwds.pop('anchor','sw') self.color = kwds.pop('color',(0,0,0)) self.bgColor = kwds.pop('bgColor',None) self.x = kwds.pop('x',0) self.y = kwds.pop('y',0) self.border = kwds.pop('border',5) @property def value(self): return self._value @value.setter def value(self,v): self._value = asBytes(v) self._recalc = True @property def size(self): return self._size @size.setter def size(self,v): self._size = self._checkVal('size', v, pylibdmtx.ENCODING_SIZE_NAMES) self._recalc = True @property def border(self): return self._border @border.setter def border(self,v): self._border = _numConv(v) self._recalc = True @property def x(self): return self._x @x.setter def x(self,v): self._x = _numConv(v) self._recalc = True @property def y(self): return self._y @y.setter def y(self,v): self._y = _numConv(v) self._recalc = True @property def cellSize(self): return self._cellSize @size.setter def cellSize(self,v): self._cellSize = v self._recalc = True @property def encoding(self): return self._encoding @encoding.setter def encoding(self,v): self._encoding = self._checkVal('encoding', v, pylibdmtx.ENCODING_SCHEME_NAMES) self._recalc = True @property def anchor(self): return self._anchor @anchor.setter def anchor(self,v): self._anchor = self._checkVal('anchor', v, ('n','ne','e','se','s','sw','w','nw','c')) self._recalc = True def recalc(self): if not self._recalc: return data = self._value size = self._size encoding = self._encoding e = pylibdmtx.encode(data, size=size, scheme=encoding) iW = e.width iH = e.height p = e.pixels iCellSize = 5 bpp = 3 #bytes per pixel rowLen = iW*bpp cellLen = iCellSize*bpp assert len(p)//rowLen == iH matrix = list(filter(None, (''.join( (('x' if p[j:j+bpp] != b'\xff\xff\xff' else ' ') for j in range(i,i+rowLen,cellLen))).strip() for i in range(0,iH*rowLen,rowLen*iCellSize)))) self._nRows = len(matrix) self._nCols = len(matrix[-1]) self._matrix = '\n'.join(matrix) cellWidth = self._cellSize if cellWidth: cellWidth = cellWidth.split('x') if len(cellWidth)>2: raise ValueError('cellSize needs to be distance x distance not %r' % self._cellSize) elif len(cellWidth)==2: cellWidth, cellHeight = cellWidth else: cellWidth = cellHeight = cellWidth[0] cellWidth = _numConv(cellWidth) cellHeight = _numConv(cellHeight) else: cellWidth = cellHeight = iCellSize self._cellWidth = cellWidth self._cellHeight = cellHeight self._recalc = False self._bord = max(self.border,cellWidth,cellHeight) self._width = cellWidth*self._nCols + 2*self._bord self._height = cellHeight*self._nRows + 2*self._bord @property def matrix(self): self.recalc() return self._matrix @property def width(self): self.recalc() return self._width @property def height(self): self.recalc() return self._height @property def cellWidth(self): self.recalc() return self._cellWidth @property def cellHeight(self): self.recalc() return self._cellHeight def draw(self): self.recalc() canv = self.canv w = self.width h = self.height x = self.x y = self.y b = self._bord anchor = self.anchor if anchor in ('nw','n','ne'): y -= h elif anchor in ('c','e','w'): y -= h//2 if anchor in ('ne','e','se'): x -= w elif anchor in ('n','c','s'): x -= w//2 canv.saveState() if self.bgColor: canv.setFillColor(toColor(self.bgColor)) canv.rect(x, y-h, w, h, fill=1, stroke=0) canv.setFillColor(toColor(self.color)) canv.setStrokeColor(None) cellWidth = self.cellWidth cellHeight = self.cellHeight yr = y - b - cellHeight x += b for row in self.matrix.split('\n'): xr = x for c in row: if c=='x': canv.rect(xr, yr, cellWidth, cellHeight, fill=1, stroke=0) xr += cellWidth yr -= cellHeight canv.restoreState() class DataMatrixWidget(Widget,_DMTXCheck): codeName = "DataMatrix" _attrMap = AttrMap( BASE = Widget, value = AttrMapValue(isString, desc='Datamatrix data'), x = AttrMapValue(isNumber, desc='x-coord'), y = AttrMapValue(isNumber, desc='y-coord'), color = AttrMapValue(isColor, desc='foreground color'), bgColor = AttrMapValue(isColorOrNone, desc='background color'), encoding = AttrMapValue(isString, desc='encoding'), size = AttrMapValue(isString, desc='size'), cellSize = AttrMapValue(isString, desc='cellSize'), anchor = AttrMapValue(isBoxAnchor, desc='anchor pooint for x,y'), ) _defaults = dict( x = ('0',_numConv), y = ('0',_numConv), color = ('black',toColor), bgColor = (None,lambda _: toColor(_) if _ is not None else _), encoding = ('Ascii',None), size = ('SquareAuto',None), cellSize = ('5x5',None), anchor = ('sw', None), ) def __init__(self,value='Hello Cruel World!', **kwds): self.pylibdmtx_check() self.value = value for k,(d,c) in self._defaults.items(): v = kwds.pop(k,d) if c: v = c(v) setattr(self,k,v) def rect(self, x, y, w, h, fill=1, stroke=0): self._gadd(Rect(x,y,w,h,strokeColor=None,fillColor=self._fillColor)) def saveState(self,*args,**kwds): pass restoreState = setStrokeColor = saveState def setFillColor(self,c): self._fillColor = c def draw(self): m = DataMatrix(value=self.value,**{k: getattr(self,k) for k in self._defaults}) m.canv = self m.y += m.height g = Group() self._gadd = g.add m.draw() return g ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1691062243.0 reportlab-4.1.0/src/reportlab/graphics/barcode/eanbc.py0000664000175000017500000004475214462707743022536 0ustar00rptlabrptlab__all__=( 'Ean13BarcodeWidget','isEanString', 'Ean8BarcodeWidget', 'UPCA', 'Ean5BarcodeWidget', 'ISBNBarcodeWidget', ) from reportlab.graphics.shapes import Group, String, Rect from reportlab.lib import colors from reportlab.pdfbase.pdfmetrics import stringWidth from reportlab.lib.validators import isNumber, isColor, isString, Validator, isBoolean, NoneOr from reportlab.lib.attrmap import * from reportlab.graphics.charts.areas import PlotArea from reportlab.lib.units import mm from reportlab.lib.utils import asNative #work out a list of manufacturer codes.... _eanNumberSystems = [ ('00-13', 'USA & Canada'), ('20-29', 'In-Store Functions'), ('30-37', 'France'), ('40-44', 'Germany'), ('45', 'Japan (also 49)'), ('46', 'Russian Federation'), ('471', 'Taiwan'), ('474', 'Estonia'), ('475', 'Latvia'), ('477', 'Lithuania'), ('479', 'Sri Lanka'), ('480', 'Philippines'), ('482', 'Ukraine'), ('484', 'Moldova'), ('485', 'Armenia'), ('486', 'Georgia'), ('487', 'Kazakhstan'), ('489', 'Hong Kong'), ('49', 'Japan (JAN-13)'), ('50', 'United Kingdom'), ('520', 'Greece'), ('528', 'Lebanon'), ('529', 'Cyprus'), ('531', 'Macedonia'), ('535', 'Malta'), ('539', 'Ireland'), ('54', 'Belgium & Luxembourg'), ('560', 'Portugal'), ('569', 'Iceland'), ('57', 'Denmark'), ('590', 'Poland'), ('594', 'Romania'), ('599', 'Hungary'), ('600-601', 'South Africa'), ('609', 'Mauritius'), ('611', 'Morocco'), ('613', 'Algeria'), ('619', 'Tunisia'), ('622', 'Egypt'), ('625', 'Jordan'), ('626', 'Iran'), ('64', 'Finland'), ('690-692', 'China'), ('70', 'Norway'), ('729', 'Israel'), ('73', 'Sweden'), ('740', 'Guatemala'), ('741', 'El Salvador'), ('742', 'Honduras'), ('743', 'Nicaragua'), ('744', 'Costa Rica'), ('746', 'Dominican Republic'), ('750', 'Mexico'), ('759', 'Venezuela'), ('76', 'Switzerland'), ('770', 'Colombia'), ('773', 'Uruguay'), ('775', 'Peru'), ('777', 'Bolivia'), ('779', 'Argentina'), ('780', 'Chile'), ('784', 'Paraguay'), ('785', 'Peru'), ('786', 'Ecuador'), ('789', 'Brazil'), ('80-83', 'Italy'), ('84', 'Spain'), ('850', 'Cuba'), ('858', 'Slovakia'), ('859', 'Czech Republic'), ('860', 'Yugloslavia'), ('869', 'Turkey'), ('87', 'Netherlands'), ('880', 'South Korea'), ('885', 'Thailand'), ('888', 'Singapore'), ('890', 'India'), ('893', 'Vietnam'), ('899', 'Indonesia'), ('90-91', 'Austria'), ('93', 'Australia'), ('94', 'New Zealand'), ('955', 'Malaysia'), ('977', 'International Standard Serial Number for Periodicals (ISSN)'), ('978', 'International Standard Book Numbering (ISBN)'), ('979', 'International Standard Music Number (ISMN)'), ('980', 'Refund receipts'), ('981-982', 'Common Currency Coupons'), ('99', 'Coupons') ] manufacturerCodes = {} for (k, v) in _eanNumberSystems: words = k.split('-') if len(words)==2: fromCode = int(words[0]) toCode = int(words[1]) for code in range(fromCode, toCode+1): manufacturerCodes[code] = v else: manufacturerCodes[int(k)] = v def nDigits(n): class _ndigits(Validator): def test(self,x): return type(x) is str and len(x)<=n and len([c for c in x if c in "0123456789"])==n return _ndigits() class Ean13BarcodeWidget(PlotArea): codeName = "EAN13" _attrMap = AttrMap(BASE=PlotArea, value = AttrMapValue(nDigits(12), desc='the number'), fontName = AttrMapValue(isString, desc='fontName'), fontSize = AttrMapValue(isNumber, desc='font size'), x = AttrMapValue(isNumber, desc='x-coord'), y = AttrMapValue(isNumber, desc='y-coord'), barFillColor = AttrMapValue(isColor, desc='bar color'), barHeight = AttrMapValue(isNumber, desc='Height of bars.'), barWidth = AttrMapValue(isNumber, desc='Width of bars.'), barStrokeWidth = AttrMapValue(isNumber, desc='Width of bar borders.'), barStrokeColor = AttrMapValue(isColor, desc='Color of bar borders.'), textColor = AttrMapValue(isColor, desc='human readable text color'), humanReadable = AttrMapValue(isBoolean, desc='if human readable'), quiet = AttrMapValue(isBoolean, desc='if quiet zone to be used'), lquiet = AttrMapValue(isBoolean, desc='left quiet zone length'), rquiet = AttrMapValue(isBoolean, desc='right quiet zone length'), ) _digits=12 _start_right = 7 #for ean-13 left = [0:7] right=[7:13] _nbars = 113 barHeight = 25.93*mm #millimeters barWidth = (37.29/_nbars)*mm humanReadable = 1 _0csw = 1 _1csw = 3 #Left Hand Digits. _left = ( ("0001101", "0011001", "0010011", "0111101", "0100011", "0110001", "0101111", "0111011", "0110111", "0001011", ), #odd left hand digits ("0100111", "0110011", "0011011", "0100001", "0011101", "0111001", "0000101", "0010001", "0001001", "0010111"), #even left hand digits ) _right = ("1110010", "1100110", "1101100", "1000010", "1011100", "1001110", "1010000", "1000100", "1001000", "1110100") quiet = 1 rquiet = lquiet = None _tail = "101" _sep = "01010" _lhconvert={ "0": (0,0,0,0,0,0), "1": (0,0,1,0,1,1), "2": (0,0,1,1,0,1), "3": (0,0,1,1,1,0), "4": (0,1,0,0,1,1), "5": (0,1,1,0,0,1), "6": (0,1,1,1,0,0), "7": (0,1,0,1,0,1), "8": (0,1,0,1,1,0), "9": (0,1,1,0,1,0) } fontSize = 8 #millimeters fontName = 'Helvetica' textColor = barFillColor = colors.black barStrokeColor = None barStrokeWidth = 0 x = 0 y = 0 def __init__(self,value='123456789012',**kw): value = str(value) if isinstance(value,int) else asNative(value) self.value=max(self._digits-len(value),0)*'0'+value[:self._digits] for k, v in kw.items(): setattr(self, k, v) width = property(lambda self: self.barWidth*(self._nbars-18+self._calc_quiet(self.lquiet)+self._calc_quiet(self.rquiet))) def wrap(self,aW,aH): return self.width,self.barHeight def _encode_left(self,s,a): cp = self._lhconvert[s[0]] #convert the left hand numbers _left = self._left z = ord('0') for i,c in enumerate(s[1:self._start_right]): a(_left[cp[i]][ord(c)-z]) def _short_bar(self,i): i += 9 - self._lquiet return self.humanReadable and ((120: v += 1 else: v = 0 return v def draw(self): g = Group() gAdd = g.add barWidth = self.barWidth width = self.width barHeight = self.barHeight x = self.x y = self.y gAdd(Rect(x,y,width,barHeight,fillColor=None,strokeColor=None,strokeWidth=0)) s = self.value+self._checkdigit(self.value) self._lquiet = lquiet = self._calc_quiet(self.lquiet) rquiet = self._calc_quiet(self.rquiet) b = [lquiet*'0',self._tail] #the signal string a = b.append self._encode_left(s,a) a(self._sep) z = ord('0') _right = self._right for c in s[self._start_right:]: a(_right[ord(c)-z]) a(self._tail) a(rquiet*'0') fontSize = self.fontSize barFillColor = self.barFillColor barStrokeWidth = self.barStrokeWidth barStrokeColor = self.barStrokeColor fth = fontSize*1.2 b = ''.join(b) lrect = None for i,c in enumerate(b): if c=="1": dh = self._short_bar(i) and fth or 0 yh = y+dh if lrect and lrect.y==yh: lrect.width += barWidth else: lrect = Rect(x,yh,barWidth,barHeight-dh,fillColor=barFillColor,strokeWidth=barStrokeWidth,strokeColor=barStrokeColor) gAdd(lrect) else: lrect = None x += barWidth if self.humanReadable: self._add_human_readable(s,gAdd) return g def _add_human_readable(self,s,gAdd): barWidth = self.barWidth fontSize = self.fontSize textColor = self.textColor fontName = self.fontName fth = fontSize*1.2 # draw the num below the line. c = s[0] w = stringWidth(c,fontName,fontSize) x = self.x+barWidth*(self._lquiet-8) y = self.y + 0.2*fth gAdd(String(x,y,c,fontName=fontName,fontSize=fontSize,fillColor=textColor)) x = self.x + (33-9+self._lquiet)*barWidth c = s[1:7] gAdd(String(x,y,c,fontName=fontName,fontSize=fontSize,fillColor=textColor,textAnchor='middle')) x += 47*barWidth c = s[7:] gAdd(String(x,y,c,fontName=fontName,fontSize=fontSize,fillColor=textColor,textAnchor='middle')) def _checkdigit(cls,num): z = ord('0') iSum = cls._0csw*sum([(ord(x)-z) for x in num[::2]]) \ + cls._1csw*sum([(ord(x)-z) for x in num[1::2]]) return chr(z+((10-(iSum%10))%10)) _checkdigit=classmethod(_checkdigit) class Ean8BarcodeWidget(Ean13BarcodeWidget): codeName = "EAN8" _attrMap = AttrMap(BASE=Ean13BarcodeWidget, value = AttrMapValue(nDigits(7), desc='the number'), ) _start_right = 4 #for ean-13 left = [0:7] right=[7:13] _nbars = 85 _digits=7 _0csw = 3 _1csw = 1 def _encode_left(self,s,a): cp = self._lhconvert[s[0]] #convert the left hand numbers _left = self._left[0] z = ord('0') for i,c in enumerate(s[0:self._start_right]): a(_left[ord(c)-z]) def _short_bar(self,i): i += 9 - self._lquiet return self.humanReadable and ((12 255: self.valid = 0 break else: self.validated = self.value def _encode_c40_char(self, char): o = ord(char) encoded = [] if o == 32 or (o >= 48 and o <= 57) or (o >= 65 and o <= 90): # Stay in set 0 if o == 32: encoded.append(o - 29) elif o >= 48 and o <= 57: encoded.append(o - 44) else: encoded.append(o - 51) elif o >= 0 and o <= 31: encoded.append(0) # Shift to set 1 encoded.append(o) elif (o >= 33 and o <= 64) or (o >= 91 and o <= 95): encoded.append(1) # Shift to set 2 if o >= 33 and o <= 64: encoded.append(o - 33) else: encoded.append(o - 69) elif o >= 96 and o <= 127: encoded.append(2) # Shift to set 3 encoded.append(o - 96) elif o >= 128 and o <= 255: # Extended ASCII encoded.append(1) # Shift to set 2 encoded.append(30) # Upper shift / hibit encoded += self._encode_c40_char(chr(o - 128)) else: raise Exception('Cannot encode %s (%s)' % (char, o)) return encoded def _encode_c40(self, value): encoded = [] for c in value: encoded += self._encode_c40_char(c) while len(encoded) % 3: encoded.append(0) # Fake padding that makes chunking in the next step easier codewords = [] codewords.append(230) # Switch to C40 encoding for i in range(0, len(encoded), 3): chunk = encoded[i:i+3] total = chunk[0] * 1600 + chunk[1] * 40 + chunk[2] + 1 codewords.append(total // 256) codewords.append(total % 256) codewords.append(254) # End of data if len(codewords) > self.cw_data: raise Exception('Too much data to fit into a data matrix of this size') if len(codewords) < self.cw_data: # Real padding codewords.append(129) # Start padding while len(codewords) < self.cw_data: r = ((149 * (len(codewords) + 1)) % 253) + 1 codewords.append((129 + r) % 254) return codewords def _gfsum(self, int1, int2): return int1 ^ int2 def _gfproduct(self, int1, int2): if int1 == 0 or int2 == 0: return 0 else: return ALOGVAL[(LOGVAL[int1] + LOGVAL[int2]) % 255] def _get_reed_solomon_code(self, data, num_code_words): """ This method is basically verbatim from "huBarcode" which is BSD licensed https://github.com/hudora/huBarcode/blob/master/hubarcode/datamatrix/reedsolomon.py """ cw_factors = FACTORS[num_code_words] code_words = [0] * num_code_words for data_word in data: tmp = self._gfsum(data_word, code_words[-1]) for j in range(num_code_words - 1, -1, -1): code_words[j] = self._gfproduct(tmp, cw_factors[j]) if j > 0: code_words[j] = self._gfsum(code_words[j - 1], code_words[j]) code_words.reverse() return code_words def _get_next_bits(self, data): value = data.pop(0) bits = [] for i in range(0, 8): bits.append(value >> i & 1) bits.reverse() return bits def _place_bit(self, row, col, bit): if row < 0: row += self.row_usable_modules col += (4 - ((self.row_usable_modules + 4) % 8)) if col < 0: col += self.col_usable_modules row += (4 - ((self.col_usable_modules + 4) % 8)) self._matrix[row][col] = bit def _place_bit_corner_1(self, data): bits = self._get_next_bits(data) self._place_bit(self.row_usable_modules - 1, 0, bits[0]) self._place_bit(self.row_usable_modules - 1, 1, bits[1]) self._place_bit(self.row_usable_modules - 1, 2, bits[2]) self._place_bit(0, self.col_usable_modules - 2, bits[3]) self._place_bit(0, self.col_usable_modules - 1, bits[4]) self._place_bit(1, self.col_usable_modules - 1, bits[5]) self._place_bit(2, self.col_usable_modules - 1, bits[6]) self._place_bit(3, self.col_usable_modules - 1, bits[7]) def _place_bit_corner_2(self, data): bits = self._get_next_bits(data) self._place_bit(self.row_usable_modules - 3, 0, bits[0]) self._place_bit(self.row_usable_modules - 2, 0, bits[1]) self._place_bit(self.row_usable_modules - 1, 0, bits[2]) self._place_bit(0, self.col_usable_modules - 4, bits[3]) self._place_bit(0, self.col_usable_modules - 3, bits[4]) self._place_bit(0, self.col_usable_modules - 2, bits[5]) self._place_bit(0, self.col_usable_modules - 1, bits[6]) self._place_bit(1, self.col_usable_modules - 1, bits[7]) def _place_bit_corner_3(self, data): bits = self._get_next_bits(data) self._place_bit(self.row_usable_modules - 3, 0, bits[0]) self._place_bit(self.row_usable_modules - 2, 0, bits[1]) self._place_bit(self.row_usable_modules - 1, 0, bits[2]) self._place_bit(0, self.col_usable_modules - 2, bits[3]) self._place_bit(0, self.col_usable_modules - 1, bits[4]) self._place_bit(1, self.col_usable_modules - 1, bits[5]) self._place_bit(2, self.col_usable_modules - 1, bits[6]) self._place_bit(3, self.col_usable_modules - 1, bits[7]) def _place_bit_corner_4(self, data): bits = self._get_next_bits(data) self._place_bit(self.row_usable_modules - 1, 0, bits[0]) self._place_bit(self.row_usable_modules - 1, self.col_usable_modules - 1, bits[1]) self._place_bit(0, self.col_usable_modules - 3, bits[2]) self._place_bit(0, self.col_usable_modules - 2, bits[3]) self._place_bit(0, self.col_usable_modules - 1, bits[4]) self._place_bit(1, self.col_usable_modules - 3, bits[5]) self._place_bit(1, self.col_usable_modules - 2, bits[6]) self._place_bit(1, self.col_usable_modules - 1, bits[7]) def _place_bit_standard(self, data, row, col): bits = self._get_next_bits(data) self._place_bit(row - 2, col - 2, bits[0]) self._place_bit(row - 2, col - 1, bits[1]) self._place_bit(row - 1, col - 2, bits[2]) self._place_bit(row - 1, col - 1, bits[3]) self._place_bit(row - 1, col, bits[4]) self._place_bit(row, col - 2, bits[5]) self._place_bit(row, col - 1, bits[6]) self._place_bit(row, col, bits[7]) def _create_matrix(self, data): """ This method is heavily influenced by "huBarcode" which is BSD licensed https://github.com/hudora/huBarcode/blob/master/hubarcode/datamatrix/placement.py """ rows = self.row_usable_modules cols = self.col_usable_modules self._matrix = self._create_empty_matrix(rows, cols) row = 4 col = 0 while True: if row == rows and col == 0: self._place_bit_corner_1(data) elif row == (rows - 2) and col == 0 and (cols % 4): self._place_bit_corner_2(data) elif row == (rows - 2) and col == 0 and (cols % 8 == 4): self._place_bit_corner_3(data) elif row == (rows + 4) and col == 2 and (cols % 8 == 0): self._place_bit_corner_4(data) while True: if row < rows and col >= 0 and self._matrix[row][col] is None: self._place_bit_standard(data, row, col) row -= 2 col += 2 if row < 0 or col >= cols: break row += 1 col += 3 while True: if row >= 0 and col < cols and self._matrix[row][col] is None: self._place_bit_standard(data, row, col) row += 2 col -= 2 if row >= rows or col < 0: break row += 3 col += 1 if row >= rows and col >= cols: break for row in self._matrix: for i in range(0, cols): if row[i] is None: row[i] = 0 return self._matrix def _create_data_regions(self, matrix): regions = [] col_offset = 0 row_offset = 0 rows = int(self.row_usable_modules / self.row_regions) cols = int(self.col_usable_modules / self.col_regions) while col_offset < self.row_regions: while row_offset < self.col_regions: r_offset = col_offset * rows c_offset = row_offset * cols region = matrix[r_offset:rows+r_offset] for i in range(0, len(region)): region[i] = region[i][c_offset:cols+c_offset] regions.append(region) row_offset += 1 row_offset = 0 col_offset += 1 return regions def _create_empty_matrix(self, row, col): matrix = [] for i in range(0, row): matrix.append([None] * col) return matrix def _wrap_data_regions_with_finders(self, regions): wrapped = [] for region in regions: matrix = self._create_empty_matrix( int(self.col_modules / self.col_regions), int(self.row_modules / self.row_regions) ) for i, rows in enumerate(region): for j, data in enumerate(rows): matrix[i+1][j+1] = data for i, row in enumerate(matrix): if i == 0: for j, col in enumerate(row): row[j] = (j + 1) % 2 elif i + 1 == len(matrix): for j, col in enumerate(row): row[j] = 1 else: row[0] = 1 row[-1] = i % 2 wrapped.append(matrix) return wrapped def _merge_data_regions(self, regions): merged = [] for i in range(0, len(regions), self.row_regions): chunk = regions[i:i+self.row_regions] j = 0 while j < len(chunk[0]): merged_row = [] for row in chunk: merged_row += row[j] merged.append(merged_row) j += 1 return merged def encode(self): if hasattr(self, 'encoded'): return self.encoded encoded = self._encode_c40(self.validated) encoded += self._get_reed_solomon_code(encoded, self.cw_ecc) matrix = self._create_matrix(encoded) data_regions = self._create_data_regions(matrix) wrapped = self._wrap_data_regions_with_finders(data_regions) self.encoded = self._merge_data_regions(wrapped) self.encoded.reverse() # Helpful since PDFs start at bottom left corner return self.encoded def computeSize(self, *args): self._height = self.row_modules * self.barWidth self._width = self.col_modules * self.barWidth def draw(self): for y, row in enumerate(self.encoded): for x, data in enumerate(row): if data: self.rect( self.x + x * self.barWidth, self.y + y * self.barWidth, self.barWidth, self.barWidth ) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1691062243.0 reportlab-4.1.0/src/reportlab/graphics/barcode/fourstate.py0000664000175000017500000000724214462707743023473 0ustar00rptlabrptlab# # Copyright (c) 2000 Tyler C. Sarna # 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. # 3. All advertising materials mentioning features or use of this software # must display the following acknowledgement: # This product includes software developed by Tyler C. Sarna. # 4. Neither the name of the author nor the names of contributors # may be used to endorse or promote products derived from this software # without specific prior written permission. # # 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. # # . 3 T Tracker # , 2 D Descender # ' 1 A Ascender # | 0 H Ascender/Descender _rm_patterns = { "0" : "--||", "1" : "-',|", "2" : "-'|,", "3" : "'-,|", "4" : "'-|,", "5" : "'',,", "6" : "-,'|", "7" : "-|-|", "8" : "-|',", "9" : "',-|", "A" : "',',", "B" : "'|-,", "C" : "-,|'", "D" : "-|,'", "E" : "-||-", "F" : "',,'", "G" : "',|-", "H" : "'|,-", "I" : ",-'|", "J" : ",'-|", "K" : ",'',", "L" : "|--|", "M" : "|-',", "N" : "|'-,", "O" : ",-|'", "P" : ",','", "Q" : ",'|-", "R" : "|-,'", "S" : "|-|-", "T" : "|',-", "U" : ",,''", "V" : ",|-'", "W" : ",|'-", "X" : "|,-'", "Y" : "|,'-", "Z" : "||--", # start, stop "(" : "'-,'", ")" : "'|,|" } _ozN_patterns = { "0" : "||", "1" : "|'", "2" : "|,", "3" : "'|", "4" : "''", "5" : "',", "6" : ",|", "7" : ",'", "8" : ",,", "9" : ".|" } _ozC_patterns = { "A" : "|||", "B" : "||'", "C" : "||,", "D" : "|'|", "E" : "|''", "F" : "|',", "G" : "|,|", "H" : "|,'", "I" : "|,,", "J" : "'||", "K" : "'|'", "L" : "'|,", "M" : "''|", "N" : "'''", "O" : "'',", "P" : "',|", "Q" : "','", "R" : "',,", "S" : ",||", "T" : ",|'", "U" : ",|,", "V" : ",'|", "W" : ",''", "X" : ",',", "Y" : ",,|", "Z" : ",,'", "a" : "|,.", "b" : "|.|", "c" : "|.'", "d" : "|.,", "e" : "|..", "f" : "'|.", "g" : "''.", "h" : "',.", "i" : "'.|", "j" : "'.'", "k" : "'.,", "l" : "'..", "m" : ",|.", "n" : ",'.", "o" : ",,.", "p" : ",.|", "q" : ",.'", "r" : ",.,", "s" : ",..", "t" : ".|.", "u" : ".'.", "v" : ".,.", "w" : "..|", "x" : "..'", "y" : "..,", "z" : "...", "0" : ",,,", "1" : ".||", "2" : ".|'", "3" : ".|,", "4" : ".'|", "5" : ".''", "6" : ".',", "7" : ".,|", "8" : ".,'", "9" : ".,,", " " : "||.", "#" : "|'.", } #http://www.auspost.com.au/futurepost/ ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1691062243.0 reportlab-4.1.0/src/reportlab/graphics/barcode/lto.py0000664000175000017500000001632114462707743022253 0ustar00rptlabrptlab# (c) 2008 Jerome Alet - # Licensing terms : ReportLab's license. from reportlab.graphics.barcode.code39 import Standard39 from reportlab.lib import colors from reportlab.lib.units import cm from string import ascii_uppercase, digits as string_digits class BaseLTOLabel(Standard39) : """ Base class for LTO labels. Specification taken from "IBM LTO Ultrium Cartridge Label Specification, Revision 3" available on May 14th 2008 from : http://www-1.ibm.com/support/docview.wss?rs=543&context=STCVQ6R&q1=ssg1*&uid=ssg1S7000429&loc=en_US&cs=utf-8&lang=en+en """ LABELWIDTH = 7.9 * cm LABELHEIGHT = 1.7 * cm LABELROUND = 0.15 * cm CODERATIO = 2.75 CODENOMINALWIDTH = 7.4088 * cm CODEBARHEIGHT = 1.11 * cm CODEBARWIDTH = 0.0432 * cm CODEGAP = CODEBARWIDTH CODELQUIET = 10 * CODEBARWIDTH CODERQUIET = 10 * CODEBARWIDTH def __init__(self, prefix="", number=None, subtype="1", border=None, checksum=False, availheight=None) : """ Initializes an LTO label. prefix : Up to six characters from [A-Z][0-9]. Defaults to "". number : Label's number or None. Defaults to None. subtype : LTO subtype string , e.g. "1" for LTO1. Defaults to "1". border : None, or the width of the label's border. Defaults to None. checksum : Boolean indicates if checksum char has to be printed. Defaults to False. availheight : Available height on the label, or None for automatic. Defaults to None. """ self.height = max(availheight, self.CODEBARHEIGHT) self.border = border if (len(subtype) != 1) \ or (subtype not in ascii_uppercase + string_digits) : raise ValueError("Invalid subtype '%s'" % subtype) if ((not number) and (len(prefix) > 6)) \ or not prefix.isalnum() : raise ValueError("Invalid prefix '%s'" % prefix) label = "%sL%s" % ((prefix + str(number or 0).zfill(6 - len(prefix)))[:6], subtype) if len(label) != 8 : raise ValueError("Invalid set of parameters (%s, %s, %s)" \ % (prefix, number, subtype)) self.label = label Standard39.__init__(self, label, ratio=self.CODERATIO, barHeight=self.height, barWidth=self.CODEBARWIDTH, gap=self.CODEGAP, lquiet=self.CODELQUIET, rquiet=self.CODERQUIET, quiet=True, checksum=checksum) def drawOn(self, canvas, x, y) : """Draws the LTO label onto the canvas.""" canvas.saveState() canvas.translate(x, y) if self.border : canvas.setLineWidth(self.border) canvas.roundRect(0, 0, self.LABELWIDTH, self.LABELHEIGHT, self.LABELROUND) Standard39.drawOn(self, canvas, (self.LABELWIDTH-self.CODENOMINALWIDTH)/2.0, self.LABELHEIGHT-self.height) canvas.restoreState() class VerticalLTOLabel(BaseLTOLabel) : """ A class for LTO labels with rectangular blocks around the tape identifier. """ LABELFONT = ("Helvetica-Bold", 14) BLOCKWIDTH = 1*cm BLOCKHEIGHT = 0.45*cm LINEWIDTH = 0.0125 NBBLOCKS = 7 COLORSCHEME = ("red", "yellow", "lightgreen", "lightblue", "grey", "orangered", "pink", "darkgreen", "orange", "purple") def __init__(self, *args, **kwargs) : """ Initializes the label. colored : boolean to determine if blocks have to be colorized. """ if "colored" in kwargs: self.colored = kwargs["colored"] del kwargs["colored"] else : self.colored = False kwargs["availheight"] = self.LABELHEIGHT-self.BLOCKHEIGHT BaseLTOLabel.__init__(self, *args, **kwargs) def drawOn(self, canvas, x, y) : """Draws some blocks around the identifier's characters.""" BaseLTOLabel.drawOn(self, canvas, x, y) canvas.saveState() canvas.setLineWidth(self.LINEWIDTH) canvas.setStrokeColorRGB(0, 0, 0) canvas.translate(x, y) xblocks = (self.LABELWIDTH-(self.NBBLOCKS*self.BLOCKWIDTH))/2.0 for i in range(self.NBBLOCKS) : (font, size) = self.LABELFONT newfont = self.LABELFONT if i == (self.NBBLOCKS - 1) : part = self.label[i:] (font, size) = newfont size /= 2.0 newfont = (font, size) else : part = self.label[i] canvas.saveState() canvas.translate(xblocks+(i*self.BLOCKWIDTH), 0) if self.colored and part.isdigit() : canvas.setFillColorRGB(*getattr(colors, self.COLORSCHEME[int(part)], colors.Color(1, 1, 1)).rgb()) else: canvas.setFillColorRGB(1, 1, 1) canvas.rect(0, 0, self.BLOCKWIDTH, self.BLOCKHEIGHT, fill=True) canvas.translate((self.BLOCKWIDTH+canvas.stringWidth(part, *newfont))/2.0, (self.BLOCKHEIGHT/2.0)) canvas.rotate(90.0) canvas.setFont(*newfont) canvas.setFillColorRGB(0, 0, 0) canvas.drawCentredString(0, 0, part) canvas.restoreState() canvas.restoreState() def test() : """Test this.""" from reportlab.pdfgen.canvas import Canvas from reportlab.lib import pagesizes canvas = Canvas("labels.pdf", pagesize=pagesizes.A4) canvas.setFont("Helvetica", 30) (width, height) = pagesizes.A4 canvas.drawCentredString(width/2.0, height-4*cm, "Sample LTO labels") xpos = xorig = 2 * cm ypos = yorig = 2 * cm colwidth = 10 * cm lineheight = 3.9 * cm count = 1234 BaseLTOLabel("RL", count, "3").drawOn(canvas, xpos, ypos) ypos += lineheight count += 1 BaseLTOLabel("RL", count, "3", border=0.0125).drawOn(canvas, xpos, ypos) ypos += lineheight count += 1 VerticalLTOLabel("RL", count, "3").drawOn(canvas, xpos, ypos) ypos += lineheight count += 1 VerticalLTOLabel("RL", count, "3", border=0.0125).drawOn(canvas, xpos, ypos) ypos += lineheight count += 1 VerticalLTOLabel("RL", count, "3", colored=True).drawOn(canvas, xpos, ypos) ypos += lineheight count += 1 VerticalLTOLabel("RL", count, "3", border=0.0125, colored=True).drawOn(canvas, xpos, ypos) canvas.showPage() canvas.save() if __name__ == "__main__" : test() ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1691062243.0 reportlab-4.1.0/src/reportlab/graphics/barcode/qr.py0000664000175000017500000001417214462707743022101 0ustar00rptlabrptlab# # ReportLab QRCode widget # # Ported from the Javascript library QRCode for Javascript by Sam Curren # # URL: http://www.d-project.com/ # http://d-project.googlecode.com/svn/trunk/misc/qrcode/js/qrcode.js # qrcode.js is copyright (c) 2009 Kazuhiko Arase # # Original ReportLab module by German M. Bravo # # modified and improved by Anders Hammarquist # and used with permission under the ReportLab License # # The word "QR Code" is registered trademark of # DENSO WAVE INCORPORATED # http://www.denso-wave.com/qrcode/faqpatent-e.html __all__ = ('QrCodeWidget') import itertools from reportlab.platypus.flowables import Flowable from reportlab.graphics.shapes import Group, Rect from reportlab.lib import colors from reportlab.lib.validators import isNumber, isNumberOrNone, isColor, Validator from reportlab.lib.attrmap import AttrMap, AttrMapValue from reportlab.graphics.widgetbase import Widget from reportlab.lib.units import mm from reportlab.lib.utils import asUnicodeEx, isUnicode from reportlab.graphics.barcode import qrencoder class isLevel(Validator): def test(self, x): return x in ['L', 'M', 'Q', 'H'] isLevel = isLevel() class isUnicodeOrQRList(Validator): def _test(self, x): if isUnicode(x): return True if all(isinstance(v, qrencoder.QR) for v in x): return True return False def test(self, x): return self._test(x) or self.normalizeTest(x) def normalize(self, x): if self._test(x): return x try: return asUnicodeEx(x) except UnicodeError: raise ValueError("Can't convert to unicode: %r" % x) isUnicodeOrQRList = isUnicodeOrQRList() class SRect(Rect): def __init__(self, x, y, width, height, fillColor=colors.black): Rect.__init__(self, x, y, width, height, fillColor=fillColor, strokeColor=None, strokeWidth=0) class QrCodeWidget(Widget): codeName = "QR" _attrMap = AttrMap( BASE = Widget, value = AttrMapValue(isUnicodeOrQRList, desc='QRCode data'), x = AttrMapValue(isNumber, desc='x-coord'), y = AttrMapValue(isNumber, desc='y-coord'), barFillColor = AttrMapValue(isColor, desc='bar color'), barWidth = AttrMapValue(isNumber, desc='Width of bars.'), # maybe should be named just width? barHeight = AttrMapValue(isNumber, desc='Height of bars.'), # maybe should be named just height? barBorder = AttrMapValue(isNumber, desc='Width of QR border.'), # maybe should be named qrBorder? barLevel = AttrMapValue(isLevel, desc='QR Code level.'), # maybe should be named qrLevel qrVersion = AttrMapValue(isNumberOrNone, desc='QR Code version. None for auto'), # Below are ignored, they make no sense barStrokeWidth = AttrMapValue(isNumber, desc='Width of bar borders.'), barStrokeColor = AttrMapValue(isColor, desc='Color of bar borders.'), ) x = 0 y = 0 barFillColor = colors.black barStrokeColor = None barStrokeWidth = 0 barHeight = 32*mm barWidth = 32*mm barBorder = 4 barLevel = 'L' qrVersion = None value = None def __init__(self, value='Hello World', **kw): self.value = isUnicodeOrQRList.normalize(value) for k, v in kw.items(): setattr(self, k, v) ec_level = getattr(qrencoder.QRErrorCorrectLevel, self.barLevel) self.__dict__['qr'] = qrencoder.QRCode(self.qrVersion, ec_level) if isUnicode(self.value): self.addData(self.value) elif self.value: for v in self.value: self.addData(v) def addData(self, value): self.qr.addData(value) def draw(self): self.qr.make() g = Group() color = self.barFillColor border = self.barBorder width = self.barWidth height = self.barHeight x = self.x y = self.y g.add(SRect(x, y, width, height, fillColor=None)) moduleCount = self.qr.getModuleCount() minwh = float(min(width, height)) boxsize = minwh / (moduleCount + border * 2.0) offsetX = x + (width - minwh) / 2.0 offsetY = y + (minwh - height) / 2.0 for r, row in enumerate(self.qr.modules): row = map(bool, row) c = 0 for t, tt in itertools.groupby(row): isDark = t count = len(list(tt)) if isDark: x = (c + border) * boxsize y = (r + border + 1) * boxsize s = SRect(offsetX + x, offsetY + height - y, count * boxsize, boxsize, fillColor=color) g.add(s) c += count return g # Flowable version class QrCode(Flowable): height = 32*mm width = 32*mm qrBorder = 4 qrLevel = 'L' qrVersion = None value = None def __init__(self, value=None, **kw): self.value = isUnicodeOrQRList.normalize(value) for k, v in kw.items(): setattr(self, k, v) ec_level = getattr(qrencoder.QRErrorCorrectLevel, self.qrLevel) self.qr = qrencoder.QRCode(self.qrVersion, ec_level) if isUnicode(self.value): self.addData(self.value) elif self.value: for v in self.value: self.addData(v) def addData(self, value): self.qr.addData(value) def draw(self): self.qr.make() moduleCount = self.qr.getModuleCount() border = self.qrBorder xsize = self.width / (moduleCount + border * 2.0) ysize = self.height / (moduleCount + border * 2.0) for r, row in enumerate(self.qr.modules): row = map(bool, row) c = 0 for t, tt in itertools.groupby(row): isDark = t count = len(list(tt)) if isDark: x = (c + border) * xsize y = self.height - (r + border + 1) * ysize self.rect(x, y, count * xsize, ysize * 1.05) c += count def rect(self, x, y, w, h): self.canv.rect(x, y, w, h, stroke=0, fill=1) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1691062243.0 reportlab-4.1.0/src/reportlab/graphics/barcode/qrencoder.py0000664000175000017500000010250514462707743023437 0ustar00rptlabrptlab# QRCode for Python # # Support for Kanji, Hanzi, ECI, FNC1 and Structurded append, # and optimizations by Anders Hammarquist # # Copyright (c) 2014 Open End AB http://www.openend.se/ # # Ported from the Javascript library by Sam Curren # # QRCode for Javascript # http://d-project.googlecode.com/svn/trunk/misc/qrcode/js/qrcode.js # # Copyright (c) 2009 Kazuhiko Arase # # URL: http://www.d-project.com/ # # Licensed under the MIT license: # http://www.opensource.org/licenses/mit-license.php # # The word "QR Code" is registered trademark of # DENSO WAVE INCORPORATED # http://www.denso-wave.com/qrcode/faqpatent-e.html import re import itertools try: from itertools import zip_longest except: from itertools import izip_longest as zip_longest try: unicode except NameError: # No unicode in Python 3 unicode = str class QR: valid = None bits = None group = 0 def __init__(self, data): if self.valid and not self.valid(data): raise ValueError self.data = data def __len__(self): return len(self.data) @property def bitlength(self): if self.bits is None: return 0 q, r = divmod(len(self), len(self.bits)) return q * sum(self.bits) + sum(self.bits[:r]) def getLengthBits(self, ver): if 0 < ver < 10: return self.lengthbits[0] elif ver < 27: return self.lengthbits[1] elif ver < 41: return self.lengthbits[2] raise ValueError("Unknown version: " + ver) def getLength(self): return len(self.data) def __repr__(self): return repr(self.data) def write_header(self, buffer, version): buffer.put(self.mode, 4) lenbits = self.getLengthBits(version) if lenbits: buffer.put(len(self.data), lenbits ) def write(self, buffer, version): self.write_header(buffer, version) for g in zip_longest(*[iter(self.data)] * self.group): bits = 0 n = 0 for i in range(self.group): if g[i] is not None: n *= len(self.chars) n += self.chars.index(g[i]) bits += self.bits[i] buffer.put(n, bits) class QRNumber(QR): valid = re.compile(u'[0-9]*$').match chars = u'0123456789' bits = (4,3,3) group = 3 mode = 0x1 lengthbits = (10, 12, 14) class QRAlphaNum(QR): valid = re.compile(u'[-0-9A-Z $%*+./:]*$').match chars = u'0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ $%*+-./:' bits = (6,5) group = 2 mode = 0x2 lengthbits = (9, 11, 13) class QR8bitByte(QR): bits = (8,) group = 1 mode = 0x4 lengthbits = (8, 16, 16) def __init__(self, data): if isinstance(data, unicode): self.data = data.encode('utf-8') # XXX This really needs an ECI too else: self.data = data # It'd better be byte data def write(self, buffer, version): self.write_header(buffer, version) for c in self.data: if isinstance(c, str): c = ord(c) buffer.put(c, 8) class QRKanji(QR): bits = (13,) group = 1 mode = 0x8 lengthbits = (8, 10, 12) def __init__(self, data): try: self.data = self.unicode_to_qrkanji(data) except UnicodeEncodeError: raise ValueError('Not valid kanji') def unicode_to_qrkanji(self, data): codes = [] for i,c in enumerate(data): try: c = c.encode('shift-jis') try: c,d = map(ord, c) except TypeError: # Python 3 c,d = c except UnicodeEncodeError as e: raise UnicodeEncodeError('qrkanji', data, i, i+1, e.args[4]) except ValueError: raise UnicodeEncodeError('qrkanji', data, i, i+1, 'illegal multibyte sequence') c = c << 8 | d if 0x8140 <= c <=0x9ffc: c -= 0x8140 c = (((c & 0xff00) >> 8) * 0xc0) + (c & 0xff) elif 0xe040 <= c <= 0xebbf: c -= 0xc140 c = (((c & 0xff00) >> 8) * 0xc0) + (c & 0xff) else: raise UnicodeEncodeError('qrkanji', data, i, i+1, 'illegal multibyte sequence') codes.append(c) return codes def write(self, buffer, version): self.write_header(buffer, version) for d in self.data: buffer.put(d, 13) class QRHanzi(QR): bits = (13,) group = 1 mode = 0xD lengthbits = (8, 10, 12) def __init__(self, data): try: self.data = self.unicode_to_qrhanzi(data) except UnicodeEncodeError: raise ValueError('Not valid hanzi') def unicode_to_qrhanzi(self, data): codes = [] for i,c in enumerate(data): try: c = c.encode('gb2312') try: c,d = map(ord, c) except TypeError: # Python 3 c,d = c except UnicodeEncodeError as e: raise UnicodeEncodeError('qrhanzi', data, i, i+1, e.args[4]) except ValueError: raise UnicodeEncodeError('qrhanzi', data, i, i+1, 'illegal multibyte sequence') c = c << 8 | d if 0xa1a1 <= c <=0xaafe: c -= 0xa1a1 c = (((c & 0xff00) >> 8) * 0x60) + (c & 0xff) elif 0xb0a1 <= c <= 0xfafe: c -= 0xa6a1 c = (((c & 0xff00) >> 8) * 0x60) + (c & 0xff) else: raise UnicodeEncodeError('qrhanzi', data, i, i+1, 'illegal multibyte sequence') codes.append(c) return codes def write_header(self, buffer, version): buffer.put(self.mode, 4) buffer.put(1, 4) # Subset 1: GB2312 encoding lenbits = self.getLengthBits(version) if lenbits: buffer.put(len(self.data), lenbits ) def write(self, buffer, version): self.write_header(buffer, version) for d in self.data: buffer.put(d, 13) # Special modes class QRECI(QR): mode = 0x7 lengthbits = (0, 0, 0) def __init__(self, data): if not 0 < data < 999999: # Spec says 999999, format supports up to 0x1fffff = 2097151 raise ValueError("ECI out of range") self.data = data def write(self, buffer, version): self.write_header(buffer, version) if self.data <= 0x7f: buffer.put(self.data, 8) elif self.data <= 0x3fff: buffer.put(self.data | 0x8000, 16) elif self.data <= 0x1fffff: buffer.put(self.data | 0xC00000, 24) class QRStructAppend(QR): mode = 0x3 lengthbits = (0, 0, 0) def __init__(self, part, total, parity): if not 0 < part <= 16: raise ValueError("part out of range [1,16]") if not 0 < total <= 16: raise ValueError("total out of range [1,16]") self.part = part self.total = total self.parity = parity def write(self, buffer, version): self.write_header(buffer, version) buffer.put(self.part, 4) buffer.put(self.total, 4) buffer.put(self.parity, 8) class QRFNC1First(QR): mode = 0x5 lengthbits = (0, 0, 0) def __init__(self): pass def write(self, buffer, version): self.write_header(buffer, version) class QRFNC1Second(QR): valid = re.compile('^([A-Za-z]|[0-9][0-9])$').match mode = 0x9 lengthbits = (0, 0, 0) def write(self, buffer, version): self.write_header(buffer, version) d = self.data if len(d) == 1: d = ord(d) + 100 else: d = int(d) buffer.put(d, 8) class QRCode: def __init__(self, version, errorCorrectLevel): self.version = version self.errorCorrectLevel = errorCorrectLevel self.modules = None self.moduleCount = 0 self.dataCache = None self.dataList = [] def addData(self, data): if isinstance(data, QR): newData = data else: for conv in (QRNumber, QRAlphaNum, QRKanji, QR8bitByte): try: newData = conv(data) break except ValueError: pass else: raise ValueError self.dataList.append(newData) self.dataCache = None def isDark(self, row, col): return self.modules[row][col] def getModuleCount(self): return self.moduleCount def calculate_version(self): # Calculate version for data to fit the QR Code capacity for version in range(1, 40): rsBlocks = QRRSBlock.getRSBlocks(version, self.errorCorrectLevel) totalDataCount = sum(block.dataCount for block in rsBlocks) length = 0 for data in self.dataList: length += 4 length += data.getLengthBits(version) length += data.bitlength if length <= totalDataCount * 8: break return version def make(self): if self.version is None: self.version = self.calculate_version() self.makeImpl(False, self.getBestMaskPattern()) def makeImpl(self, test, maskPattern): self.moduleCount = self.version * 4 + 17 self.modules = [ [False] * self.moduleCount for x in range(self.moduleCount) ] self.setupPositionProbePattern(0, 0) self.setupPositionProbePattern(self.moduleCount - 7, 0) self.setupPositionProbePattern(0, self.moduleCount - 7) self.setupPositionAdjustPattern() self.setupTimingPattern() self.setupTypeInfo(test, maskPattern) if (self.version >= 7): self.setupTypeNumber(test) if (self.dataCache == None): self.dataCache = QRCode.createData(self.version, self.errorCorrectLevel, self.dataList) self.mapData(self.dataCache, maskPattern) _positionProbePattern = [ [True, True, True, True, True, True, True], [True, False, False, False, False, False, True], [True, False, True, True, True, False, True], [True, False, True, True, True, False, True], [True, False, True, True, True, False, True], [True, False, False, False, False, False, True], [True, True, True, True, True, True, True], ] def setupPositionProbePattern(self, row, col): if row == 0: self.modules[row+7][col:col+7] = [False] * 7 if col == 0: self.modules[row+7][col+7] = False else: self.modules[row+7][col-1] = False else: # col == 0 self.modules[row-1][col:col+8] = [False] * 8 for r, data in enumerate(self._positionProbePattern): self.modules[row+r][col:col+7] = data if col == 0: self.modules[row+r][col+7] = False else: self.modules[row+r][col-1] = False def getBestMaskPattern(self): minLostPoint = 0 pattern = 0 for i in range(8): self.makeImpl(True, i); lostPoint = QRUtil.getLostPoint(self); if (i == 0 or minLostPoint > lostPoint): minLostPoint = lostPoint pattern = i return pattern def setupTimingPattern(self): for r in range(8, self.moduleCount - 8): self.modules[r][6] = (r % 2 == 0) self.modules[6][8:self.moduleCount - 8] = itertools.islice( itertools.cycle([True, False]), self.moduleCount - 16) _positionAdjustPattern = [ [True, True, True, True, True], [True, False, False, False, True], [True, False, True, False, True], [True, False, False, False, True], [True, True, True, True, True], ] def setupPositionAdjustPattern(self): pos = QRUtil.getPatternPosition(self.version) maxpos = self.moduleCount - 8 for row, col in itertools.product(pos, pos): if col <= 8 and (row <= 8 or row >= maxpos): continue elif col >= maxpos and row <= 8: continue for r, data in enumerate(self._positionAdjustPattern): self.modules[row + r - 2][col-2:col+3] = data def setupTypeNumber(self, test): bits = QRUtil.getBCHTypeNumber(self.version) for i in range(18): mod = (not test and ( (bits >> i) & 1) == 1) self.modules[i // 3][i % 3 + self.moduleCount - 8 - 3] = mod; for i in range(18): mod = (not test and ( (bits >> i) & 1) == 1) self.modules[i % 3 + self.moduleCount - 8 - 3][i // 3] = mod; def setupTypeInfo(self, test, maskPattern): data = (self.errorCorrectLevel << 3) | maskPattern bits = QRUtil.getBCHTypeInfo(data) # vertical for i in range(15): mod = (not test and ( (bits >> i) & 1) == 1) if (i < 6): self.modules[i][8] = mod elif (i < 8): self.modules[i + 1][8] = mod else: self.modules[self.moduleCount - 15 + i][8] = mod # horizontal for i in range(15): mod = (not test and ( (bits >> i) & 1) == 1); if (i < 8): self.modules[8][self.moduleCount - i - 1] = mod elif (i < 9): self.modules[8][15 - i - 1 + 1] = mod else: self.modules[8][15 - i - 1] = mod # fixed module self.modules[self.moduleCount - 8][8] = (not test) def _dataPosIterator(self): cols = itertools.chain(range(self.moduleCount - 1, 6, -2), range(5, 0, -2)) rows = (list(range(9, self.moduleCount - 8)), list(itertools.chain(range(6), range(7, self.moduleCount))), list(range(9, self.moduleCount))) rrows = tuple( list(reversed(r)) for r in rows) ppos = QRUtil.getPatternPosition(self.version) ppos = set(itertools.chain.from_iterable( (p-2, p-1, p, p+1, p+2) for p in ppos)) maxpos = self.moduleCount - 11 for col in cols: rows, rrows = rrows, rows if col <= 8: rowidx = 0 elif col >= self.moduleCount - 8: rowidx = 2 else: rowidx = 1 for row in rows[rowidx]: for c in range(2): c = col - c if self.version >= 7: if row < 6 and c >= self.moduleCount - 11: continue elif col < 6 and row >= self.moduleCount - 11: continue if row in ppos and c in ppos: if not (row < 11 and (c < 11 or c > maxpos) or c < 11 and (row < 11 or row > maxpos)): continue yield (c, row) _dataPosList = None def dataPosIterator(self): if not self._dataPosList: self._dataPosList = list(self._dataPosIterator()) return self._dataPosList def _dataBitIterator(self, data): for byte in data: for bit in [0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01]: yield bool(byte & bit) _dataBitList = None def dataBitIterator(self, data): if not self._dataBitList: self._dataBitList = list(self._dataBitIterator(data)) return iter(self._dataBitList) def mapData(self, data, maskPattern): bits = self.dataBitIterator(data) mask = QRUtil.getMask(maskPattern) for (col, row), dark in zip_longest(self.dataPosIterator(), bits, fillvalue=False): self.modules[row][col] = dark ^ mask(row, col) PAD0 = 0xEC PAD1 = 0x11 @staticmethod def createData(version, errorCorrectLevel, dataList): rsBlocks = QRRSBlock.getRSBlocks(version, errorCorrectLevel) buffer = QRBitBuffer(); for data in dataList: data.write(buffer, version) # calc num max data. totalDataCount = 0; for block in rsBlocks: totalDataCount += block.dataCount if (buffer.getLengthInBits() > totalDataCount * 8): raise Exception("code length overflow. (%d > %d)" % (buffer.getLengthInBits(), totalDataCount * 8)) # end code if (buffer.getLengthInBits() + 4 <= totalDataCount * 8): buffer.put(0, 4) # padding while (buffer.getLengthInBits() % 8 != 0): buffer.putBit(False) # padding while (True): if (buffer.getLengthInBits() >= totalDataCount * 8): break buffer.put(QRCode.PAD0, 8) if (buffer.getLengthInBits() >= totalDataCount * 8): break buffer.put(QRCode.PAD1, 8) return QRCode.createBytes(buffer, rsBlocks) @staticmethod def createBytes(buffer, rsBlocks): offset = 0 maxDcCount = 0 maxEcCount = 0 totalCodeCount = 0 dcdata = [] ecdata = [] for block in rsBlocks: totalCodeCount += block.totalCount dcCount = block.dataCount ecCount = block.totalCount - dcCount maxDcCount = max(maxDcCount, dcCount) maxEcCount = max(maxEcCount, ecCount) dcdata.append(buffer.buffer[offset:offset+dcCount]) offset += dcCount rsPoly = QRUtil.getErrorCorrectPolynomial(ecCount) rawPoly = QRPolynomial(dcdata[-1], rsPoly.getLength() - 1) modPoly = rawPoly.mod(rsPoly) rLen = rsPoly.getLength() - 1 mLen = modPoly.getLength() ecdata.append([ (modPoly.get(i) if i >= 0 else 0) for i in range(mLen - rLen, mLen) ]) data = [ d for dd in itertools.chain( zip_longest(*dcdata), zip_longest(*ecdata)) for d in dd if d is not None] return data class QRErrorCorrectLevel: L = 1 M = 0 Q = 3 H = 2 class QRMaskPattern: PATTERN000 = 0 PATTERN001 = 1 PATTERN010 = 2 PATTERN011 = 3 PATTERN100 = 4 PATTERN101 = 5 PATTERN110 = 6 PATTERN111 = 7 class QRUtil: PATTERN_POSITION_TABLE = [ [], [6, 18], [6, 22], [6, 26], [6, 30], [6, 34], [6, 22, 38], [6, 24, 42], [6, 26, 46], [6, 28, 50], [6, 30, 54], [6, 32, 58], [6, 34, 62], [6, 26, 46, 66], [6, 26, 48, 70], [6, 26, 50, 74], [6, 30, 54, 78], [6, 30, 56, 82], [6, 30, 58, 86], [6, 34, 62, 90], [6, 28, 50, 72, 94], [6, 26, 50, 74, 98], [6, 30, 54, 78, 102], [6, 28, 54, 80, 106], [6, 32, 58, 84, 110], [6, 30, 58, 86, 114], [6, 34, 62, 90, 118], [6, 26, 50, 74, 98, 122], [6, 30, 54, 78, 102, 126], [6, 26, 52, 78, 104, 130], [6, 30, 56, 82, 108, 134], [6, 34, 60, 86, 112, 138], [6, 30, 58, 86, 114, 142], [6, 34, 62, 90, 118, 146], [6, 30, 54, 78, 102, 126, 150], [6, 24, 50, 76, 102, 128, 154], [6, 28, 54, 80, 106, 132, 158], [6, 32, 58, 84, 110, 136, 162], [6, 26, 54, 82, 110, 138, 166], [6, 30, 58, 86, 114, 142, 170] ] G15 = ((1 << 10) | (1 << 8) | (1 << 5) | (1 << 4) | (1 << 2) | (1 << 1) | (1 << 0)) G18 = ((1 << 12) | (1 << 11) | (1 << 10) | (1 << 9) | (1 << 8) | (1 << 5) | (1 << 2) | (1 << 0)) G15_MASK = (1 << 14) | (1 << 12) | (1 << 10) | (1 << 4) | (1 << 1) @staticmethod def getBCHTypeInfo(data): d = data << 10; while (QRUtil.getBCHDigit(d) - QRUtil.getBCHDigit(QRUtil.G15) >= 0): d ^= (QRUtil.G15 << (QRUtil.getBCHDigit(d) - QRUtil.getBCHDigit(QRUtil.G15) ) ) return ( (data << 10) | d) ^ QRUtil.G15_MASK @staticmethod def getBCHTypeNumber(data): d = data << 12; while (QRUtil.getBCHDigit(d) - QRUtil.getBCHDigit(QRUtil.G18) >= 0): d ^= (QRUtil.G18 << (QRUtil.getBCHDigit(d) - QRUtil.getBCHDigit(QRUtil.G18) ) ) return (data << 12) | d @staticmethod def getBCHDigit(data): digit = 0; while (data != 0): digit += 1 data >>= 1 return digit @staticmethod def getPatternPosition(version): return QRUtil.PATTERN_POSITION_TABLE[version - 1] maskPattern = { 0: lambda i,j: (i + j) % 2 == 0, 1: lambda i,j: i % 2 == 0, 2: lambda i,j: j % 3 == 0, 3: lambda i,j: (i + j) % 3 == 0, 4: lambda i,j: (i // 2 + j // 3) % 2 == 0, 5: lambda i,j: (i*j)%2 + (i*j)%3 == 0, 6: lambda i,j: ( (i * j) % 2 + (i * j) % 3) % 2 == 0, 7: lambda i,j: ( (i * j) % 3 + (i + j) % 2) % 2 == 0 } @classmethod def getMask(cls, maskPattern): return cls.maskPattern[maskPattern] @staticmethod def getErrorCorrectPolynomial(errorCorrectLength): a = QRPolynomial([1], 0); for i in range(errorCorrectLength): a = a.multiply(QRPolynomial([1, QRMath.gexp(i)], 0) ) return a @classmethod def maskScoreRule1vert(cls, modules): score = 0 lastCount = [0] lastRow = None for row in modules: # Vertical patterns if lastRow: changed = [a ^ b for a,b in zip(row, lastRow)] scores = [a and (b-4+3) for a,b in zip_longest(changed, lastCount, fillvalue=0) if b >= 4] score += sum(scores) lastCount = [0 if a else b + 1 for a,b in zip_longest(changed, lastCount, fillvalue=0)] lastRow = row score += sum([b-4+3 for b in lastCount if b >= 4]) # final counts return score @classmethod def maskScoreRule2(cls, modules): score = 0 lastRow = modules[0] for row in modules[1:]: lastCol0, lastCol1 = row[0], lastRow[0] for col0, col1 in zip(row[1:], lastRow[1:]): if col0 == col1 == lastCol0 == lastCol1: score += 3 lastCol0, lastCol1 = col0, col1 lastRow = row return score @classmethod def maskScoreRule3hor( cls, modules, pattern = [True, False, True, True, True, False, True, False, False, False, False]): patternlen = len(pattern) score = 0 for row in modules: j = 0 maxj = len(row) - patternlen while j < maxj: if row[j:j+patternlen] == pattern: score += 40 j += patternlen else: j += 1 return score @classmethod def maskScoreRule4(cls, modules): cellCount = len(modules)**2 count = sum(sum(row) for row in modules) return 10 * (abs(100 * count // cellCount - 50) // 5) @classmethod def getLostPoint(cls, qrCode): lostPoint = 0; # LEVEL1 lostPoint += cls.maskScoreRule1vert(qrCode.modules) lostPoint += cls.maskScoreRule1vert(zip(*qrCode.modules)) # LEVEL2 lostPoint += cls.maskScoreRule2(qrCode.modules) # LEVEL3 lostPoint += cls.maskScoreRule3hor(qrCode.modules) lostPoint += cls.maskScoreRule3hor(zip(*qrCode.modules)) # LEVEL4 lostPoint += cls.maskScoreRule4(qrCode.modules) return lostPoint class QRMath: @staticmethod def glog(n): if (n < 1): raise Exception("glog(" + n + ")") return LOG_TABLE[n]; @staticmethod def gexp(n): while n < 0: n += 255 while n >= 256: n -= 255 return EXP_TABLE[n]; EXP_TABLE = [x for x in range(256)] LOG_TABLE = [x for x in range(256)] for i in range(8): EXP_TABLE[i] = 1 << i; for i in range(8, 256): EXP_TABLE[i] = (EXP_TABLE[i - 4] ^ EXP_TABLE[i - 5] ^ EXP_TABLE[i - 6] ^ EXP_TABLE[i - 8]) for i in range(255): LOG_TABLE[EXP_TABLE[i] ] = i class QRPolynomial: def __init__(self, num, shift): if (len(num) == 0): raise Exception(len(num) + "/" + shift) offset = 0 while offset < len(num) and num[offset] == 0: offset += 1 self.num = num[offset:] + [0]*shift def get(self, index): return self.num[index] def getLength(self): return len(self.num) def multiply(self, e): num = [0] * (self.getLength() + e.getLength() - 1); for i in range(self.getLength()): for j in range(e.getLength()): num[i + j] ^= QRMath.gexp(QRMath.glog(self.get(i) ) + QRMath.glog(e.get(j) ) ) return QRPolynomial(num, 0); def mod(self, e): if (self.getLength() < e.getLength()): return self; ratio = QRMath.glog(self.num[0] ) - QRMath.glog(e.num[0] ) num = [nn ^ QRMath.gexp(QRMath.glog(en) + ratio) for nn,en in zip(self.num, e.num)] num += self.num[e.getLength():] # recursive call return QRPolynomial(num, 0).mod(e); class QRRSBlock: RS_BLOCK_TABLE = [ # L # M # Q # H # 1 [1, 26, 19], [1, 26, 16], [1, 26, 13], [1, 26, 9], # 2 [1, 44, 34], [1, 44, 28], [1, 44, 22], [1, 44, 16], # 3 [1, 70, 55], [1, 70, 44], [2, 35, 17], [2, 35, 13], # 4 [1, 100, 80], [2, 50, 32], [2, 50, 24], [4, 25, 9], # 5 [1, 134, 108], [2, 67, 43], [2, 33, 15, 2, 34, 16], [2, 33, 11, 2, 34, 12], # 6 [2, 86, 68], [4, 43, 27], [4, 43, 19], [4, 43, 15], # 7 [2, 98, 78], [4, 49, 31], [2, 32, 14, 4, 33, 15], [4, 39, 13, 1, 40, 14], # 8 [2, 121, 97], [2, 60, 38, 2, 61, 39], [4, 40, 18, 2, 41, 19], [4, 40, 14, 2, 41, 15], # 9 [2, 146, 116], [3, 58, 36, 2, 59, 37], [4, 36, 16, 4, 37, 17], [4, 36, 12, 4, 37, 13], # 10 [2, 86, 68, 2, 87, 69], [4, 69, 43, 1, 70, 44], [6, 43, 19, 2, 44, 20], [6, 43, 15, 2, 44, 16], # 11 [4, 101, 81], [1, 80, 50, 4, 81, 51], [4, 50, 22, 4, 51, 23], [3, 36, 12, 8, 37, 13], # 12 [2, 116, 92, 2, 117, 93], [6, 58, 36, 2, 59, 37], [4, 46, 20, 6, 47, 21], [7, 42, 14, 4, 43, 15], # 13 [4, 133, 107], [8, 59, 37, 1, 60, 38], [8, 44, 20, 4, 45, 21], [12, 33, 11, 4, 34, 12], # 14 [3, 145, 115, 1, 146, 116], [4, 64, 40, 5, 65, 41], [11, 36, 16, 5, 37, 17], [11, 36, 12, 5, 37, 13], # 15 [5, 109, 87, 1, 110, 88], [5, 65, 41, 5, 66, 42], [5, 54, 24, 7, 55, 25], [11, 36, 12], # 16 [5, 122, 98, 1, 123, 99], [7, 73, 45, 3, 74, 46], [15, 43, 19, 2, 44, 20], [3, 45, 15, 13, 46, 16], # 17 [1, 135, 107, 5, 136, 108], [10, 74, 46, 1, 75, 47], [1, 50, 22, 15, 51, 23], [2, 42, 14, 17, 43, 15], # 18 [5, 150, 120, 1, 151, 121], [9, 69, 43, 4, 70, 44], [17, 50, 22, 1, 51, 23], [2, 42, 14, 19, 43, 15], # 19 [3, 141, 113, 4, 142, 114], [3, 70, 44, 11, 71, 45], [17, 47, 21, 4, 48, 22], [9, 39, 13, 16, 40, 14], # 20 [3, 135, 107, 5, 136, 108], [3, 67, 41, 13, 68, 42], [15, 54, 24, 5, 55, 25], [15, 43, 15, 10, 44, 16], # 21 [4, 144, 116, 4, 145, 117], [17, 68, 42], [17, 50, 22, 6, 51, 23], [19, 46, 16, 6, 47, 17], # 22 [2, 139, 111, 7, 140, 112], [17, 74, 46], [7, 54, 24, 16, 55, 25], [34, 37, 13], # 23 [4, 151, 121, 5, 152, 122], [4, 75, 47, 14, 76, 48], [11, 54, 24, 14, 55, 25], [16, 45, 15, 14, 46, 16], # 24 [6, 147, 117, 4, 148, 118], [6, 73, 45, 14, 74, 46], [11, 54, 24, 16, 55, 25], [30, 46, 16, 2, 47, 17], # 25 [8, 132, 106, 4, 133, 107], [8, 75, 47, 13, 76, 48], [7, 54, 24, 22, 55, 25], [22, 45, 15, 13, 46, 16], # 26 [10, 142, 114, 2, 143, 115], [19, 74, 46, 4, 75, 47], [28, 50, 22, 6, 51, 23], [33, 46, 16, 4, 47, 17], # 27 [8, 152, 122, 4, 153, 123], [22, 73, 45, 3, 74, 46], [8, 53, 23, 26, 54, 24], [12, 45, 15, 28, 46, 16], # 28 [3, 147, 117, 10, 148, 118], [3, 73, 45, 23, 74, 46], [4, 54, 24, 31, 55, 25], [11, 45, 15, 31, 46, 16], # 29 [7, 146, 116, 7, 147, 117], [21, 73, 45, 7, 74, 46], [1, 53, 23, 37, 54, 24], [19, 45, 15, 26, 46, 16], # 30 [5, 145, 115, 10, 146, 116], [19, 75, 47, 10, 76, 48], [15, 54, 24, 25, 55, 25], [23, 45, 15, 25, 46, 16], # 31 [13, 145, 115, 3, 146, 116], [2, 74, 46, 29, 75, 47], [42, 54, 24, 1, 55, 25], [23, 45, 15, 28, 46, 16], # 32 [17, 145, 115], [10, 74, 46, 23, 75, 47], [10, 54, 24, 35, 55, 25], [19, 45, 15, 35, 46, 16], # 33 [17, 145, 115, 1, 146, 116], [14, 74, 46, 21, 75, 47], [29, 54, 24, 19, 55, 25], [11, 45, 15, 46, 46, 16], # 34 [13, 145, 115, 6, 146, 116], [14, 74, 46, 23, 75, 47], [44, 54, 24, 7, 55, 25], [59, 46, 16, 1, 47, 17], # 35 [12, 151, 121, 7, 152, 122], [12, 75, 47, 26, 76, 48], [39, 54, 24, 14, 55, 25], [22, 45, 15, 41, 46, 16], # 36 [6, 151, 121, 14, 152, 122], [6, 75, 47, 34, 76, 48], [46, 54, 24, 10, 55, 25], [2, 45, 15, 64, 46, 16], # 37 [17, 152, 122, 4, 153, 123], [29, 74, 46, 14, 75, 47], [49, 54, 24, 10, 55, 25], [24, 45, 15, 46, 46, 16], # 38 [4, 152, 122, 18, 153, 123], [13, 74, 46, 32, 75, 47], [48, 54, 24, 14, 55, 25], [42, 45, 15, 32, 46, 16], # 39 [20, 147, 117, 4, 148, 118], [40, 75, 47, 7, 76, 48], [43, 54, 24, 22, 55, 25], [10, 45, 15, 67, 46, 16], # 40 [19, 148, 118, 6, 149, 119], [18, 75, 47, 31, 76, 48], [34, 54, 24, 34, 55, 25], [20, 45, 15, 61, 46, 16] ] def __init__(self, totalCount, dataCount): self.totalCount = totalCount self.dataCount = dataCount @staticmethod def getRSBlocks(version, errorCorrectLevel): rsBlock = QRRSBlock.getRsBlockTable(version, errorCorrectLevel); if rsBlock == None: raise Exception("bad rs block @ version:" + version + "/errorCorrectLevel:" + errorCorrectLevel) length = len(rsBlock) // 3 list = [] for i in range(length): count = rsBlock[i * 3 + 0] totalCount = rsBlock[i * 3 + 1] dataCount = rsBlock[i * 3 + 2] for j in range(count): list.append(QRRSBlock(totalCount, dataCount)) return list; @staticmethod def getRsBlockTable(version, errorCorrectLevel): if errorCorrectLevel == QRErrorCorrectLevel.L: return QRRSBlock.RS_BLOCK_TABLE[(version - 1) * 4 + 0]; elif errorCorrectLevel == QRErrorCorrectLevel.M: return QRRSBlock.RS_BLOCK_TABLE[(version - 1) * 4 + 1]; elif errorCorrectLevel == QRErrorCorrectLevel.Q: return QRRSBlock.RS_BLOCK_TABLE[(version - 1) * 4 + 2]; elif errorCorrectLevel == QRErrorCorrectLevel.H: return QRRSBlock.RS_BLOCK_TABLE[(version - 1) * 4 + 3]; else: return None; class QRBitBuffer: def __init__(self): self.buffer = [] self.length = 0 def __repr__(self): return ".".join([str(n) for n in self.buffer]) def get(self, index): bufIndex = index // 8 return ( (self.buffer[bufIndex] >> (7 - index % 8) ) & 1) == 1 def put(self, num, length): for i in range(length): self.putBit( ( (num >> (length - i - 1) ) & 1) == 1) def getLengthInBits(self): return self.length def putBit(self, bit): bufIndex = self.length // 8 if len(self.buffer) <= bufIndex: self.buffer.append(0) if bit: self.buffer[bufIndex] |= (0x80 >> (self.length % 8) ) self.length += 1 ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1691062243.0 reportlab-4.1.0/src/reportlab/graphics/barcode/test.py0000664000175000017500000002676514462707743022451 0ustar00rptlabrptlab#!/usr/pkg/bin/python import sys, time from reportlab import Version as __RL_Version__ from reportlab.graphics.barcode.common import * from reportlab.graphics.barcode.code39 import * from reportlab.graphics.barcode.code93 import * from reportlab.graphics.barcode.code128 import * from reportlab.graphics.barcode.usps import * from reportlab.graphics.barcode.usps4s import USPS_4State from reportlab.graphics.barcode.qr import QrCodeWidget from reportlab.graphics.barcode.dmtx import DataMatrixWidget, pylibdmtx from reportlab.platypus import Spacer, SimpleDocTemplate, PageBreak from reportlab.lib.units import inch from reportlab.lib import colors from reportlab.lib.styles import getSampleStyleSheet from reportlab.platypus.paragraph import Paragraph from reportlab.platypus.flowables import XBox, KeepTogether from reportlab.graphics.shapes import Drawing, Rect, Line from reportlab.graphics.barcode import getCodeNames, createBarcodeDrawing, createBarcodeImageInMemory def run(): styles = getSampleStyleSheet() styleN = styles['Normal'] styleH = styles['Heading1'] story = [] storyAdd = story.append #for codeNames in code storyAdd(Paragraph('I2of5', styleN)) storyAdd(I2of5('05400141288766', barWidth = inch*0.02, checksum=0)) storyAdd(I2of5('0001234567890', barWidth = inch*0.02, checksum=1)) storyAdd(I2of5('00012345678905', barWidth = inch*0.02, checksum=0)) storyAdd(I2of5('0001234567890', barWidth = inch*0.02, checksum=1, bearerBox = True)) storyAdd(Paragraph('MSI', styleN)) storyAdd(MSI(1234)) storyAdd(Paragraph('Codabar', styleN)) storyAdd(Codabar("A012345B", barWidth = inch*0.02)) storyAdd(Paragraph('Code 11', styleN)) storyAdd(Code11("01234545634563")) storyAdd(Paragraph('Code 39', styleN)) storyAdd(Standard39("A012345B%R")) storyAdd(Paragraph('Extended Code 39', styleN)) storyAdd(Extended39("A012345B}")) storyAdd(Paragraph('Code93', styleN)) storyAdd(Standard93("CODE 93")) storyAdd(Paragraph('Extended Code93', styleN)) storyAdd(Extended93("L@@K! Code 93 :-)")) #, barWidth=0.005 * inch)) storyAdd(Paragraph('Code 128', styleN)) storyAdd(Code128("AB-12345678")) storyAdd(Paragraph('Code 128 Auto', styleN)) storyAdd(Code128Auto("AB-12345678")) storyAdd(Paragraph('USPS FIM', styleN)) storyAdd(FIM("A")) storyAdd(Paragraph('USPS POSTNET', styleN)) storyAdd(POSTNET('78247-1043')) storyAdd(Paragraph('USPS 4 State', styleN)) storyAdd(USPS_4State('01234567094987654321','01234567891')) from reportlab.graphics.barcode import createBarcodeDrawing storyAdd(Paragraph('EAN13', styleN)) storyAdd(createBarcodeDrawing('EAN13', value='123456789012')) storyAdd(Paragraph('EAN13 quiet=False', styleN)) storyAdd(createBarcodeDrawing('EAN13', value='123456789012', quiet=False)) storyAdd(Paragraph('EAN8', styleN)) storyAdd(createBarcodeDrawing('EAN8', value='1234567')) storyAdd(PageBreak()) storyAdd(Paragraph('EAN5 price=True', styleN)) storyAdd(createBarcodeDrawing('EAN5', value='11299', price=True)) storyAdd(Paragraph('EAN5 price=True quiet=False', styleN)) storyAdd(createBarcodeDrawing('EAN5', value='11299', price=True, quiet=False)) storyAdd(Paragraph('EAN5 price=False', styleN)) storyAdd(createBarcodeDrawing('EAN5', value='11299', price=False)) storyAdd(Paragraph('ISBN alone', styleN)) storyAdd(createBarcodeDrawing('ISBN', value='9781565924796')) storyAdd(Paragraph('ISBN with ean5 price', styleN)) storyAdd(createBarcodeDrawing('ISBN', value='9781565924796',price='01299')) storyAdd(Paragraph('ISBN with ean5 price, quiet=False', styleN)) storyAdd(createBarcodeDrawing('ISBN', value='9781565924796',price='01299',quiet=False)) storyAdd(Paragraph('UPCA', styleN)) storyAdd(createBarcodeDrawing('UPCA', value='03600029145')) storyAdd(Paragraph('USPS_4State', styleN)) storyAdd(createBarcodeDrawing('USPS_4State', value='01234567094987654321',routing='01234567891')) storyAdd(Paragraph('QR', styleN)) storyAdd(createBarcodeDrawing('QR', value='01234567094987654321')) storyAdd(Paragraph('QR', styleN)) storyAdd(createBarcodeDrawing('QR', value='01234567094987654321',x=30,y=50)) def addCross(d,x,y,w=5,h=5, strokeColor='black', strokeWidth=0.5): w *= 0.5 h *= 0.5 d.add(Line(x-w,y,x+w,y,strokeWidth=0.5,strokeColor=colors.blue)) d.add(Line(x, y-h, x, y+h,strokeWidth=0.5,strokeColor=colors.blue)) storyAdd(Paragraph('QR in drawing at (0,0)', styleN)) d = Drawing(100,100) d.add(Rect(0,0,100,100,strokeWidth=1,strokeColor=colors.red,fillColor=None)) d.add(QrCodeWidget(value='01234567094987654321')) storyAdd(d) storyAdd(Paragraph('QR in drawing at (10,10)', styleN)) d = Drawing(100,100) d.add(Rect(0,0,100,100,strokeWidth=1,strokeColor=colors.red,fillColor=None)) addCross(d,10,10) d.add(QrCodeWidget(value='01234567094987654321',x=10,y=10)) storyAdd(d) storyAdd(Paragraph('Label Size', styleN)) storyAdd(XBox((2.0 + 5.0/8.0)*inch, 1 * inch, '1x2-5/8"')) storyAdd(Paragraph('Label Size', styleN)) storyAdd(XBox((1.75)*inch, .5 * inch, '1/2x1-3/4"')) if pylibdmtx: storyAdd(PageBreak()) storyAdd(Paragraph('DataMatrix in drawing at (10,10)', styleN)) d = Drawing(100,100) d.add(Rect(0,0,100,100,strokeWidth=1,strokeColor=colors.red,fillColor=None)) addCross(d,10,10) d.add(DataMatrixWidget(value='1234567890',x=10,y=10)) storyAdd(d) storyAdd(Paragraph('DataMatrix in drawing at (10,10)', styleN)) d = Drawing(100,100) d.add(Rect(0,0,100,100,strokeWidth=1,strokeColor=colors.red,fillColor=None)) addCross(d,10,10) d.add(DataMatrixWidget(value='1234567890',x=10,y=10,color='black',bgColor='lime')) storyAdd(d) storyAdd(Paragraph('DataMatrix in drawing at (90,90) anchor=ne', styleN)) d = Drawing(100,100) d.add(Rect(0,0,100,100,strokeWidth=1,strokeColor=colors.red,fillColor=None)) addCross(d,90,90) d.add(DataMatrixWidget(value='1234567890',x=90,y=90,color='darkblue',bgColor='yellow', anchor='ne')) storyAdd(d) SimpleDocTemplate('out.pdf').build(story) print('saved out.pdf') def fullTest(fileName="test_full.pdf"): """Creates large-ish test document with a variety of parameters""" story = [] styles = getSampleStyleSheet() styleN = styles['Normal'] styleH = styles['Heading1'] styleH2 = styles['Heading2'] story = [] story.append(Paragraph('ReportLab %s Barcode Test Suite - full output' % __RL_Version__,styleH)) story.append(Paragraph('Generated at %s' % time.ctime(time.time()), styleN)) story.append(Paragraph('About this document', styleH2)) story.append(Paragraph('History and Status', styleH2)) story.append(Paragraph(""" This is the test suite and docoumentation for the ReportLab open source barcode API. """, styleN)) story.append(Paragraph(""" Several years ago Ty Sarna contributed a barcode module to the ReportLab community. Several of the codes were used by him in hiw work and to the best of our knowledge this was correct. These were written as flowable objects and were available in PDFs, but not in our graphics framework. However, we had no knowledge of barcodes ourselves and did not advertise or extend the package. """, styleN)) story.append(Paragraph(""" We "wrapped" the barcodes to be usable within our graphics framework; they are now available as Drawing objects which can be rendered to EPS files or bitmaps. For the last 2 years this has been available in our Diagra and Report Markup Language products. However, we did not charge separately and use was on an "as is" basis. """, styleN)) story.append(Paragraph(""" A major licensee of our technology has kindly agreed to part-fund proper productisation of this code on an open source basis in Q1 2006. This has involved addition of EAN codes as well as a proper testing program. Henceforth we intend to publicise the code more widely, gather feedback, accept contributions of code and treat it as "supported". """, styleN)) story.append(Paragraph(""" This involved making available both downloads and testing resources. This PDF document is the output of the current test suite. It contains codes you can scan (if you use a nice sharp laser printer!), and will be extended over coming weeks to include usage examples and notes on each barcode and how widely tested they are. This is being done through documentation strings in the barcode objects themselves so should always be up to date. """, styleN)) story.append(Paragraph('Usage examples', styleH2)) story.append(Paragraph(""" To be completed """, styleN)) story.append(Paragraph('The codes', styleH2)) story.append(Paragraph(""" Below we show a scannable code from each barcode, with and without human-readable text. These are magnified about 2x from the natural size done by the original author to aid inspection. This will be expanded to include several test cases per code, and to add explanations of checksums. Be aware that (a) if you enter numeric codes which are too short they may be prefixed for you (e.g. "123" for an 8-digit code becomes "00000123"), and that the scanned results and readable text will generally include extra checksums at the end. """, styleN)) codeNames = getCodeNames() from reportlab.lib.utils import flatten width = [float(x[8:]) for x in sys.argv if x.startswith('--width=')] height = [float(x[9:]) for x in sys.argv if x.startswith('--height=')] isoScale = [int(x[11:]) for x in sys.argv if x.startswith('--isoscale=')] options = {} if width: options['width'] = width[0] if height: options['height'] = height[0] if isoScale: options['isoScale'] = isoScale[0] scales = [x[8:].split(',') for x in sys.argv if x.startswith('--scale=')] scales = list(map(float,scales and flatten(scales) or [1])) scales = list(map(float,scales and flatten(scales) or [1])) for scale in scales: story.append(PageBreak()) story.append(Paragraph('Scale = %.1f'%scale, styleH2)) story.append(Spacer(36, 12)) for codeName in codeNames: s = [Paragraph('Code: ' + codeName, styleH2)] for hr in (0,1): s.append(Spacer(36, 12)) dr = createBarcodeDrawing(codeName, humanReadable=hr,**options) dr.renderScale = scale s.append(dr) s.append(Spacer(36, 12)) s.append(Paragraph('Barcode should say: ' + dr._bc.value, styleN)) story.append(KeepTogether(s)) SimpleDocTemplate(fileName).build(story) print('created', fileName) if __name__=='__main__': run() fullTest() def createSample(name,memory): f = open(name,'wb') f.write(memory) f.close() createSample('test_cbcim.png',createBarcodeImageInMemory('EAN13', value='123456789012')) createSample('test_cbcim.gif',createBarcodeImageInMemory('EAN8', value='1234567', format='gif')) createSample('test_cbcim.pdf',createBarcodeImageInMemory('UPCA', value='03600029145',format='pdf', barHeight=40)) createSample('test_cbcim.tiff',createBarcodeImageInMemory('USPS_4State', value='01234567094987654321',routing='01234567891',format='tiff')) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1691062243.0 reportlab-4.1.0/src/reportlab/graphics/barcode/usps.py0000664000175000017500000001761414462707743022455 0ustar00rptlabrptlab# # Copyright (c) 1996-2000 Tyler C. Sarna # 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. # 3. All advertising materials mentioning features or use of this software # must display the following acknowledgement: # This product includes software developed by Tyler C. Sarna. # 4. Neither the name of the author nor the names of contributors # may be used to endorse or promote products derived from this software # without specific prior written permission. # # 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. # from reportlab.lib.units import inch from reportlab.graphics.barcode.common import Barcode from string import digits as string_digits, whitespace as string_whitespace from reportlab.lib.utils import asNative _fim_patterns = { 'A' : "|| | ||", 'B' : "| || || |", 'C' : "|| | | ||", 'D' : "||| | |||", # XXX There is an E. # The below has been seen, but dunno if it is E or not: # 'E' : '|||| ||||' } _postnet_patterns = { '1' : "...||", '2' : "..|.|", '3' : "..||.", '4' : ".|..|", '5' : ".|.|.", '6' : ".||..", '7' : "|...|", '8' : "|..|.", '9' : "|.|..", '0' : "||...", 'S' : "|", } class FIM(Barcode): """ FIM (Facing ID Marks) encode only one letter. There are currently four defined: A Courtesy reply mail with pre-printed POSTNET B Business reply mail without pre-printed POSTNET C Business reply mail with pre-printed POSTNET D OCR Readable mail without pre-printed POSTNET Options that may be passed to constructor: value (single character string from the set A - D. required.): The value to encode. quiet (bool, default 0): Whether to include quiet zones in the symbol. The following may also be passed, but doing so will generate nonstandard symbols which should not be used. This is mainly documented here to show the defaults: barHeight (float, default 5/8 inch): Height of the code. This might legitimately be overriden to make a taller symbol that will 'bleed' off the edge of the paper, leaving 5/8 inch remaining. lquiet (float, default 1/4 inch): Quiet zone size to left of code, if quiet is true. Default is the greater of .25 inch, or .15 times the symbol's length. rquiet (float, default 15/32 inch): Quiet zone size to right left of code, if quiet is true. Sources of information on FIM: USPS Publication 25, A Guide to Business Mail Preparation http://new.usps.com/cpim/ftp/pubs/pub25.pdf """ barWidth = inch * (1.0/32.0) spaceWidth = inch * (1.0/16.0) barHeight = inch * (5.0/8.0) rquiet = inch * (0.25) lquiet = inch * (15.0/32.0) quiet = 0 def __init__(self, value='', **args): value = str(value) if isinstance(value,int) else asNative(value) for k, v in args.items(): setattr(self, k, v) Barcode.__init__(self, value) def validate(self): self.valid = 1 self.validated = '' for c in self.value: if c in string_whitespace: continue elif c in "abcdABCD": self.validated = self.validated + c.upper() else: self.valid = 0 if len(self.validated) != 1: raise ValueError("Input must be exactly one character") return self.validated def decompose(self): self.decomposed = '' for c in self.encoded: self.decomposed = self.decomposed + _fim_patterns[c] return self.decomposed def computeSize(self): self._width = (len(self.decomposed) - 1) * self.spaceWidth + self.barWidth if self.quiet: self._width += self.lquiet + self.rquiet self._height = self.barHeight def draw(self): self._calculate() left = self.quiet and self.lquiet or 0 for c in self.decomposed: if c == '|': self.rect(left, 0.0, self.barWidth, self.barHeight) left += self.spaceWidth self.drawHumanReadable() def _humanText(self): return self.value class POSTNET(Barcode): """ POSTNET is used in the US to encode "zip codes" (postal codes) on mail. It can encode 5, 9, or 11 digit codes. I've read that it's pointless to do 5 digits, since USPS will just have to re-print them with 9 or 11 digits. Sources of information on POSTNET: USPS Publication 25, A Guide to Business Mail Preparation http://new.usps.com/cpim/ftp/pubs/pub25.pdf """ quiet = 0 shortHeight = inch * 0.050 barHeight = inch * 0.125 barWidth = inch * 0.018 spaceWidth = inch * 0.0275 def __init__(self, value='', **args): value = str(value) if isinstance(value,int) else asNative(value) for k, v in args.items(): setattr(self, k, v) Barcode.__init__(self, value) def validate(self): self.validated = '' self.valid = 1 count = 0 for c in self.value: if c in (string_whitespace + '-'): pass elif c in string_digits: count = count + 1 if count == 6: self.validated = self.validated + '-' self.validated = self.validated + c else: self.valid = 0 if len(self.validated) not in [5, 10, 12]: self.valid = 0 return self.validated def encode(self): self.encoded = "S" check = 0 for c in self.validated: if c in string_digits: self.encoded = self.encoded + c check = check + int(c) elif c == '-': pass else: raise ValueError("Invalid character in input") check = (10 - check) % 10 self.encoded = self.encoded + repr(check) + 'S' return self.encoded def decompose(self): self.decomposed = '' for c in self.encoded: self.decomposed = self.decomposed + _postnet_patterns[c] return self.decomposed def computeSize(self): self._width = len(self.decomposed) * self.barWidth + (len(self.decomposed) - 1) * self.spaceWidth self._height = self.barHeight def draw(self): self._calculate() sdown = self.barHeight - self.shortHeight left = 0 for c in self.decomposed: if c == '.': h = self.shortHeight else: h = self.barHeight self.rect(left, 0.0, self.barWidth, h) left = left + self.barWidth + self.spaceWidth self.drawHumanReadable() def _humanText(self): return self.encoded[1:-1] ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1707393347.0 reportlab-4.1.0/src/reportlab/graphics/barcode/usps4s.py0000664000175000017500000003650114561140503022701 0ustar00rptlabrptlab#copyright ReportLab Inc. 2000-2016 #see license.txt for license details from __future__ import print_function __version__='3.3.0' __all__ = ('USPS_4State',) from reportlab.graphics.barcode.common import Barcode from reportlab.lib.utils import asNative def nhex(i): 'normalized hex' r = hex(i) r = r[:2]+r[2:].lower() if r.endswith('l'): r = r[:-1] return r class USPS_4State(Barcode): ''' USPS 4-State OneView (TM) barcode. All info from USPS-B-3200A ''' _widthSize = 1 _heightSize = 1 _fontSize = 11 _humanReadable = 0 if True: tops = dict( F = (0.0625,0.0825), T = (0.0195,0.0285), A = (0.0625,0.0825), D = (0.0195,0.0285), ) bottoms = dict( F = (-0.0625,-0.0825), T = (-0.0195,-0.0285), D = (-0.0625,-0.0825), A = (-0.0195,-0.0285), ) dimensions = dict( width = (0.015, 0.025), pitch = (0.0416, 0.050), hcz = (0.125,0.125), vcz = (0.028,0.028), ) else: tops = dict( F = (0.067,0.115), T = (0.021,0.040), A = (0.067,0.115), D = (0.021,0.040), ) bottoms = dict( F = (-0.067,-0.115), D = (-0.067,-0.115), T = (-0.021,-0.040), A = (-0.021,-0.040), ) dimensions = dict( width = (0.015, 0.025), pitch = (0.0416,0.050), hcz = (0.125,0.125), vcz = (0.040,0.040), ) def __init__(self,value='01234567094987654321',routing='',**kwd): self._init() value = str(value) if isinstance(value,int) else asNative(value) if not routing: #legal values for combined tracking + routing if len(value) in (20,25,29,31): value, routing = value[:20], value[20:] else: raise ValueError('value+routing length must be 20, 25, 29 or 31 digits not %d' % len(value)) elif len(routing) not in (5,9,11): raise ValueError('routing length must be 5, 9 or 11 digits not %d' % len(routing)) self._tracking = value self._routing = routing self._setKeywords(**kwd) def _init(self): self._bvalue = None self._codewords = None self._characters = None self._barcodes = None def scale(kind,D,s): V = D[kind] return 72*(V[0]*(1-s)+s*V[1]) scale = staticmethod(scale) def tracking(self,tracking): self._init() self._tracking = tracking tracking = property(lambda self: self._tracking,tracking) def routing(self,routing): self._init() self._routing = routing routing = property(lambda self: self._routing,routing) def widthSize(self,value): self._sized = None self._widthSize = min(max(0,value),1) widthSize = property(lambda self: self._widthSize,widthSize) def heightSize(self,value): self._sized = None self._heightSize = value heightSize = property(lambda self: self._heightSize,heightSize) def fontSize(self,value): self._sized = None self._fontSize = value fontSize = property(lambda self: self._fontSize,fontSize) def humanReadable(self,value): self._sized = None self._humanReadable = value humanReadable = property(lambda self: self._humanReadable,humanReadable) def binary(self): '''convert the 4 state string values to binary >>> print(nhex(USPS_4State('01234567094987654321','').binary)) 0x1122103b5c2004b1 >>> print(nhex(USPS_4State('01234567094987654321','01234').binary)) 0xd138a87bab5cf3804b1 >>> print(nhex(USPS_4State('01234567094987654321','012345678').binary)) 0x202bdc097711204d21804b1 >>> print(nhex(USPS_4State('01234567094987654321','01234567891').binary)) 0x16907b2a24abc16a2e5c004b1 ''' value = self._bvalue if not value: routing = self.routing n = len(routing) try: if n==0: value = 0 elif n==5: value = int(routing)+1 elif n==9: value = int(routing)+100001 elif n==11: value = int(routing)+1000100001 else: raise ValueError except: raise ValueError('Problem converting %s, routing code must be 0, 5, 9 or 11 digits' % routing) tracking = self.tracking svalue = tracking[0:2] try: value *= 10 value += int(svalue[0]) value *= 5 value += int(svalue[1]) except: raise ValueError('Problem converting %s, barcode identifier must be 2 digits' % svalue) i = 2 for name,nd in (('special services',3), ('customer identifier',6), ('sequence number',9)): j = i i += nd svalue = tracking[j:i] try: if len(svalue)!=nd: raise ValueError for j in range(nd): value *= 10 value += int(svalue[j]) except: raise ValueError('Problem converting %s, %s must be %d digits' % (svalue,name,nd)) self._bvalue = value return value binary = property(binary) def codewords(self): '''convert binary value into codewords >>> print(USPS_4State('01234567094987654321','01234567891').codewords) (673, 787, 607, 1022, 861, 19, 816, 1294, 35, 602) ''' if not self._codewords: value = self.binary A, J = divmod(value,636) A, I = divmod(A,1365) A, H = divmod(A,1365) A, G = divmod(A,1365) A, F = divmod(A,1365) A, E = divmod(A,1365) A, D = divmod(A,1365) A, C = divmod(A,1365) A, B = divmod(A,1365) assert 0<=A<=658, 'improper value %s passed to _2codewords A-->%s' % (hex(int(value)),A) self._fcs = _crc11(value) if self._fcs&1024: A += 659 J *= 2 self._codewords = tuple(map(int,(A,B,C,D,E,F,G,H,I,J))) return self._codewords codewords = property(codewords) def table1(self): self.__class__.table1 = _initNof13Table(5,1287) return self.__class__.table1 table1 = property(table1) def table2(self): self.__class__.table2 = _initNof13Table(2,78) return self.__class__.table2 table2 = property(table2) def characters(self): ''' convert own codewords to characters >>> print(' '.join(hex(c)[2:] for c in USPS_4State('01234567094987654321','01234567891').characters)) dcb 85c 8e4 b06 6dd 1740 17c6 1200 123f 1b2b ''' if not self._characters: codewords = self.codewords fcs = self._fcs C = [] aC = C.append table1 = self.table1 table2 = self.table2 for i in range(10): cw = codewords[i] if cw<=1286: c = table1[cw] else: c = table2[cw-1287] if (fcs>>i)&1: c = ~c & 0x1fff aC(c) self._characters = tuple(C) return self._characters characters = property(characters) def barcodes(self): '''Get 4 state bar codes for current routing and tracking >>> print(USPS_4State('01234567094987654321','01234567891').barcodes) AADTFFDFTDADTAADAATFDTDDAAADDTDTTDAFADADDDTFFFDDTTTADFAAADFTDAADA ''' if not self._barcodes: C = self.characters B = [] aB = B.append bits2bars = self._bits2bars for dc,db,ac,ab in self.table4: aB(bits2bars[((C[dc]>>db)&1)+2*((C[ac]>>ab)&1)]) self._barcodes = ''.join(B) return self._barcodes barcodes = property(barcodes) table4 = ((7, 2, 4, 3), (1, 10, 0, 0), (9, 12, 2, 8), (5, 5, 6, 11), (8, 9, 3, 1), (0, 1, 5, 12), (2, 5, 1, 8), (4, 4, 9, 11), (6, 3, 8, 10), (3, 9, 7, 6), (5, 11, 1, 4), (8, 5, 2, 12), (9, 10, 0, 2), (7, 1, 6, 7), (3, 6, 4, 9), (0, 3, 8, 6), (6, 4, 2, 7), (1, 1, 9, 9), (7, 10, 5, 2), (4, 0, 3, 8), (6, 2, 0, 4), (8, 11, 1, 0), (9, 8, 3, 12), (2, 6, 7, 7), (5, 1, 4, 10), (1, 12, 6, 9), (7, 3, 8, 0), (5, 8, 9, 7), (4, 6, 2, 10), (3, 4, 0, 5), (8, 4, 5, 7), (7, 11, 1, 9), (6, 0, 9, 6), (0, 6, 4, 8), (2, 1, 3, 2), (5, 9, 8, 12), (4, 11, 6, 1), (9, 5, 7, 4), (3, 3, 1, 2), (0, 7, 2, 0), (1, 3, 4, 1), (6, 10, 3, 5), (8, 7, 9, 4), (2, 11, 5, 6), (0, 8, 7, 12), (4, 2, 8, 1), (5, 10, 3, 0), (9, 3, 0, 9), (6, 5, 2, 4), (7, 8, 1, 7), (5, 0, 4, 5), (2, 3, 0, 10), (6, 12, 9, 2), (3, 11, 1, 6), (8, 8, 7, 9), (5, 4, 0, 11), (1, 5, 2, 2), (9, 1, 4, 12), (8, 3, 6, 6), (7, 0, 3, 7), (4, 7, 7, 5), (0, 12, 1, 11), (2, 9, 9, 0), (6, 8, 5, 3), (3, 10, 8, 2)) _bits2bars = 'T','D','A','F' horizontalClearZone = property(lambda self: self.scale('hcz',self.dimensions,self.widthScale)) verticalClearZone = property(lambda self: self.scale('vcz',self.dimensions,self.heightScale)) @property def barWidth(self): if '_barWidth' in self.__dict__: return self.__dict__['_barWidth'] return self.scale('width',self.dimensions,self.widthScale) @barWidth.setter def barWidth(self,value): n, x = self.dimensions['width'] self.__dict__['_barWidth'] = 72*min(max(value/72.0,n),x) @property def pitch(self): if '_pitch' in self.__dict__: return self.__dict__['_pitch'] return self.scale('pitch',self.dimensions,self.widthScale) @pitch.setter def pitch(self,value): n, x = self.dimensions['pitch'] self.__dict__['_pitch'] = 72*min(max(value/72.0,n),x) @property def barHeight(self): if '_barHeight' in self.__dict__: return self.__dict__['_barHeight'] return self.scale('F',self.tops,self.heightScale) - self.scale('F',self.bottoms,self.heightScale) @barHeight.setter def barHeight(self,value): n = self.tops['F'][0] - self.bottoms['F'][0] x = self.tops['F'][1] - self.bottoms['F'][1] value = self.__dict__['_barHeight'] = 72*min(max(value/72.0,n),x) self.heightSize = (value - n)/(x-n) widthScale = property(lambda self: min(1,max(0,self.widthSize))) heightScale = property(lambda self: min(1,max(0,self.heightSize))) @property def width(self): self.computeSize() return self._width @property def height(self): self.computeSize() return self._height #we ignore attempts to set the dimensions @width.setter def width(self,v): pass @height.setter def height(self,v): pass def computeSize(self): if not getattr(self,'_sized',None): ws = self.widthScale hs = self.heightScale barHeight = self.barHeight barWidth = self.barWidth pitch = self.pitch hcz = self.horizontalClearZone vcz = self.verticalClearZone self._width = 2*hcz + barWidth + 64*pitch self._height = 2*vcz+barHeight if self.humanReadable: self._height += self.fontSize*1.2+vcz self._sized = True def wrap(self,aW,aH): self.computeSize() return self.width, self.height def _getBarVInfo(self,y0=0): vInfo = {} hs = self.heightScale for b in ('T','D','A','F'): y = self.scale(b,self.bottoms,hs)+y0 vInfo[b] = y,self.scale(b,self.tops,hs)+y0 - y return vInfo def draw(self): self.computeSize() hcz = self.horizontalClearZone vcz = self.verticalClearZone bw = self.barWidth x = hcz y0 = vcz+self.barHeight*0.5 dw = self.pitch vInfo = self._getBarVInfo(y0) for b in self.barcodes: yb, hb = vInfo[b] self.rect(x,yb,bw,hb) x += dw self.drawHumanReadable() def value(self): tracking = self.tracking routing = self.routing routing = routing and (routing,) or () return ' '.join((tracking[0:2],tracking[2:5],tracking[5:11],tracking[11:])+routing) value = property(value,lambda self,value: self.__dict__.__setitem__('tracking',value)) def drawHumanReadable(self): if self.humanReadable: hcz = self.horizontalClearZone vcz = self.verticalClearZone fontName = self.fontName fontSize = self.fontSize y = self.barHeight+2*vcz+0.2*fontSize self.annotate(hcz,y,self.value,fontName,fontSize) def annotate(self,x,y,text,fontName,fontSize,anchor='middle'): Barcode.annotate(self,x,y,text,fontName,fontSize,anchor='start') def _crc11(value): ''' >>> usps = [USPS_4State('01234567094987654321',x).binary for x in ('','01234','012345678','01234567891')] >>> print(' '.join(nhex(x) for x in usps)) 0x1122103b5c2004b1 0xd138a87bab5cf3804b1 0x202bdc097711204d21804b1 0x16907b2a24abc16a2e5c004b1 >>> print(' '.join(nhex(_crc11(x)) for x in usps)) 0x51 0x65 0x606 0x751 ''' hexbytes = nhex(int(value))[2:] hexbytes = '0'*(26-len(hexbytes))+hexbytes gp = 0x0F35 fcs = 0x07FF data = int(hexbytes[:2],16)<<5 for b in range(2,8): if (fcs ^ data)&0x400: fcs = (fcs<<1)^gp else: fcs = fcs<<1 fcs &= 0x7ff data <<= 1 for x in range(2,2*13,2): data = int(hexbytes[x:x+2],16)<<3 for b in range(8): if (fcs ^ data)&0x400: fcs = (fcs<<1)^gp else: fcs = fcs<<1 fcs &= 0x7ff data <<= 1 return fcs def _ru13(i): '''reverse unsigned 13 bit number >>> print(_ru13(7936), _ru13(31), _ru13(47), _ru13(7808)) 31 7936 7808 47 ''' r = 0 for x in range(13): r <<= 1 r |= i & 1 i >>= 1 return r def _initNof13Table(N,lenT): '''create and return table of 13 bit values with N bits on >>> T = _initNof13Table(5,1287) >>> print(' '.join('T[%d]=%d' % (i, T[i]) for i in (0,1,2,3,4,1271,1272,1284,1285,1286))) T[0]=31 T[1]=7936 T[2]=47 T[3]=7808 T[4]=55 T[1271]=6275 T[1272]=6211 T[1284]=856 T[1285]=744 T[1286]=496 ''' T = lenT*[None] l = 0 u = lenT-1 for c in range(8192): bc = 0 for b in range(13): bc += (c&(1< scale the value otherwise use the absolute value labelClass the label class to use default Label all Label keywords are acceptable (including say _text) ''' def __init__(self,v,**kwds): self._v = v self._kwds = kwds def __call__(self,axis): kwds = self._kwds.copy() labelClass = kwds.pop('labelClass',Label) scaleValue = kwds.pop('scaleValue',True) if not hasattr(axis,'_tickValues'): axis._pseudo_configure() sv = (axis.scale if scaleValue else lambda x: x)(self._v) if axis.isYAxis: x = axis._x y = sv else: x = sv y = axis._y kwds['x'] = x kwds['y'] = y return labelClass(**kwds) class AxisLineAnnotation: '''Create a grid like line using the given user value to draw the line kwds may contain startOffset if true v is offset from the default grid start position endOffset if true v is offset from the default grid end position scaleValue True/not given --> scale the value otherwise use the absolute value lo lowest coordinate to draw default 0 hi highest coordinate to draw at default = length drawAtLimit True draw line at appropriate limit if its coordinate exceeds the lo, hi range False ignore if it's outside the range all Line keywords are acceptable ''' def __init__(self,v,**kwds): self._v = v self._kwds = kwds def __call__(self,axis): kwds = self._kwds.copy() scaleValue = kwds.pop('scaleValue',True) endOffset = kwds.pop('endOffset',False) startOffset = kwds.pop('startOffset',False) if axis.isYAxis: offs = axis._x d0 = axis._y else: offs = axis._y d0 = axis._x s = kwds.pop('start',None) e = kwds.pop('end',None) if s is None or e is None: dim = getattr(getattr(axis,'joinAxis',None),'getGridDims',None) if dim and hasattr(dim,'__call__'): dim = dim() if dim: if s is None: s = dim[0] if e is None: e = dim[1] else: if s is None: s = 0 if e is None: e = 0 hi = kwds.pop('hi',axis._length)+d0 lo = kwds.pop('lo',0)+d0 lo,hi=min(lo,hi),max(lo,hi) drawAtLimit = kwds.pop('drawAtLimit',False) oaglp = axis._get_line_pos if not scaleValue: axis._get_line_pos = lambda x: x try: v = self._v if endOffset: v = v + hi elif startOffset: v = v + lo func = axis._getLineFunc(s-offs,e-offs,kwds.pop('parent',None)) if not hasattr(axis,'_tickValues'): axis._pseudo_configure() d = axis._get_line_pos(v) if dhi: if not drawAtLimit: return None if d0): return c = self.subGridStrokeColor w = self.subGridStrokeWidth or 0 if not(w and c): return s = self.subGridStart e = self.subGridEnd if s is None or e is None: if dim and hasattr(dim,'__call__'): dim = dim() if dim: if s is None: s = dim[0] if e is None: e = dim[1] else: if s is None: s = 0 if e is None: e = 0 if s or e: if self.isYAxis: offs = self._x else: offs = self._y otv = self._calcSubTicks() try: self._makeLines(g,s-offs,e-offs,c,w,self.subGridStrokeDashArray,self.subGridStrokeLineJoin,self.subGridStrokeLineCap,self.subGridStrokeMiterLimit,parent=parent,exclude=exclude) finally: self._tickValues = otv def getGridDims(self,start=None,end=None): if start is None: start = (self._x,self._y)[self.isYAxis] if end is None: end = start+self._length return start,end def isYAxis(self): if getattr(self,'_dataIndex',None)==1: return True acn = self.__class__.__name__ return acn[0]=='Y' or acn[:4]=='AdjY' isYAxis = property(isYAxis) def isXAxis(self): if getattr(self,'_dataIndex',None)==0: return True acn = self.__class__.__name__ return acn[0]=='X' or acn[:11]=='NormalDateX' isXAxis = property(isXAxis) def addAnnotations(self,g,A=None): if A is None: getattr(self,'annotations',[]) for x in A: g.add(x(self)) def _splitAnnotations(self): A = getattr(self,'annotations',[])[:] D = {} for v in ('early','beforeAxis','afterAxis','beforeTicks', 'afterTicks','beforeTickLabels', 'afterTickLabels','late'): R = [].append P = [].append for a in A: if getattr(a,v,0): R(a) else: P(a) D[v] = R.__self__ A[:] = P.__self__ D['late'] += A return D def draw(self): g = Group() A = self._splitAnnotations() self.addAnnotations(g,A['early']) if self.visible: self.addAnnotations(g,A['beforeAxis']) g.add(self.makeAxis()) self.addAnnotations(g,A['afterAxis']) self.addAnnotations(g,A['beforeTicks']) g.add(self.makeTicks()) self.addAnnotations(g,A['afterTicks']) self.addAnnotations(g,A['beforeTickLabels']) g.add(self.makeTickLabels()) self.addAnnotations(g,A['afterTickLabels']) self.addAnnotations(g,A['late']) return g class CALabel(PMVLabel): _attrMap = AttrMap(BASE=PMVLabel, labelPosFrac = AttrMapValue(isNumber, desc='where in the category range [0,1] the labels should be anchored'), ) def __init__(self,**kw): PMVLabel.__init__(self,**kw) self._setKeywords( labelPosFrac = 0.5, ) # Category axes. class CategoryAxis(_AxisG): "Abstract category axis, unusable in itself." _nodoc = 1 _attrMap = AttrMap( visible = AttrMapValue(isBoolean, desc='Display entire object, if true.'), visibleAxis = AttrMapValue(isBoolean, desc='Display axis line, if true.'), visibleTicks = AttrMapValue(isBoolean, desc='Display axis ticks, if true.'), visibleLabels = AttrMapValue(isBoolean, desc='Display axis labels, if true.'), visibleGrid = AttrMapValue(isBoolean, desc='Display axis grid, if true.'), strokeWidth = AttrMapValue(isNumber, desc='Width of axis line and ticks.'), strokeColor = AttrMapValue(isColorOrNone, desc='Color of axis line and ticks.'), strokeDashArray = AttrMapValue(isListOfNumbersOrNone, desc='Dash array used for axis line.'), strokeLineCap = AttrMapValue(OneOf(0,1,2),desc="Line cap 0=butt, 1=round & 2=square"), strokeLineJoin = AttrMapValue(OneOf(0,1,2),desc="Line join 0=miter, 1=round & 2=bevel"), strokeMiterLimit = AttrMapValue(isNumber,desc="miter limit control miter line joins"), gridStrokeWidth = AttrMapValue(isNumber, desc='Width of grid lines.'), gridStrokeColor = AttrMapValue(isColorOrNone, desc='Color of grid lines.'), gridStrokeDashArray = AttrMapValue(isListOfNumbersOrNone, desc='Dash array used for grid lines.'), gridStrokeLineCap = AttrMapValue(OneOf(0,1,2),desc="Grid Line cap 0=butt, 1=round & 2=square"), gridStrokeLineJoin = AttrMapValue(OneOf(0,1,2),desc="Grid Line join 0=miter, 1=round & 2=bevel"), gridStrokeMiterLimit = AttrMapValue(isNumber,desc="Grid miter limit control miter line joins"), gridStart = AttrMapValue(isNumberOrNone, desc='Start of grid lines wrt axis origin'), gridEnd = AttrMapValue(isNumberOrNone, desc='End of grid lines wrt axis origin'), drawGridLast = AttrMapValue(isBoolean, desc='if true draw gridlines after everything else.'), labels = AttrMapValue(None, desc='Handle of the axis labels.'), categoryNames = AttrMapValue(isListOfStringsOrNone, desc='List of category names.'), joinAxis = AttrMapValue(None, desc='Join both axes if true.'), joinAxisPos = AttrMapValue(isNumberOrNone, desc='Position at which to join with other axis.'), reverseDirection = AttrMapValue(isBoolean, desc='If true reverse category direction.'), style = AttrMapValue(OneOf('parallel','stacked','parallel_3d'),"How common category bars are plotted"), labelAxisMode = AttrMapValue(OneOf('high','low','axis', 'axispmv'), desc="Like joinAxisMode, but for the axis labels"), tickShift = AttrMapValue(isBoolean, desc='Tick shift typically'), tickStrokeWidth = AttrMapValue(isNumberOrNone, desc='Width of ticks if specified.'), tickStrokeColor = AttrMapValue(isColorOrNone, desc='Color of ticks if specified.'), loPad = AttrMapValue(isNumber, desc='extra inner space before start of the axis'), hiPad = AttrMapValue(isNumber, desc='extra inner space after end of the axis'), annotations = AttrMapValue(None,desc='list of annotations'), loLLen = AttrMapValue(isNumber, desc='extra line length before start of the axis'), hiLLen = AttrMapValue(isNumber, desc='extra line length after end of the axis'), skipGrid = AttrMapValue(OneOf('none','top','both','bottom'),"grid lines to skip top bottom both none"), innerTickDraw = AttrMapValue(isNoneOrCallable, desc="Callable to replace _drawInnerTicks"), ) def __init__(self): assert self.__class__.__name__!='CategoryAxis', "Abstract Class CategoryAxis Instantiated" # private properties set by methods. The initial values # here are to make demos easy; they would always be # overridden in real life. self._x = 50 self._y = 50 self._length = 100 self._catCount = 0 # public properties self.visible = 1 self.visibleAxis = 1 self.visibleTicks = 1 self.visibleLabels = 1 self.visibleGrid = 0 self.drawGridLast = False self.strokeWidth = 1 self.strokeColor = STATE_DEFAULTS['strokeColor'] self.strokeDashArray = STATE_DEFAULTS['strokeDashArray'] self.gridStrokeLineJoin = self.strokeLineJoin = STATE_DEFAULTS['strokeLineJoin'] self.gridStrokeLineCap = self.strokeLineCap = STATE_DEFAULTS['strokeLineCap'] self.gridStrokeMiterLimit = self.strokeMiterLimit = STATE_DEFAULTS['strokeMiterLimit'] self.gridStrokeWidth = 0.25 self.gridStrokeColor = STATE_DEFAULTS['strokeColor'] self.gridStrokeDashArray = STATE_DEFAULTS['strokeDashArray'] self.gridStart = self.gridEnd = None self.strokeLineJoin = STATE_DEFAULTS['strokeLineJoin'] self.strokeLineCap = STATE_DEFAULTS['strokeLineCap'] self.strokeMiterLimit = STATE_DEFAULTS['strokeMiterLimit'] self.labels = TypedPropertyCollection(CALabel) # if None, they don't get labels. If provided, # you need one name per data point and they are # used for label text. self.categoryNames = None self.joinAxis = None self.joinAxisPos = None self.joinAxisMode = None self.labelAxisMode = 'axis' self.reverseDirection = 0 self.style = 'parallel' #various private things which need to be initialized self._labelTextFormat = None self.tickShift = 0 self.loPad = 0 self.hiPad = 0 self.loLLen = 0 self.hiLLen = 0 def setPosition(self, x, y, length): # ensure floating point self._x = float(x) self._y = float(y) self._length = float(length) def configure(self, multiSeries,barWidth=None): self._catCount = max(list(map(len,multiSeries))) self._barWidth = barWidth or ((self._length-self.loPad-self.hiPad)/float(self._catCount or 1)) self._calcTickmarkPositions() if self.labelAxisMode == 'axispmv': self._pmv = [sum([series[i] for series in multiSeries]) for i in range(self._catCount)] def _calcTickmarkPositions(self): n = self._catCount if self.tickShift: self._tickValues = [t+0.5 for t in range(n)] else: if self.reverseDirection: self._tickValues = list(range(-1,n)) else: self._tickValues = list(range(n+1)) def _scale(self,idx): if self.reverseDirection: idx = self._catCount-idx-1 return idx def scale(self, idx): "Returns the position and width in drawing units" return (self.loScale(idx), self._barWidth) def midScale(self, idx): "Returns the bar mid position in drawing units" return self.loScale(idx) + 0.5*self._barWidth def _assertYAxis(axis): assert axis.isYAxis, "Cannot connect to other axes (%s), but Y- ones." % axis.__class__.__name__ def _assertXAxis(axis): assert axis.isXAxis, "Cannot connect to other axes (%s), but X- ones." % axis.__class__.__name__ class _XTicks: _tickTweaks = 0 #try 0.25-0.5 @property def actualTickStrokeWidth(self): return getattr(self,'tickStrokeWidth',self.strokeWidth) @property def actualTickStrokeColor(self): return getattr(self,'tickStrokeColor',self.strokeColor) def _drawTicksInner(self,tU,tD,g): itd = getattr(self,'innerTickDraw',None) if itd: itd(self,tU,tD,g) elif tU or tD: sW = self.actualTickStrokeWidth tW = self._tickTweaks if tW: if tU and not tD: tD = tW*sW elif tD and not tU: tU = tW*sW self._makeLines(g,tU,-tD,self.actualTickStrokeColor,sW,self.strokeDashArray,self.strokeLineJoin,self.strokeLineCap,self.strokeMiterLimit) def _drawTicks(self,tU,tD,g=None): g = g or Group() if self.visibleTicks: self._drawTicksInner(tU,tD,g) return g def _drawSubTicks(self,tU,tD,g): if getattr(self,'visibleSubTicks',0) and self.subTickNum>0: otv = self._calcSubTicks() try: self._subTicking = 1 self._drawTicksInner(tU,tD,g) finally: del self._subTicking self._tickValues = otv def makeTicks(self): yold=self._y try: self._y = self._labelAxisPos(getattr(self,'tickAxisMode','axis')) g = self._drawTicks(self.tickUp,self.tickDown) self._drawSubTicks(getattr(self,'subTickHi',0),getattr(self,'subTickLo',0),g) return g finally: self._y = yold def _labelAxisPos(self,mode=None): axis = self.joinAxis if axis: mode = mode or self.labelAxisMode if mode == 'low': return axis._y elif mode == 'high': return axis._y + axis._length return self._y class _YTicks(_XTicks): def _labelAxisPos(self,mode=None): axis = self.joinAxis if axis: mode = mode or self.labelAxisMode if mode == 'low': return axis._x elif mode == 'high': return axis._x + axis._length return self._x def makeTicks(self): xold=self._x try: self._x = self._labelAxisPos(getattr(self,'tickAxisMode','axis')) g = self._drawTicks(self.tickRight,self.tickLeft) self._drawSubTicks(getattr(self,'subTickHi',0),getattr(self,'subTickLo',0),g) return g finally: self._x = xold class XCategoryAxis(_XTicks,CategoryAxis): "X/category axis" _attrMap = AttrMap(BASE=CategoryAxis, tickUp = AttrMapValue(isNumber, desc='Tick length up the axis.'), tickDown = AttrMapValue(isNumber, desc='Tick length down the axis.'), joinAxisMode = AttrMapValue(OneOf('bottom', 'top', 'value', 'points', None), desc="Mode used for connecting axis ('bottom', 'top', 'value', 'points', None)."), ) _dataIndex = 0 def __init__(self): CategoryAxis.__init__(self) self.labels.boxAnchor = 'n' #north - top edge self.labels.dy = -5 # ultra-simple tick marks for now go between categories # and have same line style as axis - need more self.tickUp = 0 # how far into chart does tick go? self.tickDown = 5 # how far below axis does tick go? def demo(self): self.setPosition(30, 70, 140) self.configure([(10,20,30,40,50)]) self.categoryNames = ['One','Two','Three','Four','Five'] # all labels top-centre aligned apart from the last self.labels.boxAnchor = 'n' self.labels[4].boxAnchor = 'e' self.labels[4].angle = 90 d = Drawing(200, 100) d.add(self) return d def joinToAxis(self, yAxis, mode='bottom', pos=None): "Join with y-axis using some mode." _assertYAxis(yAxis) if mode == 'bottom': self._y = yAxis._y elif mode == 'top': self._y = yAxis._y + yAxis._length elif mode == 'value': self._y = yAxis.scale(pos) elif mode == 'points': self._y = pos def _joinToAxis(self): ja = self.joinAxis if ja: jam = self.joinAxisMode if jam in ('bottom', 'top'): self.joinToAxis(ja, mode=jam) elif jam in ('value', 'points'): self.joinToAxis(ja, mode=jam, pos=self.joinAxisPos) def loScale(self, idx): """returns the x position in drawing units""" return self._x + self.loPad + self._scale(idx)*self._barWidth def makeAxis(self): g = Group() self._joinToAxis() if not self.visibleAxis: return g axis = Line(self._x-self.loLLen, self._y, self._x + self._length+self.hiLLen, self._y) axis.strokeColor = self.strokeColor axis.strokeWidth = self.strokeWidth axis.strokeDashArray = self.strokeDashArray g.add(axis) return g def makeTickLabels(self): g = Group() if not self.visibleLabels: return g categoryNames = self.categoryNames if categoryNames is not None: catCount = self._catCount n = len(categoryNames) reverseDirection = self.reverseDirection barWidth = self._barWidth _y = self._labelAxisPos() _x = self._x pmv = self._pmv if self.labelAxisMode=='axispmv' else None for i in range(catCount): if reverseDirection: ic = catCount-i-1 else: ic = i if ic>=n: continue label=i-catCount if label in self.labels: label = self.labels[label] else: label = self.labels[i] if pmv: _dy = label.dy v = label._pmv = pmv[ic] if v<0: _dy *= -2 else: _dy = 0 lpf = label.labelPosFrac x = _x + (i+lpf) * barWidth label.setOrigin(x,_y+_dy) label.setText(categoryNames[ic] or '') g.add(label) return g class YCategoryAxis(_YTicks,CategoryAxis): "Y/category axis" _attrMap = AttrMap(BASE=CategoryAxis, tickLeft = AttrMapValue(isNumber, desc='Tick length left of the axis.'), tickRight = AttrMapValue(isNumber, desc='Tick length right of the axis.'), joinAxisMode = AttrMapValue(OneOf(('left', 'right', 'value', 'points', None)), desc="Mode used for connecting axis ('left', 'right', 'value', 'points', None)."), ) _dataIndex = 1 def __init__(self): CategoryAxis.__init__(self) self.labels.boxAnchor = 'e' #east - right edge self.labels.dx = -5 # ultra-simple tick marks for now go between categories # and have same line style as axis - need more self.tickLeft = 5 # how far left of axis does tick go? self.tickRight = 0 # how far right of axis does tick go? def demo(self): self.setPosition(50, 10, 80) self.configure([(10,20,30)]) self.categoryNames = ['One','Two','Three'] # all labels top-centre aligned apart from the last self.labels.boxAnchor = 'e' self.labels[2].boxAnchor = 's' self.labels[2].angle = 90 d = Drawing(200, 100) d.add(self) return d def joinToAxis(self, xAxis, mode='left', pos=None): "Join with x-axis using some mode." _assertXAxis(xAxis) if mode == 'left': self._x = xAxis._x * 1.0 elif mode == 'right': self._x = (xAxis._x + xAxis._length) * 1.0 elif mode == 'value': self._x = xAxis.scale(pos) * 1.0 elif mode == 'points': self._x = pos * 1.0 def _joinToAxis(self): ja = self.joinAxis if ja: jam = self.joinAxisMode if jam in ('left', 'right'): self.joinToAxis(ja, mode=jam) elif jam in ('value', 'points'): self.joinToAxis(ja, mode=jam, pos=self.joinAxisPos) def loScale(self, idx): "Returns the y position in drawing units" return self._y + self._scale(idx)*self._barWidth def makeAxis(self): g = Group() self._joinToAxis() if not self.visibleAxis: return g axis = Line(self._x, self._y-self.loLLen, self._x, self._y + self._length+self.hiLLen) axis.strokeColor = self.strokeColor axis.strokeWidth = self.strokeWidth axis.strokeDashArray = self.strokeDashArray g.add(axis) return g def makeTickLabels(self): g = Group() if not self.visibleLabels: return g categoryNames = self.categoryNames if categoryNames is not None: catCount = self._catCount n = len(categoryNames) reverseDirection = self.reverseDirection barWidth = self._barWidth labels = self.labels _x = self._labelAxisPos() _y = self._y pmv = self._pmv if self.labelAxisMode=='axispmv' else None for i in range(catCount): if reverseDirection: ic = catCount-i-1 else: ic = i if ic>=n: continue label=i-catCount if label in self.labels: label = self.labels[label] else: label = self.labels[i] lpf = label.labelPosFrac y = _y + (i+lpf) * barWidth if pmv: _dx = label.dx v = label._pmv = pmv[ic] if v<0: _dx *= -2 else: _dx = 0 label.setOrigin(_x+_dx, y) label.setText(categoryNames[ic] or '') g.add(label) return g class TickLabeller: '''Abstract base class which may be used to indicate a change in the call signature for callable label formats ''' def __call__(self,axis,value): return 'Abstract class instance called' #this matches the old python str behaviour _defaultLabelFormatter = lambda x: '%.12g' % x # Value axes. class ValueAxis(_AxisG): "Abstract value axis, unusable in itself." _attrMap = AttrMap( forceZero = AttrMapValue(EitherOr((isBoolean,OneOf('near'))), desc='Ensure zero in range if true.'), visible = AttrMapValue(isBoolean, desc='Display entire object, if true.'), visibleAxis = AttrMapValue(isBoolean, desc='Display axis line, if true.'), visibleLabels = AttrMapValue(isBoolean, desc='Display axis labels, if true.'), visibleTicks = AttrMapValue(isBoolean, desc='Display axis ticks, if true.'), visibleGrid = AttrMapValue(isBoolean, desc='Display axis grid, if true.'), strokeWidth = AttrMapValue(isNumber, desc='Width of axis line and ticks.'), strokeColor = AttrMapValue(isColorOrNone, desc='Color of axis line and ticks.'), strokeDashArray = AttrMapValue(isListOfNumbersOrNone, desc='Dash array used for axis line.'), strokeLineCap = AttrMapValue(OneOf(0,1,2),desc="Line cap 0=butt, 1=round & 2=square"), strokeLineJoin = AttrMapValue(OneOf(0,1,2),desc="Line join 0=miter, 1=round & 2=bevel"), strokeMiterLimit = AttrMapValue(isNumber,desc="miter limit control miter line joins"), gridStrokeWidth = AttrMapValue(isNumber, desc='Width of grid lines.'), gridStrokeColor = AttrMapValue(isColorOrNone, desc='Color of grid lines.'), gridStrokeDashArray = AttrMapValue(isListOfNumbersOrNone, desc='Dash array used for grid lines.'), gridStrokeLineCap = AttrMapValue(OneOf(0,1,2),desc="Grid Line cap 0=butt, 1=round & 2=square"), gridStrokeLineJoin = AttrMapValue(OneOf(0,1,2),desc="Grid Line join 0=miter, 1=round & 2=bevel"), gridStrokeMiterLimit = AttrMapValue(isNumber,desc="Grid miter limit control miter line joins"), gridStart = AttrMapValue(isNumberOrNone, desc='Start of grid lines wrt axis origin'), gridEnd = AttrMapValue(isNumberOrNone, desc='End of grid lines wrt axis origin'), drawGridLast = AttrMapValue(isBoolean, desc='if true draw gridlines after everything else.'), minimumTickSpacing = AttrMapValue(isNumber, desc='Minimum value for distance between ticks.'), maximumTicks = AttrMapValue(isNumber, desc='Maximum number of ticks.'), labels = AttrMapValue(None, desc='Handle of the axis labels.'), labelAxisMode = AttrMapValue(OneOf('high','low','axis'), desc="Like joinAxisMode, but for the axis labels"), labelTextFormat = AttrMapValue(None, desc='Formatting string or function used for axis labels.'), labelTextPostFormat = AttrMapValue(None, desc='Extra Formatting string.'), labelTextScale = AttrMapValue(isNumberOrNone, desc='Scaling for label tick values.'), valueMin = AttrMapValue(isNumberOrNone, desc='Minimum value on axis.'), valueMax = AttrMapValue(isNumberOrNone, desc='Maximum value on axis.'), valueStep = AttrMapValue(isNumberOrNone, desc='Step size used between ticks.'), valueSteps = AttrMapValue(isListOfNumbersOrNone, desc='List of step sizes used between ticks.'), avoidBoundFrac = AttrMapValue(EitherOr((isNumberOrNone,SequenceOf(isNumber,emptyOK=0,lo=2,hi=2))), desc='Fraction of interval to allow above and below.'), avoidBoundSpace = AttrMapValue(EitherOr((isNumberOrNone,SequenceOf(isNumber,emptyOK=0,lo=2,hi=2))), desc='Space to allow above and below.'), abf_ignore_zero = AttrMapValue(EitherOr((NoneOr(isBoolean),SequenceOf(isBoolean,emptyOK=0,lo=2,hi=2))), desc='Set to True to make the avoidBoundFrac calculations treat zero as non-special'), rangeRound=AttrMapValue(OneOf('none','both','ceiling','floor'),'How to round the axis limits'), zrangePref = AttrMapValue(isNumberOrNone, desc='Zero range axis limit preference.'), style = AttrMapValue(OneOf('normal','stacked','parallel_3d'),"How values are plotted!"), skipEndL = AttrMapValue(OneOf('none','start','end','both'), desc='Skip high/low tick labels'), origShiftIPC = AttrMapValue(isNumberOrNone, desc='Lowest label shift interval ratio.'), origShiftMin = AttrMapValue(isNumberOrNone, desc='Minimum amount to shift.'), origShiftSpecialValue = AttrMapValue(isNumberOrNone, desc='special value for shift'), tickAxisMode = AttrMapValue(OneOf('high','low','axis'), desc="Like joinAxisMode, but for the ticks"), reverseDirection = AttrMapValue(isBoolean, desc='If true reverse category direction.'), annotations = AttrMapValue(None,desc='list of annotations'), loLLen = AttrMapValue(isNumber, desc='extra line length before start of the axis'), hiLLen = AttrMapValue(isNumber, desc='extra line length after end of the axis'), subTickNum = AttrMapValue(isNumber, desc='Number of axis sub ticks, if >0'), subTickLo = AttrMapValue(isNumber, desc='sub tick down or left'), subTickHi = AttrMapValue(isNumber, desc='sub tick up or right'), visibleSubTicks = AttrMapValue(isBoolean, desc='Display axis sub ticks, if true.'), visibleSubGrid = AttrMapValue(isBoolean, desc='Display axis sub grid, if true.'), subGridStrokeWidth = AttrMapValue(isNumber, desc='Width of grid lines.'), subGridStrokeColor = AttrMapValue(isColorOrNone, desc='Color of grid lines.'), subGridStrokeDashArray = AttrMapValue(isListOfNumbersOrNone, desc='Dash array used for grid lines.'), subGridStrokeLineCap = AttrMapValue(OneOf(0,1,2),desc="Grid Line cap 0=butt, 1=round & 2=square"), subGridStrokeLineJoin = AttrMapValue(OneOf(0,1,2),desc="Grid Line join 0=miter, 1=round & 2=bevel"), subGridStrokeMiterLimit = AttrMapValue(isNumber,desc="Grid miter limit control miter line joins"), subGridStart = AttrMapValue(isNumberOrNone, desc='Start of grid lines wrt axis origin'), subGridEnd = AttrMapValue(isNumberOrNone, desc='End of grid lines wrt axis origin'), tickStrokeWidth = AttrMapValue(isNumber, desc='Width of ticks if specified.'), subTickStrokeWidth = AttrMapValue(isNumber, desc='Width of sub ticks if specified.'), subTickStrokeColor = AttrMapValue(isColorOrNone, desc='Color of sub ticks if specified.'), tickStrokeColor = AttrMapValue(isColorOrNone, desc='Color of ticks if specified.'), keepTickLabelsInside = AttrMapValue(isBoolean, desc='Ensure tick labels do not project beyond bounds of axis if true'), skipGrid = AttrMapValue(OneOf('none','top','both','bottom'),"grid lines to skip top bottom both none"), requiredRange = AttrMapValue(isNumberOrNone, desc='Minimum required value range.'), innerTickDraw = AttrMapValue(isNoneOrCallable, desc="Callable to replace _drawInnerTicks"), extraMinMaxValues = AttrMapValue(isListOfNumbersOrNone, desc='extra values to use in min max calculation'), ) def __init__(self,**kw): assert self.__class__.__name__!='ValueAxis', 'Abstract Class ValueAxis Instantiated' self._setKeywords(**kw) self._setKeywords( _configured = 0, # private properties set by methods. The initial values # here are to make demos easy; they would always be # overridden in real life. _x = 50, _y = 50, _length = 100, # public properties visible = 1, visibleAxis = 1, visibleLabels = 1, visibleTicks = 1, visibleGrid = 0, forceZero = 0, strokeWidth = 1, strokeColor = STATE_DEFAULTS['strokeColor'], strokeDashArray = STATE_DEFAULTS['strokeDashArray'], strokeLineJoin = STATE_DEFAULTS['strokeLineJoin'], strokeLineCap = STATE_DEFAULTS['strokeLineCap'], strokeMiterLimit = STATE_DEFAULTS['strokeMiterLimit'], gridStrokeWidth = 0.25, gridStrokeColor = STATE_DEFAULTS['strokeColor'], gridStrokeDashArray = STATE_DEFAULTS['strokeDashArray'], gridStrokeLineJoin = STATE_DEFAULTS['strokeLineJoin'], gridStrokeLineCap = STATE_DEFAULTS['strokeLineCap'], gridStrokeMiterLimit = STATE_DEFAULTS['strokeMiterLimit'], gridStart = None, gridEnd = None, drawGridLast = False, visibleSubGrid = 0, visibleSubTicks = 0, subTickNum = 0, subTickLo = 0, subTickHi = 0, subGridStrokeLineJoin = STATE_DEFAULTS['strokeLineJoin'], subGridStrokeLineCap = STATE_DEFAULTS['strokeLineCap'], subGridStrokeMiterLimit = STATE_DEFAULTS['strokeMiterLimit'], subGridStrokeWidth = 0.25, subGridStrokeColor = STATE_DEFAULTS['strokeColor'], subGridStrokeDashArray = STATE_DEFAULTS['strokeDashArray'], subGridStart = None, subGridEnd = None, labels = TypedPropertyCollection(Label), keepTickLabelsInside = 0, # how close can the ticks be? minimumTickSpacing = 10, maximumTicks = 7, # a format string like '%0.2f' # or a function which takes the value as an argument and returns a string _labelTextFormat = None, labelAxisMode = 'axis', labelTextFormat = None, labelTextPostFormat = None, labelTextScale = None, # if set to None, these will be worked out for you. # if you override any or all of them, your values # will be used. valueMin = None, valueMax = None, valueStep = None, avoidBoundFrac = None, avoidBoundSpace = None, abf_ignore_zero = False, rangeRound = 'none', zrangePref = 0, style = 'normal', skipEndL='none', origShiftIPC = None, origShiftMin = None, origShiftSpecialValue = None, tickAxisMode = 'axis', reverseDirection=0, loLLen=0, hiLLen=0, requiredRange=0, extraMinMaxValues=None, ) self.labels.angle = 0 def setPosition(self, x, y, length): # ensure floating point self._x = float(x) self._y = float(y) self._length = float(length) def configure(self, dataSeries): """Let the axis configure its scale and range based on the data. Called after setPosition. Let it look at a list of lists of numbers determine the tick mark intervals. If valueMin, valueMax and valueStep are configured then it will use them; if any of them are set to None it will look at the data and make some sensible decision. You may override this to build custom axes with irregular intervals. It creates an internal variable self._values, which is a list of numbers to use in plotting. """ self._setRange(dataSeries) self._configure_end() def _configure_end(self): self._calcTickmarkPositions() self._calcScaleFactor() self._configured = 1 def _getValueStepAndTicks(self, valueMin, valueMax,cache={}): try: K = (valueMin,valueMax) r = cache[K] except: self._valueMin = valueMin self._valueMax = valueMax valueStep,T = self._calcStepAndTickPositions() r = cache[K] = valueStep, T, valueStep*1e-8 return r def _preRangeAdjust(self,valueMin,valueMax): rr = self.requiredRange if rr>0: r = valueMax - valueMin if r=100 and y1<100: y2 = y2 + 100 - y1 y1 = 100 elif valueMin>=0 and y1<0: y2 = y2 - y1 y1 = 0 valueMin = self._cValueMin = y1 valueMax = self._cValueMax = y2 return valueMin,valueMax def _setRange(self, dataSeries): """Set minimum and maximum axis values. The dataSeries argument is assumed to be a list of data vectors. Each vector is itself a list or tuple of numbers. Returns a min, max tuple. """ oMin = valueMin = self.valueMin oMax = valueMax = self.valueMax if valueMin is None: valueMin = self._cValueMin = _findMin(dataSeries,self._dataIndex,0, self.extraMinMaxValues) if valueMax is None: valueMax = self._cValueMax = _findMax(dataSeries,self._dataIndex,0, self.extraMinMaxValues) if valueMin == valueMax: if valueMax==0: if oMin is None and oMax is None: zrp = getattr(self,'zrangePref',0) if zrp>0: valueMax = zrp valueMin = 0 elif zrp<0: valueMax = 0 valueMin = zrp else: valueMax = 0.01 valueMin = -0.01 elif self.valueMin is None: valueMin = -0.01 else: valueMax = 0.01 else: if valueMax>0: valueMax = 1.2*valueMax valueMin = 0.0 else: valueMax = 0.0 valueMin = 1.2*valueMin if getattr(self,'_bubblePlot',None): bubbleMax = float(_findMax(dataSeries,2,0)) frac=.25 bubbleV=frac*(valueMax-valueMin) self._bubbleV = bubbleV self._bubbleMax = bubbleMax self._bubbleRadius = frac*self._length def special(T,x,func,bubbleV=bubbleV,bubbleMax=bubbleMax): try: v = T[2] except IndexError: v = bubbleMAx*0.1 bubbleV *= (v/bubbleMax)**0.5 return func(T[x]+bubbleV,T[x]-bubbleV) if oMin is None: valueMin = self._cValueMin = _findMin(dataSeries,self._dataIndex,0,special=special,extraMinMaxValues=self.extraMinMaxValues) if oMax is None: valueMax = self._cValueMax = _findMax(dataSeries,self._dataIndex,0,special=special,extraMinMaxValues=self.extraMinMaxValues) valueMin, valueMax = self._preRangeAdjust(valueMin,valueMax) rangeRound = self.rangeRound cMin = valueMin cMax = valueMax forceZero = self.forceZero if forceZero: if forceZero=='near': forceZero = min(abs(valueMin),abs(valueMax)) <= 5*(valueMax-valueMin) if forceZero: if valueMax<0: valueMax=0 elif valueMin>0: valueMin = 0 abf = self.avoidBoundFrac do_rr = not getattr(self,'valueSteps',None) do_abf = abf and do_rr if not isSeq(abf): abf = abf, abf abfiz = getattr(self,'abf_ignore_zero', False) if not isSeq(abfiz): abfiz = abfiz, abfiz do_rr = rangeRound != 'none' and do_rr if do_rr: rrn = rangeRound in ['both','floor'] rrx = rangeRound in ['both','ceiling'] else: rrn = rrx = 0 abS = self.avoidBoundSpace do_abs = abS if do_abs: if not isSeq(abS): abS = abS, abS aL = float(self._length) go = do_rr or do_abf or do_abs cache = {} iter = 0 while go and iter<=10: iter += 1 go = 0 if do_abf or do_abs: valueStep, T, fuzz = self._getValueStepAndTicks(valueMin, valueMax, cache) if do_abf: i0 = valueStep*abf[0] i1 = valueStep*abf[1] else: i0 = i1 = 0 if do_abs: sf = (valueMax-valueMin)/aL i0 = max(i0,abS[0]*sf) i1 = max(i1,abS[1]*sf) if rrn: v = T[0] else: v = valueMin u = cMin-i0 if (abfiz[0] or abs(v)>fuzz) and v>=u+fuzz: valueMin = u go = 1 if rrx: v = T[-1] else: v = valueMax u = cMax+i1 if (abfiz[1] or abs(v)>fuzz) and v<=u-fuzz: valueMax = u go = 1 if do_rr: valueStep, T, fuzz = self._getValueStepAndTicks(valueMin, valueMax, cache) if rrn: if valueMin=T[0]+fuzz valueMin = T[0] if rrx: if valueMax>T[-1]+fuzz: valueMax = T[-1]+valueStep go = 1 else: go = valueMax<=T[-1]-fuzz valueMax = T[-1] if iter and not go: self._computedValueStep = valueStep else: self._computedValueStep = None self._valueMin = valueMin self._valueMax = valueMax origShiftIPC = self.origShiftIPC origShiftMin = self.origShiftMin if origShiftMin is not None or origShiftIPC is not None: origShiftSpecialValue = self.origShiftSpecialValue self._calcValueStep() valueMax, valueMin = self._valueMax, self._valueMin if origShiftSpecialValue is None or abs(origShiftSpecialValue-valueMin)<1e-6: if origShiftIPC: m = origShiftIPC*self._valueStep else: m = 0 if origShiftMin: m = max(m,(valueMax-valueMin)*origShiftMin/self._length) self._valueMin -= m self._rangeAdjust() def _pseudo_configure(self): self._valueMin = self.valueMin self._valueMax = self.valueMax if hasattr(self,'_subTickValues'): del self._subTickValues self._configure_end() def _rangeAdjust(self): """Override this if you want to alter the calculated range. E.g. if want a minumamum range of 30% or don't want 100% as the first point. """ pass def _adjustAxisTicks(self): '''Override if you want to put slack at the ends of the axis eg if you don't want the last tick to be at the bottom etc ''' pass def _calcScaleFactor(self): """Calculate the axis' scale factor. This should be called only *after* the axis' range is set. Returns a number. """ self._scaleFactor = self._length / float(self._valueMax - self._valueMin) return self._scaleFactor def _calcStepAndTickPositions(self): valueStep = getattr(self,'_computedValueStep',None) if valueStep: del self._computedValueStep self._valueStep = valueStep else: self._calcValueStep() valueStep = self._valueStep valueMin = self._valueMin valueMax = self._valueMax fuzz = 1e-8*valueStep rangeRound = self.rangeRound i0 = int(float(valueMin)/valueStep) v = i0*valueStep if rangeRound in ('both','floor'): if v>valueMin+fuzz: i0 -= 1 elif vvalueMax+fuzz: i1 -= 1 return valueStep,[i*valueStep for i in range(i0,i1+1)] def _calcTickPositions(self): return self._calcStepAndTickPositions()[1] def _calcSubTicks(self): if not hasattr(self,'_tickValues'): self._pseudo_configure() otv = self._tickValues if not hasattr(self,'_subTickValues'): acn = self.__class__.__name__ if acn[:11]=='NormalDateX': iFuzz = 0 dCnv = int else: iFuzz = 1e-8 dCnv = lambda x:x OTV = [tv for tv in otv if getattr(tv,'_doSubTicks',1)] T = [].append nst = int(self.subTickNum) i = len(OTV) if i<2: self._subTickValues = [] else: if i==2: dst = OTV[1]-OTV[0] elif i==3: dst = max(OTV[1]-OTV[0],OTV[2]-OTV[1]) else: i >>= 1 dst = OTV[i+1] - OTV[i] fuzz = dst*iFuzz vn = self._valueMin+fuzz vx = self._valueMax-fuzz if OTV[0]>vn: OTV.insert(0,OTV[0]-dst) if OTV[-1]=vx: continue T(t) self._subTickValues = T.__self__ self._tickValues = self._subTickValues return otv def _calcTickmarkPositions(self): """Calculate a list of tick positions on the axis. Returns a list of numbers.""" self._tickValues = getattr(self,'valueSteps',None) if self._tickValues: return self._tickValues self._tickValues = self._calcTickPositions() self._adjustAxisTicks() return self._tickValues def _calcValueStep(self): '''Calculate _valueStep for the axis or get from valueStep.''' if self.valueStep is None: rawRange = self._valueMax - self._valueMin rawInterval = rawRange / min(float(self.maximumTicks-1),(float(self._length)/self.minimumTickSpacing)) self._valueStep = nextRoundNumber(rawInterval) else: self._valueStep = self.valueStep def _allIntTicks(self): return _allInt(self._tickValues) def makeTickLabels(self): g = Group() if not self.visibleLabels: return g f = self._labelTextFormat # perhaps someone already set it if f is None: f = self.labelTextFormat or (self._allIntTicks() and '%.0f' or _defaultLabelFormatter) elif f is str and self._allIntTicks(): f = '%.0f' elif hasattr(f,'calcPlaces'): f.calcPlaces(self._tickValues) post = self.labelTextPostFormat scl = self.labelTextScale pos = [self._x, self._y] d = self._dataIndex pos[1-d] = self._labelAxisPos() labels = self.labels if self.skipEndL!='none': if self.isXAxis: sk = self._x else: sk = self._y if self.skipEndL=='start': sk = [sk] else: sk = [sk,sk+self._length] if self.skipEndL=='end': del sk[0] else: sk = [] nticks = len(self._tickValues) nticks1 = nticks - 1 for i,tick in enumerate(self._tickValues): label = i-nticks if label in labels: label = labels[label] else: label = labels[i] if f and label.visible: v = self.scale(tick) if sk: for skv in sk: if abs(skv-v)<1e-6: v = None break if v is not None: if scl is not None: t = tick*scl else: t = tick if isinstance(f, str): txt = f % t elif isSeq(f): #it's a list, use as many items as we get if i < len(f): txt = f[i] else: txt = '' elif hasattr(f,'__call__'): if isinstance(f,TickLabeller): txt = f(self,t) else: txt = f(t) else: raise ValueError('Invalid labelTextFormat %s' % f) if post: txt = post % txt pos[d] = v label.setOrigin(*pos) label.setText(txt) #special property to ensure a label doesn't project beyond the bounds of an x-axis if self.keepTickLabelsInside: if isinstance(self, XValueAxis): #not done yet for y axes a_x = self._x if not i: #first one x0, y0, x1, y1 = label.getBounds() if x0 < a_x: label = label.clone(dx=label.dx + a_x - x0) if i==nticks1: #final one a_x1 = a_x +self._length x0, y0, x1, y1 = label.getBounds() if x1 > a_x1: label=label.clone(dx=label.dx-x1+a_x1) g.add(label) return g def scale(self, value): """Converts a numeric value to a plotarea position. The chart first configures the axis, then asks it to """ assert self._configured, "Axis cannot scale numbers before it is configured" if value is None: value = 0 #this could be made more efficient by moving the definition of org and sf into the configuration org = (self._x, self._y)[self._dataIndex] sf = self._scaleFactor if self.reverseDirection: sf = -sf org += self._length return org + sf*(value - self._valueMin) class XValueAxis(_XTicks,ValueAxis): "X/value axis" _attrMap = AttrMap(BASE=ValueAxis, tickUp = AttrMapValue(isNumber, desc='Tick length up the axis.'), tickDown = AttrMapValue(isNumber, desc='Tick length down the axis.'), joinAxis = AttrMapValue(None, desc='Join both axes if true.'), joinAxisMode = AttrMapValue(OneOf('bottom', 'top', 'value', 'points', None), desc="Mode used for connecting axis ('bottom', 'top', 'value', 'points', None)."), joinAxisPos = AttrMapValue(isNumberOrNone, desc='Position at which to join with other axis.'), ) # Indicate the dimension of the data we're interested in. _dataIndex = 0 def __init__(self,**kw): ValueAxis.__init__(self,**kw) self.labels.boxAnchor = 'n' self.labels.dx = 0 self.labels.dy = -5 self.tickUp = 0 self.tickDown = 5 self.joinAxis = None self.joinAxisMode = None self.joinAxisPos = None def demo(self): self.setPosition(20, 50, 150) self.configure([(10,20,30,40,50)]) d = Drawing(200, 100) d.add(self) return d def joinToAxis(self, yAxis, mode='bottom', pos=None): "Join with y-axis using some mode." _assertYAxis(yAxis) if mode == 'bottom': self._y = yAxis._y * 1.0 elif mode == 'top': self._y = (yAxis._y + yAxis._length) * 1.0 elif mode == 'value': self._y = yAxis.scale(pos) * 1.0 elif mode == 'points': self._y = pos * 1.0 def _joinToAxis(self): ja = self.joinAxis if ja: jam = self.joinAxisMode or 'bottom' if jam in ('bottom', 'top'): self.joinToAxis(ja, mode=jam) elif jam in ('value', 'points'): self.joinToAxis(ja, mode=jam, pos=self.joinAxisPos) def makeAxis(self): g = Group() self._joinToAxis() if not self.visibleAxis: return g axis = Line(self._x-self.loLLen, self._y, self._x + self._length+self.hiLLen, self._y) axis.strokeColor = self.strokeColor axis.strokeWidth = self.strokeWidth axis.strokeDashArray = self.strokeDashArray g.add(axis) return g #additional utilities to help specify calendar dates on which tick marks #are to be plotted. After some thought, when the magic algorithm fails, #we can let them specify a number of days-of-the-year to tick in any given #year. ################################################################################# # # Preliminary support objects/functions for the axis used in time series charts # ################################################################################# _months = ['jan','feb','mar','apr','may','jun','jul','aug','sep','oct','nov','dec'] _maxDays = [31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31] def parseDayAndMonth(dmstr): """This accepts and validates strings like "31-Dec" i.e. dates of no particular year. 29 Feb is allowed. These can be used for recurring dates. It returns a (dd, mm) pair where mm is the month integer. If the text is not valid it raises an error. """ dstr, mstr = dmstr.split('-') dd = int(dstr) mstr = mstr.lower() mm = _months.index(mstr) + 1 assert dd <= _maxDays[mm-1] return (dd, mm) class _isListOfDaysAndMonths(Validator): """This accepts and validates lists of strings like "31-Dec" i.e. dates of no particular year. 29 Feb is allowed. These can be used for recurring dates. """ def test(self,x): if isSeq(x): answer = True for element in x: try: dd, mm = parseDayAndMonth(element) except: answer = False return answer else: return False def normalize(self,x): #we store them as presented, it's the most presentable way return x isListOfDaysAndMonths = _isListOfDaysAndMonths() _NDINTM = 1,2,3,6,12,24,60,120,180,240,300,360,420,480,540,600,720,840,960,1080,1200,2400 class NormalDateXValueAxis(XValueAxis): """An X axis applying additional rules. Depending on the data and some built-in rules, the axis displays normalDate values as nicely formatted dates. The client chart should have NormalDate X values. """ _attrMap = AttrMap(BASE = XValueAxis, bottomAxisLabelSlack = AttrMapValue(isNumber, desc="Fractional amount used to adjust label spacing"), niceMonth = AttrMapValue(isBoolean, desc="Flag for displaying months 'nicely'."), forceEndDate = AttrMapValue(isBoolean, desc='Flag for enforced displaying of last date value.'), forceFirstDate = AttrMapValue(isBoolean, desc='Flag for enforced displaying of first date value.'), forceDatesEachYear = AttrMapValue(isListOfDaysAndMonths, desc='List of dates in format "31-Dec",' + '"1-Jan". If present they will always be used for tick marks in the current year, rather ' + 'than the dates chosen by the automatic algorithm. Hyphen compulsory, case of month optional.'), xLabelFormat = AttrMapValue(None, desc="Label format string (e.g. '{mm}/{yy}') or function."), dayOfWeekName = AttrMapValue(SequenceOf(isString,emptyOK=0,lo=7,hi=7), desc='Weekday names.'), monthName = AttrMapValue(SequenceOf(isString,emptyOK=0,lo=12,hi=12), desc='Month names.'), dailyFreq = AttrMapValue(isBoolean, desc='True if we are to assume daily data to be ticked at end of month.'), specifiedTickDates = AttrMapValue(NoneOr(SequenceOf(isNormalDate)), desc='Actual tick values to use; no calculations done'), specialTickClear = AttrMapValue(isBoolean, desc='clear rather than delete close ticks when forced first/end dates'), skipGrid = AttrMapValue(OneOf('none','top','both','bottom'),"grid lines to skip top bottom both none"), ) _valueClass = normalDate.ND def __init__(self,**kw): XValueAxis.__init__(self,**kw) # some global variables still used... self.bottomAxisLabelSlack = 0.1 self.niceMonth = 1 self.forceEndDate = 0 self.forceFirstDate = 0 self.forceDatesEachYear = [] self.dailyFreq = 0 self.xLabelFormat = "{mm}/{yy}" self.dayOfWeekName = ['Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday', 'Sunday'] self.monthName = ['January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December'] self.specialTickClear = 0 self.valueSteps = self.specifiedTickDates = None def _scalar2ND(self, x): "Convert a scalar to a NormalDate value." d = self._valueClass() d.normalize(x) return d def _dateFormatter(self, v): "Create a formatted label for some value." if not isinstance(v,normalDate.NormalDate): v = self._scalar2ND(v) d, m = normalDate._dayOfWeekName, normalDate._monthName try: normalDate._dayOfWeekName, normalDate._monthName = self.dayOfWeekName, self.monthName return v.formatMS(self.xLabelFormat) finally: normalDate._dayOfWeekName, normalDate._monthName = d, m def _xAxisTicker(self, xVals): """Complex stuff... Needs explanation... Yes please says Andy :-(. Modified on 19 June 2006 to attempt to allow a mode where one can specify recurring days and months. """ VC = self._valueClass axisLength = self._length formatter = self._dateFormatter if isinstance(formatter,TickLabeller): def formatter(tick): return self._dateFormatter(self,tick) firstDate = xVals[0] if not self.valueMin else VC(self.valueMin) endDate = xVals[-1] if not self.valueMax else VC(self.valueMax) labels = self.labels fontName, fontSize, leading = labels.fontName, labels.fontSize, labels.leading textAnchor, boxAnchor, angle = labels.textAnchor, labels.boxAnchor, labels.angle RBL = _textBoxLimits(formatter(firstDate).split('\n'),fontName, fontSize,leading or 1.2*fontSize,textAnchor,boxAnchor) RBL = _rotatedBoxLimits(RBL[0],RBL[1],RBL[2],RBL[3], angle) xLabelW = RBL[1]-RBL[0] xLabelH = RBL[3]-RBL[2] w = max(xLabelW,labels.width or 0,self.minimumTickSpacing) W = w+w*self.bottomAxisLabelSlack ticks = [] labels = [] maximumTicks = self.maximumTicks if self.specifiedTickDates: ticks = [VC(x) for x in self.specifiedTickDates] labels = [formatter(d) for d in ticks] if self.forceFirstDate and firstDate==ticks[0] and (axisLength/float(ticks[-1]-ticks[0]))*(ticks[1]-ticks[0])<=W: if self.specialTickClear: labels[1] = '' else: del ticks[1], labels[1] if self.forceEndDate and endDate==ticks[-1] and (axisLength/float(ticks[-1]-ticks[0]))*(ticks[-1]-ticks[-2])<=W: if self.specialTickClear: labels[-2] = '' else: del ticks[-2], labels[-2] return ticks, labels #AR 20060619 - first we try the approach where the user has explicitly #specified the days of year to be ticked. Other explicit routes may #be added. if self.forceDatesEachYear: forcedPartialDates = list(map(parseDayAndMonth, self.forceDatesEachYear)) #generate the list of dates in the range. #print 'dates range from %s to %s' % (firstDate, endDate) firstYear = firstDate.year() lastYear = endDate.year() ticks = [] labels = [] yyyy = firstYear #generate all forced dates between the year it starts and the year it #ends, adding them if within range. while yyyy <= lastYear: for (dd, mm) in forcedPartialDates: theDate = normalDate.ND((yyyy, mm, dd)) if theDate >= firstDate and theDate <= endDate: ticks.append(theDate) labels.append(formatter(theDate)) yyyy += 1 #first and last may still be forced in. if self.forceFirstDate and firstDate!=ticks[0]: ticks.insert(0, firstDate) labels.insert(0,formatter(firstDate)) if (axisLength/float(ticks[-1]-ticks[0]))*(ticks[1]-ticks[0])<=W: if self.specialTickClear: labels[1] = '' else: del ticks[1], labels[1] if self.forceEndDate and endDate!=ticks[-1]: ticks.append(endDate) labels.append(formatter(endDate)) if (axisLength/float(ticks[-1]-ticks[0]))*(ticks[-1]-ticks[-2])<=W: if self.specialTickClear: labels[-2] = '' else: del ticks[-2], labels[-2] #print 'xVals found on forced dates =', ticks return ticks, labels def addTick(i, xVals=xVals, formatter=formatter, ticks=ticks, labels=labels): ticks.insert(0,xVals[i]) labels.insert(0,formatter(xVals[i])) n = len(xVals) #otherwise, we apply the 'magic algorithm...' which looks for nice spacing #based on the size and separation of the labels. for d in _NDINTM: k = n/d if k<=maximumTicks and k*W <= axisLength: i = n-1 if self.niceMonth: j = endDate.month() % (d<=12 and d or 12) if j: if self.forceEndDate: addTick(i) ticks[0]._doSubTicks=0 i -= j #weird first date ie not at end of month try: wfd = firstDate.month() == xVals[1].month() except: wfd = 0 while i>=wfd: addTick(i) i -= d if self.forceFirstDate and ticks[0]!=firstDate: addTick(0) ticks[0]._doSubTicks=0 if (axisLength/float(ticks[-1]-ticks[0]))*(ticks[1]-ticks[0])<=W: if self.specialTickClear: labels[1] = '' else: del ticks[1], labels[1] if self.forceEndDate and self.niceMonth and j: if (axisLength/float(ticks[-1]-ticks[0]))*(ticks[-1]-ticks[-2])<=W: if self.specialTickClear: labels[-2] = '' else: del ticks[-2], labels[-2] try: if labels[0] and labels[0]==labels[1]: del ticks[1], labels[1] except IndexError: pass return ticks, labels raise ValueError('Problem selecting NormalDate value axis tick positions') def _convertXV(self,data): '''Convert all XValues to a standard normalDate type''' VC = self._valueClass for D in data: for i in range(len(D)): x, y = D[i] if not isinstance(x,VC): D[i] = (VC(x),y) def _getStepsAndLabels(self,xVals): if self.dailyFreq: xEOM = [] pm = 0 px = xVals[0] for x in xVals: m = x.month() if pm!=m: if pm: xEOM.append(px) pm = m px = x px = xVals[-1] if xEOM[-1]!=x: xEOM.append(px) steps, labels = self._xAxisTicker(xEOM) else: steps, labels = self._xAxisTicker(xVals) return steps, labels def configure(self, data): self._convertXV(data) xVals = set() for x in data: for dv in x: xVals.add(dv[0]) xVals = list(xVals) xVals.sort() VC = self._valueClass steps,labels = self._getStepsAndLabels(xVals) valueMin, valueMax = self.valueMin, self.valueMax valueMin = xVals[0] if valueMin is None else VC(valueMin) valueMax = xVals[-1] if valueMax is None else VC(valueMax) self._valueMin, self._valueMax = valueMin, valueMax self._tickValues = steps self._labelTextFormat = labels self._scaleFactor = self._length / float(valueMax - valueMin) self._tickValues = steps self._configured = 1 class YValueAxis(_YTicks,ValueAxis): "Y/value axis" _attrMap = AttrMap(BASE=ValueAxis, tickLeft = AttrMapValue(isNumber, desc='Tick length left of the axis.'), tickRight = AttrMapValue(isNumber, desc='Tick length right of the axis.'), joinAxis = AttrMapValue(None, desc='Join both axes if true.'), joinAxisMode = AttrMapValue(OneOf(('left', 'right', 'value', 'points', None)), desc="Mode used for connecting axis ('left', 'right', 'value', 'points', None)."), joinAxisPos = AttrMapValue(isNumberOrNone, desc='Position at which to join with other axis.'), ) # Indicate the dimension of the data we're interested in. _dataIndex = 1 def __init__(self): ValueAxis.__init__(self) self.labels.boxAnchor = 'e' self.labels.dx = -5 self.labels.dy = 0 self.tickRight = 0 self.tickLeft = 5 self.joinAxis = None self.joinAxisMode = None self.joinAxisPos = None def demo(self): data = [(10, 20, 30, 42)] self.setPosition(100, 10, 80) self.configure(data) drawing = Drawing(200, 100) drawing.add(self) return drawing def joinToAxis(self, xAxis, mode='left', pos=None): "Join with x-axis using some mode." _assertXAxis(xAxis) if mode == 'left': self._x = xAxis._x * 1.0 elif mode == 'right': self._x = (xAxis._x + xAxis._length) * 1.0 elif mode == 'value': self._x = xAxis.scale(pos) * 1.0 elif mode == 'points': self._x = pos * 1.0 def _joinToAxis(self): ja = self.joinAxis if ja: jam = self.joinAxisMode if jam in ('left', 'right'): self.joinToAxis(ja, mode=jam) elif jam in ('value', 'points'): self.joinToAxis(ja, mode=jam, pos=self.joinAxisPos) def makeAxis(self): g = Group() self._joinToAxis() if not self.visibleAxis: return g axis = Line(self._x, self._y-self.loLLen, self._x, self._y + self._length+self.hiLLen) axis.strokeColor = self.strokeColor axis.strokeWidth = self.strokeWidth axis.strokeDashArray = self.strokeDashArray g.add(axis) return g class TimeValueAxis: _mc = 60 _hc = 60*_mc _dc = 24*_hc def __init__(self,*args,**kwds): if not self.labelTextFormat: self.labelTextFormat = self.timeLabelTextFormatter self._saved_tickInfo = {} def _calcValueStep(self): '''Calculate _valueStep for the axis or get from valueStep.''' if self.valueStep is None: rawRange = self._valueMax - self._valueMin rawInterval = rawRange / min(float(self.maximumTicks-1),(float(self._length)/self.minimumTickSpacing)) #here's where we try to choose the correct value for the unit if rawInterval >= self._dc: d = self._dc self._unit = 'days' elif rawInterval >= self._hc: d = self._hc self._unit = 'hours' elif rawInterval >= self._mc: d = self._mc self._unit = 'minutes' else: d = 1 self._unit = 'seconds' self._unitd = d if d>1: rawInterval = int(rawInterval/d) self._valueStep = nextRoundNumber(rawInterval) * d else: self._valueStep = self.valueStep def timeLabelTextFormatter(self,val): u = self._unitd k = (u,tuple(self._tickValues)) if k in self._saved_tickInfo: fmt = self._saved_tickInfo[k] else: uf = float(u) tv = [v/uf for v in self._tickValues] s = self._unit[0] if _allInt(tv): fmt = lambda x, uf=uf, s=s: '%.0f%s' % (x/uf,s) else: stv = ['%.10f' % v for v in tv] stvl = max((len(v.rstrip('0'))-v.index('.')-1) for v in stv) if u==1: fmt = lambda x,uf=uf,fmt='%%.%dfs' % stvl: fmt % (x/uf) else: #see if we can represent fractions fm = 24 if u==self._dc else 60 fv = [(v - int(v))*fm for v in tv] if _allInt(fv): s1 = 'h' if u==self._dc else ('m' if u==self._mc else 's') fmt = lambda x,uf=uf,fm=fm, fmt='%%d%s%%d%%s' % (s,s1): fmt % (int(x/uf),int((x/uf - int(x/uf))*fm)) else: fmt = lambda x,uf=uf,fmt='%%.%df%s' % (stvl,s): fmt % (x/uf) self._saved_tickInfo[k] = fmt return fmt(val) class XTimeValueAxis(TimeValueAxis,XValueAxis): def __init__(self,*args,**kwds): XValueAxis.__init__(self,*args,**kwds) TimeValueAxis.__init__(self,*args,**kwds) class AdjYValueAxis(YValueAxis): """A Y-axis applying additional rules. Depending on the data and some built-in rules, the axis may choose to adjust its range and origin. """ _attrMap = AttrMap(BASE = YValueAxis, leftAxisPercent = AttrMapValue(isBoolean, desc='When true add percent sign to label values.'), leftAxisOrigShiftIPC = AttrMapValue(isNumber, desc='Lowest label shift interval ratio.'), leftAxisOrigShiftMin = AttrMapValue(isNumber, desc='Minimum amount to shift.'), leftAxisSkipLL0 = AttrMapValue(EitherOr((isBoolean,isListOfNumbers)), desc='Skip/Keep lowest tick label when true/false.\nOr skiplist'), labelVOffset = AttrMapValue(isNumber, desc='add this to the labels'), ) def __init__(self,**kw): YValueAxis.__init__(self,**kw) self.requiredRange = 30 self.leftAxisPercent = 1 self.leftAxisOrigShiftIPC = 0.15 self.leftAxisOrigShiftMin = 12 self.leftAxisSkipLL0 = self.labelVOffset = 0 self.valueSteps = None def _rangeAdjust(self): "Adjusts the value range of the axis." from reportlab.graphics.charts.utils import find_good_grid, ticks y_min, y_max = self._valueMin, self._valueMax m = self.maximumTicks n = list(filter(lambda x,m=m: x<=m,[4,5,6,7,8,9])) if not n: n = [m] valueStep, requiredRange = self.valueStep, self.requiredRange if requiredRange and y_max - y_min < requiredRange: y1, y2 = find_good_grid(y_min, y_max,n=n,grid=valueStep)[:2] if y2 - y1 < requiredRange: ym = (y1+y2)*0.5 y1 = min(ym-requiredRange*0.5,y_min) y2 = max(ym+requiredRange*0.5,y_max) if y_min>=100 and y1<100: y2 = y2 + 100 - y1 y1 = 100 elif y_min>=0 and y1<0: y2 = y2 - y1 y1 = 0 self._valueMin, self._valueMax = y1, y2 T, L = ticks(self._valueMin, self._valueMax, split=1, n=n, percent=self.leftAxisPercent,grid=valueStep, labelVOffset=self.labelVOffset) abf = self.avoidBoundFrac if abf: i1 = (T[1]-T[0]) if not isSeq(abf): i0 = i1 = i1*abf else: i0 = i1*abf[0] i1 = i1*abf[1] _n = getattr(self,'_cValueMin',T[0]) _x = getattr(self,'_cValueMax',T[-1]) if _n - T[0] < i0: self._valueMin = self._valueMin - i0 if T[-1]-_x < i1: self._valueMax = self._valueMax + i1 T, L = ticks(self._valueMin, self._valueMax, split=1, n=n, percent=self.leftAxisPercent,grid=valueStep, labelVOffset=self.labelVOffset) self._valueMin = T[0] self._valueMax = T[-1] self._tickValues = T if self.labelTextFormat is None: self._labelTextFormat = L else: self._labelTextFormat = self.labelTextFormat if abs(self._valueMin-100)<1e-6: self._calcValueStep() vMax, vMin = self._valueMax, self._valueMin m = max(self.leftAxisOrigShiftIPC*self._valueStep, (vMax-vMin)*self.leftAxisOrigShiftMin/self._length) self._valueMin = self._valueMin - m if self.leftAxisSkipLL0: if isSeq(self.leftAxisSkipLL0): for x in self.leftAxisSkipLL0: try: L[x] = '' except IndexError: pass L[0] = '' class LogValueAxis(ValueAxis): def _calcScaleFactor(self): """Calculate the axis' scale factor. This should be called only *after* the axis' range is set. Returns a number. """ self._scaleFactor = self._length / float( math_log10(self._valueMax) - math_log10(self._valueMin)) return self._scaleFactor def _setRange(self,dataSeries): valueMin = self.valueMin valueMax = self.valueMax aMin = _findMin(dataSeries,self._dataIndex,0,extraMinMaxValues=self.extraMinMaxValues) aMax = _findMax(dataSeries,self._dataIndex,0,extraMinMaxValues=self.extraMinMaxValues) if valueMin is None: valueMin = aMin if valueMax is None: valueMax = aMax if valueMin>valueMax: raise ValueError('%s: valueMin=%r should not be greater than valueMax=%r!' % (self.__class__.__name__valueMin, valueMax)) if valueMin<=0: raise ValueError('%s: valueMin=%r negative values are not allowed!' % (self.__class__.__name__,valueMin)) abS = self.avoidBoundSpace if abS: lMin = math_log10(aMin) lMax = math_log10(aMax) if not isSeq(abS): abS = abS, abS a0 = abS[0] or 0 a1 = abS[1] or 0 L = self._length - (a0 + a1) sf = (lMax-lMin)/float(L) lMin -= a0*sf lMax += a1*sf valueMin = min(valueMin,10**lMin) valueMax = max(valueMax,10**lMax) self._valueMin = valueMin self._valueMax = valueMax def _calcTickPositions(self): #self._calcValueStep() valueMin = cMin = math_log10(self._valueMin) valueMax = cMax = math_log10(self._valueMax) rr = self.rangeRound if rr: if rr in ('both','ceiling'): i = int(valueMax) valueMax = i + 1 if ivalueMin else i T = [].append tv = int(valueMin) if tvself.maximumTicks: i += 1 self._powerInc = i while True: if tv>valueMax: break if tv>=valueMin: T(10**tv) tv += i if valueMin!=cMin: self._valueMin = 10**valueMin if valueMax!=cMax: self._valueMax = 10**valueMax return T.__self__ def _calcSubTicks(self): if not hasattr(self,'_tickValues'): self._pseudo_configure() otv = self._tickValues if not hasattr(self,'_subTickValues'): T = [].append valueMin = math_log10(self._valueMin) valueMax = math_log10(self._valueMax)+1 tv = round(valueMin) i = self._powerInc if i==1: fac = 10 / float(self.subTickNum) start = 1 if self.subTickNum == 10: start = 2 while tv < valueMax: for j in range(start,self.subTickNum): v = fac*j*(10**tv) if v > self._valueMin and v < self._valueMax: T(v) tv += i else: ng = min(self.subTickNum+1,i-1) while ng: if (i % ng)==0: i /= ng break ng -= 1 else: i = 1 tv = round(valueMin) while True: v = 10**tv if v >= self._valueMax: break if v not in otv: T(v) tv += i self._subTickValues = T.__self__ self._tickValues = self._subTickValues return otv class LogAxisTickLabeller(TickLabeller): def __call__(self,axis,value): e = math_log10(value) e = int(e-0.001 if e<0 else e+0.001) if e==0: return '1' if e==1: return '10' return '10%s' % e class LogAxisTickLabellerS(TickLabeller): '''simple log axis labeller tries to use integers and short forms else exponential format''' def __call__(self,axis,value): e = math_log10(value) p = int(e-0.001 if e<0 else e+0.001) if p==0: return '1' s = '1'+p*'0' if p>0 else '0.'+(-(1+p)*'0')+'1' se = '%.0e' % value return se if len(se) 0, or ten # points inside if bar value < 0. This is different # to label dx/dy which are not dependent on the # sign of the data. self.barLabels.nudge = 0 # if you have multiple series, by default they butt # together. # we really need some well-designed default lists of # colors e.g. from Tufte. These will be used in a # cycle to set the fill color of each series. self.bars = TypedPropertyCollection(BarChartProperties) self.bars.strokeWidth = 1 self.bars.strokeColor = colors.black self.bars.strokeDashArray = None self.bars[0].fillColor = colors.red self.bars[1].fillColor = colors.green self.bars[2].fillColor = colors.blue self.naLabel = self.categoryNALabel = None self.zIndexOverrides = None def demo(self): """Shows basic use of a bar chart""" if self.__class__.__name__=='BarChart': raise NotImplementedError('Abstract Class BarChart has no demo') drawing = Drawing(200, 100) bc = self.__class__() drawing.add(bc) return drawing def getSeriesOrder(self): bs = getattr(self,'seriesOrder',None) n = len(self.data) if not bs: R = [(ss,) for ss in range(n)] else: bars = self.bars unseen = set(range(n)) lines = set() R = [] for s in bs: g = {ss for ss in s if 0<=ss<=n} gl = {ss for ss in g if bars.checkAttr(ss,'isLine',False)} if gl: g -= gl lines |= gl unseen -= gl if g: R.append(tuple(g)) unseen -= g if unseen: R.extend((ss,) for ss in sorted(unseen)) if lines: R.extend((ss,) for ss in sorted(lines)) self._seriesOrder = R def _getConfigureData(self): cAStyle = self.categoryAxis.style data = self.data cc = max(list(map(len,data))) #category count _data = data if cAStyle not in ('parallel','parallel_3d'): #stacked or mixed data = [] def _accumulate(*D): pdata = max((len(d) for d in D))*[0] ndata = pdata[:] for d in D: for i,v in enumerate(d): v = v or 0 if v<=-1e-6: ndata[i] += v else: pdata[i] += v data.append(ndata) data.append(pdata) if cAStyle=='stacked': _accumulate(*_data) else: self.getSeriesOrder() for b in self._seriesOrder: _accumulate(*(_data[j] for j in b)) self._configureData = data def _getMinMax(self): '''Attempt to return the data range''' self._getConfigureData() self.valueAxis._setRange(self._configureData) return self.valueAxis._valueMin, self.valueAxis._valueMax def _drawBegin(self,org,length): '''Position and configure value axis, return crossing value''' vA = self.valueAxis vA.setPosition(self.x, self.y, length) self._getConfigureData() vA.configure(self._configureData) # if zero is in chart, put the other axis there, otherwise use org crossesAt = vA.scale(0) return crossesAt if vA.forceZero or (crossesAt>=org and crossesAt<=org+length) else org def _drawFinish(self): '''finalize the drawing of a barchart''' cA = self.categoryAxis vA = self.valueAxis cA.configure(self._configureData) self.calcBarPositions() g = Group() zIndex = getattr(self,'zIndexOverrides',None) if not zIndex: g.add(self.makeBackground()) cAdgl = getattr(cA,'drawGridLast',False) vAdgl = getattr(vA,'drawGridLast',False) if not cAdgl: cA.makeGrid(g,parent=self, dim=vA.getGridDims) if not vAdgl: vA.makeGrid(g,parent=self, dim=cA.getGridDims) g.add(self.makeBars()) g.add(cA) g.add(vA) if cAdgl: cA.makeGrid(g,parent=self, dim=vA.getGridDims) if vAdgl: vA.makeGrid(g,parent=self, dim=cA.getGridDims) for a in getattr(self,'annotations',()): g.add(a(self,cA.scale,vA.scale)) else: Z=dict( background=0, categoryAxis=1, valueAxis=2, bars=3, barLabels=4, categoryAxisGrid=5, valueAxisGrid=6, annotations=7, ) for z in zIndex.strip().split(','): z = z.strip() if not z: continue try: k,v=z.split('=') except: raise ValueError('Badly formatted zIndex clause %r in %r\nallowed variables are\n%s' % (z,zIndex,'\n'.join(['%s=%r'% (k,Z[k]) for k in sorted(Z.keys())]))) if k not in Z: raise ValueError('Unknown zIndex variable %r in %r\nallowed variables are\n%s' % (k,Z,'\n'.join(['%s=%r'% (k,Z[k]) for k in sorted(Z.keys())]))) try: v = literal_eval(v) #only constants allowed assert isinstance(v,(float,int)) except: raise ValueError('Bad zIndex value %r in clause %r of zIndex\nallowed variables are\n%s' % (v,z,zIndex,'\n'.join(['%s=%r'% (k,Z[k]) for k in sorted(Z.keys())]))) Z[k] = v Z = [(v,k) for k,v in Z.items()] Z.sort() b = self.makeBars() bl = b.contents.pop(-1) for v,k in Z: if k=='background': g.add(self.makeBackground()) elif k=='categoryAxis': g.add(cA) elif k=='categoryAxisGrid': cA.makeGrid(g,parent=self, dim=vA.getGridDims) elif k=='valueAxis': g.add(vA) elif k=='valueAxisGrid': vA.makeGrid(g,parent=self, dim=cA.getGridDims) elif k=='bars': g.add(b) elif k=='barLabels': g.add(bl) elif k=='annotations': for a in getattr(self,'annotations',()): g.add(a(self,cA.scale,vA.scale)) del self._configureData return g def calcBarPositions(self): """Works out where they go. default vertical. Sets an attribute _barPositions which is a list of lists of (x, y, width, height) matching the data. """ flipXY = self._flipXY if flipXY: org = self.y else: org = self.x cA = self.categoryAxis cScale = cA.scale data = self.data seriesCount = self._seriesCount = len(data) self._rowLength = rowLength = max(list(map(len,data))) wG = self.groupSpacing barSpacing = self.barSpacing barWidth = self.barWidth clbs = getattr(self,'categoryLabelBarSize',0) clbo = getattr(self,'categoryLabelBarOrder','auto') if clbo=='auto': clbo = flipXY and 'last' or 'first' clbo = clbo=='first' style = cA.style bars = self.bars lineCount = sum((int(bars.checkAttr(_,'isLine',False)) for _ in range(seriesCount))) seriesMLineCount = seriesCount - lineCount if style=='mixed': ss = self._seriesOrder barsPerGroup = len(ss) - lineCount wB = barsPerGroup*barWidth wS = (barsPerGroup-1)*barSpacing if barsPerGroup>1: bGapB = barWidth bGapS = barSpacing else: bGapB = bGapS = 0 accumNeg = barsPerGroup*rowLength*[0] accumPos = accumNeg[:] elif style in ('parallel','parallel_3d'): barsPerGroup = 1 wB = seriesMLineCount*barWidth wS = (seriesMLineCount-1)*barSpacing bGapB = barWidth bGapS = barSpacing else: barsPerGroup = seriesMLineCount accumNeg = rowLength*[0] accumPos = accumNeg[:] wB = barWidth wS = bGapB = bGapS = 0 self._groupWidth = groupWidth = wG+wB+wS useAbsolute = self.useAbsolute if useAbsolute: if not isinstance(useAbsolute,str): useAbsolute = 7 #all three are fixed else: useAbsolute = 0 + 1*('b' in useAbsolute)+2*('g' in useAbsolute)+4*('s' in useAbsolute) else: useAbsolute = 0 aW0 = float(cScale(0)[1]) aW = aW0 - clbs if useAbsolute==0: #case 0 all are free self._normFactor = fB = fG = fS = aW/groupWidth elif useAbsolute==7: #all fixed fB = fG = fS = 1.0 _cscale = cA._scale elif useAbsolute==1: #case 1 barWidth is fixed fB = 1.0 fG = fS = (aW-wB)/(wG+wS) elif useAbsolute==2: #groupspacing is fixed fG=1.0 fB = fS = (aW-wG)/(wB+wS) elif useAbsolute==3: #groupspacing & barwidth are fixed fB = fG = 1.0 fS = (aW-wG-wB)/wS if wS else 0 elif useAbsolute==4: #barspacing is fixed fS=1.0 fG = fB = (aW-wS)/(wG+wB) elif useAbsolute==5: #barspacing & barWidth are fixed fS = fB = 1.0 fG = (aW-wB-wS)/wG elif useAbsolute==6: #barspacing & groupspacing are fixed fS = fG = 1 fB = (aW-wS-wG)/wB self._normFactorB = fB self._normFactorG = fG self._normFactorS = fS # 'Baseline' correction... vA = self.valueAxis vScale = vA.scale vARD = vA.reverseDirection vm, vM = vA._valueMin, vA._valueMax if vm <= 0 <= vM: baseLine = vScale(0) elif 0 < vm: baseLine = vScale(vm) elif vM < 0: baseLine = vScale(vM) self._baseLine = baseLine width = barWidth*fB offs = 0.5*wG*fG bGap = bGapB*fB+bGapS*fS if clbs: if clbo: #the lable bar comes first lbpf = (offs+clbs/6.0)/aW0 offs += clbs else: lbpf = (offs+wB*fB+wS*fS+clbs/6.0)/aW0 cA.labels.labelPosFrac = lbpf self._barPositions = [] aBP = self._barPositions.append reversePlotOrder = self.reversePlotOrder def _addBar(colNo, accx): # Ufff... if useAbsolute==7: x = groupWidth*_cscale(colNo) + xVal + org else: (g, _) = cScale(colNo) x = g + xVal datum = row[colNo] if datum is None: height = None y = baseLine else: if style not in ('parallel','parallel_3d') and not isLine: if datum<=-1e-6: y = vScale(accumNeg[accx]) if (ybaseLine): y = baseLine accumNeg[accx] += datum datum = accumNeg[accx] else: y = vScale(accumPos[accx]) if (y>baseLine if vARD else y=0 and 1 or -1)*nudge if bt=='mid': b = y+height*0.5 elif bt=='hi': if value>=0: b = y + value + nudge else: b = y - nudge pm = -pm elif bt=='lo': if value<=0: b = y + value + nudge else: b = y - nudge pm = -pm else: b = y + value + nudge label._pmv = pm #the plus minus val return a,b,pm def _addBarLabel(self, g, rowNo, colNo, x, y, width, height): text = self._getLabelText(rowNo,colNo) if text: self._addLabel(text, self.barLabels[(rowNo, colNo)], g, rowNo, colNo, x, y, width, height) def _addNABarLabel(self, g, rowNo, colNo, x, y, width, height, calcOnly=False, na=None): if na is None: na = self.naLabel if na and na.text: na = copy.copy(na) v = self.valueAxis._valueMax<=0 and -1e-8 or 1e-8 if width is None: width = v if height is None: height = v return self._addLabel(na.text, na, g, rowNo, colNo, x, y, width, height, calcOnly=calcOnly) def _addLabel(self, text, label, g, rowNo, colNo, x, y, width, height, calcOnly=False): if label.visible: labelWidth = stringWidth(text, label.fontName, label.fontSize) flipXY = self._flipXY if flipXY: y0, x0, pm = self._labelXY(label,y,x,height,width) else: x0, y0, pm = self._labelXY(label,x,y,width,height) fixedEnd = getattr(label,'fixedEnd', None) if fixedEnd is not None: v = fixedEnd._getValue(self,pm) x00, y00 = x0, y0 if flipXY: x0 = v else: y0 = v else: if flipXY: x00 = x0 y00 = y+height/2.0 else: x00 = x+width/2.0 y00 = y0 fixedStart = getattr(label,'fixedStart', None) if fixedStart is not None: v = fixedStart._getValue(self,pm) if flipXY: x00 = v else: y00 = v if pm<0: if flipXY: dx = -2*label.dx dy = 0 else: dy = -2*label.dy dx = 0 else: dy = dx = 0 if calcOnly: return x0+dx, y0+dy label.setOrigin(x0+dx, y0+dy) label.setText(text) sC, sW = label.lineStrokeColor, label.lineStrokeWidth if sC and sW: g.insert(0,Line(x00,y00,x0,y0, strokeColor=sC, strokeWidth=sW)) g.add(label) alx = getattr(self,'barLabelCallOut',None) if alx: label._callOutInfo = (self,g,rowNo,colNo,x,y,width,height,x00,y00,x0,y0) alx(label) del label._callOutInfo def _makeBar(self,g,x,y,width,height,rowNo,style): r = Rect(x, y, width, height) r.strokeWidth = style.strokeWidth r.fillColor = style.fillColor r.strokeColor = style.strokeColor if style.strokeDashArray: r.strokeDashArray = style.strokeDashArray g.add(r) def _makeBars(self,g,lg): bars = self.bars br = getattr(self,'barRecord',None) BP = self._barPositions flipXY = self._flipXY catNAL = self.categoryNALabel catNNA = {} if catNAL: CBL = [] rowNoL = len(self.data) - 1 #find all the categories that have at least one value for rowNo, row in enumerate(BP): for colNo, (x, y, width, height) in enumerate(row): if None not in (width,height): catNNA[colNo] = 1 lines = [].append lineSyms = [].append for rowNo, row in enumerate(BP): styleCount = len(bars) styleIdx = rowNo % styleCount rowStyle = bars[styleIdx] isLine = bars.checkAttr(rowNo, 'isLine', False) linePts = [].append for colNo, (x,y,width,height) in enumerate(row): style = (styleIdx,colNo) in bars and bars[(styleIdx,colNo)] or rowStyle if None in (width,height): if not catNAL or colNo in catNNA: self._addNABarLabel(lg,rowNo,colNo,x,y,width,height) elif catNAL and colNo not in CBL: r0 = self._addNABarLabel(lg,rowNo,colNo,x,y,width,height,True,catNAL) if r0: x, y, width, height = BP[rowNoL][colNo] r1 = self._addNABarLabel(lg,rowNoL,colNo,x,y,width,height,True,catNAL) x = (r0[0]+r1[0])/2.0 y = (r0[1]+r1[1])/2.0 self._addNABarLabel(lg,rowNoL,colNo,x,y,0.0001,0.0001,na=catNAL) CBL.append(colNo) if isLine: linePts(None) continue # Draw a rectangular symbol for each data item, # or a normal colored rectangle. symbol = None if hasattr(style, 'symbol'): symbol = copy.deepcopy(style.symbol) elif hasattr(self.bars, 'symbol'): symbol = self.bars.symbol minDimen=getattr(style,'minDimen',None) if minDimen: if flipXY: if width<0: width = min(-style.minDimen,width) else: width = max(style.minDimen,width) else: if height<0: height = min(-style.minDimen,height) else: height = max(style.minDimen,height) if isLine: if not flipXY: yL = y + height xL = x + width*0.5 else: xL = x + width yL = y + height*0.5 linePts(xL) linePts(yL) if symbol: sym = uSymbol2Symbol(tpcGetItem(symbol,colNo),xL,yL,style.strokeColor or style.fillColor) if sym: lineSyms(sym) elif symbol: symbol.x = x symbol.y = y symbol.width = width symbol.height = height g.add(symbol) elif abs(width)>1e-7 and abs(height)>=1e-7 and (style.fillColor is not None or style.strokeColor is not None): self._makeBar(g,x,y,width,height,rowNo,style) if br: br(g.contents[-1],label=self._getLabelText(rowNo,colNo),value=self.data[rowNo][colNo],rowNo=rowNo,colNo=colNo) self._addBarLabel(lg,rowNo,colNo,x,y,width,height) for linePts in yieldNoneSplits(linePts.__self__): if linePts: lines(PolyLine(linePts, strokeColor=rowStyle.strokeColor or rowStyle.fillColor, strokeWidth=rowStyle.strokeWidth, strokeDashArray = rowStyle.strokeDashArray)) for pl in lines.__self__: g.add(pl) for sym in lineSyms.__self__: g.add(sym) def _computeLabelPosition(self, text, label, rowNo, colNo, x, y, width, height): if label.visible: labelWidth = stringWidth(text, label.fontName, label.fontSize) flipXY = self._flipXY if flipXY: y0, x0, pm = self._labelXY(label,y,x,height,width) else: x0, y0, pm = self._labelXY(label,x,y,width,height) fixedEnd = getattr(label,'fixedEnd', None) if fixedEnd is not None: v = fixedEnd._getValue(self,pm) x00, y00 = x0, y0 if flipXY: x0 = v else: y0 = v else: if flipXY: x00 = x0 y00 = y+height/2.0 else: x00 = x+width/2.0 y00 = y0 fixedStart = getattr(label,'fixedStart', None) if fixedStart is not None: v = fixedStart._getValue(self,pm) if flipXY: x00 = v else: y00 = v if pm<0: if flipXY: dx = -2*label.dx dy = 0 else: dy = -2*label.dy dx = 0 else: dy = dx = 0 label.setOrigin(x0+dx, y0+dy) label.setText(text) return pm,label.getBounds() def _computeBarPositions(self): """Information function, can be called by charts which want to with space around bars""" cA, vA = self.categoryAxis, self.valueAxis if vA: vA.joinAxis = cA if cA: cA.joinAxis = vA if self._flipXY: cA.setPosition(self._drawBegin(self.x,self.width), self.y, self.height) else: cA.setPosition(self.x, self._drawBegin(self.y,self.height), self.width) cA.configure(self._configureData) self.calcBarPositions() def _computeMaxSpace(self,size,required): '''helper for madmen who want to put stuff inside their barcharts basically after _computebarPositions we slide a line of length size down the bar profile on either side of the bars to find the maximum space. If the space at any point is >= required then we're done. Otherwise we return the largest space location and amount. ''' flipXY = self._flipXY self._computeBarPositions() lenData = len(self.data) BP = self._barPositions C = [] aC = C.append if flipXY: lo = self.x hi = lo + self.width end = self.y+self.height for bp in BP: for x, y, w, h in bp: v = x+w z = y+h aC((min(y,z),max(y,z), min(x,v) - lo, hi - max(x,v))) else: lo = self.y hi = lo + self.height end = self.x+self.width for bp in BP: for x, y, w, h in bp: v = y+h z = x+w aC((min(x,z), max(x,z), min(y,v) - lo, hi - max(y,v))) C.sort() R = [C[0]] for c in C: r = R[-1] if r[0]end: break j = i alo = ahi = 0x7fffffff while jahi: if alo>maxS: maxS = alo maxP = flipXY and (lo,v0,lo+alo,v0+size,0) or (v0,lo,v0+size,lo+alo,0) if maxS >= required: break elif ahi>maxS: maxS = ahi maxP = flipXY and (hi-ahi,v0,hi,v0+size,1) or (v0,hi-ahi,v0+size,hi,1) if maxS >= required: break return maxS, maxP def _computeSimpleBarLabelPositions(self): """Information function, can be called by charts which want to mess with labels""" cA, vA = self.categoryAxis, self.valueAxis if vA: vA.joinAxis = cA if cA: cA.joinAxis = vA if self._flipXY: cA.setPosition(self._drawBegin(self.x,self.width), self.y, self.height) else: cA.setPosition(self.x, self._drawBegin(self.y,self.height), self.width) cA.configure(self._configureData) self.calcBarPositions() bars = self.bars R = [].append BP = self._barPositions for rowNo, row in enumerate(BP): C = [].append for colNo, (x, y, width, height) in enumerate(row): if None in (width,height): na = self.naLabel if na and na.text: na = copy.copy(na) v = self.valueAxis._valueMax<=0 and -1e-8 or 1e-8 if width is None: width = v if height is None: height = v C(self._computeLabelPosition(na.text, na, rowNo, colNo, x, y, width, height)) else: C(None) else: text = self._getLabelText(rowNo,colNo) if text: C(self._computeLabelPosition(text, self.barLabels[(rowNo, colNo)], rowNo, colNo, x, y, width, height)) else: C(None) R(C.__self__) return R.__self__ def makeBars(self): g = Group() lg = Group() self._makeBars(g,lg) g.add(lg) return g def _desiredCategoryAxisLength(self): '''for dynamically computing the desired category axis length''' style = self.categoryAxis.style data = self.data n = len(data) m = max(list(map(len,data))) if style=='parallel': groupWidth = (n-1)*self.barSpacing+n*self.barWidth else: groupWidth = self.barWidth return m*(self.groupSpacing+groupWidth) def draw(self): cA, vA = self.categoryAxis, self.valueAxis if vA: vA.joinAxis = cA if cA: cA.joinAxis = vA if self._flipXY: cA.setPosition(self._drawBegin(self.x,self.width), self.y, self.height) else: cA.setPosition(self.x, self._drawBegin(self.y,self.height), self.width) return self._drawFinish() class VerticalBarChart(BarChart): "Vertical bar chart with multiple side-by-side bars." _flipXY = 0 class HorizontalBarChart(BarChart): "Horizontal bar chart with multiple side-by-side bars." _flipXY = 1 class _FakeGroup: def __init__(self, cmp=None): self._data = [] self._key = functools.cmp_to_key(cmp) def add(self,what): self._data.append(what) def value(self): return self._data def sort(self): self._data.sort(key=self._key) class BarChart3D(BarChart): _attrMap = AttrMap(BASE=BarChart, theta_x = AttrMapValue(isNumber, desc='dx/dz'), theta_y = AttrMapValue(isNumber, desc='dy/dz'), zDepth = AttrMapValue(isNumber, desc='depth of an individual series'), zSpace = AttrMapValue(isNumber, desc='z gap around series'), ) theta_x = .5 theta_y = .5 zDepth = None zSpace = None def calcBarPositions(self): BarChart.calcBarPositions(self) seriesCount = self._seriesCount zDepth = self.zDepth if zDepth is None: zDepth = self.barWidth zSpace = self.zSpace if zSpace is None: zSpace = self.barSpacing if self.categoryAxis.style=='parallel_3d': _3d_depth = seriesCount*zDepth+(seriesCount+1)*zSpace else: _3d_depth = zDepth + 2*zSpace _3d_depth *= self._normFactor self._3d_dx = self.theta_x*_3d_depth self._3d_dy = self.theta_y*_3d_depth def _calc_z0(self,rowNo): zDepth = self.zDepth if zDepth is None: zDepth = self.barWidth zSpace = self.zSpace if zSpace is None: zSpace = self.barSpacing if self.categoryAxis.style=='parallel_3d': z0 = self._normFactor*(rowNo*(zDepth+zSpace)+zSpace) else: z0 = self._normFactor*zSpace return z0 def _makeBar(self,g,x,y,width,height,rowNo,style): zDepth = self.zDepth if zDepth is None: zDepth = self.barWidth zSpace = self.zSpace if zSpace is None: zSpace = self.barSpacing z0 = self._calc_z0(rowNo) z1 = z0 + zDepth*self._normFactor if width<0: x += width width = -width x += z0*self.theta_x y += z0*self.theta_y if self._flipXY: y += zSpace else: x += zSpace g.add((0,z0,z1,x,y,width,height,rowNo,style)) def _addBarLabel(self, g, rowNo, colNo, x, y, width, height): z0 = self._calc_z0(rowNo) zSpace = self.zSpace if zSpace is None: zSpace = self.barSpacing z1 = z0 x += z0*self.theta_x y += z0*self.theta_y if self._flipXY: y += zSpace else: x += zSpace g.add((1,z0,z1,x,y,width,height,rowNo,colNo)) def makeBars(self): from reportlab.graphics.charts.utils3d import _draw_3d_bar fg = _FakeGroup(cmp=self._cmpZ) self._makeBars(fg,fg) fg.sort() g = Group() theta_x = self.theta_x theta_y = self.theta_y fg_value = fg.value() cAStyle = self.categoryAxis.style if cAStyle=='stacked': fg_value.reverse() elif cAStyle=='mixed': fg_value = [_[1] for _ in sorted((((t[1],t[2],t[3],t[4]),t) for t in fg_value))] for t in fg_value: if t[0]==0: z0,z1,x,y,width,height,rowNo,style = t[1:] dz = z1 - z0 _draw_3d_bar(g, x, x+width, y, y+height, dz*theta_x, dz*theta_y, fillColor=style.fillColor, fillColorShaded=None, strokeColor=style.strokeColor, strokeWidth=style.strokeWidth, shading=0.45) for t in fg_value: if t==1: z0,z1,x,y,width,height,rowNo,colNo = t[1:] BarChart._addBarLabel(self,g,rowNo,colNo,x,y,width,height) return g class VerticalBarChart3D(BarChart3D,VerticalBarChart): _cmpZ=lambda self,a,b:cmp((-a[1],a[3],a[0],-a[4]),(-b[1],b[3],b[0],-b[4])) class HorizontalBarChart3D(BarChart3D,HorizontalBarChart): _cmpZ = lambda self,a,b: cmp((-a[1],a[4],a[0],-a[3]),(-b[1],b[4],b[0],-b[3])) #t, z0, z1, x, y = a[:5] # Vertical samples. def sampleV0a(): "A slightly pathologic bar chart with only TWO data items." drawing = Drawing(400, 200) data = [(13, 20)] bc = VerticalBarChart() bc.x = 50 bc.y = 50 bc.height = 125 bc.width = 300 bc.data = data bc.strokeColor = colors.black bc.valueAxis.valueMin = 0 bc.valueAxis.valueMax = 60 bc.valueAxis.valueStep = 15 bc.categoryAxis.labels.boxAnchor = 'ne' bc.categoryAxis.labels.dx = 8 bc.categoryAxis.labels.dy = -2 bc.categoryAxis.labels.angle = 30 bc.categoryAxis.categoryNames = ['Ying', 'Yang'] drawing.add(bc) return drawing def sampleV0b(): "A pathologic bar chart with only ONE data item." drawing = Drawing(400, 200) data = [(42,)] bc = VerticalBarChart() bc.x = 50 bc.y = 50 bc.height = 125 bc.width = 300 bc.data = data bc.strokeColor = colors.black bc.valueAxis.valueMin = 0 bc.valueAxis.valueMax = 50 bc.valueAxis.valueStep = 15 bc.categoryAxis.labels.boxAnchor = 'ne' bc.categoryAxis.labels.dx = 8 bc.categoryAxis.labels.dy = -2 bc.categoryAxis.labels.angle = 30 bc.categoryAxis.categoryNames = ['Jan-99'] drawing.add(bc) return drawing def sampleV0c(): "A really pathologic bar chart with NO data items at all!" drawing = Drawing(400, 200) data = [()] bc = VerticalBarChart() bc.x = 50 bc.y = 50 bc.height = 125 bc.width = 300 bc.data = data bc.strokeColor = colors.black bc.valueAxis.valueMin = 0 bc.valueAxis.valueMax = 60 bc.valueAxis.valueStep = 15 bc.categoryAxis.labels.boxAnchor = 'ne' bc.categoryAxis.labels.dx = 8 bc.categoryAxis.labels.dy = -2 bc.categoryAxis.categoryNames = [] drawing.add(bc) return drawing def sampleV1(): "Sample of multi-series bar chart." drawing = Drawing(400, 200) data = [ (13, 5, 20, 22, 37, 45, 19, 4), (14, 6, 21, 23, 38, 46, 20, 5) ] bc = VerticalBarChart() bc.x = 50 bc.y = 50 bc.height = 125 bc.width = 300 bc.data = data bc.strokeColor = colors.black bc.valueAxis.valueMin = 0 bc.valueAxis.valueMax = 60 bc.valueAxis.valueStep = 15 bc.categoryAxis.labels.boxAnchor = 'ne' bc.categoryAxis.labels.dx = 8 bc.categoryAxis.labels.dy = -2 bc.categoryAxis.labels.angle = 30 catNames = 'Jan Feb Mar Apr May Jun Jul Aug'.split(' ') catNames = [n+'-99' for n in catNames] bc.categoryAxis.categoryNames = catNames drawing.add(bc) return drawing def sampleV2a(): "Sample of multi-series bar chart." data = [(2.4, -5.7, 2, 5, 9.2), (0.6, -4.9, -3, 4, 6.8) ] labels = ("Q3 2000", "Year to Date", "12 months", "Annualised\n3 years", "Since 07.10.99") drawing = Drawing(400, 200) bc = VerticalBarChart() bc.x = 50 bc.y = 50 bc.height = 120 bc.width = 300 bc.data = data bc.barSpacing = 0 bc.groupSpacing = 10 bc.barWidth = 10 bc.valueAxis.valueMin = -15 bc.valueAxis.valueMax = +15 bc.valueAxis.valueStep = 5 bc.valueAxis.labels.fontName = 'Helvetica' bc.valueAxis.labels.fontSize = 8 bc.valueAxis.labels.boxAnchor = 'n' # irrelevant (becomes 'c') bc.valueAxis.labels.textAnchor = 'middle' bc.categoryAxis.categoryNames = labels bc.categoryAxis.labels.fontName = 'Helvetica' bc.categoryAxis.labels.fontSize = 8 bc.categoryAxis.labels.dy = -60 drawing.add(bc) return drawing def sampleV2b(): "Sample of multi-series bar chart." data = [(2.4, -5.7, 2, 5, 9.2), (0.6, -4.9, -3, 4, 6.8) ] labels = ("Q3 2000", "Year to Date", "12 months", "Annualised\n3 years", "Since 07.10.99") drawing = Drawing(400, 200) bc = VerticalBarChart() bc.x = 50 bc.y = 50 bc.height = 120 bc.width = 300 bc.data = data bc.barSpacing = 5 bc.groupSpacing = 10 bc.barWidth = 10 bc.valueAxis.valueMin = -15 bc.valueAxis.valueMax = +15 bc.valueAxis.valueStep = 5 bc.valueAxis.labels.fontName = 'Helvetica' bc.valueAxis.labels.fontSize = 8 bc.valueAxis.labels.boxAnchor = 'n' # irrelevant (becomes 'c') bc.valueAxis.labels.textAnchor = 'middle' bc.categoryAxis.categoryNames = labels bc.categoryAxis.labels.fontName = 'Helvetica' bc.categoryAxis.labels.fontSize = 8 bc.categoryAxis.labels.dy = -60 drawing.add(bc) return drawing def sampleV2c(): "Sample of multi-series bar chart." data = [(2.4, -5.7, 2, 5, 9.99), (0.6, -4.9, -3, 4, 9.99) ] labels = ("Q3 2000", "Year to Date", "12 months", "Annualised\n3 years", "Since 07.10.99") drawing = Drawing(400, 200) bc = VerticalBarChart() bc.x = 50 bc.y = 50 bc.height = 120 bc.width = 300 bc.data = data bc.barSpacing = 2 bc.groupSpacing = 10 bc.barWidth = 10 bc.valueAxis.valueMin = -15 bc.valueAxis.valueMax = +15 bc.valueAxis.valueStep = 5 bc.valueAxis.labels.fontName = 'Helvetica' bc.valueAxis.labels.fontSize = 8 bc.categoryAxis.categoryNames = labels bc.categoryAxis.labels.fontName = 'Helvetica' bc.categoryAxis.labels.fontSize = 8 bc.valueAxis.labels.boxAnchor = 'n' bc.valueAxis.labels.textAnchor = 'middle' bc.categoryAxis.labels.dy = -60 bc.barLabels.nudge = 10 bc.barLabelFormat = '%0.2f' bc.barLabels.dx = 0 bc.barLabels.dy = 0 bc.barLabels.boxAnchor = 'n' # irrelevant (becomes 'c') bc.barLabels.fontName = 'Helvetica' bc.barLabels.fontSize = 6 drawing.add(bc) return drawing def sampleV3(): "Faked horizontal bar chart using a vertical real one (deprecated)." names = ("UK Equities", "US Equities", "European Equities", "Japanese Equities", "Pacific (ex Japan) Equities", "Emerging Markets Equities", "UK Bonds", "Overseas Bonds", "UK Index-Linked", "Cash") series1 = (-1.5, 0.3, 0.5, 1.0, 0.8, 0.7, 0.4, 0.1, 1.0, 0.3) series2 = (0.0, 0.33, 0.55, 1.1, 0.88, 0.77, 0.44, 0.11, 1.10, 0.33) assert len(names) == len(series1), "bad data" assert len(names) == len(series2), "bad data" drawing = Drawing(400, 200) bc = VerticalBarChart() bc.x = 0 bc.y = 0 bc.height = 100 bc.width = 150 bc.data = (series1,) bc.bars.fillColor = colors.green bc.barLabelFormat = '%0.2f' bc.barLabels.dx = 0 bc.barLabels.dy = 0 bc.barLabels.boxAnchor = 'w' # irrelevant (becomes 'c') bc.barLabels.angle = 90 bc.barLabels.fontName = 'Helvetica' bc.barLabels.fontSize = 6 bc.barLabels.nudge = 10 bc.valueAxis.visible = 0 bc.valueAxis.valueMin = -2 bc.valueAxis.valueMax = +2 bc.valueAxis.valueStep = 1 bc.categoryAxis.tickUp = 0 bc.categoryAxis.tickDown = 0 bc.categoryAxis.categoryNames = names bc.categoryAxis.labels.angle = 90 bc.categoryAxis.labels.boxAnchor = 'w' bc.categoryAxis.labels.dx = 0 bc.categoryAxis.labels.dy = -125 bc.categoryAxis.labels.fontName = 'Helvetica' bc.categoryAxis.labels.fontSize = 6 g = Group(bc) g.translate(100, 175) g.rotate(-90) drawing.add(g) return drawing def sampleV4a(): "A bar chart showing value axis region starting at *exactly* zero." drawing = Drawing(400, 200) data = [(13, 20)] bc = VerticalBarChart() bc.x = 50 bc.y = 50 bc.height = 125 bc.width = 300 bc.data = data bc.strokeColor = colors.black bc.valueAxis.valueMin = 0 bc.valueAxis.valueMax = 60 bc.valueAxis.valueStep = 15 bc.categoryAxis.labels.boxAnchor = 'n' bc.categoryAxis.labels.dy = -5 bc.categoryAxis.categoryNames = ['Ying', 'Yang'] drawing.add(bc) return drawing def sampleV4b(): "A bar chart showing value axis region starting *below* zero." drawing = Drawing(400, 200) data = [(13, 20)] bc = VerticalBarChart() bc.x = 50 bc.y = 50 bc.height = 125 bc.width = 300 bc.data = data bc.strokeColor = colors.black bc.valueAxis.valueMin = -10 bc.valueAxis.valueMax = 60 bc.valueAxis.valueStep = 15 bc.categoryAxis.labels.boxAnchor = 'n' bc.categoryAxis.labels.dy = -5 bc.categoryAxis.categoryNames = ['Ying', 'Yang'] drawing.add(bc) return drawing def sampleV4c(): "A bar chart showing value axis region staring *above* zero." drawing = Drawing(400, 200) data = [(13, 20)] bc = VerticalBarChart() bc.x = 50 bc.y = 50 bc.height = 125 bc.width = 300 bc.data = data bc.strokeColor = colors.black bc.valueAxis.valueMin = 10 bc.valueAxis.valueMax = 60 bc.valueAxis.valueStep = 15 bc.categoryAxis.labels.boxAnchor = 'n' bc.categoryAxis.labels.dy = -5 bc.categoryAxis.categoryNames = ['Ying', 'Yang'] drawing.add(bc) return drawing def sampleV4d(): "A bar chart showing value axis region entirely *below* zero." drawing = Drawing(400, 200) data = [(-13, -20)] bc = VerticalBarChart() bc.x = 50 bc.y = 50 bc.height = 125 bc.width = 300 bc.data = data bc.strokeColor = colors.black bc.valueAxis.valueMin = -30 bc.valueAxis.valueMax = -10 bc.valueAxis.valueStep = 15 bc.categoryAxis.labels.boxAnchor = 'n' bc.categoryAxis.labels.dy = -5 bc.categoryAxis.categoryNames = ['Ying', 'Yang'] drawing.add(bc) return drawing ### ##dataSample5 = [(10, 20), (20, 30), (30, 40), (40, 50), (50, 60)] ##dataSample5 = [(10, 60), (20, 50), (30, 40), (40, 30), (50, 20)] dataSample5 = [(10, 60), (20, 50), (30, 40), (40, 30)] def sampleV5a(): "A simple bar chart with no expressed spacing attributes." drawing = Drawing(400, 200) data = dataSample5 bc = VerticalBarChart() bc.x = 50 bc.y = 50 bc.height = 125 bc.width = 300 bc.data = data bc.strokeColor = colors.black bc.valueAxis.valueMin = 0 bc.valueAxis.valueMax = 60 bc.valueAxis.valueStep = 15 bc.categoryAxis.labels.boxAnchor = 'n' bc.categoryAxis.labels.dy = -5 bc.categoryAxis.categoryNames = ['Ying', 'Yang'] drawing.add(bc) return drawing def sampleV5b(): "A simple bar chart with proportional spacing." drawing = Drawing(400, 200) data = dataSample5 bc = VerticalBarChart() bc.x = 50 bc.y = 50 bc.height = 125 bc.width = 300 bc.data = data bc.strokeColor = colors.black bc.useAbsolute = 0 bc.barWidth = 40 bc.groupSpacing = 20 bc.barSpacing = 10 bc.valueAxis.valueMin = 0 bc.valueAxis.valueMax = 60 bc.valueAxis.valueStep = 15 bc.categoryAxis.labels.boxAnchor = 'n' bc.categoryAxis.labels.dy = -5 bc.categoryAxis.categoryNames = ['Ying', 'Yang'] drawing.add(bc) return drawing def sampleV5c1(): "Make sampe simple bar chart but with absolute spacing." drawing = Drawing(400, 200) data = dataSample5 bc = VerticalBarChart() bc.x = 50 bc.y = 50 bc.height = 125 bc.width = 300 bc.data = data bc.strokeColor = colors.black bc.useAbsolute = 1 bc.barWidth = 40 bc.groupSpacing = 0 bc.barSpacing = 0 bc.valueAxis.valueMin = 0 bc.valueAxis.valueMax = 60 bc.valueAxis.valueStep = 15 bc.categoryAxis.labels.boxAnchor = 'n' bc.categoryAxis.labels.dy = -5 bc.categoryAxis.categoryNames = ['Ying', 'Yang'] drawing.add(bc) return drawing def sampleV5c2(): "Make sampe simple bar chart but with absolute spacing." drawing = Drawing(400, 200) data = dataSample5 bc = VerticalBarChart() bc.x = 50 bc.y = 50 bc.height = 125 bc.width = 300 bc.data = data bc.strokeColor = colors.black bc.useAbsolute = 1 bc.barWidth = 40 bc.groupSpacing = 20 bc.barSpacing = 0 bc.valueAxis.valueMin = 0 bc.valueAxis.valueMax = 60 bc.valueAxis.valueStep = 15 bc.categoryAxis.labels.boxAnchor = 'n' bc.categoryAxis.labels.dy = -5 bc.categoryAxis.categoryNames = ['Ying', 'Yang'] drawing.add(bc) return drawing def sampleV5c3(): "Make sampe simple bar chart but with absolute spacing." drawing = Drawing(400, 200) data = dataSample5 bc = VerticalBarChart() bc.x = 50 bc.y = 50 bc.height = 125 bc.width = 300 bc.data = data bc.strokeColor = colors.black bc.useAbsolute = 1 bc.barWidth = 40 bc.groupSpacing = 0 bc.barSpacing = 10 bc.valueAxis.valueMin = 0 bc.valueAxis.valueMax = 60 bc.valueAxis.valueStep = 15 bc.categoryAxis.labels.boxAnchor = 'n' bc.categoryAxis.labels.dy = -5 bc.categoryAxis.categoryNames = ['Ying', 'Yang'] drawing.add(bc) return drawing def sampleV5c4(): "Make sampe simple bar chart but with absolute spacing." drawing = Drawing(400, 200) data = dataSample5 bc = VerticalBarChart() bc.x = 50 bc.y = 50 bc.height = 125 bc.width = 300 bc.data = data bc.strokeColor = colors.black bc.useAbsolute = 1 bc.barWidth = 40 bc.groupSpacing = 20 bc.barSpacing = 10 bc.valueAxis.valueMin = 0 bc.valueAxis.valueMax = 60 bc.valueAxis.valueStep = 15 bc.categoryAxis.labels.boxAnchor = 'n' bc.categoryAxis.labels.dy = -5 bc.categoryAxis.categoryNames = ['Ying', 'Yang'] drawing.add(bc) return drawing # Horizontal samples def sampleH0a(): "Make a slightly pathologic bar chart with only TWO data items." drawing = Drawing(400, 200) data = [(13, 20)] bc = HorizontalBarChart() bc.x = 50 bc.y = 50 bc.height = 125 bc.width = 300 bc.data = data bc.strokeColor = colors.black bc.valueAxis.valueMin = 0 bc.valueAxis.valueMax = 60 bc.valueAxis.valueStep = 15 bc.categoryAxis.labels.boxAnchor = 'se' bc.categoryAxis.labels.angle = 30 bc.categoryAxis.categoryNames = ['Ying', 'Yang'] drawing.add(bc) return drawing def sampleH0b(): "Make a pathologic bar chart with only ONE data item." drawing = Drawing(400, 200) data = [(42,)] bc = HorizontalBarChart() bc.x = 50 bc.y = 50 bc.height = 125 bc.width = 300 bc.data = data bc.strokeColor = colors.black bc.valueAxis.valueMin = 0 bc.valueAxis.valueMax = 50 bc.valueAxis.valueStep = 15 bc.categoryAxis.labels.boxAnchor = 'se' bc.categoryAxis.labels.angle = 30 bc.categoryAxis.categoryNames = ['Jan-99'] drawing.add(bc) return drawing def sampleH0c(): "Make a really pathologic bar chart with NO data items at all!" drawing = Drawing(400, 200) data = [()] bc = HorizontalBarChart() bc.x = 50 bc.y = 50 bc.height = 125 bc.width = 300 bc.data = data bc.strokeColor = colors.black bc.valueAxis.valueMin = 0 bc.valueAxis.valueMax = 60 bc.valueAxis.valueStep = 15 bc.categoryAxis.labels.boxAnchor = 'se' bc.categoryAxis.labels.angle = 30 bc.categoryAxis.categoryNames = [] drawing.add(bc) return drawing def sampleH1(): "Sample of multi-series bar chart." drawing = Drawing(400, 200) data = [ (13, 5, 20, 22, 37, 45, 19, 4), (14, 6, 21, 23, 38, 46, 20, 5) ] bc = HorizontalBarChart() bc.x = 50 bc.y = 50 bc.height = 125 bc.width = 300 bc.data = data bc.strokeColor = colors.black bc.valueAxis.valueMin = 0 bc.valueAxis.valueMax = 60 bc.valueAxis.valueStep = 15 bc.categoryAxis.labels.boxAnchor = 'e' catNames = 'Jan Feb Mar Apr May Jun Jul Aug'.split(' ') catNames = [n+'-99' for n in catNames] bc.categoryAxis.categoryNames = catNames drawing.add(bc, 'barchart') return drawing def sampleH2a(): "Sample of multi-series bar chart." data = [(2.4, -5.7, 2, 5, 9.2), (0.6, -4.9, -3, 4, 6.8) ] labels = ("Q3 2000", "Year to Date", "12 months", "Annualised\n3 years", "Since 07.10.99") drawing = Drawing(400, 200) bc = HorizontalBarChart() bc.x = 80 bc.y = 50 bc.height = 120 bc.width = 300 bc.data = data bc.barSpacing = 0 bc.groupSpacing = 10 bc.barWidth = 10 bc.valueAxis.valueMin = -15 bc.valueAxis.valueMax = +15 bc.valueAxis.valueStep = 5 bc.valueAxis.labels.fontName = 'Helvetica' bc.valueAxis.labels.fontSize = 8 bc.valueAxis.labels.boxAnchor = 'n' # irrelevant (becomes 'c') bc.valueAxis.labels.textAnchor = 'middle' bc.valueAxis.configure(bc.data) bc.categoryAxis.categoryNames = labels bc.categoryAxis.labels.fontName = 'Helvetica' bc.categoryAxis.labels.fontSize = 8 bc.categoryAxis.labels.dx = -150 drawing.add(bc) return drawing def sampleH2b(): "Sample of multi-series bar chart." data = [(2.4, -5.7, 2, 5, 9.2), (0.6, -4.9, -3, 4, 6.8) ] labels = ("Q3 2000", "Year to Date", "12 months", "Annualised\n3 years", "Since 07.10.99") drawing = Drawing(400, 200) bc = HorizontalBarChart() bc.x = 80 bc.y = 50 bc.height = 120 bc.width = 300 bc.data = data bc.barSpacing = 5 bc.groupSpacing = 10 bc.barWidth = 10 bc.valueAxis.valueMin = -15 bc.valueAxis.valueMax = +15 bc.valueAxis.valueStep = 5 bc.valueAxis.labels.fontName = 'Helvetica' bc.valueAxis.labels.fontSize = 8 bc.valueAxis.labels.boxAnchor = 'n' # irrelevant (becomes 'c') bc.valueAxis.labels.textAnchor = 'middle' bc.categoryAxis.categoryNames = labels bc.categoryAxis.labels.fontName = 'Helvetica' bc.categoryAxis.labels.fontSize = 8 bc.categoryAxis.labels.dx = -150 drawing.add(bc) return drawing def sampleH2c(): "Sample of multi-series bar chart." data = [(2.4, -5.7, 2, 5, 9.99), (0.6, -4.9, -3, 4, 9.99) ] labels = ("Q3 2000", "Year to Date", "12 months", "Annualised\n3 years", "Since 07.10.99") drawing = Drawing(400, 200) bc = HorizontalBarChart() bc.x = 80 bc.y = 50 bc.height = 120 bc.width = 300 bc.data = data bc.barSpacing = 2 bc.groupSpacing = 10 bc.barWidth = 10 bc.valueAxis.valueMin = -15 bc.valueAxis.valueMax = +15 bc.valueAxis.valueStep = 5 bc.valueAxis.labels.fontName = 'Helvetica' bc.valueAxis.labels.fontSize = 8 bc.valueAxis.labels.boxAnchor = 'n' bc.valueAxis.labels.textAnchor = 'middle' bc.categoryAxis.categoryNames = labels bc.categoryAxis.labels.fontName = 'Helvetica' bc.categoryAxis.labels.fontSize = 8 bc.categoryAxis.labels.dx = -150 bc.barLabels.nudge = 10 bc.barLabelFormat = '%0.2f' bc.barLabels.dx = 0 bc.barLabels.dy = 0 bc.barLabels.boxAnchor = 'n' # irrelevant (becomes 'c') bc.barLabels.fontName = 'Helvetica' bc.barLabels.fontSize = 6 drawing.add(bc) return drawing def sampleH3(): "A really horizontal bar chart (compared to the equivalent faked one)." names = ("UK Equities", "US Equities", "European Equities", "Japanese Equities", "Pacific (ex Japan) Equities", "Emerging Markets Equities", "UK Bonds", "Overseas Bonds", "UK Index-Linked", "Cash") series1 = (-1.5, 0.3, 0.5, 1.0, 0.8, 0.7, 0.4, 0.1, 1.0, 0.3) series2 = (0.0, 0.33, 0.55, 1.1, 0.88, 0.77, 0.44, 0.11, 1.10, 0.33) assert len(names) == len(series1), "bad data" assert len(names) == len(series2), "bad data" drawing = Drawing(400, 200) bc = HorizontalBarChart() bc.x = 100 bc.y = 20 bc.height = 150 bc.width = 250 bc.data = (series1,) bc.bars.fillColor = colors.green bc.barLabelFormat = '%0.2f' bc.barLabels.dx = 0 bc.barLabels.dy = 0 bc.barLabels.boxAnchor = 'w' # irrelevant (becomes 'c') bc.barLabels.fontName = 'Helvetica' bc.barLabels.fontSize = 6 bc.barLabels.nudge = 10 bc.valueAxis.visible = 0 bc.valueAxis.valueMin = -2 bc.valueAxis.valueMax = +2 bc.valueAxis.valueStep = 1 bc.categoryAxis.tickLeft = 0 bc.categoryAxis.tickRight = 0 bc.categoryAxis.categoryNames = names bc.categoryAxis.labels.boxAnchor = 'w' bc.categoryAxis.labels.dx = -170 bc.categoryAxis.labels.fontName = 'Helvetica' bc.categoryAxis.labels.fontSize = 6 g = Group(bc) drawing.add(g) return drawing def sampleH4a(): "A bar chart showing value axis region starting at *exactly* zero." drawing = Drawing(400, 200) data = [(13, 20)] bc = HorizontalBarChart() bc.x = 50 bc.y = 50 bc.height = 125 bc.width = 300 bc.data = data bc.strokeColor = colors.black bc.valueAxis.valueMin = 0 bc.valueAxis.valueMax = 60 bc.valueAxis.valueStep = 15 bc.categoryAxis.labels.boxAnchor = 'e' bc.categoryAxis.categoryNames = ['Ying', 'Yang'] drawing.add(bc) return drawing def sampleH4b(): "A bar chart showing value axis region starting *below* zero." drawing = Drawing(400, 200) data = [(13, 20)] bc = HorizontalBarChart() bc.x = 50 bc.y = 50 bc.height = 125 bc.width = 300 bc.data = data bc.strokeColor = colors.black bc.valueAxis.valueMin = -10 bc.valueAxis.valueMax = 60 bc.valueAxis.valueStep = 15 bc.categoryAxis.labels.boxAnchor = 'e' bc.categoryAxis.categoryNames = ['Ying', 'Yang'] drawing.add(bc) return drawing def sampleH4c(): "A bar chart showing value axis region starting *above* zero." drawing = Drawing(400, 200) data = [(13, 20)] bc = HorizontalBarChart() bc.x = 50 bc.y = 50 bc.height = 125 bc.width = 300 bc.data = data bc.strokeColor = colors.black bc.valueAxis.valueMin = 10 bc.valueAxis.valueMax = 60 bc.valueAxis.valueStep = 15 bc.categoryAxis.labels.boxAnchor = 'e' bc.categoryAxis.categoryNames = ['Ying', 'Yang'] drawing.add(bc) return drawing def sampleH4d(): "A bar chart showing value axis region entirely *below* zero." drawing = Drawing(400, 200) data = [(-13, -20)] bc = HorizontalBarChart() bc.x = 50 bc.y = 50 bc.height = 125 bc.width = 300 bc.data = data bc.strokeColor = colors.black bc.valueAxis.valueMin = -30 bc.valueAxis.valueMax = -10 bc.valueAxis.valueStep = 15 bc.categoryAxis.labels.boxAnchor = 'e' bc.categoryAxis.categoryNames = ['Ying', 'Yang'] drawing.add(bc) return drawing dataSample5 = [(10, 60), (20, 50), (30, 40), (40, 30)] def sampleH5a(): "A simple bar chart with no expressed spacing attributes." drawing = Drawing(400, 200) data = dataSample5 bc = HorizontalBarChart() bc.x = 50 bc.y = 50 bc.height = 125 bc.width = 300 bc.data = data bc.strokeColor = colors.black bc.valueAxis.valueMin = 0 bc.valueAxis.valueMax = 60 bc.valueAxis.valueStep = 15 bc.categoryAxis.labels.boxAnchor = 'e' bc.categoryAxis.categoryNames = ['Ying', 'Yang'] drawing.add(bc) return drawing def sampleH5b(): "A simple bar chart with proportional spacing." drawing = Drawing(400, 200) data = dataSample5 bc = HorizontalBarChart() bc.x = 50 bc.y = 50 bc.height = 125 bc.width = 300 bc.data = data bc.strokeColor = colors.black bc.useAbsolute = 0 bc.barWidth = 40 bc.groupSpacing = 20 bc.barSpacing = 10 bc.valueAxis.valueMin = 0 bc.valueAxis.valueMax = 60 bc.valueAxis.valueStep = 15 bc.categoryAxis.labels.boxAnchor = 'e' bc.categoryAxis.categoryNames = ['Ying', 'Yang'] drawing.add(bc) return drawing def sampleH5c1(): "A simple bar chart with absolute spacing." drawing = Drawing(400, 200) data = dataSample5 bc = HorizontalBarChart() bc.x = 50 bc.y = 50 bc.height = 125 bc.width = 300 bc.data = data bc.strokeColor = colors.black bc.useAbsolute = 1 bc.barWidth = 10 bc.groupSpacing = 0 bc.barSpacing = 0 bc.valueAxis.valueMin = 0 bc.valueAxis.valueMax = 60 bc.valueAxis.valueStep = 15 bc.categoryAxis.labels.boxAnchor = 'e' bc.categoryAxis.categoryNames = ['Ying', 'Yang'] drawing.add(bc) return drawing def sampleH5c2(): "Simple bar chart with absolute spacing." drawing = Drawing(400, 200) data = dataSample5 bc = HorizontalBarChart() bc.x = 50 bc.y = 50 bc.height = 125 bc.width = 300 bc.data = data bc.strokeColor = colors.black bc.useAbsolute = 1 bc.barWidth = 10 bc.groupSpacing = 20 bc.barSpacing = 0 bc.valueAxis.valueMin = 0 bc.valueAxis.valueMax = 60 bc.valueAxis.valueStep = 15 bc.categoryAxis.labels.boxAnchor = 'e' bc.categoryAxis.categoryNames = ['Ying', 'Yang'] drawing.add(bc) return drawing def sampleH5c3(): "Simple bar chart with absolute spacing." drawing = Drawing(400, 200) data = dataSample5 bc = HorizontalBarChart() bc.x = 50 bc.y = 20 bc.height = 155 bc.width = 300 bc.data = data bc.strokeColor = colors.black bc.useAbsolute = 1 bc.barWidth = 10 bc.groupSpacing = 0 bc.barSpacing = 2 bc.valueAxis.valueMin = 0 bc.valueAxis.valueMax = 60 bc.valueAxis.valueStep = 15 bc.categoryAxis.labels.boxAnchor = 'e' bc.categoryAxis.categoryNames = ['Ying', 'Yang'] drawing.add(bc) return drawing def sampleH5c4(): "Simple bar chart with absolute spacing." drawing = Drawing(400, 200) data = dataSample5 bc = HorizontalBarChart() bc.x = 50 bc.y = 50 bc.height = 125 bc.width = 300 bc.data = data bc.strokeColor = colors.black bc.useAbsolute = 1 bc.barWidth = 10 bc.groupSpacing = 20 bc.barSpacing = 10 bc.valueAxis.valueMin = 0 bc.valueAxis.valueMax = 60 bc.valueAxis.valueStep = 15 bc.categoryAxis.labels.boxAnchor = 'e' bc.categoryAxis.categoryNames = ['Ying', 'Yang'] drawing.add(bc) return drawing def sampleSymbol1(): "Simple bar chart using symbol attribute." drawing = Drawing(400, 200) data = dataSample5 bc = VerticalBarChart() bc.x = 50 bc.y = 50 bc.height = 125 bc.width = 300 bc.data = data bc.strokeColor = colors.black bc.barWidth = 10 bc.groupSpacing = 15 bc.barSpacing = 3 bc.valueAxis.valueMin = 0 bc.valueAxis.valueMax = 60 bc.valueAxis.valueStep = 15 bc.categoryAxis.labels.boxAnchor = 'e' bc.categoryAxis.categoryNames = ['Ying', 'Yang'] from reportlab.graphics.widgets.grids import ShadedRect sym1 = ShadedRect() sym1.fillColorStart = colors.black sym1.fillColorEnd = colors.blue sym1.orientation = 'horizontal' sym1.strokeWidth = 0 sym2 = ShadedRect() sym2.fillColorStart = colors.black sym2.fillColorEnd = colors.pink sym2.orientation = 'horizontal' sym2.strokeWidth = 0 sym3 = ShadedRect() sym3.fillColorStart = colors.blue sym3.fillColorEnd = colors.white sym3.orientation = 'vertical' sym3.cylinderMode = 1 sym3.strokeWidth = 0 bc.bars.symbol = sym1 bc.bars[2].symbol = sym2 bc.bars[3].symbol = sym3 drawing.add(bc) return drawing def sampleStacked1(): "Simple bar chart using symbol attribute." drawing = Drawing(400, 200) data = dataSample5 bc = VerticalBarChart() bc.categoryAxis.style = 'stacked' bc.x = 50 bc.y = 50 bc.height = 125 bc.width = 300 bc.data = data bc.strokeColor = colors.black bc.barWidth = 10 bc.groupSpacing = 15 bc.valueAxis.valueMin = 0 bc.categoryAxis.labels.boxAnchor = 'e' bc.categoryAxis.categoryNames = ['Ying', 'Yang'] from reportlab.graphics.widgets.grids import ShadedRect bc.bars.symbol = ShadedRect() bc.bars.symbol.fillColorStart = colors.red bc.bars.symbol.fillColorEnd = colors.white bc.bars.symbol.orientation = 'vertical' bc.bars.symbol.cylinderMode = 1 bc.bars.symbol.strokeWidth = 0 bc.bars[1].symbol = ShadedRect() bc.bars[1].symbol.fillColorStart = colors.magenta bc.bars[1].symbol.fillColorEnd = colors.white bc.bars[1].symbol.orientation = 'vertical' bc.bars[1].symbol.cylinderMode = 1 bc.bars[1].symbol.strokeWidth = 0 bc.bars[2].symbol = ShadedRect() bc.bars[2].symbol.fillColorStart = colors.green bc.bars[2].symbol.fillColorEnd = colors.white bc.bars[2].symbol.orientation = 'vertical' bc.bars[2].symbol.cylinderMode = 1 bc.bars[2].symbol.strokeWidth = 0 bc.bars[3].symbol = ShadedRect() bc.bars[3].symbol.fillColorStart = colors.blue bc.bars[3].symbol.fillColorEnd = colors.white bc.bars[3].symbol.orientation = 'vertical' bc.bars[3].symbol.cylinderMode = 1 bc.bars[3].symbol.strokeWidth = 0 drawing.add(bc) return drawing #class version of function sampleH5c4 above class SampleH5c4(Drawing): "Simple bar chart with absolute spacing." def __init__(self,width=400,height=200,*args,**kw): Drawing.__init__(self,width,height,*args,**kw) bc = HorizontalBarChart() bc.x = 50 bc.y = 50 bc.height = 125 bc.width = 300 bc.data = dataSample5 bc.strokeColor = colors.black bc.useAbsolute = 1 bc.barWidth = 10 bc.groupSpacing = 20 bc.barSpacing = 10 bc.valueAxis.valueMin = 0 bc.valueAxis.valueMax = 60 bc.valueAxis.valueStep = 15 bc.categoryAxis.labels.boxAnchor = 'e' bc.categoryAxis.categoryNames = ['Ying', 'Yang'] self.add(bc,name='HBC') bc._computeSimpleBarLabelPositions() ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1691062243.0 reportlab-4.1.0/src/reportlab/graphics/charts/dotbox.py0000664000175000017500000001474414462707743022650 0ustar00rptlabrptlabfrom reportlab.lib.colors import _PCMYK_black from reportlab.graphics.charts.textlabels import Label from reportlab.graphics.shapes import Circle, Drawing, Group, Line, Rect, String from reportlab.graphics.widgetbase import Widget from reportlab.lib.attrmap import * from reportlab.lib.validators import * from reportlab.lib.units import cm from reportlab.pdfbase.pdfmetrics import getFont from reportlab.graphics.charts.lineplots import _maxWidth class DotBox(Widget): """Returns a dotbox widget.""" #Doesn't use TypedPropertyCollection for labels - this can be a later improvement _attrMap = AttrMap( xlabels = AttrMapValue(isNoneOrListOfNoneOrStrings, desc="List of text labels for boxes on left hand side"), ylabels = AttrMapValue(isNoneOrListOfNoneOrStrings, desc="Text label for second box on left hand side"), labelFontName = AttrMapValue(isString, desc="Name of font used for the labels"), labelFontSize = AttrMapValue(isNumber, desc="Size of font used for the labels"), labelOffset = AttrMapValue(isNumber, desc="Space between label text and grid edge"), strokeWidth = AttrMapValue(isNumber, desc='Width of the grid and dot outline'), gridDivWidth = AttrMapValue(isNumber, desc="Width of each 'box'"), gridColor = AttrMapValue(isColor, desc='Colour for the box and gridding'), dotDiameter = AttrMapValue(isNumber, desc="Diameter of the circle used for the 'dot'"), dotColor = AttrMapValue(isColor, desc='Colour of the circle on the box'), dotXPosition = AttrMapValue(isNumber, desc='X Position of the circle'), dotYPosition = AttrMapValue(isNumber, desc='X Position of the circle'), x = AttrMapValue(isNumber, desc='X Position of dotbox'), y = AttrMapValue(isNumber, desc='Y Position of dotbox'), ) def __init__(self): self.xlabels=["Value", "Blend", "Growth"] self.ylabels=["Small", "Medium", "Large"] self.labelFontName = "Helvetica" self.labelFontSize = 6 self.labelOffset = 5 self.strokeWidth = 0.5 self.gridDivWidth=0.5*cm self.gridColor=colors.Color(25/255.0,77/255.0,135/255.0) self.dotDiameter=0.4*cm self.dotColor=colors.Color(232/255.0,224/255.0,119/255.0) self.dotXPosition = 1 self.dotYPosition = 1 self.x = 30 self.y = 5 def _getDrawingDimensions(self): leftPadding=rightPadding=topPadding=bottomPadding=5 #find width of grid tx=len(self.xlabels)*self.gridDivWidth #add padding (and offset) tx=tx+leftPadding+rightPadding+self.labelOffset #add in maximum width of text tx=tx+_maxWidth(self.xlabels, self.labelFontName, self.labelFontSize) #find height of grid ty=len(self.ylabels)*self.gridDivWidth #add padding (and offset) ty=ty+topPadding+bottomPadding+self.labelOffset #add in maximum width of text ty=ty+_maxWidth(self.ylabels, self.labelFontName, self.labelFontSize) #print (tx, ty) return (tx,ty) def demo(self,drawing=None): if not drawing: tx,ty=self._getDrawingDimensions() drawing = Drawing(tx,ty) drawing.add(self.draw()) return drawing def draw(self): g = Group() #box g.add(Rect(self.x,self.y,len(self.xlabels)*self.gridDivWidth,len(self.ylabels)*self.gridDivWidth, strokeColor=self.gridColor, strokeWidth=self.strokeWidth, fillColor=None)) #internal gridding for f in range (1,len(self.ylabels)): #horizontal g.add(Line(strokeColor=self.gridColor, strokeWidth=self.strokeWidth, x1 = self.x, y1 = self.y+f*self.gridDivWidth, x2 = self.x+len(self.xlabels)*self.gridDivWidth, y2 = self.y+f*self.gridDivWidth)) for f in range (1,len(self.xlabels)): #vertical g.add(Line(strokeColor=self.gridColor, strokeWidth=self.strokeWidth, x1 = self.x+f*self.gridDivWidth, y1 = self.y, x2 = self.x+f*self.gridDivWidth, y2 = self.y+len(self.ylabels)*self.gridDivWidth)) # draw the 'dot' g.add(Circle(strokeColor=self.gridColor, strokeWidth=self.strokeWidth, fillColor=self.dotColor, cx = self.x+(self.dotXPosition*self.gridDivWidth), cy = self.y+(self.dotYPosition*self.gridDivWidth), r = self.dotDiameter/2.0)) #used for centering y-labels (below) ascent=getFont(self.labelFontName).face.ascent if ascent==0: ascent=0.718 # default (from helvetica) ascent=ascent*self.labelFontSize # normalize #do y-labels if self.ylabels != None: for f in range (len(self.ylabels)-1,-1,-1): if self.ylabels[f]!= None: g.add(String(strokeColor=self.gridColor, text = self.ylabels[f], fontName = self.labelFontName, fontSize = self.labelFontSize, fillColor=_PCMYK_black, x = self.x-self.labelOffset, y = self.y+(f*self.gridDivWidth+(self.gridDivWidth-ascent)/2.0), textAnchor = 'end')) #do x-labels if self.xlabels != None: for f in range (0,len(self.xlabels)): if self.xlabels[f]!= None: l=Label() l.x=self.x+(f*self.gridDivWidth)+(self.gridDivWidth+ascent)/2.0 l.y=self.y+(len(self.ylabels)*self.gridDivWidth)+self.labelOffset l.angle=90 l.textAnchor='start' l.fontName = self.labelFontName l.fontSize = self.labelFontSize l.fillColor = _PCMYK_black l.setText(self.xlabels[f]) l.boxAnchor = 'sw' l.draw() g.add(l) return g if __name__ == "__main__": d = DotBox() d.demo().save(fnRoot="dotbox")././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1704966359.0 reportlab-4.1.0/src/reportlab/graphics/charts/doughnut.py0000664000175000017500000004476614547734327023217 0ustar00rptlabrptlab#Copyright ReportLab Europe Ltd. 2000-2017 #see license.txt for license details #history https://hg.reportlab.com/hg-public/reportlab/log/tip/src/reportlab/graphics/charts/doughnut.py # doughnut chart __version__='3.3.0' __doc__="""Doughnut chart Produces a circular chart like the doughnut charts produced by Excel. Can handle multiple series (which produce concentric 'rings' in the chart). """ from math import sin, cos, pi from reportlab.lib import colors from reportlab.lib.validators import isNumber, isListOfStringsOrNone, OneOf,\ isBoolean, isNumberOrNone, isListOfNoneOrNumber,\ isListOfListOfNoneOrNumber, EitherOr, NoneOr, \ isCallable from reportlab.lib.attrmap import * from reportlab.graphics.shapes import Group, Drawing, Wedge from reportlab.graphics.widgetbase import TypedPropertyCollection from reportlab.graphics.charts.piecharts import AbstractPieChart, WedgeProperties, _addWedgeLabel, fixLabelOverlaps from functools import reduce class SectorProperties(WedgeProperties): """This holds descriptive information about the sectors in a doughnut chart. It is not to be confused with the 'sector itself'; this just holds a recipe for how to format one, and does not allow you to hack the angles. It can format a genuine Sector object for you with its format method. """ _attrMap = AttrMap(BASE=WedgeProperties, ) class Doughnut(AbstractPieChart): _attrMap = AttrMap( x = AttrMapValue(isNumber, desc='X position of the chart within its container.'), y = AttrMapValue(isNumber, desc='Y position of the chart within its container.'), width = AttrMapValue(isNumber, desc='width of doughnut bounding box. Need not be same as width.'), height = AttrMapValue(isNumber, desc='height of doughnut bounding box. Need not be same as height.'), data = AttrMapValue(EitherOr((isListOfNoneOrNumber,isListOfListOfNoneOrNumber)), desc='list of numbers defining sector sizes; need not sum to 1'), labels = AttrMapValue(isListOfStringsOrNone, desc="optional list of labels to use for each data point"), startAngle = AttrMapValue(isNumber, desc="angle of first slice; like the compass, 0 is due North"), direction = AttrMapValue(OneOf('clockwise', 'anticlockwise'), desc="'clockwise' or 'anticlockwise'"), slices = AttrMapValue(None, desc="collection of sector descriptor objects"), simpleLabels = AttrMapValue(isBoolean, desc="If true(default) use String not super duper WedgeLabel"), # advanced usage checkLabelOverlap = AttrMapValue(isBoolean, desc="If true check and attempt to fix\n standard label overlaps(default off)",advancedUsage=1), sideLabels = AttrMapValue(isBoolean, desc="If true attempt to make chart with labels along side and pointers", advancedUsage=1), innerRadiusFraction = AttrMapValue(isNumberOrNone, desc='None or the fraction of the radius to be used as the inner hole.\nIf not a suitable default will be used.'), labelClass=AttrMapValue(NoneOr(isCallable), desc="A class factory to use for non simple labels"), ) def __init__(self): self.x = 0 self.y = 0 self.width = 100 self.height = 100 self.data = [1,1] self.labels = None # or list of strings self.startAngle = 90 self.direction = "clockwise" self.simpleLabels = 1 self.checkLabelOverlap = 0 self.sideLabels = 0 self.innerRadiusFraction = None self.slices = TypedPropertyCollection(SectorProperties) self.slices[0].fillColor = colors.darkcyan self.slices[1].fillColor = colors.blueviolet self.slices[2].fillColor = colors.blue self.slices[3].fillColor = colors.cyan self.slices[4].fillColor = colors.pink self.slices[5].fillColor = colors.magenta self.slices[6].fillColor = colors.yellow def demo(self): d = Drawing(200, 100) dn = Doughnut() dn.x = 50 dn.y = 10 dn.width = 100 dn.height = 80 dn.data = [10,20,30,40,50,60] dn.labels = ['a','b','c','d','e','f'] dn.slices.strokeWidth=0.5 dn.slices[3].popout = 10 dn.slices[3].strokeWidth = 2 dn.slices[3].strokeDashArray = [2,2] dn.slices[3].labelRadius = 1.75 dn.slices[3].fontColor = colors.red dn.slices[0].fillColor = colors.darkcyan dn.slices[1].fillColor = colors.blueviolet dn.slices[2].fillColor = colors.blue dn.slices[3].fillColor = colors.cyan dn.slices[4].fillColor = colors.aquamarine dn.slices[5].fillColor = colors.cadetblue dn.slices[6].fillColor = colors.lightcoral d.add(dn) return d def normalizeData(self, data=None): from operator import add sum = float(reduce(add,data,0)) return abs(sum)>=1e-8 and list(map(lambda x,f=360./sum: f*x, data)) or len(data)*[0] def makeSectors(self): # normalize slice data data = self.data multi = isListOfListOfNoneOrNumber(data) if multi: #it's a nested list, more than one sequence normData = [] n = [] for l in data: t = self.normalizeData(l) normData.append(t) n.append(len(t)) self._seriesCount = max(n) else: normData = self.normalizeData(data) n = len(normData) self._seriesCount = n #labels checkLabelOverlap = self.checkLabelOverlap L = [] L_add = L.append labels = self.labels if labels is None: labels = [] if not multi: labels = [''] * n else: for m in n: labels = list(labels) + [''] * m else: #there's no point in raising errors for less than enough labels if #we silently create all for the extreme case of no labels. if not multi: i = n-len(labels) if i>0: labels = list(labels) + [''] * i else: tlab = 0 for m in n: tlab += m i = tlab-len(labels) if i>0: labels = list(labels) + [''] * i self.labels = labels xradius = self.width/2.0 yradius = self.height/2.0 centerx = self.x + xradius centery = self.y + yradius if self.direction == "anticlockwise": whichWay = 1 else: whichWay = -1 g = Group() startAngle = self.startAngle #% 360 styleCount = len(self.slices) irf = self.innerRadiusFraction if multi: #multi-series doughnut ndata = len(data) if irf is None: yir = (yradius/2.5)/ndata xir = (xradius/2.5)/ndata else: yir = yradius*irf xir = xradius*irf ydr = (yradius-yir)/ndata xdr = (xradius-xir)/ndata for sn,series in enumerate(normData): for i,angle in enumerate(series): endAngle = (startAngle + (angle * whichWay)) #% 360 aa = abs(startAngle-endAngle) if aa<1e-5: startAngle = endAngle continue if startAngle < endAngle: a1 = startAngle a2 = endAngle else: a1 = endAngle a2 = startAngle startAngle = endAngle #if we didn't use %stylecount here we'd end up with the later sectors #all having the default style sectorStyle = self.slices[sn,i%styleCount] # is it a popout? cx, cy = centerx, centery if sectorStyle.popout != 0: # pop out the sector averageAngle = (a1+a2)/2.0 aveAngleRadians = averageAngle * pi/180.0 popdistance = sectorStyle.popout cx = centerx + popdistance * cos(aveAngleRadians) cy = centery + popdistance * sin(aveAngleRadians) yr1 = yir+sn*ydr yr = yr1 + ydr xr1 = xir+sn*xdr xr = xr1 + xdr if len(series) > 1: theSector = Wedge(cx, cy, xr, a1, a2, yradius=yr, radius1=xr1, yradius1=yr1) else: theSector = Wedge(cx, cy, xr, a1, a2, yradius=yr, radius1=xr1, yradius1=yr1, annular=True) theSector.fillColor = sectorStyle.fillColor theSector.strokeColor = sectorStyle.strokeColor theSector.strokeWidth = sectorStyle.strokeWidth theSector.strokeDashArray = sectorStyle.strokeDashArray shader = sectorStyle.shadingKind if shader: nshades = aa / float(sectorStyle.shadingAngle) if nshades > 1: shader = colors.Whiter if shader=='lighten' else colors.Blacker nshades = 1+int(nshades) shadingAmount = 1-sectorStyle.shadingAmount if sectorStyle.shadingDirection=='normal': dsh = (1-shadingAmount)/float(nshades-1) shf1 = shadingAmount else: dsh = (shadingAmount-1)/float(nshades-1) shf1 = 1 shda = (a2-a1)/float(nshades) shsc = sectorStyle.fillColor theSector.fillColor = None for ish in range(nshades): sha1 = a1 + ish*shda sha2 = a1 + (ish+1)*shda shc = shader(shsc,shf1 + dsh*ish) if len(series)>1: shSector = Wedge(cx, cy, xr, sha1, sha2, yradius=yr, radius1=xr1, yradius1=yr1) else: shSector = Wedge(cx, cy, xr, sha1, sha2, yradius=yr, radius1=xr1, yradius1=yr1, annular=True) shSector.fillColor = shc shSector.strokeColor = None shSector.strokeWidth = 0 g.add(shSector) g.add(theSector) if sn == 0 and sectorStyle.visible and sectorStyle.label_visible: text = self.getSeriesName(i,'') if text: averageAngle = (a1+a2)/2.0 aveAngleRadians = averageAngle*pi/180.0 labelRadius = sectorStyle.labelRadius rx = xradius*labelRadius ry = yradius*labelRadius labelX = centerx + (0.5 * self.width * cos(aveAngleRadians) * labelRadius) labelY = centery + (0.5 * self.height * sin(aveAngleRadians) * labelRadius) l = _addWedgeLabel(self,text,averageAngle,labelX,labelY,sectorStyle) if checkLabelOverlap: l._origdata = { 'x': labelX, 'y':labelY, 'angle': averageAngle, 'rx': rx, 'ry':ry, 'cx':cx, 'cy':cy, 'bounds': l.getBounds(), } L_add(l) else: #single series doughnut if irf is None: yir = yradius/2.5 xir = xradius/2.5 else: yir = yradius*irf xir = xradius*irf for i,angle in enumerate(normData): endAngle = (startAngle + (angle * whichWay)) #% 360 aa = abs(startAngle-endAngle) if aa<1e-5: startAngle = endAngle continue if startAngle < endAngle: a1 = startAngle a2 = endAngle else: a1 = endAngle a2 = startAngle startAngle = endAngle #if we didn't use %stylecount here we'd end up with the later sectors #all having the default style sectorStyle = self.slices[i%styleCount] # is it a popout? cx, cy = centerx, centery if sectorStyle.popout != 0: # pop out the sector averageAngle = (a1+a2)/2.0 aveAngleRadians = averageAngle * pi/180.0 popdistance = sectorStyle.popout cx = centerx + popdistance * cos(aveAngleRadians) cy = centery + popdistance * sin(aveAngleRadians) if n > 1: theSector = Wedge(cx, cy, xradius, a1, a2, yradius=yradius, radius1=xir, yradius1=yir) elif n==1: theSector = Wedge(cx, cy, xradius, a1, a2, yradius=yradius, radius1=xir, yradius1=yir, annular=True) theSector.fillColor = sectorStyle.fillColor theSector.strokeColor = sectorStyle.strokeColor theSector.strokeWidth = sectorStyle.strokeWidth theSector.strokeDashArray = sectorStyle.strokeDashArray shader = sectorStyle.shadingKind if shader: nshades = aa / float(sectorStyle.shadingAngle) if nshades > 1: shader = colors.Whiter if shader=='lighten' else colors.Blacker nshades = 1+int(nshades) shadingAmount = 1-sectorStyle.shadingAmount if sectorStyle.shadingDirection=='normal': dsh = (1-shadingAmount)/float(nshades-1) shf1 = shadingAmount else: dsh = (shadingAmount-1)/float(nshades-1) shf1 = 1 shda = (a2-a1)/float(nshades) shsc = sectorStyle.fillColor theSector.fillColor = None for ish in range(nshades): sha1 = a1 + ish*shda sha2 = a1 + (ish+1)*shda shc = shader(shsc,shf1 + dsh*ish) if n > 1: shSector = Wedge(cx, cy, xradius, sha1, sha2, yradius=yradius, radius1=xir, yradius1=yir) elif n==1: shSector = Wedge(cx, cy, xradius, sha1, sha2, yradius=yradius, radius1=xir, yradius1=yir, annular=True) shSector.fillColor = shc shSector.strokeColor = None shSector.strokeWidth = 0 g.add(shSector) g.add(theSector) # now draw a label if labels[i] and sectorStyle.visible and sectorStyle.label_visible: averageAngle = (a1+a2)/2.0 aveAngleRadians = averageAngle*pi/180.0 labelRadius = sectorStyle.labelRadius labelX = centerx + (0.5 * self.width * cos(aveAngleRadians) * labelRadius) labelY = centery + (0.5 * self.height * sin(aveAngleRadians) * labelRadius) rx = xradius*labelRadius ry = yradius*labelRadius l = _addWedgeLabel(self,labels[i],averageAngle,labelX,labelY,sectorStyle) if checkLabelOverlap: l._origdata = { 'x': labelX, 'y':labelY, 'angle': averageAngle, 'rx': rx, 'ry':ry, 'cx':cx, 'cy':cy, 'bounds': l.getBounds(), } L_add(l) if checkLabelOverlap and L: fixLabelOverlaps(L) for l in L: g.add(l) return g def draw(self): g = Group() g.add(self.makeSectors()) return g def sample1(): "Make up something from the individual Sectors" d = Drawing(400, 400) g = Group() s1 = Wedge(centerx=200, centery=200, radius=150, startangledegrees=0, endangledegrees=120, radius1=100) s1.fillColor=colors.red s1.strokeColor=None d.add(s1) s2 = Wedge(centerx=200, centery=200, radius=150, startangledegrees=120, endangledegrees=240, radius1=100) s2.fillColor=colors.green s2.strokeColor=None d.add(s2) s3 = Wedge(centerx=200, centery=200, radius=150, startangledegrees=240, endangledegrees=260, radius1=100) s3.fillColor=colors.blue s3.strokeColor=None d.add(s3) s4 = Wedge(centerx=200, centery=200, radius=150, startangledegrees=260, endangledegrees=360, radius1=100) s4.fillColor=colors.gray s4.strokeColor=None d.add(s4) return d def sample2(): "Make a simple demo" d = Drawing(400, 400) dn = Doughnut() dn.x = 50 dn.y = 50 dn.width = 300 dn.height = 300 dn.data = [10,20,30,40,50,60] d.add(dn) return d def sample3(): "Make a more complex demo" d = Drawing(400, 400) dn = Doughnut() dn.x = 50 dn.y = 50 dn.width = 300 dn.height = 300 dn.data = [[10,20,30,40,50,60], [10,20,30,40]] dn.labels = ['a','b','c','d','e','f'] d.add(dn) return d def sample4(): "Make a more complex demo with Label Overlap fixing" d = Drawing(400, 400) dn = Doughnut() dn.x = 50 dn.y = 50 dn.width = 300 dn.height = 300 dn.data = [[10,20,30,40,50,60], [10,20,30,40]] dn.labels = ['a','b','c','d','e','f'] dn.checkLabelOverlap = True d.add(dn) return d if __name__=='__main__': from reportlab.graphics.renderPDF import drawToFile d = sample1() drawToFile(d, 'doughnut1.pdf') d = sample2() drawToFile(d, 'doughnut2.pdf') d = sample3() drawToFile(d, 'doughnut3.pdf') ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1704966359.0 reportlab-4.1.0/src/reportlab/graphics/charts/legends.py0000664000175000017500000006212714547734327022772 0ustar00rptlabrptlab#Copyright ReportLab Europe Ltd. 2000-2017 #see license.txt for license details #history https://hg.reportlab.com/hg-public/reportlab/log/tip/src/reportlab/graphics/charts/legends.py __version__='3.3.0' __doc__="""This will be a collection of legends to be used with charts.""" import copy from reportlab.lib import colors from reportlab.lib.validators import isNumber, OneOf, isString, isColorOrNone,\ isNumberOrNone, isListOfNumbersOrNone, isBoolean,\ EitherOr, NoneOr, AutoOr, isAuto, Auto, isBoxAnchor, SequenceOf, isInstanceOf from reportlab.lib.attrmap import * from reportlab.pdfbase.pdfmetrics import stringWidth, getFont from reportlab.graphics.widgetbase import Widget, TypedPropertyCollection, PropHolder from reportlab.graphics.shapes import Drawing, Group, String, Rect, Line, STATE_DEFAULTS from reportlab.graphics.widgets.markers import uSymbol2Symbol, isSymbol from reportlab.lib.utils import isSeq, find_locals, isStr, asNative from reportlab.graphics.shapes import _baseGFontName def _transMax(n,A): X = n*[0] m = 0 for a in A: m = max(m,len(a)) for i,x in enumerate(a): X[i] = max(X[i],x) X = [0] + X[:m] for i in range(m): X[i+1] += X[i] return X def _objStr(s): if isStr(s): return asNative(s) else: return str(s) def _getStr(s): if isSeq(s): return list(map(_getStr,s)) else: return _objStr(s) def _getLines(s): if isSeq(s): return tuple([(x or '').split('\n') for x in s]) else: return (s or '').split('\n') def _getLineCount(s): T = _getLines(s) if isSeq(s): return max([len(x) for x in T]) else: return len(T) def _getWidths(i,s, fontName, fontSize, subCols): S = [] aS = S.append if isSeq(s): for j,t in enumerate(s): sc = subCols[j,i] fN = getattr(sc,'fontName',fontName) fS = getattr(sc,'fontSize',fontSize) m = [stringWidth(x, fN, fS) for x in t.split('\n')] m = max(sc.minWidth,m and max(m) or 0) aS(m) aS(sc.rpad) del S[-1] else: sc = subCols[0,i] fN = getattr(sc,'fontName',fontName) fS = getattr(sc,'fontSize',fontSize) m = [stringWidth(x, fN, fS) for x in s.split('\n')] aS(max(sc.minWidth,m and max(m) or 0)) return S class SubColProperty(PropHolder): dividerLines = 0 _attrMap = AttrMap( minWidth = AttrMapValue(isNumber,desc="minimum width for this subcol"), rpad = AttrMapValue(isNumber,desc="right padding for this subcol"), align = AttrMapValue(OneOf('left','right','center','centre','numeric'),desc='alignment in subCol'), fontName = AttrMapValue(isString, desc="Font name of the strings"), fontSize = AttrMapValue(isNumber, desc="Font size of the strings"), leading = AttrMapValue(isNumberOrNone, desc="leading for the strings"), fillColor = AttrMapValue(isColorOrNone, desc="fontColor"), underlines = AttrMapValue(EitherOr((NoneOr(isInstanceOf(Line)),SequenceOf(isInstanceOf(Line),emptyOK=0,lo=0,hi=0x7fffffff))), desc="underline definitions"), overlines = AttrMapValue(EitherOr((NoneOr(isInstanceOf(Line)),SequenceOf(isInstanceOf(Line),emptyOK=0,lo=0,hi=0x7fffffff))), desc="overline definitions"), dx = AttrMapValue(isNumber, desc="x offset from default position"), dy = AttrMapValue(isNumber, desc="y offset from default position"), vAlign = AttrMapValue(OneOf('top','bottom','middle'),desc='vertical alignment in the row'), ) class LegendCallout: def _legendValues(legend,*args): '''return a tuple of values from the first function up the stack with isinstance(self,legend)''' L = find_locals(lambda L: L.get('self',None) is legend and L or None) return tuple([L[a] for a in args]) _legendValues = staticmethod(_legendValues) def _selfOrLegendValues(self,legend,*args): L = find_locals(lambda L: L.get('self',None) is legend and L or None) return tuple([getattr(self,a,L[a]) for a in args]) def __call__(self,legend,g,thisx,y,colName): col, name = colName class LegendSwatchCallout(LegendCallout): def __call__(self,legend,g,thisx,y,i,colName,swatch): col, name = colName class LegendColEndCallout(LegendCallout): def __call__(self,legend, g, x, xt, y, width, lWidth): pass class Legend(Widget): """A simple legend containing rectangular swatches and strings. The swatches are filled rectangles whenever the respective color object in 'colorNamePairs' is a subclass of Color in reportlab.lib.colors. Otherwise the object passed instead is assumed to have 'x', 'y', 'width' and 'height' attributes. A legend then tries to set them or catches any error. This lets you plug-in any widget you like as a replacement for the default rectangular swatches. Strings can be nicely aligned left or right to the swatches. """ _attrMap = AttrMap( x = AttrMapValue(isNumber, desc="x-coordinate of upper-left reference point"), y = AttrMapValue(isNumber, desc="y-coordinate of upper-left reference point"), deltax = AttrMapValue(isNumberOrNone, desc="x-distance between neighbouring swatches"), deltay = AttrMapValue(isNumberOrNone, desc="y-distance between neighbouring swatches"), dxTextSpace = AttrMapValue(isNumber, desc="Distance between swatch rectangle and text"), autoXPadding = AttrMapValue(isNumber, desc="x Padding between columns if deltax=None",advancedUsage=1), autoYPadding = AttrMapValue(isNumber, desc="y Padding between rows if deltay=None",advancedUsage=1), yGap = AttrMapValue(isNumber, desc="Additional gap between rows",advancedUsage=1), dx = AttrMapValue(isNumber, desc="Width of swatch rectangle"), dy = AttrMapValue(isNumber, desc="Height of swatch rectangle"), columnMaximum = AttrMapValue(isNumber, desc="Max. number of items per column"), alignment = AttrMapValue(OneOf("left", "right"), desc="Alignment of text with respect to swatches"), colorNamePairs = AttrMapValue(None, desc="List of color/name tuples (color can also be widget)"), fontName = AttrMapValue(isString, desc="Font name of the strings"), fontSize = AttrMapValue(isNumber, desc="Font size of the strings"), leading = AttrMapValue(isNumberOrNone, desc="text leading"), fillColor = AttrMapValue(isColorOrNone, desc="swatches filling color"), strokeColor = AttrMapValue(isColorOrNone, desc="Border color of the swatches"), strokeWidth = AttrMapValue(isNumber, desc="Width of the border color of the swatches"), swatchMarker = AttrMapValue(NoneOr(AutoOr(isSymbol)), desc="None, Auto() or makeMarker('Diamond') ...",advancedUsage=1), callout = AttrMapValue(None, desc="a user callout(self,g,x,y,(color,text))",advancedUsage=1), boxAnchor = AttrMapValue(isBoxAnchor,'Anchor point for the legend area'), variColumn = AttrMapValue(isBoolean,'If true column widths may vary (default is false)',advancedUsage=1), dividerLines = AttrMapValue(OneOf(0,1,2,3,4,5,6,7),'If 1 we have dividers between the rows | 2 for extra top | 4 for bottom',advancedUsage=1), dividerWidth = AttrMapValue(isNumber, desc="dividerLines width",advancedUsage=1), dividerColor = AttrMapValue(isColorOrNone, desc="dividerLines color",advancedUsage=1), dividerDashArray = AttrMapValue(isListOfNumbersOrNone, desc='Dash array for dividerLines.',advancedUsage=1), dividerOffsX = AttrMapValue(SequenceOf(isNumber,emptyOK=0,lo=2,hi=2), desc='divider lines X offsets',advancedUsage=1), dividerOffsY = AttrMapValue(isNumber, desc="dividerLines Y offset",advancedUsage=1), colEndCallout = AttrMapValue(None, desc="a user callout(self,g, x, xt, y,width, lWidth)",advancedUsage=1), subCols = AttrMapValue(None,desc="subColumn properties"), swatchCallout = AttrMapValue(None, desc="a user swatch callout(self,g,x,y,i,(col,name),swatch)",advancedUsage=1), swdx = AttrMapValue(isNumber, desc="x position adjustment for the swatch"), swdy = AttrMapValue(isNumber, desc="y position adjustment for the swatch"), ) def __init__(self): # Upper-left reference point. self.x = 0 self.y = 0 # Alginment of text with respect to swatches. self.alignment = "left" # x- and y-distances between neighbouring swatches. self.deltax = 75 self.deltay = 20 self.autoXPadding = 5 self.autoYPadding = 2 # Size of swatch rectangle. self.dx = 10 self.dy = 10 self.swdx = 0 self.swdy = 0 # Distance between swatch rectangle and text. self.dxTextSpace = 10 # Max. number of items per column. self.columnMaximum = 3 # Color/name pairs. self.colorNamePairs = [ (colors.red, "red"), (colors.blue, "blue"), (colors.green, "green"), (colors.pink, "pink"), (colors.yellow, "yellow") ] # Font name and size of the labels. self.fontName = STATE_DEFAULTS['fontName'] self.fontSize = STATE_DEFAULTS['fontSize'] self.leading = None #will be used as 1.2*fontSize self.fillColor = STATE_DEFAULTS['fillColor'] self.strokeColor = STATE_DEFAULTS['strokeColor'] self.strokeWidth = STATE_DEFAULTS['strokeWidth'] self.swatchMarker = None self.boxAnchor = 'nw' self.yGap = 0 self.variColumn = 0 self.dividerLines = 0 self.dividerWidth = 0.5 self.dividerDashArray = None self.dividerColor = colors.black self.dividerOffsX = (0,0) self.dividerOffsY = 0 self.colEndCallout = None self._init_subCols() def _init_subCols(self): sc = self.subCols = TypedPropertyCollection(SubColProperty) sc.rpad = 1 sc.dx = sc.dy = sc.minWidth = 0 sc.align = 'right' sc[0].align = 'left' sc.vAlign = 'top' #that's current sc.leading = None def _getChartStyleName(self,chart): for a in 'lines', 'bars', 'slices', 'strands': if hasattr(chart,a): return a return None def _getChartStyle(self,chart): return getattr(chart,self._getChartStyleName(chart),None) def _getTexts(self,colorNamePairs): if not isAuto(colorNamePairs): texts = [_getStr(p[1]) for p in colorNamePairs] else: chart = getattr(colorNamePairs,'chart',getattr(colorNamePairs,'obj',None)) texts = [chart.getSeriesName(i,'series %d' % i) for i in range(chart._seriesCount)] return texts def _calculateMaxBoundaries(self, colorNamePairs): "Calculate the maximum width of some given strings." fontName = self.fontName fontSize = self.fontSize subCols = self.subCols M = [_getWidths(i, m, fontName, fontSize, subCols) for i,m in enumerate(self._getTexts(colorNamePairs))] if not M: return [0,0] n = max([len(m) for m in M]) if self.variColumn: columnMaximum = self.columnMaximum return [_transMax(n,M[r:r+columnMaximum]) for r in range(0,len(M),self.columnMaximum)] else: return _transMax(n,M) def _calcHeight(self): dy = self.dy yGap = self.yGap thisy = upperlefty = self.y - dy fontSize = self.fontSize fontName = self.fontName ascent=getFont(fontName).face.ascent/1000. if ascent==0: ascent=0.718 # default (from helvetica) ascent *= fontSize leading = fontSize*1.2 deltay = self.deltay if not deltay: deltay = max(dy,leading)+self.autoYPadding columnCount = 0 count = 0 lowy = upperlefty lim = self.columnMaximum - 1 for name in self._getTexts(self.colorNamePairs): y0 = thisy+(dy-ascent)*0.5 y = y0 - _getLineCount(name)*leading leadingMove = 2*y0-y-thisy newy = thisy-max(deltay,leadingMove)-yGap lowy = min(y,newy,lowy) if count==lim: count = 0 thisy = upperlefty columnCount += 1 else: thisy = newy count = count+1 return upperlefty - lowy def _defaultSwatch(self,x,thisy,dx,dy,fillColor,strokeWidth,strokeColor): return Rect(x, thisy, dx, dy, fillColor = fillColor, strokeColor = strokeColor, strokeWidth = strokeWidth, ) def draw(self): colorNamePairs = self.colorNamePairs autoCP = isAuto(colorNamePairs) if autoCP: chart = getattr(colorNamePairs,'chart',getattr(colorNamePairs,'obj',None)) swatchMarker = None autoCP = Auto(obj=chart) n = chart._seriesCount chartTexts = self._getTexts(colorNamePairs) else: swatchMarker = getattr(self,'swatchMarker',None) if isAuto(swatchMarker): chart = getattr(swatchMarker,'chart',getattr(swatchMarker,'obj',None)) swatchMarker = Auto(obj=chart) n = len(colorNamePairs) dx = self.dx dy = self.dy alignment = self.alignment columnMaximum = self.columnMaximum deltax = self.deltax deltay = self.deltay dxTextSpace = self.dxTextSpace fontName = self.fontName fontSize = self.fontSize fillColor = self.fillColor strokeWidth = self.strokeWidth strokeColor = self.strokeColor subCols = self.subCols leading = fontSize*1.2 yGap = self.yGap if not deltay: deltay = max(dy,leading)+self.autoYPadding ba = self.boxAnchor maxWidth = self._calculateMaxBoundaries(colorNamePairs) nCols = int((n+columnMaximum-1)/(columnMaximum*1.0)) xW = dx+dxTextSpace+self.autoXPadding variColumn = self.variColumn if variColumn: width = sum([m[-1] for m in maxWidth])+xW*nCols else: deltax = max(maxWidth[-1]+xW,deltax) width = nCols*deltax maxWidth = nCols*[maxWidth] thisx = self.x thisy = self.y - self.dy if ba not in ('ne','n','nw','autoy'): height = self._calcHeight() if ba in ('e','c','w'): thisy += height/2. else: thisy += height if ba not in ('nw','w','sw','autox'): if ba in ('n','c','s'): thisx -= width/2 else: thisx -= width upperlefty = thisy g = Group() ascent=getFont(fontName).face.ascent/1000. if ascent==0: ascent=0.718 # default (from helvetica) ascent *= fontSize # normalize lim = columnMaximum - 1 callout = getattr(self,'callout',None) scallout = getattr(self,'swatchCallout',None) dividerLines = self.dividerLines if dividerLines: dividerWidth = self.dividerWidth dividerColor = self.dividerColor dividerDashArray = self.dividerDashArray dividerOffsX = self.dividerOffsX dividerOffsY = self.dividerOffsY for i in range(n): if autoCP: col = autoCP col.index = i name = chartTexts[i] else: col, name = colorNamePairs[i] if isAuto(swatchMarker): col = swatchMarker col.index = i if isAuto(name): name = getattr(swatchMarker,'chart',getattr(swatchMarker,'obj',None)).getSeriesName(i,'series %d' % i) T = _getLines(name) S = [] aS = S.append j = int(i/(columnMaximum*1.0)) jOffs = maxWidth[j] # thisy+dy/2 = y+leading/2 y = y0 = thisy+(dy-ascent)*0.5 if callout: callout(self,g,thisx,y,(col,name)) if alignment == "left": x = thisx xn = thisx+jOffs[-1]+dxTextSpace elif alignment == "right": x = thisx+dx+dxTextSpace xn = thisx else: raise ValueError("bad alignment") if not isSeq(name): T = [T] lineCount = _getLineCount(name) yd = y for k,lines in enumerate(T): y = y0 kk = k*2 x1 = x+jOffs[kk] x2 = x+jOffs[kk+1] sc = subCols[k,i] anchor = sc.align scdx = sc.dx scdy = sc.dy fN = getattr(sc,'fontName',fontName) fS = getattr(sc,'fontSize',fontSize) fC = getattr(sc,'fillColor',fillColor) fL = sc.leading or 1.2*fontSize if fN==fontName: fA = (ascent*fS)/fontSize else: fA = getFont(fontName).face.ascent/1000. if fA==0: fA=0.718 fA *= fS vA = sc.vAlign if vA=='top': vAdy = 0 else: vAdy = -fL * (lineCount - len(lines)) if vA=='middle': vAdy *= 0.5 if anchor=='left': anchor = 'start' xoffs = x1 elif anchor=='right': anchor = 'end' xoffs = x2 elif anchor=='numeric': xoffs = x2 else: anchor = 'middle' xoffs = 0.5*(x1+x2) for t in lines: aS(String(xoffs+scdx,y+scdy+vAdy,t,fontName=fN,fontSize=fS,fillColor=fC, textAnchor = anchor)) y -= fL yd = min(yd,y) y += fL for iy, a in ((y-max(fL-fA,0),'underlines'),(y+fA,'overlines')): il = getattr(sc,a,None) if il: if not isinstance(il,(tuple,list)): il = (il,) for l in il: l = copy.copy(l) l.y1 += iy l.y2 += iy l.x1 += x1 l.x2 += x2 aS(l) x = xn y = yd leadingMove = 2*y0-y-thisy if dividerLines: xd = thisx+dx+dxTextSpace+jOffs[-1]+dividerOffsX[1] yd = thisy+dy*0.5+dividerOffsY if ((dividerLines&1) and i%columnMaximum) or ((dividerLines&2) and not i%columnMaximum): g.add(Line(thisx+dividerOffsX[0],yd,xd,yd, strokeColor=dividerColor, strokeWidth=dividerWidth, strokeDashArray=dividerDashArray)) if (dividerLines&4) and (i%columnMaximum==lim or i==(n-1)): yd -= max(deltay,leadingMove)+yGap g.add(Line(thisx+dividerOffsX[0],yd,xd,yd, strokeColor=dividerColor, strokeWidth=dividerWidth, strokeDashArray=dividerDashArray)) # Make a 'normal' color swatch... swatchX = x + getattr(self,'swdx',0) swatchY = thisy + getattr(self,'swdy',0) if isAuto(col): chart = getattr(col,'chart',getattr(col,'obj',None)) c = chart.makeSwatchSample(getattr(col,'index',i),swatchX,swatchY,dx,dy) elif isinstance(col, colors.Color): if isSymbol(swatchMarker): c = uSymbol2Symbol(swatchMarker,swatchX+dx/2.,swatchY+dy/2.,col) else: c = self._defaultSwatch(swatchX,swatchY,dx,dy,fillColor=col,strokeWidth=strokeWidth,strokeColor=strokeColor) elif col is not None: try: c = copy.deepcopy(col) c.x = swatchX c.y = swatchY c.width = dx c.height = dy except: c = None else: c = None if c: g.add(c) if scallout: scallout(self,g,thisx,y0,i,(col,name),c) for s in S: g.add(s) if self.colEndCallout and (i%columnMaximum==lim or i==(n-1)): if alignment == "left": xt = thisx else: xt = thisx+dx+dxTextSpace yd = thisy+dy*0.5+dividerOffsY - (max(deltay,leadingMove)+yGap) self.colEndCallout(self, g, thisx, xt, yd, jOffs[-1], jOffs[-1]+dx+dxTextSpace) if i%columnMaximum==lim: if variColumn: thisx += jOffs[-1]+xW else: thisx = thisx+deltax thisy = upperlefty else: thisy = thisy-max(deltay,leadingMove)-yGap return g def demo(self): "Make sample legend." d = Drawing(200, 100) legend = Legend() legend.alignment = 'left' legend.x = 0 legend.y = 100 legend.dxTextSpace = 5 items = 'red green blue yellow pink black white'.split() items = [(getattr(colors, i), i) for i in items] legend.colorNamePairs = items d.add(legend, 'legend') return d class TotalAnnotator(LegendColEndCallout): def __init__(self, lText='Total', rText='0.0', fontName=_baseGFontName, fontSize=10, fillColor=colors.black, strokeWidth=0.5, strokeColor=colors.black, strokeDashArray=None, dx=0, dy=0, dly=0, dlx=(0,0)): self.lText = lText self.rText = rText self.fontName = fontName self.fontSize = fontSize self.fillColor = fillColor self.dy = dy self.dx = dx self.dly = dly self.dlx = dlx self.strokeWidth = strokeWidth self.strokeColor = strokeColor self.strokeDashArray = strokeDashArray def __call__(self,legend, g, x, xt, y, width, lWidth): from reportlab.graphics.shapes import String, Line fontSize = self.fontSize fontName = self.fontName fillColor = self.fillColor strokeColor = self.strokeColor strokeWidth = self.strokeWidth ascent=getFont(fontName).face.ascent/1000. if ascent==0: ascent=0.718 # default (from helvetica) ascent *= fontSize leading = fontSize*1.2 yt = y+self.dy-ascent*1.3 if self.lText and fillColor: g.add(String(xt,yt,self.lText, fontName=fontName, fontSize=fontSize, fillColor=fillColor, textAnchor = "start")) if self.rText: g.add(String(xt+width,yt,self.rText, fontName=fontName, fontSize=fontSize, fillColor=fillColor, textAnchor = "end")) if strokeWidth and strokeColor: yL = y+self.dly-leading g.add(Line(x+self.dlx[0],yL,x+self.dlx[1]+lWidth,yL, strokeColor=strokeColor, strokeWidth=strokeWidth, strokeDashArray=self.strokeDashArray)) class LineSwatch(Widget): """basically a Line with properties added so it can be used in a LineLegend""" _attrMap = AttrMap( x = AttrMapValue(isNumber, desc="x-coordinate for swatch line start point"), y = AttrMapValue(isNumber, desc="y-coordinate for swatch line start point"), width = AttrMapValue(isNumber, desc="length of swatch line"), height = AttrMapValue(isNumber, desc="used for line strokeWidth"), strokeColor = AttrMapValue(isColorOrNone, desc="color of swatch line"), strokeWidth = AttrMapValue(isNumberOrNone, desc="thickness of the swatch"), strokeDashArray = AttrMapValue(isListOfNumbersOrNone, desc="dash array for swatch line"), ) def __init__(self): from reportlab.lib.colors import red self.x = 0 self.y = 0 self.width = 20 self.height = 1 self.strokeColor = red self.strokeDashArray = None self.strokeWidth = 1 def draw(self): l = Line(self.x,self.y,self.x+self.width,self.y) l.strokeColor = self.strokeColor l.strokeDashArray = self.strokeDashArray l.strokeWidth = self.strokeWidth return l class LineLegend(Legend): """A subclass of Legend for drawing legends with lines as the swatches rather than rectangles. Useful for lineCharts and linePlots. Should be similar in all other ways the the standard Legend class. """ def __init__(self): Legend.__init__(self) # Size of swatch rectangle. self.dx = 10 self.dy = 2 def _defaultSwatch(self,x,thisy,dx,dy,fillColor,strokeWidth,strokeColor): l = LineSwatch() l.x = x l.y = thisy l.width = dx l.height = dy l.strokeColor = fillColor l.strokeWidth = strokeWidth return l ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1707393347.0 reportlab-4.1.0/src/reportlab/graphics/charts/linecharts.py0000664000175000017500000006542014561140503023463 0ustar00rptlabrptlab#Copyright ReportLab Europe Ltd. 2000-2017 #see license.txt for license details #history https://hg.reportlab.com/hg-public/reportlab/log/tip/src/reportlab/graphics/charts/linecharts.py __version__='3.3.0' __doc__="""This modules defines a very preliminary Line Chart example.""" from reportlab.lib import colors from reportlab.lib.validators import isNumber, isNumberOrNone, isColorOrNone, \ isListOfStringsOrNone, isBoolean, NoneOr, \ isListOfNumbersOrNone, isStringOrNone, OneOf, Percentage from reportlab.lib.attrmap import * from reportlab.lib.utils import flatten from reportlab.graphics.widgetbase import TypedPropertyCollection, PropHolder, tpcGetItem from reportlab.graphics.shapes import Line, Rect, Group, Drawing, Polygon, PolyLine from reportlab.graphics.widgets.signsandsymbols import NoEntry from reportlab.graphics.charts.axes import XCategoryAxis, YValueAxis from reportlab.graphics.charts.textlabels import Label from reportlab.graphics.widgets.markers import uSymbol2Symbol, isSymbol, makeMarker from reportlab.graphics.charts.areas import PlotArea from reportlab.graphics.charts.legends import _objStr from .utils import FillPairedData class LineChartProperties(PropHolder): _attrMap = AttrMap( strokeWidth = AttrMapValue(isNumber, desc='Width of a line.'), strokeColor = AttrMapValue(isColorOrNone, desc='Color of a line or border.'), fillColor = AttrMapValue(isColorOrNone, desc='fill color of a bar.'), strokeDashArray = AttrMapValue(isListOfNumbersOrNone, desc='Dash array of a line.'), symbol = AttrMapValue(NoneOr(isSymbol), desc='Widget placed at data points.',advancedUsage=1), shader = AttrMapValue(None, desc='Shader Class.',advancedUsage=1), filler = AttrMapValue(None, desc='Filler Class.',advancedUsage=1), name = AttrMapValue(isStringOrNone, desc='Name of the line.'), lineStyle = AttrMapValue(NoneOr(OneOf('line','joinedLine','bar')), desc="What kind of plot this line is",advancedUsage=1), barWidth = AttrMapValue(isNumberOrNone,desc="Percentage of available width to be used for a bar",advancedUsage=1), inFill = AttrMapValue(isBoolean, desc='If true flood fill to x axis',advancedUsage=1), ) class AbstractLineChart(PlotArea): def makeSwatchSample(self,rowNo, x, y, width, height): baseStyle = self.lines styleIdx = rowNo % len(baseStyle) style = baseStyle[styleIdx] color = style.strokeColor yh2 = y+height/2. lineStyle = getattr(style,'lineStyle',None) if lineStyle=='bar': dash = getattr(style, 'strokeDashArray', getattr(baseStyle,'strokeDashArray',None)) strokeWidth= getattr(style, 'strokeWidth', getattr(style, 'strokeWidth',None)) L = Rect(x,y,width,height,strokeWidth=strokeWidth,strokeColor=color,strokeLineCap=0,strokeDashArray=dash,fillColor=getattr(style,'fillColor',color)) elif self.joinedLines or lineStyle=='joinedLine': dash = getattr(style, 'strokeDashArray', getattr(baseStyle,'strokeDashArray',None)) strokeWidth= getattr(style, 'strokeWidth', getattr(style, 'strokeWidth',None)) L = Line(x,yh2,x+width,yh2,strokeColor=color,strokeLineCap=0) if strokeWidth: L.strokeWidth = strokeWidth if dash: L.strokeDashArray = dash else: L = None if hasattr(style, 'symbol'): S = style.symbol elif hasattr(baseStyle, 'symbol'): S = baseStyle.symbol else: S = None if S: S = uSymbol2Symbol(S,x+width/2.,yh2,color) if S and L: g = Group() g.add(L) g.add(S) return g return S or L def getSeriesName(self,i,default=None): '''return series name i or default''' return _objStr(getattr(self.lines[i],'name',default)) class LineChart(AbstractLineChart): pass # This is conceptually similar to the VerticalBarChart. # Still it is better named HorizontalLineChart... :-/ class HorizontalLineChart(LineChart): """Line chart with multiple lines. A line chart is assumed to have one category and one value axis. Despite its generic name this particular line chart class has a vertical value axis and a horizontal category one. It may evolve into individual horizontal and vertical variants (like with the existing bar charts). Available attributes are: x: x-position of lower-left chart origin y: y-position of lower-left chart origin width: chart width height: chart height useAbsolute: disables auto-scaling of chart elements (?) lineLabelNudge: distance of data labels to data points lineLabels: labels associated with data values lineLabelFormat: format string or callback function groupSpacing: space between categories joinedLines: enables drawing of lines strokeColor: color of chart lines (?) fillColor: color for chart background (?) lines: style list, used cyclically for data series valueAxis: value axis object categoryAxis: category axis object categoryNames: category names data: chart data, a list of data series of equal length """ _attrMap = AttrMap(BASE=LineChart, useAbsolute = AttrMapValue(isNumber, desc='Flag to use absolute spacing values.',advancedUsage=1), lineLabelNudge = AttrMapValue(isNumber, desc='Distance between a data point and its label.',advancedUsage=1), lineLabels = AttrMapValue(None, desc='Handle to the list of data point labels.'), lineLabelFormat = AttrMapValue(None, desc='Formatting string or function used for data point labels.'), lineLabelArray = AttrMapValue(None, desc='explicit array of line label values, must match size of data if present.'), groupSpacing = AttrMapValue(isNumber, desc='? - Likely to disappear.'), joinedLines = AttrMapValue(isNumber, desc='Display data points joined with lines if true.'), lines = AttrMapValue(None, desc='Handle of the lines.'), valueAxis = AttrMapValue(None, desc='Handle of the value axis.'), categoryAxis = AttrMapValue(None, desc='Handle of the category axis.'), categoryNames = AttrMapValue(isListOfStringsOrNone, desc='List of category names.'), data = AttrMapValue(None, desc='Data to be plotted, list of (lists of) numbers.'), inFill = AttrMapValue(isBoolean, desc='Whether infilling should be done.',advancedUsage=1), reversePlotOrder = AttrMapValue(isBoolean, desc='If true reverse plot order.',advancedUsage=1), annotations = AttrMapValue(None, desc='list of callables, will be called with self, xscale, yscale.',advancedUsage=1), ) def __init__(self): LineChart.__init__(self) # Allow for a bounding rectangle. self.strokeColor = None self.fillColor = None # Named so we have less recoding for the horizontal one :-) self.categoryAxis = XCategoryAxis() self.valueAxis = YValueAxis() # This defines two series of 3 points. Just an example. self.data = [(100,110,120,130), (70, 80, 80, 90)] self.categoryNames = ('North','South','East','West') self.lines = TypedPropertyCollection(LineChartProperties) self.lines.strokeWidth = 1 self.lines[0].strokeColor = colors.red self.lines[1].strokeColor = colors.green self.lines[2].strokeColor = colors.blue # control spacing. if useAbsolute = 1 then # the next parameters are in points; otherwise # they are 'proportions' and are normalized to # fit the available space. self.useAbsolute = 0 #- not done yet self.groupSpacing = 1 #5 self.lineLabels = TypedPropertyCollection(Label) self.lineLabelFormat = None self.lineLabelArray = None # This says whether the origin is above or below # the data point. +10 means put the origin ten points # above the data point if value > 0, or ten # points below if data value < 0. This is different # to label dx/dy which are not dependent on the # sign of the data. self.lineLabelNudge = 10 # If you have multiple series, by default they butt # together. # New line chart attributes. self.joinedLines = 1 # Connect items with straight lines. self.inFill = 0 self.reversePlotOrder = 0 def demo(self): """Shows basic use of a line chart.""" drawing = Drawing(200, 100) data = [ (13, 5, 20, 22, 37, 45, 19, 4), (14, 10, 21, 28, 38, 46, 25, 5) ] lc = HorizontalLineChart() lc.x = 20 lc.y = 10 lc.height = 85 lc.width = 170 lc.data = data lc.lines.symbol = makeMarker('Circle') drawing.add(lc) return drawing def calcPositions(self): """Works out where they go. Sets an attribute _positions which is a list of lists of (x, y) matching the data. """ self._seriesCount = len(self.data) self._rowLength = max(list(map(len,self.data))) if self.useAbsolute: # Dimensions are absolute. normFactor = 1.0 else: # Dimensions are normalized to fit. normWidth = self.groupSpacing availWidth = self.categoryAxis.scale(0)[1] normFactor = availWidth / normWidth self._normFactor = normFactor self._yzero = yzero = self.valueAxis.scale(0) self._hngs = hngs = 0.5 * self.groupSpacing * normFactor pairs = set() P = [].append cscale = self.categoryAxis.scale vscale = self.valueAxis.scale data = self.data n = len(data) for rowNo,row in enumerate(data): if isinstance(row, FillPairedData): other = row.other if 0<=other 0: label.setOrigin(x, y + self.lineLabelNudge) else: label.setOrigin(x, y - self.lineLabelNudge) label.setText(labelText) else: label = None return label def drawLabel(self, G, rowNo, colNo, x, y): '''Draw a label for a given item in the list. G must have an add method''' G.add(self._innerDrawLabel(rowNo,colNo,x,y)) def makeLines(self): g = Group() labelFmt = self.lineLabelFormat P = self._positions if self.reversePlotOrder: P.reverse() lines = self.lines styleCount = len(lines) _inFill = self.inFill if (_inFill or self._pairInFills or [rowNo for rowNo in range(len(P)) if getattr(lines[rowNo%styleCount],'inFill',False)] ): inFillY = self.categoryAxis._y inFillX0 = self.valueAxis._x inFillX1 = inFillX0 + self.categoryAxis._length inFillG = getattr(self,'_inFillG',g) yzero = self._yzero bypos = None # Iterate over data rows. for rowNo, row in enumerate(reversed(P) if self.reversePlotOrder else P): styleIdx = rowNo % styleCount rowStyle = lines[styleIdx] strokeColor = rowStyle.strokeColor fillColor = getattr(rowStyle,'fillColor',strokeColor) inFill = getattr(rowStyle,'inFill',_inFill) dash = getattr(rowStyle, 'strokeDashArray', None) lineStyle = getattr(rowStyle,'lineStyle',None) if hasattr(rowStyle, 'strokeWidth'): strokeWidth = rowStyle.strokeWidth elif hasattr(lines, 'strokeWidth'): strokeWidth = lines.strokeWidth else: strokeWidth = None # Iterate over data columns. if lineStyle=='bar': if bypos is None: x = self.valueAxis bypos = max(x._y,yzero) byneg = min(x._y+x._length,yzero) barWidth = getattr(rowStyle,'barWidth',Percentage(50)) if isinstance(barWidth,Percentage): hbw = self._hngs*barWidth*0.01 else: hbw = barWidth*0.5 for x, y in row: _y0 = byneg if y self.y + self.height) or (xAxisCrossesAt < self.y)): y = self.y else: y = xAxisCrossesAt cA.setPosition(self.x, y, self.width) cA.configure(self.data) self.calcPositions() g = Group() g.add(self.makeBackground()) if self.inFill: self._inFillG = Group() g.add(self._inFillG) g.add(cA) g.add(vA) cAdgl = getattr(cA,'drawGridLast',False) vAdgl = getattr(vA,'drawGridLast',False) if not cAdgl: cA.makeGrid(g,parent=self,dim=vA.getGridDims) if not vAdgl: vA.makeGrid(g,parent=self,dim=cA.getGridDims) g.add(self.makeLines()) if cAdgl: cA.makeGrid(g,parent=self,dim=vA.getGridDims) if vAdgl: vA.makeGrid(g,parent=self,dim=cA.getGridDims) for a in getattr(self,'annotations',()): g.add(a(self,cA.scale,vA.scale)) return g def _fakeItemKey(a): '''t, z0, z1, x, y = a[:5]''' return (-a[1],a[3],a[0],-a[4]) class _FakeGroup: def __init__(self): self._data = [] def add(self,what): if what: self._data.append(what) def value(self): return self._data def sort(self): self._data.sort(key=_fakeItemKey) #for t in self._data: print t class HorizontalLineChart3D(HorizontalLineChart): _attrMap = AttrMap(BASE=HorizontalLineChart, theta_x = AttrMapValue(isNumber, desc='dx/dz'), theta_y = AttrMapValue(isNumber, desc='dy/dz'), zDepth = AttrMapValue(isNumber, desc='depth of an individual series'), zSpace = AttrMapValue(isNumber, desc='z gap around series'), ) theta_x = .5 theta_y = .5 zDepth = 10 zSpace = 3 def calcPositions(self): HorizontalLineChart.calcPositions(self) nSeries = self._seriesCount zSpace = self.zSpace zDepth = self.zDepth if self.categoryAxis.style=='parallel_3d': _3d_depth = nSeries*zDepth+(nSeries+1)*zSpace else: _3d_depth = zDepth + 2*zSpace self._3d_dx = self.theta_x*_3d_depth self._3d_dy = self.theta_y*_3d_depth def _calc_z0(self,rowNo): zSpace = self.zSpace if self.categoryAxis.style=='parallel_3d': z0 = rowNo*(self.zDepth+zSpace)+zSpace else: z0 = zSpace return z0 def _zadjust(self,x,y,z): return x+z*self.theta_x, y+z*self.theta_y def makeLines(self): labelFmt = self.lineLabelFormat P = list(range(len(self._positions))) if self.reversePlotOrder: P.reverse() inFill = self.inFill assert not inFill, "inFill not supported for 3d yet" #if inFill: #inFillY = self.categoryAxis._y #inFillX0 = self.valueAxis._x #inFillX1 = inFillX0 + self.categoryAxis._length #inFillG = getattr(self,'_inFillG',g) zDepth = self.zDepth _zadjust = self._zadjust theta_x = self.theta_x theta_y = self.theta_y F = _FakeGroup() from reportlab.graphics.charts.utils3d import _make_3d_line_info tileWidth = getattr(self,'_3d_tilewidth',None) if not tileWidth and self.categoryAxis.style!='parallel_3d': tileWidth = 1 # Iterate over data rows. for rowNo in P: row = self._positions[rowNo] n = len(row) styleCount = len(self.lines) styleIdx = rowNo % styleCount rowStyle = self.lines[styleIdx] rowColor = rowStyle.strokeColor dash = getattr(rowStyle, 'strokeDashArray', None) z0 = self._calc_z0(rowNo) z1 = z0 + zDepth if hasattr(self.lines[styleIdx], 'strokeWidth'): strokeWidth = self.lines[styleIdx].strokeWidth elif hasattr(self.lines, 'strokeWidth'): strokeWidth = self.lines.strokeWidth else: strokeWidth = None # Iterate over data columns. if self.joinedLines: if n: x0, y0 = row[0] for colNo in range(1,n): x1, y1 = row[colNo] _make_3d_line_info( F, x0, x1, y0, y1, z0, z1, theta_x, theta_y, rowColor, fillColorShaded=None, tileWidth=tileWidth, strokeColor=None, strokeWidth=None, strokeDashArray=None, shading=0.1) x0, y0 = x1, y1 if hasattr(self.lines[styleIdx], 'symbol'): uSymbol = self.lines[styleIdx].symbol elif hasattr(self.lines, 'symbol'): uSymbol = self.lines.symbol else: uSymbol = None if uSymbol: for colNo in range(n): x1, y1 = row[colNo] x1, y1 = _zadjust(x1,y1,z0) symbol = uSymbol2Symbol(uSymbol,x1,y1,rowColor) if symbol: F.add((2,z0,z0,x1,y1,symbol)) # Draw item labels. for colNo in range(n): x1, y1 = row[colNo] x1, y1 = _zadjust(x1,y1,z0) L = self._innerDrawLabel(rowNo, colNo, x1, y1) if L: F.add((2,z0,z0,x1,y1,L)) F.sort() g = Group() for v in F.value(): g.add(v[-1]) return g class VerticalLineChart(LineChart): pass def sample1(): drawing = Drawing(400, 200) data = [ (13, 5, 20, 22, 37, 45, 19, 4), (5, 20, 46, 38, 23, 21, 6, 14) ] lc = HorizontalLineChart() lc.x = 50 lc.y = 50 lc.height = 125 lc.width = 300 lc.data = data lc.joinedLines = 1 lc.lines.symbol = makeMarker('FilledDiamond') lc.lineLabelFormat = '%2.0f' catNames = 'Jan Feb Mar Apr May Jun Jul Aug'.split(' ') lc.categoryAxis.categoryNames = catNames lc.categoryAxis.labels.boxAnchor = 'n' lc.valueAxis.valueMin = 0 lc.valueAxis.valueMax = 60 lc.valueAxis.valueStep = 15 drawing.add(lc) return drawing class SampleHorizontalLineChart(HorizontalLineChart): "Sample class overwriting one method to draw additional horizontal lines." def demo(self): """Shows basic use of a line chart.""" drawing = Drawing(200, 100) data = [ (13, 5, 20, 22, 37, 45, 19, 4), (14, 10, 21, 28, 38, 46, 25, 5) ] lc = SampleHorizontalLineChart() lc.x = 20 lc.y = 10 lc.height = 85 lc.width = 170 lc.data = data lc.strokeColor = colors.white lc.fillColor = colors.HexColor(0xCCCCCC) drawing.add(lc) return drawing def makeBackground(self): g = Group() g.add(HorizontalLineChart.makeBackground(self)) valAxis = self.valueAxis valTickPositions = valAxis._tickValues for y in valTickPositions: y = valAxis.scale(y) g.add(Line(self.x, y, self.x+self.width, y, strokeColor = self.strokeColor)) return g def sample1a(): drawing = Drawing(400, 200) data = [ (13, 5, 20, 22, 37, 45, 19, 4), (5, 20, 46, 38, 23, 21, 6, 14) ] lc = SampleHorizontalLineChart() lc.x = 50 lc.y = 50 lc.height = 125 lc.width = 300 lc.data = data lc.joinedLines = 1 lc.strokeColor = colors.white lc.fillColor = colors.HexColor(0xCCCCCC) lc.lines.symbol = makeMarker('FilledDiamond') lc.lineLabelFormat = '%2.0f' catNames = 'Jan Feb Mar Apr May Jun Jul Aug'.split(' ') lc.categoryAxis.categoryNames = catNames lc.categoryAxis.labels.boxAnchor = 'n' lc.valueAxis.valueMin = 0 lc.valueAxis.valueMax = 60 lc.valueAxis.valueStep = 15 drawing.add(lc) return drawing def sample2(): drawing = Drawing(400, 200) data = [ (13, 5, 20, 22, 37, 45, 19, 4), (5, 20, 46, 38, 23, 21, 6, 14) ] lc = HorizontalLineChart() lc.x = 50 lc.y = 50 lc.height = 125 lc.width = 300 lc.data = data lc.joinedLines = 1 lc.lines.symbol = makeMarker('Smiley') lc.lineLabelFormat = '%2.0f' lc.strokeColor = colors.black lc.fillColor = colors.lightblue catNames = 'Jan Feb Mar Apr May Jun Jul Aug'.split(' ') lc.categoryAxis.categoryNames = catNames lc.categoryAxis.labels.boxAnchor = 'n' lc.valueAxis.valueMin = 0 lc.valueAxis.valueMax = 60 lc.valueAxis.valueStep = 15 drawing.add(lc) return drawing def sample3(): drawing = Drawing(400, 200) data = [ (13, 5, 20, 22, 37, 45, 19, 4), (5, 20, 46, 38, 23, 21, 6, 14) ] lc = HorizontalLineChart() lc.x = 50 lc.y = 50 lc.height = 125 lc.width = 300 lc.data = data lc.joinedLines = 1 lc.lineLabelFormat = '%2.0f' lc.strokeColor = colors.black lc.lines[0].symbol = makeMarker('Smiley') lc.lines[1].symbol = NoEntry lc.lines[0].strokeWidth = 2 lc.lines[1].strokeWidth = 4 catNames = 'Jan Feb Mar Apr May Jun Jul Aug'.split(' ') lc.categoryAxis.categoryNames = catNames lc.categoryAxis.labels.boxAnchor = 'n' lc.valueAxis.valueMin = 0 lc.valueAxis.valueMax = 60 lc.valueAxis.valueStep = 15 drawing.add(lc) return drawing def sampleCandleStick(): from reportlab.graphics.widgetbase import CandleSticks d = Drawing(400, 200) chart = HorizontalLineChart() d.add(chart) chart.y = 20 boxMid = (100, 110, 120, 130) hi = [m+10 for m in boxMid] lo = [m-10 for m in boxMid] boxHi = [m+6 for m in boxMid] boxLo = [m-4 for m in boxMid] boxFillColor = colors.pink boxWidth = 20 crossWidth = 10 candleStrokeWidth = 0.5 candleStrokeColor = colors.black chart.valueAxis.avoidBoundSpace = 5 chart.valueAxis.valueMin = min(min(boxMid),min(hi),min(lo),min(boxLo),min(boxHi)) chart.valueAxis.valueMax = max(max(boxMid),max(hi),max(lo),max(boxLo),max(boxHi)) lines = chart.lines lines[0].strokeColor = None I = range(len(boxMid)) chart.data = [boxMid] lines[0].symbol = candles = CandleSticks(chart=chart, boxFillColor=boxFillColor, boxWidth=boxWidth, crossWidth=crossWidth, strokeWidth=candleStrokeWidth, strokeColor=candleStrokeColor) for i in I: candles[i].setProperties(dict(position=i,boxMid=boxMid[i],crossLo=lo[i],crossHi=hi[i],boxLo=boxLo[i],boxHi=boxHi[i])) return d ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1707393347.0 reportlab-4.1.0/src/reportlab/graphics/charts/lineplots.py0000664000175000017500000014374714561140503023351 0ustar00rptlabrptlab#Copyright ReportLab Europe Ltd. 2000-2017 #see license.txt for license details #history https://hg.reportlab.com/hg-public/reportlab/log/tip/src/reportlab/graphics/charts/lineplots.py __version__='3.3.0' __doc__="""This module defines a very preliminary Line Plot example.""" from reportlab.lib import colors from reportlab.lib.validators import * from reportlab.lib.attrmap import * from reportlab.lib.utils import flatten, isStr from reportlab.graphics.shapes import Drawing, Group, Rect, PolyLine, Polygon, _SetKeyWordArgs from reportlab.graphics.widgetbase import TypedPropertyCollection, PropHolder, tpcGetItem from reportlab.graphics.charts.textlabels import Label from reportlab.graphics.charts.axes import XValueAxis, YValueAxis, AdjYValueAxis, NormalDateXValueAxis from reportlab.graphics.charts.utils import * from reportlab.graphics.widgets.markers import uSymbol2Symbol, makeMarker from reportlab.graphics.widgets.grids import Grid, DoubleGrid, ShadedPolygon from reportlab.pdfbase.pdfmetrics import stringWidth, getFont from reportlab.graphics.charts.areas import PlotArea from .utils import FillPairedData # This might be moved again from here... class LinePlotProperties(PropHolder): _attrMap = AttrMap( strokeWidth = AttrMapValue(isNumber, desc='Width of a line.'), strokeColor = AttrMapValue(isColorOrNone, desc='Color of a line.'), strokeDashArray = AttrMapValue(isListOfNumbersOrNone, desc='Dash array of a line.'), fillColor = AttrMapValue(isColorOrNone, desc='Color of infill defaults to the strokeColor.'), symbol = AttrMapValue(None, desc='Widget placed at data points.',advancedUsage=1), shader = AttrMapValue(None, desc='Shader Class.',advancedUsage=1), filler = AttrMapValue(None, desc='Filler Class.',advancedUsage=1), name = AttrMapValue(isStringOrNone, desc='Name of the line.'), lineStyle = AttrMapValue(NoneOr(OneOf('line','joinedLine','bar')), desc="What kind of plot this line is",advancedUsage=1), barWidth = AttrMapValue(isNumberOrNone,desc="Percentage of available width to be used for a bar",advancedUsage=1), inFill = AttrMapValue(isBoolean, desc='If true flood fill to x axis',advancedUsage=1), ) class InFillValue(int): def __new__(cls,v,yValue=None): self = int.__new__(cls,v) self.yValue = yValue return self class Shader(_SetKeyWordArgs): _attrMap = AttrMap(BASE=PlotArea, vertical = AttrMapValue(isBoolean, desc='If true shade to x axis'), colors = AttrMapValue(SequenceOf(isColorOrNone,lo=2,hi=2), desc='(AxisColor, LineColor)'), ) def shade(self, lp, g, rowNo, rowColor, row): c = [None,None] c = getattr(self,'colors',c) or c if not c[0]: c[0] = getattr(lp,'fillColor',colors.white) if not c[1]: c[1] = rowColor class NoFiller: def fill(self, lp, g, rowNo, rowColor, points): pass class Filler: '''mixin providing simple polygon fill''' _attrMap = AttrMap( fillColor = AttrMapValue(isColorOrNone, desc='filler interior color'), strokeColor = AttrMapValue(isColorOrNone, desc='filler edge color'), strokeWidth = AttrMapValue(isNumberOrNone, desc='filler edge width'), ) def __init__(self,**kw): self.__dict__ = kw def fill(self, lp, g, rowNo, rowColor, points): g.add(Polygon(points, fillColor=getattr(self,'fillColor',rowColor), strokeColor=getattr(self,'strokeColor',rowColor), strokeWidth=getattr(self,'strokeWidth',0.1))) class ShadedPolyFiller(Filler,ShadedPolygon): pass class PolyFiller(Filler,Polygon): pass from reportlab.graphics.charts.linecharts import AbstractLineChart class LinePlot(AbstractLineChart): """Line plot with multiple lines. Both x- and y-axis are value axis (so there are no seperate X and Y versions of this class). """ _attrMap = AttrMap(BASE=PlotArea, reversePlotOrder = AttrMapValue(isBoolean, desc='If true reverse plot order.',advancedUsage=1), lineLabelNudge = AttrMapValue(isNumber, desc='Distance between a data point and its label.',advancedUsage=1), lineLabels = AttrMapValue(None, desc='Handle to the list of data point labels.'), lineLabelFormat = AttrMapValue(None, desc='Formatting string or function used for data point labels.'), lineLabelArray = AttrMapValue(None, desc='explicit array of line label values, must match size of data if present.'), #joinedLines = AttrMapValue(isNumber, desc='Display data points joined with lines if true.'), strokeColor = AttrMapValue(isColorOrNone, desc='Color used for background border of plot area.'), fillColor = AttrMapValue(isColorOrNone, desc='Color used for background interior of plot area.'), lines = AttrMapValue(None, desc='Handle of the lines.'), xValueAxis = AttrMapValue(None, desc='Handle of the x axis.'), yValueAxis = AttrMapValue(None, desc='Handle of the y axis.'), data = AttrMapValue(None, desc='Data to be plotted, list of (lists of) x/y tuples.'), annotations = AttrMapValue(None, desc='list of callables, will be called with self, xscale, yscale.',advancedUsage=1), behindAxes = AttrMapValue(isBoolean, desc='If true use separate line group.',advancedUsage=1), gridFirst = AttrMapValue(isBoolean, desc='If true use draw grids before axes.',advancedUsage=1), ) def __init__(self): PlotArea.__init__(self) self.reversePlotOrder = 0 self.xValueAxis = XValueAxis() self.yValueAxis = YValueAxis() # this defines two series of 3 points. Just an example. self.data = [ ((1,1), (2,2), (2.5,1), (3,3), (4,5)), ((1,2), (2,3), (2.5,2), (3,4), (4,6)) ] self.lines = TypedPropertyCollection(LinePlotProperties) self.lines.strokeWidth = 1 self.joinedLines = 1 # Connect items with straight lines. self.lines[0].strokeColor = colors.red self.lines[1].strokeColor = colors.blue self.lineLabels = TypedPropertyCollection(Label) self.lineLabelFormat = None self.lineLabelArray = None # this says whether the origin is inside or outside # the bar - +10 means put the origin ten points # above the tip of the bar if value > 0, or ten # points inside if bar value < 0. This is different # to label dx/dy which are not dependent on the # sign of the data. self.lineLabelNudge = 10 # if you have multiple series, by default they butt # together. #private attributes self._inFill = None self.annotations = [] self.behindAxes = 0 self.gridFirst = 0 @property def joinedLines(self): return self.lines.lineStyle=='joinedLine' @joinedLines.setter def joinedLines(self,v): self.lines.lineStyle = 'joinedLine' if v else 'line' def demo(self): """Shows basic use of a line chart.""" drawing = Drawing(400, 200) data = [ ((1,1), (2,2), (2.5,1), (3,3), (4,5)), ((1,2), (2,3), (2.5,2), (3.5,5), (4,6)) ] lp = LinePlot() lp.x = 50 lp.y = 50 lp.height = 125 lp.width = 300 lp.data = data lp.joinedLines = 1 lp.lineLabelFormat = '%2.0f' lp.strokeColor = colors.black lp.lines[0].strokeColor = colors.red lp.lines[0].symbol = makeMarker('FilledCircle') lp.lines[1].strokeColor = colors.blue lp.lines[1].symbol = makeMarker('FilledDiamond') lp.xValueAxis.valueMin = 0 lp.xValueAxis.valueMax = 5 lp.xValueAxis.valueStep = 1 lp.yValueAxis.valueMin = 0 lp.yValueAxis.valueMax = 7 lp.yValueAxis.valueStep = 1 drawing.add(lp) return drawing def calcPositions(self): """Works out where they go. Sets an attribute _positions which is a list of lists of (x, y) matching the data. """ self._seriesCount = len(self.data) self._rowLength = max(list(map(len,self.data))) pairs = set() P = [].append xscale = self.xValueAxis.scale yscale = self.yValueAxis.scale data = self.data n = len(data) for rowNo, row in enumerate(data): if isinstance(row, FillPairedData): other = row.other if 0<=other 0: label.setOrigin(x, y + self.lineLabelNudge) else: label.setOrigin(x, y - self.lineLabelNudge) label.setText(labelText) else: label = None return label def drawLabel(self, G, rowNo, colNo, x, y): '''Draw a label for a given item in the list. G must have an add method''' G.add(self._innerDrawLabel(rowNo,colNo,x,y)) def makeLines(self): g = Group() yA = self.yValueAxis xA = self.xValueAxis bubblePlot = getattr(self,'_bubblePlot',None) if bubblePlot: bubbleR = min(yA._bubbleRadius,xA._bubbleRadius) bubbleMax = xA._bubbleMax labelFmt = self.lineLabelFormat P = self._positions _inFill = getattr(self,'_inFill',None) lines = self.lines styleCount = len(lines) if (_inFill or self._pairInFills or [rowNo for rowNo in range(len(P)) if getattr(lines[rowNo%styleCount],'inFill',False)] ): inFillY = getattr(_inFill,'yValue',None) if inFillY is None: inFillY = xA._y else: inFillY = yA.scale(inFillY) inFillX0 = yA._x inFillX1 = inFillX0 + xA._length inFillG = getattr(self,'_inFillG',g) bw = None lG = getattr(self,'_lineG',g) # Iterate over data rows. R = range(len(P)) if self.reversePlotOrder: R = reversed(R) for rowNo in R: row = P[rowNo] styleRowNo = rowNo % styleCount rowStyle = lines[styleRowNo] strokeColor = getattr(rowStyle,'strokeColor',None) strokeWidth = getattr(rowStyle,'strokeWidth',None) fillColor = getattr(rowStyle, 'fillColor', strokeColor) inFill = getattr(rowStyle,'inFill',_inFill) dash = getattr(rowStyle, 'strokeDashArray', None) lineStyle = getattr(rowStyle,'lineStyle',None) if hasattr(rowStyle, 'strokeWidth'): width = rowStyle.strokeWidth elif hasattr(lines, 'strokeWidth'): width = lines.strokeWidth else: width = None # Iterate over data columns. if lineStyle=='bar': if bw is None: x = max(map(len,P)) - 1 #the number of gaps bw = (self.width/x - 1) if x>0 else self.width barWidth = getattr(rowStyle,'barWidth',Percentage(50)) x = self.yValueAxis y0 = x.scale(0) bypos = max(x._y,y0) byneg = min(x._y+x._length,y0) xmin = self.xValueAxis._x xmax = xmin + self.xValueAxis._length if isinstance(barWidth,Percentage): bw *= barWidth*0.005 else: bw = barWidth*0.5 for x, y in row: w = bw #print(f'{x=} {y=} {y0=} {byneg=} {bypos=}') _y0 = byneg if y xmax: w -= xmax - x g.add(Rect(x,_y0,w,y-_y0,strokeWidth=strokeWidth,strokeColor=strokeColor,fillColor=fillColor)) elif lineStyle=='joinedLine': points = flatten(row) if inFill or isinstance(row,FillPairedData): filler = getattr(rowStyle, 'filler', None) if isinstance(row,FillPairedData): fpoints = points + flatten(reversed(P[row.other])) else: fpoints = [inFillX0,inFillY] + points + [inFillX1,inFillY] if filler: filler.fill(self,inFillG,rowNo,fillColor,fpoints) else: inFillG.add(Polygon(fpoints,fillColor=fillColor,strokeColor=strokeColor if strokeColor==fillColor else None,strokeWidth=width or 0.1)) if not inFill or inFill==2 or strokeColor!=fillColor: line = PolyLine(points,strokeColor=strokeColor,strokeLineCap=0,strokeLineJoin=1) if width: line.strokeWidth = width if dash: line.strokeDashArray = dash lG.add(line) if hasattr(rowStyle, 'symbol'): uSymbol = rowStyle.symbol elif hasattr(lines, 'symbol'): uSymbol = lines.symbol else: uSymbol = None if uSymbol: if bubblePlot: drow = self.data[rowNo] for j,xy in enumerate(row): if (styleRowNo,j) in lines: juSymbol = getattr(lines[styleRowNo,j],'symbol',uSymbol) else: juSymbol = uSymbol if juSymbol is uSymbol: symbol = uSymbol symColor = strokeColor else: symbol = juSymbol symColor = getattr(symbol,'fillColor',strokeColor) symbol = uSymbol2Symbol(tpcGetItem(symbol,j),xy[0],xy[1],symColor) if symbol: if bubblePlot: symbol.size = bubbleR*(drow[j][2]/bubbleMax)**0.5 g.add(symbol) else: if bubblePlot: drow = self.data[rowNo] for j,xy in enumerate(row): juSymbol = getattr(lines[styleRowNo,j],'symbol',None) if not juSymbol: continue symColor = getattr(juSymbol,'fillColor',getattr(juSymbol,'strokeColor',strokeColor)) symbol = uSymbol2Symbol(juSymbol,xy[0],xy[1],symColor) if symbol: if bubblePlot: symbol.size = bubbleR*(drow[j][2]/bubbleMax)**0.5 g.add(symbol) # Draw data labels. for colNo,datum in enumerate(row): x1, y1 = datum self.drawLabel(g, rowNo, colNo, x1, y1) shader = getattr(rowStyle, 'shader', None) if shader: shader.shade(self,g,rowNo,strokeColor,row) return g def draw(self): yA = self.yValueAxis xA = self.xValueAxis if getattr(self,'_bubblePlot',None): yA._bubblePlot = xA._bubblePlot = 1 yA.setPosition(self.x, self.y, self.height) if yA: yA.joinAxis = xA if xA: xA.joinAxis = yA yA.configure(self.data) # if zero is in chart, put x axis there, otherwise use bottom. xAxisCrossesAt = yA.scale(0) if ((xAxisCrossesAt > self.y + self.height) or (xAxisCrossesAt < self.y)): y = self.y else: y = xAxisCrossesAt xA.setPosition(self.x, y, self.width) xA.configure(self.data) self.calcPositions() g = Group() g.add(self.makeBackground()) if self._inFill or self.behindAxes: xA._joinToAxis() if self._inFill: self._inFillG = Group() g.add(self._inFillG) if self.behindAxes: self._lineG = Group() g.add(self._lineG) xA._joinToAxis() yA._joinToAxis() xAex = xA.visibleAxis and [xA._y] or [] yAex = yA.visibleAxis and [yA._x] or [] skipGrid = getattr(xA,'skipGrid','none') if skipGrid!=None: if skipGrid in ('both','top'): yAex.append(xA._x+xA._length) if skipGrid in ('both','bottom'): yAex.append(xA._x) skipGrid = getattr(yA,'skipGrid','none') if skipGrid!=None: if skipGrid in ('both','top'): xAex.append(yA._y+yA._length) if skipGrid in ('both','bottom'): xAex.append(yA._y) if self.gridFirst: xA.makeGrid(g,parent=self,dim=yA.getGridDims,exclude=yAex) yA.makeGrid(g,parent=self,dim=xA.getGridDims,exclude=xAex) g.add(xA.draw()) g.add(yA.draw()) if not self.gridFirst: xAdgl = getattr(xA,'drawGridLast',False) yAdgl = getattr(yA,'drawGridLast',False) if not xAdgl: xA.makeGrid(g,parent=self,dim=yA.getGridDims,exclude=yAex) if not yAdgl: yA.makeGrid(g,parent=self,dim=xA.getGridDims,exclude=xAex) annotations = getattr(self,'annotations',[]) for a in annotations: if getattr(a,'beforeLines',None): g.add(a(self,xA.scale,yA.scale)) g.add(self.makeLines()) if not self.gridFirst: if xAdgl: xA.makeGrid(g,parent=self,dim=yA.getGridDims,exclude=yAex) if yAdgl: yA.makeGrid(g,parent=self,dim=xA.getGridDims,exclude=xAex) for a in annotations: if not getattr(a,'beforeLines',None): g.add(a(self,xA.scale,yA.scale)) return g def addCrossHair(self,name,xv,yv,strokeColor=colors.black,strokeWidth=1,beforeLines=True): from reportlab.graphics.shapes import Group, Line annotations = [a for a in getattr(self,'annotations',[]) if getattr(a,'name',None)!=name] def annotation(self,xScale,yScale): x = xScale(xv) y = yScale(yv) g = Group() xA = xScale.__self__ #the x axis g.add(Line(xA._x,y,xA._x+xA._length,y,strokeColor=strokeColor,strokeWidth=strokeWidth)) yA = yScale.__self__ #the y axis g.add(Line(x,yA._y,x,yA._y+yA._length,strokeColor=strokeColor,strokeWidth=strokeWidth)) return g annotation.beforeLines = beforeLines annotations.append(annotation) self.annotations = annotations class LinePlot3D(LinePlot): _attrMap = AttrMap(BASE=LinePlot, theta_x = AttrMapValue(isNumber, desc='dx/dz'), theta_y = AttrMapValue(isNumber, desc='dy/dz'), zDepth = AttrMapValue(isNumber, desc='depth of an individual series'), zSpace = AttrMapValue(isNumber, desc='z gap around series'), ) theta_x = .5 theta_y = .5 zDepth = 10 zSpace = 3 def calcPositions(self): LinePlot.calcPositions(self) nSeries = self._seriesCount zSpace = self.zSpace zDepth = self.zDepth if self.xValueAxis.style=='parallel_3d': _3d_depth = nSeries*zDepth+(nSeries+1)*zSpace else: _3d_depth = zDepth + 2*zSpace self._3d_dx = self.theta_x*_3d_depth self._3d_dy = self.theta_y*_3d_depth def _calc_z0(self,rowNo): zSpace = self.zSpace if self.xValueAxis.style=='parallel_3d': z0 = rowNo*(self.zDepth+zSpace)+zSpace else: z0 = zSpace return z0 def _zadjust(self,x,y,z): return x+z*self.theta_x, y+z*self.theta_y def makeLines(self): bubblePlot = getattr(self,'_bubblePlot',None) assert not bubblePlot, "_bubblePlot not supported for 3d yet" #if bubblePlot: # yA = self.yValueAxis # xA = self.xValueAxis # bubbleR = min(yA._bubbleRadius,xA._bubbleRadius) # bubbleMax = xA._bubbleMax labelFmt = self.lineLabelFormat positions = self._positions P = list(range(len(positions))) if self.reversePlotOrder: P.reverse() inFill = getattr(self,'_inFill',None) assert not inFill, "inFill not supported for 3d yet" #if inFill: # inFillY = self.xValueAxis._y # inFillX0 = self.yValueAxis._x # inFillX1 = inFillX0 + self.xValueAxis._length # inFillG = getattr(self,'_inFillG',g) zDepth = self.zDepth _zadjust = self._zadjust theta_x = self.theta_x theta_y = self.theta_y from reportlab.graphics.charts.linecharts import _FakeGroup F = _FakeGroup() from reportlab.graphics.charts.utils3d import _make_3d_line_info, find_intersections if self.xValueAxis.style!='parallel_3d': tileWidth = getattr(self,'_3d_tilewidth',1) if getattr(self,'_find_intersections',None): from copy import copy fpositions = list(map(copy,positions)) I = find_intersections(fpositions,small=tileWidth) ic = None for i,j,x,y in I: if ic!=i: ic = i jc = 0 else: jc+=1 fpositions[i].insert(j+jc,(x,y)) tileWidth = None else: fpositions = positions else: tileWidth = None fpositions = positions # Iterate over data rows. styleCount = len(self.lines) for rowNo in P: row = positions[rowNo] n = len(row) rowStyle = self.lines[rowNo % styleCount] rowColor = rowStyle.strokeColor dash = getattr(rowStyle, 'strokeDashArray', None) z0 = self._calc_z0(rowNo) z1 = z0 + zDepth if hasattr(rowStyle, 'strokeWidth'): width = rowStyle.strokeWidth elif hasattr(self.lines, 'strokeWidth'): width = self.lines.strokeWidth else: width = None # Iterate over data columns. if self.joinedLines: if n: frow = fpositions[rowNo] x0, y0 = frow[0] for colNo in range(1,len(frow)): x1, y1 = frow[colNo] _make_3d_line_info( F, x0, x1, y0, y1, z0, z1, theta_x, theta_y, rowColor, fillColorShaded=None, tileWidth=tileWidth, strokeColor=None, strokeWidth=None, strokeDashArray=None, shading=0.1) x0, y0 = x1, y1 if hasattr(rowStyle, 'symbol'): uSymbol = rowStyle.symbol elif hasattr(self.lines, 'symbol'): uSymbol = self.lines.symbol else: uSymbol = None if uSymbol: for xy in row: x1, y1 = row[colNo] x1, y1 = _zadjust(x1,y1,z0) symbol = uSymbol2Symbol(uSymbol,xy[0],xy[1],rowColor) if symbol: F.add((1,z0,z0,x1,y1,symbol)) # Draw data labels. for colNo in range(n): x1, y1 = row[colNo] x1, y1 = _zadjust(x1,y1,z0) L = self._innerDrawLabel(rowNo, colNo, x1, y1) if L: F.add((2,z0,z0,x1,y1,L)) F.sort() g = Group() for v in F.value(): g.add(v[-1]) return g _monthlyIndexData = [[(19971202, 100.0), (19971231, 100.1704367), (19980131, 101.5639577), (19980228, 102.1879927), (19980331, 101.6337257), (19980430, 102.7640446), (19980531, 102.9198038), (19980630, 103.25938789999999), (19980731, 103.2516421), (19980831, 105.4744329), (19980930, 109.3242705), (19981031, 111.9859291), (19981130, 110.9184642), (19981231, 110.9184642), (19990131, 111.9882532), (19990228, 109.7912614), (19990331, 110.24189629999999), (19990430, 110.4279321), (19990531, 109.33955469999999), (19990630, 108.2341748), (19990731, 110.21294469999999), (19990831, 110.9683062), (19990930, 112.4425371), (19991031, 112.7314032), (19991130, 112.3509645), (19991231, 112.3660659), (20000131, 110.9255248), (20000229, 110.5266306), (20000331, 113.3116101), (20000430, 111.0449133), (20000531, 111.702717), (20000630, 113.5832178)], [(19971202, 100.0), (19971231, 100.0), (19980131, 100.8), (19980228, 102.0), (19980331, 101.9), (19980430, 103.0), (19980531, 103.0), (19980630, 103.1), (19980731, 103.1), (19980831, 102.8), (19980930, 105.6), (19981031, 108.3), (19981130, 108.1), (19981231, 111.9), (19990131, 113.1), (19990228, 110.2), (19990331, 111.8), (19990430, 112.3), (19990531, 110.1), (19990630, 109.3), (19990731, 111.2), (19990831, 111.7), (19990930, 112.6), (19991031, 113.2), (19991130, 113.9), (19991231, 115.4), (20000131, 112.7), (20000229, 113.9), (20000331, 115.8), (20000430, 112.2), (20000531, 112.6), (20000630, 114.6)]] class SimpleTimeSeriesPlot(LinePlot): """A customized version of LinePlot. It uses NormalDateXValueAxis() and AdjYValueAxis() for the X and Y axes. """ def __init__(self): LinePlot.__init__(self) self.xValueAxis = NormalDateXValueAxis() self.yValueAxis = YValueAxis() self.data = _monthlyIndexData class GridLinePlot(SimpleTimeSeriesPlot): """A customized version of SimpleTimeSeriesSPlot. It uses NormalDateXValueAxis() and AdjYValueAxis() for the X and Y axes. The chart has a default grid background with thin horizontal lines aligned with the tickmarks (and labels). You can change the back- ground to be any Grid or ShadedRect, or scale the whole chart. If you do provide a background, you can specify the colours of the stripes with 'background.stripeColors'. """ _attrMap = AttrMap(BASE=LinePlot, background = AttrMapValue(None, desc='Background for chart area (now Grid or ShadedRect).'), scaleFactor = AttrMapValue(isNumberOrNone, desc='Scalefactor to apply to whole drawing.'), ) def __init__(self): from reportlab.lib import colors SimpleTimeSeriesPlot.__init__(self) self.scaleFactor = None self.background = Grid() self.background.orientation = 'horizontal' self.background.useRects = 0 self.background.useLines = 1 self.background.strokeWidth = 0.5 self.background.strokeColor = colors.black def demo(self,drawing=None): from reportlab.lib import colors if not drawing: drawing = Drawing(400, 200) lp = GridLinePlot() lp.x = 50 lp.y = 50 lp.height = 125 lp.width = 300 lp.data = _monthlyIndexData lp.joinedLines = 1 lp.strokeColor = colors.black c0 = colors.PCMYKColor(100,65,0,30, spotName='PANTONE 288 CV', density=100) lp.lines[0].strokeColor = c0 lp.lines[0].strokeWidth = 2 lp.lines[0].strokeDashArray = None c1 = colors.PCMYKColor(0,79,91,0, spotName='PANTONE Wm Red CV', density=100) lp.lines[1].strokeColor = c1 lp.lines[1].strokeWidth = 1 lp.lines[1].strokeDashArray = [3,1] lp.xValueAxis.labels.fontSize = 10 lp.xValueAxis.labels.textAnchor = 'start' lp.xValueAxis.labels.boxAnchor = 'w' lp.xValueAxis.labels.angle = -45 lp.xValueAxis.labels.dx = 0 lp.xValueAxis.labels.dy = -8 lp.xValueAxis.xLabelFormat = '{mm}/{yy}' lp.yValueAxis.labelTextFormat = '%5d%% ' lp.yValueAxis.tickLeft = 5 lp.yValueAxis.labels.fontSize = 10 lp.background = Grid() lp.background.stripeColors = [colors.pink, colors.lightblue] lp.background.orientation = 'vertical' drawing.add(lp,'plot') return drawing def draw(self): xva, yva = self.xValueAxis, self.yValueAxis if xva: xva.joinAxis = yva if yva: yva.joinAxis = xva yva.setPosition(self.x, self.y, self.height) yva.configure(self.data) # if zero is in chart, put x axis there, otherwise # use bottom. xAxisCrossesAt = yva.scale(0) if ((xAxisCrossesAt > self.y + self.height) or (xAxisCrossesAt < self.y)): y = self.y else: y = xAxisCrossesAt xva.setPosition(self.x, y, self.width) xva.configure(self.data) back = self.background if isinstance(back, Grid): if back.orientation == 'vertical' and xva._tickValues: xpos = list(map(xva.scale, [xva._valueMin] + xva._tickValues)) steps = [] for i in range(len(xpos)-1): steps.append(xpos[i+1] - xpos[i]) back.deltaSteps = steps elif back.orientation == 'horizontal' and yva._tickValues: ypos = list(map(yva.scale, [yva._valueMin] + yva._tickValues)) steps = [] for i in range(len(ypos)-1): steps.append(ypos[i+1] - ypos[i]) back.deltaSteps = steps elif isinstance(back, DoubleGrid): # Ideally, these lines would not be needed... back.grid0.x = self.x back.grid0.y = self.y back.grid0.width = self.width back.grid0.height = self.height back.grid1.x = self.x back.grid1.y = self.y back.grid1.width = self.width back.grid1.height = self.height # some room left for optimization... if back.grid0.orientation == 'vertical' and xva._tickValues: xpos = list(map(xva.scale, [xva._valueMin] + xva._tickValues)) steps = [] for i in range(len(xpos)-1): steps.append(xpos[i+1] - xpos[i]) back.grid0.deltaSteps = steps elif back.grid0.orientation == 'horizontal' and yva._tickValues: ypos = list(map(yva.scale, [yva._valueMin] + yva._tickValues)) steps = [] for i in range(len(ypos)-1): steps.append(ypos[i+1] - ypos[i]) back.grid0.deltaSteps = steps if back.grid1.orientation == 'vertical' and xva._tickValues: xpos = list(map(xva.scale, [xva._valueMin] + xva._tickValues)) steps = [] for i in range(len(xpos)-1): steps.append(xpos[i+1] - xpos[i]) back.grid1.deltaSteps = steps elif back.grid1.orientation == 'horizontal' and yva._tickValues: ypos = list(map(yva.scale, [yva._valueMin] + yva._tickValues)) steps = [] for i in range(len(ypos)-1): steps.append(ypos[i+1] - ypos[i]) back.grid1.deltaSteps = steps self.calcPositions() width, height, scaleFactor = self.width, self.height, self.scaleFactor if scaleFactor and scaleFactor!=1: #g = Drawing(scaleFactor*width, scaleFactor*height) g.transform = (scaleFactor, 0, 0, scaleFactor,0,0) else: g = Group() g.add(self.makeBackground()) g.add(self.xValueAxis) g.add(self.yValueAxis) g.add(self.makeLines()) return g class AreaLinePlot(LinePlot): '''we're given data in the form [(X1,Y11,..Y1M)....(Xn,Yn1,...YnM)]'''#' def __init__(self): LinePlot.__init__(self) self._inFill = 1 self.reversePlotOrder = 1 self.data = [(1,20,100,30),(2,11,50,15),(3,15,70,40)] def draw(self): try: odata = self.data n = len(odata) m = len(odata[0]) S = n*[0] self.data = [] for i in range(1,m): D = [] for j in range(n): S[j] = S[j] + odata[j][i] D.append((odata[j][0],S[j])) self.data.append(D) return LinePlot.draw(self) finally: self.data = odata class SplitLinePlot(AreaLinePlot): def __init__(self): AreaLinePlot.__init__(self) self.xValueAxis = NormalDateXValueAxis() self.yValueAxis = AdjYValueAxis() self.data=[(20030601,0.95,0.05,0.0),(20030701,0.95,0.05,0.0),(20030801,0.95,0.05,0.0),(20030901,0.95,0.05,0.0),(20031001,0.95,0.05,0.0),(20031101,0.95,0.05,0.0),(20031201,0.95,0.05,0.0),(20040101,0.95,0.05,0.0),(20040201,0.95,0.05,0.0),(20040301,0.95,0.05,0.0),(20040401,0.95,0.05,0.0),(20040501,0.95,0.05,0.0),(20040601,0.95,0.05,0.0),(20040701,0.95,0.05,0.0),(20040801,0.95,0.05,0.0),(20040901,0.95,0.05,0.0),(20041001,0.95,0.05,0.0),(20041101,0.95,0.05,0.0),(20041201,0.95,0.05,0.0),(20050101,0.95,0.05,0.0),(20050201,0.95,0.05,0.0),(20050301,0.95,0.05,0.0),(20050401,0.95,0.05,0.0),(20050501,0.95,0.05,0.0),(20050601,0.95,0.05,0.0),(20050701,0.95,0.05,0.0),(20050801,0.95,0.05,0.0),(20050901,0.95,0.05,0.0),(20051001,0.95,0.05,0.0),(20051101,0.95,0.05,0.0),(20051201,0.95,0.05,0.0),(20060101,0.95,0.05,0.0),(20060201,0.95,0.05,0.0),(20060301,0.95,0.05,0.0),(20060401,0.95,0.05,0.0),(20060501,0.95,0.05,0.0),(20060601,0.95,0.05,0.0),(20060701,0.95,0.05,0.0),(20060801,0.95,0.05,0.0),(20060901,0.95,0.05,0.0),(20061001,0.95,0.05,0.0),(20061101,0.95,0.05,0.0),(20061201,0.95,0.05,0.0),(20070101,0.95,0.05,0.0),(20070201,0.95,0.05,0.0),(20070301,0.95,0.05,0.0),(20070401,0.95,0.05,0.0),(20070501,0.95,0.05,0.0),(20070601,0.95,0.05,0.0),(20070701,0.95,0.05,0.0),(20070801,0.95,0.05,0.0),(20070901,0.95,0.05,0.0),(20071001,0.95,0.05,0.0),(20071101,0.95,0.05,0.0),(20071201,0.95,0.05,0.0),(20080101,0.95,0.05,0.0),(20080201,0.95,0.05,0.0),(20080301,0.95,0.05,0.0),(20080401,0.95,0.05,0.0),(20080501,0.95,0.05,0.0),(20080601,0.95,0.05,0.0),(20080701,0.95,0.05,0.0),(20080801,0.95,0.05,0.0),(20080901,0.95,0.05,0.0),(20081001,0.95,0.05,0.0),(20081101,0.95,0.05,0.0),(20081201,0.95,0.05,0.0),(20090101,0.95,0.05,0.0),(20090201,0.91,0.09,0.0),(20090301,0.91,0.09,0.0),(20090401,0.91,0.09,0.0),(20090501,0.91,0.09,0.0),(20090601,0.91,0.09,0.0),(20090701,0.91,0.09,0.0),(20090801,0.91,0.09,0.0),(20090901,0.91,0.09,0.0),(20091001,0.91,0.09,0.0),(20091101,0.91,0.09,0.0),(20091201,0.91,0.09,0.0),(20100101,0.91,0.09,0.0),(20100201,0.81,0.19,0.0),(20100301,0.81,0.19,0.0),(20100401,0.81,0.19,0.0),(20100501,0.81,0.19,0.0),(20100601,0.81,0.19,0.0),(20100701,0.81,0.19,0.0),(20100801,0.81,0.19,0.0),(20100901,0.81,0.19,0.0),(20101001,0.81,0.19,0.0),(20101101,0.81,0.19,0.0),(20101201,0.81,0.19,0.0),(20110101,0.81,0.19,0.0),(20110201,0.72,0.28,0.0),(20110301,0.72,0.28,0.0),(20110401,0.72,0.28,0.0),(20110501,0.72,0.28,0.0),(20110601,0.72,0.28,0.0),(20110701,0.72,0.28,0.0),(20110801,0.72,0.28,0.0),(20110901,0.72,0.28,0.0),(20111001,0.72,0.28,0.0),(20111101,0.72,0.28,0.0),(20111201,0.72,0.28,0.0),(20120101,0.72,0.28,0.0),(20120201,0.53,0.47,0.0),(20120301,0.53,0.47,0.0),(20120401,0.53,0.47,0.0),(20120501,0.53,0.47,0.0),(20120601,0.53,0.47,0.0),(20120701,0.53,0.47,0.0),(20120801,0.53,0.47,0.0),(20120901,0.53,0.47,0.0),(20121001,0.53,0.47,0.0),(20121101,0.53,0.47,0.0),(20121201,0.53,0.47,0.0),(20130101,0.53,0.47,0.0),(20130201,0.44,0.56,0.0),(20130301,0.44,0.56,0.0),(20130401,0.44,0.56,0.0),(20130501,0.44,0.56,0.0),(20130601,0.44,0.56,0.0),(20130701,0.44,0.56,0.0),(20130801,0.44,0.56,0.0),(20130901,0.44,0.56,0.0),(20131001,0.44,0.56,0.0),(20131101,0.44,0.56,0.0),(20131201,0.44,0.56,0.0),(20140101,0.44,0.56,0.0),(20140201,0.36,0.5,0.14),(20140301,0.36,0.5,0.14),(20140401,0.36,0.5,0.14),(20140501,0.36,0.5,0.14),(20140601,0.36,0.5,0.14),(20140701,0.36,0.5,0.14),(20140801,0.36,0.5,0.14),(20140901,0.36,0.5,0.14),(20141001,0.36,0.5,0.14),(20141101,0.36,0.5,0.14),(20141201,0.36,0.5,0.14),(20150101,0.36,0.5,0.14),(20150201,0.3,0.41,0.29),(20150301,0.3,0.41,0.29),(20150401,0.3,0.41,0.29),(20150501,0.3,0.41,0.29),(20150601,0.3,0.41,0.29),(20150701,0.3,0.41,0.29),(20150801,0.3,0.41,0.29),(20150901,0.3,0.41,0.29),(20151001,0.3,0.41,0.29),(20151101,0.3,0.41,0.29),(20151201,0.3,0.41,0.29),(20160101,0.3,0.41,0.29),(20160201,0.26,0.36,0.38),(20160301,0.26,0.36,0.38),(20160401,0.26,0.36,0.38),(20160501,0.26,0.36,0.38),(20160601,0.26,0.36,0.38),(20160701,0.26,0.36,0.38),(20160801,0.26,0.36,0.38),(20160901,0.26,0.36,0.38),(20161001,0.26,0.36,0.38),(20161101,0.26,0.36,0.38),(20161201,0.26,0.36,0.38),(20170101,0.26,0.36,0.38),(20170201,0.2,0.3,0.5),(20170301,0.2,0.3,0.5),(20170401,0.2,0.3,0.5),(20170501,0.2,0.3,0.5),(20170601,0.2,0.3,0.5),(20170701,0.2,0.3,0.5),(20170801,0.2,0.3,0.5),(20170901,0.2,0.3,0.5),(20171001,0.2,0.3,0.5),(20171101,0.2,0.3,0.5),(20171201,0.2,0.3,0.5),(20180101,0.2,0.3,0.5),(20180201,0.13,0.37,0.5),(20180301,0.13,0.37,0.5),(20180401,0.13,0.37,0.5),(20180501,0.13,0.37,0.5),(20180601,0.13,0.37,0.5),(20180701,0.13,0.37,0.5),(20180801,0.13,0.37,0.5),(20180901,0.13,0.37,0.5),(20181001,0.13,0.37,0.5),(20181101,0.13,0.37,0.5),(20181201,0.13,0.37,0.5),(20190101,0.13,0.37,0.5),(20190201,0.1,0.4,0.5),(20190301,0.1,0.4,0.5),(20190401,0.1,0.4,0.5),(20190501,0.1,0.4,0.5),(20190601,0.1,0.4,0.5),(20190701,0.1,0.4,0.5),(20190801,0.1,0.4,0.5),(20190901,0.1,0.4,0.5),(20191001,0.1,0.4,0.5),(20191101,0.1,0.4,0.5),(20191201,0.1,0.4,0.5),(20200101,0.1,0.4,0.5)] self.yValueAxis.requiredRange = None self.yValueAxis.leftAxisPercent = 0 self.yValueAxis.leftAxisOrigShiftMin = 0 self.yValueAxis.leftAxisOrigShiftIPC = 0 self.lines[0].strokeColor = colors.toColor(0x0033cc) self.lines[1].strokeColor = colors.toColor(0x99c3ff) self.lines[2].strokeColor = colors.toColor(0xCC0033) def _maxWidth(T, fontName, fontSize): '''return max stringWidth for the list of strings T''' if not isinstance(T,(tuple,list)): T = (T,) T = [_f for _f in T if _f] return T and max(list(map(lambda t,sW=stringWidth,fN=fontName, fS=fontSize: sW(t,fN,fS),T))) or 0 class ScatterPlot(LinePlot): """A scatter plot widget""" _attrMap = AttrMap(BASE=LinePlot, width = AttrMapValue(isNumber, desc="Width of the area inside the axes"), height = AttrMapValue(isNumber, desc="Height of the area inside the axes"), outerBorderOn = AttrMapValue(isBoolean, desc="Is there an outer border (continuation of axes)"), outerBorderColor = AttrMapValue(isColorOrNone, desc="Color of outer border (if any)"), labelOffset = AttrMapValue(isNumber, desc="Space between label and Axis (or other labels)",advancedUsage=1), axisTickLengths = AttrMapValue(isNumber, desc="Lenth of the ticks on both axes"), axisStrokeWidth = AttrMapValue(isNumber, desc="Stroke width for both axes"), xLabel = AttrMapValue(isString, desc="Label for the whole X-Axis"), yLabel = AttrMapValue(isString, desc="Label for the whole Y-Axis"), data = AttrMapValue(isAnything, desc='Data points - a list of x/y tuples.'), strokeColor = AttrMapValue(isColorOrNone, desc='Color used for border of plot area.'), fillColor = AttrMapValue(isColorOrNone, desc='Color used for background interior of plot area.'), leftPadding = AttrMapValue(isNumber, desc='Padding on left of drawing'), rightPadding = AttrMapValue(isNumber, desc='Padding on right of drawing'), topPadding = AttrMapValue(isNumber, desc='Padding at top of drawing'), bottomPadding = AttrMapValue(isNumber, desc='Padding at bottom of drawing'), ) def __init__(self): LinePlot.__init__(self) self.width = 142 self.height = 77 self.outerBorderOn = 1 self.outerBorderColor = colors.black self.background = None _labelOffset = 3 _axisTickLengths = 2 _axisStrokeWidth = 0.5 self.yValueAxis.valueMin = None self.yValueAxis.valueMax = None self.yValueAxis.valueStep = None self.yValueAxis.labelTextFormat = '%s' self.xLabel="X Lable" self.xValueAxis.labels.fontSize = 6 self.yLabel="Y Lable" self.yValueAxis.labels.fontSize = 6 self.data =[((0.030, 62.73), (0.074, 54.363), (1.216, 17.964)), ((1.360, 11.621), (1.387, 50.011), (1.428, 68.953)), ((1.444, 86.888), (1.754, 35.58), (1.766, 36.05))] #values for lineplot self.joinedLines = 0 self.leftPadding=5 self.rightPadding=10 self.topPadding=5 self.bottomPadding=5 self.x = self.leftPadding+_axisTickLengths+(_labelOffset*2) self.x=self.x+_maxWidth(str(self.yValueAxis.valueMax), self.yValueAxis.labels.fontName, self.yValueAxis.labels.fontSize) self.y = self.bottomPadding+_axisTickLengths+_labelOffset+self.xValueAxis.labels.fontSize self.xValueAxis.labels.dy = -_labelOffset self.xValueAxis.tickDown = _axisTickLengths self.xValueAxis.strokeWidth = _axisStrokeWidth self.xValueAxis.rangeRound='both' self.yValueAxis.labels.dx = -_labelOffset self.yValueAxis.tickLeft = _axisTickLengths self.yValueAxis.strokeWidth = _axisStrokeWidth self.yValueAxis.rangeRound='both' self.lineLabelFormat="%.2f" self.lineLabels.fontSize = 5 self.lineLabels.boxAnchor = 'e' self.lineLabels.dx = -2 self.lineLabelNudge = 0 self.lines.symbol=makeMarker('FilledCircle',size=3) self.lines[1].symbol=makeMarker('FilledDiamond',size=3) self.lines[2].symbol=makeMarker('FilledSquare',size=3) self.lines[2].strokeColor = colors.green def _getDrawingDimensions(self): tx = self.leftPadding+self.yValueAxis.tickLeft+(self.yValueAxis.labels.dx*2)+self.xValueAxis.labels.fontSize tx=tx+(5*_maxWidth(str(self.yValueAxis.valueMax), self.yValueAxis.labels.fontName, self.yValueAxis.labels.fontSize)) tx=tx+self.width+self.rightPadding t=('%.2f%%'%self.xValueAxis.valueMax) tx=tx+(_maxWidth(t, self.yValueAxis.labels.fontName, self.yValueAxis.labels.fontSize)) ty = self.bottomPadding+self.xValueAxis.tickDown+(self.xValueAxis.labels.dy*2)+(self.xValueAxis.labels.fontSize*2) ty=ty+self.yValueAxis.labels.fontSize+self.height+self.topPadding #print (tx, ty) return (tx,ty) def demo(self,drawing=None): if not drawing: tx,ty=self._getDrawingDimensions() drawing = Drawing(tx,ty) drawing.add(self.draw()) return drawing def draw(self): ascent=getFont(self.xValueAxis.labels.fontName).face.ascent if ascent==0: ascent=0.718 # default (from helvetica) ascent=ascent*self.xValueAxis.labels.fontSize # normalize #basic LinePlot - does the Axes, Ticks etc lp = LinePlot.draw(self) xLabel = self.xLabel if xLabel: #Overall label for the X-axis xl=Label() xl.x = (self.x+self.width)/2.0 xl.y = 0 xl.fontName = self.xValueAxis.labels.fontName xl.fontSize = self.xValueAxis.labels.fontSize xl.setText(xLabel) lp.add(xl) yLabel = self.yLabel if yLabel: #Overall label for the Y-axis yl=Label() yl.angle = 90 yl.x = 0 yl.y = (self.y+self.height/2.0) yl.fontName = self.yValueAxis.labels.fontName yl.fontSize = self.yValueAxis.labels.fontSize yl.setText(yLabel) lp.add(yl) # do a bounding box - in the same style as the axes if self.outerBorderOn: lp.add(Rect(self.x, self.y, self.width, self.height, strokeColor = self.outerBorderColor, strokeWidth = self.yValueAxis.strokeWidth, fillColor = None)) lp.shift(self.leftPadding, self.bottomPadding) return lp def sample1a(): "A line plot with non-equidistant points in x-axis." drawing = Drawing(400, 200) data = [ ((1,1), (2,2), (2.5,1), (3,3), (4,5)), ((1,2), (2,3), (2.5,2), (3.5,5), (4,6)) ] lp = LinePlot() lp.x = 50 lp.y = 50 lp.height = 125 lp.width = 300 lp.data = data lp.joinedLines = 1 lp.strokeColor = colors.black lp.lines.symbol = makeMarker('UK_Flag') lp.lines[0].strokeWidth = 2 lp.lines[1].strokeWidth = 4 lp.xValueAxis.valueMin = 0 lp.xValueAxis.valueMax = 5 lp.xValueAxis.valueStep = 1 lp.yValueAxis.valueMin = 0 lp.yValueAxis.valueMax = 7 lp.yValueAxis.valueStep = 1 drawing.add(lp) return drawing def sample1b(): "A line plot with non-equidistant points in x-axis." drawing = Drawing(400, 200) data = [ ((1,1), (2,2), (2.5,1), (3,3), (4,5)), ((1,2), (2,3), (2.5,2), (3.5,5), (4,6)) ] lp = LinePlot() lp.x = 50 lp.y = 50 lp.height = 125 lp.width = 300 lp.data = data lp.joinedLines = 1 lp.lines.symbol = makeMarker('Circle') lp.lineLabelFormat = '%2.0f' lp.strokeColor = colors.black lp.xValueAxis.valueMin = 0 lp.xValueAxis.valueMax = 5 lp.xValueAxis.valueSteps = [1, 2, 2.5, 3, 4, 5] lp.xValueAxis.labelTextFormat = '%2.1f' lp.yValueAxis.valueMin = 0 lp.yValueAxis.valueMax = 7 lp.yValueAxis.valueStep = 1 drawing.add(lp) return drawing def sample1c(): "A line plot with non-equidistant points in x-axis." drawing = Drawing(400, 200) data = [ ((1,1), (2,2), (2.5,1), (3,3), (4,5)), ((1,2), (2,3), (2.5,2), (3.5,5), (4,6)) ] lp = LinePlot() lp.x = 50 lp.y = 50 lp.height = 125 lp.width = 300 lp.data = data lp.joinedLines = 1 lp.lines[0].symbol = makeMarker('FilledCircle') lp.lines[1].symbol = makeMarker('Circle') lp.lineLabelFormat = '%2.0f' lp.strokeColor = colors.black lp.xValueAxis.valueMin = 0 lp.xValueAxis.valueMax = 5 lp.xValueAxis.valueSteps = [1, 2, 2.5, 3, 4, 5] lp.xValueAxis.labelTextFormat = '%2.1f' lp.yValueAxis.valueMin = 0 lp.yValueAxis.valueMax = 7 lp.yValueAxis.valueSteps = [1, 2, 3, 5, 6] drawing.add(lp) return drawing def preprocessData(series): "Convert date strings into seconds and multiply values by 100." return [(str2seconds(x[0]), x[1]*100) for x in series] def sample2(): "A line plot with non-equidistant points in x-axis." drawing = Drawing(400, 200) data = [ (('25/11/1991',1), ('30/11/1991',1.000933333), ('31/12/1991',1.0062), ('31/01/1992',1.0112), ('29/02/1992',1.0158), ('31/03/1992',1.020733333), ('30/04/1992',1.026133333), ('31/05/1992',1.030266667), ('30/06/1992',1.034466667), ('31/07/1992',1.038733333), ('31/08/1992',1.0422), ('30/09/1992',1.045533333), ('31/10/1992',1.049866667), ('30/11/1992',1.054733333), ('31/12/1992',1.061), ), ] data[0] = preprocessData(data[0]) lp = LinePlot() lp.x = 50 lp.y = 50 lp.height = 125 lp.width = 300 lp.data = data lp.joinedLines = 1 lp.lines.symbol = makeMarker('FilledDiamond') lp.strokeColor = colors.black start = mktime(mkTimeTuple('25/11/1991')) t0 = mktime(mkTimeTuple('30/11/1991')) t1 = mktime(mkTimeTuple('31/12/1991')) t2 = mktime(mkTimeTuple('31/03/1992')) t3 = mktime(mkTimeTuple('30/06/1992')) t4 = mktime(mkTimeTuple('30/09/1992')) end = mktime(mkTimeTuple('31/12/1992')) lp.xValueAxis.valueMin = start lp.xValueAxis.valueMax = end lp.xValueAxis.valueSteps = [start, t0, t1, t2, t3, t4, end] lp.xValueAxis.labelTextFormat = seconds2str lp.xValueAxis.labels[1].dy = -20 lp.xValueAxis.labels[2].dy = -35 lp.yValueAxis.labelTextFormat = '%4.2f' lp.yValueAxis.valueMin = 100 lp.yValueAxis.valueMax = 110 lp.yValueAxis.valueStep = 2 drawing.add(lp) return drawing def sampleFillPairedData(): d = Drawing(400,200) chart = SimpleTimeSeriesPlot() d.add(chart) chart.data = [FillPairedData(chart.data[0],1),chart.data[1]] chart.lines[0].filler= Filler(fillColor=colors.toColor('#9f9f9f'),strokeWidth=0,strokeColor=None) chart.lines[0].strokeColor = None chart.lines[1].strokeColor = None return d ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1691062243.0 reportlab-4.1.0/src/reportlab/graphics/charts/markers.py0000664000175000017500000000331314462707743023003 0ustar00rptlabrptlab#Copyright ReportLab Europe Ltd. 2000-2017 #see license.txt for license details #history https://hg.reportlab.com/hg-public/reportlab/log/tip/src/reportlab/graphics/charts/markers.py __version__='3.3.0' __doc__="""This modules defines a collection of markers used in charts. The make* functions return a simple shape or a widget as for the smiley. """ from reportlab.lib import colors from reportlab.graphics.shapes import Rect, Circle, Polygon from reportlab.graphics.widgets.signsandsymbols import SmileyFace def makeEmptySquare(x, y, size, color): "Make an empty square marker." d = size/2.0 rect = Rect(x-d, y-d, 2*d, 2*d) rect.strokeColor = color rect.fillColor = None return rect def makeFilledSquare(x, y, size, color): "Make a filled square marker." d = size/2.0 rect = Rect(x-d, y-d, 2*d, 2*d) rect.strokeColor = color rect.fillColor = color return rect def makeFilledDiamond(x, y, size, color): "Make a filled diamond marker." d = size/2.0 poly = Polygon((x-d,y, x,y+d, x+d,y, x,y-d)) poly.strokeColor = color poly.fillColor = color return poly def makeEmptyCircle(x, y, size, color): "Make a hollow circle marker." d = size/2.0 circle = Circle(x, y, d) circle.strokeColor = color circle.fillColor = colors.white return circle def makeFilledCircle(x, y, size, color): "Make a hollow circle marker." d = size/2.0 circle = Circle(x, y, d) circle.strokeColor = color circle.fillColor = color return circle def makeSmiley(x, y, size, color): "Make a smiley marker." d = size s = SmileyFace() s.fillColor = color s.x = x-d s.y = y-d s.size = d*2 return s ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1704966359.0 reportlab-4.1.0/src/reportlab/graphics/charts/piecharts.py0000664000175000017500000020235214547734327023327 0ustar00rptlabrptlab#Copyright ReportLab Europe Ltd. 2000-2017 #see license.txt for license details #history https://hg.reportlab.com/hg-public/reportlab/log/tip/src/reportlab/graphics/charts/piecharts.py # experimental pie chart script. Two types of pie - one is a monolithic #widget with all top-level properties, the other delegates most stuff to #a wedges collection whic lets you customize the group or every individual #wedge. __version__='3.3.0' __doc__="""Basic Pie Chart class. This permits you to customize and pop out individual wedges; supports elliptical and circular pies. """ import functools from math import sin, cos, pi from reportlab.lib import colors from reportlab.lib.validators import isNumber, isListOfNumbersOrNone,\ isListOfNumbers, isColorOrNone, isString,\ isListOfStringsOrNone, OneOf,\ isBoolean, isListOfColors, isNumberOrNone,\ isNoneOrListOfNoneOrStrings, isTextAnchor,\ isNoneOrListOfNoneOrNumbers, isBoxAnchor,\ isStringOrNone, NoneOr, EitherOr,\ isNumberInRange, isCallable from reportlab.graphics.widgets.markers import uSymbol2Symbol, isSymbol from reportlab.lib.attrmap import * from reportlab.graphics.shapes import Group, Drawing, Ellipse, Wedge, String, STATE_DEFAULTS, ArcPath, Polygon, Rect, PolyLine, Line from reportlab.graphics.widgetbase import TypedPropertyCollection, PropHolder from reportlab.graphics.charts.areas import PlotArea from reportlab.graphics.charts.legends import _objStr from reportlab.graphics.charts.textlabels import Label from reportlab import cmp _ANGLE2BOXANCHOR={0:'w', 45:'sw', 90:'s', 135:'se', 180:'e', 225:'ne', 270:'n', 315: 'nw', -45: 'nw'} _ANGLE2RBOXANCHOR={0:'e', 45:'ne', 90:'n', 135:'nw', 180:'w', 225:'sw', 270:'s', 315: 'se', -45: 'se'} _ANGLELO = 1e-7 _ANGLEHI = 360.0 - _ANGLELO class WedgeLabel(Label): def _checkDXY(self,ba): pass def _getBoxAnchor(self): ba = self.boxAnchor if ba in ('autox','autoy'): na = (int((self._pmv%360)/45.)*45)%360 if not (na % 90): # we have a right angle case da = (self._pmv - na) % 360 if abs(da)>5: na += (da>0 and 45 or -45) ba = (getattr(self,'_anti',None) and _ANGLE2RBOXANCHOR or _ANGLE2BOXANCHOR)[na] self._checkDXY(ba) return ba class WedgeProperties(PropHolder): """This holds descriptive information about the wedges in a pie chart. It is not to be confused with the 'wedge itself'; this just holds a recipe for how to format one, and does not allow you to hack the angles. It can format a genuine Wedge object for you with its format method. """ _attrMap = AttrMap( strokeWidth = AttrMapValue(isNumber,desc='Width of the wedge border'), fillColor = AttrMapValue(isColorOrNone,desc='Filling color of the wedge'), strokeColor = AttrMapValue(isColorOrNone,desc='Color of the wedge border'), strokeDashArray = AttrMapValue(isListOfNumbersOrNone,desc='Style of the wedge border, expressed as a list of lengths of alternating dashes and blanks'), strokeLineCap = AttrMapValue(OneOf(0,1,2),desc="Line cap 0=butt, 1=round & 2=square"), strokeLineJoin = AttrMapValue(OneOf(0,1,2),desc="Line join 0=miter, 1=round & 2=bevel"), strokeMiterLimit = AttrMapValue(isNumber,desc='Miter limit control miter line joins'), popout = AttrMapValue(isNumber,desc="How far of centre a wedge to pop"), fontName = AttrMapValue(isString,desc='Name of the font of the label text'), fontSize = AttrMapValue(isNumber,desc='Size of the font of the label text in points'), fontColor = AttrMapValue(isColorOrNone,desc='Color of the font of the label text'), labelRadius = AttrMapValue(isNumber,desc='Distance between the center of the label box and the center of the pie, expressed in times the radius of the pie'), label_dx = AttrMapValue(isNumber,desc='X Offset of the label'), label_dy = AttrMapValue(isNumber,desc='Y Offset of the label'), label_angle = AttrMapValue(isNumber,desc='Angle of the label, default (0) is horizontal, 90 is vertical, 180 is upside down'), label_boxAnchor = AttrMapValue(isBoxAnchor,desc='Anchoring point of the label'), label_boxStrokeColor = AttrMapValue(isColorOrNone,desc='Border color for the label box'), label_boxStrokeWidth = AttrMapValue(isNumber,desc='Border width for the label box'), label_boxFillColor = AttrMapValue(isColorOrNone,desc='Filling color of the label box'), label_strokeColor = AttrMapValue(isColorOrNone,desc='Border color for the label text'), label_strokeWidth = AttrMapValue(isNumber,desc='Border width for the label text'), label_text = AttrMapValue(isStringOrNone,desc='Text of the label'), label_leading = AttrMapValue(isNumberOrNone,desc=''), label_width = AttrMapValue(isNumberOrNone,desc='Width of the label'), label_maxWidth = AttrMapValue(isNumberOrNone,desc='Maximum width the label can grow to'), label_height = AttrMapValue(isNumberOrNone,desc='Height of the label'), label_textAnchor = AttrMapValue(isTextAnchor,desc='Maximum height the label can grow to'), label_visible = AttrMapValue(isBoolean,desc="True if the label is to be drawn"), label_topPadding = AttrMapValue(isNumber,'Padding at top of box'), label_leftPadding = AttrMapValue(isNumber,'Padding at left of box'), label_rightPadding = AttrMapValue(isNumber,'Padding at right of box'), label_bottomPadding = AttrMapValue(isNumber,'Padding at bottom of box'), label_simple_pointer = AttrMapValue(isBoolean,'Set to True for simple pointers'), label_pointer_strokeColor = AttrMapValue(isColorOrNone,desc='Color of indicator line'), label_pointer_strokeWidth = AttrMapValue(isNumber,desc='StrokeWidth of indicator line'), label_pointer_elbowLength = AttrMapValue(isNumber,desc='Length of final indicator line segment'), label_pointer_edgePad = AttrMapValue(isNumber,desc='pad between pointer label and box'), label_pointer_piePad = AttrMapValue(isNumber,desc='pad between pointer label and pie'), swatchMarker = AttrMapValue(NoneOr(isSymbol), desc="None or makeMarker('Diamond') ...",advancedUsage=1), visible = AttrMapValue(isBoolean,'Set to false to skip displaying'), shadingAmount = AttrMapValue(isNumberOrNone,desc='amount by which to shade fillColor'), shadingAngle = AttrMapValue(isNumber,desc='shading changes at multiple of this angle (in degrees)'), shadingDirection = AttrMapValue(OneOf('normal','anti'),desc="Whether shading is at start or end of wedge/sector"), shadingKind = AttrMapValue(OneOf(None,'lighten','darken'),desc="use colors.Whiter or Blacker"), ) def __init__(self): self.strokeWidth = 0 self.fillColor = None self.strokeColor = STATE_DEFAULTS["strokeColor"] self.strokeDashArray = STATE_DEFAULTS["strokeDashArray"] self.strokeLineJoin = 1 self.strokeLineCap = 0 self.strokeMiterLimit = 0 self.popout = 0 self.fontName = STATE_DEFAULTS["fontName"] self.fontSize = STATE_DEFAULTS["fontSize"] self.fontColor = STATE_DEFAULTS["fillColor"] self.labelRadius = 1.2 self.label_dx = self.label_dy = self.label_angle = 0 self.label_text = None self.label_topPadding = self.label_leftPadding = self.label_rightPadding = self.label_bottomPadding = 0 self.label_boxAnchor = 'autox' self.label_boxStrokeColor = None #boxStroke self.label_boxStrokeWidth = 0.5 #boxStrokeWidth self.label_boxFillColor = None self.label_strokeColor = None self.label_strokeWidth = 0.1 self.label_leading = self.label_width = self.label_maxWidth = self.label_height = None self.label_textAnchor = 'start' self.label_simple_pointer = 0 self.label_visible = 1 self.label_pointer_strokeColor = colors.black self.label_pointer_strokeWidth = 0.5 self.label_pointer_elbowLength = 3 self.label_pointer_edgePad = 2 self.label_pointer_piePad = 3 self.visible = 1 self.shadingKind = None self.shadingAmount = 0.5 self.shadingAngle = 2.0137 self.shadingDirection = 'normal' #or 'anti' def _addWedgeLabel(self,text,angle,labelX,labelY,wedgeStyle,labelClass=None): # now draw a label if self.simpleLabels: theLabel = String(labelX, labelY, text) if not self.sideLabels: theLabel.textAnchor = "middle" else: if (abs(angle) < 90 ) or (angle >270 and angle<450) or (-450< angle <-270): theLabel.textAnchor = "start" else: theLabel.textAnchor = "end" theLabel._pmv = angle theLabel._simple_pointer = 0 else: if labelClass is None: labelClass = getattr(self,'labelClass',WedgeLabel) theLabel = labelClass() theLabel._pmv = angle theLabel.x = labelX theLabel.y = labelY theLabel.dx = wedgeStyle.label_dx if not self.sideLabels: theLabel.dy = wedgeStyle.label_dy theLabel.boxAnchor = wedgeStyle.label_boxAnchor else: if wedgeStyle.fontSize is None: sideLabels_dy = self.fontSize / 2.5 else: sideLabels_dy = wedgeStyle.fontSize / 2.5 if wedgeStyle.label_dy is None: theLabel.dy = sideLabels_dy else: theLabel.dy = wedgeStyle.label_dy + sideLabels_dy if (abs(angle) < 90 ) or (angle >270 and angle<450) or (-450< angle <-270): theLabel.boxAnchor = 'w' else: theLabel.boxAnchor = 'e' theLabel.angle = wedgeStyle.label_angle theLabel.boxStrokeColor = wedgeStyle.label_boxStrokeColor theLabel.boxStrokeWidth = wedgeStyle.label_boxStrokeWidth theLabel.boxFillColor = wedgeStyle.label_boxFillColor theLabel.strokeColor = wedgeStyle.label_strokeColor theLabel.strokeWidth = wedgeStyle.label_strokeWidth _text = wedgeStyle.label_text if _text is None: _text = text theLabel._text = _text theLabel.leading = wedgeStyle.label_leading theLabel.width = wedgeStyle.label_width theLabel.maxWidth = wedgeStyle.label_maxWidth theLabel.height = wedgeStyle.label_height theLabel.textAnchor = wedgeStyle.label_textAnchor theLabel.visible = wedgeStyle.label_visible theLabel.topPadding = wedgeStyle.label_topPadding theLabel.leftPadding = wedgeStyle.label_leftPadding theLabel.rightPadding = wedgeStyle.label_rightPadding theLabel.bottomPadding = wedgeStyle.label_bottomPadding theLabel._simple_pointer = wedgeStyle.label_simple_pointer theLabel.fontSize = wedgeStyle.fontSize theLabel.fontName = wedgeStyle.fontName theLabel.fillColor = wedgeStyle.fontColor return theLabel def _fixLabels(labels,n): if labels is None: labels = [''] * n else: i = n-len(labels) if i>0: labels = list(labels)+['']*i return labels class AbstractPieChart(PlotArea): def makeSwatchSample(self, rowNo, x, y, width, height): baseStyle = self.slices styleIdx = rowNo % len(baseStyle) style = baseStyle[styleIdx] strokeColor = getattr(style, 'strokeColor', getattr(baseStyle,'strokeColor',None)) fillColor = getattr(style, 'fillColor', getattr(baseStyle,'fillColor',None)) strokeDashArray = getattr(style, 'strokeDashArray', getattr(baseStyle,'strokeDashArray',None)) strokeWidth = getattr(style, 'strokeWidth', getattr(baseStyle, 'strokeWidth',None)) swatchMarker = getattr(style, 'swatchMarker', getattr(baseStyle, 'swatchMarker',None)) if swatchMarker: return uSymbol2Symbol(swatchMarker,x+width/2.,y+height/2.,fillColor) return Rect(x,y,width,height,strokeWidth=strokeWidth,strokeColor=strokeColor, strokeDashArray=strokeDashArray,fillColor=fillColor) def getSeriesName(self,i,default=None): '''return series name i or default''' try: text = _objStr(self.labels[i]) except: text = default if not self.simpleLabels: _text = getattr(self.slices[i],'label_text','') if _text is not None: text = _text return text def boundsOverlap(P,Q): return not(P[0]>Q[2]-1e-2 or Q[0]>P[2]-1e-2 or P[1]>(0.5*(Q[1]+Q[3]))-1e-2 or Q[1]>(0.5*(P[1]+P[3]))-1e-2) def _findOverlapRun(B,i,wrap): '''find overlap run containing B[i]''' n = len(B) R = [i] while 1: i = R[-1] j = (i+1)%n if j in R or not boundsOverlap(B[i],B[j]): break R.append(j) while 1: i = R[0] j = (i-1)%n if j in R or not boundsOverlap(B[i],B[j]): break R.insert(0,j) return R def findOverlapRun(B,wrap=1): '''determine a set of overlaps in bounding boxes B or return None''' n = len(B) if n>1: for i in range(n-1): R = _findOverlapRun(B,i,wrap) if len(R)>1: return R return None def fixLabelOverlaps(L, sideLabels=False, mult0=1.0): nL = len(L) if nL<2: return B = [l._origdata['bounds'] for l in L] OK = 1 RP = [] iter = 0 mult0 = float(mult0 + 0) mult = mult0 if not sideLabels: while iter<30: R = findOverlapRun(B) if not R: break nR = len(R) if nR==nL: break if not [r for r in RP if r in R]: mult = mult0 da = 0 r0 = R[0] rL = R[-1] bi = B[r0] taa = aa = _360(L[r0]._pmv) for r in R[1:]: b = B[r] da = max(da,min(b[2]-bi[0],bi[2]-b[0])) bi = b aa += L[r]._pmv aa = aa/float(nR) utaa = abs(L[rL]._pmv-taa) ntaa = _360(utaa) da *= mult*(nR-1)/ntaa for r in R: l = L[r] orig = l._origdata angle = l._pmv = _360(l._pmv+da*(_360(l._pmv)-aa)) rad = angle/_180_pi l.x = orig['cx'] + orig['rx']*cos(rad) l.y = orig['cy'] + orig['ry']*sin(rad) B[r] = l.getBounds() RP = R mult *= 1.05 iter += 1 else: while iter<30: R = findOverlapRun(B) if not R: break nR = len(R) if nR == nL: break l1 = L[-1] orig1 = l1._origdata bounds1 = orig1['bounds'] for i,r in enumerate(R): l = L[r] orig = l._origdata bounds = orig['bounds'] diff1 = 0 diff2 = 0 if not i == nR-1: if not bounds == bounds1: if bounds[3]>bounds1[1] and bounds1[1]bounds[1] and bounds[1] diff2: l.y +=0.5*(bounds1[3]-bounds1[1]) elif diff2 >= diff1: l.y -= 0.5*(bounds1[3]-bounds1[1]) B[r] = l.getBounds() iter += 1 def intervalIntersection(A,B): x,y = max(min(A),min(B)),min(max(A),max(B)) if x>=y: return None return x,y def _makeSideArcDefs(sa,direction): sa %= 360 if 90<=sa<270: if direction=='clockwise': a = (0,90,sa),(1,-90,90),(0,-360+sa,-90) else: a = (0,sa,270),(1,270,450),(0,450,360+sa) else: offs = sa>=270 and 360 or 0 if direction=='clockwise': a = (1,offs-90,sa),(0,offs-270,offs-90),(1,-360+sa,offs-270) else: a = (1,sa,offs+90),(0,offs+90,offs+270),(1,offs+270,360+sa) return tuple([a for a in a if a[1]1: a.sort(key=_keyFLA) return a[0] def _fPLSide(l,width,side=None): data = l._origdata if side is None: li = data['li'] ri = data['ri'] if li is None: side = 1 i = ri elif ri is None: side = 0 i = li elif li[1]-li[0]>ri[1]-ri[0]: side = 0 i = li else: side = 1 i = ri w = data['width'] edgePad = data['edgePad'] if not side: #on left l._pmv = 180 l.x = edgePad+w i = data['li'] else: l._pmv = 0 l.x = width - w - edgePad i = data['ri'] mid = data['mid'] = (i[0]+i[1])*0.5 data['smid'] = sin(mid/_180_pi) data['cmid'] = cos(mid/_180_pi) data['side'] = side return side,w #key functions def _fPLCF(a,b): return cmp(b._origdata['smid'],a._origdata['smid']) _fPLCF = functools.cmp_to_key(_fPLCF) def _arcCF(a): return a[1] def _fixPointerLabels(n,L,x,y,width,height,side=None): LR = [],[] mlr = [0,0] for l in L: i,w = _fPLSide(l,width,side) LR[i].append(l) mlr[i] = max(w,mlr[i]) mul = 1 G = n*[None] mel = 0 hh = height*0.5 yhh = y+hh m = max(mlr) for i in (0,1): T = LR[i] if T: B = [] aB = B.append S = [] aS = S.append T.sort(key=_fPLCF) p = 0 yh = y+height for l in T: data = l._origdata inc = x+mul*(m-data['width']) l.x += inc G[data['index']] = l ly = yhh+data['smid']*hh b = data['bounds'] b2 = (b[3]-b[1])*0.5 if ly+b2>yh: ly = yh-b2 if ly-b2sFree: break yh = B[j0][3]+sAbove*sNeed/sFree for r in R: l = T[r] data = l._origdata b = data['bounds'] b2 = (b[3]-b[1])*0.5 yh -= 0.5 ly = l.y = yh-b2 B[r] = data['bounds'] = (b[0],ly-b2,b[2],yh) yh = ly - b2 - 0.5 mlr[i] = m+p mul = -1 return G, mlr[0], mlr[1], mel def theta0(data, direction): fac = (2*pi)/sum(data) rads = [d*fac for d in data] r0 = 0 hrads = [] for r in rads: hrads.append(r0+r*0.5) r0 += r vstar = len(data)*1e6 rstar = 0 delta = pi/36.0 for i in range(36): r = i*delta v = sum([abs(sin(r+a)) for a in hrads]) if v < vstar: if direction == 'clockwise': rstar=-r else: rstar=r vstar = v return rstar*180/pi class AngleData(float): '''use this to carry the data along with the angle''' def __new__(cls,angle,data): self = float.__new__(cls,angle) self._data = data return self class Pie(AbstractPieChart): _attrMap = AttrMap(BASE=AbstractPieChart, data = AttrMapValue(isListOfNumbers, desc='List of numbers defining wedge sizes; need not sum to 1'), labels = AttrMapValue(isListOfStringsOrNone, desc="Optional list of labels to use for each data point"), startAngle = AttrMapValue(isNumber, desc="Angle of first slice; 0 is due East"), direction = AttrMapValue(OneOf('clockwise', 'anticlockwise'), desc="'clockwise' or 'anticlockwise'"), slices = AttrMapValue(None, desc="Collection of wedge descriptor objects"), simpleLabels = AttrMapValue(isBoolean, desc="If true(default) use a simple String not an advanced WedgeLabel. A WedgeLabel is customisable using the properties prefixed label_ in the collection slices."), other_threshold = AttrMapValue(isNumber, desc='A value for doing threshholding, not used yet.',advancedUsage=1), checkLabelOverlap = AttrMapValue(EitherOr((isNumberInRange(0.05,1),isBoolean)), desc="If true check and attempt to fix\n standard label overlaps(default off)",advancedUsage=1), pointerLabelMode = AttrMapValue(OneOf(None,'LeftRight','LeftAndRight'), desc='',advancedUsage=1), sameRadii = AttrMapValue(isBoolean, desc="If true make x/y radii the same(default off)",advancedUsage=1), orderMode = AttrMapValue(OneOf('fixed','alternate'),advancedUsage=1), xradius = AttrMapValue(isNumberOrNone, desc="X direction Radius"), yradius = AttrMapValue(isNumberOrNone, desc="Y direction Radius"), innerRadiusFraction = AttrMapValue(isNumberOrNone, desc="fraction of radii to start wedges at"), wedgeRecord = AttrMapValue(None, desc="callable(wedge,*args,**kwds)",advancedUsage=1), sideLabels = AttrMapValue(isBoolean, desc="If true attempt to make piechart with labels along side and pointers"), sideLabelsOffset = AttrMapValue(isNumber, desc="The fraction of the pie width that the labels are situated at from the edges of the pie"), labelClass=AttrMapValue(NoneOr(isCallable), desc="A class factory to use for non simple labels"), ) other_threshold=None def __init__(self,**kwd): PlotArea.__init__(self) self.x = 0 self.y = 0 self.width = 100 self.height = 100 self.data = [1,2.3,1.7,4.2] self.labels = None # or list of strings self.startAngle = 90 self.direction = "clockwise" self.simpleLabels = 1 self.checkLabelOverlap = 0 self.pointerLabelMode = None self.sameRadii = False self.orderMode = 'fixed' self.xradius = self.yradius = self.innerRadiusFraction = None self.sideLabels = 0 self.sideLabelsOffset = 0.1 self.slices = TypedPropertyCollection(WedgeProperties) self.slices[0].fillColor = colors.darkcyan self.slices[1].fillColor = colors.blueviolet self.slices[2].fillColor = colors.blue self.slices[3].fillColor = colors.cyan self.slices[4].fillColor = colors.pink self.slices[5].fillColor = colors.magenta self.slices[6].fillColor = colors.yellow def demo(self): d = Drawing(200, 100) pc = Pie() pc.x = 50 pc.y = 10 pc.width = 100 pc.height = 80 pc.data = [10,20,30,40,50,60] pc.labels = ['a','b','c','d','e','f'] pc.slices.strokeWidth=0.5 pc.slices[3].popout = 10 pc.slices[3].strokeWidth = 2 pc.slices[3].strokeDashArray = [2,2] pc.slices[3].labelRadius = 1.75 pc.slices[3].fontColor = colors.red pc.slices[0].fillColor = colors.darkcyan pc.slices[1].fillColor = colors.blueviolet pc.slices[2].fillColor = colors.blue pc.slices[3].fillColor = colors.cyan pc.slices[4].fillColor = colors.aquamarine pc.slices[5].fillColor = colors.cadetblue pc.slices[6].fillColor = colors.lightcoral d.add(pc) return d def makePointerLabels(self,angles,plMode): class PL: def __init__(self,centerx,centery,xradius,yradius,data,lu=0,ru=0): self.centerx = centerx self.centery = centery self.xradius = xradius self.yradius = yradius self.data = data self.lu = lu self.ru = ru labelX = self.width-2 labelY = self.height n = nr = nl = maxW = sumH = 0 styleCount = len(self.slices) L=[] L_add = L.append refArcs = _makeSideArcDefs(self.startAngle,self.direction) for i, A in angles: if A[1] is None: continue sn = self.getSeriesName(i,'') if not sn: continue style = self.slices[i%styleCount] if not style.label_visible or not style.visible: continue n += 1 l=_addWedgeLabel(self,sn,180,labelX,labelY,style) L_add(l) b = l.getBounds() w = b[2]-b[0] h = b[3]-b[1] ri = [(a[0],intervalIntersection(A,(a[1],a[2]))) for a in refArcs] li = _findLargestArc(ri,0) ri = _findLargestArc(ri,1) if li and ri: if plMode=='LeftAndRight': if li[1]-li[0]ri[1]-ri[0]: ri = None if ri: nr += 1 if li: nl += 1 l._origdata = dict(bounds=b,width=w,height=h,li=li,ri=ri,index=i,edgePad=style.label_pointer_edgePad,piePad=style.label_pointer_piePad,elbowLength=style.label_pointer_elbowLength) maxW = max(w,maxW) sumH += h+2 if not n: #we have no labels xradius = self.width*0.5 yradius = self.height*0.5 centerx = self.x+xradius centery = self.y+yradius if self.xradius: xradius = self.xradius if self.yradius: yradius = self.yradius if self.sameRadii: xradius=yradius=min(xradius,yradius) return PL(centerx,centery,xradius,yradius,[]) aonR = nr==n if sumH=1e-5] W.sort(key=_arcCF) T = [[],[]] i = 0 while W: if i<2: a = W.pop(0) else: a = W.pop(-1) T[i%2].append(a) i += 1 i %= 4 T[1].reverse() D = T[0]+T[1] + [a for a in D if abs(a[1])<1e-5] A = [] a = A.append for i, angle in D: endAngle = (startAngle + (angle * whichWay)) if abs(angle)>=_ANGLELO: if startAngle >= endAngle: aa = endAngle,startAngle else: aa = startAngle,endAngle else: aa = startAngle, None if wr: aa = (AngleData(aa[0],angle._data),aa[1]) startAngle = endAngle a((i,aa)) return A def makeWedges(self): angles = self.makeAngles() #Checking to see whether there are too many wedges packed in too small a space halfAngles = [] for i,(a1,a2) in angles: if a2 is None: halfAngle = a1 else: halfAngle = 0.5*(a2+a1) halfAngles.append(halfAngle) sideLabels = self.sideLabels n = len(angles) labels = _fixLabels(self.labels,n) wr = getattr(self,'wedgeRecord',None) self._seriesCount = n styleCount = len(self.slices) plMode = self.pointerLabelMode if sideLabels: plMode = None if plMode: checkLabelOverlap = False PL=self.makePointerLabels(angles,plMode) xradius = PL.xradius yradius = PL.yradius centerx = PL.centerx centery = PL.centery PL_data = PL.data gSN = lambda i: '' else: xradius = self.width*0.5 yradius = self.height*0.5 centerx = self.x + xradius centery = self.y + yradius if self.xradius: xradius = self.xradius if self.yradius: yradius = self.yradius if self.sameRadii: xradius=yradius=min(xradius,yradius) checkLabelOverlap = self.checkLabelOverlap gSN = lambda i: self.getSeriesName(i,'') g = Group() g_add = g.add L = [] L_add = L.append innerRadiusFraction = self.innerRadiusFraction for i,(a1,a2) in angles: if a2 is None: continue #if we didn't use %stylecount here we'd end up with the later wedges #all having the default style wedgeStyle = self.slices[i%styleCount] if not wedgeStyle.visible: continue aa = abs(a2-a1) # is it a popout? cx, cy = centerx, centery text = gSN(i) popout = wedgeStyle.popout if text or popout: averageAngle = (a1+a2)/2.0 aveAngleRadians = averageAngle/_180_pi cosAA = cos(aveAngleRadians) sinAA = sin(aveAngleRadians) if popout and aa<_ANGLEHI: # pop out the wedge cx = centerx + popout*cosAA cy = centery + popout*sinAA if innerRadiusFraction: theWedge = Wedge(cx, cy, xradius, a1, a2, yradius=yradius, radius1=xradius*innerRadiusFraction,yradius1=yradius*innerRadiusFraction) else: if aa>=_ANGLEHI: theWedge = Ellipse(cx, cy, xradius, yradius) else: theWedge = Wedge(cx, cy, xradius, a1, a2, yradius=yradius) theWedge.fillColor = wedgeStyle.fillColor theWedge.strokeColor = wedgeStyle.strokeColor theWedge.strokeWidth = wedgeStyle.strokeWidth theWedge.strokeLineJoin = wedgeStyle.strokeLineJoin theWedge.strokeLineCap = wedgeStyle.strokeLineCap theWedge.strokeMiterLimit = wedgeStyle.strokeMiterLimit theWedge.strokeDashArray = wedgeStyle.strokeDashArray shader = wedgeStyle.shadingKind if shader: nshades = aa / float(wedgeStyle.shadingAngle) if nshades > 1: shader = colors.Whiter if shader=='lighten' else colors.Blacker nshades = 1+int(nshades) shadingAmount = 1-wedgeStyle.shadingAmount if wedgeStyle.shadingDirection=='normal': dsh = (1-shadingAmount)/float(nshades-1) shf1 = shadingAmount else: dsh = (shadingAmount-1)/float(nshades-1) shf1 = 1 shda = (a2-a1)/float(nshades) shsc = wedgeStyle.fillColor theWedge.fillColor = None for ish in range(nshades): sha1 = a1 + ish*shda sha2 = a1 + (ish+1)*shda shc = shader(shsc,shf1 + dsh*ish) if innerRadiusFraction: shWedge = Wedge(cx, cy, xradius, sha1, sha2, yradius=yradius, radius1=xradius*innerRadiusFraction,yradius1=yradius*innerRadiusFraction) else: shWedge = Wedge(cx, cy, xradius, sha1, sha2, yradius=yradius) shWedge.fillColor = shc shWedge.strokeColor = None shWedge.strokeWidth = 0 g_add(shWedge) g_add(theWedge) if wr: wr(theWedge,value=a1._data,label=text) if wedgeStyle.label_visible: if not sideLabels: if text: labelRadius = wedgeStyle.labelRadius rx = xradius*labelRadius ry = yradius*labelRadius labelX = cx + rx*cosAA labelY = cy + ry*sinAA l = _addWedgeLabel(self,text,averageAngle,labelX,labelY,wedgeStyle) L_add(l) if not plMode and l._simple_pointer: l._aax = cx+xradius*cosAA l._aay = cy+yradius*sinAA if checkLabelOverlap: l._origdata = { 'x': labelX, 'y':labelY, 'angle': averageAngle, 'rx': rx, 'ry':ry, 'cx':cx, 'cy':cy, 'bounds': l.getBounds(), 'angles':(a1,a2), } elif plMode and PL_data: l = PL_data[i] if l: data = l._origdata sinM = data['smid'] cosM = data['cmid'] lX = cx + xradius*cosM lY = cy + yradius*sinM lpel = wedgeStyle.label_pointer_elbowLength lXi = lX + lpel*cosM lYi = lY + lpel*sinM L_add(PolyLine((lX,lY,lXi,lYi,l.x,l.y), strokeWidth=wedgeStyle.label_pointer_strokeWidth, strokeColor=wedgeStyle.label_pointer_strokeColor)) L_add(l) else: if text: slices_popout = self.slices.popout m=0 for n, angle in angles: if self.slices[n].fillColor: m += 1 else: r = n%m self.slices[n].fillColor = self.slices[r].fillColor self.slices[n].popout = self.slices[r].popout for j in range(0,m-1): if self.slices[j].popout > slices_popout: slices_popout = self.slices[j].popout labelRadius = wedgeStyle.labelRadius ry = yradius*labelRadius if (abs(averageAngle) < 90 ) or (averageAngle >270 and averageAngle <450) or (-450< averageAngle <-270): labelX = (1+self.sideLabelsOffset)*self.width + self.x + slices_popout rx = 0 else: labelX = self.x - (self.sideLabelsOffset)*self.width - slices_popout rx = 0 labelY = cy + ry*sinAA l = _addWedgeLabel(self,text,averageAngle,labelX,labelY,wedgeStyle) L_add(l) if not plMode: l._aax = cx+xradius*cosAA l._aay = cy+yradius*sinAA if checkLabelOverlap: l._origdata = { 'x': labelX, 'y':labelY, 'angle': averageAngle, 'rx': rx, 'ry':ry, 'cx':cx, 'cy':cy, 'bounds': l.getBounds(), } x1,y1,x2,y2 = l.getBounds() if checkLabelOverlap and L: fixLabelOverlaps(L, sideLabels, mult0=checkLabelOverlap) for l in L: g_add(l) if not plMode: for l in L: if l._simple_pointer and not sideLabels: g_add(Line(l.x,l.y,l._aax,l._aay, strokeWidth=wedgeStyle.label_pointer_strokeWidth, strokeColor=wedgeStyle.label_pointer_strokeColor)) elif sideLabels: x1,y1,x2,y2 = l.getBounds() #add pointers if l.x == (1+self.sideLabelsOffset)*self.width + self.x: g_add(Line(l._aax,l._aay,0.5*(l._aax+l.x),l.y+(0.25*(y2-y1)), strokeWidth=wedgeStyle.label_pointer_strokeWidth, strokeColor=wedgeStyle.label_pointer_strokeColor)) g_add(Line(0.5*(l._aax+l.x),l.y+(0.25*(y2-y1)),l.x,l.y+(0.25*(y2-y1)), strokeWidth=wedgeStyle.label_pointer_strokeWidth, strokeColor=wedgeStyle.label_pointer_strokeColor)) else: g_add(Line(l._aax,l._aay,0.5*(l._aax+l.x),l.y+(0.25*(y2-y1)), strokeWidth=wedgeStyle.label_pointer_strokeWidth, strokeColor=wedgeStyle.label_pointer_strokeColor)) g_add(Line(0.5*(l._aax+l.x),l.y+(0.25*(y2-y1)),l.x,l.y+(0.25*(y2-y1)), strokeWidth=wedgeStyle.label_pointer_strokeWidth, strokeColor=wedgeStyle.label_pointer_strokeColor)) return g def draw(self): G = self.makeBackground() w = self.makeWedges() if G: return Group(G,w) return w class LegendedPie(Pie): """Pie with a two part legend (one editable with swatches, one hidden without swatches).""" _attrMap = AttrMap(BASE=Pie, drawLegend = AttrMapValue(isBoolean, desc="If true then create and draw legend"), legend1 = AttrMapValue(None, desc="Handle to legend for pie"), legendNumberFormat = AttrMapValue(None, desc="Formatting routine for number on right hand side of legend."), legendNumberOffset = AttrMapValue(isNumber, desc="Horizontal space between legend and numbers on r/hand side"), pieAndLegend_colors = AttrMapValue(isListOfColors, desc="Colours used for both swatches and pie"), legend_names = AttrMapValue(isNoneOrListOfNoneOrStrings, desc="Names used in legend (or None)"), legend_data = AttrMapValue(isNoneOrListOfNoneOrNumbers, desc="Numbers used on r/hand side of legend (or None)"), leftPadding = AttrMapValue(isNumber, desc='Padding on left of drawing'), rightPadding = AttrMapValue(isNumber, desc='Padding on right of drawing'), topPadding = AttrMapValue(isNumber, desc='Padding at top of drawing'), bottomPadding = AttrMapValue(isNumber, desc='Padding at bottom of drawing'), ) def __init__(self): Pie.__init__(self) self.x = 0 self.y = 0 self.height = 100 self.width = 100 self.data = [38.4, 20.7, 18.9, 15.4, 6.6] self.labels = None self.direction = 'clockwise' PCMYKColor, black = colors.PCMYKColor, colors.black self.pieAndLegend_colors = [PCMYKColor(11,11,72,0,spotName='PANTONE 458 CV'), PCMYKColor(100,65,0,30,spotName='PANTONE 288 CV'), PCMYKColor(11,11,72,0,spotName='PANTONE 458 CV',density=75), PCMYKColor(100,65,0,30,spotName='PANTONE 288 CV',density=75), PCMYKColor(11,11,72,0,spotName='PANTONE 458 CV',density=50), PCMYKColor(100,65,0,30,spotName='PANTONE 288 CV',density=50)] #Allows us up to six 'wedges' to be coloured self.slices[0].fillColor=self.pieAndLegend_colors[0] self.slices[1].fillColor=self.pieAndLegend_colors[1] self.slices[2].fillColor=self.pieAndLegend_colors[2] self.slices[3].fillColor=self.pieAndLegend_colors[3] self.slices[4].fillColor=self.pieAndLegend_colors[4] self.slices[5].fillColor=self.pieAndLegend_colors[5] self.slices.strokeWidth = 0.75 self.slices.strokeColor = black legendOffset = 17 self.legendNumberOffset = 51 self.legendNumberFormat = '%.1f%%' self.legend_data = self.data #set up the legends from reportlab.graphics.charts.legends import Legend self.legend1 = Legend() self.legend1.x = self.width+legendOffset self.legend1.y = self.height self.legend1.deltax = 5.67 self.legend1.deltay = 14.17 self.legend1.dxTextSpace = 11.39 self.legend1.dx = 5.67 self.legend1.dy = 5.67 self.legend1.columnMaximum = 7 self.legend1.alignment = 'right' self.legend_names = ['AAA:','AA:','A:','BBB:','NR:'] for f in range(len(self.data)): self.legend1.colorNamePairs.append((self.pieAndLegend_colors[f], self.legend_names[f])) self.legend1.fontName = "Helvetica-Bold" self.legend1.fontSize = 6 self.legend1.strokeColor = black self.legend1.strokeWidth = 0.5 self._legend2 = Legend() self._legend2.dxTextSpace = 0 self._legend2.dx = 0 self._legend2.alignment = 'right' self._legend2.fontName = "Helvetica-Oblique" self._legend2.fontSize = 6 self._legend2.strokeColor = self.legend1.strokeColor self.leftPadding = 5 self.rightPadding = 5 self.topPadding = 5 self.bottomPadding = 5 self.drawLegend = 1 def draw(self): if self.drawLegend: self.legend1.colorNamePairs = [] self._legend2.colorNamePairs = [] for f in range(len(self.data)): if self.legend_names == None: self.slices[f].fillColor = self.pieAndLegend_colors[f] self.legend1.colorNamePairs.append((self.pieAndLegend_colors[f], None)) else: try: self.slices[f].fillColor = self.pieAndLegend_colors[f] self.legend1.colorNamePairs.append((self.pieAndLegend_colors[f], self.legend_names[f])) except IndexError: self.slices[f].fillColor = self.pieAndLegend_colors[f%len(self.pieAndLegend_colors)] self.legend1.colorNamePairs.append((self.pieAndLegend_colors[f%len(self.pieAndLegend_colors)], self.legend_names[f])) if self.legend_data != None: ldf = self.legend_data[f] lNF = self.legendNumberFormat if ldf is None or lNF is None: pass elif isinstance(lNF,str): ldf = lNF % ldf elif hasattr(lNF,'__call__'): ldf = lNF(ldf) else: raise ValueError("Unknown formatter type %s, expected string or function" % ascii(self.legendNumberFormat)) self._legend2.colorNamePairs.append((None,ldf)) p = Pie.draw(self) if self.drawLegend: p.add(self.legend1) #hide from user - keeps both sides lined up! self._legend2.x = self.legend1.x+self.legendNumberOffset self._legend2.y = self.legend1.y self._legend2.deltax = self.legend1.deltax self._legend2.deltay = self.legend1.deltay self._legend2.dy = self.legend1.dy self._legend2.columnMaximum = self.legend1.columnMaximum p.add(self._legend2) p.shift(self.leftPadding, self.bottomPadding) return p def _getDrawingDimensions(self): tx = self.rightPadding if self.drawLegend: tx += self.legend1.x+self.legendNumberOffset #self._legend2.x tx += self._legend2._calculateMaxWidth(self._legend2.colorNamePairs) ty = self.bottomPadding+self.height+self.topPadding return (tx,ty) def demo(self, drawing=None): if not drawing: tx,ty = self._getDrawingDimensions() drawing = Drawing(tx, ty) drawing.add(self.draw()) return drawing from reportlab.graphics.charts.utils3d import _getShaded, _2rad, _360, _180_pi class Wedge3dProperties(PropHolder): """This holds descriptive information about the wedges in a pie chart. It is not to be confused with the 'wedge itself'; this just holds a recipe for how to format one, and does not allow you to hack the angles. It can format a genuine Wedge object for you with its format method. """ _attrMap = AttrMap( fillColor = AttrMapValue(isColorOrNone,desc=''), fillColorShaded = AttrMapValue(isColorOrNone,desc=''), fontColor = AttrMapValue(isColorOrNone,desc=''), fontName = AttrMapValue(isString,desc=''), fontSize = AttrMapValue(isNumber,desc=''), label_angle = AttrMapValue(isNumber,desc=''), label_bottomPadding = AttrMapValue(isNumber,'padding at bottom of box'), label_boxAnchor = AttrMapValue(isBoxAnchor,desc=''), label_boxFillColor = AttrMapValue(isColorOrNone,desc=''), label_boxStrokeColor = AttrMapValue(isColorOrNone,desc=''), label_boxStrokeWidth = AttrMapValue(isNumber,desc=''), label_dx = AttrMapValue(isNumber,desc=''), label_dy = AttrMapValue(isNumber,desc=''), label_height = AttrMapValue(isNumberOrNone,desc=''), label_leading = AttrMapValue(isNumberOrNone,desc=''), label_leftPadding = AttrMapValue(isNumber,'padding at left of box'), label_maxWidth = AttrMapValue(isNumberOrNone,desc=''), label_rightPadding = AttrMapValue(isNumber,'padding at right of box'), label_simple_pointer = AttrMapValue(isBoolean,'set to True for simple pointers'), label_strokeColor = AttrMapValue(isColorOrNone,desc=''), label_strokeWidth = AttrMapValue(isNumber,desc=''), label_text = AttrMapValue(isStringOrNone,desc=''), label_textAnchor = AttrMapValue(isTextAnchor,desc=''), label_topPadding = AttrMapValue(isNumber,'padding at top of box'), label_visible = AttrMapValue(isBoolean,desc="True if the label is to be drawn"), label_width = AttrMapValue(isNumberOrNone,desc=''), labelRadius = AttrMapValue(isNumber,desc=''), popout = AttrMapValue(isNumber,desc=''), shading = AttrMapValue(isNumber,desc=''), strokeColor = AttrMapValue(isColorOrNone,desc=''), strokeColorShaded = AttrMapValue(isColorOrNone,desc=''), strokeDashArray = AttrMapValue(isListOfNumbersOrNone,desc=''), strokeWidth = AttrMapValue(isNumber,desc=''), visible = AttrMapValue(isBoolean,'set to false to skip displaying'), ) def __init__(self): self.strokeWidth = 0 self.shading = 0.3 self.visible = 1 self.strokeColorShaded = self.fillColorShaded = self.fillColor = None self.strokeColor = STATE_DEFAULTS["strokeColor"] self.strokeDashArray = STATE_DEFAULTS["strokeDashArray"] self.popout = 0 self.fontName = STATE_DEFAULTS["fontName"] self.fontSize = STATE_DEFAULTS["fontSize"] self.fontColor = STATE_DEFAULTS["fillColor"] self.labelRadius = 1.2 self.label_dx = self.label_dy = self.label_angle = 0 self.label_text = None self.label_topPadding = self.label_leftPadding = self.label_rightPadding = self.label_bottomPadding = 0 self.label_boxAnchor = 'autox' self.label_boxStrokeColor = None #boxStroke self.label_boxStrokeWidth = 0.5 #boxStrokeWidth self.label_boxFillColor = None self.label_strokeColor = None self.label_strokeWidth = 0.1 self.label_leading = self.label_width = self.label_maxWidth = self.label_height = None self.label_textAnchor = 'start' self.label_visible = 1 self.label_simple_pointer = 0 class _SL3D: def __init__(self,lo,hi): if lo<0: lo += 360 hi += 360 self.lo = lo self.hi = hi self.mid = (lo+hi)*0.5 self.not360 = abs(hi-lo) < _ANGLEHI def __str__(self): return '_SL3D(%.2f,%.2f)' % (self.lo,self.hi) def _keyS3D(a,b): return -cmp(a[0],b[0]) _keyS3D = functools.cmp_to_key(_keyS3D) _270r = _2rad(270) class Pie3d(Pie): _attrMap = AttrMap(BASE=Pie, perspective = AttrMapValue(isNumber, desc='A flattening parameter.'), depth_3d = AttrMapValue(isNumber, desc='depth of the pie.'), angle_3d = AttrMapValue(isNumber, desc='The view angle.'), ) perspective = 70 depth_3d = 25 angle_3d = 180 def _popout(self,i): return self._sl3d[i].not360 and self.slices[i].popout or 0 def CX(self, i,d ): return self._cx+(d and self._xdepth_3d or 0)+self._popout(i)*cos(_2rad(self._sl3d[i].mid)) def CY(self,i,d): return self._cy+(d and self._ydepth_3d or 0)+self._popout(i)*sin(_2rad(self._sl3d[i].mid)) def OX(self,i,o,d): return self.CX(i,d)+self._radiusx*cos(_2rad(o)) def OY(self,i,o,d): return self.CY(i,d)+self._radiusy*sin(_2rad(o)) def rad_dist(self,a): _3dva = self._3dva return min(abs(a-_3dva),abs(a-_3dva+360)) def __init__(self): Pie.__init__(self) self.slices = TypedPropertyCollection(Wedge3dProperties) self.slices[0].fillColor = colors.darkcyan self.slices[1].fillColor = colors.blueviolet self.slices[2].fillColor = colors.blue self.slices[3].fillColor = colors.cyan self.slices[4].fillColor = colors.azure self.slices[5].fillColor = colors.crimson self.slices[6].fillColor = colors.darkviolet self.xradius = self.yradius = None self.width = 300 self.height = 200 self.data = [12.50,20.10,2.00,22.00,5.00,18.00,13.00] def _fillSide(self,L,i,angle,strokeColor,strokeWidth,fillColor): rd = self.rad_dist(angle) if rd0: angle0, angle1 = angle1, angle0 _sl3d.append(_SL3D(angle0,angle1)) labels = _fixLabels(self.labels,n) a0 = _3d_angle a1 = _3d_angle+180 T = [] S = [] L = [] class WedgeLabel3d(WedgeLabel): _ydepth_3d = self._ydepth_3d def _checkDXY(self,ba): if ba[0]=='n': if not hasattr(self,'_ody'): self._ody = self.dy self.dy = -self._ody + self._ydepth_3d checkLabelOverlap = self.checkLabelOverlap for i in range(n): style = slices[i] if not style.visible: continue sl = _sl3d[i] lo = angle0 = sl.lo hi = angle1 = sl.hi aa = abs(hi-lo) if aa<_ANGLELO: continue fillColor = _getShaded(style.fillColor,style.fillColorShaded,style.shading) strokeColor = _getShaded(style.strokeColor,style.strokeColorShaded,style.shading) or fillColor strokeWidth = style.strokeWidth cx0 = CX(i,0) cy0 = CY(i,0) cx1 = CX(i,1) cy1 = CY(i,1) if depth_3d: #background shaded pie bottom g.add(Wedge(cx1,cy1,radiusx, lo, hi,yradius=radiusy, strokeColor=strokeColor,strokeWidth=strokeWidth,fillColor=fillColor, strokeLineJoin=1)) #connect to top if lo < a0 < hi: angle0 = a0 if lo < a1 < hi: angle1 = a1 p = ArcPath(strokeColor=strokeColor, fillColor=fillColor,strokeWidth=strokeWidth,strokeLineJoin=1) p.addArc(cx1,cy1,radiusx,angle0,angle1,yradius=radiusy,moveTo=1) p.lineTo(OX(i,angle1,0),OY(i,angle1,0)) p.addArc(cx0,cy0,radiusx,angle0,angle1,yradius=radiusy,reverse=1) p.closePath() if angle0<=_3dva and angle1>=_3dva: rd = 0 else: rd = min(rad_dist(angle0),rad_dist(angle1)) S.append((rd,p)) _fillSide(S,i,lo,strokeColor,strokeWidth,fillColor) _fillSide(S,i,hi,strokeColor,strokeWidth,fillColor) #bright shaded top fillColor = style.fillColor strokeColor = style.strokeColor or fillColor T.append(Wedge(cx0,cy0,radiusx,lo,hi,yradius=radiusy, strokeColor=strokeColor,strokeWidth=strokeWidth,fillColor=fillColor,strokeLineJoin=1)) if aa>=_ANGLEHI: theWedge = Ellipse(cx0, cy0, radiusx, radiusy, strokeColor=strokeColor,strokeWidth=strokeWidth,fillColor=fillColor,strokeLineJoin=1) else: theWedge = Wedge(cx0,cy0,radiusx,lo,hi,yradius=radiusy, strokeColor=strokeColor,strokeWidth=strokeWidth,fillColor=fillColor,strokeLineJoin=1) T.append(theWedge) text = labels[i] if style.label_visible and text: rat = style.labelRadius self._radiusx *= rat self._radiusy *= rat mid = sl.mid labelX = OX(i,mid,0) labelY = OY(i,mid,0) l=_addWedgeLabel(self,text,mid,labelX,labelY,style,labelClass=WedgeLabel3d) L.append(l) if checkLabelOverlap: l._origdata = { 'x': labelX, 'y':labelY, 'angle': mid, 'rx': self._radiusx, 'ry':self._radiusy, 'cx':CX(i,0), 'cy':CY(i,0), 'bounds': l.getBounds(), } self._radiusx = radiusx self._radiusy = radiusy S.sort(key=_keyS3D) if checkLabelOverlap and L: fixLabelOverlaps(L,self.sideLabels) for x in ([s[1] for s in S]+T+L): g.add(x) return g def demo(self): d = Drawing(200, 100) pc = Pie() pc.x = 50 pc.y = 10 pc.width = 100 pc.height = 80 pc.data = [10,20,30,40,50,60] pc.labels = ['a','b','c','d','e','f'] pc.slices.strokeWidth=0.5 pc.slices[3].popout = 10 pc.slices[3].strokeWidth = 2 pc.slices[3].strokeDashArray = [2,2] pc.slices[3].labelRadius = 1.75 pc.slices[3].fontColor = colors.red pc.slices[0].fillColor = colors.darkcyan pc.slices[1].fillColor = colors.blueviolet pc.slices[2].fillColor = colors.blue pc.slices[3].fillColor = colors.cyan pc.slices[4].fillColor = colors.aquamarine pc.slices[5].fillColor = colors.cadetblue pc.slices[6].fillColor = colors.lightcoral self.slices[1].visible = 0 self.slices[3].visible = 1 self.slices[4].visible = 1 self.slices[5].visible = 1 self.slices[6].visible = 0 d.add(pc) return d def sample0a(): "Make a degenerated pie chart with only one slice." d = Drawing(400, 200) pc = Pie() pc.x = 150 pc.y = 50 pc.data = [10] pc.labels = ['a'] pc.slices.strokeWidth=1#0.5 d.add(pc) return d def sample0b(): "Make a degenerated pie chart with only one slice." d = Drawing(400, 200) pc = Pie() pc.x = 150 pc.y = 50 pc.width = 120 pc.height = 100 pc.data = [10] pc.labels = ['a'] pc.slices.strokeWidth=1#0.5 d.add(pc) return d def sample1(): "Make a typical pie chart with with one slice treated in a special way." d = Drawing(400, 200) pc = Pie() pc.x = 150 pc.y = 50 pc.data = [10, 20, 30, 40, 50, 60] pc.labels = ['a', 'b', 'c', 'd', 'e', 'f'] pc.slices.strokeWidth=1#0.5 pc.slices[3].popout = 20 pc.slices[3].strokeWidth = 2 pc.slices[3].strokeDashArray = [2,2] pc.slices[3].labelRadius = 1.75 pc.slices[3].fontColor = colors.red d.add(pc) return d def sample2(): "Make a pie chart with nine slices." d = Drawing(400, 200) pc = Pie() pc.x = 125 pc.y = 25 pc.data = [0.31, 0.148, 0.108, 0.076, 0.033, 0.03, 0.019, 0.126, 0.15] pc.labels = ['1', '2', '3', '4', '5', '6', '7', '8', 'X'] pc.width = 150 pc.height = 150 pc.slices.strokeWidth=1#0.5 pc.slices[0].fillColor = colors.steelblue pc.slices[1].fillColor = colors.thistle pc.slices[2].fillColor = colors.cornflower pc.slices[3].fillColor = colors.lightsteelblue pc.slices[4].fillColor = colors.aquamarine pc.slices[5].fillColor = colors.cadetblue pc.slices[6].fillColor = colors.lightcoral pc.slices[7].fillColor = colors.tan pc.slices[8].fillColor = colors.darkseagreen d.add(pc) return d def sample3(): "Make a pie chart with a very slim slice." d = Drawing(400, 200) pc = Pie() pc.x = 125 pc.y = 25 pc.data = [74, 1, 25] pc.width = 150 pc.height = 150 pc.slices.strokeWidth=1#0.5 pc.slices[0].fillColor = colors.steelblue pc.slices[1].fillColor = colors.thistle pc.slices[2].fillColor = colors.cornflower d.add(pc) return d def sample4(): "Make a pie chart with several very slim slices." d = Drawing(400, 200) pc = Pie() pc.x = 125 pc.y = 25 pc.data = [74, 1, 1, 1, 1, 22] pc.width = 150 pc.height = 150 pc.slices.strokeWidth=1#0.5 pc.slices[0].fillColor = colors.steelblue pc.slices[1].fillColor = colors.thistle pc.slices[2].fillColor = colors.cornflower pc.slices[3].fillColor = colors.lightsteelblue pc.slices[4].fillColor = colors.aquamarine pc.slices[5].fillColor = colors.cadetblue d.add(pc) return d def sample5(): "Make a pie with side labels." d = Drawing(400, 200) pc = Pie() pc.x = 125 pc.y = 25 pc.data = [7, 1, 1, 1, 1, 2] pc.labels = ['example1', 'example2', 'example3', 'example4', 'example5', 'example6'] pc.sideLabels = 1 pc.width = 150 pc.height = 150 pc.slices.strokeWidth=1#0.5 pc.slices[0].fillColor = colors.steelblue pc.slices[1].fillColor = colors.thistle pc.slices[2].fillColor = colors.cornflower pc.slices[3].fillColor = colors.lightsteelblue pc.slices[4].fillColor = colors.aquamarine pc.slices[5].fillColor = colors.cadetblue d.add(pc) return d def sample6(): "Illustrates the pie moving to leave space for the left labels" d = Drawing(400, 200) pc = Pie() "The x value of the pie chart is 0" pc.x = 0 pc.y = 25 pc.data = [74, 1, 1, 1, 1, 22] pc.labels = ['example1', 'example2', 'example3', 'example4', 'example5', 'example6'] pc.sideLabels = 1 pc.width = 150 pc.height = 150 pc.slices.strokeWidth=1#0.5 pc.slices[0].fillColor = colors.steelblue pc.slices[1].fillColor = colors.thistle pc.slices[2].fillColor = colors.cornflower pc.slices[3].fillColor = colors.lightsteelblue pc.slices[4].fillColor = colors.aquamarine pc.slices[5].fillColor = colors.cadetblue l = Line(0,0,0,200) d.add(pc) d.add(l) return d def sample7(): "Case with overlapping pointers" d = Drawing(400, 200) pc = Pie() pc.y = 50 pc.x = 150 pc.width = 100 pc.height = 100 pc.data = [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1] pc.labels = ['example1', 'example2', 'example3', 'example4', 'example5', 'example6', 'example7', 'example8', 'example9', 'example10', 'example11', 'example12', 'example13', 'example14', 'example15', 'example16', 'example17', 'example18', 'example19', 'example20', 'example21', 'example22', 'example23', 'example24', 'example25', 'example26', 'example27', 'example28'] pc.sideLabels = 1 pc.checkLabelOverlap = 1 pc.simpleLabels = 0 pc.slices.strokeWidth=1#0.5 pc.slices[0].fillColor = colors.steelblue pc.slices[1].fillColor = colors.thistle pc.slices[2].fillColor = colors.cornflower pc.slices[3].fillColor = colors.lightsteelblue pc.slices[4].fillColor = colors.aquamarine pc.slices[5].fillColor = colors.cadetblue d.add(pc) return d def sample8(): "Case with overlapping labels" "Labels overlap if they do not belong to adjacent pie slices due to nature of checkLabelOverlap" d = Drawing(400, 200) pc = Pie() pc.y = 50 pc.x = 150 pc.width = 100 pc.height = 100 pc.data = [1, 1, 1, 1, 1, 30, 50, 1, 1, 1, 1, 1, 1, 40,20,10] pc.labels = ['example1', 'example2', 'example3', 'example4', 'example5', 'example6', 'example7', 'example8', 'example9', 'example10', 'example11', 'example12', 'example13', 'example14', 'example15', 'example16'] pc.sideLabels = 1 pc.checkLabelOverlap = 1 pc.slices.strokeWidth=1#0.5 pc.slices[0].fillColor = colors.steelblue pc.slices[1].fillColor = colors.thistle pc.slices[2].fillColor = colors.cornflower pc.slices[3].fillColor = colors.lightsteelblue pc.slices[4].fillColor = colors.aquamarine pc.slices[5].fillColor = colors.cadetblue d.add(pc) return d def sample9(): "Case with overlapping labels" "Labels overlap if they do not belong to adjacent pies due to nature of checkLabelOverlap" d = Drawing(400, 200) pc = Pie() pc.x = 125 pc.y = 50 pc.data = [41, 20, 40, 15, 20, 30, 50, 15, 25, 35, 25, 20, 30, 40, 20, 30] pc.labels = ['example1', 'example2', 'example3', 'example4', 'example5', 'example6', 'example7', 'example8', 'example9', 'example10', 'example11', 'example12', 'example13', 'example14', 'example15', 'example16'] pc.sideLabels = 1 pc.checkLabelOverlap = 1 pc.width = 100 pc.height = 100 pc.slices.strokeWidth=1#0.5 pc.slices[0].fillColor = colors.steelblue pc.slices[1].fillColor = colors.thistle pc.slices[2].fillColor = colors.cornflower pc.slices[3].fillColor = colors.lightsteelblue pc.slices[4].fillColor = colors.aquamarine pc.slices[5].fillColor = colors.cadetblue d.add(pc) return d if __name__=='__main__': """Normally nobody will execute this It's helpful for reportlab developers to put a 'main' block in to execute the most recently edited feature. """ import sys from reportlab.graphics import renderPDF argv = sys.argv[1:] or ['7'] for a in argv: name = a if a.startswith('sample') else 'sample%s' % a drawing = globals()[name]() renderPDF.drawToFile(drawing, '%s.pdf' % name) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1691062243.0 reportlab-4.1.0/src/reportlab/graphics/charts/slidebox.py0000664000175000017500000002054414462707743023155 0ustar00rptlabrptlabfrom reportlab.lib import colors from reportlab.lib.colors import black, white from reportlab.graphics.shapes import Polygon, String, Drawing, Group, Rect from reportlab.graphics.widgetbase import Widget from reportlab.lib.attrmap import * from reportlab.lib.validators import * from reportlab.lib.units import cm from reportlab.pdfbase.pdfmetrics import getFont from reportlab.graphics.widgets.grids import ShadedRect class SlideBox(Widget): """Returns a slidebox widget""" _attrMap = AttrMap( labelFontName = AttrMapValue(isString, desc="Name of font used for the labels"), labelFontSize = AttrMapValue(isNumber, desc="Size of font used for the labels"), labelStrokeColor = AttrMapValue(isColorOrNone, desc="Colour for for number outlines"), labelFillColor = AttrMapValue(isColorOrNone, desc="Colour for number insides"), startColor = AttrMapValue(isColor, desc='Color of first box'), endColor = AttrMapValue(isColor, desc='Color of last box'), numberOfBoxes = AttrMapValue(isInt, desc='How many boxes there are'), trianglePosition = AttrMapValue(isInt, desc='Which box is highlighted by the triangles'), triangleHeight = AttrMapValue(isNumber, desc="Height of indicator triangles"), triangleWidth = AttrMapValue(isNumber, desc="Width of indicator triangles"), triangleFillColor = AttrMapValue(isColor, desc="Colour of indicator triangles"), triangleStrokeColor = AttrMapValue(isColorOrNone, desc="Colour of indicator triangle outline"), triangleStrokeWidth = AttrMapValue(isNumber, desc="Colour of indicator triangle outline"), boxHeight = AttrMapValue(isNumber, desc="Height of the boxes"), boxWidth = AttrMapValue(isNumber, desc="Width of the boxes"), boxSpacing = AttrMapValue(isNumber, desc="Space between the boxes"), boxOutlineColor = AttrMapValue(isColorOrNone, desc="Colour used to outline the boxes (if any)"), boxOutlineWidth = AttrMapValue(isNumberOrNone, desc="Width of the box outline (if any)"), leftPadding = AttrMapValue(isNumber, desc='Padding on left of drawing'), rightPadding = AttrMapValue(isNumber, desc='Padding on right of drawing'), topPadding = AttrMapValue(isNumber, desc='Padding at top of drawing'), bottomPadding = AttrMapValue(isNumber, desc='Padding at bottom of drawing'), background = AttrMapValue(isColorOrNone, desc='Colour of the background to the drawing (if any)'), sourceLabelText = AttrMapValue(isNoneOrString, desc="Text used for the 'source' label (can be empty)"), sourceLabelOffset = AttrMapValue(isNumber, desc='Padding at bottom of drawing'), sourceLabelFontName = AttrMapValue(isString, desc="Name of font used for the 'source' label"), sourceLabelFontSize = AttrMapValue(isNumber, desc="Font size for the 'source' label"), sourceLabelFillColor = AttrMapValue(isColorOrNone, desc="Colour ink for the 'source' label (bottom right)"), ) def __init__(self): self.labelFontName = "Helvetica-Bold" self.labelFontSize = 10 self.labelStrokeColor = black self.labelFillColor = white self.startColor = colors.Color(232/255.0,224/255.0,119/255.0) self.endColor = colors.Color(25/255.0,77/255.0,135/255.0) self.numberOfBoxes = 7 self.trianglePosition = 7 self.triangleHeight = 0.12*cm self.triangleWidth = 0.38*cm self.triangleFillColor = white self.triangleStrokeColor = black self.triangleStrokeWidth = 0.58 self.boxHeight = 0.55*cm self.boxWidth = 0.73*cm self.boxSpacing = 0.075*cm self.boxOutlineColor = black self.boxOutlineWidth = 0.58 self.leftPadding=5 self.rightPadding=5 self.topPadding=5 self.bottomPadding=5 self.background=None self.sourceLabelText = "Source: ReportLab" self.sourceLabelOffset = 0.2*cm self.sourceLabelFontName = "Helvetica-Oblique" self.sourceLabelFontSize = 6 self.sourceLabelFillColor = black def _getDrawingDimensions(self): tx=(self.numberOfBoxes*self.boxWidth) if self.numberOfBoxes>1: tx=tx+((self.numberOfBoxes-1)*self.boxSpacing) tx=tx+self.leftPadding+self.rightPadding ty=self.boxHeight+self.triangleHeight ty=ty+self.topPadding+self.bottomPadding+self.sourceLabelOffset+self.sourceLabelFontSize return (tx,ty) def _getColors(self): # for calculating intermediate colors... numShades = self.numberOfBoxes+1 fillColorStart = self.startColor fillColorEnd = self.endColor colorsList =[] for i in range(0,numShades): colorsList.append(colors.linearlyInterpolatedColor(fillColorStart, fillColorEnd, 0, numShades-1, i)) return colorsList def demo(self,drawing=None): if not drawing: tx,ty=self._getDrawingDimensions() drawing = Drawing(tx,ty) drawing.add(self.draw()) return drawing def draw(self): g = Group() ys = self.bottomPadding+(self.triangleHeight/2)+self.sourceLabelOffset+self.sourceLabelFontSize if self.background: x,y = self._getDrawingDimensions() g.add(Rect(-self.leftPadding,-ys,x,y, strokeColor=None, strokeWidth=0, fillColor=self.background)) ascent=getFont(self.labelFontName).face.ascent/1000. if ascent==0: ascent=0.718 # default (from helvetica) ascent=ascent*self.labelFontSize # normalize colorsList = self._getColors() # Draw the boxes - now uses ShadedRect from grids x=0 for f in range (0,self.numberOfBoxes): sr=ShadedRect() sr.x=x sr.y=0 sr.width=self.boxWidth sr.height=self.boxHeight sr.orientation = 'vertical' sr.numShades = 30 sr.fillColorStart = colorsList[f] sr.fillColorEnd = colorsList[f+1] sr.strokeColor = None sr.strokeWidth = 0 g.add(sr) g.add(Rect(x,0,self.boxWidth,self.boxHeight, strokeColor=self.boxOutlineColor, strokeWidth=self.boxOutlineWidth, fillColor=None)) g.add(String(x+self.boxWidth/2.,(self.boxHeight-ascent)/2., text = str(f+1), fillColor = self.labelFillColor, strokeColor=self.labelStrokeColor, textAnchor = 'middle', fontName = self.labelFontName, fontSize = self.labelFontSize)) x=x+self.boxWidth+self.boxSpacing #do triangles xt = (self.trianglePosition*self.boxWidth) if self.trianglePosition>1: xt = xt+(self.trianglePosition-1)*self.boxSpacing xt = xt-(self.boxWidth/2) g.add(Polygon( strokeColor = self.triangleStrokeColor, strokeWidth = self.triangleStrokeWidth, fillColor = self.triangleFillColor, points=[xt,self.boxHeight-(self.triangleHeight/2), xt-(self.triangleWidth/2),self.boxHeight+(self.triangleHeight/2), xt+(self.triangleWidth/2),self.boxHeight+(self.triangleHeight/2), xt,self.boxHeight-(self.triangleHeight/2)])) g.add(Polygon( strokeColor = self.triangleStrokeColor, strokeWidth = self.triangleStrokeWidth, fillColor = self.triangleFillColor, points=[xt,0+(self.triangleHeight/2), xt-(self.triangleWidth/2),0-(self.triangleHeight/2), xt+(self.triangleWidth/2),0-(self.triangleHeight/2), xt,0+(self.triangleHeight/2)])) #source label if self.sourceLabelText != None: g.add(String(x-self.boxSpacing,0-(self.triangleHeight/2)-self.sourceLabelOffset-(self.sourceLabelFontSize), text = self.sourceLabelText, fillColor = self.sourceLabelFillColor, textAnchor = 'end', fontName = self.sourceLabelFontName, fontSize = self.sourceLabelFontSize)) g.shift(self.leftPadding, ys) return g if __name__ == "__main__": d = SlideBox() d.demo().save(fnRoot="slidebox") ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1704966359.0 reportlab-4.1.0/src/reportlab/graphics/charts/spider.py0000664000175000017500000003740414547734327022637 0ustar00rptlabrptlab #Copyright ReportLab Europe Ltd. 2000-2017 #see license.txt for license details #history https://hg.reportlab.com/hg-public/reportlab/log/tip/src/reportlab/graphics/charts/spider.py # spider chart, also known as radar chart __version__='3.3.0' __doc__="""Spider Chart Normal use shows variation of 5-10 parameters against some 'norm' or target. When there is more than one series, place the series with the largest numbers first, as it will be overdrawn by each successive one. """ from math import sin, cos, pi from reportlab.lib import colors from reportlab.lib.validators import isNumber, isListOfNumbersOrNone,\ isColorOrNone, isListOfStringsOrNone, OneOf,\ isBoolean, isNumberOrNone,\ isStringOrNone, isStringOrNone, EitherOr,\ isCallable, NoneOr from reportlab.lib.attrmap import * from reportlab.graphics.shapes import Group, Drawing, Line, Rect, Polygon, PolyLine, \ STATE_DEFAULTS from reportlab.graphics.widgetbase import TypedPropertyCollection, PropHolder from reportlab.graphics.charts.areas import PlotArea from reportlab.graphics.charts.legends import _objStr from reportlab.graphics.charts.piecharts import WedgeLabel from reportlab.graphics.widgets.markers import makeMarker, uSymbol2Symbol, isSymbol class StrandProperty(PropHolder): _attrMap = AttrMap( strokeWidth = AttrMapValue(isNumber,desc='width'), fillColor = AttrMapValue(isColorOrNone,desc='filling color'), strokeColor = AttrMapValue(isColorOrNone,desc='stroke color'), strokeDashArray = AttrMapValue(isListOfNumbersOrNone,desc='dashing pattern, e.g. (3,2)'), symbol = AttrMapValue(EitherOr((isStringOrNone,isSymbol)), desc='Widget placed at data points.',advancedUsage=1), symbolSize= AttrMapValue(isNumber, desc='Symbol size.',advancedUsage=1), name = AttrMapValue(isStringOrNone, desc='Name of the strand.'), ) def __init__(self): self.strokeWidth = 1 self.fillColor = None self.strokeColor = STATE_DEFAULTS["strokeColor"] self.strokeDashArray = STATE_DEFAULTS["strokeDashArray"] self.symbol = None self.symbolSize = 5 self.name = None class SpokeProperty(PropHolder): _attrMap = AttrMap( strokeWidth = AttrMapValue(isNumber,desc='width'), fillColor = AttrMapValue(isColorOrNone,desc='filling color'), strokeColor = AttrMapValue(isColorOrNone,desc='stroke color'), strokeDashArray = AttrMapValue(isListOfNumbersOrNone,desc='dashing pattern, e.g. (2,1)'), labelRadius = AttrMapValue(isNumber,desc='label radius',advancedUsage=1), visible = AttrMapValue(isBoolean,desc="True if the spoke line is to be drawn"), ) def __init__(self,**kw): self.strokeWidth = 0.5 self.fillColor = None self.strokeColor = STATE_DEFAULTS["strokeColor"] self.strokeDashArray = STATE_DEFAULTS["strokeDashArray"] self.visible = 1 self.labelRadius = 1.05 class SpokeLabel(WedgeLabel): def __init__(self,**kw): WedgeLabel.__init__(self,**kw) if '_text' not in list(kw.keys()): self._text = '' class StrandLabel(SpokeLabel): _attrMap = AttrMap(BASE=SpokeLabel, format = AttrMapValue(EitherOr((isStringOrNone,isCallable)),desc="Format for the label"), dR = AttrMapValue(isNumberOrNone,desc="radial shift for label"), ) def __init__(self,**kw): self.format = '' self.dR = 0 SpokeLabel.__init__(self,**kw) def _setupLabel(labelClass, text, radius, cx, cy, angle, car, sar, sty): L = labelClass() L._text = text L.x = cx + radius*car L.y = cy + radius*sar L._pmv = angle*180/pi L.boxAnchor = sty.boxAnchor L.dx = sty.dx L.dy = sty.dy L.angle = sty.angle L.boxAnchor = sty.boxAnchor L.boxStrokeColor = sty.boxStrokeColor L.boxStrokeWidth = sty.boxStrokeWidth L.boxFillColor = sty.boxFillColor L.strokeColor = sty.strokeColor L.strokeWidth = sty.strokeWidth L.leading = sty.leading L.width = sty.width L.maxWidth = sty.maxWidth L.height = sty.height L.textAnchor = sty.textAnchor L.visible = sty.visible L.topPadding = sty.topPadding L.leftPadding = sty.leftPadding L.rightPadding = sty.rightPadding L.bottomPadding = sty.bottomPadding L.fontName = sty.fontName L.fontSize = sty.fontSize L.fillColor = sty.fillColor return L class SpiderChart(PlotArea): _attrMap = AttrMap(BASE=PlotArea, data = AttrMapValue(None, desc='Data to be plotted, list of (lists of) numbers.'), labels = AttrMapValue(isListOfStringsOrNone, desc="optional list of labels to use for each data point"), startAngle = AttrMapValue(isNumber, desc="angle of first slice; like the compass, 0 is due North"), direction = AttrMapValue( OneOf('clockwise', 'anticlockwise'), desc="'clockwise' or 'anticlockwise'"), strands = AttrMapValue(None, desc="collection of strand descriptor objects"), spokes = AttrMapValue(None, desc="collection of spoke descriptor objects"), strandLabels = AttrMapValue(None, desc="collection of strand label descriptor objects"), strandLabelClass=AttrMapValue(NoneOr(isCallable), desc="A class factory to use for the strand labels"), spokeLabels = AttrMapValue(None, desc="collection of spoke label descriptor objects"), spokeLabelClass=AttrMapValue(NoneOr(isCallable), desc="A class factory to use for the spoke labels"), ) def makeSwatchSample(self, rowNo, x, y, width, height): baseStyle = self.strands styleIdx = rowNo % len(baseStyle) style = baseStyle[styleIdx] strokeColor = getattr(style, 'strokeColor', getattr(baseStyle,'strokeColor',None)) fillColor = getattr(style, 'fillColor', getattr(baseStyle,'fillColor',None)) strokeDashArray = getattr(style, 'strokeDashArray', getattr(baseStyle,'strokeDashArray',None)) strokeWidth = getattr(style, 'strokeWidth', getattr(baseStyle, 'strokeWidth',0)) symbol = getattr(style, 'symbol', getattr(baseStyle, 'symbol',None)) ym = y+height/2.0 if fillColor is None and strokeColor is not None and strokeWidth>0: bg = Line(x,ym,x+width,ym,strokeWidth=strokeWidth,strokeColor=strokeColor, strokeDashArray=strokeDashArray) elif fillColor is not None: bg = Rect(x,y,width,height,strokeWidth=strokeWidth,strokeColor=strokeColor, strokeDashArray=strokeDashArray,fillColor=fillColor) else: bg = None if symbol: symbol = uSymbol2Symbol(symbol,x+width/2.,ym,color) if bg: g = Group() g.add(bg) g.add(symbol) return g return symbol or bg def getSeriesName(self,i,default=None): '''return series name i or default''' return _objStr(getattr(self.strands[i],'name',default)) def __init__(self): PlotArea.__init__(self) self.data = [[10,12,14,16,14,12], [6,8,10,12,9,11]] self.labels = None # or list of strings self.labels = ['a','b','c','d','e','f'] self.startAngle = 90 self.direction = "clockwise" self.strands = TypedPropertyCollection(StrandProperty) self.spokes = TypedPropertyCollection(SpokeProperty) self.spokeLabels = TypedPropertyCollection(SpokeLabel) self.spokeLabels._text = None self.strandLabels = TypedPropertyCollection(StrandLabel) self.x = 10 self.y = 10 self.width = 180 self.height = 180 def demo(self): d = Drawing(200, 200) d.add(SpiderChart()) return d def normalizeData(self, outer = 0.0): """Turns data into normalized ones where each datum is < 1.0, and 1.0 = maximum radius. Adds 10% at outside edge by default""" data = self.data assert min(list(map(min,data))) >=0, "Cannot do spider plots of negative numbers!" norm = max(list(map(max,data))) norm *= (1.0+outer) if norm<1e-9: norm = 1.0 self._norm = norm return [[e/norm for e in row] for row in data] def _innerDrawLabel(self, sty, radius, cx, cy, angle, car, sar, labelClass=None): "Draw a label for a given item in the list." fmt = sty.format value = radius*self._norm if not fmt: text = None elif isinstance(fmt,str): if fmt == 'values': text = sty._text else: text = fmt % value elif hasattr(fmt,'__call__'): text = fmt(value) else: raise ValueError("Unknown formatter type %s, expected string or function" % fmt) if text: dR = sty.dR if dR: radius += dR/self._radius L = _setupLabel(labelClass, text, radius, cx, cy, angle, car, sar, sty) if dR<0: L._anti = 1 else: L = None return L def labelClass(self,kind): klass = getattr(self,f'{kind}LabelClass',None) if not klass: klass = globals()[f'{kind.capitalize()}Label'] return klass def draw(self): # normalize slice data g = self.makeBackground() or Group() xradius = self.width/2.0 yradius = self.height/2.0 self._radius = radius = min(xradius, yradius) cx = self.x + xradius cy = self.y + yradius data = self.normalizeData() self._seriesCount = len(data) n = len(data[0]) #labels if self.labels is None: labels = [''] * n else: labels = self.labels #there's no point in raising errors for less than enough errors if #we silently create all for the extreme case of no labels. i = n-len(labels) if i>0: labels = labels + ['']*i S = [] STRANDS = [] STRANDAREAS = [] syms = [] labs = [] csa = [] angle = self.startAngle*pi/180 direction = self.direction == "clockwise" and -1 or 1 angleBetween = direction*(2 * pi)/float(n) spokes = self.spokes spokeLabels = self.spokeLabels for i in range(n): car = cos(angle)*radius sar = sin(angle)*radius csa.append((car,sar,angle)) si = self.spokes[i] if si.visible: spoke = Line(cx, cy, cx + car, cy + sar, strokeWidth = si.strokeWidth, strokeColor=si.strokeColor, strokeDashArray=si.strokeDashArray) S.append(spoke) sli = spokeLabels[i] text = sli._text if not text: text = labels[i] if text: S.append(_setupLabel(self.labelClass('spoke'), text, si.labelRadius, cx, cy, angle, car, sar, sli)) angle += angleBetween # now plot the polygons rowIdx = 0 strands = self.strands strandLabels = self.strandLabels for row in data: # series plot rsty = strands[rowIdx] points = [] car, sar = csa[-1][:2] r = row[-1] points.append(cx+car*r) points.append(cy+sar*r) for i in range(n): car, sar, angle = csa[i] r = row[i] points.append(cx+car*r) points.append(cy+sar*r) L = self._innerDrawLabel(strandLabels[(rowIdx,i)], r, cx, cy, angle, car, sar, labelClass=self.labelClass('strand')) if L: labs.append(L) sty = strands[(rowIdx,i)] uSymbol = sty.symbol # put in a marker, if it needs one if uSymbol: s_x = cx+car*r s_y = cy+sar*r s_fillColor = sty.fillColor s_strokeColor = sty.strokeColor s_strokeWidth = sty.strokeWidth s_angle = 0 s_size = sty.symbolSize if type(uSymbol) is type(''): symbol = makeMarker(uSymbol, size = s_size, x = s_x, y = s_y, fillColor = s_fillColor, strokeColor = s_strokeColor, strokeWidth = s_strokeWidth, angle = s_angle, ) else: symbol = uSymbol2Symbol(uSymbol,s_x,s_y,s_fillColor) for k,v in (('size', s_size), ('fillColor', s_fillColor), ('x', s_x), ('y', s_y), ('strokeColor',s_strokeColor), ('strokeWidth',s_strokeWidth), ('angle',s_angle),): if getattr(symbol,k,None) is None: try: setattr(symbol,k,v) except: pass syms.append(symbol) # make up the 'strand' if rsty.fillColor: strand = Polygon(points) strand.fillColor = rsty.fillColor strand.strokeColor = None strand.strokeWidth = 0 STRANDAREAS.append(strand) if rsty.strokeColor and rsty.strokeWidth: strand = PolyLine(points) strand.strokeColor = rsty.strokeColor strand.strokeWidth = rsty.strokeWidth strand.strokeDashArray = rsty.strokeDashArray STRANDS.append(strand) rowIdx += 1 for s in (STRANDAREAS+STRANDS+syms+S+labs): g.add(s) return g def sample1(): "Make a simple spider chart" d = Drawing(400, 400) sp = SpiderChart() sp.x = 50 sp.y = 50 sp.width = 300 sp.height = 300 sp.data = [[10,12,14,16,14,12], [6,8,10,12,9,15],[7,8,17,4,12,8]] sp.labels = ['a','b','c','d','e','f'] sp.strands[0].strokeColor = colors.cornsilk sp.strands[1].strokeColor = colors.cyan sp.strands[2].strokeColor = colors.palegreen sp.strands[0].fillColor = colors.cornsilk sp.strands[1].fillColor = colors.cyan sp.strands[2].fillColor = colors.palegreen sp.spokes.strokeDashArray = (2,2) d.add(sp) return d def sample2(): "Make a spider chart with markers, but no fill" d = Drawing(400, 400) sp = SpiderChart() sp.x = 50 sp.y = 50 sp.width = 300 sp.height = 300 sp.data = [[10,12,14,16,14,12], [6,8,10,12,9,15],[7,8,17,4,12,8]] sp.labels = ['U','V','W','X','Y','Z'] sp.strands.strokeWidth = 1 sp.strands[0].fillColor = colors.pink sp.strands[1].fillColor = colors.lightblue sp.strands[2].fillColor = colors.palegreen sp.strands[0].strokeColor = colors.red sp.strands[1].strokeColor = colors.blue sp.strands[2].strokeColor = colors.green sp.strands.symbol = "FilledDiamond" sp.strands[1].symbol = makeMarker("Circle") sp.strands[1].symbol.strokeWidth = 0.5 sp.strands[1].symbol.fillColor = colors.yellow sp.strands.symbolSize = 6 sp.strandLabels[0,3]._text = 'special' sp.strandLabels[0,1]._text = 'one' sp.strandLabels[0,0]._text = 'zero' sp.strandLabels[1,0]._text = 'Earth' sp.strandLabels[2,2]._text = 'Mars' sp.strandLabels.format = 'values' sp.strandLabels.dR = -5 d.add(sp) return d if __name__=='__main__': d = sample1() from reportlab.graphics.renderPDF import drawToFile drawToFile(d, 'spider.pdf') d = sample2() drawToFile(d, 'spider2.pdf') ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1704966359.0 reportlab-4.1.0/src/reportlab/graphics/charts/textlabels.py0000664000175000017500000005464114547734327023522 0ustar00rptlabrptlab#Copyright ReportLab Europe Ltd. 2000-2017 #see license.txt for license details #history https://hg.reportlab.com/hg-public/reportlab/log/tip/src/reportlab/graphics/charts/textlabels.py __version__='3.3.0' from reportlab.lib import colors from reportlab.lib.utils import simpleSplit from reportlab.lib.validators import isNumber, isNumberOrNone, OneOf, isColorOrNone, isString, \ isTextAnchor, isBoxAnchor, isBoolean, NoneOr, isInstanceOf, isNoneOrString, isNoneOrCallable, \ isSubclassOf from reportlab.lib.attrmap import * from reportlab.pdfbase.pdfmetrics import stringWidth, getAscentDescent from reportlab.graphics.shapes import Drawing, Group, Circle, Rect, String, STATE_DEFAULTS from reportlab.graphics.widgetbase import Widget, PropHolder from reportlab.graphics.shapes import DirectDraw from reportlab.platypus import XPreformatted, Flowable from reportlab.lib.styles import ParagraphStyle, PropertySet from reportlab.lib.enums import TA_LEFT, TA_RIGHT, TA_CENTER _ta2al = dict(start=TA_LEFT,end=TA_RIGHT,middle=TA_CENTER) from ..utils import text2Path as _text2Path #here for continuity _A2BA= { 'x': {0:'n', 45:'ne', 90:'e', 135:'se', 180:'s', 225:'sw', 270:'w', 315: 'nw', -45: 'nw'}, 'y': {0:'e', 45:'se', 90:'s', 135:'sw', 180:'w', 225:'nw', 270:'n', 315: 'ne', -45: 'ne'}, } try: from rlextra.graphics.canvasadapter import DirectDrawFlowable except ImportError: DirectDrawFlowable = None _BA2TA={'w':'start','nw':'start','sw':'start','e':'end', 'ne': 'end', 'se':'end', 'n':'middle','s':'middle','c':'middle'} class Label(Widget): """A text label to attach to something else, such as a chart axis. This allows you to specify an offset, angle and many anchor properties relative to the label's origin. It allows, for example, angled multiline axis labels. """ # fairly straight port of Robin Becker's textbox.py to new widgets # framework. _attrMap = AttrMap( x = AttrMapValue(isNumber,desc=''), y = AttrMapValue(isNumber,desc=''), dx = AttrMapValue(isNumber,desc='delta x - offset'), dy = AttrMapValue(isNumber,desc='delta y - offset'), angle = AttrMapValue(isNumber,desc='angle of label: default (0), 90 is vertical, 180 is upside down, etc'), boxAnchor = AttrMapValue(isBoxAnchor,desc='anchoring point of the label'), boxStrokeColor = AttrMapValue(isColorOrNone,desc='border color of the box'), boxStrokeWidth = AttrMapValue(isNumber,desc='border width'), boxFillColor = AttrMapValue(isColorOrNone,desc='the filling color of the box'), boxTarget = AttrMapValue(OneOf('normal','anti','lo','hi'),desc="one of ('normal','anti','lo','hi')"), fillColor = AttrMapValue(isColorOrNone,desc='label text color'), strokeColor = AttrMapValue(isColorOrNone,desc='label text border color'), strokeWidth = AttrMapValue(isNumber,desc='label text border width'), text = AttrMapValue(isString,desc='the actual text to display'), fontName = AttrMapValue(isString,desc='the name of the font used'), fontSize = AttrMapValue(isNumber,desc='the size of the font'), leading = AttrMapValue(isNumberOrNone,desc=''), width = AttrMapValue(isNumberOrNone,desc='the width of the label'), maxWidth = AttrMapValue(isNumberOrNone,desc='maximum width the label can grow to'), height = AttrMapValue(isNumberOrNone,desc='the height of the text'), textAnchor = AttrMapValue(isTextAnchor,desc='the anchoring point of the text inside the label'), visible = AttrMapValue(isBoolean,desc="True if the label is to be drawn"), topPadding = AttrMapValue(isNumber,desc='padding at top of box'), leftPadding = AttrMapValue(isNumber,desc='padding at left of box'), rightPadding = AttrMapValue(isNumber,desc='padding at right of box'), bottomPadding = AttrMapValue(isNumber,desc='padding at bottom of box'), useAscentDescent = AttrMapValue(isBoolean,desc="If True then the font's Ascent & Descent will be used to compute default heights and baseline."), customDrawChanger = AttrMapValue(isNoneOrCallable,desc="An instance of CustomDrawChanger to modify the behavior at draw time", _advancedUsage=1), ddf = AttrMapValue(NoneOr(isSubclassOf(DirectDraw),'NoneOrDirectDraw'),desc="A DirectDrawFlowable instance", _advancedUsage=1), ddfKlass = AttrMapValue(NoneOr(isSubclassOf(Flowable),'NoneOrDirectDraw'),desc="A Flowable class for direct drawing (default is XPreformatted", _advancedUsage=1), ddfStyle = AttrMapValue(NoneOr((isSubclassOf(PropertySet),isInstanceOf(PropertySet))),desc="A style or style class for a ddfKlass or None", _advancedUsage=1), ) def __init__(self,**kw): self._setKeywords(**kw) self._setKeywords( _text = 'Multi-Line\nString', boxAnchor = 'c', angle = 0, x = 0, y = 0, dx = 0, dy = 0, topPadding = 0, leftPadding = 0, rightPadding = 0, bottomPadding = 0, boxStrokeWidth = 0.5, boxStrokeColor = None, boxTarget = 'normal', strokeColor = None, boxFillColor = None, leading = None, width = None, maxWidth = None, height = None, fillColor = STATE_DEFAULTS['fillColor'], fontName = STATE_DEFAULTS['fontName'], fontSize = STATE_DEFAULTS['fontSize'], strokeWidth = 0.1, textAnchor = 'start', visible = 1, useAscentDescent = False, ddf = DirectDrawFlowable, ddfKlass = getattr(self.__class__,'ddfKlass',None), ddfStyle = getattr(self.__class__,'ddfStyle',None), ) def setText(self, text): """Set the text property. May contain embedded newline characters. Called by the containing chart or axis.""" self._text = text def setOrigin(self, x, y): """Set the origin. This would be the tick mark or bar top relative to which it is defined. Called by the containing chart or axis.""" self.x = x self.y = y def demo(self): """This shows a label positioned with its top right corner at the top centre of the drawing, and rotated 45 degrees.""" d = Drawing(200, 100) # mark the origin of the label d.add(Circle(100,90, 5, fillColor=colors.green)) lab = Label() lab.setOrigin(100,90) lab.boxAnchor = 'ne' lab.angle = 45 lab.dx = 0 lab.dy = -20 lab.boxStrokeColor = colors.green lab.setText('Another\nMulti-Line\nString') d.add(lab) return d def _getBoxAnchor(self): '''hook for allowing special box anchor effects''' ba = self.boxAnchor if ba in ('autox', 'autoy'): angle = self.angle na = (int((angle%360)/45.)*45)%360 if not (na % 90): # we have a right angle case da = (angle - na) % 360 if abs(da)>5: na = na + (da>0 and 45 or -45) ba = _A2BA[ba[-1]][na] return ba def _getBaseLineRatio(self): if self.useAscentDescent: self._ascent, self._descent = getAscentDescent(self.fontName,self.fontSize) self._baselineRatio = self._ascent/(self._ascent-self._descent) else: self._baselineRatio = 1/1.2 def _computeSizeEnd(self,objH): self._height = self.height or (objH + self.topPadding + self.bottomPadding) self._ewidth = (self._width-self.leftPadding-self.rightPadding) self._eheight = (self._height-self.topPadding-self.bottomPadding) boxAnchor = self._getBoxAnchor() if boxAnchor in ['n','ne','nw']: self._top = -self.topPadding elif boxAnchor in ['s','sw','se']: self._top = self._height-self.topPadding else: self._top = 0.5*self._eheight self._bottom = self._top - self._eheight if boxAnchor in ['ne','e','se']: self._left = self.leftPadding - self._width elif boxAnchor in ['nw','w','sw']: self._left = self.leftPadding else: self._left = -self._ewidth*0.5 self._right = self._left+self._ewidth def computeSize(self): # the thing will draw in its own coordinate system ddfKlass = getattr(self,'ddfKlass',None) if not ddfKlass: self._lineWidths = [] self._lines = simpleSplit(self._text,self.fontName,self.fontSize,self.maxWidth) if not self.width: self._width = self.leftPadding+self.rightPadding if self._lines: self._lineWidths = [stringWidth(line,self.fontName,self.fontSize) for line in self._lines] self._width += max(self._lineWidths) else: self._width = self.width self._getBaseLineRatio() if self.leading: self._leading = self.leading elif self.useAscentDescent: self._leading = self._ascent - self._descent else: self._leading = self.fontSize*1.2 objH = self._leading*len(self._lines) else: if self.ddf is None: raise RuntimeError('DirectDrawFlowable class is not available you need the rlextra package as well as reportlab') sty = dict( name='xlabel-generated', fontName=self.fontName, fontSize=self.fontSize, fillColor=self.fillColor, strokeColor=self.strokeColor, ) if not self.ddfStyle: sty = ParagraphStyle(**sty) elif isinstance(self.ddfStyle,PropertySet): sty = self.ddfStyle.clone(**sty) elif isinstance(self.ddfStyle,type) and issubclass(self.ddfStyle,PropertySet): sty = self.ddfStyle(**sty) else: raise ValueError(f'ddfStyle has invalid type {type(self.ddfStyle)}') self._style = sty self._getBaseLineRatio() if self.useAscentDescent: sty.autoLeading = True sty.leading = self._ascent - self._descent else: sty.leading = self.leading if self.leading else self.fontSize*1.2 self._leading = sty.leading ta = self._getTextAnchor() aW = self.maxWidth or 0x7fffffff if ta!='start': sty.alignment = TA_LEFT obj = ddfKlass(self._text,style=sty) _, objH = obj.wrap(aW,0x7fffffff) aW = self.maxWidth or obj._width_max sty.alignment = _ta2al[ta] self._ddfObj = obj = ddfKlass(self._text,style=sty) _, objH = obj.wrap(aW,0x7fffffff) if not self.width: self._width = self.leftPadding+self.rightPadding self._width += obj._width_max else: self._width = self.width self._computeSizeEnd(objH) def _getTextAnchor(self): '''This can be overridden to allow special effects''' ta = self.textAnchor if ta=='boxauto': ta = _BA2TA[self._getBoxAnchor()] return ta def _rawDraw(self): _text = self._text self._text = _text or '' self.computeSize() self._text = _text g = Group() g.translate(self.x + self.dx, self.y + self.dy) g.rotate(self.angle) ddfKlass = getattr(self,'ddfKlass',None) if ddfKlass: x = self._left else: y = self._top - self._leading*self._baselineRatio textAnchor = self._getTextAnchor() if textAnchor == 'start': x = self._left elif textAnchor == 'middle': x = self._left + self._ewidth*0.5 else: x = self._right # paint box behind text just in case they # fill it if self.boxFillColor or (self.boxStrokeColor and self.boxStrokeWidth): g.add(Rect( self._left-self.leftPadding, self._bottom-self.bottomPadding, self._width, self._height, strokeColor=self.boxStrokeColor, strokeWidth=self.boxStrokeWidth, fillColor=self.boxFillColor) ) if ddfKlass: g1 = Group() g1.translate(x,self._top-self._eheight) g1.add(self.ddf(self._ddfObj)) g.add(g1) else: fillColor, fontName, fontSize = self.fillColor, self.fontName, self.fontSize strokeColor, strokeWidth, leading = self.strokeColor, self.strokeWidth, self._leading svgAttrs=getattr(self,'_svgAttrs',{}) if strokeColor: for line in self._lines: s = _text2Path(line, x, y, fontName, fontSize, textAnchor) s.fillColor = fillColor s.strokeColor = strokeColor s.strokeWidth = strokeWidth g.add(s) y -= leading else: for line in self._lines: s = String(x, y, line, _svgAttrs=svgAttrs) s.textAnchor = textAnchor s.fontName = fontName s.fontSize = fontSize s.fillColor = fillColor g.add(s) y -= leading return g def draw(self): customDrawChanger = getattr(self,'customDrawChanger',None) if customDrawChanger: customDrawChanger(True,self) try: return self._rawDraw() finally: customDrawChanger(False,self) else: return self._rawDraw() class LabelDecorator: _attrMap = AttrMap( x = AttrMapValue(isNumberOrNone,desc=''), y = AttrMapValue(isNumberOrNone,desc=''), dx = AttrMapValue(isNumberOrNone,desc=''), dy = AttrMapValue(isNumberOrNone,desc=''), angle = AttrMapValue(isNumberOrNone,desc=''), boxAnchor = AttrMapValue(isBoxAnchor,desc=''), boxStrokeColor = AttrMapValue(isColorOrNone,desc=''), boxStrokeWidth = AttrMapValue(isNumberOrNone,desc=''), boxFillColor = AttrMapValue(isColorOrNone,desc=''), fillColor = AttrMapValue(isColorOrNone,desc=''), strokeColor = AttrMapValue(isColorOrNone,desc=''), strokeWidth = AttrMapValue(isNumberOrNone),desc='', fontName = AttrMapValue(isNoneOrString,desc=''), fontSize = AttrMapValue(isNumberOrNone,desc=''), leading = AttrMapValue(isNumberOrNone,desc=''), width = AttrMapValue(isNumberOrNone,desc=''), maxWidth = AttrMapValue(isNumberOrNone,desc=''), height = AttrMapValue(isNumberOrNone,desc=''), textAnchor = AttrMapValue(isTextAnchor,desc=''), visible = AttrMapValue(isBoolean,desc="True if the label is to be drawn"), ) def __init__(self): self.textAnchor = 'start' self.boxAnchor = 'w' for a in self._attrMap.keys(): if not hasattr(self,a): setattr(self,a,None) def decorate(self,l,L): chart,g,rowNo,colNo,x,y,width,height,x00,y00,x0,y0 = l._callOutInfo L.setText(chart.categoryAxis.categoryNames[colNo]) g.add(L) def __call__(self,l): L = Label() for a,v in self.__dict__.items(): if v is None: v = getattr(l,a,None) setattr(L,a,v) self.decorate(l,L) isOffsetMode=OneOf('high','low','bar','axis') class LabelOffset(PropHolder): _attrMap = AttrMap( posMode = AttrMapValue(isOffsetMode,desc="Where to base +ve offset"), pos = AttrMapValue(isNumber,desc='Value for positive elements'), negMode = AttrMapValue(isOffsetMode,desc="Where to base -ve offset"), neg = AttrMapValue(isNumber,desc='Value for negative elements'), ) def __init__(self): self.posMode=self.negMode='axis' self.pos = self.neg = 0 def _getValue(self, chart, val): flipXY = chart._flipXY A = chart.categoryAxis jA = A.joinAxis if val>=0: mode = self.posMode delta = self.pos else: mode = self.negMode delta = self.neg if flipXY: v = A._x else: v = A._y if jA: if flipXY: _v = jA._x else: _v = jA._y if mode=='high': v = _v + jA._length elif mode=='low': v = _v elif mode=='bar': v = _v+val return v+delta NoneOrInstanceOfLabelOffset=NoneOr(isInstanceOf(LabelOffset)) class PMVLabel(Label): _attrMap = AttrMap( BASE=Label, ) def __init__(self, **kwds): Label.__init__(self, **kwds) self._pmv = 0 def _getBoxAnchor(self): a = Label._getBoxAnchor(self) if self._pmv<0: a = {'nw':'se','n':'s','ne':'sw','w':'e','c':'c','e':'w','sw':'ne','s':'n','se':'nw'}[a] return a def _getTextAnchor(self): a = Label._getTextAnchor(self) if self._pmv<0: a = {'start':'end', 'middle':'middle', 'end':'start'}[a] return a class BarChartLabel(PMVLabel): """ An extended Label allowing for nudging, lines visibility etc """ _attrMap = AttrMap( BASE=PMVLabel, lineStrokeWidth = AttrMapValue(isNumberOrNone, desc="Non-zero for a drawn line"), lineStrokeColor = AttrMapValue(isColorOrNone, desc="Color for a drawn line"), fixedEnd = AttrMapValue(NoneOrInstanceOfLabelOffset, desc="None or fixed draw ends +/-"), fixedStart = AttrMapValue(NoneOrInstanceOfLabelOffset, desc="None or fixed draw starts +/-"), nudge = AttrMapValue(isNumber, desc="Non-zero sign dependent nudge"), boxTarget = AttrMapValue(OneOf('normal','anti','lo','hi','mid'),desc="one of ('normal','anti','lo','hi','mid')"), ) def __init__(self, **kwds): PMVLabel.__init__(self, **kwds) self.lineStrokeWidth = 0 self.lineStrokeColor = None self.fixedStart = self.fixedEnd = None self.nudge = 0 class NA_Label(BarChartLabel): """ An extended Label allowing for nudging, lines visibility etc """ _attrMap = AttrMap( BASE=BarChartLabel, text = AttrMapValue(isNoneOrString, desc="Text to be used for N/A values"), ) def __init__(self): BarChartLabel.__init__(self) self.text = 'n/a' NoneOrInstanceOfNA_Label=NoneOr(isInstanceOf(NA_Label)) from reportlab.graphics.charts.utils import CustomDrawChanger class RedNegativeChanger(CustomDrawChanger): def __init__(self,fillColor=colors.red): CustomDrawChanger.__init__(self) self.fillColor = fillColor def _changer(self,obj): R = {} if obj._text.startswith('-'): R['fillColor'] = obj.fillColor obj.fillColor = self.fillColor return R class XLabel(Label): '''like label but uses XPreFormatted/Paragraph to draw the _text''' _attrMap = AttrMap(BASE=Label, ) def __init__(self,*args,**kwds): Label.__init__(self,*args,**kwds) self.ddfKlass = kwds.pop('ddfKlass',XPreformatted) self.ddf = kwds.pop('directDrawClass',self.ddf) if False: def __init__(self,*args,**kwds): self._flowableClass = kwds.pop('flowableClass',XPreformatted) ddf = kwds.pop('directDrawClass',DirectDrawFlowable) if ddf is None: raise RuntimeError('DirectDrawFlowable class is not available you need the rlextra package as well as reportlab') self._ddf = ddf Label.__init__(self,*args,**kwds) def computeSize(self): # the thing will draw in its own coordinate system self._lineWidths = [] sty = self._style = ParagraphStyle('xlabel-generated', fontName=self.fontName, fontSize=self.fontSize, fillColor=self.fillColor, strokeColor=self.strokeColor, ) self._getBaseLineRatio() if self.useAscentDescent: sty.autoLeading = True sty.leading = self._ascent - self._descent else: sty.leading = self.leading if self.leading else self.fontSize*1.2 self._leading = sty.leading ta = self._getTextAnchor() aW = self.maxWidth or 0x7fffffff if ta!='start': sty.alignment = TA_LEFT obj = self._flowableClass(self._text,style=sty) _, objH = obj.wrap(aW,0x7fffffff) aW = self.maxWidth or obj._width_max sty.alignment = _ta2al[ta] self._obj = obj = self._flowableClass(self._text,style=sty) _, objH = obj.wrap(aW,0x7fffffff) if not self.width: self._width = self.leftPadding+self.rightPadding self._width += self._obj._width_max else: self._width = self.width self._computeSizeEnd(objH) def _rawDraw(self): _text = self._text self._text = _text or '' self.computeSize() self._text = _text g = Group() g.translate(self.x + self.dx, self.y + self.dy) g.rotate(self.angle) x = self._left # paint box behind text just in case they # fill it if self.boxFillColor or (self.boxStrokeColor and self.boxStrokeWidth): g.add(Rect( self._left-self.leftPadding, self._bottom-self.bottomPadding, self._width, self._height, strokeColor=self.boxStrokeColor, strokeWidth=self.boxStrokeWidth, fillColor=self.boxFillColor) ) g1 = Group() g1.translate(x,self._top-self._eheight) g1.add(self._ddf(self._obj)) g.add(g1) return g ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1691062243.0 reportlab-4.1.0/src/reportlab/graphics/charts/utils.py0000664000175000017500000002644414462707743022511 0ustar00rptlabrptlab#Copyright ReportLab Europe Ltd. 2000-2017 #see license.txt for license details #history https://hg.reportlab.com/hg-public/reportlab/log/tip/src/reportlab/graphics/charts/utils.py __version__='3.3.0' __doc__="Utilities used here and there." from time import mktime, gmtime, strftime from math import log10, pi, floor, sin, cos, hypot import weakref from reportlab.graphics.shapes import transformPoints, inverse, Ellipse, Group, String, numericXShift from reportlab.lib.utils import flatten from reportlab.pdfbase.pdfmetrics import stringWidth ### Dinu's stuff used in some line plots (likely to vansih). def mkTimeTuple(timeString): "Convert a 'dd/mm/yyyy' formatted string to a tuple for use in the time module." L = [0] * 9 dd, mm, yyyy = list(map(int, timeString.split('/'))) L[:3] = [yyyy, mm, dd] return tuple(L) def str2seconds(timeString): "Convert a number of seconds since the epoch into a date string." return mktime(mkTimeTuple(timeString)) def seconds2str(seconds): "Convert a date string into the number of seconds since the epoch." return strftime('%Y-%m-%d', gmtime(seconds)) ### Aaron's rounding function for making nice values on axes. def nextRoundNumber(x): """Return the first 'nice round number' greater than or equal to x Used in selecting apropriate tick mark intervals; we say we want an interval which places ticks at least 10 points apart, work out what that is in chart space, and ask for the nextRoundNumber(). Tries the series 1,2,5,10,20,50,100.., going up or down as needed. """ #guess to nearest order of magnitude if x in (0, 1): return x if x < 0: return -1.0 * nextRoundNumber(-x) else: lg = int(log10(x)) if lg == 0: if x < 1: base = 0.1 else: base = 1.0 elif lg < 0: base = 10.0 ** (lg - 1) else: base = 10.0 ** lg # e.g. base(153) = 100 # base will always be lower than x if base >= x: return base * 1.0 elif (base * 2) >= x: return base * 2.0 elif (base * 5) >= x: return base * 5.0 else: return base * 10.0 _intervals=(.1, .2, .25, .5) _j_max=len(_intervals)-1 def find_interval(lo,hi,I=5): 'determine tick parameters for range [lo, hi] using I intervals' if lo >= hi: if lo==hi: if lo==0: lo = -.1 hi = .1 else: lo = 0.9*lo hi = 1.1*hi else: raise ValueError("lo>hi") x=(hi - lo)/float(I) b= (x>0 and (x<1 or x>10)) and 10**floor(log10(x)) or 1 b = b while 1: a = x/b if a<=_intervals[-1]: break b = b*10 j = 0 while a>_intervals[j]: j = j + 1 while 1: ss = _intervals[j]*b n = lo/ss l = int(n)-(n<0) n = ss*l x = ss*(l+I) a = I*ss if n>0: if a>=hi: n = 0.0 x = a elif hi<0: a = -a if lo>a: n = a x = 0 if hi<=x and n<=lo: break j = j + 1 if j>_j_max: j = 0 b = b*10 return n, x, ss, lo - n + x - hi def find_good_grid(lower,upper,n=(4,5,6,7,8,9), grid=None): if grid: t = divmod(lower,grid)[0] * grid hi, z = divmod(upper,grid) if z>1e-8: hi = hi+1 hi = hi*grid else: try: n[0] except TypeError: n = range(max(1,n-2),max(n+3,2)) w = 1e308 for i in n: z=find_interval(lower,upper,i) if z[3] 3 or power < -3: format = '%+'+repr(w+7)+'.0e' else: if power >= 0: digits = int(power)+w format = '%' + repr(digits)+'.0f' else: digits = w-int(power) format = '%'+repr(digits+2)+'.'+repr(digits)+'f' if percent: format=format+'%%' T = [] n = int(float(hi-t)/grid+0.1)+1 if split: labels = [] for i in range(n): v = t+grid*i T.append(v) labels.append(format % (v+labelVOffset)) return T, labels else: for i in range(n): v = t+grid*i T.append((v, format % (v+labelVOffset))) return T def findNones(data): m = len(data) if None in data: b = 0 while bdepth_slope and _getShaded(fillColor,fillColorShaded,shading) or fillColor zy0 = z0*theta_y zx0 = z0*theta_x tileStrokeWidth = 0.6 if tileWidth is None: D = [(x1,y1)] else: T = ((y1-y0)**2+(x1-x0)**2)**0.5 tileStrokeWidth *= tileWidth if Tself.x1: return 1 if o.s==self.s and o.i in (self.i-1,self.i+1): return a = self.a b = self.b oa = o.a ob = o.b det = ob*a - oa*b if -1e-81 or ou<0 or ou>1: return x = x0 + u*a y = self.y0 + u*b if _ZERO=small: a(seg) S.sort(key=_segKey) I = [] n = len(S) for i in range(0,n-1): s = S[i] for j in range(i+1,n): if s.intersect(S[j],I)==1: break I.sort() return I if __name__=='__main__': from reportlab.graphics.shapes import Drawing from reportlab.lib.colors import lightgrey, pink D = Drawing(300,200) _draw_3d_bar(D, 10, 20, 10, 50, 5, 5, fillColor=lightgrey, strokeColor=pink) _draw_3d_bar(D, 30, 40, 10, 45, 5, 5, fillColor=lightgrey, strokeColor=pink) D.save(formats=['pdf'],outDir='.',fnRoot='_draw_3d_bar') print(find_intersections([[(0,0.5),(1,0.5),(0.5,0),(0.5,1)],[(.2666666667,0.4),(0.1,0.4),(0.1,0.2),(0,0),(1,1)],[(0,1),(0.4,0.1),(1,0.1)]])) print(find_intersections([[(0.1, 0.2), (0.1, 0.4)], [(0, 1), (0.4, 0.1)]])) print(find_intersections([[(0.2, 0.4), (0.1, 0.4)], [(0.1, 0.8), (0.4, 0.1)]])) print(find_intersections([[(0,0),(1,1)],[(0.4,0.1),(1,0.1)]])) print(find_intersections([[(0,0.5),(1,0.5),(0.5,0),(0.5,1)],[(0,0),(1,1)],[(0.1,0.8),(0.4,0.1),(1,0.1)]])) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1704966359.0 reportlab-4.1.0/src/reportlab/graphics/renderPDF.py0000664000175000017500000003546414547734327021702 0ustar00rptlabrptlab#Copyright ReportLab Europe Ltd. 2000-2017 #see license.txt for license details #history https://hg.reportlab.com/hg-public/reportlab/log/tip/src/reportlab/graphics/renderPDF.py # renderPDF - draws Drawings onto a canvas __version__='3.3.0' __doc__="""Render Drawing objects within others PDFs or standalone Usage:: import renderpdf renderpdf.draw(drawing, canvas, x, y) Execute the script to see some test drawings. changed """ from io import BytesIO from reportlab.graphics.shapes import * from reportlab.pdfgen.canvas import Canvas from reportlab.pdfbase.pdfmetrics import stringWidth from reportlab import rl_config from reportlab.graphics.renderbase import Renderer, getStateDelta, renderScaledDrawing, STATE_DEFAULTS # the main entry point for users... def draw(drawing, canvas, x, y, showBoundary=rl_config._unset_): """As it says""" R = _PDFRenderer() R.draw(renderScaledDrawing(drawing), canvas, x, y, showBoundary=showBoundary) class _PDFRenderer(Renderer): """This draws onto a PDF document. It needs to be a class rather than a function, as some PDF-specific state tracking is needed outside of the state info in the SVG model.""" def __init__(self): self._stroke = 0 self._fill = 0 def drawNode(self, node): """This is the recursive method called for each node in the tree""" #print "pdf:drawNode", self #if node.__class__ is Wedge: stop if not (isinstance(node, Path) and node.isClipPath): self._canvas.saveState() #apply state changes deltas = getStateDelta(node) self._tracker.push(deltas) self.applyStateChanges(deltas, {}) #draw the object, or recurse self.drawNodeDispatcher(node) self._tracker.pop() if not (isinstance(node, Path) and node.isClipPath): self._canvas.restoreState() def drawRect(self, rect): if rect.rx == rect.ry == 0: #plain old rectangle self._canvas.rect( rect.x, rect.y, rect.width, rect.height, stroke=self._stroke, fill=self._fill ) else: #cheat and assume ry = rx; better to generalize #pdfgen roundRect function. TODO self._canvas.roundRect( rect.x, rect.y, rect.width, rect.height, rect.rx, fill=self._fill, stroke=self._stroke ) def drawImage(self, image): path = image.path # currently not implemented in other renderers if path and (hasattr(path,'mode') or os.path.exists(image.path)): self._canvas.drawInlineImage( path, image.x, image.y, image.width, image.height, ) def drawLine(self, line): if self._stroke: self._canvas.line(line.x1, line.y1, line.x2, line.y2) def drawCircle(self, circle): self._canvas.circle( circle.cx, circle.cy, circle.r, fill=self._fill, stroke=self._stroke, ) def drawPolyLine(self, polyline): if self._stroke: assert len(polyline.points) >= 2, 'Polyline must have 2 or more points' head, tail = polyline.points[0:2], polyline.points[2:], path = self._canvas.beginPath() path.moveTo(head[0], head[1]) for i in range(0, len(tail), 2): path.lineTo(tail[i], tail[i+1]) self._canvas.drawPath(path) def drawWedge(self, wedge): if wedge.annular: self.drawPath(wedge.asPolygon()) else: centerx, centery, radius, startangledegrees, endangledegrees = \ wedge.centerx, wedge.centery, wedge.radius, wedge.startangledegrees, wedge.endangledegrees yradius, radius1, yradius1 = wedge._xtraRadii() if yradius is None: yradius = radius angle = endangledegrees-startangledegrees path = self._canvas.beginPath() if (radius1==0 or radius1 is None) and (yradius1==0 or yradius1 is None): path.moveTo(centerx, centery) path.arcTo(centerx-radius, centery-yradius, centerx+radius, centery+yradius, startangledegrees, angle) else: path.arc(centerx-radius, centery-yradius, centerx+radius, centery+yradius, startangledegrees, angle) path.arcTo(centerx-radius1, centery-yradius1, centerx+radius1, centery+yradius1, endangledegrees, -angle) path.close() self._canvas.drawPath(path, fill=self._fill, stroke=self._stroke, ) def drawEllipse(self, ellipse): #need to convert to pdfgen's bounding box representation x1 = ellipse.cx - ellipse.rx x2 = ellipse.cx + ellipse.rx y1 = ellipse.cy - ellipse.ry y2 = ellipse.cy + ellipse.ry self._canvas.ellipse(x1,y1,x2,y2,fill=self._fill,stroke=self._stroke) def drawPolygon(self, polygon): assert len(polygon.points) >= 2, 'Polyline must have 2 or more points' head, tail = polygon.points[0:2], polygon.points[2:], path = self._canvas.beginPath() path.moveTo(head[0], head[1]) for i in range(0, len(tail), 2): path.lineTo(tail[i], tail[i+1]) path.close() self._canvas.drawPath( path, stroke=self._stroke, fill=self._fill, ) def drawString(self, stringObj): textRenderMode = getattr(stringObj,'textRenderMode',0) needFill = textRenderMode in (0,2,4,6) needStroke = textRenderMode in (1,2,5,6) if (self._fill and needFill) or (self._stroke and needStroke): S = self._tracker.getState() text_anchor, x, y, text, enc = S['textAnchor'], stringObj.x,stringObj.y,stringObj.text, stringObj.encoding if not text_anchor in ['start','inherited']: font, font_size = S['fontName'], S['fontSize'] textLen = stringWidth(text, font, font_size, enc) if text_anchor=='end': x -= textLen elif text_anchor=='middle': x -= textLen*0.5 elif text_anchor=='numeric': x -= numericXShift(text_anchor,text,textLen,font,font_size,enc) else: raise ValueError('bad value for textAnchor '+str(text_anchor)) self._canvas.drawString(x, y, text, mode=textRenderMode or None) def drawPath(self, path): from reportlab.graphics.shapes import _renderPath pdfPath = self._canvas.beginPath() drawFuncs = (pdfPath.moveTo, pdfPath.lineTo, pdfPath.curveTo, pdfPath.close) autoclose = getattr(path,'autoclose','') fill = self._fill stroke = self._stroke isClosed = _renderPath(path, drawFuncs, forceClose=fill and autoclose=='pdf') dP = self._canvas.drawPath cP = self._canvas.clipPath if path.isClipPath else dP fillMode = getattr(path,'fillMode',None) if autoclose=='svg': if fill and stroke and not isClosed: cP(pdfPath, fill=fill, stroke=0) dP(pdfPath, stroke=stroke, fill=0, fillMode=fillMode) else: cP(pdfPath, fill=fill, stroke=stroke, fillMode=fillMode) elif autoclose=='pdf': cP(pdfPath, fill=fill, stroke=stroke, fillMode=fillMode) else: #our old broken default if not isClosed: fill = 0 cP(pdfPath, fill=fill, stroke=stroke, fillMode=fillMode) def setStrokeColor(self,c): self._canvas.setStrokeColor(c) def setFillColor(self,c): self._canvas.setFillColor(c) def applyStateChanges(self, delta, newState): """This takes a set of states, and outputs the PDF operators needed to set those properties""" for key, value in (sorted(delta.items()) if rl_config.invariant else delta.items()): if key == 'transform': self._canvas.transform(value[0], value[1], value[2], value[3], value[4], value[5]) elif key == 'strokeColor': #this has different semantics in PDF to SVG; #we always have a color, and either do or do #not apply it; in SVG one can have a 'None' color if value is None: self._stroke = 0 else: self._stroke = 1 self.setStrokeColor(value) elif key == 'strokeWidth': self._canvas.setLineWidth(value) elif key == 'strokeLineCap': #0,1,2 self._canvas.setLineCap(value) elif key == 'strokeLineJoin': self._canvas.setLineJoin(value) # elif key == 'stroke_dasharray': # self._canvas.setDash(array=value) elif key == 'strokeDashArray': if value: if isinstance(value,(list,tuple)) and len(value)==2 and isinstance(value[1],(tuple,list)): phase = value[0] value = value[1] else: phase = 0 self._canvas.setDash(value,phase) else: self._canvas.setDash() elif key == 'fillColor': #this has different semantics in PDF to SVG; #we always have a color, and either do or do #not apply it; in SVG one can have a 'None' color if value is None: self._fill = 0 else: self._fill = 1 self.setFillColor(value) elif key in ['fontSize', 'fontName']: # both need setting together in PDF # one or both might be in the deltas, # so need to get whichever is missing fontname = delta.get('fontName', self._canvas._fontname) fontsize = delta.get('fontSize', self._canvas._fontsize) self._canvas.setFont(fontname, fontsize) elif key=='fillOpacity': if value is not None: self._canvas.setFillAlpha(value) elif key=='strokeOpacity': if value is not None: self._canvas.setStrokeAlpha(value) elif key=='fillOverprint': self._canvas.setFillOverprint(value) elif key=='strokeOverprint': self._canvas.setStrokeOverprint(value) elif key=='overprintMask': self._canvas.setOverprintMask(value) elif key=='fillMode': self._canvas._fillMode = value from reportlab.platypus import Flowable class GraphicsFlowable(Flowable): """Flowable wrapper around a Pingo drawing""" def __init__(self, drawing): self.drawing = drawing self.width = self.drawing.width self.height = self.drawing.height def draw(self): draw(self.drawing, self.canv, 0, 0) def drawToFile(d, fn, msg="", showBoundary=rl_config._unset_, autoSize=1, canvasKwds={}): """Makes a one-page PDF with just the drawing. If autoSize=1, the PDF will be the same size as the drawing; if 0, it will place the drawing on an A4 page with a title above it - possibly overflowing if too big.""" d = renderScaledDrawing(d) for x in ('Name','Size'): a = 'initialFont'+x canvasKwds[a] = getattr(d,a,canvasKwds.pop(a,STATE_DEFAULTS['font'+x])) c = Canvas(fn,**canvasKwds) if msg: c.setFont(rl_config.defaultGraphicsFontName, 36) c.drawString(80, 750, msg) c.setTitle(msg) if autoSize: c.setPageSize((d.width, d.height)) draw(d, c, 0, 0, showBoundary=showBoundary) else: #show with a title c.setFont(rl_config.defaultGraphicsFontName, 12) y = 740 i = 1 y = y - d.height draw(d, c, 80, y, showBoundary=showBoundary) c.showPage() c.save() if sys.platform=='mac' and not hasattr(fn, "write"): try: import macfs, macostools macfs.FSSpec(fn).SetCreatorType("CARO", "PDF ") macostools.touched(fn) except: pass def drawToString(d, msg="", showBoundary=rl_config._unset_,autoSize=1,canvasKwds={}): "Returns a PDF as a string in memory, without touching the disk" s = BytesIO() drawToFile(d, s, msg=msg, showBoundary=showBoundary,autoSize=autoSize, canvasKwds=canvasKwds) return s.getvalue() ######################################################### # # test code. First, define a bunch of drawings. # Routine to draw them comes at the end. # ######################################################### def test(outDir='pdfout',shout=False): from reportlab.graphics.shapes import _baseGFontName, _baseGFontNameBI from reportlab.rl_config import verbose import os if not os.path.isdir(outDir): os.mkdir(outDir) fn = os.path.join(outDir,'renderPDF.pdf') c = Canvas(fn) c.setFont(_baseGFontName, 36) c.drawString(80, 750, 'Graphics Test') # print all drawings and their doc strings from the test # file #grab all drawings from the test module from reportlab.graphics import testshapes drawings = [] for funcname in dir(testshapes): if funcname[0:10] == 'getDrawing': func = getattr(testshapes,funcname) drawing = func() #execute it docstring = getattr(func,'__doc__','') drawings.append((drawing, docstring)) #print in a loop, with their doc strings c.setFont(_baseGFontName, 12) y = 740 i = 1 for (drawing, docstring) in drawings: assert (docstring is not None), "Drawing %d has no docstring!" % i if y < 300: #allows 5-6 lines of text c.showPage() y = 740 # draw a title y = y - 30 c.setFont(_baseGFontNameBI,12) c.drawString(80, y, 'Drawing %d' % i) c.setFont(_baseGFontName,12) y = y - 14 textObj = c.beginText(80, y) textObj.textLines(docstring) c.drawText(textObj) y = textObj.getY() y = y - drawing.height draw(drawing, c, 80, y) i = i + 1 if y!=740: c.showPage() c.save() if shout or verbose>2: print('saved %s' % ascii(fn)) if __name__=='__main__': test(shout=True) import sys if len(sys.argv)>1: outdir = sys.argv[1] else: outdir = 'pdfout' test(outdir,shout=True) #testFlowable() ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1691062243.0 reportlab-4.1.0/src/reportlab/graphics/renderPM.py0000664000175000017500000007230614462707743021577 0ustar00rptlabrptlab#Copyright ReportLab Europe Ltd. 2000-2017 #see license.txt for license details #history www.reportlab.co.uk/rl-cgi/viewcvs.cgi/rlextra/graphics/Csrc/renderPM/renderP.py __version__='3.3.0' __doc__="""Render drawing objects in common bitmap formats Usage:: from reportlab.graphics import renderPM renderPM.drawToFile(drawing,filename,fmt='GIF',configPIL={....}) Other functions let you create a PM drawing as string or into a PM buffer. Execute the script to see some test drawings.""" from reportlab.graphics.shapes import * from reportlab.graphics.renderbase import getStateDelta, renderScaledDrawing from reportlab.pdfbase.pdfmetrics import getFont, unicode2T1 from reportlab.lib.utils import isUnicode from reportlab import rl_config from .utils import setFont as _setFont, RenderPMError import os, sys from io import BytesIO, StringIO from math import sin, cos, pi, ceil def _getPMBackend(backend=None): if not backend: backend = rl_config.renderPMBackend if backend=='_renderPM': try: import _rl_renderPM as M except ImportError as errMsg: try: import rlPyCairo as M except ImportError: raise RenderPMError("""Cannot import desired renderPM backend, {backend}. No module named _rl_renderPM it may be badly or not installed! You may need to install development tools or seek advice at the users list see https://pairlist2.pair.net/mailman/listinfo/reportlab-users""") elif 'cairo' in backend.lower(): try: import rlPyCairo as M except ImportError as errMsg: try: import _rl_renderPM as M except ImportError: raise RenderPMError(f"""cannot import desired renderPM backend {backend} Seek advice at the users list see https://pairlist2.pair.net/mailman/listinfo/reportlab-users""") else: raise RenderPMError(f'Invalid renderPM backend, {backend}') return M try: _pmBackend = _getPMBackend(rl_config.renderPMBackend) except RenderPMError: _pmBackend=None def _getImage(): try: from PIL import Image except ImportError: import Image return Image def Color2Hex(c): #assert isinstance(colorobj, colors.Color) #these checks don't work well RGB if c: return ((0xFF&int(255*c.red)) << 16) | ((0xFF&int(255*c.green)) << 8) | (0xFF&int(255*c.blue)) return c # the main entry point for users... def draw(drawing, canvas, x, y, showBoundary=rl_config._unset_): """As it says""" R = _PMRenderer() R.draw(renderScaledDrawing(drawing), canvas, x, y, showBoundary=showBoundary) from reportlab.graphics.renderbase import Renderer class _PMRenderer(Renderer): """This draws onto a pix map image. It needs to be a class rather than a function, as some image-specific state tracking is needed outside of the state info in the SVG model.""" def pop(self): self._tracker.pop() self.applyState() def push(self,node): deltas = getStateDelta(node) self._tracker.push(deltas) self.applyState() def applyState(self): s = self._tracker.getState() self._canvas.ctm = s['ctm'] self._canvas.strokeWidth = s['strokeWidth'] alpha = s['strokeOpacity'] if alpha is not None: self._canvas.strokeOpacity = alpha self._canvas.setStrokeColor(s['strokeColor']) self._canvas.lineCap = s['strokeLineCap'] self._canvas.lineJoin = s['strokeLineJoin'] self._canvas.fillMode = s['fillMode'] da = s['strokeDashArray'] if not da: da = None else: if not isinstance(da,(list,tuple)): da = da, if len(da)!=2 or not isinstance(da[1],(list,tuple)): da = 0, da #assume phase of 0 self._canvas.dashArray = da alpha = s['fillOpacity'] if alpha is not None: self._canvas.fillOpacity = alpha self._canvas.setFillColor(s['fillColor']) self._canvas.setFont(s['fontName'], s['fontSize']) def initState(self,x,y): deltas = self._tracker._combined[-1] deltas['transform'] = deltas['ctm'] = self._canvas._baseCTM[0:4]+(x,y) self._tracker.push(deltas) self.applyState() def drawNode(self, node): """This is the recursive method called for each node in the tree""" #apply state changes self.push(node) #draw the object, or recurse self.drawNodeDispatcher(node) # restore the state self.pop() def drawRect(self, rect): c = self._canvas if rect.rx == rect.ry == 0: #plain old rectangle, draw clockwise (x-axis to y-axis) direction c.rect(rect.x,rect.y, rect.width, rect.height) else: c.roundRect(rect.x,rect.y, rect.width, rect.height, rect.rx, rect.ry) def drawLine(self, line): self._canvas.line(line.x1,line.y1,line.x2,line.y2) def drawImage(self, image): path = image.path if isinstance(path,str): if not (path and os.path.isfile(path)): return im = _getImage().open(path).convert('RGB') elif hasattr(path,'convert'): im = path.convert('RGB') else: return srcW, srcH = im.size dstW, dstH = image.width, image.height if dstW is None: dstW = srcW if dstH is None: dstH = srcH self._canvas._aapixbuf( image.x, image.y, dstW, dstH, (im if self._canvas._backend=='rlPyCairo' #rlPyCairo has a from_pil method else (im.tobytes if hasattr(im,'tobytes') else im.tostring)()), srcW, srcH, 3, ) def drawCircle(self, circle): c = self._canvas c.circle(circle.cx,circle.cy, circle.r) c.fillstrokepath() def drawPolyLine(self, polyline, _doClose=0): P = polyline.points assert len(P) >= 2, 'Polyline must have 1 or more points' c = self._canvas c.pathBegin() c.moveTo(P[0], P[1]) for i in range(2, len(P), 2): c.lineTo(P[i], P[i+1]) if _doClose: c.pathClose() c.pathFill() c.pathStroke() def drawEllipse(self, ellipse): c=self._canvas c.ellipse(ellipse.cx, ellipse.cy, ellipse.rx,ellipse.ry) c.fillstrokepath() def drawPolygon(self, polygon): self.drawPolyLine(polygon,_doClose=1) def drawString(self, stringObj): canv = self._canvas fill = canv.fillColor textRenderMode = getattr(stringObj,'textRenderMode',0) if fill is not None or textRenderMode: S = self._tracker.getState() text_anchor = S['textAnchor'] fontName = S['fontName'] fontSize = S['fontSize'] text = stringObj.text x = stringObj.x y = stringObj.y if not text_anchor in ['start','inherited']: textLen = stringWidth(text, fontName,fontSize) if text_anchor=='end': x -= textLen elif text_anchor=='middle': x -= textLen/2 elif text_anchor=='numeric': x -= numericXShift(text_anchor,text,textLen,fontName,fontSize,stringObj.encoding) else: raise ValueError('bad value for textAnchor '+str(text_anchor)) oldTextRenderMode = canv.textRenderMode canv.textRenderMode = textRenderMode try: canv.drawString(x,y,text,_fontInfo=(fontName,fontSize)) finally: canv.textRenderMode = oldTextRenderMode def drawPath(self, path): c = self._canvas if path is EmptyClipPath: del c._clipPaths[-1] if c._clipPaths: P = c._clipPaths[-1] icp = P.isClipPath P.isClipPath = 1 self.drawPath(P) P.isClipPath = icp else: c.clipPathClear() return from reportlab.graphics.shapes import _renderPath drawFuncs = (c.moveTo, c.lineTo, c.curveTo, c.pathClose) autoclose = getattr(path,'autoclose','') def rP(forceClose=False): c.pathBegin() return _renderPath(path, drawFuncs, forceClose=forceClose) if path.isClipPath: rP() c.clipPathSet() c._clipPaths.append(path) fill = c.fillColor is not None stroke = c.strokeColor is not None fillMode = getattr(path,'fillMode',-1) if autoclose=='svg': if fill and stroke: rP(forceClose=True) c.pathFill(fillMode) rP() c.pathStroke() elif fill: rP(forceClose=True) c.pathFill(fillMode) elif stroke: rP() c.pathStroke() elif autoclose=='pdf': rP(forceClose=True) if fill: c.pathFill(fillMode) if stroke: c.pathStroke() else: if rP(): c.pathFill(fillMode) c.pathStroke() def _convert2pilp(im): Image = _getImage() return im.convert("P", dither=Image.NONE, palette=Image.ADAPTIVE) def _convert2pilL(im): return im.convert("L") def _convert2pil1(im): return im.convert("1") def _saveAsPICT(im,fn,fmt,transparent=None): im = _convert2pilp(im) cols, rows = im.size s = _pmBackend.pil2pict(cols,rows,(im.tobytes if hasattr(im,'tobytes') else im.tostring)(),im.im.getpalette()) if not hasattr(fn,'write'): with open(os.path.splitext(fn)[0]+'.'+fmt.lower(),'wb') as f: f.write(s) if os.name=='mac': from reportlab.lib.utils import markfilename markfilename(fn,ext='PICT') else: fn.write(s) BEZIER_ARC_MAGIC = 0.5522847498 #constant for drawing circular arcs w/ Beziers class PMCanvas: def __init__(self,w,h,dpi=72,bg=0xffffff,configPIL=None,backend=None, backendFmt='RGB'): '''configPIL dict is passed to image save method''' scale = dpi/72.0 w = int(w*scale+0.5) h = int(h*scale+0.5) self.__dict__['_gs'] = self._getGState(w,h,bg,backend) self.__dict__['_bg'] = bg self.__dict__['_baseCTM'] = (scale,0,0,scale,0,0) self.__dict__['_clipPaths'] = [] self.__dict__['configPIL'] = configPIL self.__dict__['_dpi'] = dpi #the _rl_renderPM.gstate object doesn't support hasattr so we use this as a proxy test for 'isbuiltin' self.__dict__['_backend'] = '_renderPM' if type(self._gs._aapixbuf)==type(pow) else 'rlPyCairo' self.__dict__['_backendfmt'] = backendFmt self.ctm = self._baseCTM @staticmethod def _getGState(w, h, bg, backend=None, fmt='RGB24'): mod = _getPMBackend(backend) if backend is None: backend = rl_config.renderPMBackend if backend=='_renderPM': try: return mod.gstate(w,h,bg=bg) except TypeError: try: return mod.GState(w,h,bg,fmt=fmt) except: pass elif 'cairo' in backend.lower(): try: return mod.GState(w,h,bg,fmt=fmt) except AttributeError: return mod.gstate(w,h,bg=bg) raise RuntimeError(f'Cannot obtain PM graphics state using backend {backend!r}') def _drawTimeResize(self,w,h,bg=None): if bg is None: bg = self._bg self._drawing.width, self._drawing.height = w, h A = {'ctm':None, 'strokeWidth':None, 'strokeColor':None, 'lineCap':None, 'lineJoin':None, 'dashArray':None, 'fillColor':None} gs = self._gs fN,fS = gs.fontName, gs.fontSize for k in A.keys(): A[k] = getattr(gs,k) del gs, self._gs gs = self.__dict__['_gs'] = _pmBackend.gstate(w,h,bg=bg) for k in A.keys(): setattr(self,k,A[k]) gs.setFont(fN,fS) def toPIL(self): im = _getImage().new('RGB', size=(self._gs.width, self._gs.height)) im.frombytes(self._gs.pixBuf) return im def saveToFile(self,fn,fmt=None): im = self.toPIL() if fmt is None: if not isinstance(fn,str): raise ValueError("Invalid value '%s' for fn when fmt is None" % ascii(fn)) fmt = os.path.splitext(fn)[1] if fmt.startswith('.'): fmt = fmt[1:] configPIL = self.configPIL or {} configPIL.setdefault('preConvertCB',None) preConvertCB=configPIL.pop('preConvertCB') if preConvertCB: im = preConvertCB(im) fmt = fmt.upper() if fmt in ('GIF',): im = _convert2pilp(im) elif fmt in ('TIFF','TIFFP','TIFFL','TIF','TIFF1'): if fmt.endswith('P'): im = _convert2pilp(im) elif fmt.endswith('L'): im = _convert2pilL(im) elif fmt.endswith('1'): im = _convert2pil1(im) fmt='TIFF' elif fmt in ('PCT','PICT'): return _saveAsPICT(im,fn,fmt,transparent=configPIL.get('transparent',None)) elif fmt in ('PNG','BMP', 'PPM'): pass elif fmt in ('JPG','JPEG'): fmt = 'JPEG' else: raise RenderPMError("Unknown image kind %s" % fmt) if fmt=='TIFF': tc = configPIL.get('transparent',None) if tc: from PIL import ImageChops, Image T = 768*[0] for o, c in zip((0,256,512), tc.bitmap_rgb()): T[o+c] = 255 #if isinstance(fn,str): ImageChops.invert(im.point(T).convert('L').point(255*[0]+[255])).save(fn+'_mask.gif','GIF') im = Image.merge('RGBA', im.split()+(ImageChops.invert(im.point(T).convert('L').point(255*[0]+[255])),)) #if isinstance(fn,str): im.save(fn+'_masked.gif','GIF') for a,d in ('resolution',self._dpi),('resolution unit','inch'): configPIL[a] = configPIL.get(a,d) configPIL.setdefault('chops_invert',0) if configPIL.pop('chops_invert'): from PIL import ImageChops im = ImageChops.invert(im) configPIL.setdefault('preSaveCB',None) preSaveCB=configPIL.pop('preSaveCB') if preSaveCB: im = preSaveCB(im) im.save(fn,fmt,**configPIL) if not hasattr(fn,'write') and os.name=='mac': from reportlab.lib.utils import markfilename markfilename(fn,ext=fmt) def saveToString(self,fmt='GIF'): s = BytesIO() self.saveToFile(s,fmt=fmt) return s.getvalue() def _saveToBMP(self,f): ''' Niki Spahiev, , asserts that this is a respectable way to get BMP without PIL f is a file like object to which the BMP is written ''' import struct gs = self._gs pix, width, height = gs.pixBuf, gs.width, gs.height f.write(struct.pack('=2sLLLLLLhh24x','BM',len(pix)+54,0,54,40,width,height,1,24)) rowb = width * 3 for o in range(len(pix),0,-rowb): f.write(pix[o-rowb:o]) f.write( '\0' * 14 ) def setFont(self,fontName,fontSize,leading=None): _setFont(self._gs,fontName,fontSize) def __setattr__(self,name,value): setattr(self._gs,name,value) def __getattr__(self,name): return getattr(self._gs,name) def fillstrokepath(self,stroke=1,fill=1): if fill: self.pathFill() if stroke: self.pathStroke() def _bezierArcSegmentCCW(self, cx,cy, rx,ry, theta0, theta1): """compute the control points for a bezier arc with theta1-theta0 <= 90. Points are computed for an arc with angle theta increasing in the counter-clockwise (CCW) direction. returns a tuple with starting point and 3 control points of a cubic bezier curve for the curvto opertator""" # Requires theta1 - theta0 <= 90 for a good approximation assert abs(theta1 - theta0) <= 90 cos0 = cos(pi*theta0/180.0) sin0 = sin(pi*theta0/180.0) x0 = cx + rx*cos0 y0 = cy + ry*sin0 cos1 = cos(pi*theta1/180.0) sin1 = sin(pi*theta1/180.0) x3 = cx + rx*cos1 y3 = cy + ry*sin1 dx1 = -rx * sin0 dy1 = ry * cos0 #from pdfgeom halfAng = pi*(theta1-theta0)/(2.0 * 180.0) k = abs(4.0 / 3.0 * (1.0 - cos(halfAng) ) /(sin(halfAng)) ) x1 = x0 + dx1 * k y1 = y0 + dy1 * k dx2 = -rx * sin1 dy2 = ry * cos1 x2 = x3 - dx2 * k y2 = y3 - dy2 * k return ((x0,y0), ((x1,y1), (x2,y2), (x3,y3)) ) def bezierArcCCW(self, cx,cy, rx,ry, theta0, theta1): """return a set of control points for Bezier approximation to an arc with angle increasing counter clockwise. No requirement on (theta1-theta0) <= 90 However, it must be true that theta1-theta0 > 0.""" # I believe this is also clockwise # pretty much just like Robert Kern's pdfgeom.BezierArc angularExtent = theta1 - theta0 # break down the arc into fragments of <=90 degrees if abs(angularExtent) <= 90.0: # we just need one fragment angleList = [(theta0,theta1)] else: Nfrag = int( ceil( abs(angularExtent)/90.) ) fragAngle = float(angularExtent)/ Nfrag # this could be negative angleList = [] for ii in range(Nfrag): a = theta0 + ii * fragAngle b = a + fragAngle # hmm.. is I wonder if this is precise enought angleList.append((a,b)) ctrlpts = [] for (a,b) in angleList: if not ctrlpts: # first time [(x0,y0), pts] = self._bezierArcSegmentCCW(cx,cy, rx,ry, a,b) ctrlpts.append(pts) else: [(tmpx,tmpy), pts] = self._bezierArcSegmentCCW(cx,cy, rx,ry, a,b) ctrlpts.append(pts) return ((x0,y0), ctrlpts) def addEllipsoidalArc(self, cx,cy, rx, ry, ang1, ang2): """adds an ellisesoidal arc segment to a path, with an ellipse centered on cx,cy and with radii (major & minor axes) rx and ry. The arc is drawn in the CCW direction. Requires: (ang2-ang1) > 0""" ((x0,y0), ctrlpts) = self.bezierArcCCW(cx,cy, rx,ry,ang1,ang2) self.lineTo(x0,y0) for ((x1,y1), (x2,y2),(x3,y3)) in ctrlpts: self.curveTo(x1,y1,x2,y2,x3,y3) def drawCentredString(self, x, y, text, text_anchor='middle'): self.drawString(x,y,text, text_anchor=text_anchor) def drawRightString(self, text, x, y): self.drawString(text,x,y,text_anchor='end') def drawString(self, x, y, text, _fontInfo=None, text_anchor='left'): gs = self._gs gs_fontSize = gs.fontSize gs_fontName = gs.fontName if _fontInfo and _fontInfo!=(gs_fontSize,gs_fontName): fontName, fontSize = _fontInfo _setFont(gs,fontName,fontSize) else: fontName = gs_fontName fontSize = gs_fontSize try: if text_anchor in ('end','middle', 'end'): textLen = stringWidth(text, fontName,fontSize) if text_anchor=='end': x -= textLen elif text_anchor=='middle': x -= textLen/2. elif text_anchor=='numeric': x -= numericXShift(text_anchor,text,textLen,fontName,fontSize) if self._backend=='rlPyCairo': gs.drawString(x,y,text) else: font = getFont(fontName) if font._dynamicFont: gs.drawString(x,y,text) else: fc = font if not isUnicode(text): try: text = text.decode('utf8') except UnicodeDecodeError as e: i,j = e.args[2:4] raise UnicodeDecodeError(*(e.args[:4]+('%s\n%s-->%s<--%s' % (e.args[4],text[i-10:i],text[i:j],text[j:j+10]),))) FT = unicode2T1(text,[font]+font.substitutionFonts) n = len(FT) nm1 = n-1 for i in range(n): f, t = FT[i] if f!=fc: _setFont(gs,f.fontName,fontSize) fc = f gs.drawString(x,y,t) if i!=nm1: x += f.stringWidth(t.decode(f.encName),fontSize) finally: gs.setFont(gs_fontName,gs_fontSize) def line(self,x1,y1,x2,y2): if self.strokeColor is not None: self.pathBegin() self.moveTo(x1,y1) self.lineTo(x2,y2) self.pathStroke() def rect(self,x,y,width,height,stroke=1,fill=1): self.pathBegin() self.moveTo(x, y) self.lineTo(x+width, y) self.lineTo(x+width, y + height) self.lineTo(x, y + height) self.pathClose() self.fillstrokepath(stroke=stroke,fill=fill) def roundRect(self, x, y, width, height, rx,ry): """rect(self, x, y, width, height, rx,ry): Draw a rectangle if rx or rx and ry are specified the corners are rounded with ellipsoidal arcs determined by rx and ry (drawn in the counter-clockwise direction)""" if rx==0: rx = ry if ry==0: ry = rx x2 = x + width y2 = y + height self.pathBegin() self.moveTo(x+rx,y) self.addEllipsoidalArc(x2-rx, y+ry, rx, ry, 270, 360 ) self.addEllipsoidalArc(x2-rx, y2-ry, rx, ry, 0, 90) self.addEllipsoidalArc(x+rx, y2-ry, rx, ry, 90, 180) self.addEllipsoidalArc(x+rx, y+ry, rx, ry, 180, 270) self.pathClose() self.fillstrokepath() def circle(self, cx, cy, r): "add closed path circle with center cx,cy and axes r: counter-clockwise orientation" self.ellipse(cx,cy,r,r) def ellipse(self, cx,cy,rx,ry): """add closed path ellipse with center cx,cy and axes rx,ry: counter-clockwise orientation (remember y-axis increases downward) """ self.pathBegin() # first segment x0 = cx + rx # (x0,y0) start pt y0 = cy x3 = cx # (x3,y3) end pt of arc y3 = cy-ry x1 = cx+rx y1 = cy-ry*BEZIER_ARC_MAGIC x2 = x3 + rx*BEZIER_ARC_MAGIC y2 = y3 self.moveTo(x0, y0) self.curveTo(x1,y1,x2,y2,x3,y3) # next segment x0 = x3 y0 = y3 x3 = cx-rx y3 = cy x1 = cx-rx*BEZIER_ARC_MAGIC y1 = cy-ry x2 = x3 y2 = cy- ry*BEZIER_ARC_MAGIC self.curveTo(x1,y1,x2,y2,x3,y3) # next segment x0 = x3 y0 = y3 x3 = cx y3 = cy+ry x1 = cx-rx y1 = cy+ry*BEZIER_ARC_MAGIC x2 = cx -rx*BEZIER_ARC_MAGIC y2 = cy+ry self.curveTo(x1,y1,x2,y2,x3,y3) #last segment x0 = x3 y0 = y3 x3 = cx+rx y3 = cy x1 = cx+rx*BEZIER_ARC_MAGIC y1 = cy+ry x2 = cx+rx y2 = cy+ry*BEZIER_ARC_MAGIC self.curveTo(x1,y1,x2,y2,x3,y3) self.pathClose() def saveState(self): '''do nothing for compatibility''' pass def setFillColor(self,aColor): self.fillColor = Color2Hex(aColor) alpha = getattr(aColor,'alpha',None) if alpha is not None: self.fillOpacity = alpha def setStrokeColor(self,aColor): self.strokeColor = Color2Hex(aColor) alpha = getattr(aColor,'alpha',None) if alpha is not None: self.strokeOpacity = alpha restoreState = saveState # compatibility routines def setLineCap(self,cap): self.lineCap = cap def setLineJoin(self,join): self.lineJoin = join def setLineWidth(self,width): self.strokeWidth = width def drawToPMCanvas(d, dpi=72, bg=0xffffff, configPIL=None, showBoundary=rl_config._unset_,backend=rl_config.renderPMBackend): d = renderScaledDrawing(d) c = PMCanvas(d.width, d.height, dpi=dpi, bg=bg, configPIL=configPIL, backend=backend) draw(d, c, 0, 0, showBoundary=showBoundary) return c def drawToPIL(d, dpi=72, bg=0xffffff, configPIL=None, showBoundary=rl_config._unset_,backend=rl_config.renderPMBackend): return drawToPMCanvas(d, dpi=dpi, bg=bg, configPIL=configPIL, showBoundary=showBoundary, backend=backend).toPIL() def drawToPILP(d, dpi=72, bg=0xffffff, configPIL=None, showBoundary=rl_config._unset_,backend=rl_config.renderPMBackend): Image = _getImage() im = drawToPIL(d, dpi=dpi, bg=bg, configPIL=configPIL, showBoundary=showBoundary,backend=backend) return im.convert("P", dither=Image.NONE, palette=Image.ADAPTIVE) def drawToFile(d,fn,fmt='GIF', dpi=72, bg=0xffffff, configPIL=None, showBoundary=rl_config._unset_,backend=rl_config.renderPMBackend): '''create a pixmap and draw drawing, d to it then save as a file configPIL dict is passed to image save method''' c = drawToPMCanvas(d, dpi=dpi, bg=bg, configPIL=configPIL, showBoundary=showBoundary,backend=backend) c.saveToFile(fn,fmt) def drawToString(d,fmt='GIF', dpi=72, bg=0xffffff, configPIL=None, showBoundary=rl_config._unset_,backend=rl_config.renderPMBackend): s = BytesIO() drawToFile(d,s,fmt=fmt, dpi=dpi, bg=bg, configPIL=configPIL,backend=backend) return s.getvalue() save = drawToFile def test(outDir='pmout', shout=False): def ext(x): if x=='tiff': x='tif' return x #grab all drawings from the test module and write out. #make a page of links in HTML to assist viewing. import os from reportlab.graphics import testshapes from reportlab.rl_config import verbose getAllTestDrawings = testshapes.getAllTestDrawings drawings = [] if not os.path.isdir(outDir): os.mkdir(outDir) htmlTop = """renderPM output results

renderPM results of output

""" htmlBottom = """ """ html = [htmlTop] names = {} argv = sys.argv[1:] E = [a for a in argv if a.startswith('--ext=')] if not E: E = ['gif','tiff', 'png', 'jpg', 'pct', 'py', 'svg'] else: for a in E: argv.remove(a) E = (','.join([a[6:] for a in E])).split(',') errs = [] import traceback from xml.sax.saxutils import escape def handleError(name,fmt): msg = 'Problem drawing %s fmt=%s file'%(name,fmt) if shout or verbose>2: print(msg) errs.append('

%s

' % msg) buf = StringIO() traceback.print_exc(file=buf) errs.append('
%s
' % escape(buf.getvalue())) #print in a loop, with their doc strings for (drawing, docstring, name) in getAllTestDrawings(doTTF=hasattr(_pmBackend,'ft_get_face')): i = names[name] = names.setdefault(name,0)+1 if i>1: name += '.%02d' % (i-1) if argv and name not in argv: continue fnRoot = name w = int(drawing.width) h = int(drawing.height) html.append('

Drawing %s

\n
%s
' % (name, docstring)) for k in E: if k in ['gif','png','jpg','pct']: html.append('

%s format

\n' % k.upper()) try: filename = '%s.%s' % (fnRoot, ext(k)) fullpath = os.path.join(outDir, filename) if os.path.isfile(fullpath): os.remove(fullpath) if k=='pct': from reportlab.lib.colors import white drawToFile(drawing,fullpath,fmt=k,configPIL={'transparent':white}) elif k in ['py','svg']: drawing.save(formats=['py','svg'],outDir=outDir,fnRoot=fnRoot) else: drawToFile(drawing,fullpath,fmt=k) if k in ['gif','png','jpg']: html.append('
\n' % filename) elif k=='py': html.append('python source
\n' % filename) elif k=='svg': html.append('SVG
\n' % filename) if shout or verbose>2: print('wrote %s'%ascii(fullpath)) except AttributeError: handleError(name,k) if os.environ.get('RL_NOEPSPREVIEW','0')=='1': drawing.__dict__['preview'] = 0 for k in ('eps', 'pdf'): try: drawing.save(formats=[k],outDir=outDir,fnRoot=fnRoot) except: handleError(name,k) if errs: html[0] = html[0].replace('',' (errors)') html.append('') html.extend(errs) html.append(htmlBottom) htmlFileName = os.path.join(outDir, 'pm-index.html') with open(htmlFileName, 'w') as f: f.writelines(html) if sys.platform=='mac': from reportlab.lib.utils import markfilename markfilename(htmlFileName,ext='HTML') if shout or verbose>2: print('wrote %s' % htmlFileName) if __name__=='__main__': test(shout=True) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1691062243.0 reportlab-4.1.0/src/reportlab/graphics/renderPS.py0000664000175000017500000011206114462707743021576 0ustar00rptlabrptlab#Copyright ReportLab Europe Ltd. 2000-2017 #see license.txt for license details #history https://hg.reportlab.com/hg-public/reportlab/log/tip/src/reportlab/graphics/renderPS.py __version__='3.3.0' __doc__="""Render drawing objects in Postscript""" import math from io import BytesIO, StringIO from reportlab.pdfbase.pdfmetrics import getFont, stringWidth, unicode2T1 # for font info from reportlab.lib.utils import asBytes, char2int, rawBytes, asNative, isUnicode from reportlab.lib.rl_accel import fp_str from reportlab.graphics.renderbase import Renderer, getStateDelta, renderScaledDrawing from reportlab.graphics.shapes import STATE_DEFAULTS from reportlab import rl_config from reportlab.pdfgen.canvas import FILL_EVEN_ODD _ESCAPEDICT={} for c in range(256): if c<32 or c>=127: _ESCAPEDICT[c]= '\\%03o' % c elif c in (ord('\\'),ord('('),ord(')')): _ESCAPEDICT[c] = '\\'+chr(c) else: _ESCAPEDICT[c] = chr(c) del c def _escape_and_limit(s): s = asBytes(s) R = [] aR = R.append n = 0 for c in s: c = _ESCAPEDICT[char2int(c)] aR(c) n += len(c) if n>=200: n = 0 aR('\\\n') return ''.join(R) # we need to create encoding vectors for each font we use, or they will # come out in Adobe's old StandardEncoding, which NOBODY uses. PS_WinAnsiEncoding=""" /RE { %def findfont begin currentdict dup length dict begin { %forall 1 index /FID ne { def } { pop pop } ifelse } forall /FontName exch def dup length 0 ne { %if /Encoding Encoding 256 array copy def 0 exch { %forall dup type /nametype eq { %ifelse Encoding 2 index 2 index put pop 1 add }{ %else exch pop } ifelse } forall } if pop currentdict dup end end /FontName get exch definefont pop } bind def /WinAnsiEncoding [ 39/quotesingle 96/grave 128/euro 130/quotesinglbase/florin/quotedblbase /ellipsis/dagger/daggerdbl/circumflex/perthousand /Scaron/guilsinglleft/OE 145/quoteleft/quoteright /quotedblleft/quotedblright/bullet/endash/emdash /tilde/trademark/scaron/guilsinglright/oe/dotlessi 159/Ydieresis 164/currency 166/brokenbar 168/dieresis/copyright /ordfeminine 172/logicalnot 174/registered/macron/ring 177/plusminus/twosuperior/threesuperior/acute/mu 183/periodcentered/cedilla/onesuperior/ordmasculine 188/onequarter/onehalf/threequarters 192/Agrave/Aacute /Acircumflex/Atilde/Adieresis/Aring/AE/Ccedilla /Egrave/Eacute/Ecircumflex/Edieresis/Igrave/Iacute /Icircumflex/Idieresis/Eth/Ntilde/Ograve/Oacute /Ocircumflex/Otilde/Odieresis/multiply/Oslash /Ugrave/Uacute/Ucircumflex/Udieresis/Yacute/Thorn /germandbls/agrave/aacute/acircumflex/atilde/adieresis /aring/ae/ccedilla/egrave/eacute/ecircumflex /edieresis/igrave/iacute/icircumflex/idieresis /eth/ntilde/ograve/oacute/ocircumflex/otilde /odieresis/divide/oslash/ugrave/uacute/ucircumflex /udieresis/yacute/thorn/ydieresis ] def """ class PSCanvas: def __init__(self,size=(300,300), PostScriptLevel=2): self.width, self.height = size xtraState = [] self._xtraState_push = xtraState.append self._xtraState_pop = xtraState.pop self.comments = 0 self.code = [] self.code_append = self.code.append self._sep = '\n' self._strokeColor = self._fillColor = self._lineWidth = \ self._font = self._fontSize = self._lineCap = \ self._lineJoin = self._color = None self._fontsUsed = [] # track them as we go self.setFont(STATE_DEFAULTS['fontName'],STATE_DEFAULTS['fontSize']) self.setStrokeColor(STATE_DEFAULTS['strokeColor']) self.setLineCap(2) self.setLineJoin(0) self.setLineWidth(1) self.PostScriptLevel=PostScriptLevel self._fillMode = FILL_EVEN_ODD def comment(self,msg): if self.comments: self.code_append('%'+msg) def drawImage(self, image, x1,y1, width=None,height=None): # Postscript Level2 version # select between postscript level 1 or level 2 if self.PostScriptLevel==1: self._drawImageLevel1(image, x1,y1, width, height) elif self.PostScriptLevel==2: self._drawImageLevel2(image, x1, y1, width, height) else : raise ValueError('Unsupported Postscript Level %s' % self.PostScriptLevel) def clear(self): self.code_append('showpage') # ugh, this makes no sense oh well. def _t1_re_encode(self): if not self._fontsUsed: return # for each font used, reencode the vectors C = [] for fontName in self._fontsUsed: fontObj = getFont(fontName) if not fontObj._dynamicFont and fontObj.encName=='WinAnsiEncoding': C.append('WinAnsiEncoding /%s /%s RE' % (fontName, fontName)) if C: C.insert(0,PS_WinAnsiEncoding) self.code.insert(1, self._sep.join(C)) def save(self,f=None): if not hasattr(f,'write'): _f = open(f,'wb') else: _f = f if self.code[-1]!='showpage': self.clear() self.code.insert(0,'''\ %%!PS-Adobe-3.0 EPSF-3.0 %%%%BoundingBox: 0 0 %d %d %%%% Initialization: /m {moveto} bind def /l {lineto} bind def /c {curveto} bind def ''' % (self.width,self.height)) self._t1_re_encode() _f.write(rawBytes(self._sep.join(self.code))) if _f is not f: _f.close() from reportlab.lib.utils import markfilename markfilename(f,creatorcode='XPR3',filetype='EPSF') def saveState(self): self._xtraState_push((self._fontCodeLoc,)) self.code_append('gsave') def restoreState(self): self.code_append('grestore') self._fontCodeLoc, = self._xtraState_pop() def stringWidth(self, s, font=None, fontSize=None): """Return the logical width of the string if it were drawn in the current font (defaults to self.font).""" font = font or self._font fontSize = fontSize or self._fontSize return stringWidth(s, font, fontSize) def setLineCap(self,v): if self._lineCap!=v: self._lineCap = v self.code_append('%d setlinecap'%v) def setLineJoin(self,v): if self._lineJoin!=v: self._lineJoin = v self.code_append('%d setlinejoin'%v) def setDash(self, array=[], phase=0): """Two notations. pass two numbers, or an array and phase""" # copied and modified from reportlab.canvas psoperation = "setdash" if isinstance(array,(float,int)): self.code_append('[%s %s] 0 %s' % (array, phase, psoperation)) elif isinstance(array,(tuple,list)): assert phase >= 0, "phase is a length in user space" textarray = ' '.join(map(str, array)) self.code_append('[%s] %s %s' % (textarray, phase, psoperation)) def setStrokeColor(self, color): self._strokeColor = color self.setColor(color) def setColor(self, color): if self._color!=color: self._color = color if color: if hasattr(color, "cyan"): self.code_append('%s setcmykcolor' % fp_str(color.cyan, color.magenta, color.yellow, color.black)) else: self.code_append('%s setrgbcolor' % fp_str(color.red, color.green, color.blue)) def setFillColor(self, color): self._fillColor = color self.setColor(color) def setFillMode(self, v): self._fillMode = v def setLineWidth(self, width): if width != self._lineWidth: self._lineWidth = width self.code_append('%s setlinewidth' % width) def setFont(self,font,fontSize,leading=None): if self._font!=font or self._fontSize!=fontSize: self._fontCodeLoc = len(self.code) self._font = font self._fontSize = fontSize self.code_append('') def line(self, x1, y1, x2, y2): if self._strokeColor != None: self.setColor(self._strokeColor) self.code_append('%s m %s l stroke' % (fp_str(x1, y1), fp_str(x2, y2))) def _escape(self, s): ''' return a copy of string s with special characters in postscript strings escaped with backslashes. ''' try: return _escape_and_limit(s) except: raise ValueError("cannot escape %s" % ascii(s)) def _textOut(self, x, y, s, textRenderMode=0): if textRenderMode==3: return xy = fp_str(x,y) s = self._escape(s) if textRenderMode==0: #the standard case self.setColor(self._fillColor) self.code_append('%s m (%s) show ' % (xy,s)) return fill = textRenderMode==0 or textRenderMode==2 or textRenderMode==4 or textRenderMode==6 stroke = textRenderMode==1 or textRenderMode==2 or textRenderMode==5 or textRenderMode==6 addToClip = textRenderMode>=4 if fill and stroke: if self._fillColor is None: op = '' else: op = 'fill ' self.setColor(self._fillColor) self.code_append('%s m (%s) true charpath gsave %s' % (xy,s,op)) self.code_append('grestore ') if self._strokeColor is not None: self.setColor(self._strokeColor) self.code_append('stroke ') else: #can only be stroke alone self.setColor(self._strokeColor) self.code_append('%s m (%s) true charpath stroke ' % (xy,s)) def _issueT1String(self,fontObj,x,y,s, textRenderMode=0): fc = fontObj code_append = self.code_append fontSize = self._fontSize fontsUsed = self._fontsUsed escape = self._escape if not isUnicode(s): try: s = s.decode('utf8') except UnicodeDecodeError as e: i,j = e.args[2:4] raise UnicodeDecodeError(*(e.args[:4]+('%s\n%s-->%s<--%s' % (e.args[4],s[i-10:i],s[i:j],s[j:j+10]),))) for f, t in unicode2T1(s,[fontObj]+fontObj.substitutionFonts): if f!=fc: psName = asNative(f.face.name) code_append('(%s) findfont %s scalefont setfont' % (psName,fp_str(fontSize))) if psName not in fontsUsed: fontsUsed.append(psName) fc = f self._textOut(x,y,t,textRenderMode) x += f.stringWidth(t.decode(f.encName),fontSize) if fontObj!=fc: self._font = None self.setFont(fontObj.face.name,fontSize) def drawString(self, x, y, s, angle=0, text_anchor='left', textRenderMode=0): needFill = textRenderMode in (0,2,4,6) needStroke = textRenderMode in (1,2,5,6) if needFill or needStroke: if text_anchor!='left': textLen = stringWidth(s, self._font,self._fontSize) if text_anchor=='end': x -= textLen elif text_anchor=='middle': x -= textLen/2. elif text_anchor=='numeric': x -= numericXShift(text_anchor,s,textLen,self._font,self._fontSize) fontObj = getFont(self._font) if not self.code[self._fontCodeLoc]: psName = asNative(fontObj.face.name) self.code[self._fontCodeLoc]='(%s) findfont %s scalefont setfont' % (psName,fp_str(self._fontSize)) if psName not in self._fontsUsed: self._fontsUsed.append(psName) if angle!=0: self.code_append('gsave %s translate %s rotate' % (fp_str(x,y),fp_str(angle))) x = y = 0 oldColor = self._color if fontObj._dynamicFont: self._textOut(x, y, s, textRenderMode=textRenderMode) else: self._issueT1String(fontObj,x,y,s, textRenderMode=textRenderMode) self.setColor(oldColor) if angle!=0: self.code_append('grestore') def drawCentredString(self, x, y, text, text_anchor='middle', textRenderMode=0): self.drawString(x,y,text, text_anchor=text_anchor, textRenderMode=textRenderMode) def drawRightString(self, text, x, y, text_anchor='end', textRenderMode=0): self.drawString(text,x,y,text_anchor=text_anchor, textRenderMode=textRenderMode) def drawCurve(self, x1, y1, x2, y2, x3, y3, x4, y4, closed=0): codeline = '%s m %s curveto' data = (fp_str(x1, y1), fp_str(x2, y2, x3, y3, x4, y4)) if self._fillColor != None: self.setColor(self._fillColor) self.code_append((codeline % data) + ' eofill') if self._strokeColor != None: self.setColor(self._strokeColor) self.code_append((codeline % data) + ((closed and ' closepath') or '') + ' stroke') ######################################################################################## def rect(self, x1,y1, x2,y2, stroke=1, fill=1): "Draw a rectangle between x1,y1, and x2,y2" # Path is drawn in counter-clockwise direction" x1, x2 = min(x1,x2), max(x1, x2) # from piddle.py y1, y2 = min(y1,y2), max(y1, y2) self.polygon(((x1,y1),(x2,y1),(x2,y2),(x1,y2)), closed=1, stroke=stroke, fill = fill) def roundRect(self, x1,y1, x2,y2, rx=8, ry=8): """Draw a rounded rectangle between x1,y1, and x2,y2, with corners inset as ellipses with x radius rx and y radius ry. These should have x10, and ry>0.""" # Path is drawn in counter-clockwise direction x1, x2 = min(x1,x2), max(x1, x2) # from piddle.py y1, y2 = min(y1,y2), max(y1, y2) # Note: arcto command draws a line from current point to beginning of arc # save current matrix, translate to center of ellipse, scale by rx ry, and draw # a circle of unit radius in counterclockwise dir, return to original matrix # arguments are (cx, cy, rx, ry, startAngle, endAngle) ellipsePath = 'matrix currentmatrix %s %s translate %s %s scale 0 0 1 %s %s arc setmatrix' # choice between newpath and moveTo beginning of arc # go with newpath for precision, does this violate any assumptions in code??? rr = ['newpath'] # Round Rect code path a = rr.append # upper left corner ellipse is first a(ellipsePath % (x1+rx, y1+ry, rx, -ry, 90, 180)) a(ellipsePath % (x1+rx, y2-ry, rx, -ry, 180, 270)) a(ellipsePath % (x2-rx, y2-ry, rx, -ry, 270, 360)) a(ellipsePath % (x2-rx, y1+ry, rx, -ry, 0, 90) ) a('closepath') self._fillAndStroke(rr) def ellipse(self, x1,y1, x2,y2): """Draw an orthogonal ellipse inscribed within the rectangle x1,y1,x2,y2. These should have x1= 0: arc='arc' else: arc='arcn' data = (x,y, xScale, yScale, startAng, startAng+extent, arc) return codeline % data def polygon(self, p, closed=0, stroke=1, fill=1): assert len(p) >= 2, 'Polygon must have 2 or more points' start = p[0] p = p[1:] poly = [] a = poly.append a("%s m" % fp_str(start)) for point in p: a("%s l" % fp_str(point)) if closed: a("closepath") self._fillAndStroke(poly,stroke=stroke,fill=fill) def lines(self, lineList, color=None, width=None): if self._strokeColor != None: self._setColor(self._strokeColor) codeline = '%s m %s l stroke' for line in lineList: self.code_append(codeline % (fp_str(line[0]),fp_str(line[1]))) def moveTo(self,x,y): self.code_append('%s m' % fp_str(x, y)) def lineTo(self,x,y): self.code_append('%s l' % fp_str(x, y)) def curveTo(self,x1,y1,x2,y2,x3,y3): self.code_append('%s c' % fp_str(x1,y1,x2,y2,x3,y3)) def closePath(self): self.code_append('closepath') def polyLine(self, p): assert len(p) >= 1, 'Polyline must have 1 or more points' if self._strokeColor != None: self.setColor(self._strokeColor) self.moveTo(p[0][0], p[0][1]) for t in p[1:]: self.lineTo(t[0], t[1]) self.code_append('stroke') def drawFigure(self, partList, closed=0): figureCode = [] a = figureCode.append first = 1 for part in partList: op = part[0] args = list(part[1:]) if op == figureLine: if first: first = 0 a("%s m" % fp_str(args[:2])) else: a("%s l" % fp_str(args[:2])) a("%s l" % fp_str(args[2:])) elif op == figureArc: first = 0 x1,y1,x2,y2,startAngle,extent = args[:6] a(self._genArcCode(x1,y1,x2,y2,startAngle,extent)) elif op == figureCurve: if first: first = 0 a("%s m" % fp_str(args[:2])) else: a("%s l" % fp_str(args[:2])) a("%s curveto" % fp_str(args[2:])) else: raise TypeError("unknown figure operator: "+op) if closed: a("closepath") self._fillAndStroke(figureCode) def _fillAndStroke(self,code,clip=0,fill=1,stroke=1,fillMode=None): fill = self._fillColor and fill stroke = self._strokeColor and stroke if fill or stroke or clip: self.code.extend(code) if fill: if fillMode is None: fillMode = self._fillMode if stroke or clip: self.code_append("gsave") self.setColor(self._fillColor) self.code_append("eofill" if fillMode==FILL_EVEN_ODD else "fill") if stroke or clip: self.code_append("grestore") if stroke: if clip: self.code_append("gsave") self.setColor(self._strokeColor) self.code_append("stroke") if clip: self.code_append("grestore") if clip: self.code_append("clip") self.code_append("newpath") def translate(self,x,y): self.code_append('%s translate' % fp_str(x,y)) def scale(self,x,y): self.code_append('%s scale' % fp_str(x,y)) def transform(self,a,b,c,d,e,f): self.code_append('[%s] concat' % fp_str(a,b,c,d,e,f)) def _drawTimeResize(self,w,h): '''if this is used we're probably in the wrong world''' self.width, self.height = w, h def _drawImageLevel1(self, image, x1, y1, width=None, height=None): # Postscript Level1 version available for fallback mode when Level2 doesn't work # For now let's start with 24 bit RGB images (following piddlePDF again) component_depth = 8 myimage = image.convert('RGB') imgwidth, imgheight = myimage.size if not width: width = imgwidth if not height: height = imgheight #print 'Image size (%d, %d); Draw size (%d, %d)' % (imgwidth, imgheight, width, height) # now I need to tell postscript how big image is # "image operators assume that they receive sample data from # their data source in x-axis major index order. The coordinate # of the lower-left corner of the first sample is (0,0), of the # second (1,0) and so on" -PS2 ref manual p. 215 # # The ImageMatrix maps unit squre of user space to boundary of the source image # # The CurrentTransformationMatrix (CTM) maps the unit square of # user space to the rect...on the page that is to receive the # image. A common ImageMatrix is [width 0 0 -height 0 height] # (for a left to right, top to bottom image ) # first let's map the user coordinates start at offset x1,y1 on page self.code.extend([ 'gsave', '%s %s translate' % (x1,y1), # need to start are lower left of image '%s %s scale' % (width,height), '/scanline %d 3 mul string def' % imgwidth # scanline by multiples of image width ]) # now push the dimensions and depth info onto the stack # and push the ImageMatrix to map the source to the target rectangle (see above) # finally specify source (PS2 pp. 225 ) and by exmample self.code.extend([ '%s %s %s' % (imgwidth, imgheight, component_depth), '[%s %s %s %s %s %s]' % (imgwidth, 0, 0, -imgheight, 0, imgheight), '{ currentfile scanline readhexstring pop } false 3', 'colorimage ' ]) # data source output--now we just need to deliver a hex encode # series of lines of the right overall size can follow # piddlePDF again rawimage = (myimage.tobytes if hasattr(myimage,'tobytes') else myimage.tostring)() hex_encoded = self._AsciiHexEncode(rawimage) # write in blocks of 78 chars per line outstream = StringIO(hex_encoded) dataline = outstream.read(78) while dataline != "": self.code_append(dataline) dataline= outstream.read(78) self.code_append('% end of image data') # for clarity self.code_append('grestore') # return coordinates to normal # end of drawImage def _AsciiHexEncode(self, input): # also based on piddlePDF "Helper function used by images" output = StringIO() for char in asBytes(input): output.write('%02x' % char2int(char)) return output.getvalue() def _drawImageLevel2(self, image, x1,y1, width=None,height=None): # Postscript Level2 version '''At present we're handling only PIL''' ### what sort of image are we to draw if image.mode=='L' : imBitsPerComponent = 8 imNumComponents = 1 myimage = image elif image.mode == '1': myimage = image.convert('L') imNumComponents = 1 myimage = image else : myimage = image.convert('RGB') imNumComponents = 3 imBitsPerComponent = 8 imwidth, imheight = myimage.size if not width: width = imwidth if not height: height = imheight self.code.extend([ 'gsave', '%s %s translate' % (x1,y1), # need to start are lower left of image '%s %s scale' % (width,height)]) if imNumComponents == 3 : self.code_append('/DeviceRGB setcolorspace') elif imNumComponents == 1 : self.code_append('/DeviceGray setcolorspace') # create the image dictionary self.code_append(""" << /ImageType 1 /Width %d /Height %d %% dimensions of source image /BitsPerComponent %d""" % (imwidth, imheight, imBitsPerComponent) ) if imNumComponents == 1: self.code_append('/Decode [0 1]') if imNumComponents == 3: self.code_append('/Decode [0 1 0 1 0 1] %% decode color values normally') self.code.extend([ '/ImageMatrix [%s 0 0 %s 0 %s]' % (imwidth, -imheight, imheight), '/DataSource currentfile /ASCIIHexDecode filter', '>> % End image dictionary', 'image']) # after image operator just need to dump image dat to file as hexstring rawimage = (myimage.tobytes if hasattr(myimage,'tobytes') else myimage.tostring)() hex_encoded = self._AsciiHexEncode(rawimage) # write in blocks of 78 chars per line outstream = StringIO(hex_encoded) dataline = outstream.read(78) while dataline != "": self.code_append(dataline) dataline= outstream.read(78) self.code_append('> % end of image data') # > is EOD for hex encoded filterfor clarity self.code_append('grestore') # return coordinates to normal # renderpdf - draws them onto a canvas """Usage: from reportlab.graphics import renderPS renderPS.draw(drawing, canvas, x, y) Execute the script to see some test drawings.""" from reportlab.graphics.shapes import * # hack so we only get warnings once each #warnOnce = WarnOnce() # the main entry point for users... def draw(drawing, canvas, x=0, y=0, showBoundary=rl_config.showBoundary): """As it says""" R = _PSRenderer() R.draw(renderScaledDrawing(drawing), canvas, x, y, showBoundary=showBoundary) def _pointsFromList(L): ''' given a list of coordinates [x0, y0, x1, y1....] produce a list of points [(x0,y0), (y1,y0),....] ''' P=[] a = P.append for i in range(0,len(L),2): a((L[i],L[i+1])) return P class _PSRenderer(Renderer): """This draws onto a EPS document. It needs to be a class rather than a function, as some EPS-specific state tracking is needed outside of the state info in the SVG model.""" def drawNode(self, node): """This is the recursive method called for each node in the tree""" self._canvas.comment('begin node %r'%node) color = self._canvas._color if not (isinstance(node, Path) and node.isClipPath): self._canvas.saveState() #apply state changes deltas = getStateDelta(node) self._tracker.push(deltas) self.applyStateChanges(deltas, {}) #draw the object, or recurse self.drawNodeDispatcher(node) rDeltas = self._tracker.pop() if not (isinstance(node, Path) and node.isClipPath): self._canvas.restoreState() self._canvas.comment('end node %r'%node) self._canvas._color = color #restore things we might have lost (without actually doing anything). for k, v in rDeltas.items(): if k in self._restores: setattr(self._canvas,self._restores[k],v) ## _restores = {'stroke':'_stroke','stroke_width': '_lineWidth','stroke_linecap':'_lineCap', ## 'stroke_linejoin':'_lineJoin','fill':'_fill','font_family':'_font', ## 'font_size':'_fontSize'} _restores = {'strokeColor':'_strokeColor','strokeWidth': '_lineWidth','strokeLineCap':'_lineCap', 'strokeLineJoin':'_lineJoin','fillColor':'_fillColor','fontName':'_font', 'fontSize':'_fontSize'} def drawRect(self, rect): if rect.rx == rect.ry == 0: #plain old rectangle self._canvas.rect( rect.x, rect.y, rect.x+rect.width, rect.y+rect.height) else: #cheat and assume ry = rx; better to generalize #pdfgen roundRect function. TODO self._canvas.roundRect( rect.x, rect.y, rect.x+rect.width, rect.y+rect.height, rect.rx, rect.ry ) def drawLine(self, line): if self._canvas._strokeColor: self._canvas.line(line.x1, line.y1, line.x2, line.y2) def drawCircle(self, circle): self._canvas.circle( circle.cx, circle.cy, circle.r) def drawWedge(self, wedge): yradius, radius1, yradius1 = wedge._xtraRadii() if (radius1==0 or radius1 is None) and (yradius1==0 or yradius1 is None) and not wedge.annular: startangledegrees = wedge.startangledegrees endangledegrees = wedge.endangledegrees centerx= wedge.centerx centery = wedge.centery radius = wedge.radius extent = endangledegrees - startangledegrees self._canvas.drawArc(centerx-radius, centery-yradius, centerx+radius, centery+yradius, startangledegrees, extent, fromcenter=1) else: P = wedge.asPolygon() if isinstance(P,Path): self.drawPath(P) else: self.drawPolygon(P) def drawPolyLine(self, p): if self._canvas._strokeColor: self._canvas.polyLine(_pointsFromList(p.points)) def drawEllipse(self, ellipse): #need to convert to pdfgen's bounding box representation x1 = ellipse.cx - ellipse.rx x2 = ellipse.cx + ellipse.rx y1 = ellipse.cy - ellipse.ry y2 = ellipse.cy + ellipse.ry self._canvas.ellipse(x1,y1,x2,y2) def drawPolygon(self, p): self._canvas.polygon(_pointsFromList(p.points), closed=1) def drawString(self, stringObj): textRenderMode = getattr(stringObj,'textRenderMode',0) if self._canvas._fillColor or textRenderMode: S = self._tracker.getState() text_anchor, x, y, text = S['textAnchor'], stringObj.x,stringObj.y,stringObj.text if not text_anchor in ['start','inherited']: font, fontSize = S['fontName'], S['fontSize'] textLen = stringWidth(text, font,fontSize) if text_anchor=='end': x -= textLen elif text_anchor=='middle': x -= textLen/2 elif text_anchor=='numeric': x -= numericXShift(text_anchor,text,textLen,font,fontSize,encoding='winansi') else: raise ValueError('bad value for text_anchor '+str(text_anchor)) self._canvas.drawString(x,y,text, textRenderMode=textRenderMode) def drawPath(self, path, fillMode=None): from reportlab.graphics.shapes import _renderPath c = self._canvas drawFuncs = (c.moveTo, c.lineTo, c.curveTo, c.closePath) autoclose = getattr(path,'autoclose','') def rP(**kwds): return _renderPath(path, drawFuncs, **kwds) if fillMode is None: fillMode = getattr(path,'fillMode',c._fillMode) fill = c._fillColor is not None stroke = c._strokeColor is not None clip = path.isClipPath fas = lambda **kwds: c._fillAndStroke([], fillMode=fillMode, **kwds) pathFill = lambda : c._fillAndStroke([], stroke=0, fillMode=fillMode) pathStroke = lambda : c._fillAndStroke([], fill=0) if autoclose=='svg': rP() fas(stroke=stroke,fill=fill,clip=clip) elif autoclose=='pdf': if fill: rP(forceClose=True) fas(stroke=stroke,fill=fill,clip=clip) elif stroke or clip: rP() fas(stroke=stroke,fill=0,clip=clip) else: if fill and rP(countOnly=True): rP() elif stroke or clip: rP() fas(stroke=stroke,fill=0,clip=clip) def applyStateChanges(self, delta, newState): """This takes a set of states, and outputs the operators needed to set those properties""" for key, value in delta.items(): if key == 'transform': self._canvas.transform(value[0], value[1], value[2], value[3], value[4], value[5]) elif key == 'strokeColor': #this has different semantics in PDF to SVG; #we always have a color, and either do or do #not apply it; in SVG one can have a 'None' color self._canvas.setStrokeColor(value) elif key == 'strokeWidth': self._canvas.setLineWidth(value) elif key == 'strokeLineCap': #0,1,2 self._canvas.setLineCap(value) elif key == 'strokeLineJoin': self._canvas.setLineJoin(value) elif key == 'strokeDashArray': if value: if isinstance(value,(list,tuple)) and len(value)==2 and isinstance(value[1],(tuple,list)): phase = value[0] value = value[1] else: phase = 0 self._canvas.setDash(value,phase) else: self._canvas.setDash() ## elif key == 'stroke_opacity': ## warnOnce('Stroke Opacity not supported yet') elif key == 'fillColor': #this has different semantics in PDF to SVG; #we always have a color, and either do or do #not apply it; in SVG one can have a 'None' color self._canvas.setFillColor(value) ## elif key == 'fill_rule': ## warnOnce('Fill rules not done yet') ## elif key == 'fill_opacity': ## warnOnce('Fill opacity not done yet') elif key in ['fontSize', 'fontName']: # both need setting together in PDF # one or both might be in the deltas, # so need to get whichever is missing fontname = delta.get('fontName', self._canvas._font) fontsize = delta.get('fontSize', self._canvas._fontSize) self._canvas.setFont(fontname, fontsize) def drawImage(self, image): from reportlab.lib.utils import ImageReader im = ImageReader(image.path) self._canvas.drawImage(im._image,image.x,image.y,image.width,image.height) def drawToFile(d,fn, showBoundary=rl_config.showBoundary,**kwd): d = renderScaledDrawing(d) c = PSCanvas((d.width,d.height)) draw(d, c, 0, 0, showBoundary=showBoundary) c.save(fn) def drawToString(d, showBoundary=rl_config.showBoundary): "Returns a PS as a string in memory, without touching the disk" s = BytesIO() drawToFile(d, s, showBoundary=showBoundary) return s.getvalue() ######################################################### # # test code. First, define a bunch of drawings. # Routine to draw them comes at the end. # ######################################################### def test(outDir='epsout',shout=False): from reportlab.graphics import testshapes from reportlab.rl_config import verbose OLDFONTS = testshapes._FONTS[:] testshapes._FONTS[:] = ['Times-Roman','Times-Bold','Times-Italic', 'Times-BoldItalic','Courier'] try: import os # save all drawings and their doc strings from the test file if not os.path.isdir(outDir): os.mkdir(outDir) #grab all drawings from the test module drawings = [] for funcname in dir(testshapes): if funcname[0:10] == 'getDrawing': func = getattr(testshapes,funcname) drawing = func() docstring = getattr(func,'__doc__','') drawings.append((drawing, docstring)) i = 0 for (d, docstring) in drawings: filename = outDir + os.sep + 'renderPS_%d.eps'%i drawToFile(d,filename) if shout or verbose>2: print('renderPS test saved %s' % ascii(filename)) i += 1 finally: testshapes._FONTS[:] = OLDFONTS if __name__=='__main__': import sys if len(sys.argv)>1: outdir = sys.argv[1] else: outdir = 'epsout' test(outdir,shout=True) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1691062243.0 reportlab-4.1.0/src/reportlab/graphics/renderSVG.py0000664000175000017500000011146614462707743021723 0ustar00rptlabrptlab__doc__="""An experimental SVG renderer for the ReportLab graphics framework. This will create SVG code from the ReportLab Graphics API (RLG). To read existing SVG code and convert it into ReportLab graphics objects download the svglib module here: http://python.net/~gherman/#svglib """ import math, sys, os, codecs, base64 from io import BytesIO, StringIO from reportlab.pdfbase.pdfmetrics import stringWidth # for font info from reportlab.lib.rl_accel import fp_str from reportlab.lib.utils import asNative from reportlab.graphics.renderbase import getStateDelta, Renderer, renderScaledDrawing from reportlab.graphics.shapes import STATE_DEFAULTS, Path, UserNode from reportlab.graphics.shapes import * # (only for test0) from reportlab import rl_config from reportlab.lib.utils import RLString, isUnicode, isBytes from reportlab.pdfgen.canvas import FILL_EVEN_ODD, FILL_NON_ZERO from .renderPM import _getImage from xml.dom import getDOMImplementation ### some constants ### sin = math.sin cos = math.cos pi = math.pi AREA_STYLES = 'stroke-width stroke-linecap stroke stroke-opacity fill fill-opacity stroke-dasharray stroke-dashoffset fill-rule id'.split() LINE_STYLES = 'stroke-width stroke-linecap stroke stroke-opacity stroke-dasharray stroke-dashoffset id'.split() TEXT_STYLES = 'font-family font-weight font-style font-variant font-size id'.split() EXTRA_STROKE_STYLES = 'stroke-width stroke-linecap stroke stroke-opacity stroke-dasharray stroke-dashoffset'.split() EXTRA_FILL_STYLES = 'fill fill-opacity'.split() ### top-level user function ### def drawToString(d, showBoundary=rl_config.showBoundary,**kwds): "Returns a SVG as a string in memory, without touching the disk" s = StringIO() drawToFile(d, s, showBoundary=showBoundary,**kwds) return s.getvalue() def drawToFile(d, fn, showBoundary=rl_config.showBoundary,**kwds): d = renderScaledDrawing(d) c = SVGCanvas((d.width, d.height),**kwds) draw(d, c, 0, 0, showBoundary=showBoundary) c.save(fn) def draw(drawing, canvas, x=0, y=0, showBoundary=rl_config.showBoundary): """As it says.""" r = _SVGRenderer() r.draw(renderScaledDrawing(drawing), canvas, x, y, showBoundary=showBoundary) ### helper functions ### def _pointsFromList(L): """ given a list of coordinates [x0, y0, x1, y1....] produce a list of points [(x0,y0), (y1,y0),....] """ P=[] for i in range(0,len(L), 2): P.append((L[i], L[i+1])) return P def transformNode(doc, newTag, node=None, **attrDict): """Transform a DOM node into new node and copy selected attributes. Creates a new DOM node with tag name 'newTag' for document 'doc' and copies selected attributes from an existing 'node' as provided in 'attrDict'. The source 'node' can be None. Attribute values will be converted to strings. E.g. n = transformNode(doc, "node1", x="0", y="1") -> DOM node for n = transformNode(doc, "node1", x=0, y=1+1) -> DOM node for n = transformNode(doc, "node1", node0, x="x0", y="x0", zoo=bar()) -> DOM node for """ newNode = doc.createElement(newTag) for newAttr, attr in attrDict.items(): sattr = str(attr) if not node: newNode.setAttribute(newAttr, sattr) else: attrVal = node.getAttribute(sattr) newNode.setAttribute(newAttr, attrVal or sattr) return newNode class EncodedWriter(list): ''' EncodedWriter(encoding) assumes .write will be called with either unicode or utf8 encoded bytes. it will accumulate unicode ''' BOMS = { 'utf-32':codecs.BOM_UTF32, 'utf-32-be':codecs.BOM_UTF32_BE, 'utf-32-le':codecs.BOM_UTF32_LE, 'utf-16':codecs.BOM_UTF16, 'utf-16-be':codecs.BOM_UTF16_BE, 'utf-16-le':codecs.BOM_UTF16_LE, } def __init__(self,encoding,bom=False): list.__init__(self) self.encoding = encoding = codecs.lookup(encoding).name if bom and '16' in encoding or '32' in encoding: self.write(self.BOMS[encoding]) def write(self,u): if isBytes(u): try: u = u.decode('utf-8') except: et, ev, tb = sys.exc_info() ev = str(ev) del et, tb raise ValueError("String %r not encoded as 'utf-8'\nerror=%s" % (u,ev)) elif not isUnicode(u): raise ValueError("EncodedWriter.write(%s) argument should be 'utf-8' bytes or str" % ascii(u)) self.append(u) def getvalue(self): r = ''.join(self) del self[:] return r _fillRuleMap = { FILL_NON_ZERO: 'nonzero', 'non-zero': 'nonzero', 'nonzero': 'nonzero', FILL_EVEN_ODD: 'evenodd', 'even-odd': 'evenodd', 'evenodd': 'evenodd', } def py_fp_str(*args): return ' '.join((('%f' % a).rstrip('0').rstrip('.') for a in args)) ### classes ### class SVGCanvas: def __init__(self, size=(300,300), encoding='utf-8', verbose=0, bom=False, **kwds): ''' verbose = 0 >0 means do verbose stuff useClip = False True means don't use a clipPath definition put the global clip into the clip property to get around an issue with safari extraXmlDecl = '' use to add extra xml declarations scaleGroupId = '' id of an extra group to add around the drawing to allow easy scaling svgAttrs = {} dictionary of attributes to be applied to the svg tag itself ''' self.verbose = verbose self.encoding = codecs.lookup(encoding).name self.bom = bom useClip = kwds.pop('useClip',False) self.fontHacks = kwds.pop('fontHacks',{}) self.extraXmlDecl = kwds.pop('extraXmlDecl','') scaleGroupId = kwds.pop('scaleGroupId','') self._fillMode = FILL_EVEN_ODD self.width, self.height = self.size = size # self.height = size[1] self.code = [] self.style = {} self.path = '' self._strokeColor = self._fillColor = self._lineWidth = \ self._font = self._fontSize = self._lineCap = \ self._lineJoin = None if kwds.pop('use_fp_str',False): self.fp_str = fp_str else: self.fp_str = py_fp_str self.cfp_str = lambda *args: self.fp_str(*args).replace(' ',',') implementation = getDOMImplementation('minidom') #Based on official example here http://www.w3.org/TR/SVG10/linking.html want: # #Thus, #doctype = implementation.createDocumentType("svg", # "-//W3C//DTD SVG 20010904//EN", # "http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd") # #However, putting that example through http://validator.w3.org/ recommends: # #So we'll use that for our SVG 1.0 output. doctype = implementation.createDocumentType("svg", "-//W3C//DTD SVG 1.0//EN", "http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd") self.doc = implementation.createDocument(None,"svg",doctype) self.svg = self.doc.documentElement svgAttrs = dict( width = str(size[0]), height=str(self.height), preserveAspectRatio="xMinYMin meet", viewBox="0 0 %d %d" % (self.width, self.height), #baseProfile = "full", #disliked in V 1.0 #these suggested by Tim Roberts, as updated by peter@maubp.freeserve.co.uk xmlns="http://www.w3.org/2000/svg", version="1.0", ) svgAttrs['fill-rule'] = _fillRuleMap[self._fillMode] svgAttrs["xmlns:xlink"] = "http://www.w3.org/1999/xlink" svgAttrs.update(kwds.pop('svgAttrs',{})) for k,v in svgAttrs.items(): self.svg.setAttribute(k,v) title = self.doc.createElement('title') text = self.doc.createTextNode('...') title.appendChild(text) self.svg.appendChild(title) desc = self.doc.createElement('desc') text = self.doc.createTextNode('...') desc.appendChild(text) self.svg.appendChild(desc) self.setFont(STATE_DEFAULTS['fontName'], STATE_DEFAULTS['fontSize']) self.setStrokeColor(STATE_DEFAULTS['strokeColor']) self.setLineCap(2) self.setLineJoin(0) self.setLineWidth(1) if not useClip: # Add a rectangular clipping path identical to view area. clipPath = transformNode(self.doc, "clipPath", id="clip") clipRect = transformNode(self.doc, "rect", x=0, y=0, width=self.width, height=self.height) clipPath.appendChild(clipRect) self.svg.appendChild(clipPath) gtkw = dict(style="clip-path: url(#clip)") else: gtkw = dict(clip="0 0 %d %d" % (self.width,self.height)) self.groupTree = transformNode(self.doc, "g", id="group", transform="scale(1,-1) translate(0,-%d)" % self.height, **gtkw ) if scaleGroupId: self.scaleTree = transformNode(self.doc, "g", id=scaleGroupId, transform="scale(1,1)") self.scaleTree.appendChild(self.groupTree) self.svg.appendChild(self.scaleTree) else: self.svg.appendChild(self.groupTree) self.currGroup = self.groupTree def save(self, fn=None): writer = EncodedWriter(self.encoding,bom=self.bom) self.doc.writexml(writer,addindent="\t",newl="\n",encoding=self.encoding) if hasattr(fn,'write'): f = fn else: f = open(fn, 'w',encoding=self.encoding) svg = writer.getvalue() exd = self.extraXmlDecl if exd: svg = svg.replace('?>','?>'+exd) f.write(svg) if f is not fn: f.close() ### helpers ### def NOTUSED_stringWidth(self, s, font=None, fontSize=None): """Return the logical width of the string if it were drawn in the current font (defaults to self.font). """ font = font or self._font fontSize = fontSize or self._fontSize return stringWidth(s, font, fontSize) def _formatStyle(self, include=[], exclude='',**kwds): style = self.style.copy() style.update(kwds) keys = list(style.keys()) if include: keys = [k for k in keys if k in include] if exclude: exclude = exclude.split() items = [k+': '+str(style[k]) for k in keys if k not in exclude] else: items = [k+': '+str(style[k]) for k in keys] return '; '.join(items) + ';' def _escape(self, s): '''I don't think this was ever needed; seems to have been copied from renderPS''' return s def _genArcCode(self, x1, y1, x2, y2, startAng, extent): """Calculate the path for an arc inscribed in rectangle defined by (x1,y1),(x2,y2).""" return #calculate semi-minor and semi-major axes of ellipse xScale = abs((x2-x1)/2.0) yScale = abs((y2-y1)/2.0) #calculate centre of ellipse x, y = (x1+x2)/2.0, (y1+y2)/2.0 codeline = 'matrix currentmatrix %s %s translate %s %s scale 0 0 1 %s %s %s setmatrix' if extent >= 0: arc='arc' else: arc='arcn' data = (x,y, xScale, yScale, startAng, startAng+extent, arc) return codeline % data def _fillAndStroke(self, code, clip=0, link_info=None,styles=AREA_STYLES,fillMode=None): xtra = {} if fillMode: xtra['fill-rule'] = _fillRuleMap[fillMode] path = transformNode(self.doc, "path", d=self.path, style=self._formatStyle(styles), ) if link_info : path = self._add_link(path, link_info) self.currGroup.appendChild(path) self.path = '' ### styles ### def setLineCap(self, v): vals = {0:'butt', 1:'round', 2:'square'} if self._lineCap != v: self._lineCap = v self.style['stroke-linecap'] = vals[v] def setLineJoin(self, v): vals = {0:'miter', 1:'round', 2:'bevel'} if self._lineJoin != v: self._lineJoin = v self.style['stroke-linecap'] = vals[v] def setDash(self, array=[], phase=0): """Two notations. Pass two numbers, or an array and phase.""" if isinstance(array,(float,int)): self.style['stroke-dasharray'] = ', '.join(map(str, ([array, phase]))) elif isinstance(array,(tuple,list)) and len(array) > 0: assert phase >= 0, "phase is a length in user space" self.style['stroke-dasharray'] = ', '.join(map(str, array)) if phase>0: self.style['stroke-dashoffset'] = str(phase) def setStrokeColor(self, color): self._strokeColor = color if color == None: self.style['stroke'] = 'none' else: r, g, b = color.red, color.green, color.blue self.style['stroke'] = 'rgb(%d%%,%d%%,%d%%)' % (r*100, g*100, b*100) alpha = color.normalizedAlpha if alpha!=1: self.style['stroke-opacity'] = '%s' % alpha elif 'stroke-opacity' in self.style: del self.style['stroke-opacity'] def setFillColor(self, color): self._fillColor = color if color == None: self.style['fill'] = 'none' else: r, g, b = color.red, color.green, color.blue self.style['fill'] = 'rgb(%d%%,%d%%,%d%%)' % (r*100, g*100, b*100) alpha = color.normalizedAlpha if alpha!=1: self.style['fill-opacity'] = '%s' % alpha elif 'fill-opacity' in self.style: del self.style['fill-opacity'] def setFillMode(self, v): self._fillMode = v self.style['fill-rule'] = _fillRuleMap[v] def setLineWidth(self, width): if width != self._lineWidth: self._lineWidth = width self.style['stroke-width'] = width def setFont(self, font, fontSize): if self._font != font or self._fontSize != fontSize: self._font = font self._fontSize = fontSize style = self.style for k in TEXT_STYLES: if k in style: del style[k] svgAttrs = self.fontHacks[font] if font in self.fontHacks else {} if isinstance(font,RLString): svgAttrs.update(iter(font.svgAttrs.items())) if svgAttrs: for k,v in svgAttrs.items(): a = 'font-'+k if a in TEXT_STYLES: style[a] = v if 'font-family' not in style: style['font-family'] = font style['font-size'] = '%spx' % fontSize def _add_link(self, dom_object, link_info) : assert isinstance(link_info, dict) link = transformNode(self.doc, "a", **link_info) link.appendChild(dom_object) return link ### shapes ### def rect(self, x1,y1, x2,y2, rx=8, ry=8, link_info=None, **_svgAttrs): "Draw a rectangle between x1,y1 and x2,y2." if self.verbose: print("+++ SVGCanvas.rect") x = min(x1,x2) y = min(y1,y2) kwds = {} rect = transformNode(self.doc, "rect", x=x, y=y, width=max(x1,x2)-x, height=max(y1,y2)-y, style=self._formatStyle(AREA_STYLES),**_svgAttrs) if link_info : rect = self._add_link(rect, link_info) self.currGroup.appendChild(rect) def roundRect(self, x1,y1, x2,y2, rx=8, ry=8, link_info=None, **_svgAttrs): """Draw a rounded rectangle between x1,y1 and x2,y2. Corners inset as ellipses with x-radius rx and y-radius ry. These should have x10, and ry>0. """ rect = transformNode(self.doc, "rect", x=x1, y=y1, width=x2-x1, height=y2-y1, rx=rx, ry=ry, style=self._formatStyle(AREA_STYLES), **_svgAttrs) if link_info: rect = self._add_link(rect, link_info) self.currGroup.appendChild(rect) def drawString(self, s, x, y, angle=0, link_info=None, text_anchor='left', textRenderMode=0, **_svgAttrs): if textRenderMode==3: return #invisible s = asNative(s) if self.verbose: print("+++ SVGCanvas.drawString") needFill = textRenderMode==0 or textRenderMode==2 or textRenderMode==4 or textRenderMode==6 needStroke = textRenderMode==1 or textRenderMode==2 or textRenderMode==5 or textRenderMode==6 if (self._fillColor!=None and needFill) or (self._strokeColor!=None and needStroke): if not text_anchor in ['start', 'inherited', 'left']: textLen = stringWidth(s,self._font,self._fontSize) if text_anchor=='end': x -= textLen elif text_anchor=='middle': x -= textLen/2. elif text_anchor=='numeric': x -= numericXShift(text_anchor,s,textLen,self._font,self._fontSize) else: raise ValueError('bad value for text_anchor ' + str(text_anchor)) s = self._escape(s) st = self._formatStyle(TEXT_STYLES) if angle != 0: st = st + " rotate(%s);" % self.fp_str(angle, x, y) if needFill: st += self._formatStyle(EXTRA_FILL_STYLES) else: st += " fill:none;" if needStroke: st += self._formatStyle(EXTRA_STROKE_STYLES) else: st += " stroke:none;" #if textRenderMode>=4: # _gstate_clipPathSetOrAddself, -1, 1, 0 /*we are adding*/ text = transformNode(self.doc, "text", x=x, y=y, style=st, transform="translate(0,%d) scale(1,-1)" % (2*y), **_svgAttrs ) content = self.doc.createTextNode(s) text.appendChild(content) if link_info: text = self._add_link(text, link_info) self.currGroup.appendChild(text) def drawCentredString(self, s, x, y, angle=0, text_anchor='middle', link_info=None, textRenderMode=0, **_svgAttrs): if self.verbose: print("+++ SVGCanvas.drawCentredString") self.drawString(s,x,y,angle=angle, link_info=link_info, text_anchor=text_anchor, textRenderMode=textRenderMode, **_svgAttrs) def drawRightString(self, text, x, y, angle=0,text_anchor='end', link_info=None, textRenderMode=0, **_svgAttrs): if self.verbose: print("+++ SVGCanvas.drawRightString") self.drawString(text,x,y,angle=angle, link_info=link_info, text_anchor=text_anchor, textRenderMode=textRenderMode, **_svgAttrs) def comment(self, data): "Add a comment." comment = self.doc.createComment(data) # self.currGroup.appendChild(comment) def drawImage(self, image, x, y, width, height, embed=True): buf = BytesIO() image.save(buf,'png') buf = asNative(base64.b64encode(buf.getvalue())) self.currGroup.appendChild( transformNode(self.doc,'image', x=x,y=y,width=width,height=height, href="data:image/png;base64,"+buf, transform="matrix(%s)" % self.cfp_str(1,0,0,-1,0,height+2*y), ) ) def line(self, x1, y1, x2, y2): if self._strokeColor != None: if 0: # something is wrong with line in my SVG viewer... line = transformNode(self.doc, "line", x=x1, y=y1, x2=x2, y2=y2, style=self._formatStyle(LINE_STYLES)) self.currGroup.appendChild(line) path = transformNode(self.doc, "path", d="M %s L %s Z" % (self.cfp_str(x1,y1),self.cfp_str(x2,y2)), style=self._formatStyle(LINE_STYLES)) self.currGroup.appendChild(path) def ellipse(self, x1, y1, x2, y2, link_info=None): """Draw an orthogonal ellipse inscribed within the rectangle x1,y1,x2,y2. These should have x1=180, 0, cfp_str(mx, my))) else: s("M %s A %s %d %d %d %s Z" % \ (cfp_str(mx, my), cfp_str(rx, ry), 0, extent>=180, 0, cfp_str(mx, my))) if fromcenter: s("L %s Z" % cfp_str(cx, cy)) path = transformNode(self.doc, "path", d=' '.join(s.__self__), style=self._formatStyle()) self.currGroup.appendChild(path) def polygon(self, points, closed=0, link_info=None): assert len(points) >= 2, 'Polygon must have 2 or more points' if self._strokeColor!=None or self._fillColor!=None: pts = ', '.join([fp_str(*p) for p in points]) polyline = transformNode(self.doc, "polygon", points=pts, style=self._formatStyle(AREA_STYLES)) if link_info: polyline = self._add_link(polyline, link_info) self.currGroup.appendChild(polyline) # self._fillAndStroke(polyCode) def lines(self, lineList, color=None, width=None): # print "### lineList", lineList return if self._strokeColor != None: codeline = '%s m %s l stroke' for line in lineList: self.code.append(codeline % (fp_str(line[0]), fp_str(line[1]))) def polyLine(self, points): assert len(points) >= 1, 'Polyline must have 1 or more points' if self._strokeColor != None: pts = ', '.join([fp_str(*p) for p in points]) polyline = transformNode(self.doc, "polyline", points=pts, style=self._formatStyle(AREA_STYLES,fill=None)) self.currGroup.appendChild(polyline) ### groups ### def startGroup(self,attrDict=dict(transform="")): if self.verbose: print("+++ begin SVGCanvas.startGroup") currGroup = self.currGroup group = transformNode(self.doc, "g", **attrDict) currGroup.appendChild(group) self.currGroup = group if self.verbose: print("+++ end SVGCanvas.startGroup") return currGroup def endGroup(self,currGroup): if self.verbose: print("+++ begin SVGCanvas.endGroup") self.currGroup = currGroup if self.verbose: print("+++ end SVGCanvas.endGroup") def transform(self, a, b, c, d, e, f): if self.verbose: print("!!! begin SVGCanvas.transform", a, b, c, d, e, f) tr = self.currGroup.getAttribute("transform") if (a, b, c, d, e, f) != (1, 0, 0, 1, 0, 0): t = 'matrix(%s)' % self.cfp_str(a,b,c,d,e,f) self.currGroup.setAttribute("transform", "%s %s" % (tr, t)) def translate(self, x, y): if (x,y) != (0,0): self.currGroup.setAttribute("transform", "%s %s" % (self.currGroup.getAttribute("transform"), 'translate(%s)' % self.cfp_str(x,y))) def scale(self, sx, sy): if (sx,sy) != (1,1): self.currGroup.setAttribute("transform", "%s %s" % (self.groups[-1].getAttribute("transform"), 'scale(%s)' % self.cfp_str(sx, sy))) ### paths ### def moveTo(self, x, y): self.path = self.path + 'M %s ' % self.fp_str(x, y) def lineTo(self, x, y): self.path = self.path + 'L %s ' % self.fp_str(x, y) def curveTo(self, x1, y1, x2, y2, x3, y3): self.path = self.path + 'C %s ' % self.fp_str(x1, y1, x2, y2, x3, y3) def closePath(self): self.path = self.path + 'Z ' def saveState(self): pass def restoreState(self): pass class _SVGRenderer(Renderer): """This draws onto an SVG document. """ def __init__(self): self.verbose = 0 def drawNode(self, node): """This is the recursive method called for each node in the tree. """ if self.verbose: print("### begin _SVGRenderer.drawNode(%r)" % node) self._canvas.comment('begin node %r'%node) style = self._canvas.style.copy() if not (isinstance(node, Path) and node.isClipPath): pass # self._canvas.saveState() #apply state changes deltas = getStateDelta(node) self._tracker.push(deltas) self.applyStateChanges(deltas, {}) #draw the object, or recurse self.drawNodeDispatcher(node) rDeltas = self._tracker.pop() if not (isinstance(node, Path) and node.isClipPath): pass #self._canvas.restoreState() self._canvas.comment('end node %r'%node) #restore things we might have lost (without actually doing anything). for k, v in rDeltas.items(): if k in self._restores: setattr(self._canvas,self._restores[k],v) self._canvas.style = style if self.verbose: print("### end _SVGRenderer.drawNode(%r)" % node) _restores = {'strokeColor':'_strokeColor','strokeWidth': '_lineWidth','strokeLineCap':'_lineCap', 'strokeLineJoin':'_lineJoin','fillColor':'_fillColor','fontName':'_font', 'fontSize':'_fontSize'} def _get_link_info_dict(self, obj): #We do not want None or False as the link, even if it is the #attribute's value - use the empty string instead. url = getattr(obj, "hrefURL", "") or "" title = getattr(obj, "hrefTitle", "") or "" if url : #Is it valid to have a link with no href? The XML requires #the xlink:href to be present, but you might just want a #tool tip shown (via the xlink:title attribute). Note that #giving an href of "" is equivalent to "the current page" #(a relative link saying go nowhere). return {"xlink:href":url, "xlink:title":title, "target":"_top"} #Currently of all the mainstream browsers I have tested, only Safari/webkit #will show SVG images embedded in HTML using a simple tag. #However, the links don't work (Safari 3.2.1 on the Mac). # #Therefore I use the following, which also works for Firefox, Opera, and #IE 6.0 with Adobe SVG Viewer 6 beta: # # #Once displayed, Firefox and Safari treat the SVG like a frame, and #by default clicking on links acts "in frame" and replaces the image. #Opera does what I expect, and replaces the whole page with the link. # #Therefore I use target="_top" to force the links to replace the whole page. #This now works as expected on Safari 3.2.1, Firefox 3.0.6, Opera 9.20. #Perhaps the target attribute should be an option, perhaps defaulting to #"_top" as used here? else : return None def drawGroup(self, group): if self.verbose: print("### begin _SVGRenderer.drawGroup") currGroup = self._canvas.startGroup() a, b, c, d, e, f = self._tracker.getState()['transform'] for childNode in group.getContents(): if isinstance(childNode, UserNode): node2 = childNode.provideNode() else: node2 = childNode self.drawNode(node2) self._canvas.transform(a, b, c, d, e, f) self._canvas.endGroup(currGroup) if self.verbose: print("### end _SVGRenderer.drawGroup") def drawRect(self, rect): link_info = self._get_link_info_dict(rect) svgAttrs = getattr(rect,'_svgAttrs',{}) if rect.rx == rect.ry == 0: #plain old rectangle self._canvas.rect( rect.x, rect.y, rect.x+rect.width, rect.y+rect.height, link_info=link_info, **svgAttrs) else: #cheat and assume ry = rx; better to generalize #pdfgen roundRect function. TODO self._canvas.roundRect( rect.x, rect.y, rect.x+rect.width, rect.y+rect.height, rect.rx, rect.ry, link_info=link_info, **svgAttrs) def drawString(self, stringObj): S = self._tracker.getState() text_anchor, x, y, text = S['textAnchor'], stringObj.x, stringObj.y, stringObj.text self._canvas.drawString(text,x,y,link_info=self._get_link_info_dict(stringObj), text_anchor=text_anchor, textRenderMode=getattr(stringObj,'textRenderMode',0), **getattr(stringObj,'_svgAttrs',{})) def drawLine(self, line): if self._canvas._strokeColor: self._canvas.line(line.x1, line.y1, line.x2, line.y2) def drawCircle(self, circle): self._canvas.circle( circle.cx, circle.cy, circle.r, link_info=self._get_link_info_dict(circle)) def drawWedge(self, wedge): yradius, radius1, yradius1 = wedge._xtraRadii() if (radius1==0 or radius1 is None) and (yradius1==0 or yradius1 is None) and not wedge.annular: centerx, centery, radius, startangledegrees, endangledegrees = \ wedge.centerx, wedge.centery, wedge.radius, wedge.startangledegrees, wedge.endangledegrees yradius = wedge.yradius or wedge.radius (x1, y1) = (centerx-radius, centery-yradius) (x2, y2) = (centerx+radius, centery+yradius) extent = endangledegrees - startangledegrees self._canvas.drawArc(x1, y1, x2, y2, startangledegrees, extent, fromcenter=1) else: P = wedge.asPolygon() if isinstance(P,Path): self.drawPath(P) else: self.drawPolygon(P) def drawPolyLine(self, p): if self._canvas._strokeColor: self._canvas.polyLine(_pointsFromList(p.points)) def drawEllipse(self, ellipse): #need to convert to pdfgen's bounding box representation x1 = ellipse.cx - ellipse.rx x2 = ellipse.cx + ellipse.rx y1 = ellipse.cy - ellipse.ry y2 = ellipse.cy + ellipse.ry self._canvas.ellipse(x1,y1,x2,y2, link_info=self._get_link_info_dict(ellipse)) def drawPolygon(self, p): self._canvas.polygon(_pointsFromList(p.points), closed=1, link_info=self._get_link_info_dict(p)) def drawPath(self, path, fillMode=FILL_EVEN_ODD): # print "### drawPath", path.points from reportlab.graphics.shapes import _renderPath c = self._canvas drawFuncs = (c.moveTo, c.lineTo, c.curveTo, c.closePath) if fillMode is None: fillMode = getattr(path,'fillMode',FILL_EVEN_ODD) link_info = self._get_link_info_dict(path) autoclose = getattr(path,'autoclose','') def rP(**kwds): return _renderPath(path, drawFuncs, **kwds) if autoclose=='svg': rP() c._fillAndStroke([], clip=path.isClipPath, link_info=link_info, fillMode=fillMode) elif autoclose=='pdf': rP(forceClose=True) c._fillAndStroke([], clip=path.isClipPath, link_info=link_info, fillMode=fillMode) else: isClosed = rP() if not isClosed: ofc = c._fillColor c.setFillColor(None) try: link_info = None c._fillAndStroke([], clip=path.isClipPath, link_info=link_info, fillMode=fillMode) finally: c.setFillColor(ofc) else: c._fillAndStroke([], clip=path.isClipPath, link_info=link_info, fillMode=fillMode) def drawImage(self, image): path = image.path if isinstance(path,str): if not (path and os.path.isfile(path)): return im = _getImage().open(path) elif hasattr(path,'convert'): im = path else: return srcW, srcH = im.size dstW, dstH = image.width, image.height if dstW is None: dstW = srcW if dstH is None: dstH = srcH self._canvas.drawImage(im, image.x, image.y, dstW, dstH, embed=True) def applyStateChanges(self, delta, newState): """This takes a set of states, and outputs the operators needed to set those properties""" for key, value in delta.items(): if key == 'transform': pass #self._canvas.transform(value[0], value[1], value[2], value[3], value[4], value[5]) elif key == 'strokeColor': self._canvas.setStrokeColor(value) elif key == 'strokeWidth': self._canvas.setLineWidth(value) elif key == 'strokeLineCap': #0,1,2 self._canvas.setLineCap(value) elif key == 'strokeLineJoin': self._canvas.setLineJoin(value) elif key == 'strokeDashArray': if value: if isinstance(value,(list,tuple)) and len(value)==2 and isinstance(value[1],(tuple,list)): phase = value[0] value = value[1] else: phase = 0 self._canvas.setDash(value,phase) else: self._canvas.setDash() elif key == 'fillColor': self._canvas.setFillColor(value) elif key in ['fontSize', 'fontName']: fontname = delta.get('fontName', self._canvas._font) fontsize = delta.get('fontSize', self._canvas._fontSize) self._canvas.setFont(fontname, fontsize) elif key == 'fillMode': self._canvas.setFillMode(value) def test(outDir='out-svg'): # print all drawings and their doc strings from the test # file if not os.path.isdir(outDir): os.mkdir(outDir) #grab all drawings from the test module from reportlab.graphics import testshapes drawings = [] for funcname in dir(testshapes): if funcname[0:10] == 'getDrawing': func = getattr(testshapes,funcname) drawing = func() docstring = getattr(func,'__doc__','') drawings.append((drawing, docstring)) i = 0 for (d, docstring) in drawings: filename = os.path.join(outDir,'renderSVG_%d.svg' % i) drawToFile(d, filename) i += 1 from reportlab.graphics.testshapes import getDrawing01 d = getDrawing01() drawToFile(d, os.path.join(outDir,"test.svg")) from reportlab.lib.corp import RL_CorpLogo from reportlab.graphics.shapes import Drawing rl = RL_CorpLogo() d = Drawing(rl.width,rl.height) d.add(rl) drawToFile(d, os.path.join(outDir,"corplogo.svg")) if __name__=='__main__': test() ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1691062243.0 reportlab-4.1.0/src/reportlab/graphics/renderbase.py0000664000175000017500000003103414462707743022166 0ustar00rptlabrptlab#Copyright ReportLab Europe Ltd. 2000-2021 #see license.txt for license details #history https://hg.reportlab.com/hg-public/reportlab/log/tip/src/reportlab/graphics/renderbase.py __version__='3.3.0' __doc__='''Superclass for renderers to factor out common functionality and default implementations.''' from reportlab.graphics.shapes import * from reportlab.lib.validators import DerivedValue from reportlab import rl_config from . transform import mmult, inverse def getStateDelta(shape): """Used to compute when we need to change the graphics state. For example, if we have two adjacent red shapes we don't need to set the pen color to red in between. Returns the effect the given shape would have on the graphics state""" delta = {} for prop, value in shape.getProperties().items(): if prop in STATE_DEFAULTS: delta[prop] = value return delta class StateTracker: """Keeps a stack of transforms and state properties. It can contain any properties you want, but the keys 'transform' and 'ctm' have special meanings. The getCTM() method returns the current transformation matrix at any point, without needing to invert matrixes when you pop.""" def __init__(self, defaults=None, defaultObj=None): # one stack to keep track of what changes... self._deltas = [] # and another to keep track of cumulative effects. Last one in # list is the current graphics state. We put one in to simplify # loops below. self._combined = [] if defaults is None: defaults = STATE_DEFAULTS.copy() if defaultObj: for k in STATE_DEFAULTS.keys(): a = 'initial'+k[:1].upper()+k[1:] if hasattr(defaultObj,a): defaults[k] = getattr(defaultObj,a) #ensure that if we have a transform, we have a CTM if 'transform' in defaults: defaults['ctm'] = defaults['transform'] self._combined.append(defaults) def _applyDefaultObj(self,d): return d def push(self,delta): """Take a new state dictionary of changes and push it onto the stack. After doing this, the combined state is accessible through getState()""" newstate = self._combined[-1].copy() for key, value in delta.items(): if key == 'transform': #do cumulative matrix newstate['transform'] = delta['transform'] newstate['ctm'] = mmult(self._combined[-1]['ctm'], delta['transform']) #print 'statetracker transform = (%0.2f, %0.2f, %0.2f, %0.2f, %0.2f, %0.2f)' % tuple(newstate['transform']) #print 'statetracker ctm = (%0.2f, %0.2f, %0.2f, %0.2f, %0.2f, %0.2f)' % tuple(newstate['ctm']) else: #just overwrite it newstate[key] = value self._combined.append(newstate) self._deltas.append(delta) def pop(self): """steps back one, and returns a state dictionary with the deltas to reverse out of wherever you are. Depending on your back end, you may not need the return value, since you can get the complete state afterwards with getState()""" del self._combined[-1] newState = self._combined[-1] lastDelta = self._deltas[-1] del self._deltas[-1] #need to diff this against the last one in the state reverseDelta = {} #print 'pop()...' for key, curValue in lastDelta.items(): #print ' key=%s, value=%s' % (key, curValue) prevValue = newState[key] if prevValue != curValue: #print ' state popping "%s"="%s"' % (key, curValue) if key == 'transform': reverseDelta[key] = inverse(lastDelta['transform']) else: #just return to previous state reverseDelta[key] = prevValue return reverseDelta def getState(self): "returns the complete graphics state at this point" return self._combined[-1] def getCTM(self): "returns the current transformation matrix at this point""" return self._combined[-1]['ctm'] def __getitem__(self,key): "returns the complete graphics state value of key at this point" return self._combined[-1][key] def __setitem__(self,key,value): "sets the complete graphics state value of key to value" self._combined[-1][key] = value def testStateTracker(): print('Testing state tracker') defaults = {'fillColor':None, 'strokeColor':None,'fontName':None, 'transform':[1,0,0,1,0,0]} from reportlab.graphics.shapes import _baseGFontName deltas = [ {'fillColor':'red'}, {'fillColor':'green', 'strokeColor':'blue','fontName':_baseGFontName}, {'transform':[0.5,0,0,0.5,0,0]}, {'transform':[0.5,0,0,0.5,2,3]}, {'strokeColor':'red'} ] st = StateTracker(defaults) print('initial:', st.getState()) print() for delta in deltas: print('pushing:', delta) st.push(delta) print('state: ',st.getState(),'\n') for delta in deltas: print('popping:',st.pop()) print('state: ',st.getState(),'\n') def _expandUserNode(node,canvas): if isinstance(node, UserNode): try: if hasattr(node,'_canvas'): ocanvas = 1 else: node._canvas = canvas ocanvas = None onode = node node = node.provideNode() finally: if not ocanvas: del onode._canvas return node def renderScaledDrawing(d): renderScale = d.renderScale if renderScale!=1.0: o = d d = d.__class__(o.width*renderScale,o.height*renderScale) d.__dict__ = o.__dict__.copy() d.scale(renderScale,renderScale) d.renderScale = 1.0 return d class Renderer: """Virtual superclass for graphics renderers.""" def undefined(self, operation): raise ValueError("%s operation not defined at superclass class=%s" %(operation, self.__class__)) def draw(self, drawing, canvas, x=0, y=0, showBoundary=rl_config._unset_): """This is the top level function, which draws the drawing at the given location. The recursive part is handled by drawNode.""" self._tracker = StateTracker(defaultObj=drawing) #stash references for ease of communication if showBoundary is rl_config._unset_: showBoundary=rl_config.showBoundary self._canvas = canvas canvas.__dict__['_drawing'] = self._drawing = drawing drawing._parent = None try: #bounding box if showBoundary: if hasattr(canvas,'drawBoundary'): canvas.drawBoundary(showBoundary,x,y,drawing.width,drawing.height) else: canvas.rect(x, y, drawing.width, drawing.height) canvas.saveState() self.initState(x,y) #this is the push() self.drawNode(drawing) self.pop() canvas.restoreState() finally: #remove any circular references del self._canvas, self._drawing, canvas._drawing, drawing._parent, self._tracker def initState(self,x,y): deltas = self._tracker._combined[-1] deltas['transform'] = tuple(list(deltas['transform'])[:4])+(x,y) self._tracker.push(deltas) self.applyStateChanges(deltas, {}) def pop(self): self._tracker.pop() def drawNode(self, node): """This is the recursive method called for each node in the tree""" # Undefined here, but with closer analysis probably can be handled in superclass self.undefined("drawNode") def getStateValue(self, key): """Return current state parameter for given key""" currentState = self._tracker._combined[-1] return currentState[key] def fillDerivedValues(self, node): """Examine a node for any values which are Derived, and replace them with their calculated values. Generally things may look at the drawing or their parent. """ for key, value in node.__dict__.items(): if isinstance(value, DerivedValue): #just replace with default for key? #print ' fillDerivedValues(%s)' % key newValue = value.getValue(self, key) #print ' got value of %s' % newValue node.__dict__[key] = newValue def drawNodeDispatcher(self, node): """dispatch on the node's (super) class: shared code""" canvas = getattr(self,'_canvas',None) # replace UserNode with its contents try: node = _expandUserNode(node,canvas) if not node: return if hasattr(node,'_canvas'): ocanvas = 1 else: node._canvas = canvas ocanvas = None self.fillDerivedValues(node) dtcb = getattr(node,'_drawTimeCallback',None) if dtcb: dtcb(node,canvas=canvas,renderer=self) #draw the object, or recurse if isinstance(node, Line): self.drawLine(node) elif isinstance(node, Image): self.drawImage(node) elif isinstance(node, Rect): self.drawRect(node) elif isinstance(node, Circle): self.drawCircle(node) elif isinstance(node, Ellipse): self.drawEllipse(node) elif isinstance(node, PolyLine): self.drawPolyLine(node) elif isinstance(node, Polygon): self.drawPolygon(node) elif isinstance(node, Path): self.drawPath(node) elif isinstance(node, String): self.drawString(node) elif isinstance(node, Group): self.drawGroup(node) elif isinstance(node, Wedge): self.drawWedge(node) elif isinstance(node, DirectDraw): node.drawDirectly(self) else: print('DrawingError','Unexpected element %s in drawing!' % str(node)) finally: if not ocanvas: del node._canvas _restores = {'stroke':'_stroke','stroke_width': '_lineWidth','stroke_linecap':'_lineCap', 'stroke_linejoin':'_lineJoin','fill':'_fill','font_family':'_font', 'font_size':'_fontSize'} def drawGroup(self, group): # just do the contents. Some renderers might need to override this # if they need a flipped transform canvas = getattr(self,'_canvas',None) for node in group.getContents(): node = _expandUserNode(node,canvas) if not node: continue #here is where we do derived values - this seems to get everything. Touch wood. self.fillDerivedValues(node) try: if hasattr(node,'_canvas'): ocanvas = 1 else: node._canvas = canvas ocanvas = None node._parent = group self.drawNode(node) finally: del node._parent if not ocanvas: del node._canvas def drawWedge(self, wedge): # by default ask the wedge to make a polygon of itself and draw that! #print "drawWedge" P = wedge.asPolygon() if isinstance(P,Path): self.drawPath(P) else: self.drawPolygon(P) def drawPath(self, path): polygons = path.asPolygons() for polygon in polygons: self.drawPolygon(polygon) def drawRect(self, rect): # could be implemented in terms of polygon self.undefined("drawRect") def drawLine(self, line): self.undefined("drawLine") def drawCircle(self, circle): self.undefined("drawCircle") def drawPolyLine(self, p): self.undefined("drawPolyLine") def drawEllipse(self, ellipse): self.undefined("drawEllipse") def drawPolygon(self, p): self.undefined("drawPolygon") def drawString(self, stringObj): self.undefined("drawString") def applyStateChanges(self, delta, newState): """This takes a set of states, and outputs the operators needed to set those properties""" self.undefined("applyStateChanges") def drawImage(self,*args,**kwds): raise NotImplementedError('drawImage') if __name__=='__main__': print("this file has no script interpretation") print(__doc__) ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707393948.4105587 reportlab-4.1.0/src/reportlab/graphics/samples/0000775000175000017500000000000014561141634021134 5ustar00rptlabrptlab././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1691062243.0 reportlab-4.1.0/src/reportlab/graphics/samples/__init__.py0000664000175000017500000000010514462707743023252 0ustar00rptlabrptlab__doc__="""Example drawings to review, used in autogenerated docs""" ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1691062243.0 reportlab-4.1.0/src/reportlab/graphics/samples/bubble.py0000664000175000017500000000700014462707743022747 0ustar00rptlabrptlab#Autogenerated by ReportLab guiedit do not edit from reportlab.graphics.charts.legends import Legend from reportlab.graphics.charts.lineplots import ScatterPlot from reportlab.graphics.shapes import Drawing, _DrawingEditorMixin from reportlab.graphics.charts.textlabels import Label from reportlab.graphics.samples.excelcolors import * class Bubble(_DrawingEditorMixin,Drawing): def __init__(self,width=200,height=150,*args,**kw): Drawing.__init__(self,width,height,*args,**kw) self._add(self,ScatterPlot(),name='chart',validate=None,desc="The main chart") self.chart.width = 115 self.chart.height = 80 self.chart.x = 30 self.chart.y = 40 self.chart.lines[0].strokeColor = color01 self.chart.lines[1].strokeColor = color02 self.chart.lines[2].strokeColor = color03 self.chart.lines[3].strokeColor = color04 self.chart.lines[4].strokeColor = color05 self.chart.lines[5].strokeColor = color06 self.chart.lines[6].strokeColor = color07 self.chart.lines[7].strokeColor = color08 self.chart.lines[8].strokeColor = color09 self.chart.lines[9].strokeColor = color10 self.chart.lines.symbol.kind ='Circle' self.chart.lines.symbol.size = 15 self.chart.fillColor = backgroundGrey self.chart.lineLabels.fontName = 'Helvetica' self.chart.xValueAxis.labels.fontName = 'Helvetica' self.chart.xValueAxis.labels.fontSize = 7 self.chart.xValueAxis.forceZero = 0 self.chart.data = [((100,100), (200,200), (250,210), (300,300), (350,450))] self.chart.xValueAxis.avoidBoundFrac = 1 self.chart.xValueAxis.gridEnd = 115 self.chart.xValueAxis.tickDown = 3 self.chart.xValueAxis.visibleGrid = 1 self.chart.yValueAxis.tickLeft = 3 self.chart.yValueAxis.labels.fontName = 'Helvetica' self.chart.yValueAxis.labels.fontSize = 7 self._add(self,Label(),name='Title',validate=None,desc="The title at the top of the chart") self.Title.fontName = 'Helvetica-Bold' self.Title.fontSize = 7 self.Title.x = 100 self.Title.y = 135 self.Title._text = 'Chart Title' self.Title.maxWidth = 180 self.Title.height = 20 self.Title.textAnchor ='middle' self._add(self,Legend(),name='Legend',validate=None,desc="The legend or key for the chart") self.Legend.colorNamePairs = [(color01, 'Widgets')] self.Legend.fontName = 'Helvetica' self.Legend.fontSize = 7 self.Legend.x = 153 self.Legend.y = 85 self.Legend.dxTextSpace = 5 self.Legend.dy = 5 self.Legend.dx = 5 self.Legend.deltay = 5 self.Legend.alignment ='right' self.chart.lineLabelFormat = None self.chart.xLabel = 'X Axis' self.chart.y = 30 self.chart.yLabel = 'Y Axis' self.chart.yValueAxis.labelTextFormat = '%d' self.chart.yValueAxis.forceZero = 1 self.chart.xValueAxis.forceZero = 1 self._add(self,0,name='preview',validate=None,desc=None) if __name__=="__main__": #NORUNTESTS Bubble().save(formats=['pdf'],outDir=None,fnRoot='bubble') ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1691062243.0 reportlab-4.1.0/src/reportlab/graphics/samples/clustered_bar.py0000664000175000017500000001022114462707743024331 0ustar00rptlabrptlab#Autogenerated by ReportLab guiedit do not edit from reportlab.graphics.charts.legends import Legend from reportlab.graphics.samples.excelcolors import * from reportlab.graphics.charts.barcharts import HorizontalBarChart from reportlab.graphics.shapes import Drawing, _DrawingEditorMixin from reportlab.graphics.charts.textlabels import Label class ClusteredBar(_DrawingEditorMixin,Drawing): def __init__(self,width=200,height=150,*args,**kw): Drawing.__init__(self,width,height,*args,**kw) self._add(self,HorizontalBarChart(),name='chart',validate=None,desc="The main chart") self.chart.width = 115 self.chart.height = 80 self.chart.x = 30 self.chart.y = 40 self.chart.bars[0].fillColor = color01 self.chart.bars[1].fillColor = color02 self.chart.bars[2].fillColor = color03 self.chart.bars[3].fillColor = color04 self.chart.bars[4].fillColor = color05 self.chart.bars[5].fillColor = color06 self.chart.bars[6].fillColor = color07 self.chart.bars[7].fillColor = color08 self.chart.bars[8].fillColor = color09 self.chart.bars[9].fillColor = color10 self.chart.fillColor = backgroundGrey self.chart.barLabels.fontName = 'Helvetica' self.chart.valueAxis.labels.fontName = 'Helvetica' self.chart.valueAxis.labels.fontSize = 6 self.chart.valueAxis.forceZero = 1 self.chart.data = [(100, 150, 180), (125, 180, 200)] self.chart.groupSpacing = 15 self.chart.valueAxis.avoidBoundFrac = 1 self.chart.valueAxis.gridEnd = 80 self.chart.valueAxis.tickDown = 3 self.chart.valueAxis.visibleGrid = 1 self.chart.categoryAxis.categoryNames = ['North', 'South', 'Central'] self.chart.categoryAxis.tickLeft = 3 self.chart.categoryAxis.labels.fontName = 'Helvetica' self.chart.categoryAxis.labels.fontSize = 6 self.chart.categoryAxis.labels.dx = -3 self._add(self,Label(),name='Title',validate=None,desc="The title at the top of the chart") self.Title.fontName = 'Helvetica-Bold' self.Title.fontSize = 7 self.Title.x = 100 self.Title.y = 135 self.Title._text = 'Chart Title' self.Title.maxWidth = 180 self.Title.height = 20 self.Title.textAnchor ='middle' self._add(self,Legend(),name='Legend',validate=None,desc="The legend or key for the chart") self.Legend.colorNamePairs = [(color01, 'Widgets'), (color02, 'Sprockets')] self.Legend.fontName = 'Helvetica' self.Legend.fontSize = 7 self.Legend.x = 153 self.Legend.y = 85 self.Legend.dxTextSpace = 5 self.Legend.dy = 5 self.Legend.dx = 5 self.Legend.deltay = 5 self.Legend.alignment ='right' self._add(self,Label(),name='XLabel',validate=None,desc="The label on the horizontal axis") self.XLabel.fontName = 'Helvetica' self.XLabel.fontSize = 7 self.XLabel.x = 85 self.XLabel.y = 10 self.XLabel.textAnchor ='middle' self.XLabel.maxWidth = 100 self.XLabel.height = 20 self.XLabel._text = "X Axis" self._add(self,Label(),name='YLabel',validate=None,desc="The label on the vertical axis") self.YLabel.fontName = 'Helvetica' self.YLabel.fontSize = 7 self.YLabel.x = 12 self.YLabel.y = 80 self.YLabel.angle = 90 self.YLabel.textAnchor ='middle' self.YLabel.maxWidth = 100 self.YLabel.height = 20 self.YLabel._text = "Y Axis" self._add(self,0,name='preview',validate=None,desc=None) if __name__=="__main__": #NORUNTESTS ClusteredBar().save(formats=['pdf'],outDir=None,fnRoot='clustered_bar') ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1691062243.0 reportlab-4.1.0/src/reportlab/graphics/samples/clustered_column.py0000664000175000017500000001013414462707743025065 0ustar00rptlabrptlab#Autogenerated by ReportLab guiedit do not edit from reportlab.graphics.charts.legends import Legend from reportlab.graphics.samples.excelcolors import * from reportlab.graphics.charts.barcharts import VerticalBarChart from reportlab.graphics.shapes import Drawing, _DrawingEditorMixin from reportlab.graphics.charts.textlabels import Label class ClusteredColumn(_DrawingEditorMixin,Drawing): def __init__(self,width=200,height=150,*args,**kw): Drawing.__init__(self,width,height,*args,**kw) self._add(self,VerticalBarChart(),name='chart',validate=None,desc="The main chart") self.chart.width = 115 self.chart.height = 80 self.chart.x = 30 self.chart.y = 40 self.chart.bars[0].fillColor = color01 self.chart.bars[1].fillColor = color02 self.chart.bars[2].fillColor = color03 self.chart.bars[3].fillColor = color04 self.chart.bars[4].fillColor = color05 self.chart.bars[5].fillColor = color06 self.chart.bars[6].fillColor = color07 self.chart.bars[7].fillColor = color08 self.chart.bars[8].fillColor = color09 self.chart.bars[9].fillColor = color10 self.chart.fillColor = backgroundGrey self.chart.barLabels.fontName = 'Helvetica' self.chart.valueAxis.labels.fontName = 'Helvetica' self.chart.valueAxis.labels.fontSize = 7 self.chart.valueAxis.forceZero = 1 self.chart.data = [(100, 150, 180), (125, 180, 200)] self.chart.groupSpacing = 15 self.chart.valueAxis.avoidBoundFrac = 1 self.chart.valueAxis.gridEnd = 115 self.chart.valueAxis.tickLeft = 3 self.chart.valueAxis.visibleGrid = 1 self.chart.categoryAxis.categoryNames = ['North', 'South', 'Central'] self.chart.categoryAxis.tickDown = 3 self.chart.categoryAxis.labels.fontName = 'Helvetica' self.chart.categoryAxis.labels.fontSize = 7 self._add(self,Label(),name='Title',validate=None,desc="The title at the top of the chart") self.Title.fontName = 'Helvetica-Bold' self.Title.fontSize = 7 self.Title.x = 100 self.Title.y = 135 self.Title._text = 'Chart Title' self.Title.maxWidth = 180 self.Title.height = 20 self.Title.textAnchor ='middle' self._add(self,Legend(),name='Legend',validate=None,desc="The legend or key for the chart") self.Legend.colorNamePairs = [(color01, 'Widgets'), (color02, 'Sprockets')] self.Legend.fontName = 'Helvetica' self.Legend.fontSize = 7 self.Legend.x = 153 self.Legend.y = 85 self.Legend.dxTextSpace = 5 self.Legend.dy = 5 self.Legend.dx = 5 self.Legend.deltay = 5 self.Legend.alignment ='right' self._add(self,Label(),name='XLabel',validate=None,desc="The label on the horizontal axis") self.XLabel.fontName = 'Helvetica' self.XLabel.fontSize = 7 self.XLabel.x = 85 self.XLabel.y = 10 self.XLabel.textAnchor ='middle' self.XLabel.maxWidth = 100 self.XLabel.height = 20 self.XLabel._text = "X Axis" self._add(self,Label(),name='YLabel',validate=None,desc="The label on the vertical axis") self.YLabel.fontName = 'Helvetica' self.YLabel.fontSize = 7 self.YLabel.x = 12 self.YLabel.y = 80 self.YLabel.angle = 90 self.YLabel.textAnchor ='middle' self.YLabel.maxWidth = 100 self.YLabel.height = 20 self.YLabel._text = "Y Axis" self._add(self,0,name='preview',validate=None,desc=None) if __name__=="__main__": #NORUNTESTS ClusteredColumn().save(formats=['pdf'],outDir=None,fnRoot='clustered_column') ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1691062243.0 reportlab-4.1.0/src/reportlab/graphics/samples/excelcolors.py0000664000175000017500000000363314462707743024046 0ustar00rptlabrptlab# define standard colors to mimic those used by Microsoft Excel from reportlab.lib.colors import PCMYKColor #colour names as comments at the end of each line are as a memory jogger ONLY #NOT HTML named colours! #Main colours as used for bars etc color01 = PCMYKColor(40,40,0,0) # Lavender color02 = PCMYKColor(0,66,33,39) # Maroon color03 = PCMYKColor(0,0,20,0) # Yellow color04 = PCMYKColor(20,0,0,0) # Cyan color05 = PCMYKColor(0,100,0,59) # Purple color06 = PCMYKColor(0,49,49,0) # Salmon color07 = PCMYKColor(100,49,0,19) # Blue color08 = PCMYKColor(20,20,0,0) # PaleLavender color09 = PCMYKColor(100,100,0,49) # NavyBlue color10 = PCMYKColor(0,100,0,0) # Purple #Highlight colors - eg for the tops of bars color01Light = PCMYKColor(39,39,0,25) # Light Lavender color02Light = PCMYKColor(0,66,33,54) # Light Maroon color03Light = PCMYKColor(0,0,19,25) # Light Yellow color04Light = PCMYKColor(19,0,0,25) # Light Cyan color05Light = PCMYKColor(0,100,0,69) # Light Purple color06Light = PCMYKColor(0,49,49,25) # Light Salmon color07Light = PCMYKColor(100,49,0,39) # Light Blue color08Light = PCMYKColor(19,19,0,25) # Light PaleLavender color09Light = PCMYKColor(100,100,0,62) # Light NavyBlue color10Light = PCMYKColor(0,100,0,25) # Light Purple #Lowlight colors - eg for the sides of bars color01Dark = PCMYKColor(39,39,0,49) # Dark Lavender color02Dark = PCMYKColor(0,66,33,69) # Dark Maroon color03Dark = PCMYKColor(0,0,20,49) # Dark Yellow color04Dark = PCMYKColor(20,0,0,49) # Dark Cyan color05Dark = PCMYKColor(0,100,0,80) # Dark Purple color06Dark = PCMYKColor(0,50,50,49) # Dark Salmon color07Dark = PCMYKColor(100,50,0,59) # Dark Blue color08Dark = PCMYKColor(20,20,0,49) # Dark PaleLavender color09Dark = PCMYKColor(100,100,0,79) # Dark NavyBlue color10Dark = PCMYKColor(0,100,0,49) # Dark Purple #for standard grey backgrounds backgroundGrey = PCMYKColor(0,0,0,24) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1691062243.0 reportlab-4.1.0/src/reportlab/graphics/samples/exploded_pie.py0000664000175000017500000000606614462707743024170 0ustar00rptlabrptlab#Autogenerated by ReportLab guiedit do not edit from reportlab.graphics.charts.piecharts import Pie from reportlab.graphics.samples.excelcolors import * from reportlab.graphics.widgets.grids import ShadedRect from reportlab.graphics.charts.legends import Legend from reportlab.graphics.shapes import Drawing, _DrawingEditorMixin from reportlab.graphics.charts.textlabels import Label class ExplodedPie(_DrawingEditorMixin,Drawing): def __init__(self,width=200,height=150,*args,**kw): Drawing.__init__(self,width,height,*args,**kw) self._add(self,Pie(),name='chart',validate=None,desc="The main chart") self.chart.width = 100 self.chart.height = 100 self.chart.x = 25 self.chart.y = 25 self.chart.slices[0].fillColor = color01 self.chart.slices[1].fillColor = color02 self.chart.slices[2].fillColor = color03 self.chart.slices[3].fillColor = color04 self.chart.slices[4].fillColor = color05 self.chart.slices[5].fillColor = color06 self.chart.slices[6].fillColor = color07 self.chart.slices[7].fillColor = color08 self.chart.slices[8].fillColor = color09 self.chart.slices[9].fillColor = color10 self.chart.data = (100, 150, 180) self.chart.startAngle = -90 self._add(self,Label(),name='Title',validate=None,desc="The title at the top of the chart") self.Title.fontName = 'Helvetica-Bold' self.Title.fontSize = 7 self.Title.x = 100 self.Title.y = 135 self.Title._text = 'Chart Title' self.Title.maxWidth = 180 self.Title.height = 20 self.Title.textAnchor ='middle' self._add(self,Legend(),name='Legend',validate=None,desc="The legend or key for the chart") self.Legend.colorNamePairs = [(color01, 'North'), (color02, 'South'), (color03, 'Central')] self.Legend.fontName = 'Helvetica' self.Legend.fontSize = 7 self.Legend.x = 160 self.Legend.y = 85 self.Legend.dxTextSpace = 5 self.Legend.dy = 5 self.Legend.dx = 5 self.Legend.deltay = 5 self.Legend.alignment ='right' self.Legend.columnMaximum = 10 self.chart.slices.strokeWidth = 1 self.chart.slices.fontName = 'Helvetica' self.background = ShadedRect() self.background.fillColorStart = backgroundGrey self.background.fillColorEnd = backgroundGrey self.background.numShades = 1 self.background.strokeWidth = 0.5 self.background.x = 20 self.background.y = 20 self.chart.slices.popout = 5 self.background.height = 110 self.background.width = 110 self._add(self,0,name='preview',validate=None,desc=None) if __name__=="__main__": #NORUNTESTS ExplodedPie().save(formats=['pdf'],outDir=None,fnRoot='exploded_pie') ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1691062243.0 reportlab-4.1.0/src/reportlab/graphics/samples/filled_radar.py0000664000175000017500000000520314462707743024127 0ustar00rptlabrptlab#Autogenerated by ReportLab guiedit do not edit from reportlab.graphics.charts.legends import Legend from reportlab.graphics.charts.spider import SpiderChart from reportlab.graphics.shapes import Drawing, _DrawingEditorMixin from reportlab.graphics.charts.textlabels import Label from reportlab.graphics.samples.excelcolors import * class FilledRadarChart(_DrawingEditorMixin,Drawing): def __init__(self,width=200,height=150,*args,**kw): Drawing.__init__(self,width,height,*args,**kw) self._add(self,SpiderChart(),name='chart',validate=None,desc="The main chart") self.chart.width = 90 self.chart.height = 90 self.chart.x = 45 self.chart.y = 25 self.chart.strands[0].fillColor = color01 self.chart.strands[1].fillColor = color02 self.chart.strands[2].fillColor = color03 self.chart.strands[3].fillColor = color04 self.chart.strands[4].fillColor = color05 self.chart.strands[5].fillColor = color06 self.chart.strands[6].fillColor = color07 self.chart.strands[7].fillColor = color08 self.chart.strands[8].fillColor = color09 self.chart.strands[9].fillColor = color10 self.chart.strandLabels.fontName = 'Helvetica' self.chart.strandLabels.fontSize = 6 self.chart.fillColor = backgroundGrey self.chart.data = [(125, 180, 200), (100, 150, 180)] self.chart.labels = ['North', 'South', 'Central'] self._add(self,Label(),name='Title',validate=None,desc="The title at the top of the chart") self.Title.fontName = 'Helvetica-Bold' self.Title.fontSize = 7 self.Title.x = 100 self.Title.y = 135 self.Title._text = 'Chart Title' self.Title.maxWidth = 180 self.Title.height = 20 self.Title.textAnchor ='middle' self._add(self,Legend(),name='Legend',validate=None,desc="The legend or key for the chart") self.Legend.colorNamePairs = [(color01, 'Widgets'), (color02, 'Sprockets')] self.Legend.fontName = 'Helvetica' self.Legend.fontSize = 7 self.Legend.x = 153 self.Legend.y = 85 self.Legend.dxTextSpace = 5 self.Legend.dy = 5 self.Legend.dx = 5 self.Legend.deltay = 5 self.Legend.alignment ='right' self._add(self,0,name='preview',validate=None,desc=None) if __name__=="__main__": #NORUNTESTS FilledRadarChart().save(formats=['pdf'],outDir=None,fnRoot='filled_radar') ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1691062243.0 reportlab-4.1.0/src/reportlab/graphics/samples/line_chart.py0000664000175000017500000001025314462707743023630 0ustar00rptlabrptlab#Autogenerated by ReportLab guiedit do not edit from reportlab.graphics.charts.legends import Legend from reportlab.graphics.charts.lineplots import LinePlot from reportlab.graphics.shapes import Drawing, _DrawingEditorMixin from reportlab.graphics.charts.textlabels import Label from reportlab.graphics.samples.excelcolors import * class LineChart(_DrawingEditorMixin,Drawing): def __init__(self,width=200,height=150,*args,**kw): Drawing.__init__(self,width,height,*args,**kw) self._add(self,LinePlot(),name='chart',validate=None,desc="The main chart") self.chart.width = 115 self.chart.height = 80 self.chart.x = 30 self.chart.y = 40 self.chart.lines[0].strokeColor = color01 self.chart.lines[1].strokeColor = color02 self.chart.lines[2].strokeColor = color03 self.chart.lines[3].strokeColor = color04 self.chart.lines[4].strokeColor = color05 self.chart.lines[5].strokeColor = color06 self.chart.lines[6].strokeColor = color07 self.chart.lines[7].strokeColor = color08 self.chart.lines[8].strokeColor = color09 self.chart.lines[9].strokeColor = color10 self.chart.fillColor = backgroundGrey self.chart.lineLabels.fontName = 'Helvetica' self.chart.xValueAxis.labels.fontName = 'Helvetica' self.chart.xValueAxis.labels.fontSize = 7 self.chart.xValueAxis.forceZero = 0 self.chart.data = [((0, 50), (100,100), (200,200), (250,210), (300,300), (400,500)), ((0, 150), (100,200), (200,300), (250,200), (300,400), (400, 600))] self.chart.xValueAxis.avoidBoundFrac = 1 self.chart.xValueAxis.gridEnd = 115 self.chart.xValueAxis.tickDown = 3 self.chart.xValueAxis.visibleGrid = 1 self.chart.yValueAxis.tickLeft = 3 self.chart.yValueAxis.labels.fontName = 'Helvetica' self.chart.yValueAxis.labels.fontSize = 7 self._add(self,Label(),name='Title',validate=None,desc="The title at the top of the chart") self.Title.fontName = 'Helvetica-Bold' self.Title.fontSize = 7 self.Title.x = 100 self.Title.y = 135 self.Title._text = 'Chart Title' self.Title.maxWidth = 180 self.Title.height = 20 self.Title.textAnchor ='middle' self._add(self,Legend(),name='Legend',validate=None,desc="The legend or key for the chart") self.Legend.colorNamePairs = [(color01, 'Widgets'), (color02, 'Sprockets')] self.Legend.fontName = 'Helvetica' self.Legend.fontSize = 7 self.Legend.x = 153 self.Legend.y = 85 self.Legend.dxTextSpace = 5 self.Legend.dy = 5 self.Legend.dx = 5 self.Legend.deltay = 5 self.Legend.alignment ='right' self._add(self,Label(),name='XLabel',validate=None,desc="The label on the horizontal axis") self.XLabel.fontName = 'Helvetica' self.XLabel.fontSize = 7 self.XLabel.x = 85 self.XLabel.y = 10 self.XLabel.textAnchor ='middle' self.XLabel.maxWidth = 100 self.XLabel.height = 20 self.XLabel._text = "X Axis" self._add(self,Label(),name='YLabel',validate=None,desc="The label on the vertical axis") self.YLabel.fontName = 'Helvetica' self.YLabel.fontSize = 7 self.YLabel.x = 12 self.YLabel.y = 80 self.YLabel.angle = 90 self.YLabel.textAnchor ='middle' self.YLabel.maxWidth = 100 self.YLabel.height = 20 self.YLabel._text = "Y Axis" self.chart.yValueAxis.forceZero = 1 self.chart.xValueAxis.forceZero = 1 self._add(self,0,name='preview',validate=None,desc=None) if __name__=="__main__": #NORUNTESTS LineChart().save(formats=['pdf'],outDir=None,fnRoot='line_chart') ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1691062243.0 reportlab-4.1.0/src/reportlab/graphics/samples/linechart_with_markers.py0000664000175000017500000001161714462707743026255 0ustar00rptlabrptlab#Autogenerated by ReportLab guiedit do not edit from reportlab.graphics.charts.legends import Legend from reportlab.graphics.charts.lineplots import LinePlot from reportlab.graphics.shapes import Drawing, _DrawingEditorMixin from reportlab.graphics.widgets.markers import makeMarker from reportlab.graphics.charts.textlabels import Label from reportlab.graphics.samples.excelcolors import * class LineChartWithMarkers(_DrawingEditorMixin,Drawing): def __init__(self,width=200,height=150,*args,**kw): Drawing.__init__(self,width,height,*args,**kw) self._add(self,LinePlot(),name='chart',validate=None,desc="The main chart") self.chart.width = 115 self.chart.height = 80 self.chart.x = 30 self.chart.y = 40 self.chart.lines[0].strokeColor = color01 self.chart.lines[1].strokeColor = color02 self.chart.lines[2].strokeColor = color03 self.chart.lines[3].strokeColor = color04 self.chart.lines[4].strokeColor = color05 self.chart.lines[5].strokeColor = color06 self.chart.lines[6].strokeColor = color07 self.chart.lines[7].strokeColor = color08 self.chart.lines[8].strokeColor = color09 self.chart.lines[9].strokeColor = color10 self.chart.lines[0].symbol = makeMarker('FilledSquare') self.chart.lines[1].symbol = makeMarker('FilledDiamond') self.chart.lines[2].symbol = makeMarker('FilledStarFive') self.chart.lines[3].symbol = makeMarker('FilledTriangle') self.chart.lines[4].symbol = makeMarker('FilledCircle') self.chart.lines[5].symbol = makeMarker('FilledPentagon') self.chart.lines[6].symbol = makeMarker('FilledStarSix') self.chart.lines[7].symbol = makeMarker('FilledHeptagon') self.chart.lines[8].symbol = makeMarker('FilledOctagon') self.chart.lines[9].symbol = makeMarker('FilledCross') self.chart.fillColor = backgroundGrey self.chart.lineLabels.fontName = 'Helvetica' self.chart.xValueAxis.labels.fontName = 'Helvetica' self.chart.xValueAxis.labels.fontSize = 7 self.chart.xValueAxis.forceZero = 0 self.chart.data = [((0, 50), (100,100), (200,200), (250,210), (300,300), (400,500)), ((0, 150), (100,200), (200,300), (250,200), (300,400), (400, 600))] self.chart.xValueAxis.avoidBoundFrac = 1 self.chart.xValueAxis.gridEnd = 115 self.chart.xValueAxis.tickDown = 3 self.chart.xValueAxis.visibleGrid = 1 self.chart.yValueAxis.tickLeft = 3 self.chart.yValueAxis.labels.fontName = 'Helvetica' self.chart.yValueAxis.labels.fontSize = 7 self._add(self,Label(),name='Title',validate=None,desc="The title at the top of the chart") self.Title.fontName = 'Helvetica-Bold' self.Title.fontSize = 7 self.Title.x = 100 self.Title.y = 135 self.Title._text = 'Chart Title' self.Title.maxWidth = 180 self.Title.height = 20 self.Title.textAnchor ='middle' self._add(self,Legend(),name='Legend',validate=None,desc="The legend or key for the chart") self.Legend.colorNamePairs = [(color01, 'Widgets'), (color02, 'Sprockets')] self.Legend.fontName = 'Helvetica' self.Legend.fontSize = 7 self.Legend.x = 153 self.Legend.y = 85 self.Legend.dxTextSpace = 5 self.Legend.dy = 5 self.Legend.dx = 5 self.Legend.deltay = 5 self.Legend.alignment ='right' self._add(self,Label(),name='XLabel',validate=None,desc="The label on the horizontal axis") self.XLabel.fontName = 'Helvetica' self.XLabel.fontSize = 7 self.XLabel.x = 85 self.XLabel.y = 10 self.XLabel.textAnchor ='middle' self.XLabel.maxWidth = 100 self.XLabel.height = 20 self.XLabel._text = "X Axis" self._add(self,Label(),name='YLabel',validate=None,desc="The label on the vertical axis") self.YLabel.fontName = 'Helvetica' self.YLabel.fontSize = 7 self.YLabel.x = 12 self.YLabel.y = 80 self.YLabel.angle = 90 self.YLabel.textAnchor ='middle' self.YLabel.maxWidth = 100 self.YLabel.height = 20 self.YLabel._text = "Y Axis" self.chart.yValueAxis.forceZero = 1 self.chart.xValueAxis.forceZero = 1 self._add(self,0,name='preview',validate=None,desc=None) if __name__=="__main__": #NORUNTESTS LineChartWithMarkers().save(formats=['pdf'],outDir=None,fnRoot='linechart_with_markers') ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1691062243.0 reportlab-4.1.0/src/reportlab/graphics/samples/radar.py0000664000175000017500000000625414462707743022617 0ustar00rptlabrptlab#Autogenerated by ReportLab guiedit do not edit from reportlab.graphics.charts.legends import Legend from reportlab.graphics.samples.excelcolors import * from reportlab.graphics.charts.spider import SpiderChart from reportlab.graphics.shapes import Drawing, _DrawingEditorMixin from reportlab.graphics.charts.textlabels import Label class RadarChart(_DrawingEditorMixin,Drawing): def __init__(self,width=200,height=150,*args,**kw): Drawing.__init__(self,width,height,*args,**kw) self._add(self,SpiderChart(),name='chart',validate=None,desc="The main chart") self.chart.width = 90 self.chart.height = 90 self.chart.x = 45 self.chart.y = 25 self.chart.strands[0].strokeColor= color01 self.chart.strands[1].strokeColor= color02 self.chart.strands[2].strokeColor= color03 self.chart.strands[3].strokeColor= color04 self.chart.strands[4].strokeColor= color05 self.chart.strands[5].strokeColor= color06 self.chart.strands[6].strokeColor= color07 self.chart.strands[7].strokeColor= color08 self.chart.strands[8].strokeColor= color09 self.chart.strands[9].strokeColor= color10 self.chart.strands[0].fillColor = None self.chart.strands[1].fillColor = None self.chart.strands[2].fillColor = None self.chart.strands[3].fillColor = None self.chart.strands[4].fillColor = None self.chart.strands[5].fillColor = None self.chart.strands[6].fillColor = None self.chart.strands[7].fillColor = None self.chart.strands[8].fillColor = None self.chart.strands[9].fillColor = None self.chart.strands.strokeWidth = 1 self.chart.strandLabels.fontName = 'Helvetica' self.chart.strandLabels.fontSize = 6 self.chart.fillColor = backgroundGrey self.chart.data = [(125, 180, 200), (100, 150, 180)] self.chart.labels = ['North', 'South', 'Central'] self._add(self,Label(),name='Title',validate=None,desc="The title at the top of the chart") self.Title.fontName = 'Helvetica-Bold' self.Title.fontSize = 7 self.Title.x = 100 self.Title.y = 135 self.Title._text = 'Chart Title' self.Title.maxWidth = 180 self.Title.height = 20 self.Title.textAnchor ='middle' self._add(self,Legend(),name='Legend',validate=None,desc="The legend or key for the chart") self.Legend.colorNamePairs = [(color01, 'Widgets'), (color02, 'Sprockets')] self.Legend.fontName = 'Helvetica' self.Legend.fontSize = 7 self.Legend.x = 153 self.Legend.y = 85 self.Legend.dxTextSpace = 5 self.Legend.dy = 5 self.Legend.dx = 5 self.Legend.deltay = 5 self.Legend.alignment ='right' self.chart.strands.strokeWidth = 1 self._add(self,0,name='preview',validate=None,desc=None) if __name__=="__main__": #NORUNTESTS RadarChart().save(formats=['pdf'],outDir=None,fnRoot='radar') ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1691062243.0 reportlab-4.1.0/src/reportlab/graphics/samples/runall.py0000664000175000017500000000364514462707743023024 0ustar00rptlabrptlab# runs all the GUIedit charts in this directory - # makes a PDF sample for eaxh existing chart type import sys import glob import inspect def moduleClasses(mod): def P(obj, m=mod.__name__, CT=type): return (type(obj)==CT and obj.__module__==m) try: return inspect.getmembers(mod, P)[0][1] except: return None def getclass(f): return moduleClasses(__import__(f)) def run(format, VERBOSE=0): formats = format.split( ',') for i in range(0, len(formats)): formats[i] == formats[i].strip().lower() allfiles = glob.glob('*.py') allfiles.sort() for fn in allfiles: f = fn.split('.')[0] c = getclass(f) if c != None: print(c.__name__) try: for fmt in formats: if fmt: c().save(formats=[fmt],outDir='.',fnRoot=c.__name__) if VERBOSE: print(" %s.%s" % (c.__name__, fmt)) except: print(" COULDN'T CREATE '%s.%s'!" % (c.__name__, format)) if __name__ == "__main__": if len(sys.argv) == 1: run('pdf,pict,png') else: try: if sys.argv[1] == "-h": print('usage: runall.py [FORMAT] [-h]') print(' if format is supplied is should be one or more of pdf,gif,eps,png etc') print(' if format is missing the following formats are assumed: pdf,pict,png') print(' -h prints this message') else: t = sys.argv[1:] for f in t: run(f) except: print('usage: runall.py [FORMAT][-h]') print(' if format is supplied is should be one or more of pdf,gif,eps,png etc') print(' if format is missing the following formats are assumed: pdf,pict,png') print(' -h prints this message') raise ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1691062243.0 reportlab-4.1.0/src/reportlab/graphics/samples/scatter.py0000664000175000017500000000675614462707743023202 0ustar00rptlabrptlab#Autogenerated by ReportLab guiedit do not edit from reportlab.graphics.charts.legends import Legend from reportlab.graphics.charts.lineplots import ScatterPlot from reportlab.graphics.shapes import Drawing, _DrawingEditorMixin from reportlab.graphics.charts.textlabels import Label from reportlab.graphics.samples.excelcolors import * class Scatter(_DrawingEditorMixin,Drawing): def __init__(self,width=200,height=150,*args,**kw): Drawing.__init__(self,width,height,*args,**kw) self._add(self,ScatterPlot(),name='chart',validate=None,desc="The main chart") self.chart.width = 115 self.chart.height = 80 self.chart.x = 30 self.chart.y = 40 self.chart.lines[0].strokeColor = color01 self.chart.lines[1].strokeColor = color02 self.chart.lines[2].strokeColor = color03 self.chart.lines[3].strokeColor = color04 self.chart.lines[4].strokeColor = color05 self.chart.lines[5].strokeColor = color06 self.chart.lines[6].strokeColor = color07 self.chart.lines[7].strokeColor = color08 self.chart.lines[8].strokeColor = color09 self.chart.lines[9].strokeColor = color10 self.chart.fillColor = backgroundGrey self.chart.lineLabels.fontName = 'Helvetica' self.chart.xValueAxis.labels.fontName = 'Helvetica' self.chart.xValueAxis.labels.fontSize = 7 self.chart.xValueAxis.forceZero = 0 self.chart.data = [((100,100), (200,200), (250,210), (300,300), (400,500)), ((100,200), (200,300), (250,200), (300,400), (400, 600))] self.chart.xValueAxis.avoidBoundFrac = 1 self.chart.xValueAxis.gridEnd = 115 self.chart.xValueAxis.tickDown = 3 self.chart.xValueAxis.visibleGrid = 1 self.chart.yValueAxis.tickLeft = 3 self.chart.yValueAxis.labels.fontName = 'Helvetica' self.chart.yValueAxis.labels.fontSize = 7 self._add(self,Label(),name='Title',validate=None,desc="The title at the top of the chart") self.Title.fontName = 'Helvetica-Bold' self.Title.fontSize = 7 self.Title.x = 100 self.Title.y = 135 self.Title._text = 'Chart Title' self.Title.maxWidth = 180 self.Title.height = 20 self.Title.textAnchor ='middle' self._add(self,Legend(),name='Legend',validate=None,desc="The legend or key for the chart") self.Legend.colorNamePairs = [(color01, 'Widgets'), (color02, 'Sprockets')] self.Legend.fontName = 'Helvetica' self.Legend.fontSize = 7 self.Legend.x = 153 self.Legend.y = 85 self.Legend.dxTextSpace = 5 self.Legend.dy = 5 self.Legend.dx = 5 self.Legend.deltay = 5 self.Legend.alignment ='right' self.chart.lineLabelFormat = None self.chart.xLabel = 'X Axis' self.chart.y = 30 self.chart.yLabel = 'Y Axis' self.chart.yValueAxis.labelTextFormat = '%d' self.chart.yValueAxis.forceZero = 1 self.chart.xValueAxis.forceZero = 1 self._add(self,0,name='preview',validate=None,desc=None) if __name__=="__main__": #NORUNTESTS Scatter().save(formats=['pdf'],outDir=None,fnRoot='scatter') ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1691062243.0 reportlab-4.1.0/src/reportlab/graphics/samples/scatter_lines.py0000664000175000017500000001010414462707743024352 0ustar00rptlabrptlab#Autogenerated by ReportLab guiedit do not edit from reportlab.graphics.charts.legends import Legend from reportlab.graphics.charts.lineplots import ScatterPlot from reportlab.graphics.shapes import Drawing, _DrawingEditorMixin from reportlab.graphics.charts.textlabels import Label from reportlab.graphics.samples.excelcolors import * class ScatterLines(_DrawingEditorMixin,Drawing): def __init__(self,width=200,height=150,*args,**kw): Drawing.__init__(self,width,height,*args,**kw) self._add(self,ScatterPlot(),name='chart',validate=None,desc="The main chart") self.chart.width = 115 self.chart.height = 80 self.chart.x = 30 self.chart.y = 40 self.chart.lines[0].strokeColor = color01 self.chart.lines[1].strokeColor = color02 self.chart.lines[2].strokeColor = color03 self.chart.lines[3].strokeColor = color04 self.chart.lines[4].strokeColor = color05 self.chart.lines[5].strokeColor = color06 self.chart.lines[6].strokeColor = color07 self.chart.lines[7].strokeColor = color08 self.chart.lines[8].strokeColor = color09 self.chart.lines[9].strokeColor = color10 self.chart.lines[0].symbol = None self.chart.lines[1].symbol = None self.chart.lines[2].symbol = None self.chart.lines[3].symbol = None self.chart.lines[4].symbol = None self.chart.lines[5].symbol = None self.chart.lines[6].symbol = None self.chart.lines[7].symbol = None self.chart.lines[8].symbol = None self.chart.lines[9].symbol = None self.chart.fillColor = backgroundGrey self.chart.lineLabels.fontName = 'Helvetica' self.chart.xValueAxis.labels.fontName = 'Helvetica' self.chart.xValueAxis.labels.fontSize = 7 self.chart.xValueAxis.forceZero = 0 self.chart.data = [((100,100), (200,200), (250,210), (300,300), (400,500)), ((100,200), (200,300), (250,200), (300,400), (400, 600))] self.chart.xValueAxis.avoidBoundFrac = 1 self.chart.xValueAxis.gridEnd = 115 self.chart.xValueAxis.tickDown = 3 self.chart.xValueAxis.visibleGrid = 1 self.chart.yValueAxis.tickLeft = 3 self.chart.yValueAxis.labels.fontName = 'Helvetica' self.chart.yValueAxis.labels.fontSize = 7 self._add(self,Label(),name='Title',validate=None,desc="The title at the top of the chart") self.Title.fontName = 'Helvetica-Bold' self.Title.fontSize = 7 self.Title.x = 100 self.Title.y = 135 self.Title._text = 'Chart Title' self.Title.maxWidth = 180 self.Title.height = 20 self.Title.textAnchor ='middle' self._add(self,Legend(),name='Legend',validate=None,desc="The legend or key for the chart") self.Legend.colorNamePairs = [(color01, 'Widgets'), (color02, 'Sprockets')] self.Legend.fontName = 'Helvetica' self.Legend.fontSize = 7 self.Legend.x = 153 self.Legend.y = 85 self.Legend.dxTextSpace = 5 self.Legend.dy = 5 self.Legend.dx = 5 self.Legend.deltay = 5 self.Legend.alignment ='right' self.chart.lineLabelFormat = None self.chart.xLabel = 'X Axis' self.chart.y = 30 self.chart.yLabel = 'Y Axis' self.chart.yValueAxis.gridEnd = 115 self.chart.yValueAxis.visibleGrid = 1 self.chart.yValueAxis.labelTextFormat = '%d' self.chart.yValueAxis.forceZero = 1 self.chart.xValueAxis.forceZero = 1 self.chart.joinedLines = 1 self._add(self,0,name='preview',validate=None,desc=None) if __name__=="__main__": #NORUNTESTS ScatterLines().save(formats=['pdf'],outDir=None,fnRoot='scatter_lines') ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1691062243.0 reportlab-4.1.0/src/reportlab/graphics/samples/scatter_lines_markers.py0000664000175000017500000000726614462707743026115 0ustar00rptlabrptlab#Autogenerated by ReportLab guiedit do not edit from reportlab.graphics.charts.legends import Legend from reportlab.graphics.charts.lineplots import ScatterPlot from reportlab.graphics.shapes import Drawing, _DrawingEditorMixin from reportlab.graphics.charts.textlabels import Label from reportlab.graphics.samples.excelcolors import * class ScatterLinesMarkers(_DrawingEditorMixin,Drawing): def __init__(self,width=200,height=150,*args,**kw): Drawing.__init__(self,width,height,*args,**kw) self._add(self,ScatterPlot(),name='chart',validate=None,desc="The main chart") self.chart.width = 115 self.chart.height = 80 self.chart.x = 30 self.chart.y = 40 self.chart.lines[0].strokeColor = color01 self.chart.lines[1].strokeColor = color02 self.chart.lines[2].strokeColor = color03 self.chart.lines[3].strokeColor = color04 self.chart.lines[4].strokeColor = color05 self.chart.lines[5].strokeColor = color06 self.chart.lines[6].strokeColor = color07 self.chart.lines[7].strokeColor = color08 self.chart.lines[8].strokeColor = color09 self.chart.lines[9].strokeColor = color10 self.chart.fillColor = backgroundGrey self.chart.lineLabels.fontName = 'Helvetica' self.chart.xValueAxis.labels.fontName = 'Helvetica' self.chart.xValueAxis.labels.fontSize = 7 self.chart.xValueAxis.forceZero = 0 self.chart.data = [((100,100), (200,200), (250,210), (300,300), (400,500)), ((100,200), (200,300), (250,200), (300,400), (400, 600))] self.chart.xValueAxis.avoidBoundFrac = 1 self.chart.xValueAxis.gridEnd = 115 self.chart.xValueAxis.tickDown = 3 self.chart.xValueAxis.visibleGrid = 1 self.chart.yValueAxis.tickLeft = 3 self.chart.yValueAxis.labels.fontName = 'Helvetica' self.chart.yValueAxis.labels.fontSize = 7 self._add(self,Label(),name='Title',validate=None,desc="The title at the top of the chart") self.Title.fontName = 'Helvetica-Bold' self.Title.fontSize = 7 self.Title.x = 100 self.Title.y = 135 self.Title._text = 'Chart Title' self.Title.maxWidth = 180 self.Title.height = 20 self.Title.textAnchor ='middle' self._add(self,Legend(),name='Legend',validate=None,desc="The legend or key for the chart") self.Legend.colorNamePairs = [(color01, 'Widgets'), (color02, 'Sprockets')] self.Legend.fontName = 'Helvetica' self.Legend.fontSize = 7 self.Legend.x = 153 self.Legend.y = 85 self.Legend.dxTextSpace = 5 self.Legend.dy = 5 self.Legend.dx = 5 self.Legend.deltay = 5 self.Legend.alignment ='right' self.chart.lineLabelFormat = None self.chart.xLabel = 'X Axis' self.chart.y = 30 self.chart.yLabel = 'Y Axis' self.chart.yValueAxis.gridEnd = 115 self.chart.yValueAxis.visibleGrid = 1 self.chart.yValueAxis.labelTextFormat = '%d' self.chart.yValueAxis.forceZero = 1 self.chart.xValueAxis.forceZero = 1 self.chart.joinedLines = 1 self._add(self,0,name='preview',validate=None,desc=None) if __name__=="__main__": #NORUNTESTS ScatterLinesMarkers().save(formats=['pdf'],outDir=None,fnRoot='scatter_lines_markers') ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1691062243.0 reportlab-4.1.0/src/reportlab/graphics/samples/simple_pie.py0000664000175000017500000000556514462707743023660 0ustar00rptlabrptlab#Autogenerated by ReportLab guiedit do not edit from reportlab.graphics.charts.piecharts import Pie from reportlab.graphics.widgets.grids import ShadedRect from reportlab.graphics.charts.legends import Legend from reportlab.graphics.shapes import Drawing, _DrawingEditorMixin from reportlab.graphics.charts.textlabels import Label from reportlab.graphics.samples.excelcolors import * class SimplePie(_DrawingEditorMixin,Drawing): def __init__(self,width=200,height=150,*args,**kw): Drawing.__init__(self,width,height,*args,**kw) self._add(self,Pie(),name='chart',validate=None,desc="The main chart") self.chart.width = 100 self.chart.height = 100 self.chart.x = 25 self.chart.y = 25 self.chart.slices[0].fillColor = color01 self.chart.slices[1].fillColor = color02 self.chart.slices[2].fillColor = color03 self.chart.slices[3].fillColor = color04 self.chart.slices[4].fillColor = color05 self.chart.slices[5].fillColor = color06 self.chart.slices[6].fillColor = color07 self.chart.slices[7].fillColor = color08 self.chart.slices[8].fillColor = color09 self.chart.slices[9].fillColor = color10 self.chart.data = (100, 150, 180) self._add(self,Label(),name='Title',validate=None,desc="The title at the top of the chart") self.Title.fontName = 'Helvetica-Bold' self.Title.fontSize = 7 self.Title.x = 100 self.Title.y = 135 self.Title._text = 'Chart Title' self.Title.maxWidth = 180 self.Title.height = 20 self.Title.textAnchor ='middle' self._add(self,Legend(),name='Legend',validate=None,desc="The legend or key for the chart") self.Legend.colorNamePairs = [(color01, 'North'), (color02, 'South'),(color03, 'Central')] self.Legend.fontName = 'Helvetica' self.Legend.fontSize = 7 self.Legend.x = 160 self.Legend.y = 85 self.Legend.dxTextSpace = 5 self.Legend.dy = 5 self.Legend.dx = 5 self.Legend.deltay = 5 self.Legend.alignment ='right' self.chart.slices.strokeWidth = 1 self.chart.slices.fontName = 'Helvetica' self.background = ShadedRect() self.background.fillColorStart = backgroundGrey self.background.fillColorEnd = backgroundGrey self.background.numShades = 1 self.background.strokeWidth = 0.5 self.background.x = 25 self.background.y = 25 self.Legend.columnMaximum = 10 self._add(self,0,name='preview',validate=None,desc=None) if __name__=="__main__": #NORUNTESTS SimplePie().save(formats=['pdf'],outDir=None,fnRoot=None) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1691062243.0 reportlab-4.1.0/src/reportlab/graphics/samples/stacked_bar.py0000664000175000017500000001027414462707743023765 0ustar00rptlabrptlab#Autogenerated by ReportLab guiedit do not edit from reportlab.graphics.charts.legends import Legend from reportlab.graphics.charts.barcharts import HorizontalBarChart from reportlab.graphics.shapes import Drawing, _DrawingEditorMixin from reportlab.graphics.charts.textlabels import Label from reportlab.graphics.samples.excelcolors import * class StackedBar(_DrawingEditorMixin,Drawing): def __init__(self,width=200,height=150,*args,**kw): Drawing.__init__(self,width,height,*args,**kw) self._add(self,HorizontalBarChart(),name='chart',validate=None,desc="The main chart") self.chart.width = 115 self.chart.height = 80 self.chart.x = 30 self.chart.y = 40 self.chart.bars[0].fillColor = color01 self.chart.bars[1].fillColor = color02 self.chart.bars[2].fillColor = color03 self.chart.bars[3].fillColor = color04 self.chart.bars[4].fillColor = color05 self.chart.bars[5].fillColor = color06 self.chart.bars[6].fillColor = color07 self.chart.bars[7].fillColor = color08 self.chart.bars[8].fillColor = color09 self.chart.bars[9].fillColor = color10 self.chart.fillColor = backgroundGrey self.chart.barLabels.fontName = 'Helvetica' self.chart.valueAxis.labels.fontName = 'Helvetica' self.chart.valueAxis.labels.fontSize = 6 self.chart.valueAxis.forceZero = 1 self.chart.data = [(100, 150, 180), (125, 180, 200)] self.chart.groupSpacing = 15 self.chart.valueAxis.avoidBoundFrac = 1 self.chart.valueAxis.gridEnd = 80 self.chart.valueAxis.tickDown = 3 self.chart.valueAxis.visibleGrid = 1 self.chart.categoryAxis.categoryNames = ['North', 'South', 'Central'] self.chart.categoryAxis.tickLeft = 3 self.chart.categoryAxis.labels.fontName = 'Helvetica' self.chart.categoryAxis.labels.fontSize = 6 self.chart.categoryAxis.labels.dx = -3 self._add(self,Label(),name='Title',validate=None,desc="The title at the top of the chart") self.Title.fontName = 'Helvetica-Bold' self.Title.fontSize = 7 self.Title.x = 100 self.Title.y = 135 self.Title._text = 'Chart Title' self.Title.maxWidth = 180 self.Title.height = 20 self.Title.textAnchor ='middle' self._add(self,Legend(),name='Legend',validate=None,desc="The legend or key for the chart") self.Legend.colorNamePairs = [(color01, 'Widgets'), (color02, 'Sprockets')] self.Legend.fontName = 'Helvetica' self.Legend.fontSize = 7 self.Legend.x = 153 self.Legend.y = 85 self.Legend.dxTextSpace = 5 self.Legend.dy = 5 self.Legend.dx = 5 self.Legend.deltay = 5 self.Legend.alignment ='right' self._add(self,Label(),name='XLabel',validate=None,desc="The label on the horizontal axis") self.XLabel.fontName = 'Helvetica' self.XLabel.fontSize = 7 self.XLabel.x = 85 self.XLabel.y = 10 self.XLabel.textAnchor ='middle' self.XLabel.maxWidth = 100 self.XLabel.height = 20 self.XLabel._text = "X Axis" self._add(self,Label(),name='YLabel',validate=None,desc="The label on the vertical axis") self.YLabel.fontName = 'Helvetica' self.YLabel.fontSize = 7 self.YLabel.x = 12 self.YLabel.y = 80 self.YLabel.angle = 90 self.YLabel.textAnchor ='middle' self.YLabel.maxWidth = 100 self.YLabel.height = 20 self.YLabel._text = "Y Axis" self.chart.categoryAxis.style='stacked' self._add(self,0,name='preview',validate=None,desc=None) if __name__=="__main__": #NORUNTESTS StackedBar().save(formats=['pdf'],outDir=None,fnRoot='stacked_bar') ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1691062243.0 reportlab-4.1.0/src/reportlab/graphics/samples/stacked_column.py0000664000175000017500000001020614462707743024511 0ustar00rptlabrptlab#Autogenerated by ReportLab guiedit do not edit from reportlab.graphics.charts.legends import Legend from reportlab.graphics.charts.barcharts import VerticalBarChart from reportlab.graphics.shapes import Drawing, _DrawingEditorMixin from reportlab.graphics.charts.textlabels import Label from reportlab.graphics.samples.excelcolors import * class StackedColumn(_DrawingEditorMixin,Drawing): def __init__(self,width=200,height=150,*args,**kw): Drawing.__init__(self,width,height,*args,**kw) self._add(self,VerticalBarChart(),name='chart',validate=None,desc="The main chart") self.chart.width = 115 self.chart.height = 80 self.chart.x = 30 self.chart.y = 40 self.chart.bars[0].fillColor = color01 self.chart.bars[1].fillColor = color02 self.chart.bars[2].fillColor = color03 self.chart.bars[3].fillColor = color04 self.chart.bars[4].fillColor = color05 self.chart.bars[5].fillColor = color06 self.chart.bars[6].fillColor = color07 self.chart.bars[7].fillColor = color08 self.chart.bars[8].fillColor = color09 self.chart.bars[9].fillColor = color10 self.chart.fillColor = backgroundGrey self.chart.barLabels.fontName = 'Helvetica' self.chart.valueAxis.labels.fontName = 'Helvetica' self.chart.valueAxis.labels.fontSize = 7 self.chart.valueAxis.forceZero = 1 self.chart.data = [(100, 150, 180), (125, 180, 200)] self.chart.groupSpacing = 15 self.chart.valueAxis.avoidBoundFrac = 1 self.chart.valueAxis.gridEnd = 115 self.chart.valueAxis.tickLeft = 3 self.chart.valueAxis.visibleGrid = 1 self.chart.categoryAxis.categoryNames = ['North', 'South', 'Central'] self.chart.categoryAxis.tickDown = 3 self.chart.categoryAxis.labels.fontName = 'Helvetica' self.chart.categoryAxis.labels.fontSize = 7 self._add(self,Label(),name='Title',validate=None,desc="The title at the top of the chart") self.Title.fontName = 'Helvetica-Bold' self.Title.fontSize = 7 self.Title.x = 100 self.Title.y = 135 self.Title._text = 'Chart Title' self.Title.maxWidth = 180 self.Title.height = 20 self.Title.textAnchor ='middle' self._add(self,Legend(),name='Legend',validate=None,desc="The legend or key for the chart") self.Legend.colorNamePairs = [(color01, 'Widgets'), (color02, 'Sprockets')] self.Legend.fontName = 'Helvetica' self.Legend.fontSize = 7 self.Legend.x = 153 self.Legend.y = 85 self.Legend.dxTextSpace = 5 self.Legend.dy = 5 self.Legend.dx = 5 self.Legend.deltay = 5 self.Legend.alignment ='right' self._add(self,Label(),name='XLabel',validate=None,desc="The label on the horizontal axis") self.XLabel.fontName = 'Helvetica' self.XLabel.fontSize = 7 self.XLabel.x = 85 self.XLabel.y = 10 self.XLabel.textAnchor ='middle' self.XLabel.maxWidth = 100 self.XLabel.height = 20 self.XLabel._text = "X Axis" self._add(self,Label(),name='YLabel',validate=None,desc="The label on the vertical axis") self.YLabel.fontName = 'Helvetica' self.YLabel.fontSize = 7 self.YLabel.x = 12 self.YLabel.y = 80 self.YLabel.angle = 90 self.YLabel.textAnchor ='middle' self.YLabel.maxWidth = 100 self.YLabel.height = 20 self.YLabel._text = "Y Axis" self.chart.categoryAxis.style='stacked' self._add(self,0,name='preview',validate=None,desc=None) if __name__=="__main__": #NORUNTESTS StackedColumn().save(formats=['pdf'],outDir=None,fnRoot='stacked_column') ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1704966359.0 reportlab-4.1.0/src/reportlab/graphics/shapes.py0000664000175000017500000016362314547734327021353 0ustar00rptlabrptlab#Copyright ReportLab Europe Ltd. 2000-2017 #see license.txt for license details #history https://hg.reportlab.com/hg-public/reportlab/log/tip/src/reportlab/graphics/shapes.py __version__='3.5.60' __doc__='''Core of the graphics library - defines Drawing and Shapes''' import os, sys from math import pi, cos, sin, sqrt, radians, floor from reportlab.platypus import Flowable from reportlab.rl_config import shapeChecking, verbose, defaultGraphicsFontName as _baseGFontName, _unset_, decimalSymbol from reportlab.lib import logger from reportlab.lib import colors from reportlab.lib.validators import * from reportlab.lib.utils import isSeq, asBytes isOpacity = NoneOr(isNumberInRange(0,1)) from reportlab.lib.attrmap import * from reportlab.lib.rl_accel import fp_str from reportlab.pdfbase.pdfmetrics import stringWidth from reportlab.lib.fonts import tt2ps from reportlab.pdfgen.canvas import FILL_EVEN_ODD, FILL_NON_ZERO _baseGFontNameB = tt2ps(_baseGFontName,1,0) _baseGFontNameI = tt2ps(_baseGFontName,0,1) _baseGFontNameBI = tt2ps(_baseGFontName,1,1) # two constants for filling rules NON_ZERO_WINDING = 'Non-Zero Winding' EVEN_ODD = 'Even-Odd' ## these can be overridden at module level before you start #creating shapes. So, if using a special color model, #this provides support for the rendering mechanism. #you can change defaults globally before you start #making shapes; one use is to substitute another #color model cleanly throughout the drawing. STATE_DEFAULTS = { # sensible defaults for all 'transform': (1,0,0,1,0,0), # styles follow SVG naming 'strokeColor': colors.black, 'strokeWidth': 1, 'strokeLineCap': 0, 'strokeLineJoin': 0, 'strokeMiterLimit' : 10, # don't know yet so let bomb here 'strokeDashArray': None, 'strokeOpacity': None, #100% 'fillOpacity': None, 'fillOverprint': False, 'strokeOverprint': False, 'overprintMask': 0, 'fillColor': colors.black, #...or text will be invisible 'fillMode': FILL_EVEN_ODD, #same as pdfgen.canvas 'fontSize': 10, 'fontName': _baseGFontName, 'textAnchor': 'start' # can be start, middle, end, inherited } #################################################################### # math utilities. These are now in reportlab.graphics.transform #################################################################### from . transform import * def _textBoxLimits(text, font, fontSize, leading, textAnchor, boxAnchor): w = 0 for t in text: w = max(w,stringWidth(t,font, fontSize)) h = len(text)*leading yt = fontSize if boxAnchor[0]=='s': yb = -h yt = yt - h elif boxAnchor[0]=='n': yb = 0 else: yb = -h/2.0 yt = yt + yb if boxAnchor[-1]=='e': xb = -w if textAnchor=='end': xt = 0 elif textAnchor=='start': xt = -w else: xt = -w/2.0 elif boxAnchor[-1]=='w': xb = 0 if textAnchor=='end': xt = w elif textAnchor=='start': xt = 0 else: xt = w/2.0 else: xb = -w/2.0 if textAnchor=='end': xt = -xb elif textAnchor=='start': xt = xb else: xt = 0 return xb, yb, w, h, xt, yt def _rotatedBoxLimits( x, y, w, h, angle): ''' Find the corner points of the rotated w x h sized box at x,y return the corner points and the min max points in the original space ''' C = zTransformPoints(rotate(angle),((x,y),(x+w,y),(x+w,y+h),(x,y+h))) X = [x[0] for x in C] Y = [x[1] for x in C] return min(X), max(X), min(Y), max(Y), C class _DrawTimeResizeable: '''Addin class to provide the horribleness of _drawTimeResize''' def _drawTimeResize(self,w,h): if hasattr(self,'_canvas'): canvas = self._canvas drawing = canvas._drawing drawing.width, drawing.height = w, h if hasattr(canvas,'_drawTimeResize'): canvas._drawTimeResize(w,h) class _SetKeyWordArgs: def __init__(self, keywords={}): """In general properties may be supplied to the constructor.""" for key, value in keywords.items(): setattr(self, key, value) ################################################################# # # Helper functions for working out bounds # ################################################################# def getRectsBounds(rectList): # filter out any None objects, e.g. empty groups L = [x for x in rectList if x is not None] if not L: return None xMin, yMin, xMax, yMax = L[0] for (x1, y1, x2, y2) in L[1:]: if x1 < xMin: xMin = x1 if x2 > xMax: xMax = x2 if y1 < yMin: yMin = y1 if y2 > yMax: yMax = y2 return (xMin, yMin, xMax, yMax) def _getBezierExtrema(y0,y1,y2,y3): ''' this is used to find if a curveTo path operator has extrema in its range The curveTo operator is defined by the points y0, y1, y2, y3 B(t):=(1-t)^3*y0+3*(1-t)^2*t*y1+3*(1-t)*t^2*y2+t^3*y3 :=t^3*(y3-3*y2+3*y1-y0)+t^2*(3*y2-6*y1+3*y0)+t*(3*y1-3*y0)+y0 and is a cubic bezier curve. The differential is a quadratic t^2*(3*y3-9*y2+9*y1-3*y0)+t*(6*y2-12*y1+6*y0)+3*y1-3*y0 The extrema must be at real roots, r, of the above which lie in 0<=r<=1 The quadratic coefficients are a=3*y3-9*y2+9*y1-3*y0 b=6*y2-12*y1+6*y0 c=3*y1-3*y0 or a=y3-3*y2+3*y1-y0 b=2*y2-4*y1+2*y0 c=y1-y0 (remove common factor of 3) or a=y3-3*(y2-y1)-y0 b=2*(y2-2*y1+y0) c=y1-y0 The returned value is [y0,x1,x2,y3] where if found x1, x2 are any extremals that were found; there can be 0, 1 or 2 extremals ''' a=y3-3*(y2-y1)-y0 b=2*(y2-2*y1+y0) c=y1-y0 Y = [y0] #the set of points #standard method to find roots of quadratic d = b*b - 4*a*c if d>=0: d = sqrt(d) if b<0: d = -d q = -0.5*(b+d) R = [] try: R.append(q/a) except: pass try: R.append(c/q) except: pass b *= 1.5 c *= 3 for t in R: if 0<=t<=1: #real root in range evaluate spline there and add to X Y.append(t*(t*(t*a+b)+c)+y0) Y.append(y3) return Y def getPathBounds(points): n = len(points) f = lambda i,p = points: p[i] xs = list(map(f,range(0,n,2))) ys = list(map(f,range(1,n,2))) return (min(xs), min(ys), max(xs), max(ys)) def getPointsBounds(pointList): "Helper function for list of points" first = pointList[0] if isSeq(first): xs = [xy[0] for xy in pointList] ys = [xy[1] for xy in pointList] return (min(xs), min(ys), max(xs), max(ys)) else: return getPathBounds(pointList) ################################################################# # # And now the shapes themselves.... # ################################################################# class Shape(_SetKeyWordArgs,_DrawTimeResizeable): """Base class for all nodes in the tree. Nodes are simply packets of data to be created, stored, and ultimately rendered - they don't do anything active. They provide convenience methods for verification but do not check attribiute assignments or use any clever setattr tricks this time.""" _attrMap = AttrMap() def copy(self): """Return a clone of this shape.""" # implement this in the descendants as they need the right init methods. raise NotImplementedError("No copy method implemented for %s" % self.__class__.__name__) def getProperties(self,recur=1): """Interface to make it easy to extract automatic documentation""" #basic nodes have no children so this is easy. #for more complex objects like widgets you #may need to override this. props = {} for key, value in self.__dict__.items(): if key[0:1] != '_': props[key] = value return props def setProperties(self, props): """Supports the bulk setting if properties from, for example, a GUI application or a config file.""" self.__dict__.update(props) #self.verify() def dumpProperties(self, prefix=""): """Convenience. Lists them on standard output. You may provide a prefix - mostly helps to generate code samples for documentation.""" propList = list(self.getProperties().items()) propList.sort() if prefix: prefix = prefix + '.' for (name, value) in propList: print('%s%s = %s' % (prefix, name, value)) def verify(self): """If the programmer has provided the optional _attrMap attribute, this checks all expected attributes are present; no unwanted attributes are present; and (if a checking function is found) checks each attribute. Either succeeds or raises an informative exception.""" if self._attrMap is not None: for key in self.__dict__.keys(): if key[0] != '_': assert key in self._attrMap, "Unexpected attribute %s found in %s" % (key, self) for attr, metavalue in self._attrMap.items(): assert hasattr(self, attr), "Missing attribute %s from %s" % (attr, self) value = getattr(self, attr) assert metavalue.validate(value), "Invalid value %s for attribute %s in class %s" % (value, attr, self.__class__.__name__) if shapeChecking: """This adds the ability to check every attribute assignment as it is made. It slows down shapes but is a big help when developing. It does not get defined if rl_config.shapeChecking = 0""" def __setattr__(self, attr, value): """By default we verify. This could be off in some parallel base classes.""" validateSetattr(self,attr,value) #from reportlab.lib.attrmap def getBounds(self): "Returns bounding rectangle of object as (x1,y1,x2,y2)" raise NotImplementedError("Shapes and widgets must implement getBounds") class Group(Shape): """Groups elements together. May apply a transform to its contents. Has a publicly accessible property 'contents' which may be used to iterate over contents. In addition, child nodes may be given a name in which case they are subsequently accessible as properties.""" _attrMap = AttrMap( transform = AttrMapValue(isTransform,desc="Coordinate transformation to apply",advancedUsage=1), contents = AttrMapValue(isListOfShapes,desc="Contained drawable elements"), strokeOverprint = AttrMapValue(isBoolean,desc='Turn on stroke overprinting'), fillOverprint = AttrMapValue(isBoolean,desc='Turn on fill overprinting',advancedUsage=1), overprintMask = AttrMapValue(isBoolean,desc='overprinting for ordinary CMYK',advancedUsage=1), ) def __init__(self, *elements, **keywords): """Initial lists of elements may be provided to allow compact definitions in literal Python code. May or may not be useful.""" # Groups need _attrMap to be an instance rather than # a class attribute, as it may be extended at run time. self._attrMap = self._attrMap.clone() self.contents = [] self.transform = (1,0,0,1,0,0) for elt in elements: self.add(elt) # this just applies keywords; do it at the end so they #don;t get overwritten _SetKeyWordArgs.__init__(self, keywords) def _addNamedNode(self,name,node): 'if name is not None add an attribute pointing to node and add to the attrMap' if name: if name not in list(self._attrMap.keys()): self._attrMap[name] = AttrMapValue(isValidChild) setattr(self, name, node) def add(self, node, name=None): """Appends non-None child node to the 'contents' attribute. In addition, if a name is provided, it is subsequently accessible by name """ # propagates properties down if node is not None: assert isValidChild(node), "Can only add Shape or UserNode objects to a Group" self.contents.append(node) self._addNamedNode(name,node) def _nn(self,node): self.add(node) return self.contents[-1] def insert(self, i, n, name=None): 'Inserts sub-node n in contents at specified location' if n is not None: assert isValidChild(n), "Can only insert Shape or UserNode objects in a Group" if i<0: self.contents[i:i] =[n] else: self.contents.insert(i,n) self._addNamedNode(name,n) def expandUserNodes(self): """Return a new object which only contains primitive shapes.""" # many limitations - shared nodes become multiple ones, obj = isinstance(self,Drawing) and Drawing(self.width,self.height) or Group() obj._attrMap = self._attrMap.clone() if hasattr(obj,'transform'): obj.transform = self.transform[:] self_contents = self.contents a = obj.contents.append for child in self_contents: if isinstance(child, UserNode): newChild = child.provideNode() elif isinstance(child, Group): newChild = child.expandUserNodes() else: newChild = child.copy() a(newChild) self._copyNamedContents(obj) return obj def _explode(self): ''' return a fully expanded object''' obj = Group() if hasattr(self,'__label__'): obj.__label__=self.__label__ if hasattr(obj,'transform'): obj.transform = self.transform[:] P = self.getContents()[:] # pending nodes while P: n = P.pop(0) if isinstance(n, UserNode): P.append(n.provideNode()) elif isinstance(n, Group): n = n._explode() if n.transform==(1,0,0,1,0,0): obj.contents.extend(n.contents) else: obj.add(n) else: obj.add(n) return obj def _copyContents(self,obj): for child in self.contents: obj.contents.append(child) def _copyNamedContents(self,obj,aKeys=None,noCopy=('contents',)): from copy import copy self_contents = self.contents if not aKeys: aKeys = list(self._attrMap.keys()) for k, v in self.__dict__.items(): if v in self_contents: pos = self_contents.index(v) setattr(obj, k, obj.contents[pos]) elif k in aKeys and k not in noCopy: setattr(obj, k, copy(v)) def _copy(self,obj): """copies to obj""" obj._attrMap = self._attrMap.clone() self._copyContents(obj) self._copyNamedContents(obj) return obj def copy(self): """returns a copy""" return self._copy(self.__class__()) def rotate(self, theta): """Convenience to help you set transforms""" self.transform = mmult(self.transform, rotate(theta)) def translate(self, dx, dy): """Convenience to help you set transforms""" self.transform = mmult(self.transform, translate(dx, dy)) def scale(self, sx, sy): """Convenience to help you set transforms""" self.transform = mmult(self.transform, scale(sx, sy)) def skew(self, kx, ky): """Convenience to help you set transforms""" self.transform = mmult(mmult(self.transform, skewX(kx)),skewY(ky)) def shift(self, x, y): '''Convenience function to set the origin arbitrarily''' self.transform = self.transform[:-2]+(x,y) def asDrawing(self, width, height): """ Convenience function to make a drawing from a group After calling this the instance will be a drawing! """ self.__class__ = Drawing self._attrMap.update(self._xtraAttrMap) self.width = width self.height = height def getContents(self): '''Return the list of things to be rendered override to get more complicated behaviour''' b = getattr(self,'background',None) C = self.contents if b and b not in C: C = [b]+C return C def getBounds(self): if self.contents: b = [] for elem in self.contents: b.append(elem.getBounds()) x1 = getRectsBounds(b) if x1 is None: return None x1, y1, x2, y2 = x1 trans = self.transform corners = [[x1,y1], [x1, y2], [x2, y1], [x2,y2]] newCorners = [] for corner in corners: newCorners.append(transformPoint(trans, corner)) return getPointsBounds(newCorners) else: #empty group needs a sane default; this #will happen when interactively creating a group #nothing has been added to yet. The alternative is #to handle None as an allowed return value everywhere. return None def _addObjImport(obj,I,n=None): '''add an import of obj's class to a dictionary of imports''' #' from inspect import getmodule c = obj.__class__ m = getmodule(c).__name__ n = n or c.__name__ if m not in I: I[m] = [n] elif n not in I[m]: I[m].append(n) def _repr(self,I=None): '''return a repr style string with named fixed args first, then keywords''' if isinstance(self,float): return fp_str(self) elif isSeq(self): s = '' for v in self: s = s + '%s,' % _repr(v,I) if isinstance(self,list): return '[%s]' % s[:-1] else: return '(%s%s)' % (s[:-1],len(self)==1 and ',' or '') elif self is EmptyClipPath: if I: _addObjImport(self,I,'EmptyClipPath') return 'EmptyClipPath' elif isinstance(self,Shape): if I: _addObjImport(self,I) from inspect import getfullargspec args, varargs, varkw, defaults, kwonlyargs, kwonlydefaults, annotations = getfullargspec(self.__init__) if defaults: kargs = args[-len(defaults):] del args[-len(defaults):] else: kargs = [] P = self.getProperties() s = self.__class__.__name__+'(' for n in args[1:]: v = P.pop(n,None) s += '%s,' % _repr(v,I) for n in kargs: v = P.pop(n,None) s += '%s=%s,' % (n,_repr(v,I)) for n,v in P.items(): v = P[n] s += '%s=%s,' % (n, _repr(v,I)) return s[:-1]+')' else: return repr(self) def _renderGroupPy(G,pfx,I,i=0,indent='\t\t'): s = '' C = getattr(G,'transform',None) if C: s = s + ('%s%s.transform = %s\n' % (indent,pfx,_repr(C))) C = G.contents for n in C: if isinstance(n, Group): npfx = 'v%d' % i i += 1 l = getattr(n,'__label__','') if l: l='#'+l s = s + '%s%s=%s._nn(Group())%s\n' % (indent,npfx,pfx,l) s = s + _renderGroupPy(n,npfx,I,i,indent) i -= 1 else: s = s + '%s%s.add(%s)\n' % (indent,pfx,_repr(n,I)) return s def _extraKW(self,pfx,**kw): kw.update(self.__dict__) n = len(pfx) return {k[n:]:v for k,v in kw.items() if k.startswith(pfx)} class Drawing(Group, Flowable): """Outermost container; the thing a renderer works on. This has no properties except a height, width and list of contents.""" _saveModes = { 'bmp', 'eps', 'gif', 'jpeg', 'jpg', 'pct', 'pdf', 'pict', 'png', 'ps', 'py', 'svg', 'tif', 'tiff', 'tiff1', 'tiffl', 'tiffp', } _bmModes = _saveModes - {'eps','pdf','ps','py','svg'} _xtraAttrMap = AttrMap( width = AttrMapValue(isNumber,desc="Drawing width in points."), height = AttrMapValue(isNumber,desc="Drawing height in points."), canv = AttrMapValue(None), background = AttrMapValue(isValidChildOrNone,desc="Background widget for the drawing e.g. Rect(0,0,width,height)"), hAlign = AttrMapValue(OneOf("LEFT", "RIGHT", "CENTER", "CENTRE"), desc="Horizontal alignment within parent document"), vAlign = AttrMapValue(OneOf("TOP", "BOTTOM", "CENTER", "CENTRE"), desc="Vertical alignment within parent document"), #AR temporary hack to track back up. #fontName = AttrMapValue(isStringOrNone), renderScale = AttrMapValue(isNumber,desc="Global scaling for rendering"), initialFontName = AttrMapValue(isStringOrNone,desc="override the STATE_DEFAULTS value for fontName"), initialFontSize = AttrMapValue(isNumberOrNone,desc="override the STATE_DEFAULTS value for fontSize"), ) _attrMap = AttrMap(BASE=Group, formats = AttrMapValue(SequenceOf( OneOf(*_saveModes), lo=1,emptyOK=0), desc='One or more plot modes'), ) _attrMap.update(_xtraAttrMap) def __init__(self, width=400, height=200, *nodes, **keywords): self.background = None Group.__init__(self,*nodes,**keywords) self.width = width self.height = height self.hAlign = 'LEFT' self.vAlign = 'BOTTOM' self.renderScale = 1.0 def _renderPy(self): I = { 'reportlab.graphics.shapes': ['_DrawingEditorMixin','Drawing','Group'], 'reportlab.lib.colors': ['Color','CMYKColor','PCMYKColor'], } G = _renderGroupPy(self._explode(),'self',I) n = 'ExplodedDrawing_' + self.__class__.__name__ s = '#Autogenerated by ReportLab guiedit do not edit\n' for m, o in I.items(): s = s + 'from %s import %s\n' % (m,str(o)[1:-1].replace("'","")) s = s + '\nclass %s(_DrawingEditorMixin,Drawing):\n' % n s = s + '\tdef __init__(self,width=%s,height=%s,*args,**kw):\n' % (self.width,self.height) s = s + '\t\tDrawing.__init__(self,width,height,*args,**kw)\n' s = s + G s = s + '\n\nif __name__=="__main__": #NORUNTESTS\n\t%s().save(formats=[\'pdf\'],outDir=\'.\',fnRoot=None)\n' % n return s def draw(self,showBoundary=_unset_): """This is used by the Platypus framework to let the document draw itself in a story. It is specific to PDF and should not be used directly.""" from reportlab.graphics import renderPDF renderPDF.draw(self, self.canv, 0, 0, showBoundary=showBoundary if showBoundary is not _unset_ else getattr(self,'_showBoundary',_unset_)) def wrap(self, availWidth, availHeight): width = self.width height = self.height renderScale = self.renderScale if renderScale!=1.0: width *= renderScale height *= renderScale return width, height def expandUserNodes(self): """Return a new drawing which only contains primitive shapes.""" obj = Group.expandUserNodes(self) obj.width = self.width obj.height = self.height return obj def copy(self): """Returns a copy""" return self._copy(self.__class__(self.width, self.height)) def asGroup(self,*args,**kw): return self._copy(Group(*args,**kw)) def save(self, formats=None, verbose=None, fnRoot=None, outDir=None, title='', **kw): """Saves copies of self in desired location and formats. Multiple formats can be supported in one call the extra keywords can be of the form _renderPM_dpi=96 (which passes dpi=96 to renderPM) """ genFmt = kw.pop('seqNumber','') if isinstance(genFmt,int): genFmt = '%4d: ' % genFmt else: genFmt = '' genFmt += 'generating %s file %s' from reportlab import rl_config ext = '' if not fnRoot: fnRoot = getattr(self,'fileNamePattern',(self.__class__.__name__+'%03d')) chartId = getattr(self,'chartId',0) if hasattr(chartId,'__call__'): chartId = chartId(self) if hasattr(fnRoot,'__call__'): fnRoot = fnRoot(chartId) else: try: fnRoot = fnRoot % chartId except TypeError as err: #the exact error message changed from 2.2 to 2.3 so we need to #check a substring if str(err).find('not all arguments converted') < 0: raise if outDir is None: outDir = getattr(self,'outDir',None) if hasattr(outDir,'__call__'): outDir = outDir(self) if os.path.isabs(fnRoot): outDir, fnRoot = os.path.split(fnRoot) else: outDir = outDir or getattr(self,'outDir','.') outDir = outDir.rstrip().rstrip(os.sep) if not outDir: outDir = '.' if not os.path.isabs(outDir): outDir = os.path.join(getattr(self,'_override_CWD',os.path.dirname(sys.argv[0])),outDir) if not os.path.isdir(outDir): os.makedirs(outDir) fnroot = os.path.normpath(os.path.join(outDir,fnRoot)) plotMode = os.path.splitext(fnroot) if plotMode[1][1:].lower() in self._saveModes: fnroot = plotMode[0] plotMode = [x.lower() for x in (formats or getattr(self,'formats',['pdf']))] verbose = (verbose is not None and (verbose,) or (getattr(self,'verbose',verbose),))[0] _saved = logger.warnOnce.enabled, logger.infoOnce.enabled logger.warnOnce.enabled = logger.infoOnce.enabled = verbose if 'pdf' in plotMode: from reportlab.graphics import renderPDF filename = fnroot+'.pdf' if verbose: print(genFmt % ('PDF',filename)) renderPDF.drawToFile(self, filename, title, showBoundary=getattr(self,'showBorder',rl_config.showBoundary),**_extraKW(self,'_renderPDF_',**kw)) ext = ext + '/.pdf' if sys.platform=='mac': import macfs, macostools macfs.FSSpec(filename).SetCreatorType("CARO", "PDF ") macostools.touched(filename) for bmFmt in self._bmModes: if bmFmt in plotMode: from reportlab.graphics import renderPM filename = '%s.%s' % (fnroot,bmFmt) if verbose: print(genFmt % (bmFmt,filename)) dtc = getattr(self,'_drawTimeCollector',None) if dtc: dtcfmts = getattr(dtc,'formats',[bmFmt]) if bmFmt in dtcfmts and not getattr(dtc,'disabled',0): dtc.clear() else: dtc = None renderPM.drawToFile(self, filename,fmt=bmFmt,showBoundary=getattr(self,'showBorder',rl_config.showBoundary),**_extraKW(self,'_renderPM_',**kw)) ext = ext + '/.' + bmFmt if dtc: dtc.save(filename) if 'eps' in plotMode: try: from rlextra.graphics import renderPS_SEP as renderPS except ImportError: from reportlab.graphics import renderPS filename = fnroot+'.eps' if verbose: print(genFmt % ('EPS',filename)) renderPS.drawToFile(self, filename, title = fnroot, dept = getattr(self,'EPS_info',['Testing'])[0], company = getattr(self,'EPS_info',['','ReportLab'])[1], preview = getattr(self,'preview',rl_config.eps_preview), showBoundary=getattr(self,'showBorder',rl_config.showBoundary), ttf_embed=getattr(self,'ttf_embed',rl_config.eps_ttf_embed), **_extraKW(self,'_renderPS_',**kw)) ext = ext + '/.eps' if 'svg' in plotMode: from reportlab.graphics import renderSVG filename = fnroot+'.svg' if verbose: print(genFmt % ('SVG',filename)) renderSVG.drawToFile(self, filename, showBoundary=getattr(self,'showBorder',rl_config.showBoundary),**_extraKW(self,'_renderSVG_',**kw)) ext = ext + '/.svg' if 'ps' in plotMode: from reportlab.graphics import renderPS filename = fnroot+'.ps' if verbose: print(genFmt % ('EPS',filename)) renderPS.drawToFile(self, filename, showBoundary=getattr(self,'showBorder',rl_config.showBoundary),**_extraKW(self,'_renderPS_',**kw)) ext = ext + '/.ps' if 'py' in plotMode: filename = fnroot+'.py' if verbose: print(genFmt % ('py',filename)) with open(filename,'wb') as f: f.write(asBytes(self._renderPy().replace('\n',os.linesep))) ext = ext + '/.py' logger.warnOnce.enabled, logger.infoOnce.enabled = _saved if hasattr(self,'saveLogger'): self.saveLogger(fnroot,ext) return ext and fnroot+ext[1:] or '' def asString(self, format, verbose=None, preview=0, **kw): """Converts to an 8 bit string in given format.""" assert format in self._saveModes, 'Unknown file format "%s"' % format from reportlab import rl_config #verbose = verbose is not None and (verbose,) or (getattr(self,'verbose',verbose),)[0] if format == 'pdf': from reportlab.graphics import renderPDF return renderPDF.drawToString(self) elif format in self._bmModes: from reportlab.graphics import renderPM return renderPM.drawToString(self, fmt=format,showBoundary=getattr(self,'showBorder', rl_config.showBoundary),**_extraKW(self,'_renderPM_',**kw)) elif format == 'eps': try: from rlextra.graphics import renderPS_SEP as renderPS except ImportError: from reportlab.graphics import renderPS return renderPS.drawToString(self, preview = preview, showBoundary=getattr(self,'showBorder',rl_config.showBoundary)) elif format == 'ps': from reportlab.graphics import renderPS return renderPS.drawToString(self, showBoundary=getattr(self,'showBorder',rl_config.showBoundary)) elif format == 'py': return self._renderPy() elif format == 'svg': from reportlab.graphics import renderSVG return renderSVG.drawToString(self,showBoundary=getattr(self,'showBorder',rl_config.showBoundary),**_extraKW(self,'_renderSVG_',**kw)) def resized(self,kind='fit',lpad=0,rpad=0,bpad=0,tpad=0): '''return a base class drawing which ensures all the contents fits''' C = self.getContents() oW = self.width oH = self.height drawing = Drawing(oW,oH,*C) xL,yL,xH,yH = drawing.getBounds() if kind=='fit' or (kind=='expand' and (xLoW-rpad or yLoH-tpad)): drawing.width = xH-xL+lpad+rpad drawing.height = yH-yL+tpad+bpad drawing.transform = (1,0,0,1,lpad-xL,bpad-yL) elif kind=='fitx' or (kind=='expandx' and (xLoW-rpad)): drawing.width = xH-xL+lpad+rpad drawing.transform = (1,0,0,1,lpad-xL,0) elif kind=='fity' or (kind=='expandy' and (yLoH-tpad)): drawing.height = yH-yL+tpad+bpad drawing.transform = (1,0,0,1,0,bpad-yL) return drawing class _DrawingEditorMixin: '''This is a mixin to provide functionality for edited drawings''' def _add(self,obj,value,name=None,validate=None,desc=None,pos=None): ''' effectively setattr(obj,name,value), but takes care of things with _attrMaps etc ''' ivc = isValidChild(value) if name and hasattr(obj,'_attrMap'): if '_attrMap' not in obj.__dict__: obj._attrMap = obj._attrMap.clone() if ivc and validate is None: validate = isValidChild obj._attrMap[name] = AttrMapValue(validate,desc) if hasattr(obj,'add') and ivc: if pos: obj.insert(pos,value,name) else: obj.add(value,name) elif name: setattr(obj,name,value) else: raise ValueError("Can't add, need name") class isStrokeDashArray(Validator): def test(self,x): return isListOfNumbersOrNone.test(x) or (isinstance(x,(list,tuple)) and isNumber(x[0]) and isListOfNumbers(x[1])) isStrokeDashArray = isStrokeDashArray() class LineShape(Shape): # base for types of lines _attrMap = AttrMap( strokeColor = AttrMapValue(isColorOrNone), strokeWidth = AttrMapValue(isNumber), strokeLineCap = AttrMapValue(OneOf(0,1,2),desc="Line cap 0=butt, 1=round & 2=square"), strokeLineJoin = AttrMapValue(OneOf(0,1,2),desc="Line join 0=miter, 1=round & 2=bevel"), strokeMiterLimit = AttrMapValue(isNumber,desc="miter limit control miter line joins"), strokeDashArray = AttrMapValue(isStrokeDashArray,desc="[numbers] or [phase,[numbers]]"), strokeOpacity = AttrMapValue(isOpacity,desc="The level of transparency of the line, any real number betwen 0 and 1"), strokeOverprint = AttrMapValue(isBoolean,desc='Turn on stroke overprinting'), overprintMask = AttrMapValue(isBoolean,desc='overprinting for ordinary CMYK',advancedUsage=1), ) def __init__(self, kw): self.strokeColor = STATE_DEFAULTS['strokeColor'] self.strokeWidth = 1 self.strokeLineCap = 0 self.strokeLineJoin = 0 self.strokeMiterLimit = 0 self.strokeDashArray = None self.strokeOpacity = None self.setProperties(kw) class Line(LineShape): _attrMap = AttrMap(BASE=LineShape, x1 = AttrMapValue(isNumber,desc=""), y1 = AttrMapValue(isNumber,desc=""), x2 = AttrMapValue(isNumber,desc=""), y2 = AttrMapValue(isNumber,desc=""), ) def __init__(self, x1, y1, x2, y2, **kw): LineShape.__init__(self, kw) self.x1 = x1 self.y1 = y1 self.x2 = x2 self.y2 = y2 def getBounds(self): "Returns bounding rectangle of object as (x1,y1,x2,y2)" return (self.x1, self.y1, self.x2, self.y2) class SolidShape(LineShape): # base for anything with outline and content _attrMap = AttrMap(BASE=LineShape, fillColor = AttrMapValue(isColorOrNone,desc="filling color of the shape, e.g. red"), fillOpacity = AttrMapValue(isOpacity,desc="the level of transparency of the color, any real number between 0 and 1"), fillOverprint = AttrMapValue(isBoolean,desc='Turn on fill overprinting'), overprintMask = AttrMapValue(isBoolean,desc='overprinting for ordinary CMYK',advancedUsage=1), fillMode = AttrMapValue(OneOf(FILL_EVEN_ODD,FILL_NON_ZERO)), ) def __init__(self, kw): self.fillColor = STATE_DEFAULTS['fillColor'] self.fillOpacity = None # do this at the end so keywords overwrite #the above settings LineShape.__init__(self, kw) # path operator constants _MOVETO, _LINETO, _CURVETO, _CLOSEPATH = list(range(4)) _PATH_OP_ARG_COUNT = (2, 2, 6, 0) # [moveTo, lineTo, curveTo, closePath] _PATH_OP_NAMES=['moveTo','lineTo','curveTo','closePath'] def _renderPath(path,drawFuncs,countOnly=False,forceClose=False): """Helper function for renderers.""" # this could be a method of Path... points = path.points i = 0 hadClosePath = 0 hadMoveTo = 0 active = not countOnly for op in path.operators: if op == _MOVETO: if forceClose: if hadMoveTo and pop!=_CLOSEPATH: hadClosePath += 1 if active: drawFuncs[_CLOSEPATH]() hadMoveTo += 1 nArgs = _PATH_OP_ARG_COUNT[op] j = i + nArgs drawFuncs[op](*points[i:j]) i = j if op == _CLOSEPATH: hadClosePath += 1 pop = op if forceClose and hadMoveTo and pop!=_CLOSEPATH: hadClosePath += 1 if active: drawFuncs[_CLOSEPATH]() return hadMoveTo == hadClosePath _fillModeMap = { None: None, FILL_NON_ZERO: FILL_NON_ZERO, 'non-zero': FILL_NON_ZERO, 'nonzero': FILL_NON_ZERO, FILL_EVEN_ODD: FILL_EVEN_ODD, 'even-odd': FILL_EVEN_ODD, 'evenodd': FILL_EVEN_ODD, } class Path(SolidShape): """Path, made up of straight lines and bezier curves.""" _attrMap = AttrMap(BASE=SolidShape, points = AttrMapValue(isListOfNumbers), operators = AttrMapValue(isListOfNumbers), isClipPath = AttrMapValue(isBoolean), autoclose = AttrMapValue(NoneOr(OneOf('svg','pdf'))), fillMode = AttrMapValue(OneOf(FILL_EVEN_ODD,FILL_NON_ZERO)), ) def __init__(self, points=None, operators=None, isClipPath=0, autoclose=None, fillMode=FILL_EVEN_ODD, **kw): SolidShape.__init__(self, kw) if points is None: points = [] if operators is None: operators = [] assert len(points) % 2 == 0, 'Point list must have even number of elements!' self.points = points self.operators = operators self.isClipPath = isClipPath self.autoclose=autoclose self.fillMode = fillMode def copy(self): new = self.__class__(self.points[:], self.operators[:]) new.setProperties(self.getProperties()) return new def moveTo(self, x, y): self.points.extend([x, y]) self.operators.append(_MOVETO) def lineTo(self, x, y): self.points.extend([x, y]) self.operators.append(_LINETO) def curveTo(self, x1, y1, x2, y2, x3, y3): self.points.extend([x1, y1, x2, y2, x3, y3]) self.operators.append(_CURVETO) def closePath(self): self.operators.append(_CLOSEPATH) def getBounds(self): points = self.points try: #in case this complex algorithm is not yet ready :) X = [] aX = X.append eX = X.extend Y=[] aY = Y.append eY = Y.extend i = 0 for op in self.operators: nArgs = _PATH_OP_ARG_COUNT[op] j = i + nArgs if nArgs==2: #either moveTo or lineT0 aX(points[i]) aY(points[i+1]) elif nArgs==6: #curveTo x1,x2,x3 = points[i:j:2] eX(_getBezierExtrema(X[-1],x1,x2,x3)) y1,y2,y3 = points[i+1:j:2] eY(_getBezierExtrema(Y[-1],y1,y2,y3)) i = j return min(X),min(Y),max(X),max(Y) except: return getPathBounds(points) EmptyClipPath=Path() #special path def getArcPoints(centerx, centery, radius, startangledegrees, endangledegrees, yradius=None, degreedelta=None, reverse=None): if yradius is None: yradius = radius points = [] degreestoradians = pi/180.0 startangle = startangledegrees*degreestoradians endangle = endangledegrees*degreestoradians while endangle.001: degreedelta = min(angle,degreedelta or 1.) radiansdelta = degreedelta*degreestoradians n = max(int(angle/radiansdelta+0.5),1) radiansdelta = angle/n n += 1 else: n = 1 radiansdelta = 0 for angle in range(n): angle = startangle+angle*radiansdelta a((centerx+radius*cos(angle),centery+yradius*sin(angle))) if reverse: points.reverse() return points class ArcPath(Path): '''Path with an addArc method''' def addArc(self, centerx, centery, radius, startangledegrees, endangledegrees, yradius=None, degreedelta=None, moveTo=None, reverse=None): P = getArcPoints(centerx, centery, radius, startangledegrees, endangledegrees, yradius=yradius, degreedelta=degreedelta, reverse=reverse) if moveTo or not len(self.operators): self.moveTo(P[0][0],P[0][1]) del P[0] for x, y in P: self.lineTo(x,y) def definePath(pathSegs=[],isClipPath=0, dx=0, dy=0, **kw): O = [] P = [] for seg in pathSegs: if not isSeq(seg): opName = seg args = [] else: opName = seg[0] args = seg[1:] if opName not in _PATH_OP_NAMES: raise ValueError('bad operator name %s' % opName) op = _PATH_OP_NAMES.index(opName) if len(args)!=_PATH_OP_ARG_COUNT[op]: raise ValueError('%s bad arguments %s' % (opName,str(args))) O.append(op) P.extend(list(args)) for d,o in (dx,0), (dy,1): for i in range(o,len(P),2): P[i] = P[i]+d #if there's a bounding box given we constrain so our points lie in it #partial bbox is allowed and does something sensible bbox = kw.pop('bbox',None) if bbox: for j in 0,1: d = bbox[j],bbox[j+2] if d[0] is None and d[1] is None: continue a = P[j::2] a, b = min(a), max(a) if d[0] is not None and d[1] is not None: c, d = min(d), max(d) fac = (b-a) if abs(fac)>=1e-6: fac = (d-c)/fac for i in range(j,len(P),2): P[i] = c + fac*(P[i]-a) else: #there's no range in the bbox so fixed as average for i in range(j,len(P),2): P[i] = (c + d)*0.5 else: #if there's a lower bound shift so min is lower bound #else there's an upper bound shift so max is upper bound c = d[0] - a if d[0] is not None else d[1] - b for i in range(j,len(P),2): P[i] += c return Path(P,O,isClipPath,**kw) class Rect(SolidShape): """Rectangle, possibly with rounded corners.""" _attrMap = AttrMap(BASE=SolidShape, x = AttrMapValue(isNumber), y = AttrMapValue(isNumber), width = AttrMapValue(isNumber,desc="width of the object in points"), height = AttrMapValue(isNumber,desc="height of the objects in points"), rx = AttrMapValue(isNumber), ry = AttrMapValue(isNumber), ) def __init__(self, x, y, width, height, rx=0, ry=0, **kw): SolidShape.__init__(self, kw) self.x = x self.y = y self.width = width self.height = height self.rx = rx self.ry = ry def copy(self): new = self.__class__(self.x, self.y, self.width, self.height) new.setProperties(self.getProperties()) return new def getBounds(self): return (self.x, self.y, self.x + self.width, self.y + self.height) class Image(SolidShape): """Bitmap image.""" _attrMap = AttrMap(BASE=SolidShape, x = AttrMapValue(isNumber), y = AttrMapValue(isNumber), width = AttrMapValue(isNumberOrNone,desc="width of the object in points"), height = AttrMapValue(isNumberOrNone,desc="height of the objects in points"), path = AttrMapValue(None), ) def __init__(self, x, y, width, height, path, **kw): SolidShape.__init__(self, kw) self.x = x self.y = y self.width = width self.height = height self.path = path def copy(self): new = self.__class__(self.x, self.y, self.width, self.height, self.path) new.setProperties(self.getProperties()) return new def getBounds(self): # bug fix contributed by Marcel Tromp return (self.x, self.y, self.x + self.width, self.y + self.height) class Circle(SolidShape): _attrMap = AttrMap(BASE=SolidShape, cx = AttrMapValue(isNumber,desc="x of the centre"), cy = AttrMapValue(isNumber,desc="y of the centre"), r = AttrMapValue(isNumber,desc="radius in points"), ) def __init__(self, cx, cy, r, **kw): SolidShape.__init__(self, kw) self.cx = cx self.cy = cy self.r = r def copy(self): new = self.__class__(self.cx, self.cy, self.r) new.setProperties(self.getProperties()) return new def getBounds(self): return (self.cx - self.r, self.cy - self.r, self.cx + self.r, self.cy + self.r) class Ellipse(SolidShape): _attrMap = AttrMap(BASE=SolidShape, cx = AttrMapValue(isNumber,desc="x of the centre"), cy = AttrMapValue(isNumber,desc="y of the centre"), rx = AttrMapValue(isNumber,desc="x radius"), ry = AttrMapValue(isNumber,desc="y radius"), ) def __init__(self, cx, cy, rx, ry, **kw): SolidShape.__init__(self, kw) self.cx = cx self.cy = cy self.rx = rx self.ry = ry def copy(self): new = self.__class__(self.cx, self.cy, self.rx, self.ry) new.setProperties(self.getProperties()) return new def getBounds(self): return (self.cx - self.rx, self.cy - self.ry, self.cx + self.rx, self.cy + self.ry) class Wedge(SolidShape): """A "slice of a pie" by default translates to a polygon moves anticlockwise from start angle to end angle""" _attrMap = AttrMap(BASE=SolidShape, centerx = AttrMapValue(isNumber,desc="x of the centre"), centery = AttrMapValue(isNumber,desc="y of the centre"), radius = AttrMapValue(isNumber,desc="radius in points"), startangledegrees = AttrMapValue(isNumber), endangledegrees = AttrMapValue(isNumber), yradius = AttrMapValue(isNumberOrNone), radius1 = AttrMapValue(isNumberOrNone), yradius1 = AttrMapValue(isNumberOrNone), annular = AttrMapValue(isBoolean,desc='treat as annular ring'), ) degreedelta = 1 # jump every 1 degrees def __init__(self, centerx, centery, radius, startangledegrees, endangledegrees, yradius=None, annular=False, **kw): SolidShape.__init__(self, kw) while endangledegrees0.001: degreedelta = min(self.degreedelta or 1.,angle) radiansdelta = degreedelta*degreestoradians n = max(1,int(angle/radiansdelta+0.5)) radiansdelta = angle/n n += 1 else: n = 1 radiansdelta = 0 CA = [] CAA = CA.append a = points.append for angle in range(n): angle = startangle+angle*radiansdelta CAA((cos(angle),sin(angle))) for c,s in CA: a(centerx+radius*c) a(centery+yradius*s) if (radius1==0 or radius1 is None) and (yradius1==0 or yradius1 is None): a(centerx); a(centery) else: CA.reverse() for c,s in CA: a(centerx+radius1*c) a(centery+yradius1*s) if self.annular: P = Path(fillMode=getattr(self,'fillMode', FILL_EVEN_ODD)) P.moveTo(points[0],points[1]) for x in range(2,2*n,2): P.lineTo(points[x],points[x+1]) P.closePath() P.moveTo(points[2*n],points[2*n+1]) for x in range(2*n+2,4*n,2): P.lineTo(points[x],points[x+1]) P.closePath() return P else: return Polygon(points) def copy(self): new = self.__class__(self.centerx, self.centery, self.radius, self.startangledegrees, self.endangledegrees) new.setProperties(self.getProperties()) return new def getBounds(self): return self.asPolygon().getBounds() class Polygon(SolidShape): """Defines a closed shape; Is implicitly joined back to the start for you.""" _attrMap = AttrMap(BASE=SolidShape, points = AttrMapValue(isListOfNumbers,desc="list of numbers in the form x1, y1, x2, y2 ... xn, yn"), ) def __init__(self, points=[], **kw): SolidShape.__init__(self, kw) assert len(points) % 2 == 0, 'Point list must have even number of elements!' self.points = points or [] def copy(self): new = self.__class__(self.points) new.setProperties(self.getProperties()) return new def getBounds(self): return getPointsBounds(self.points) class PolyLine(LineShape): """Series of line segments. Does not define a closed shape; never filled even if apparently joined. Put the numbers in the list, not two-tuples.""" _attrMap = AttrMap(BASE=LineShape, points = AttrMapValue(isListOfNumbers,desc="list of numbers in the form x1, y1, x2, y2 ... xn, yn"), ) def __init__(self, points=[], **kw): LineShape.__init__(self, kw) points = points or [] lenPoints = len(points) if lenPoints: if isSeq(points[0]): L = [] for (x,y) in points: L.append(x) L.append(y) points = L else: assert len(points) % 2 == 0, 'Point list must have even number of elements!' self.points = points def copy(self): new = self.__class__(self.points) new.setProperties(self.getProperties()) return new def getBounds(self): return getPointsBounds(self.points) class Hatching(Path): '''define a hatching of a set of polygons defined by lists of the form [x0,y0,x1,y1,....,xn,yn]''' _attrMap = AttrMap(BASE=Path, xyLists = AttrMapValue(EitherOr((isListOfNumbers,SequenceOf(isListOfNumbers,lo=1)),"xy list(s)"),desc="list(s) of numbers in the form x1, y1, x2, y2 ... xn, yn"), angles = AttrMapValue(EitherOr((isNumber,isListOfNumbers,"angle(s)")),desc="the angle or list of angles at which hatching lines should be drawn"), spacings = AttrMapValue(EitherOr((isNumber,isListOfNumbers,"spacings(s)")),desc="orthogonal distance(s) between hatching lines"), ) def __init__(self, spacings=2, angles=45, xyLists=[], **kwds): Path.__init__(self, **kwds) if isListOfNumbers(xyLists): xyLists = (xyLists,) if isNumber(angles): angles = (angles,) #turn into a sequence if isNumber(spacings): spacings = (spacings,) #turn into a sequence i = len(angles)-len(spacings) if i>0: spacings = list(spacings)+i*[spacings[-1]] self.xyLists = xyLists self.angles = angles self.spacings = spacings moveTo = self.moveTo lineTo = self.lineTo for i, theta in enumerate(angles): spacing = spacings[i] theta = radians(theta) cosTheta = cos(theta) sinTheta = sin(theta) spanMin = 0x7fffffff spanMax = -spanMin # Loop to determine the span over which diagonal lines must be drawn. for P in xyLists: for j in range(0,len(P),2): # rotated point, since the stripes may be at an angle. y = P[j+1]*cosTheta-P[j]*sinTheta spanMin = min(y,spanMin) spanMax = max(y,spanMax) # Turn the span into a discrete step range. spanStart = int(floor(spanMin/spacing)) - 1 spanEnd = int(floor(spanMax/spacing)) + 1 # Loop to create all stripes. for step in range(spanStart,spanEnd): nodeX = [] stripeY = spacing*step # Loop to build a node list for one row of stripes. for P in xyLists: k = len(P)-2 #start by comparing with the last point for j in range(0,len(P),2): a = P[k] b = P[k+1] a1 = a*cosTheta + b*sinTheta b1 = b*cosTheta - a*sinTheta x = P[j] y = P[j+1] x1 = x*cosTheta+y*sinTheta y1 = y*cosTheta-x*sinTheta # Find the node, if any. if (b1=stripeY) or y1=stripeY: nodeX.append(a1+(x1-a1)*(stripeY-b1)/(y1-b1)) k = j nodeX.sort() # Loop to draw one row of line segments. for j in range(0,len(nodeX),2): # Rotate the points back to their original coordinate system. a = nodeX[j]*cosTheta - stripeY*sinTheta b = stripeY*cosTheta+nodeX[j]*sinTheta x = nodeX[j+1]*cosTheta - stripeY*sinTheta y = stripeY*cosTheta + nodeX[j+1]*sinTheta #Draw a single stripe segment. moveTo(a,b) lineTo(x,y) def numericXShift(tA,text,w,fontName,fontSize,encoding=None,pivotCharacter=decimalSymbol): dp = getattr(tA,'_dp',pivotCharacter) i = text.rfind(dp) if i>=0: dpOffs = getattr(tA,'_dpLen',0) w = dpOffs + stringWidth(text[:i],fontName,fontSize,encoding) return w class String(Shape): """Not checked against the spec, just a way to make something work. Can be anchored left, middle or end.""" # to do. _attrMap = AttrMap( x = AttrMapValue(isNumber,desc="x point of anchoring"), y = AttrMapValue(isNumber,desc="y point of anchoring"), text = AttrMapValue(isString,desc="the text of the string"), fontName = AttrMapValue(None,desc="font name of the text - font is either acrobat standard or registered when using external font."), fontSize = AttrMapValue(isNumber,desc="font size"), fillColor = AttrMapValue(isColorOrNone,desc="color of the font"), textAnchor = AttrMapValue(OneOf('start','middle','end','numeric'),desc="treat (x,y) as one of the options below."), encoding = AttrMapValue(isString), textRenderMode = AttrMapValue(OneOf(0,1,2,3,4,5,6,7),desc="Control whether text is filled/stroked etc etc"), ) encoding = 'utf8' def __init__(self, x, y, text, **kw): self.x = x self.y = y self.text = text self.textAnchor = 'start' self.fontName = STATE_DEFAULTS['fontName'] self.fontSize = STATE_DEFAULTS['fontSize'] self.fillColor = STATE_DEFAULTS['fillColor'] self.setProperties(kw) def getEast(self): return self.x + stringWidth(self.text,self.fontName,self.fontSize, self.encoding) def copy(self): new = self.__class__(self.x, self.y, self.text) new.setProperties(self.getProperties()) return new def getBounds(self): # assumes constant drop of 0.2*size to baseline t = self.text w = stringWidth(t,self.fontName,self.fontSize,self.encoding) tA = self.textAnchor x = self.x if tA!='start': if tA=='middle': x -= 0.5*w elif tA=='end': x -= w elif tA=='numeric': x -= numericXShift(tA,t,w,self.fontName,self.fontSize,self.encoding) return (x, self.y - 0.2 * self.fontSize, x+w, self.y + self.fontSize) class UserNode(_DrawTimeResizeable): """A simple template for creating a new node. The user (Python programmer) may subclasses this. provideNode() must be defined to provide a Shape primitive when called by a renderer. It does NOT inherit from Shape, as the renderer always replaces it, and your own classes can safely inherit from it without getting lots of unintended behaviour.""" def provideNode(self): """Override this to create your own node. This lets widgets be added to drawings; they must create a shape (typically a group) so that the renderer can draw the custom node.""" raise NotImplementedError("this method must be redefined by the user/programmer") class DirectDraw(Shape): """try to draw directly on the canvas""" def drawDirectly(self,canvas): raise NotImplementedError("this method must be redefined by the user/programmer") def test(): r = Rect(10,10,200,50) import pprint pp = pprint.pprint w = sys.stdout.write w('a Rectangle: ') pp(r.getProperties()) w('\nverifying...') r.verify() w(' OK\n') #print 'setting rect.z = "spam"' #r.z = 'spam' w('deleting rect.width ') del r.width w('verifying...') r.verify() if __name__=='__main__': test() ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1704966359.0 reportlab-4.1.0/src/reportlab/graphics/svgpath.py0000664000175000017500000003736414547734327021546 0ustar00rptlabrptlab'''this code is derived from that used by svglib.''' __all__=('SvgPath',) import re, copy from math import acos, ceil, copysign, cos, degrees, fabs, hypot, radians, sin, sqrt from .shapes import Group, mmult, rotate, translate, transformPoint, Path, FILL_EVEN_ODD, _CLOSEPATH, UserNode def split_floats(op, min_num, value): """Split `value`, a list of numbers as a string, to a list of float numbers. Also optionally insert a `l` or `L` operation depending on the operation and the length of values. Example: with op='m' and value='10,20 30,40,' the returned value will be ['m', [10.0, 20.0], 'l', [30.0, 40.0]] """ floats = [float(seq) for seq in re.findall(r'(-?\d*\.?\d*(?:[eE][+-]?\d+)?)', value) if seq] res = [] for i in range(0, len(floats), min_num): if i > 0 and op in {'m', 'M'}: op = 'l' if op == 'm' else 'L' res.extend([op, floats[i:i + min_num]]) return res def split_arc_values(op, value): float_re = r'(-?\d*\.?\d*(?:[eE][+-]?\d+)?)' flag_re = r'([1|0])' # 3 numb, 2 flags, 1 coord pair a_seq_re = r'[\s,]*'.join([ float_re, float_re, float_re, flag_re, flag_re, float_re, float_re ]) + r'[\s,]*' res = [] for seq in re.finditer(a_seq_re, value.strip()): res.extend([op, [float(num) for num in seq.groups()]]) return res def normalise_svg_path(attr): """Normalise SVG path. This basically introduces operator codes for multi-argument parameters. Also, it fixes sequences of consecutive M or m operators to MLLL... and mlll... operators. It adds an empty list as argument for Z and z only in order to make the resul- ting list easier to iterate over. E.g. "M 10 20, M 20 20, L 30 40, 40 40, Z" -> ['M', [10, 20], 'L', [20, 20], 'L', [30, 40], 'L', [40, 40], 'Z', []] """ # operator codes mapped to the minimum number of expected arguments ops = { 'A': 7, 'a': 7, 'Q': 4, 'q': 4, 'T': 2, 't': 2, 'S': 4, 's': 4, 'M': 2, 'L': 2, 'm': 2, 'l': 2, 'H': 1, 'V': 1, 'h': 1, 'v': 1, 'C': 6, 'c': 6, 'Z': 0, 'z': 0, } op_keys = ops.keys() # do some preprocessing result = [] groups = re.split('([achlmqstvz])', attr.strip(), flags=re.I) op = None for item in groups: if item.strip() == '': continue if item in op_keys: # fix sequences of M to one M plus a sequence of L operators, # same for m and l. if item == 'M' and item == op: op = 'L' elif item == 'm' and item == op: op = 'l' else: op = item if ops[op] == 0: # Z, z result.extend([op, []]) else: if op.lower() == 'a': result.extend(split_arc_values(op, item)) else: result.extend(split_floats(op, ops[op], item)) op = result[-2] # Remember last op return result def convert_quadratic_to_cubic_path(q0, q1, q2): """ Convert a quadratic Bezier curve through q0, q1, q2 to a cubic one. """ c0 = q0 c1 = (q0[0] + 2 / 3 * (q1[0] - q0[0]), q0[1] + 2 / 3 * (q1[1] - q0[1])) c2 = (c1[0] + 1 / 3 * (q2[0] - q0[0]), c1[1] + 1 / 3 * (q2[1] - q0[1])) c3 = q2 return c0, c1, c2, c3 # *********************************************** # Helper functions for elliptical arc conversion. # *********************************************** def vector_angle(u, v): d = hypot(*u) * hypot(*v) if d == 0: return 0 c = (u[0] * v[0] + u[1] * v[1]) / d if c < -1: c = -1 elif c > 1: c = 1 s = u[0] * v[1] - u[1] * v[0] return degrees(copysign(acos(c), s)) def end_point_to_center_parameters(x1, y1, x2, y2, fA, fS, rx, ry, phi=0): ''' See http://www.w3.org/TR/SVG/implnote.html#ArcImplementationNotes F.6.5 note that we reduce phi to zero outside this routine ''' rx = fabs(rx) ry = fabs(ry) # step 1 if phi: phi_rad = radians(phi) sin_phi = sin(phi_rad) cos_phi = cos(phi_rad) tx = 0.5 * (x1 - x2) ty = 0.5 * (y1 - y2) x1d = cos_phi * tx - sin_phi * ty y1d = sin_phi * tx + cos_phi * ty else: x1d = 0.5 * (x1 - x2) y1d = 0.5 * (y1 - y2) # step 2 # we need to calculate # (rx*rx*ry*ry-rx*rx*y1d*y1d-ry*ry*x1d*x1d) # ----------------------------------------- # (rx*rx*y1d*y1d+ry*ry*x1d*x1d) # # that is equivalent to # # rx*rx*ry*ry # = ----------------------------- - 1 # (rx*rx*y1d*y1d+ry*ry*x1d*x1d) # # 1 # = -------------------------------- - 1 # x1d*x1d/(rx*rx) + y1d*y1d/(ry*ry) # # = 1/r - 1 # # it turns out r is what they recommend checking # for the negative radicand case r = x1d * x1d / (rx * rx) + y1d * y1d / (ry * ry) if r > 1: rr = sqrt(r) rx *= rr ry *= rr r = x1d * x1d / (rx * rx) + y1d * y1d / (ry * ry) r = 1 / r - 1 elif r != 0: r = 1 / r - 1 if -1e-10 < r < 0: r = 0 r = sqrt(r) if fA == fS: r = -r cxd = (r * rx * y1d) / ry cyd = -(r * ry * x1d) / rx # step 3 if phi: cx = cos_phi * cxd - sin_phi * cyd + 0.5 * (x1 + x2) cy = sin_phi * cxd + cos_phi * cyd + 0.5 * (y1 + y2) else: cx = cxd + 0.5 * (x1 + x2) cy = cyd + 0.5 * (y1 + y2) # step 4 theta1 = vector_angle((1, 0), ((x1d - cxd) / rx, (y1d - cyd) / ry)) dtheta = vector_angle( ((x1d - cxd) / rx, (y1d - cyd) / ry), ((-x1d - cxd) / rx, (-y1d - cyd) / ry) ) % 360 if fS == 0 and dtheta > 0: dtheta -= 360 elif fS == 1 and dtheta < 0: dtheta += 360 return cx, cy, rx, ry, -theta1, -dtheta def bezier_arc_from_centre(cx, cy, rx, ry, start_ang=0, extent=90): if abs(extent) <= 90: nfrag = 1 frag_angle = extent else: nfrag = ceil(abs(extent) / 90) frag_angle = extent / nfrag if frag_angle == 0: return [] frag_rad = radians(frag_angle) half_rad = frag_rad * 0.5 kappa = abs(4 / 3 * (1 - cos(half_rad)) / sin(half_rad)) if frag_angle < 0: kappa = -kappa point_list = [] theta1 = radians(start_ang) start_rad = theta1 + frag_rad c1 = cos(theta1) s1 = sin(theta1) for i in range(nfrag): c0 = c1 s0 = s1 theta1 = start_rad + i * frag_rad c1 = cos(theta1) s1 = sin(theta1) point_list.append((cx + rx * c0, cy - ry * s0, cx + rx * (c0 - kappa * s0), cy - ry * (s0 + kappa * c0), cx + rx * (c1 + kappa * s1), cy - ry * (s1 - kappa * c1), cx + rx * c1, cy - ry * s1)) return point_list def bezier_arc_from_end_points(x1, y1, rx, ry, phi, fA, fS, x2, y2): if (x1 == x2 and y1 == y2): # From https://www.w3.org/TR/SVG/implnote.html#ArcImplementationNotes: # If the endpoints (x1, y1) and (x2, y2) are identical, then this is # equivalent to omitting the elliptical arc segment entirely. return [] if phi: # Our box bezier arcs can't handle rotations directly # move to a well known point, eliminate phi and transform the other point mx = mmult(rotate(-phi), translate(-x1, -y1)) tx2, ty2 = transformPoint(mx, (x2, y2)) # Convert to box form in unrotated coords cx, cy, rx, ry, start_ang, extent = end_point_to_center_parameters( 0, 0, tx2, ty2, fA, fS, rx, ry ) bp = bezier_arc_from_centre(cx, cy, rx, ry, start_ang, extent) # Re-rotate by the desired angle and add back the translation mx = mmult(translate(x1, y1), rotate(phi)) res = [] for x1, y1, x2, y2, x3, y3, x4, y4 in bp: res.append( transformPoint(mx, (x1, y1)) + transformPoint(mx, (x2, y2)) + transformPoint(mx, (x3, y3)) + transformPoint(mx, (x4, y4)) ) return res else: cx, cy, rx, ry, start_ang, extent = end_point_to_center_parameters( x1, y1, x2, y2, fA, fS, rx, ry ) return bezier_arc_from_centre(cx, cy, rx, ry, start_ang, extent) class SvgPath(Path,UserNode): """Path, from an svg path string""" def __init__(self, s, isClipPath=0, autoclose=None, fillMode=FILL_EVEN_ODD, **kw): vswap = kw.pop('vswap',0) hswap = kw.pop('hswap',0) super().__init__( points=None,operators=None, isClipPath=isClipPath, autoclose=autoclose, fillMode=fillMode, **kw) if not s: return normPath = normalise_svg_path(s) points = self.points # Track subpaths needing to be closed later unclosed_subpath_pointers = [] subpath_start = [] lastop = '' last_quadratic_cp = None for i in range(0, len(normPath), 2): op, nums = normPath[i:i+2] if op in ('m', 'M') and i > 0 and self.operators[-1] != _CLOSEPATH: unclosed_subpath_pointers.append(len(self.operators)) # moveto absolute if op == 'M': self.moveTo(*nums) subpath_start = points[-2:] # lineto absolute elif op == 'L': self.lineTo(*nums) # moveto relative elif op == 'm': if len(points) >= 2: if lastop in ('Z', 'z'): starting_point = subpath_start else: starting_point = points[-2:] xn, yn = starting_point[0] + nums[0], starting_point[1] + nums[1] self.moveTo(xn, yn) else: self.moveTo(*nums) subpath_start = points[-2:] # lineto relative elif op == 'l': xn, yn = points[-2] + nums[0], points[-1] + nums[1] self.lineTo(xn, yn) # horizontal/vertical line absolute elif op == 'H': self.lineTo(nums[0], points[-1]) elif op == 'V': self.lineTo(points[-2], nums[0]) # horizontal/vertical line relative elif op == 'h': self.lineTo(points[-2] + nums[0], points[-1]) elif op == 'v': self.lineTo(points[-2], points[-1] + nums[0]) # cubic bezier, absolute elif op == 'C': self.curveTo(*nums) elif op == 'S': x2, y2, xn, yn = nums if len(points) < 4 or lastop not in {'c', 'C', 's', 'S'}: xp, yp, x0, y0 = points[-2:] * 2 else: xp, yp, x0, y0 = points[-4:] xi, yi = x0 + (x0 - xp), y0 + (y0 - yp) self.curveTo(xi, yi, x2, y2, xn, yn) # cubic bezier, relative elif op == 'c': xp, yp = points[-2:] x1, y1, x2, y2, xn, yn = nums self.curveTo(xp + x1, yp + y1, xp + x2, yp + y2, xp + xn, yp + yn) elif op == 's': x2, y2, xn, yn = nums if len(points) < 4 or lastop not in {'c', 'C', 's', 'S'}: xp, yp, x0, y0 = points[-2:] * 2 else: xp, yp, x0, y0 = points[-4:] xi, yi = x0 + (x0 - xp), y0 + (y0 - yp) self.curveTo(xi, yi, x0 + x2, y0 + y2, x0 + xn, y0 + yn) # quadratic bezier, absolute elif op == 'Q': x0, y0 = points[-2:] x1, y1, xn, yn = nums last_quadratic_cp = (x1, y1) (x0, y0), (x1, y1), (x2, y2), (xn, yn) = \ convert_quadratic_to_cubic_path((x0, y0), (x1, y1), (xn, yn)) self.curveTo(x1, y1, x2, y2, xn, yn) elif op == 'T': if last_quadratic_cp is not None: xp, yp = last_quadratic_cp else: xp, yp = points[-2:] x0, y0 = points[-2:] xi, yi = x0 + (x0 - xp), y0 + (y0 - yp) last_quadratic_cp = (xi, yi) xn, yn = nums (x0, y0), (x1, y1), (x2, y2), (xn, yn) = \ convert_quadratic_to_cubic_path((x0, y0), (xi, yi), (xn, yn)) self.curveTo(x1, y1, x2, y2, xn, yn) # quadratic bezier, relative elif op == 'q': x0, y0 = points[-2:] x1, y1, xn, yn = nums x1, y1, xn, yn = x0 + x1, y0 + y1, x0 + xn, y0 + yn last_quadratic_cp = (x1, y1) (x0, y0), (x1, y1), (x2, y2), (xn, yn) = \ convert_quadratic_to_cubic_path((x0, y0), (x1, y1), (xn, yn)) self.curveTo(x1, y1, x2, y2, xn, yn) elif op == 't': if last_quadratic_cp is not None: xp, yp = last_quadratic_cp else: xp, yp = points[-2:] x0, y0 = points[-2:] xn, yn = nums xn, yn = x0 + xn, y0 + yn xi, yi = x0 + (x0 - xp), y0 + (y0 - yp) last_quadratic_cp = (xi, yi) (x0, y0), (x1, y1), (x2, y2), (xn, yn) = \ convert_quadratic_to_cubic_path((x0, y0), (xi, yi), (xn, yn)) self.curveTo(x1, y1, x2, y2, xn, yn) # elliptical arc elif op in ('A', 'a'): rx, ry, phi, fA, fS, x2, y2 = nums x1, y1 = points[-2:] if op == 'a': x2 += x1 y2 += y1 if abs(rx) <= 1e-10 or abs(ry) <= 1e-10: self.lineTo(x2, y2) else: bp = bezier_arc_from_end_points(x1, y1, rx, ry, phi, fA, fS, x2, y2) for _, _, x1, y1, x2, y2, xn, yn in bp: self.curveTo(x1, y1, x2, y2, xn, yn) # close self elif op in ('Z', 'z'): self.closePath() else: logger.debug("Suspicious self operator: %s", op) if op not in ('Q', 'q', 'T', 't'): last_quadratic_cp = None lastop = op if self.operators[-1] != _CLOSEPATH: unclosed_subpath_pointers.append(len(self.operators)) if vswap or hswap: b = self.getBounds() if hswap: m = b[2]+b[0] for i in range(0,len(points),2): points[i] = m - points[i] if vswap: m = b[3]+b[1] for i in range(1,len(points),2): points[i] = m - points[i] if unclosed_subpath_pointers and self.fillColor is not None: # ReportLab doesn't fill unclosed paths, so we are creating a copy # of self with all subpaths closed, but without stroke. # https://bitbucket.org/rptlab/reportlab/issues/99/ closed_path = Path() closed_path.__dict__.update(copy.deepcopy(self.__dict__)) for pointer in reversed(unclosed_subpath_pointers): closed_path.operators.insert(pointer, _CLOSEPATH) self.__closed_path = closed_path self.fillColor = None else: self.__closed_path = None def provideNode(self): p = Path() p.__dict__ = self.__dict__.copy() del p._SvgPath__closed_path if self.__closed_path: g = Group() g.add(self.__closed_path) g.add(p) return g else: return p ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1691062243.0 reportlab-4.1.0/src/reportlab/graphics/testdrawings.py0000664000175000017500000002233114462707743022572 0ustar00rptlabrptlab#!/bin/env python #Copyright ReportLab Europe Ltd. 2000-2017 #see license.txt for license details #history https://hg.reportlab.com/hg-public/reportlab/log/tip/src/reportlab/graphics/testdrawings.py __version__='3.3.0' __doc__="""Defines some standard drawings to use as test cases This contains a number of routines to generate test drawings for reportlab/graphics. For now they are contrived, but we will expand them to try and trip up any parser. Feel free to add more. """ from reportlab.graphics.shapes import * from reportlab.lib import colors def getDrawing1(): """Hello World, on a rectangular background""" D = Drawing(400, 200) D.add(Rect(50, 50, 300, 100, fillColor=colors.yellow)) #round corners D.add(String(180,100, 'Hello World', fillColor=colors.red)) return D def getDrawing2(): """This demonstrates the basic shapes. There are no groups or references. Each solid shape should have a purple fill.""" D = Drawing(400, 200) #, fillColor=colors.purple) D.add(Line(10,10,390,190)) D.add(Circle(100,100,20, fillColor=colors.purple)) D.add(Circle(200,100,20, fillColor=colors.purple)) D.add(Circle(300,100,20, fillColor=colors.purple)) D.add(Wedge(330,100,40, -10,40, fillColor=colors.purple)) D.add(PolyLine([120,10,130,20,140,10,150,20,160,10, 170,20,180,10,190,20,200,10])) D.add(Polygon([300,20,350,20,390,80,300,75, 330, 40])) D.add(Ellipse(50, 150, 40, 20)) D.add(Rect(120, 150, 60, 30, strokeWidth=10, strokeColor=colors.red, fillColor=colors.yellow)) #square corners D.add(Rect(220, 150, 60, 30, 10, 10)) #round corners D.add(String(10,50, 'Basic Shapes', fillColor=colors.black)) return D ##def getDrawing2(): ## """This drawing uses groups. Each group has two circles and a comment. ## The line style is set at group level and should be red for the left, ## bvlue for the right.""" ## D = Drawing(400, 200) ## ## Group1 = Group() ## ## Group1.add(String(50, 50, 'Group 1', fillColor=colors.black)) ## Group1.add(Circle(75,100,25)) ## Group1.add(Circle(125,100,25)) ## D.add(Group1) ## ## Group2 = Group( ## String(250, 50, 'Group 2', fillColor=colors.black), ## Circle(275,100,25), ## Circle(325,100,25)#, ##def getDrawing2(): ## """This drawing uses groups. Each group has two circles and a comment. ## The line style is set at group level and should be red for the left, ## bvlue for the right.""" ## D = Drawing(400, 200) ## ## Group1 = Group() ## ## Group1.add(String(50, 50, 'Group 1', fillColor=colors.black)) ## Group1.add(Circle(75,100,25)) ## Group1.add(Circle(125,100,25)) ## D.add(Group1) ## ## Group2 = Group( ## String(250, 50, 'Group 2', fillColor=colors.black), ## Circle(275,100,25), ## Circle(325,100,25)#, ## ## #group attributes ## #strokeColor=colors.blue ## ) ## D.add(Group2) ## return D ## ## ##def getDrawing3(): ## """This uses a named reference object. The house is a 'subroutine' ## the basic brick colored walls are defined, but the roof and window ## color are undefined and may be set by the container.""" ## ## D = Drawing(400, 200, fill=colors.bisque) ## ## ## House = Group( ## Rect(2,20,36,30, fill=colors.bisque), #walls ## Polygon([0,20,40,20,20,5]), #roof ## Rect(8, 38, 8, 12), #door ## Rect(25, 38, 8, 7), #window ## Rect(8, 25, 8, 7), #window ## Rect(25, 25, 8, 7) #window ## ## ) ## D.addDef('MyHouse', House) ## ## # one row all the same color ## D.add(String(20, 40, 'British Street...',fill=colors.black)) ## for i in range(6): ## x = i * 50 ## D.add(NamedReference('MyHouse', ## House, ## transform=translate(x, 40), ## fill = colors.brown ## ) ## ) ## ## # now do a row all different ## D.add(String(20, 120, 'Mediterranean Street...',fill=colors.black)) ## x = 0 ## for color in (colors.blue, colors.yellow, colors.orange, ## colors.red, colors.green, colors.chartreuse): ## D.add(NamedReference('MyHouse', ## House, ## transform=translate(x,120), ## fill = color, ## ) ## ) ## x = x + 50 ## #..by popular demand, the mayor gets a big one at the end ## D.add(NamedReference('MyHouse', ## House, ## transform=mmult(translate(x,110), scale(1.2,1.2)), ## fill = color, ## ) ## ) ## ## ## return D ## ##def getDrawing4(): ## """This tests that attributes are 'unset' correctly when ## one steps back out of a drawing node. All the circles are part of a ## group setting the line color to blue; the second circle explicitly ## sets it to red. Ideally, the third circle should go back to blue.""" ## D = Drawing(400, 200) ## ## ## G = Group( ## Circle(100,100,20), ## Circle(200,100,20, stroke=colors.blue), ## Circle(300,100,20), ## stroke=colors.red, ## stroke_width=3, ## fill=colors.aqua ## ) ## D.add(G) ## ## ## D.add(String(10,50, 'Stack Unwinding - should be red, blue, red')) ## ## return D ## ## ##def getDrawing5(): ## """This Rotates Coordinate Axes""" ## D = Drawing(400, 200) ## ## ## ## Axis = Group( ## Line(0,0,100,0), #x axis ## Line(0,0,0,50), # y axis ## Line(0,10,10,10), #ticks on y axis ## Line(0,20,10,20), ## Line(0,30,10,30), ## Line(0,40,10,40), ## Line(10,0,10,10), #ticks on x axis ## Line(20,0,20,10), ## Line(30,0,30,10), ## Line(40,0,40,10), ## Line(50,0,50,10), ## Line(60,0,60,10), ## Line(70,0,70,10), ## Line(80,0,80,10), ## Line(90,0,90,10), ## String(20, 35, 'Axes', fill=colors.black) ## ) ## ## D.addDef('Axes', Axis) ## ## D.add(NamedReference('Axis', Axis, ## transform=translate(10,10))) ## D.add(NamedReference('Axis', Axis, ## transform=mmult(translate(150,10),rotate(15))) ## ) ## return D ## ##def getDrawing6(): ## """This Rotates Text""" ## D = Drawing(400, 300, fill=colors.black) ## ## xform = translate(200,150) ## C = (colors.black,colors.red,colors.green,colors.blue,colors.brown,colors.gray, colors.pink, ## colors.lavender,colors.lime, colors.mediumblue, colors.magenta, colors.limegreen) ## ## for i in range(12): ## D.add(String(0, 0, ' - - Rotated Text', fill=C[i%len(C)], transform=mmult(xform, rotate(30*i)))) ## ## return D ## ##def getDrawing7(): ## """This defines and tests a simple UserNode0 (the trailing zero denotes ## an experimental method which is not part of the supported API yet). ## Each of the four charts is a subclass of UserNode which generates a random ## series when rendered.""" ## ## class MyUserNode(UserNode0): ## import whrandom, math ## ## ## def provideNode(self, sender): ## """draw a simple chart that changes everytime it's drawn""" ## # print "here's a random number %s" % self.whrandom.random() ## #print "MyUserNode.provideNode being called by %s" % sender ## g = Group() ## #g._state = self._state # this is naughty ## PingoNode.__init__(g, self._state) # is this less naughty ? ## w = 80.0 ## h = 50.0 ## g.add(Rect(0,0, w, h, stroke=colors.black)) ## N = 10.0 ## x,y = (0,h) ## dx = w/N ## for ii in range(N): ## dy = (h/N) * self.whrandom.random() ## g.add(Line(x,y,x+dx, y-dy)) ## x = x + dx ## y = y - dy ## return g ## ## D = Drawing(400,200, fill=colors.white) # AR - same size as others ## ## D.add(MyUserNode()) ## ## graphcolor= [colors.green, colors.red, colors.brown, colors.purple] ## for ii in range(4): ## D.add(Group( MyUserNode(stroke=graphcolor[ii], stroke_width=2), ## transform=translate(ii*90,0) )) ## ## #un = MyUserNode() ## #print un.provideNode() ## return D ## ##def getDrawing8(): ## """Test Path operations--lineto, curveTo, etc.""" ## D = Drawing(400, 200, fill=None, stroke=colors.purple, stroke_width=2) ## ## xform = translate(200,100) ## C = (colors.black,colors.red,colors.green,colors.blue,colors.brown,colors.gray, colors.pink, ## colors.lavender,colors.lime, colors.mediumblue, colors.magenta, colors.limegreen) ## p = Path(50,50) ## p.lineTo(100,100) ## p.moveBy(-25,25) ## p.curveTo(150,125, 125,125, 200,50) ## p.curveTo(175, 75, 175, 98, 62, 87) ## ## ## D.add(p) ## D.add(String(10,30, 'Tests of path elements-lines and bezier curves-and text formating')) ## D.add(Line(220,150, 220,200, stroke=colors.red)) ## D.add(String(220,180, "Text should be centered", text_anchor="middle") ) ## ## ## return D if __name__=='__main__': print(__doc__) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1691062243.0 reportlab-4.1.0/src/reportlab/graphics/testshapes.py0000664000175000017500000004152514462707743022245 0ustar00rptlabrptlab#!/bin/env python #Copyright ReportLab Europe Ltd. 2000-2017 #see license.txt for license details #history https://hg.reportlab.com/hg-public/reportlab/log/tip/src/reportlab/graphics/testshapes.py # testshapes.py - draws shapes onto a PDF canvas. __version__ = ''' $Id $ ''' __doc__='''Execute this script to see some test drawings. This contains a number of routines to generate test drawings for reportlab/graphics. For now many of them are contrived, but we will expand them to try and trip up any parser. Feel free to add more. ''' import os, sys from io import BytesIO from reportlab.lib import colors from reportlab.lib.units import cm from reportlab.lib.utils import asNative, base64_decodebytes from reportlab.pdfgen.canvas import Canvas from reportlab.pdfbase.pdfmetrics import stringWidth from reportlab.graphics.shapes import * import unittest _FONTS = ['Times-Roman','Vera','Times-BoldItalic',] def _setup(): from reportlab.pdfbase import pdfmetrics, ttfonts pdfmetrics.registerFont(ttfonts.TTFont("Vera", "Vera.ttf")) pdfmetrics.registerFont(ttfonts.TTFont("VeraBd", "VeraBd.ttf")) pdfmetrics.registerFont(ttfonts.TTFont("VeraIt", "VeraIt.ttf")) pdfmetrics.registerFont(ttfonts.TTFont("VeraBI", "VeraBI.ttf")) F = ['Times-Roman','Courier','Helvetica','Vera', 'VeraBd', 'VeraIt', 'VeraBI'] if sys.platform=='win32': for name, ttf in [ ('Adventurer Light SF','Advlit.ttf'),('ArialMS','ARIAL.TTF'), ('Arial Unicode MS', 'ARIALUNI.TTF'), ('Book Antiqua','BKANT.TTF'), ('Century Gothic','GOTHIC.TTF'), ('Comic Sans MS', 'COMIC.TTF'), ('Elementary Heavy SF Bold','Vwagh.ttf'), ('Firenze SF','flot.ttf'), ('Garamond','GARA.TTF'), ('Jagger','Rols.ttf'), ('Monotype Corsiva','MTCORSVA.TTF'), ('Seabird SF','seag.ttf'), ('Tahoma','TAHOMA.TTF'), ('VerdanaMS','VERDANA.TTF'), ]: for D in (r'c:\WINNT',r'c:\Windows'): fn = os.path.join(D,'Fonts',ttf) if os.path.isfile(fn): try: f = ttfonts.TTFont(name, fn) pdfmetrics.registerFont(f) F.append(name) except: pass return F def resetFonts(): for f in _setup(): if f not in _FONTS: _FONTS.append(f) from reportlab.rl_config import register_reset register_reset(resetFonts) resetFonts() ######################################################### # # Collections of shape drawings. # ######################################################### def getFailedDrawing(funcName): """Generate a drawing in case something goes really wrong. This will create a drawing to be displayed whenever some other drawing could not be executed, because the generating function does something terribly wrong! The box contains an attention triangle, plus some error message. """ D = Drawing(400, 200) points = [200,170, 140,80, 260,80] D.add(Polygon(points, strokeWidth=0.5*cm, strokeColor=colors.red, fillColor=colors.yellow)) s = String(200, 40, "Error in generating function '%s'!" % funcName, textAnchor='middle') D.add(s) return D # These are the real drawings to be eye-balled. def getDrawing01(): """Hello World, on a rectangular background. The rectangle's fillColor is yellow. The string's fillColor is red. """ D = Drawing(400, 200) D.add(Rect(50, 50, 300, 100, fillColor=colors.yellow)) D.add(String(180,100, 'Hello World', fillColor=colors.red)) D.add(String(180,86, b'Special characters \xc2\xa2\xc2\xa9\xc2\xae\xc2\xa3\xce\xb1\xce\xb2', fillColor=colors.red)) return D def getDrawing02(): """Various Line shapes. The lines are blue and their strokeWidth is 5 mm. One line has a strokeDashArray set to [5, 10, 15]. """ D = Drawing(400, 200) D.add(Line(50,50, 300,100, strokeColor=colors.blue, strokeWidth=0.5*cm, )) D.add(Line(50,100, 300,50, strokeColor=colors.blue, strokeWidth=0.5*cm, strokeDashArray=[5, 10, 15], )) #x = 1/0 # Comment this to see the actual drawing! return D def getDrawing03(): """Text strings in various sizes and different fonts. Font size increases from 12 to 36 and from bottom left to upper right corner. The first ones should be in Times-Roman. Finally, a solitary Courier string at the top right corner. """ D = Drawing(400, 200) for size in range(12, 36, 4): D.add(String(10+size*2, 10+size*2, 'Hello World', fontName=_FONTS[0], fontSize=size)) D.add(String(150, 150, 'Hello World', fontName=_FONTS[1], fontSize=36)) return D def getDrawing04(): """Text strings in various colours. Colours are blue, yellow and red from bottom left to upper right. """ D = Drawing(400, 200) i = 0 for color in (colors.blue, colors.yellow, colors.red): D.add(String(50+i*30, 50+i*30, 'Hello World', fillColor=color)) i = i + 1 return D def getDrawing05(): """Text strings with various anchors (alignments). Text alignment conforms to the anchors in the left column. """ D = Drawing(400, 200) lineX = 250 D.add(Line(lineX,10, lineX,190, strokeColor=colors.gray)) y = 130 for anchor in ('start', 'middle', 'end'): D.add(String(lineX, y, 'Hello World', textAnchor=anchor)) D.add(String(50, y, anchor + ':')) y = y - 30 return D def getDrawing06(): """This demonstrates all the basic shapes at once. There are no groups or references. Each solid shape should have a green fill. """ green = colors.green D = Drawing(400, 200) #, fillColor=green) D.add(Line(10,10, 390,190)) D.add(Circle(100,100,20, fillColor=green)) D.add(Circle(200,100,40, fillColor=green)) D.add(Circle(300,100,30, fillColor=green)) D.add(Wedge(330,100,40, -10,40, fillColor=green)) D.add(PolyLine([120,10, 130,20, 140,10, 150,20, 160,10, 170,20, 180,10, 190,20, 200,10], fillColor=green)) D.add(Polygon([300,20, 350,20, 390,80, 300,75, 330,40], fillColor=green)) D.add(Ellipse(50,150, 40, 20, fillColor=green)) D.add(Rect(120,150, 60,30, strokeWidth=10, strokeColor=colors.yellow, fillColor=green)) #square corners D.add(Rect(220, 150, 60, 30, 10, 10, fillColor=green)) #round corners D.add(String(10,50, 'Basic Shapes', fillColor=colors.black, fontName='Helvetica')) return D def getDrawing07(): """This tests the ability to translate and rotate groups. The first set of axes should be near the bottom left of the drawing. The second should be rotated counterclockwise by 15 degrees. The third should be rotated by 30 degrees.""" D = Drawing(400, 200) Axis = Group( Line(0,0,100,0), #x axis Line(0,0,0,50), # y axis Line(0,10,10,10), #ticks on y axis Line(0,20,10,20), Line(0,30,10,30), Line(0,40,10,40), Line(10,0,10,10), #ticks on x axis Line(20,0,20,10), Line(30,0,30,10), Line(40,0,40,10), Line(50,0,50,10), Line(60,0,60,10), Line(70,0,70,10), Line(80,0,80,10), Line(90,0,90,10), String(20, 35, 'Axes', fill=colors.black) ) firstAxisGroup = Group(Axis) firstAxisGroup.translate(10,10) D.add(firstAxisGroup) secondAxisGroup = Group(Axis) secondAxisGroup.translate(150,10) secondAxisGroup.rotate(15) D.add(secondAxisGroup) thirdAxisGroup = Group(Axis, transform=mmult(translate(300,10), rotate(30))) D.add(thirdAxisGroup) return D def getDrawing08(): """This tests the ability to scale coordinates. The bottom left set of axes should be near the bottom left of the drawing. The bottom right should be stretched vertically by a factor of 2. The top left one should be stretched horizontally by a factor of 2. The top right should have the vertical axiss leaning over to the right by 30 degrees.""" D = Drawing(400, 200) Axis = Group( Line(0,0,100,0), #x axis Line(0,0,0,50), # y axis Line(0,10,10,10), #ticks on y axis Line(0,20,10,20), Line(0,30,10,30), Line(0,40,10,40), Line(10,0,10,10), #ticks on x axis Line(20,0,20,10), Line(30,0,30,10), Line(40,0,40,10), Line(50,0,50,10), Line(60,0,60,10), Line(70,0,70,10), Line(80,0,80,10), Line(90,0,90,10), String(20, 35, 'Axes', fill=colors.black) ) firstAxisGroup = Group(Axis) firstAxisGroup.translate(10,10) D.add(firstAxisGroup) secondAxisGroup = Group(Axis) secondAxisGroup.translate(150,10) secondAxisGroup.scale(1,2) D.add(secondAxisGroup) thirdAxisGroup = Group(Axis) thirdAxisGroup.translate(10,125) thirdAxisGroup.scale(2,1) D.add(thirdAxisGroup) fourthAxisGroup = Group(Axis) fourthAxisGroup.translate(250,125) fourthAxisGroup.skew(30,0) D.add(fourthAxisGroup) return D def getDrawing09(): """This tests rotated strings Some renderers will have a separate mechanism for font drawing. This test just makes sure strings get transformed the same way as regular graphics.""" D = Drawing(400, 200) fontName = _FONTS[0] fontSize = 12 text = "I should be totally horizontal and enclosed in a box" textWidth = stringWidth(text, fontName, fontSize) g1 = Group( String(20, 20, text, fontName=fontName, fontSize = fontSize), Rect(18, 18, textWidth + 4, fontSize + 4, fillColor=None) ) D.add(g1) text = "I should slope up by 15 degrees, so my right end is higher than my left" textWidth = stringWidth(text, fontName, fontSize) g2 = Group( String(20, 20, text, fontName=fontName, fontSize = fontSize), Rect(18, 18, textWidth + 4, fontSize + 4, fillColor=None) ) g2.translate(0, 50) g2.rotate(15) D.add(g2) return D def getDrawing10(): """This tests nested groups with multiple levels of coordinate transformation. Each box should be staggered up and to the right, moving by 25 points each time.""" D = Drawing(400, 200) fontName = _FONTS[0] fontSize = 12 g1 = Group( Rect(0, 0, 100, 20, fillColor=colors.yellow), String(5, 5, 'Text in the box', fontName=fontName, fontSize = fontSize) ) D.add(g1) g2 = Group(g1, transform = translate(25,25)) D.add(g2) g3 = Group(g2, transform = translate(25,25)) D.add(g3) g4 = Group(g3, transform = translate(25,25)) D.add(g4) return D from reportlab.graphics.widgets.signsandsymbols import SmileyFace def getDrawing11(): '''test of anchoring''' def makeSmiley(x, y, size, color): "Make a smiley data item representation." d = size s = SmileyFace() s.fillColor = color s.x = x-d s.y = y-d s.size = d*2 return s D = Drawing(400, 200) #, fillColor=colors.purple) g = Group(transform=(1,0,0,1,0,0)) g.add(makeSmiley(100,100,10,colors.red)) g.add(Line(90,100,110,100,strokeColor=colors.green)) g.add(Line(100,90,100,110,strokeColor=colors.green)) D.add(g) g = Group(transform=(2,0,0,2,100,-100)) g.add(makeSmiley(100,100,10,colors.blue)) g.add(Line(90,100,110,100,strokeColor=colors.green)) g.add(Line(100,90,100,110,strokeColor=colors.green)) D.add(g) g = Group(transform=(2,0,0,2,0,0)) return D def getDrawing12(): """Text strings in a non-standard font. All that is required is to place the .afm and .pfb files on the font path given in rl_config.py, for example in reportlab/fonts/. """ faceName = "DarkGardenMK" D = Drawing(400, 200) for size in range(12, 36, 4): D.add(String(10+size*2, 10+size*2, 'Hello World', fontName=faceName, fontSize=size)) return D def getDrawing13(): 'Test Various TTF Fonts' def drawit(F,w=400,h=200,fontSize=12,slack=2,gap=5): D = Drawing(w,h) th = 2*gap + fontSize*1.2 gh = gap + .2*fontSize y = h maxx = 0 for fontName in F: y -= th text = fontName+asNative(b': I should be totally horizontal and enclosed in a box and end in alphabetagamma \xc2\xa2\xc2\xa9\xc2\xae\xc2\xa3\xca\xa5\xd0\x96\xd6\x83\xd7\x90\xd9\x82\xe0\xa6\x95\xce\xb1\xce\xb2\xce\xb3') textWidth = stringWidth(text, fontName, fontSize) maxx = max(maxx,textWidth+20) D.add( Group(Rect(8, y-gh, textWidth + 4, th, strokeColor=colors.red, strokeWidth=.5, fillColor=colors.lightgrey), String(10, y, text, fontName=fontName, fontSize = fontSize))) y -= 5 return maxx, h-y+gap, D maxx, maxy, D = drawit(_FONTS) if maxx>400 or maxy>200: _,_,D = drawit(_FONTS,maxx,maxy) return D def smallArrow(): '''create a small PIL image''' from reportlab.graphics.renderPM import _getImage b = base64_decodebytes(b'''R0lGODdhCgAHAIMAAP/////29v/d3f+ysv9/f/9VVf9MTP8iIv8ICP8AAAAAAAAAAAAAAAAAAAAA AAAAACwAAAAACgAHAAAIMwABCBxIsKABAQASFli4MAECAgEAJJhIceKBAQkyasx4YECBjx8TICAQ AIDJkwYEAFgZEAA7''') return _getImage().open(BytesIO(b)) def getDrawing14(): '''test shapes.Image''' from reportlab.graphics.shapes import Image D = Drawing(400, 200) im0 = smallArrow() D.add(Image(x=0,y=0,width=None,height=None,path=im0)) im1 = smallArrow() D.add(Image(x=400-20,y=200-14,width=20,height=14,path=im1)) return D def getAllFunctionDrawingNames(doTTF=1): "Get a list of drawing function names from somewhere." funcNames = [] # Here we get the names from the global name space. symbols = list(globals().keys()) symbols.sort() for funcName in symbols: if funcName[0:10] == 'getDrawing': if doTTF or funcName!='getDrawing13': funcNames.append(funcName) return funcNames def _evalFuncDrawing(name, D, l=None, g=None): if g is None: g = globals() if l is None: l = locals() func = l.get(name,g.get(name,None)) try: d = func() except: d = getFailedDrawing(name) D.append((d, getattr(func,'.__doc__',''), name[3:])) def getAllTestDrawings(doTTF=1): D = [] for f in getAllFunctionDrawingNames(doTTF=doTTF): _evalFuncDrawing(f,D) return D def writePDF(drawings): "Create and save a PDF file containing some drawings." pdfPath = os.path.splitext(sys.argv[0])[0] + '.pdf' c = Canvas(pdfPath) c.setFont(_FONTS[0], 32) c.drawString(80, 750, 'ReportLab Graphics-Shapes Test') # Print drawings in a loop, with their doc strings. c.setFont(_FONTS[0], 12) y = 740 i = 1 for (drawing, docstring, funcname) in drawings: if y < 300: # Allows 5-6 lines of text. c.showPage() y = 740 # Draw a title. y = y - 30 c.setFont(_FONTS[2],12) c.drawString(80, y, '%s (#%d)' % (funcname, i)) c.setFont(_FONTS[0],12) y = y - 14 textObj = c.beginText(80, y) textObj.textLines(docstring) c.drawText(textObj) y = textObj.getY() y = y - drawing.height drawing.drawOn(c, 80, y) i = i + 1 c.save() print('wrote %s ' % pdfPath) class ShapesTestCase(unittest.TestCase): "Test generating all kinds of shapes." def setUp(self): "Prepare some things before the tests start." self.funcNames = getAllFunctionDrawingNames() self.drawings = [] def tearDown(self): "Do what has to be done after the tests are over." writePDF(self.drawings) # This should always succeed. If each drawing would be # wrapped in a dedicated test method like this one, it # would be possible to have a count for wrong tests # as well... Something like this is left for later... def testAllDrawings(self): "Make a list of drawings." for f in self.funcNames: if f[0:10] == 'getDrawing': # Make an instance and get its doc string. # If that fails, use a default error drawing. _evalFuncDrawing(f,self.drawings) def makeSuite(): "Make a test suite for unit testing." suite = unittest.TestSuite() suite.addTest(ShapesTestCase('testAllDrawings')) return suite if __name__ == "__main__": unittest.TextTestRunner().run(makeSuite()) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1691062243.0 reportlab-4.1.0/src/reportlab/graphics/transform.py0000664000175000017500000000364414462707743022075 0ustar00rptlabrptlab'''functions for 2D affine transformations''' __all__ = ( 'nullTransform', 'translate', 'scale', 'rotate', 'skewX', 'skewY', 'mmult', 'inverse', 'zTransformPoint', 'transformPoint', 'transformPoints', 'zTransformPoints', ) from math import cos, sin, tan, radians # constructors for matrices: def nullTransform(): return (1, 0, 0, 1, 0, 0) def translate(dx, dy): return (1, 0, 0, 1, dx, dy) def scale(sx, sy): return (sx, 0, 0, sy, 0, 0) def rotate(angle): a = radians(angle) sina = sin(a) cosa = cos(a) return (cosa, sina, -sina, cosa, 0, 0) def skewX(angle): return (1, 0, tan(radians(angle)), 1, 0, 0) def skewY(angle): return (1, tan(radians(angle)), 0, 1, 0, 0) def mmult(A, B): "A postmultiplied by B" # I checked this RGB # [a0 a2 a4] [b0 b2 b4] # [a1 a3 a5] * [b1 b3 b5] # [ 1 ] [ 1 ] # return (A[0]*B[0] + A[2]*B[1], A[1]*B[0] + A[3]*B[1], A[0]*B[2] + A[2]*B[3], A[1]*B[2] + A[3]*B[3], A[0]*B[4] + A[2]*B[5] + A[4], A[1]*B[4] + A[3]*B[5] + A[5]) def inverse(A): "For A affine 2D represented as 6vec return 6vec version of A**(-1)" # I checked this RGB det = float(A[0]*A[3] - A[2]*A[1]) R = [A[3]/det, -A[1]/det, -A[2]/det, A[0]/det] return tuple(R+[-R[0]*A[4]-R[2]*A[5],-R[1]*A[4]-R[3]*A[5]]) def zTransformPoint(A,v): "Apply the homogenous part of atransformation a to vector v --> A*v" return (A[0]*v[0]+A[2]*v[1],A[1]*v[0]+A[3]*v[1]) def transformPoint(A,v): "Apply transformation a to vector v --> A*v" return (A[0]*v[0]+A[2]*v[1]+A[4],A[1]*v[0]+A[3]*v[1]+A[5]) def transformPoints(matrix, V): r = [transformPoint(matrix,v) for v in V] if isinstance(V,tuple): r = tuple(r) return r def zTransformPoints(matrix, V): return list(map(lambda x,matrix=matrix: zTransformPoint(matrix,x), V)) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1704966359.0 reportlab-4.1.0/src/reportlab/graphics/utils.py0000664000175000017500000003071414547734327021222 0ustar00rptlabrptlab__all__ = ( 'setFont', 'pathNumTrunc', 'processGlyph', 'text2PathDescription', 'text2Path', 'RenderPMError', ) from reportlab.pdfbase.pdfmetrics import getFont, unicode2T1 from reportlab.lib.utils import open_and_read, isBytes, rl_exec from .shapes import _baseGFontName, _PATH_OP_ARG_COUNT, _PATH_OP_NAMES, definePath from sys import exc_info class RenderPMError(Exception): pass def _errorDump(fontName, fontSize): s1, s2 = list(map(str,exc_info()[:2])) from reportlab import rl_config if rl_config.verbose>=2: import os _ = os.path.join(os.path.dirname(rl_config.__file__),'fonts') print('!!!!! %s: %s' % (_,os.listdir(_))) for _ in ('T1SearchPath','TTFSearchPath'): print('!!!!! rl_config.%s = %s' % (_,repr(getattr(rl_config,_)))) code = 'raise RenderPMError("Error in setFont(%s,%s) missing the T1 files?\\nOriginally %s: %s")' % (repr(fontName),repr(fontSize),s1,s2) code += ' from None' rl_exec(code,dict(RenderPMError=RenderPMError)) def setFont(gs,fontName,fontSize): try: gs.setFont(fontName,fontSize) except ValueError as e: if not e.args[0].endswith("Can't find font!"): _errorDump(fontName,fontSize) #here's where we try to add a font to the canvas from _rl_renderPM import makeT1Font try: f = getFont(fontName) makeT1Font(fontName,f.face.findT1File(),f.encoding.vector,open_and_read) except: _errorDump(fontName,fontSize) gs.setFont(fontName,fontSize) def pathNumTrunc(n): if int(n)==n: return int(n) return round(n,5) def __makeTextPathsCode__(tp=None, _TP = ('freetype','_renderPM')): from reportlab.rl_config import textPaths, renderPMBackend if tp is not None: textPaths = tp if textPaths=='backend': tp = 'freetype' if renderPMBackend!='rlPyCairo' else '_renderPM' elif textPaths in _TP: tp = textPaths else: raise ValueError(f"textPaths={textPaths!r} should be one of 'backend', 'freetype' or '_renderPM')") TP = (tp,) + tuple((_ for _ in _TP if _!=tp)) for tp in TP: if tp=='freetype': try: import freetype except ImportError: continue import io class FTTextPath: ftLFlags = freetype.FT_LOAD_DEFAULT | freetype.FT_LOAD_NO_SCALE | freetype.FT_LOAD_NO_BITMAP def __init__(self): self.faces = {} def setFont(self,fontName): if fontName not in self.faces: font = getFont(fontName) if not font: raise ValueError(f'font {fontName!r} has not been registered') if font._dynamicFont: path_or_stream = font.face._ttf_data #path_or_stream = getattr(font,'_ttfont_data',None) #if not path_or_stream: #path_or_stream = font._ttfont_data path_or_stream = io.BytesIO(path_or_stream) else: path_or_stream = getattr(font.face,'pfbFileName',None) if not path_or_stream: path_or_stream = font.face.findT1File() face = freetype.Face(path_or_stream) self.faces[fontName] = (face,font) return self.faces[fontName] def _text2Path(self, text, x=0, y=0, fontName=_baseGFontName, fontSize=1000, **kwds): face, font = self.setFont(fontName) scale = fontSize/face.units_per_EM #font scaling __dx__ = x/scale __dy__ = y/scale P = [] S = [] P_append = P.append truncate = kwds.pop('truncate',0) if truncate: xpt = lambda x: pathNumTrunc(scale*(x+__dx__)) ypt = lambda y: pathNumTrunc(scale*(y+__dy__)) else: xpt = lambda x: scale*(x + __dx__) ypt = lambda y: scale*(y + __dy__) def move_to(a, ctx): if P: P_append(('closePath',)) P_append(('moveTo',xpt(a.x),ypt(a.y))) def line_to(a, ctx): P_append(('lineTo',xpt(a.x),ypt(a.y))) def conic_to(a, b, ctx): '''using the cubic equivalent''' x0,y0 = P[-1][-2:] if P else (a.x, a.y) x1 = xpt(a.x) y1 = ypt(a.y) x2 = xpt(b.x) y2 = ypt(b.y) P_append(('curveTo',x0+((x1-x0)*2)/3,y0+((y1-y0)*2)/3,x1+(x2-x1)/3,y1+(y2-y1)/3,x2,y2)) def cubic_to(a, b, c, ctx): P_append(('curveTo',xpt(a.x),ypt(a.y),xpt(b.x),ypt(b.y),xpt(c.x),ypt(c.y))) lineHeight = fontSize*1.2/scale ftLFlags = self.ftLFlags for c in text: if c=='\n': __dx__ = 0 __dy__ -= lineHeight continue face.load_char(c, ftLFlags) face.glyph.outline.decompose(self, move_to=move_to, line_to=line_to, conic_to=conic_to, cubic_to=cubic_to) __dx__ = __dx__ + face.glyph.metrics.horiAdvance if P: P_append(('closePath',)) return P def text2PathDescription(text, x=0, y=0, fontName=_baseGFontName, fontSize=1000, anchor='start', truncate=1, pathReverse=0, gs=None): '''freetype text2PathDescription(text, x=0, y=0, fontName='fontname', fontSize=1000, font = 'fontName', anchor='start', truncate=1, pathReverse=0, gs=None) ''' font = getFont(fontName) if font._multiByte and not font._dynamicFont: raise ValueError("text2PathDescription doesn't support multi byte fonts like %r" % fontName) P_extend = [].extend if not anchor=='start': textLen = stringWidth(text, fontName, fontSize) if anchor=='end': x = x-textLen elif anchor=='middle': x = x - textLen/2. if gs is None: gs = FTTextPath() if font._dynamicFont: P_extend(gs._text2Path(text,x=x,y=y,fontName=fontName,fontSize=fontSize, truncate=truncate,pathReverse=pathReverse)) else: if isBytes(text): try: text = text.decode('utf8') except UnicodeDecodeError as e: i,j = e.args[2:4] raise UnicodeDecodeError(*(e.args[:4]+('%s\n%s-->%s<--%s' % (e.args[4],text[max(i-10,0):i],text[i:j],text[j:j+10]),))) FT = unicode2T1(text,[font]+font.substitutionFonts) nm1 = len(FT)-1 for i, (f, t) in enumerate(FT): if isinstance(t,bytes): t = t.decode(f.encName) P_extend(gs._text2Path(t,x=x,y=y,fontName=f.fontName,fontSize=fontSize, truncate=truncate,pathReverse=pathReverse)) if i!=nm1: x += f.stringWidth(t, fontSize) return P_extend.__self__ return dict(text2PathDescription=text2PathDescription,FTTextPath=FTTextPath) elif tp=='_renderPM': try: import _rl_renderPM except ImportError: continue def processGlyph(G, truncate=1, pathReverse=0): O = [] P = [] R_append = [].append if G and len(G)==1 and G[0][0]=='lineTo': G = (('moveToClosed',)+G[0][1:],)+G #hack fix for some errors for g in (G or ())+(('end',),): op = g[0] if O and op in ['moveTo', 'moveToClosed','end']: if O[0]=='moveToClosed': del O[0] if pathReverse: P[1::2],P[0::2] = P[0::2],P[1::2] #exchange x and y P.reverse() O.reverse() O.insert(0,'moveTo') O.append('closePath') i = 0 if truncate: P = list(map(pathNumTrunc,P)) for o in O: j = i + _PATH_OP_ARG_COUNT[_PATH_OP_NAMES.index(o)] R_append((o,)+ tuple(P[i:j])) i = j O = [] P = [] O.append(op) P.extend(g[1:]) return R_append.__self__ def text2PathDescription(text, x=0, y=0, fontName=_baseGFontName, fontSize=1000, anchor='start', truncate=1, pathReverse=0, gs=None): '''_renderPM text2PathDescription(text, x=0, y=0, fontName='fontname', fontSize=1000, font = 'fontName', anchor='start', truncate=1, pathReverse=0, gs=None) ''' font = getFont(fontName) if font._multiByte and not font._dynamicFont: raise ValueError("text2PathDescription doesn't support multi byte fonts like %r" % fontName) P_extend = [].extend if not anchor=='start': textLen = stringWidth(text, fontName, fontSize) if anchor=='end': x = x-textLen elif anchor=='middle': x = x - textLen/2. if gs is None: from _rl_renderPM import gstate gs = gstate(1,1) setFont(gs,fontName,fontSize) if font._dynamicFont: for g in gs._stringPath(text,x,y): P_extend(processGlyph(g,truncate=truncate,pathReverse=pathReverse)) else: if isBytes(text): try: text = text.decode('utf8') except UnicodeDecodeError as e: i,j = e.args[2:4] raise UnicodeDecodeError(*(e.args[:4]+('%s\n%s-->%s<--%s' % (e.args[4],text[max(i-10,0):i],text[i:j],text[j:j+10]),))) fc = font FT = unicode2T1(text,[font]+font.substitutionFonts) nm1 = len(FT)-1 for i, (f, t) in enumerate(FT): if f!=fc: setFont(gs,f.fontName,fontSize) fc = f for g in gs._stringPath(t,x,y): P_extend(processGlyph(g,truncate=truncate,pathReverse=pathReverse)) if i!=nm1: x += f.stringWidth(t.decode(f.encName), fontSize) return P_extend.__self__ return dict(text2PathDescription=text2PathDescription,processGlyph=processGlyph,setFont=setFont) else: def _(*args,**kwds): raise RuntimeError(f'''This installation of reportLab has neither PYCAIRO or RENDERPM extras installed. It cannot create paths from text. Could not create text2PathDescription for using backends from {TP!a}''') return dict(processGlyph=_,setFont=_,FTTextPath=_,text2PathDescription=_) globals().update(__makeTextPathsCode__()) def text2Path(text, x=0, y=0, fontName=_baseGFontName, fontSize=1000, anchor='start', truncate=1, pathReverse=0, gs=None, **kwds): t2pd = kwds.pop('text2PathDescription',text2PathDescription) return definePath(t2pd(text,x=x,y=y,fontName=fontName, fontSize=fontSize,anchor=anchor,truncate=truncate,pathReverse=pathReverse, gs=gs),**kwds) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1691062243.0 reportlab-4.1.0/src/reportlab/graphics/widgetbase.py0000664000175000017500000006172014462707743022177 0ustar00rptlabrptlab#Copyright ReportLab Europe Ltd. 2000-2017 #see license.txt for license details #history https://hg.reportlab.com/hg-public/reportlab/log/tip/src/reportlab/graphics/widgetbase.py __version__='3.3.0' __doc__='''Base class for user-defined graphical widgets''' from reportlab.graphics import shapes from reportlab import rl_config from reportlab.lib import colors from reportlab.lib.validators import * from reportlab.lib.attrmap import * from weakref import ref as weakref_ref class PropHolder: '''Base for property holders''' _attrMap = None def verify(self): """If the _attrMap attribute is not None, this checks all expected attributes are present; no unwanted attributes are present; and (if a checking function is found) checks each attribute has a valid value. Either succeeds or raises an informative exception. """ if self._attrMap is not None: for key in self.__dict__.keys(): if key[0] != '_': msg = "Unexpected attribute %s found in %s" % (key, self) assert key in self._attrMap, msg for attr, metavalue in self._attrMap.items(): msg = "Missing attribute %s from %s" % (attr, self) assert hasattr(self, attr), msg value = getattr(self, attr) args = (value, attr, self.__class__.__name__) assert metavalue.validate(value), "Invalid value %s for attribute %s in class %s" % args if rl_config.shapeChecking: """This adds the ability to check every attribute assignment as it is made. It slows down shapes but is a big help when developing. It does not get defined if rl_config.shapeChecking = 0. """ def __setattr__(self, name, value): """By default we verify. This could be off in some parallel base classes.""" validateSetattr(self,name,value) def getProperties(self,recur=1): """Returns a list of all properties which can be edited and which are not marked as private. This may include 'child widgets' or 'primitive shapes'. You are free to override this and provide alternative implementations; the default one simply returns everything without a leading underscore. """ from reportlab.lib.validators import isValidChild # TODO when we need it, but not before - # expose sequence contents? props = {} for name in self.__dict__.keys(): if name[0:1] != '_': component = getattr(self, name) if recur and isValidChild(component): # child object, get its properties too childProps = component.getProperties(recur=recur) for childKey, childValue in childProps.items(): #key might be something indexed like '[2].fillColor' #or simple like 'fillColor'; in the former case we #don't need a '.' between me and my child. if childKey[0] == '[': props['%s%s' % (name, childKey)] = childValue else: props['%s.%s' % (name, childKey)] = childValue else: props[name] = component return props def setProperties(self, propDict): """Permits bulk setting of properties. These may include child objects e.g. "chart.legend.width = 200". All assignments will be validated by the object as if they were set individually in python code. All properties of a top-level object are guaranteed to be set before any of the children, which may be helpful to widget designers. """ childPropDicts = {} for name, value in propDict.items(): parts = name.split('.', 1) if len(parts) == 1: #simple attribute, set it now setattr(self, name, value) else: (childName, remains) = parts try: childPropDicts[childName][remains] = value except KeyError: childPropDicts[childName] = {remains: value} # now assign to children for childName, childPropDict in childPropDicts.items(): child = getattr(self, childName) child.setProperties(childPropDict) def dumpProperties(self, prefix=""): """Convenience. Lists them on standard output. You may provide a prefix - mostly helps to generate code samples for documentation. """ propList = list(self.getProperties().items()) propList.sort() if prefix: prefix = prefix + '.' for (name, value) in propList: print('%s%s = %s' % (prefix, name, value)) class Widget(PropHolder, shapes.UserNode): """Base for all user-defined widgets. Keep as simple as possible. Does not inherit from Shape so that we can rewrite shapes without breaking widgets and vice versa.""" def _setKeywords(self,**kw): for k,v in kw.items(): if k not in self.__dict__: setattr(self,k,v) def draw(self): msg = "draw() must be implemented for each Widget!" raise NotImplementedError(msg) def demo(self): msg = "demo() must be implemented for each Widget!" raise NotImplementedError(msg) def provideNode(self): return self.draw() def getBounds(self): "Return outer boundary as x1,y1,x2,y2. Can be overridden for efficiency" return self.draw().getBounds() class ScaleWidget(Widget): '''Contents with a scale and offset''' _attrMap = AttrMap( x = AttrMapValue(isNumber,desc="x offset"), y = AttrMapValue(isNumber,desc="y offset"), scale = AttrMapValue(isNumber,desc="scale"), contents = AttrMapValue(None,desc="Contained drawable elements"), ) def __init__(self,x=0,y=0,scale=1.0,contents=None): self.x = x self.y = y if not contents: contents=[] elif not isinstance(contents,(tuple,list)): contents = (contents,) self.contents = list(contents) self.scale = scale def draw(self): return shapes.Group(transform=(self.scale,0,0,self.scale,self.x,self.y),*self.contents) _ItemWrapper={} class CloneMixin: def clone(self,**kwds): n = self.__class__() n.__dict__.clear() n.__dict__.update(self.__dict__) if kwds: n.__dict__.update(kwds) return n class TypedPropertyCollection(PropHolder): """A container with properties for objects of the same kind. This makes it easy to create lists of objects. You initialize it with a class of what it is to contain, and that is all you can add to it. You can assign properties to the collection as a whole, or to a numeric index within it; if so it creates a new child object to hold that data. So: wedges = TypedPropertyCollection(WedgeProperties) wedges.strokeWidth = 2 # applies to all wedges.strokeColor = colors.red # applies to all wedges[3].strokeColor = colors.blue # only to one The last line should be taken as a prescription of how to create wedge no. 3 if one is needed; no error is raised if there are only two data points. We try and make sensible use of tuple indices. line[(3,x)] is backed by line[(3,)] == line[3] & line """ def __init__(self, exampleClass, **kwds): #give it same validation rules as what it holds self.__dict__['_value'] = exampleClass(**kwds) self.__dict__['_children'] = {} def wKlassFactory(self,Klass): class WKlass(Klass,CloneMixin): def __getattr__(self,name): try: return self.__class__.__bases__[0].__getattr__(self,name) except: parent = self.parent c = parent._children x = self.__propholder_index__ while x: if x in c: return getattr(c[x],name) x = x[:-1] return getattr(parent,name) @property def parent(self): return self.__propholder_parent__() return WKlass def __getitem__(self, x): x = tuple(x) if isinstance(x,(tuple,list)) else (x,) try: return self._children[x] except KeyError: Klass = self._value.__class__ if Klass in _ItemWrapper: WKlass = _ItemWrapper[Klass] else: _ItemWrapper[Klass] = WKlass = self.wKlassFactory(Klass) child = WKlass() for i in filter(lambda x,K=list(child.__dict__.keys()): x in K,list(child._attrMap.keys())): del child.__dict__[i] child.__dict__.update(dict( __propholder_parent__ = weakref_ref(self), __propholder_index__ = x[:-1]) ) self._children[x] = child return child def __contains__(self,key): return (tuple(key) if isinstance(key,(tuple,list)) else (key,)) in self._children def __setitem__(self, key, value): assert isinstance(value, self._value.__class__), ( "This collection can only hold objects of type %s" % self._value.__class__.__name__) def __len__(self): return len(list(self._children.keys())) def getProperties(self,recur=1): # return any children which are defined and whatever # differs from the parent props = {} for key, value in self._value.getProperties(recur=recur).items(): props['%s' % key] = value for idx in self._children.keys(): childProps = self._children[idx].getProperties(recur=recur) for key, value in childProps.items(): if not hasattr(self,key) or getattr(self, key)!=value: newKey = '[%s].%s' % (idx if len(idx)>1 else idx[0], key) props[newKey] = value return props def setVector(self,**kw): for name, value in kw.items(): for i, v in enumerate(value): setattr(self[i],name,v) def __getattr__(self,name): return getattr(self._value,name) def __setattr__(self,name,value): return setattr(self._value,name,value) def checkAttr(self, key, a, default=None): return getattr(self[key], a, default) if key in self else default def tpcGetItem(obj,x): '''return obj if it's not a TypedPropertyCollection else obj[x]''' return obj[x] if isinstance(obj,TypedPropertyCollection) else obj def isWKlass(obj): if not hasattr(obj,'__propholder_parent__'): return ph = obj.__propholder_parent__ if not isinstance(ph,weakref_ref): return return isinstance(ph(),TypedPropertyCollection) ## No longer needed! class StyleProperties(PropHolder): """A container class for attributes used in charts and legends. Attributes contained can be those for any graphical element (shape?) in the ReportLab graphics package. The idea for this container class is to be useful in combination with legends and/or the individual appearance of data series in charts. A legend could be as simple as a wrapper around a list of style properties, where the 'desc' attribute contains a descriptive string and the rest could be used by the legend e.g. to draw something like a color swatch. The graphical presentation of the legend would be its own business, though. A chart could be inspecting a legend or, more directly, a list of style properties to pick individual attributes that it knows about in order to render a particular row of the data. A bar chart e.g. could simply use 'strokeColor' and 'fillColor' for drawing the bars while a line chart could also use additional ones like strokeWidth. """ _attrMap = AttrMap( strokeWidth = AttrMapValue(isNumber,desc='width of the stroke line'), strokeLineCap = AttrMapValue(isNumber,desc='Line cap 0=butt, 1=round & 2=square',advancedUsage=1), strokeLineJoin = AttrMapValue(isNumber,desc='Line join 0=miter, 1=round & 2=bevel',advancedUsage=1), strokeMiterLimit = AttrMapValue(None,desc='miter limit control miter line joins',advancedUsage=1), strokeDashArray = AttrMapValue(isListOfNumbersOrNone,desc='dashing patterns e.g. (1,3)'), strokeOpacity = AttrMapValue(isNumber,desc='level of transparency (alpha) accepts values between 0..1',advancedUsage=1), strokeColor = AttrMapValue(isColorOrNone,desc='the color of the stroke'), fillColor = AttrMapValue(isColorOrNone,desc='the filling color'), desc = AttrMapValue(isString), ) def __init__(self, **kwargs): "Initialize with attributes if any." for k, v in kwargs.items(): setattr(self, k, v) def __setattr__(self, name, value): "Verify attribute name and value, before setting it." validateSetattr(self,name,value) class TwoCircles(Widget): def __init__(self): self.leftCircle = shapes.Circle(100,100,20, fillColor=colors.red) self.rightCircle = shapes.Circle(300,100,20, fillColor=colors.red) def draw(self): return shapes.Group(self.leftCircle, self.rightCircle) class Face(Widget): """This draws a face with two eyes. It exposes a couple of properties to configure itself and hides all other details. """ _attrMap = AttrMap( x = AttrMapValue(isNumber), y = AttrMapValue(isNumber), size = AttrMapValue(isNumber), skinColor = AttrMapValue(isColorOrNone), eyeColor = AttrMapValue(isColorOrNone), mood = AttrMapValue(OneOf('happy','sad','ok')), ) def __init__(self): self.x = 10 self.y = 10 self.size = 80 self.skinColor = None self.eyeColor = colors.blue self.mood = 'happy' def demo(self): pass def draw(self): s = self.size # abbreviate as we will use this a lot g = shapes.Group() g.transform = [1,0,0,1,self.x, self.y] # background g.add(shapes.Circle(s * 0.5, s * 0.5, s * 0.5, fillColor=self.skinColor)) # left eye g.add(shapes.Circle(s * 0.35, s * 0.65, s * 0.1, fillColor=colors.white)) g.add(shapes.Circle(s * 0.35, s * 0.65, s * 0.05, fillColor=self.eyeColor)) # right eye g.add(shapes.Circle(s * 0.65, s * 0.65, s * 0.1, fillColor=colors.white)) g.add(shapes.Circle(s * 0.65, s * 0.65, s * 0.05, fillColor=self.eyeColor)) # nose g.add(shapes.Polygon( points=[s * 0.5, s * 0.6, s * 0.4, s * 0.3, s * 0.6, s * 0.3], fillColor=None)) # mouth if self.mood == 'happy': offset = -0.05 elif self.mood == 'sad': offset = +0.05 else: offset = 0 g.add(shapes.Polygon( points = [ s * 0.3, s * 0.2, #left of mouth s * 0.7, s * 0.2, #right of mouth s * 0.6, s * (0.2 + offset), # the bit going up or down s * 0.4, s * (0.2 + offset) # the bit going up or down ], fillColor = colors.pink, strokeColor = colors.red, strokeWidth = s * 0.03 )) return g class TwoFaces(Widget): def __init__(self): self.faceOne = Face() self.faceOne.mood = "happy" self.faceTwo = Face() self.faceTwo.x = 100 self.faceTwo.mood = "sad" def draw(self): """Just return a group""" return shapes.Group(self.faceOne, self.faceTwo) def demo(self): """The default case already looks good enough, no implementation needed here""" pass class Sizer(Widget): "Container to show size of all enclosed objects" _attrMap = AttrMap(BASE=shapes.SolidShape, contents = AttrMapValue(isListOfShapes,desc="Contained drawable elements"), ) def __init__(self, *elements): self.contents = [] self.fillColor = colors.cyan self.strokeColor = colors.magenta for elem in elements: self.add(elem) def _addNamedNode(self,name,node): 'if name is not None add an attribute pointing to node and add to the attrMap' if name: if name not in list(self._attrMap.keys()): self._attrMap[name] = AttrMapValue(isValidChild) setattr(self, name, node) def add(self, node, name=None): """Appends non-None child node to the 'contents' attribute. In addition, if a name is provided, it is subsequently accessible by name """ # propagates properties down if node is not None: assert isValidChild(node), "Can only add Shape or UserNode objects to a Group" self.contents.append(node) self._addNamedNode(name,node) def getBounds(self): # get bounds of each object if self.contents: b = [] for elem in self.contents: b.append(elem.getBounds()) return shapes.getRectsBounds(b) else: return (0,0,0,0) def draw(self): g = shapes.Group() (x1, y1, x2, y2) = self.getBounds() r = shapes.Rect( x = x1, y = y1, width = x2-x1, height = y2-y1, fillColor = self.fillColor, strokeColor = self.strokeColor ) g.add(r) for elem in self.contents: g.add(elem) return g class CandleStickProperties(PropHolder): _attrMap = AttrMap( strokeWidth = AttrMapValue(isNumber, desc='Width of a line.'), strokeColor = AttrMapValue(isColorOrNone, desc='Color of a line or border.'), strokeDashArray = AttrMapValue(isListOfNumbersOrNone, desc='Dash array of a line.'), crossWidth = AttrMapValue(isNumberOrNone,desc="cross line width",advancedUsage=1), crossLo = AttrMapValue(isNumberOrNone,desc="cross line low value",advancedUsage=1), crossHi = AttrMapValue(isNumberOrNone,desc="cross line high value",advancedUsage=1), boxWidth = AttrMapValue(isNumberOrNone,desc="width of the box part",advancedUsage=1), boxFillColor = AttrMapValue(isColorOrNone, desc='fill color of box'), boxStrokeColor = AttrMapValue(NotSetOr(isColorOrNone), desc='stroke color of box'), boxStrokeDashArray = AttrMapValue(NotSetOr(isListOfNumbersOrNone), desc='Dash array of the box.'), boxStrokeWidth = AttrMapValue(NotSetOr(isNumber), desc='Width of the box lines.'), boxLo = AttrMapValue(isNumberOrNone,desc="low value of the box",advancedUsage=1), boxMid = AttrMapValue(isNumberOrNone,desc="middle box line value",advancedUsage=1), boxHi = AttrMapValue(isNumberOrNone,desc="high value of the box",advancedUsage=1), boxSides = AttrMapValue(isBoolean,desc="whether to show box sides",advancedUsage=1), position = AttrMapValue(isNumberOrNone,desc="position of the candle",advancedUsage=1), chart = AttrMapValue(None,desc="our chart",advancedUsage=1), candleKind = AttrMapValue(OneOf('vertical','horizontal'),desc="candle direction",advancedUsage=1), axes = AttrMapValue(SequenceOf(isString,emptyOK=0,lo=2,hi=2),desc="candle direction",advancedUsage=1), ) def __init__(self,**kwds): self.strokeWidth = kwds.pop('strokeWidth',1) self.strokeColor = kwds.pop('strokeColor',colors.black) self.strokeDashArray = kwds.pop('strokeDashArray',None) self.crossWidth = kwds.pop('crossWidth',5) self.crossLo = kwds.pop('crossLo',None) self.crossHi = kwds.pop('crossHi',None) self.boxWidth = kwds.pop('boxWidth',None) self.boxFillColor = kwds.pop('boxFillColor',None) self.boxStrokeColor =kwds.pop('boxStrokeColor',NotSetOr._not_set) self.boxStrokeWidth =kwds.pop('boxStrokeWidth',NotSetOr._not_set) self.boxStrokeDashArray =kwds.pop('boxStrokeDashArray',NotSetOr._not_set) self.boxLo = kwds.pop('boxLo',None) self.boxMid = kwds.pop('boxMid',None) self.boxHi = kwds.pop('boxHi',None) self.boxSides = kwds.pop('boxSides',True) self.position = kwds.pop('position',None) self.candleKind = kwds.pop('candleKind','vertical') self.axes = kwds.pop('axes',['categoryAxis','valueAxis']) chart = kwds.pop('chart',None) self.chart = weakref_ref(chart) if chart else (lambda:None) def __call__(self,_x,_y,_size,_color): '''the symbol interface''' chart = self.chart() xA = getattr(chart,self.axes[0]) _xScale = getattr(xA,'midScale',None) if not _xScale: _xScale = getattr(xA,'scale') xScale = lambda x: _xScale(x) if x is not None else None yA = getattr(chart,self.axes[1]) _yScale = getattr(yA,'midScale',None) if not _yScale: _yScale = getattr(yA,'scale') yScale = lambda x: _yScale(x) if x is not None else None G = shapes.Group().add strokeWidth = self.strokeWidth strokeColor = self.strokeColor strokeDashArray = self.strokeDashArray crossWidth = self.crossWidth crossLo = yScale(self.crossLo) crossHi = yScale(self.crossHi) boxWidth = self.boxWidth boxFillColor = self.boxFillColor boxStrokeColor = NotSetOr.conditionalValue(self.boxStrokeColor,strokeColor) boxStrokeWidth = NotSetOr.conditionalValue(self.boxStrokeWidth,strokeWidth) boxStrokeDashArray = NotSetOr.conditionalValue(self.boxStrokeDashArray,strokeDashArray) boxLo = yScale(self.boxLo) boxMid = yScale(self.boxMid) boxHi = yScale(self.boxHi) position = xScale(self.position) candleKind = self.candleKind haveBox = None not in (boxWidth,boxLo,boxHi) haveLine = None not in (crossLo,crossHi) def aLine(x0,y0,x1,y1): if candleKind!='vertical': x0,y0 = y0,x0 x1,y1 = y1,x1 G(shapes.Line(x0,y0,x1,y1,strokeWidth=strokeWidth,strokeColor=strokeColor,strokeDashArray=strokeDashArray)) if haveBox: boxLo, boxHi = min(boxLo,boxHi), max(boxLo,boxHi) if haveLine: crossLo, crossHi = min(crossLo,crossHi), max(crossLo,crossHi) if not haveBox or crossLo>=boxHi or crossHi<=boxLo: aLine(position,crossLo,position,crossHi) if crossWidth is not None: aLine(position-crossWidth*0.5,crossLo,position+crossWidth*0.5,crossLo) aLine(position-crossWidth*0.5,crossHi,position+crossWidth*0.5,crossHi) elif haveBox: if crossLoboxHi: aLine(position,boxHi,position,crossHi) aLine(position-crossWidth*0.5,crossHi,position+crossWidth*0.5,crossHi) if haveBox: x = position - boxWidth*0.5 y = boxLo h = boxHi - boxLo w = boxWidth if candleKind!='vertical': x, y, w, h = y, x, h, w G(shapes.Rect(x,y,w,h,strokeColor=boxStrokeColor if self.boxSides else None,strokeWidth=boxStrokeWidth,strokeDashArray=boxStrokeDashArray,fillColor=boxFillColor)) if not self.boxSides: aLine(position-0.5*boxWidth,boxHi,position+0.5*boxWidth,boxHi) aLine(position-0.5*boxWidth,boxLo,position+0.5*boxWidth,boxLo) if boxMid is not None: aLine(position-0.5*boxWidth,boxMid,position+0.5*boxWidth,boxMid) return G.__self__ def CandleSticks(**kwds): return TypedPropertyCollection(CandleStickProperties,**kwds) def test(): from reportlab.graphics.charts.piecharts import WedgeProperties wedges = TypedPropertyCollection(WedgeProperties) wedges.fillColor = colors.red wedges.setVector(fillColor=(colors.blue,colors.green,colors.white)) print(len(_ItemWrapper)) d = shapes.Drawing(400, 200) tc = TwoCircles() d.add(tc) from reportlab.graphics import renderPDF renderPDF.drawToFile(d, 'sample_widget.pdf', 'A Sample Widget') print('saved sample_widget.pdf') d = shapes.Drawing(400, 200) f = Face() f.skinColor = colors.yellow f.mood = "sad" d.add(f, name='theFace') print('drawing 1 properties:') d.dumpProperties() renderPDF.drawToFile(d, 'face.pdf', 'A Sample Widget') print('saved face.pdf') d2 = d.expandUserNodes() renderPDF.drawToFile(d2, 'face_copy.pdf', 'An expanded drawing') print('saved face_copy.pdf') print('drawing 2 properties:') d2.dumpProperties() if __name__=='__main__': test() ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1707393948.4105587 reportlab-4.1.0/src/reportlab/graphics/widgets/0000775000175000017500000000000014561141634021136 5ustar00rptlabrptlab././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1691062243.0 reportlab-4.1.0/src/reportlab/graphics/widgets/__init__.py0000664000175000017500000000036214462707743023261 0ustar00rptlabrptlab#Copyright ReportLab Europe Ltd. 2000-2017 #see license.txt for license details #history https://hg.reportlab.com/hg-public/reportlab/log/tip/src/reportlab/graphics/widgets/__init__.py __version__='3.3.0' __doc__='''Some non-chart widgets''' ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1691062243.0 reportlab-4.1.0/src/reportlab/graphics/widgets/adjustableArrow.py0000664000175000017500000000752014462707743024656 0ustar00rptlabrptlabfrom reportlab.lib import colors from reportlab.lib.validators import * from reportlab.lib.attrmap import * from reportlab.graphics.shapes import Drawing, _DrawingEditorMixin, Group, Polygon from reportlab.graphics.widgetbase import Widget class AdjustableArrow(Widget): """This widget draws an arrow (style one). possible attributes: 'x', 'y', 'size', 'fillColor' """ _attrMap = AttrMap( x = AttrMapValue(isNumber,desc='symbol x coordinate'), y = AttrMapValue(isNumber,desc='symbol y coordinate'), dx = AttrMapValue(isNumber,desc='symbol x coordinate adjustment'), dy = AttrMapValue(isNumber,desc='symbol x coordinate adjustment'), stemThickness = AttrMapValue(isNumber, 'width of the stem'), stemLength = AttrMapValue(isNumber, 'length of the stem'), headProjection = AttrMapValue(isNumber, 'how much the head projects from the stem'), headLength = AttrMapValue(isNumber, 'length of the head'), headSweep = AttrMapValue(isNumber, 'howmuch the head sweeps back (-ve) or forwards (+ve)'), scale = AttrMapValue(isNumber, 'scaling factor'), fillColor = AttrMapValue(isColorOrNone), strokeColor = AttrMapValue(isColorOrNone), strokeWidth = AttrMapValue(isNumber), boxAnchor = AttrMapValue(isBoxAnchor,desc='anchoring point of the label'), right =AttrMapValue(isBoolean,desc='If True (default) the arrow is horizontal pointing right\nFalse means it points up'), angle = AttrMapValue(isNumber, desc='angle of arrow default (0), right True 0 is horizontal to right else vertical up'), ) def __init__(self,**kwds): self._setKeywords(**kwds) self._setKeywords(**dict( x = 0, y = 0, fillColor = colors.red, strokeWidth = 0, strokeColor = None, boxAnchor = 'c', angle = 0, stemThickness = 33, stemLength = 50, headProjection = 15, headLength = 50, headSweep = 0, scale = 1., right=True, )) def draw(self): # general widget bits g = Group() x = self.x y = self.y scale = self.scale stemThickness = self.stemThickness*scale stemLength = self.stemLength*scale headProjection = self.headProjection*scale headLength = self.headLength*scale headSweep = self.headSweep*scale w = stemLength+headLength h = 2*headProjection+stemThickness # shift to the boxAnchor boxAnchor = self.boxAnchor if self.right: if boxAnchor in ('sw','w','nw'): dy = -h elif boxAnchor in ('s','c','n'): dy = -h*0.5 else: dy = 0 if boxAnchor in ('w','c','e'): dx = -w*0.5 elif boxAnchor in ('nw','n','ne'): dx = -w else: dx = 0 points = [ dx, dy+headProjection+stemThickness, dx+stemLength, dy+headProjection+stemThickness, dx+stemLength+headSweep, dy+2*headProjection+stemThickness, dx+stemLength+headLength, dy+0.5*stemThickness+headProjection, dx+stemLength+headSweep, dy, dx+stemLength, dy+headProjection, dx, dy+headProjection, ] else: w,h = h,w if boxAnchor in ('nw','n','ne'): dy = -h elif boxAnchor in ('w','c','e'): dy = -h*0.5 else: dy = 0 if boxAnchor in ('ne','e','se'): dx = -w elif boxAnchor in ('n','c','s'): dx = -w*0.5 else: dx = 0 points = [ dx+headProjection, dy, #sw dx+headProjection+stemThickness, dy, #se dx+headProjection+stemThickness, dy+stemLength, dx+w, dy+stemLength+headSweep, dx+headProjection+0.5*stemThickness, dy+h, dx, dy+stemLength+headSweep, dx+headProjection, dy+stemLength, ] g.add(Polygon( points = points, fillColor = self.fillColor, strokeColor = self.strokeColor, strokeWidth = self.strokeWidth, )) g.translate(x,y) g.rotate(self.angle) return g class AdjustableArrowDrawing(_DrawingEditorMixin,Drawing): def __init__(self,width=100,height=63,*args,**kw): Drawing.__init__(self,width,height,*args,**kw) self._add(self,AdjustableArrow(),name='adjustableArrow',validate=None,desc=None) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1691062243.0 reportlab-4.1.0/src/reportlab/graphics/widgets/eventcal.py0000664000175000017500000003142114462707743023323 0ustar00rptlabrptlab#see license.txt for license details #history https://hg.reportlab.com/hg-public/reportlab/log/tip/src/reportlab/graphics/widgets/eventcal.py # Event Calendar widget # author: Andy Robinson __version__='3.3.0' __doc__="""This file is a """ from reportlab.lib import colors from reportlab.graphics.shapes import Rect, Drawing, Group, String from reportlab.graphics.charts.textlabels import Label from reportlab.graphics.widgetbase import Widget class EventCalendar(Widget): def __init__(self): self.x = 0 self.y = 0 self.width = 300 self.height = 150 self.timeColWidth = None # if declared, use it; otherwise auto-size. self.trackRowHeight = 20 self.data = [] # list of Event objects self.trackNames = None self.startTime = None #displays ALL data on day if not set self.endTime = None # displays ALL data on day if not set self.day = 0 # we will keep any internal geometry variables # here. These are computed by computeSize(), # which is the first thing done when drawing. self._talksVisible = [] # subset of data which will get plotted, cache self._startTime = None self._endTime = None self._trackCount = 0 self._colWidths = [] self._colLeftEdges = [] # left edge of each column def computeSize(self): "Called at start of draw. Sets various column widths" self._talksVisible = self.getRelevantTalks(self.data) self._trackCount = len(self.getAllTracks()) self.computeStartAndEndTimes() self._colLeftEdges = [self.x] if self.timeColWidth is None: w = self.width / (1 + self._trackCount) self._colWidths = [w] * (1+ self._trackCount) for i in range(self._trackCount): self._colLeftEdges.append(self._colLeftEdges[-1] + w) else: self._colWidths = [self.timeColWidth] w = (self.width - self.timeColWidth) / self._trackCount for i in range(self._trackCount): self._colWidths.append(w) self._colLeftEdges.append(self._colLeftEdges[-1] + w) def computeStartAndEndTimes(self): "Work out first and last times to display" if self.startTime: self._startTime = self.startTime else: for (title, speaker, trackId, day, start, duration) in self._talksVisible: if self._startTime is None: #first one self._startTime = start else: if start < self._startTime: self._startTime = start if self.endTime: self._endTime = self.endTime else: for (title, speaker, trackId, day, start, duration) in self._talksVisible: if self._endTime is None: #first one self._endTime = start + duration else: if start + duration > self._endTime: self._endTime = start + duration def getAllTracks(self): tracks = [] for (title, speaker, trackId, day, hours, duration) in self.data: if trackId is not None: if trackId not in tracks: tracks.append(trackId) tracks.sort() return tracks def getRelevantTalks(self, talkList): "Scans for tracks actually used" used = [] for talk in talkList: (title, speaker, trackId, day, hours, duration) = talk assert trackId != 0, "trackId must be None or 1,2,3... zero not allowed!" if day == self.day: if (((self.startTime is None) or ((hours + duration) >= self.startTime)) and ((self.endTime is None) or (hours <= self.endTime))): used.append(talk) return used def scaleTime(self, theTime): "Return y-value corresponding to times given" axisHeight = self.height - self.trackRowHeight # compute fraction between 0 and 1, 0 is at start of period proportionUp = ((theTime - self._startTime) / (self._endTime - self._startTime)) y = self.y + axisHeight - (axisHeight * proportionUp) return y def getTalkRect(self, startTime, duration, trackId, text): "Return shapes for a specific talk" g = Group() y_bottom = self.scaleTime(startTime + duration) y_top = self.scaleTime(startTime) y_height = y_top - y_bottom if trackId is None: #spans all columns x = self._colLeftEdges[1] width = self.width - self._colWidths[0] else: #trackId is 1-based and these arrays have the margin info in column #zero, so no need to add 1 x = self._colLeftEdges[trackId] width = self._colWidths[trackId] lab = Label() lab.setText(text) lab.setOrigin(x + 0.5*width, y_bottom+0.5*y_height) lab.boxAnchor = 'c' lab.width = width lab.height = y_height lab.fontSize = 6 r = Rect(x, y_bottom, width, y_height, fillColor=colors.cyan) g.add(r) g.add(lab) #now for a label # would expect to color-code and add text return g def draw(self): self.computeSize() g = Group() # time column g.add(Rect(self.x, self.y, self._colWidths[0], self.height - self.trackRowHeight, fillColor=colors.cornsilk)) # track headers x = self.x + self._colWidths[0] y = self.y + self.height - self.trackRowHeight for trk in range(self._trackCount): wid = self._colWidths[trk+1] r = Rect(x, y, wid, self.trackRowHeight, fillColor=colors.yellow) s = String(x + 0.5*wid, y, 'Track %d' % trk, align='middle') g.add(r) g.add(s) x = x + wid for talk in self._talksVisible: (title, speaker, trackId, day, start, duration) = talk r = self.getTalkRect(start, duration, trackId, title + '\n' + speaker) g.add(r) return g def test(): "Make a conference event for day 1 of UP Python 2003" d = Drawing(400,200) cal = EventCalendar() cal.x = 50 cal.y = 25 cal.data = [ # these might be better as objects instead of tuples, since I # predict a large number of "optionsl" variables to affect # formatting in future. #title, speaker, track id, day, start time (hrs), duration (hrs) # track ID is 1-based not zero-based! ('Keynote: Why design another programming language?', 'Guido van Rossum', None, 1, 9.0, 1.0), ('Siena Web Service Architecture', 'Marc-Andre Lemburg', 1, 1, 10.5, 1.5), ('Extreme Programming in Python', 'Chris Withers', 2, 1, 10.5, 1.5), ('Pattern Experiences in C++', 'Mark Radford', 3, 1, 10.5, 1.5), ('What is the Type of std::toupper()', 'Gabriel Dos Reis', 4, 1, 10.5, 1.5), ('Linguistic Variables: Clear Thinking with Fuzzy Logic ', 'Walter Banks', 5, 1, 10.5, 1.5), ('lunch, short presentations, vendor presentations', '', None, 1, 12.0, 2.0), ("CORBA? Isn't that obsolete", 'Duncan Grisby', 1, 1, 14.0, 1.5), ("Python Design Patterns", 'Duncan Booth', 2, 1, 14.0, 1.5), ("Inside Security Checks and Safe Exceptions", 'Brandon Bray', 3, 1, 14.0, 1.5), ("Studying at a Distance", 'Panel Discussion, Panel to include Alan Lenton & Francis Glassborow', 4, 1, 14.0, 1.5), ("Coding Standards - Given the ANSI C Standard why do I still need a coding Standard", 'Randy Marques', 5, 1, 14.0, 1.5), ("RESTful Python", 'Hamish Lawson', 1, 1, 16.0, 1.5), ("Parsing made easier - a radical old idea", 'Andrew Koenig', 2, 1, 16.0, 1.5), ("C++ & Multimethods", 'Julian Smith', 3, 1, 16.0, 1.5), ("C++ Threading", 'Kevlin Henney', 4, 1, 16.0, 1.5), ("The Organisation Strikes Back", 'Alan Griffiths & Sarah Lees', 5, 1, 16.0, 1.5), ('Birds of a Feather meeting', '', None, 1, 17.5, 2.0), ('Keynote: In the Spirit of C', 'Greg Colvin', None, 2, 9.0, 1.0), ('The Infinite Filing Cabinet - object storage in Python', 'Jacob Hallen', 1, 2, 10.5, 1.5), ('Introduction to Python and Jython for C++ and Java Programmers', 'Alex Martelli', 2, 2, 10.5, 1.5), ('Template metaprogramming in Haskell', 'Simon Peyton Jones', 3, 2, 10.5, 1.5), ('Plenty People Programming: C++ Programming in a Group, Workshop with a difference', 'Nico Josuttis', 4, 2, 10.5, 1.5), ('Design and Implementation of the Boost Graph Library', 'Jeremy Siek', 5, 2, 10.5, 1.5), ('lunch, short presentations, vendor presentations', '', None, 2, 12.0, 2.0), ("Building GUI Applications with PythonCard and PyCrust", 'Andy Todd', 1, 2, 14.0, 1.5), ("Integrating Python, C and C++", 'Duncan Booth', 2, 2, 14.0, 1.5), ("Secrets and Pitfalls of Templates", 'Nicolai Josuttis & David Vandevoorde', 3, 2, 14.0, 1.5), ("Being a Mentor", 'Panel Discussion, Panel to include Alan Lenton & Francis Glassborow', 4, 2, 14.0, 1.5), ("The Embedded C Extensions to C", 'Willem Wakker', 5, 2, 14.0, 1.5), ("Lightning Talks", 'Paul Brian', 1, 2, 16.0, 1.5), ("Scripting Java Applications with Jython", 'Anthony Eden', 2, 2, 16.0, 1.5), ("Metaprogramming and the Boost Metaprogramming Library", 'David Abrahams', 3, 2, 16.0, 1.5), ("A Common Vendor ABI for C++ -- GCC's why, what and not", 'Nathan Sidwell & Gabriel Dos Reis', 4, 2, 16.0, 1.5), ("The Timing and Cost of Choices", 'Hubert Matthews', 5, 2, 16.0, 1.5), ('Birds of a Feather meeting', '', None, 2, 17.5, 2.0), ('Keynote: The Cost of C & C++ Compatibility', 'Andy Koenig', None, 3, 9.0, 1.0), ('Prying Eyes: Generic Observer Implementations in C++', 'Andrei Alexandrescu', 1, 2, 10.5, 1.5), ('The Roadmap to Generative Programming With C++', 'Ulrich Eisenecker', 2, 2, 10.5, 1.5), ('Design Patterns in C++ and C# for the Common Language Runtime', 'Brandon Bray', 3, 2, 10.5, 1.5), ('Extreme Hour (XH): (workshop) - Jutta Eckstein and Nico Josuttis', 'Jutta Ecstein', 4, 2, 10.5, 1.5), ('The Lambda Library : Unnamed Functions for C++', 'Jaako Jarvi', 5, 2, 10.5, 1.5), ('lunch, short presentations, vendor presentations', '', None, 3, 12.0, 2.0), ('Reflective Metaprogramming', 'Daveed Vandevoorde', 1, 3, 14.0, 1.5), ('Advanced Template Issues and Solutions (double session)', 'Herb Sutter',2, 3, 14.0, 3), ('Concurrent Programming in Java (double session)', 'Angelika Langer', 3, 3, 14.0, 3), ('What can MISRA-C (2nd Edition) do for us?', 'Chris Hills', 4, 3, 14.0, 1.5), ('C++ Metaprogramming Concepts and Results', 'Walter E Brown', 5, 3, 14.0, 1.5), ('Binding C++ to Python with the Boost Python Library', 'David Abrahams', 1, 3, 16.0, 1.5), ('Using Aspect Oriented Programming for Enterprise Application Integration', 'Arno Schmidmeier', 4, 3, 16.0, 1.5), ('Defective C++', 'Marc Paterno', 5, 3, 16.0, 1.5), ("Speakers' Banquet & Birds of a Feather meeting", '', None, 3, 17.5, 2.0), ('Keynote: The Internet, Software and Computers - A Report Card', 'Alan Lenton', None, 4, 9.0, 1.0), ('Multi-Platform Software Development; Lessons from the Boost libraries', 'Beman Dawes', 1, 5, 10.5, 1.5), ('The Stability of the C++ ABI', 'Steve Clamage', 2, 5, 10.5, 1.5), ('Generic Build Support - A Pragmatic Approach to the Software Build Process', 'Randy Marques', 3, 5, 10.5, 1.5), ('How to Handle Project Managers: a survival guide', 'Barb Byro', 4, 5, 10.5, 1.5), ('lunch, ACCU AGM', '', None, 5, 12.0, 2.0), ('Sauce: An OO recursive descent parser; its design and implementation.', 'Jon Jagger', 1, 5, 14.0, 1.5), ('GNIRTS ESAC REWOL - Bringing the UNIX filters to the C++ iostream library.', 'JC van Winkel', 2, 5, 14.0, 1.5), ('Pattern Writing: Live and Direct', 'Frank Buschmann & Kevlin Henney', 3, 5, 14.0, 3.0), ('The Future of Programming Languages - A Goldfish Bowl', 'Francis Glassborow and friends', 3, 5, 14.0, 1.5), ('Honey, I Shrunk the Threads: Compile-time checked multithreaded transactions in C++', 'Andrei Alexandrescu', 1, 5, 16.0, 1.5), ('Fun and Functionality with Functors', 'Lois Goldthwaite', 2, 5, 16.0, 1.5), ('Agile Enough?', 'Alan Griffiths', 4, 5, 16.0, 1.5), ("Conference Closure: A brief plenary session", '', None, 5, 17.5, 0.5), ] #return cal cal.day = 1 d.add(cal) for format in ['pdf']:#,'gif','png']: out = d.asString(format) open('eventcal.%s' % format, 'wb').write(out) print('saved eventcal.%s' % format) if __name__=='__main__': test() ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1691062243.0 reportlab-4.1.0/src/reportlab/graphics/widgets/flags.py0000664000175000017500000007303114462707743022621 0ustar00rptlabrptlab#see license.txt for license details #history https://hg.reportlab.com/hg-public/reportlab/log/tip/src/reportlab/graphics/widgets/flags.py # Flag Widgets - a collection of flags as widgets # author: John Precedo (johnp@reportlab.com) __version__='3.3.0' __doc__="""This file is a collection of flag graphics as widgets. All flags are represented at the ratio of 1:2, even where the official ratio for the flag is something else (such as 3:5 for the German national flag). The only exceptions are for where this would look _very_ wrong, such as the Danish flag whose (ratio is 28:37), or the Swiss flag (which is square). Unless otherwise stated, these flags are all the 'national flags' of the countries, rather than their state flags, naval flags, ensigns or any other variants. (National flags are the flag flown by civilians of a country and the ones usually used to represent a country abroad. State flags are the variants used by the government and by diplomatic missions overseas). To check on how close these are to the 'official' representations of flags, check the World Flag Database at http://www.flags.ndirect.co.uk/ The flags this file contains are: EU Members: United Kingdom, Austria, Belgium, Denmark, Finland, France, Germany, Greece, Ireland, Italy, Luxembourg, Holland (The Netherlands), Spain, Sweden Others: USA, Czech Republic, European Union, Switzerland, Turkey, Brazil (Brazilian flag contributed by Publio da Costa Melo [publio@planetarium.com.br]). """ from reportlab.lib import colors from reportlab.lib.validators import * from reportlab.lib.attrmap import * from reportlab.graphics.shapes import Line, Rect, Polygon, Drawing, Group, String, Circle, Wedge from reportlab.graphics import renderPDF from reportlab.graphics.widgets.signsandsymbols import _Symbol import copy from math import sin, cos, pi validFlag=OneOf(None, 'UK', 'USA', 'Afghanistan', 'Austria', 'Belgium', 'China', 'Cuba', 'Denmark', 'Finland', 'France', 'Germany', 'Greece', 'Ireland', 'Italy', 'Japan', 'Luxembourg', 'Holland', 'Palestine', 'Portugal', 'Russia', 'Spain', 'Sweden', 'Norway', 'CzechRepublic', 'Turkey', 'Switzerland', 'EU', 'Brazil' ) _size = 100. class Star(_Symbol): """This draws a 5-pointed star. possible attributes: 'x', 'y', 'size', 'fillColor', 'strokeColor' """ _attrMap = AttrMap(BASE=_Symbol, angle = AttrMapValue(isNumber, desc='angle in degrees'), ) _size = 100. def __init__(self): _Symbol.__init__(self) self.size = 100 self.fillColor = colors.yellow self.strokeColor = None self.angle = 0 def demo(self): D = Drawing(200, 100) et = Star() et.x=50 et.y=0 D.add(et) labelFontSize = 10 D.add(String(et.x+(et.size/2.0),(et.y-(1.2*labelFontSize)), et.__class__.__name__, fillColor=colors.black, textAnchor='middle', fontSize=labelFontSize)) return D def draw(self): s = float(self.size) #abbreviate as we will use this a lot g = Group() # new algorithm from markers.StarFive R = float(self.size)/2 r = R*sin(18*(pi/180.0))/cos(36*(pi/180.0)) P = [] angle = 90 for i in range(5): for radius in R, r: theta = angle*(pi/180.0) P.append(radius*cos(theta)) P.append(radius*sin(theta)) angle = angle + 36 # star specific bits star = Polygon(P, fillColor = self.fillColor, strokeColor = self.strokeColor, strokeWidth=s/50) g.rotate(self.angle) g.shift(self.x+self.dx,self.y+self.dy) g.add(star) return g class Flag(_Symbol): """This is a generic flag class that all the flags in this file use as a basis. This class basically provides edges and a tidy-up routine to hide any bits of line that overlap the 'outside' of the flag possible attributes: 'x', 'y', 'size', 'fillColor' """ _attrMap = AttrMap(BASE=_Symbol, fillColor = AttrMapValue(isColor, desc='Background color'), border = AttrMapValue(isBoolean, 'Whether a background is drawn'), kind = AttrMapValue(validFlag, desc='Which flag'), ) _cache = {} def __init__(self,**kw): _Symbol.__init__(self) self.kind = None self.size = 100 self.fillColor = colors.white self.border=1 self.setProperties(kw) def availableFlagNames(self): '''return a list of the things we can display''' return [x for x in self._attrMap['kind'].validate._enum if x is not None] def _Flag_None(self): s = _size # abbreviate as we will use this a lot g = Group() g.add(Rect(0, 0, s*2, s, fillColor = colors.purple, strokeColor = colors.black, strokeWidth=0)) return g def _borderDraw(self,f): s = self.size # abbreviate as we will use this a lot g = Group() g.add(f) x, y, sW = self.x+self.dx, self.y+self.dy, self.strokeWidth/2. g.insert(0,Rect(-sW, -sW, width=getattr(self,'_width',2*s)+3*sW, height=getattr(self,'_height',s)+2*sW, fillColor = None, strokeColor = self.strokeColor, strokeWidth=sW*2)) g.shift(x,y) g.scale(s/_size, s/_size) return g def draw(self): kind = self.kind or 'None' f = self._cache.get(kind) if not f: f = getattr(self,'_Flag_'+kind)() self._cache[kind] = f._explode() return self._borderDraw(f) def clone(self): return copy.copy(self) def demo(self): D = Drawing(200, 100) name = self.availableFlagNames() import time name = name[int(time.time()) % len(name)] fx = Flag() fx.kind = name fx.x = 0 fx.y = 0 D.add(fx) labelFontSize = 10 D.add(String(fx.x+(fx.size/2.0),(fx.y-(1.2*labelFontSize)), name, fillColor=colors.black, textAnchor='middle', fontSize=labelFontSize)) labelFontSize = int(fx.size/4.0) D.add(String(fx.x+(fx.size),(fx.y+((fx.size/2.0))), "SAMPLE", fillColor=colors.gold, textAnchor='middle', fontSize=labelFontSize, fontName="Helvetica-Bold")) return D def _Flag_UK(self): s = _size g = Group() w = s*2 g.add(Rect(0, 0, w, s, fillColor = colors.navy, strokeColor = colors.black, strokeWidth=0)) g.add(Polygon([0,0, s*.225,0, w,s*(1-.1125), w,s, w-s*.225,s, 0, s*.1125], fillColor = colors.mintcream, strokeColor=None, strokeWidth=0)) g.add(Polygon([0,s*(1-.1125), 0, s, s*.225,s, w, s*.1125, w,0, w-s*.225,0], fillColor = colors.mintcream, strokeColor=None, strokeWidth=0)) g.add(Polygon([0, s-(s/15.0), (s-((s/10.0)*4)), (s*0.65), (s-(s/10.0)*3), (s*0.65), 0, s], fillColor = colors.red, strokeColor = None, strokeWidth=0)) g.add(Polygon([0, 0, (s-((s/10.0)*3)), (s*0.35), (s-((s/10.0)*2)), (s*0.35), (s/10.0), 0], fillColor = colors.red, strokeColor = None, strokeWidth=0)) g.add(Polygon([w, s, (s+((s/10.0)*3)), (s*0.65), (s+((s/10.0)*2)), (s*0.65), w-(s/10.0), s], fillColor = colors.red, strokeColor = None, strokeWidth=0)) g.add(Polygon([w, (s/15.0), (s+((s/10.0)*4)), (s*0.35), (s+((s/10.0)*3)), (s*0.35), w, 0], fillColor = colors.red, strokeColor = None, strokeWidth=0)) g.add(Rect(((s*0.42)*2), 0, width=(0.16*s)*2, height=s, fillColor = colors.mintcream, strokeColor = None, strokeWidth=0)) g.add(Rect(0, (s*0.35), width=w, height=s*0.3, fillColor = colors.mintcream, strokeColor = None, strokeWidth=0)) g.add(Rect(((s*0.45)*2), 0, width=(0.1*s)*2, height=s, fillColor = colors.red, strokeColor = None, strokeWidth=0)) g.add(Rect(0, (s*0.4), width=w, height=s*0.2, fillColor = colors.red, strokeColor = None, strokeWidth=0)) return g def _Flag_USA(self): s = _size # abbreviate as we will use this a lot g = Group() box = Rect(0, 0, s*2, s, fillColor = colors.mintcream, strokeColor = colors.black, strokeWidth=0) g.add(box) for stripecounter in range (13,0, -1): stripeheight = s/13.0 if not (stripecounter%2 == 0): stripecolor = colors.red else: stripecolor = colors.mintcream redorwhiteline = Rect(0, (s-(stripeheight*stripecounter)), width=s*2, height=stripeheight, fillColor = stripecolor, strokeColor = None, strokeWidth=20) g.add(redorwhiteline) bluebox = Rect(0, (s-(stripeheight*7)), width=0.8*s, height=stripeheight*7, fillColor = colors.darkblue, strokeColor = None, strokeWidth=0) g.add(bluebox) lss = s*0.045 lss2 = lss/2.0 s9 = s/9.0 s7 = s/7.0 for starxcounter in range(5): for starycounter in range(4): ls = Star() ls.size = lss ls.x = 0-s/22.0+lss/2.0+s7+starxcounter*s7 ls.fillColor = colors.mintcream ls.y = s-(starycounter+1)*s9+lss2 g.add(ls) for starxcounter in range(6): for starycounter in range(5): ls = Star() ls.size = lss ls.x = 0-(s/22.0)+lss/2.0+s/14.0+starxcounter*s7 ls.fillColor = colors.mintcream ls.y = s-(starycounter+1)*s9+(s/18.0)+lss2 g.add(ls) return g def _Flag_Afghanistan(self): s = _size g = Group() box = Rect(0, 0, s*2, s, fillColor = colors.mintcream, strokeColor = colors.black, strokeWidth=0) g.add(box) greenbox = Rect(0, ((s/3.0)*2.0), width=s*2.0, height=s/3.0, fillColor = colors.limegreen, strokeColor = None, strokeWidth=0) g.add(greenbox) blackbox = Rect(0, 0, width=s*2.0, height=s/3.0, fillColor = colors.black, strokeColor = None, strokeWidth=0) g.add(blackbox) return g def _Flag_Austria(self): s = _size # abbreviate as we will use this a lot g = Group() box = Rect(0, 0, s*2, s, fillColor = colors.mintcream, strokeColor = colors.black, strokeWidth=0) g.add(box) redbox1 = Rect(0, 0, width=s*2.0, height=s/3.0, fillColor = colors.red, strokeColor = None, strokeWidth=0) g.add(redbox1) redbox2 = Rect(0, ((s/3.0)*2.0), width=s*2.0, height=s/3.0, fillColor = colors.red, strokeColor = None, strokeWidth=0) g.add(redbox2) return g def _Flag_Belgium(self): s = _size g = Group() box = Rect(0, 0, s*2, s, fillColor = colors.black, strokeColor = colors.black, strokeWidth=0) g.add(box) box1 = Rect(0, 0, width=(s/3.0)*2.0, height=s, fillColor = colors.black, strokeColor = None, strokeWidth=0) g.add(box1) box2 = Rect(((s/3.0)*2.0), 0, width=(s/3.0)*2.0, height=s, fillColor = colors.gold, strokeColor = None, strokeWidth=0) g.add(box2) box3 = Rect(((s/3.0)*4.0), 0, width=(s/3.0)*2.0, height=s, fillColor = colors.red, strokeColor = None, strokeWidth=0) g.add(box3) return g def _Flag_China(self): s = _size g = Group() self._width = w = s*1.5 g.add(Rect(0, 0, w, s, fillColor=colors.red, strokeColor=None, strokeWidth=0)) def addStar(x,y,size,angle,g=g,w=s/20.0,x0=0,y0=s/2.0): s = Star() s.fillColor=colors.yellow s.angle = angle s.size = size*w*2 s.x = x*w+x0 s.y = y*w+y0 g.add(s) addStar(5,5,3, 0) addStar(10,1,1,36.86989765) addStar(12,3,1,8.213210702) addStar(12,6,1,16.60154960) addStar(10,8,1,53.13010235) return g def _Flag_Cuba(self): s = _size g = Group() for i in range(5): stripe = Rect(0, i*s/5.0, width=s*2, height=s/5.0, fillColor = [colors.darkblue, colors.mintcream][i%2], strokeColor = None, strokeWidth=0) g.add(stripe) redwedge = Polygon(points = [ 0, 0, 4*s/5.0, (s/2.0), 0, s], fillColor = colors.red, strokeColor = None, strokeWidth=0) g.add(redwedge) star = Star() star.x = 2.5*s/10.0 star.y = s/2.0 star.size = 3*s/10.0 star.fillColor = colors.white g.add(star) box = Rect(0, 0, s*2, s, fillColor = None, strokeColor = colors.black, strokeWidth=0) g.add(box) return g def _Flag_Denmark(self): s = _size g = Group() self._width = w = s*1.4 box = Rect(0, 0, w, s, fillColor = colors.red, strokeColor = colors.black, strokeWidth=0) g.add(box) whitebox1 = Rect(((s/5.0)*2), 0, width=s/6.0, height=s, fillColor = colors.mintcream, strokeColor = None, strokeWidth=0) g.add(whitebox1) whitebox2 = Rect(0, ((s/2.0)-(s/12.0)), width=w, height=s/6.0, fillColor = colors.mintcream, strokeColor = None, strokeWidth=0) g.add(whitebox2) return g def _Flag_Finland(self): s = _size g = Group() # crossbox specific bits box = Rect(0, 0, s*2, s, fillColor = colors.ghostwhite, strokeColor = colors.black, strokeWidth=0) g.add(box) blueline1 = Rect((s*0.6), 0, width=0.3*s, height=s, fillColor = colors.darkblue, strokeColor = None, strokeWidth=0) g.add(blueline1) blueline2 = Rect(0, (s*0.4), width=s*2, height=s*0.3, fillColor = colors.darkblue, strokeColor = None, strokeWidth=0) g.add(blueline2) return g def _Flag_France(self): s = _size g = Group() box = Rect(0, 0, s*2, s, fillColor = colors.navy, strokeColor = colors.black, strokeWidth=0) g.add(box) bluebox = Rect(0, 0, width=((s/3.0)*2.0), height=s, fillColor = colors.blue, strokeColor = None, strokeWidth=0) g.add(bluebox) whitebox = Rect(((s/3.0)*2.0), 0, width=((s/3.0)*2.0), height=s, fillColor = colors.mintcream, strokeColor = None, strokeWidth=0) g.add(whitebox) redbox = Rect(((s/3.0)*4.0), 0, width=((s/3.0)*2.0), height=s, fillColor = colors.red, strokeColor = None, strokeWidth=0) g.add(redbox) return g def _Flag_Germany(self): s = _size g = Group() box = Rect(0, 0, s*2, s, fillColor = colors.gold, strokeColor = colors.black, strokeWidth=0) g.add(box) blackbox1 = Rect(0, ((s/3.0)*2.0), width=s*2.0, height=s/3.0, fillColor = colors.black, strokeColor = None, strokeWidth=0) g.add(blackbox1) redbox1 = Rect(0, (s/3.0), width=s*2.0, height=s/3.0, fillColor = colors.orangered, strokeColor = None, strokeWidth=0) g.add(redbox1) return g def _Flag_Greece(self): s = _size g = Group() box = Rect(0, 0, s*2, s, fillColor = colors.gold, strokeColor = colors.black, strokeWidth=0) g.add(box) for stripecounter in range (9,0, -1): stripeheight = s/9.0 if not (stripecounter%2 == 0): stripecolor = colors.deepskyblue else: stripecolor = colors.mintcream blueorwhiteline = Rect(0, (s-(stripeheight*stripecounter)), width=s*2, height=stripeheight, fillColor = stripecolor, strokeColor = None, strokeWidth=20) g.add(blueorwhiteline) bluebox1 = Rect(0, ((s)-stripeheight*5), width=(stripeheight*5), height=stripeheight*5, fillColor = colors.deepskyblue, strokeColor = None, strokeWidth=0) g.add(bluebox1) whiteline1 = Rect(0, ((s)-stripeheight*3), width=stripeheight*5, height=stripeheight, fillColor = colors.mintcream, strokeColor = None, strokeWidth=0) g.add(whiteline1) whiteline2 = Rect((stripeheight*2), ((s)-stripeheight*5), width=stripeheight, height=stripeheight*5, fillColor = colors.mintcream, strokeColor = None, strokeWidth=0) g.add(whiteline2) return g def _Flag_Ireland(self): s = _size g = Group() box = Rect(0, 0, s*2, s, fillColor = colors.forestgreen, strokeColor = colors.black, strokeWidth=0) g.add(box) whitebox = Rect(((s*2.0)/3.0), 0, width=(2.0*(s*2.0)/3.0), height=s, fillColor = colors.mintcream, strokeColor = None, strokeWidth=0) g.add(whitebox) orangebox = Rect(((2.0*(s*2.0)/3.0)), 0, width=(s*2.0)/3.0, height=s, fillColor = colors.darkorange, strokeColor = None, strokeWidth=0) g.add(orangebox) return g def _Flag_Italy(self): s = _size g = Group() g.add(Rect(0,0,s*2,s,fillColor=colors.forestgreen,strokeColor=None, strokeWidth=0)) g.add(Rect((2*s)/3.0, 0, width=(s*4)/3.0, height=s, fillColor = colors.mintcream, strokeColor = None, strokeWidth=0)) g.add(Rect((4*s)/3.0, 0, width=(s*2)/3.0, height=s, fillColor = colors.red, strokeColor = None, strokeWidth=0)) return g def _Flag_Japan(self): s = _size g = Group() w = self._width = s*1.5 g.add(Rect(0,0,w,s,fillColor=colors.mintcream,strokeColor=None, strokeWidth=0)) g.add(Circle(cx=w/2.0,cy=s/2.0,r=0.3*w,fillColor=colors.red,strokeColor=None, strokeWidth=0)) return g def _Flag_Luxembourg(self): s = _size g = Group() box = Rect(0, 0, s*2, s, fillColor = colors.mintcream, strokeColor = colors.black, strokeWidth=0) g.add(box) redbox = Rect(0, ((s/3.0)*2.0), width=s*2.0, height=s/3.0, fillColor = colors.red, strokeColor = None, strokeWidth=0) g.add(redbox) bluebox = Rect(0, 0, width=s*2.0, height=s/3.0, fillColor = colors.dodgerblue, strokeColor = None, strokeWidth=0) g.add(bluebox) return g def _Flag_Holland(self): s = _size g = Group() box = Rect(0, 0, s*2, s, fillColor = colors.mintcream, strokeColor = colors.black, strokeWidth=0) g.add(box) redbox = Rect(0, ((s/3.0)*2.0), width=s*2.0, height=s/3.0, fillColor = colors.red, strokeColor = None, strokeWidth=0) g.add(redbox) bluebox = Rect(0, 0, width=s*2.0, height=s/3.0, fillColor = colors.darkblue, strokeColor = None, strokeWidth=0) g.add(bluebox) return g def _Flag_Portugal(self): return Group() def _Flag_Russia(self): s = _size g = Group() w = self._width = s*1.5 t = s/3.0 g.add(Rect(0, 0, width=w, height=t, fillColor = colors.red, strokeColor = None, strokeWidth=0)) g.add(Rect(0, t, width=w, height=t, fillColor = colors.blue, strokeColor = None, strokeWidth=0)) g.add(Rect(0, 2*t, width=w, height=t, fillColor = colors.mintcream, strokeColor = None, strokeWidth=0)) return g def _Flag_Spain(self): s = _size g = Group() w = self._width = s*1.5 g.add(Rect(0, 0, width=w, height=s, fillColor = colors.red, strokeColor = None, strokeWidth=0)) g.add(Rect(0, (s/4.0), width=w, height=s/2.0, fillColor = colors.yellow, strokeColor = None, strokeWidth=0)) return g def _Flag_Sweden(self): s = _size g = Group() self._width = s*1.4 box = Rect(0, 0, self._width, s, fillColor = colors.dodgerblue, strokeColor = colors.black, strokeWidth=0) g.add(box) box1 = Rect(((s/5.0)*2), 0, width=s/6.0, height=s, fillColor = colors.gold, strokeColor = None, strokeWidth=0) g.add(box1) box2 = Rect(0, ((s/2.0)-(s/12.0)), width=self._width, height=s/6.0, fillColor = colors.gold, strokeColor = None, strokeWidth=0) g.add(box2) return g def _Flag_Norway(self): s = _size g = Group() self._width = s*1.4 box = Rect(0, 0, self._width, s, fillColor = colors.red, strokeColor = colors.black, strokeWidth=0) g.add(box) box = Rect(0, 0, self._width, s, fillColor = colors.red, strokeColor = colors.black, strokeWidth=0) g.add(box) whiteline1 = Rect(((s*0.2)*2), 0, width=s*0.2, height=s, fillColor = colors.ghostwhite, strokeColor = None, strokeWidth=0) g.add(whiteline1) whiteline2 = Rect(0, (s*0.4), width=self._width, height=s*0.2, fillColor = colors.ghostwhite, strokeColor = None, strokeWidth=0) g.add(whiteline2) blueline1 = Rect(((s*0.225)*2), 0, width=0.1*s, height=s, fillColor = colors.darkblue, strokeColor = None, strokeWidth=0) g.add(blueline1) blueline2 = Rect(0, (s*0.45), width=self._width, height=s*0.1, fillColor = colors.darkblue, strokeColor = None, strokeWidth=0) g.add(blueline2) return g def _Flag_CzechRepublic(self): s = _size g = Group() box = Rect(0, 0, s*2, s, fillColor = colors.mintcream, strokeColor = colors.black, strokeWidth=0) g.add(box) redbox = Rect(0, 0, width=s*2, height=s/2.0, fillColor = colors.red, strokeColor = None, strokeWidth=0) g.add(redbox) bluewedge = Polygon(points = [ 0, 0, s, (s/2.0), 0, s], fillColor = colors.darkblue, strokeColor = None, strokeWidth=0) g.add(bluewedge) return g def _Flag_Palestine(self): s = _size g = Group() box = Rect(0, s/3.0, s*2, s/3.0, fillColor = colors.mintcream, strokeColor = None, strokeWidth=0) g.add(box) greenbox = Rect(0, 0, width=s*2, height=s/3.0, fillColor = colors.limegreen, strokeColor = None, strokeWidth=0) g.add(greenbox) blackbox = Rect(0, 2*s/3.0, width=s*2, height=s/3.0, fillColor = colors.black, strokeColor = None, strokeWidth=0) g.add(blackbox) redwedge = Polygon(points = [ 0, 0, 2*s/3.0, (s/2.0), 0, s], fillColor = colors.red, strokeColor = None, strokeWidth=0) g.add(redwedge) return g def _Flag_Turkey(self): s = _size g = Group() box = Rect(0, 0, s*2, s, fillColor = colors.red, strokeColor = colors.black, strokeWidth=0) g.add(box) whitecircle = Circle(cx=((s*0.35)*2), cy=s/2.0, r=s*0.3, fillColor = colors.mintcream, strokeColor = None, strokeWidth=0) g.add(whitecircle) redcircle = Circle(cx=((s*0.39)*2), cy=s/2.0, r=s*0.24, fillColor = colors.red, strokeColor = None, strokeWidth=0) g.add(redcircle) ws = Star() ws.angle = 15 ws.size = s/5.0 ws.x = (s*0.5)*2+ws.size/2.0 ws.y = (s*0.5) ws.fillColor = colors.mintcream ws.strokeColor = None g.add(ws) return g def _Flag_Switzerland(self): s = _size g = Group() self._width = s g.add(Rect(0, 0, s, s, fillColor = colors.red, strokeColor = colors.black, strokeWidth=0)) g.add(Line((s/2.0), (s/5.5), (s/2), (s-(s/5.5)), fillColor = colors.mintcream, strokeColor = colors.mintcream, strokeWidth=(s/5.0))) g.add(Line((s/5.5), (s/2.0), (s-(s/5.5)), (s/2.0), fillColor = colors.mintcream, strokeColor = colors.mintcream, strokeWidth=s/5.0)) return g def _Flag_EU(self): s = _size g = Group() w = self._width = 1.5*s g.add(Rect(0, 0, w, s, fillColor = colors.darkblue, strokeColor = None, strokeWidth=0)) centerx=w/2.0 centery=s/2.0 radius=s/3.0 yradius = radius xradius = radius nStars = 12 delta = 2*pi/nStars for i in range(nStars): rad = i*delta gs = Star() gs.x=cos(rad)*radius+centerx gs.y=sin(rad)*radius+centery gs.size=s/10.0 gs.fillColor=colors.gold g.add(gs) return g def _Flag_Brazil(self): s = _size # abbreviate as we will use this a lot g = Group() m = s/14.0 self._width = w = (m * 20) def addStar(x,y,size, g=g, w=w, s=s, m=m): st = Star() st.fillColor=colors.mintcream st.size = size*m st.x = (w/2.0) + (x * (0.35 * m)) st.y = (s/2.0) + (y * (0.35 * m)) g.add(st) g.add(Rect(0, 0, w, s, fillColor = colors.green, strokeColor = None, strokeWidth=0)) g.add(Polygon(points = [ 1.7*m, (s/2.0), (w/2.0), s-(1.7*m), w-(1.7*m),(s/2.0),(w/2.0), 1.7*m], fillColor = colors.yellow, strokeColor = None, strokeWidth=0)) g.add(Circle(cx=w/2.0, cy=s/2.0, r=3.5*m, fillColor=colors.blue,strokeColor=None, strokeWidth=0)) g.add(Wedge((w/2.0)-(2*m), 0, 8.5*m, 50, 98.1, 8.5*m, fillColor=colors.mintcream,strokeColor=None, strokeWidth=0)) g.add(Wedge((w/2.0), (s/2.0), 3.501*m, 156, 352, 3.501*m, fillColor=colors.mintcream,strokeColor=None, strokeWidth=0)) g.add(Wedge((w/2.0)-(2*m), 0, 8*m, 48.1, 100, 8*m, fillColor=colors.blue,strokeColor=None, strokeWidth=0)) g.add(Rect(0, 0, w, (s/4.0) + 1.7*m, fillColor = colors.green, strokeColor = None, strokeWidth=0)) g.add(Polygon(points = [ 1.7*m,(s/2.0), (w/2.0),s/2.0 - 2*m, w-(1.7*m),(s/2.0) , (w/2.0),1.7*m], fillColor = colors.yellow, strokeColor = None, strokeWidth=0)) g.add(Wedge(w/2.0, s/2.0, 3.502*m, 166, 342.1, 3.502*m, fillColor=colors.blue,strokeColor=None, strokeWidth=0)) addStar(3.2,3.5,0.3) addStar(-8.5,1.5,0.3) addStar(-7.5,-3,0.3) addStar(-4,-5.5,0.3) addStar(0,-4.5,0.3) addStar(7,-3.5,0.3) addStar(-3.5,-0.5,0.25) addStar(0,-1.5,0.25) addStar(1,-2.5,0.25) addStar(3,-7,0.25) addStar(5,-6.5,0.25) addStar(6.5,-5,0.25) addStar(7,-4.5,0.25) addStar(-5.5,-3.2,0.25) addStar(-6,-4.2,0.25) addStar(-1,-2.75,0.2) addStar(2,-5.5,0.2) addStar(4,-5.5,0.2) addStar(5,-7.5,0.2) addStar(5,-5.5,0.2) addStar(6,-5.5,0.2) addStar(-8.8,-3.2,0.2) addStar(2.5,0.5,0.2) addStar(-0.2,-3.2,0.14) addStar(-7.2,-2,0.14) addStar(0,-8,0.1) sTmp = "ORDEM E PROGRESSO" nTmp = len(sTmp) delta = 0.850848010347/nTmp radius = 7.9 *m centerx = (w/2.0)-(2*m) centery = 0 for i in range(nTmp): rad = 2*pi - i*delta -4.60766922527 x=cos(rad)*radius+centerx y=sin(rad)*radius+centery if i == 6: z = 0.35*m else: z= 0.45*m g2 = Group(String(x, y, sTmp[i], fontName='Helvetica-Bold', fontSize = z,strokeColor=None,fillColor=colors.green)) g2.rotate(rad) g.add(g2) return g def makeFlag(name): flag = Flag() flag.kind = name return flag def test(): """This function produces three pdf files with examples of all the signs and symbols from this file. """ # page 1 labelFontSize = 10 X = (20,245) flags = [ 'UK', 'USA', 'Afghanistan', 'Austria', 'Belgium', 'Denmark', 'Cuba', 'Finland', 'France', 'Germany', 'Greece', 'Ireland', 'Italy', 'Luxembourg', 'Holland', 'Palestine', 'Portugal', 'Spain', 'Sweden', 'Norway', 'CzechRepublic', 'Turkey', 'Switzerland', 'EU', 'Brazil', ] y = Y0 = 530 f = 0 D = None for name in flags: if not D: D = Drawing(450,650) flag = makeFlag(name) i = flags.index(name) flag.x = X[i%2] flag.y = y D.add(flag) D.add(String(flag.x+(flag.size/2.0),(flag.y-(1.2*labelFontSize)), name, fillColor=colors.black, textAnchor='middle', fontSize=labelFontSize)) if i%2: y = y - 125 if (i%2 and y<0) or name==flags[-1]: renderPDF.drawToFile(D, 'flags%02d.pdf'%f, 'flags.py - Page #%d'%(f+1)) y = Y0 f = f+1 D = None if __name__=='__main__': test() ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1691062243.0 reportlab-4.1.0/src/reportlab/graphics/widgets/grids.py0000664000175000017500000004214014462707743022632 0ustar00rptlabrptlab#Copyright ReportLab Europe Ltd. 2000-2017 #see license.txt for license details #history https://hg.reportlab.com/hg-public/reportlab/log/tip/src/reportlab/graphics/widgets/grids.py __version__='3.3.0' from reportlab.lib import colors from reportlab.lib.validators import isNumber, isColorOrNone, isBoolean, isListOfNumbers, OneOf, isListOfColors, isNumberOrNone from reportlab.lib.attrmap import AttrMap, AttrMapValue from reportlab.graphics.shapes import Drawing, Group, Line, Rect, LineShape, definePath, EmptyClipPath from reportlab.graphics.widgetbase import Widget def frange(start, end=None, inc=None): "A range function, that does accept float increments..." if end == None: end = start + 0.0 start = 0.0 if inc == None: inc = 1.0 L = [] end = end - inc*0.0001 #to avoid numrical problems while 1: next = start + len(L) * inc if inc > 0 and next >= end: break elif inc < 0 and next <= end: break L.append(next) return L def makeDistancesList(list): """Returns a list of distances between adjacent numbers in some input list. E.g. [1, 1, 2, 3, 5, 7] -> [0, 1, 1, 2, 2] """ d = [] for i in range(len(list[:-1])): d.append(list[i+1] - list[i]) return d class Grid(Widget): """This makes a rectangular grid of equidistant stripes. The grid contains an outer border rectangle, and stripes inside which can be drawn with lines and/or as solid tiles. The drawing order is: outer rectangle, then lines and tiles. The stripes' width is indicated as 'delta'. The sequence of stripes can have an offset named 'delta0'. Both values need to be positive! """ _attrMap = AttrMap( x = AttrMapValue(isNumber, desc="The grid's lower-left x position."), y = AttrMapValue(isNumber, desc="The grid's lower-left y position."), width = AttrMapValue(isNumber, desc="The grid's width."), height = AttrMapValue(isNumber, desc="The grid's height."), orientation = AttrMapValue(OneOf(('vertical', 'horizontal')), desc='Determines if stripes are vertical or horizontal.'), useLines = AttrMapValue(OneOf((0, 1)), desc='Determines if stripes are drawn with lines.'), useRects = AttrMapValue(OneOf((0, 1)), desc='Determines if stripes are drawn with solid rectangles.'), delta = AttrMapValue(isNumber, desc='Determines the width/height of the stripes.'), delta0 = AttrMapValue(isNumber, desc='Determines the stripes initial width/height offset.'), deltaSteps = AttrMapValue(isListOfNumbers, desc='List of deltas to be used cyclically.'), stripeColors = AttrMapValue(isListOfColors, desc='Colors applied cyclically in the right or upper direction.'), fillColor = AttrMapValue(isColorOrNone, desc='Background color for entire rectangle.'), strokeColor = AttrMapValue(isColorOrNone, desc='Color used for lines.'), strokeWidth = AttrMapValue(isNumber, desc='Width used for lines.'), rectStrokeColor = AttrMapValue(isColorOrNone, desc='Color for outer rect stroke.'), rectStrokeWidth = AttrMapValue(isNumberOrNone, desc='Width for outer rect stroke.'), ) def __init__(self): self.x = 0 self.y = 0 self.width = 100 self.height = 100 self.orientation = 'vertical' self.useLines = 0 self.useRects = 1 self.delta = 20 self.delta0 = 0 self.deltaSteps = [] self.fillColor = colors.white self.stripeColors = [colors.red, colors.green, colors.blue] self.strokeColor = colors.black self.strokeWidth = 2 def demo(self): D = Drawing(100, 100) g = Grid() D.add(g) return D def makeOuterRect(self): strokeColor = getattr(self,'rectStrokeColor',self.strokeColor) strokeWidth = getattr(self,'rectStrokeWidth',self.strokeWidth) if self.fillColor or (strokeColor and strokeWidth): rect = Rect(self.x, self.y, self.width, self.height) rect.fillColor = self.fillColor rect.strokeColor = strokeColor rect.strokeWidth = strokeWidth return rect else: return None def makeLinePosList(self, start, isX=0): "Returns a list of positions where to place lines." w, h = self.width, self.height if isX: length = w else: length = h if self.deltaSteps: r = [start + self.delta0] i = 0 while 1: if r[-1] > start + length: del r[-1] break r.append(r[-1] + self.deltaSteps[i % len(self.deltaSteps)]) i = i + 1 else: r = frange(start + self.delta0, start + length, self.delta) r.append(start + length) if self.delta0 != 0: r.insert(0, start) #print 'Grid.makeLinePosList() -> %s' % r return r def makeInnerLines(self): # inner grid lines group = Group() w, h = self.width, self.height if self.useLines == 1: if self.orientation == 'vertical': r = self.makeLinePosList(self.x, isX=1) for x in r: line = Line(x, self.y, x, self.y + h) line.strokeColor = self.strokeColor line.strokeWidth = self.strokeWidth group.add(line) elif self.orientation == 'horizontal': r = self.makeLinePosList(self.y, isX=0) for y in r: line = Line(self.x, y, self.x + w, y) line.strokeColor = self.strokeColor line.strokeWidth = self.strokeWidth group.add(line) return group def makeInnerTiles(self): # inner grid lines group = Group() w, h = self.width, self.height # inner grid stripes (solid rectangles) if self.useRects == 1: cols = self.stripeColors if self.orientation == 'vertical': r = self.makeLinePosList(self.x, isX=1) elif self.orientation == 'horizontal': r = self.makeLinePosList(self.y, isX=0) dist = makeDistancesList(r) i = 0 for j in range(len(dist)): if self.orientation == 'vertical': x = r[j] stripe = Rect(x, self.y, dist[j], h) elif self.orientation == 'horizontal': y = r[j] stripe = Rect(self.x, y, w, dist[j]) stripe.fillColor = cols[i % len(cols)] stripe.strokeColor = None group.add(stripe) i = i + 1 return group def draw(self): # general widget bits group = Group() group.add(self.makeOuterRect()) group.add(self.makeInnerTiles()) group.add(self.makeInnerLines(),name='_gridLines') return group class DoubleGrid(Widget): """This combines two ordinary Grid objects orthogonal to each other. """ _attrMap = AttrMap( x = AttrMapValue(isNumber, desc="The grid's lower-left x position."), y = AttrMapValue(isNumber, desc="The grid's lower-left y position."), width = AttrMapValue(isNumber, desc="The grid's width."), height = AttrMapValue(isNumber, desc="The grid's height."), grid0 = AttrMapValue(None, desc="The first grid component."), grid1 = AttrMapValue(None, desc="The second grid component."), ) def __init__(self): self.x = 0 self.y = 0 self.width = 100 self.height = 100 g0 = Grid() g0.x = self.x g0.y = self.y g0.width = self.width g0.height = self.height g0.orientation = 'vertical' g0.useLines = 1 g0.useRects = 0 g0.delta = 20 g0.delta0 = 0 g0.deltaSteps = [] g0.fillColor = colors.white g0.stripeColors = [colors.red, colors.green, colors.blue] g0.strokeColor = colors.black g0.strokeWidth = 1 g1 = Grid() g1.x = self.x g1.y = self.y g1.width = self.width g1.height = self.height g1.orientation = 'horizontal' g1.useLines = 1 g1.useRects = 0 g1.delta = 20 g1.delta0 = 0 g1.deltaSteps = [] g1.fillColor = colors.white g1.stripeColors = [colors.red, colors.green, colors.blue] g1.strokeColor = colors.black g1.strokeWidth = 1 self.grid0 = g0 self.grid1 = g1 ## # This gives an AttributeError: ## # DoubleGrid instance has no attribute 'grid0' ## def __setattr__(self, name, value): ## if name in ('x', 'y', 'width', 'height'): ## setattr(self.grid0, name, value) ## setattr(self.grid1, name, value) def demo(self): D = Drawing(100, 100) g = DoubleGrid() D.add(g) return D def draw(self): group = Group() g0, g1 = self.grid0, self.grid1 # Order groups to make sure both v and h lines # are visible (works only when there is only # one kind of stripes, v or h). G = g0.useRects == 1 and g1.useRects == 0 and (g0,g1) or (g1,g0) for g in G: group.add(g.makeOuterRect()) for g in G: group.add(g.makeInnerTiles()) group.add(g.makeInnerLines(),name='_gridLines') return group class ShadedRect(Widget): """This makes a rectangle with shaded colors between two colors. Colors are interpolated linearly between 'fillColorStart' and 'fillColorEnd', both of which appear at the margins. If 'numShades' is set to one, though, only 'fillColorStart' is used. """ _attrMap = AttrMap( x = AttrMapValue(isNumber, desc="The grid's lower-left x position."), y = AttrMapValue(isNumber, desc="The grid's lower-left y position."), width = AttrMapValue(isNumber, desc="The grid's width."), height = AttrMapValue(isNumber, desc="The grid's height."), orientation = AttrMapValue(OneOf(('vertical', 'horizontal')), desc='Determines if stripes are vertical or horizontal.'), numShades = AttrMapValue(isNumber, desc='The number of interpolating colors.'), fillColorStart = AttrMapValue(isColorOrNone, desc='Start value of the color shade.'), fillColorEnd = AttrMapValue(isColorOrNone, desc='End value of the color shade.'), strokeColor = AttrMapValue(isColorOrNone, desc='Color used for border line.'), strokeWidth = AttrMapValue(isNumber, desc='Width used for lines.'), cylinderMode = AttrMapValue(isBoolean, desc='True if shading reverses in middle.'), ) def __init__(self,**kw): self.x = 0 self.y = 0 self.width = 100 self.height = 100 self.orientation = 'vertical' self.numShades = 20 self.fillColorStart = colors.pink self.fillColorEnd = colors.black self.strokeColor = colors.black self.strokeWidth = 2 self.cylinderMode = 0 self.setProperties(kw) def demo(self): D = Drawing(100, 100) g = ShadedRect() D.add(g) return D def _flipRectCorners(self): "Flip rectangle's corners if width or height is negative." x, y, width, height, fillColorStart, fillColorEnd = self.x, self.y, self.width, self.height, self.fillColorStart, self.fillColorEnd if width < 0 and height > 0: x = x + width width = -width if self.orientation=='vertical': fillColorStart, fillColorEnd = fillColorEnd, fillColorStart elif height<0 and width>0: y = y + height height = -height if self.orientation=='horizontal': fillColorStart, fillColorEnd = fillColorEnd, fillColorStart elif height < 0 and height < 0: x = x + width width = -width y = y + height height = -height return x, y, width, height, fillColorStart, fillColorEnd def draw(self): # general widget bits group = Group() x, y, w, h, c0, c1 = self._flipRectCorners() numShades = self.numShades if self.cylinderMode: if not numShades%2: numShades = numShades+1 halfNumShades = int((numShades-1)/2) + 1 num = float(numShades) # must make it float! vertical = self.orientation == 'vertical' if vertical: if numShades == 1: V = [x] else: V = frange(x, x + w, w/num) else: if numShades == 1: V = [y] else: V = frange(y, y + h, h/num) for v in V: stripe = vertical and Rect(v, y, w/num, h) or Rect(x, v, w, h/num) if self.cylinderMode: if V.index(v)>=halfNumShades: col = colors.linearlyInterpolatedColor(c1,c0,V[halfNumShades],V[-1], v) else: col = colors.linearlyInterpolatedColor(c0,c1,V[0],V[halfNumShades], v) else: col = colors.linearlyInterpolatedColor(c0,c1,V[0],V[-1], v) stripe.fillColor = col stripe.strokeColor = col stripe.strokeWidth = 1 group.add(stripe) if self.strokeColor and self.strokeWidth>=0: rect = Rect(x, y, w, h) rect.strokeColor = self.strokeColor rect.strokeWidth = self.strokeWidth rect.fillColor = None group.add(rect) return group def colorRange(c0, c1, n): "Return a range of intermediate colors between c0 and c1" if n==1: return [c0] C = [] if n>1: lim = n-1 for i in range(n): C.append(colors.linearlyInterpolatedColor(c0,c1,0,lim, i)) return C def centroid(P): '''compute average point of a set of points''' cx = 0 cy = 0 for x,y in P: cx+=x cy+=y n = float(len(P)) return cx/n, cy/n def rotatedEnclosingRect(P, angle, rect): ''' given P a sequence P of x,y coordinate pairs and an angle in degrees find the centroid of P and the axis at angle theta through it find the extreme points of P wrt axis parallel distance and axis orthogonal distance. Then compute the least rectangle that will still enclose P when rotated by angle. The class R ''' from math import pi, cos, sin x0, y0 = centroid(P) theta = (angle/180.)*pi s,c=sin(theta),cos(theta) def parallelAxisDist(xy,s=s,c=c,x0=x0,y0=y0): x,y = xy return (s*(y-y0)+c*(x-x0)) def orthogonalAxisDist(xy,s=s,c=c,x0=x0,y0=y0): x,y = xy return (c*(y-y0)+s*(x-x0)) L = list(map(parallelAxisDist,P)) L.sort() a0, a1 = L[0], L[-1] L = list(map(orthogonalAxisDist,P)) L.sort() b0, b1 = L[0], L[-1] rect.x, rect.width = a0, a1-a0 rect.y, rect.height = b0, b1-b0 g = Group(transform=(c,s,-s,c,x0,y0)) g.add(rect) return g class ShadedPolygon(Widget,LineShape): _attrMap = AttrMap(BASE=LineShape, angle = AttrMapValue(isNumber,desc="Shading angle"), fillColorStart = AttrMapValue(isColorOrNone), fillColorEnd = AttrMapValue(isColorOrNone), numShades = AttrMapValue(isNumber, desc='The number of interpolating colors.'), cylinderMode = AttrMapValue(isBoolean, desc='True if shading reverses in middle.'), points = AttrMapValue(isListOfNumbers), ) def __init__(self,**kw): self.angle = 90 self.fillColorStart = colors.red self.fillColorEnd = colors.green self.cylinderMode = 0 self.numShades = 50 self.points = [-1,-1,2,2,3,-1] LineShape.__init__(self,kw) def draw(self): P = self.points P = list(map(lambda i, P=P:(P[i],P[i+1]),range(0,len(P),2))) path = definePath([('moveTo',)+P[0]]+[('lineTo',)+x for x in P[1:]]+['closePath'], fillColor=None, strokeColor=None) path.isClipPath = 1 g = Group() g.add(path) angle = self.angle orientation = 'vertical' if angle==180: angle = 0 elif angle in (90,270): orientation ='horizontal' angle = 0 rect = ShadedRect(strokeWidth=0,strokeColor=None,orientation=orientation) for k in 'fillColorStart', 'fillColorEnd', 'numShades', 'cylinderMode': setattr(rect,k,getattr(self,k)) g.add(rotatedEnclosingRect(P, angle, rect)) g.add(EmptyClipPath) path = path.copy() path.isClipPath = 0 path.strokeColor = self.strokeColor path.strokeWidth = self.strokeWidth g.add(path) return g if __name__=='__main__': #noruntests angle=45 D = Drawing(120,120) D.add(ShadedPolygon(points=(10,10,60,60,110,10),strokeColor=None,strokeWidth=1,angle=90,numShades=50,cylinderMode=0)) D.save(formats=['gif'],fnRoot='shobj',outDir='/tmp') ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1691062243.0 reportlab-4.1.0/src/reportlab/graphics/widgets/markers.py0000664000175000017500000002035014462707743023165 0ustar00rptlabrptlab#Copyright ReportLab Europe Ltd. 2000-2017 #see license.txt for license details __version__='3.3.0' __doc__="""This modules defines a collection of markers used in charts. """ from reportlab.graphics.shapes import Rect, Circle, Polygon, Drawing, Group from reportlab.graphics.widgets.signsandsymbols import SmileyFace from reportlab.graphics.widgetbase import Widget from reportlab.lib.validators import isNumber, isColorOrNone, OneOf, Validator from reportlab.lib.attrmap import AttrMap, AttrMapValue from reportlab.lib.colors import black from reportlab.lib.utils import isClass from reportlab.graphics.widgets.flags import Flag, _Symbol from math import sin, cos, pi _toradians = pi/180.0 class Marker(Widget): '''A polymorphic class of markers''' _attrMap = AttrMap(BASE=Widget, kind = AttrMapValue( OneOf(None, 'Square', 'Diamond', 'Circle', 'Cross', 'Triangle', 'StarSix', 'Pentagon', 'Hexagon', 'Heptagon', 'Octagon', 'StarFive', 'FilledSquare', 'FilledCircle', 'FilledDiamond', 'FilledCross', 'FilledTriangle','FilledStarSix', 'FilledPentagon', 'FilledHexagon', 'FilledHeptagon', 'FilledOctagon', 'FilledStarFive', 'Smiley','ArrowHead', 'FilledArrowHead'), desc='marker type name'), size = AttrMapValue(isNumber,desc='marker size'), x = AttrMapValue(isNumber,desc='marker x coordinate'), y = AttrMapValue(isNumber,desc='marker y coordinate'), dx = AttrMapValue(isNumber,desc='marker x coordinate adjustment'), dy = AttrMapValue(isNumber,desc='marker y coordinate adjustment'), angle = AttrMapValue(isNumber,desc='marker rotation'), fillColor = AttrMapValue(isColorOrNone, desc='marker fill colour'), strokeColor = AttrMapValue(isColorOrNone, desc='marker stroke colour'), strokeWidth = AttrMapValue(isNumber, desc='marker stroke width'), arrowBarbDx = AttrMapValue(isNumber, desc='arrow only the delta x for the barbs'), arrowHeight = AttrMapValue(isNumber, desc='arrow only height'), ) def __init__(self,*args,**kw): self.setProperties(kw) self._setKeywords( kind = None, strokeColor = black, strokeWidth = 0.1, fillColor = None, size = 5, x = 0, y = 0, dx = 0, dy = 0, angle = 0, arrowBarbDx = -1.25, arrowHeight = 1.875, ) def clone(self,**kwds): n = self.__class__(**self.__dict__) if kwds: n.__dict__.update(kwds) return n def _Smiley(self): x, y = self.x+self.dx, self.y+self.dy d = self.size/2.0 s = SmileyFace() s.fillColor = self.fillColor s.strokeWidth = self.strokeWidth s.strokeColor = self.strokeColor s.x = x-d s.y = y-d s.size = d*2 return s def _Square(self): x, y = self.x+self.dx, self.y+self.dy d = self.size/2.0 s = Rect(x-d,y-d,2*d,2*d,fillColor=self.fillColor,strokeColor=self.strokeColor,strokeWidth=self.strokeWidth) return s def _Diamond(self): d = self.size/2.0 return self._doPolygon((-d,0,0,d,d,0,0,-d)) def _Circle(self): x, y = self.x+self.dx, self.y+self.dy s = Circle(x,y,self.size/2.0,fillColor=self.fillColor,strokeColor=self.strokeColor,strokeWidth=self.strokeWidth) return s def _Cross(self): x, y = self.x+self.dx, self.y+self.dy s = float(self.size) h, s = s/2, s/6 return self._doPolygon((-s,-h,-s,-s,-h,-s,-h,s,-s,s,-s,h,s,h,s,s,h,s,h,-s,s,-s,s,-h)) def _Triangle(self): x, y = self.x+self.dx, self.y+self.dy r = float(self.size)/2 c = 30*_toradians s = sin(30*_toradians)*r c = cos(c)*r return self._doPolygon((0,r,-c,-s,c,-s)) def _StarSix(self): r = float(self.size)/2 c = 30*_toradians s = sin(c)*r c = cos(c)*r z = s/2 g = c/2 return self._doPolygon((0,r,-z,s,-c,s,-s,0,-c,-s,-z,-s,0,-r,z,-s,c,-s,s,0,c,s,z,s)) def _StarFive(self): R = float(self.size)/2 r = R*sin(18*_toradians)/cos(36*_toradians) P = [] angle = 90 for i in range(5): for radius in R, r: theta = angle*_toradians P.append(radius*cos(theta)) P.append(radius*sin(theta)) angle = angle + 36 return self._doPolygon(P) def _Pentagon(self): return self._doNgon(5) def _Hexagon(self): return self._doNgon(6) def _Heptagon(self): return self._doNgon(7) def _Octagon(self): return self._doNgon(8) def _ArrowHead(self): s = self.size h = self.arrowHeight b = self.arrowBarbDx return self._doPolygon((0,0,b,-h,s,0,b,h)) def _doPolygon(self,P): x, y = self.x+self.dx, self.y+self.dy if x or y: P = list(map(lambda i,P=P,A=[x,y]: P[i] + A[i&1], list(range(len(P))))) return Polygon(P, strokeWidth =self.strokeWidth, strokeColor=self.strokeColor, fillColor=self.fillColor) def _doFill(self): old = self.fillColor if old is None: self.fillColor = self.strokeColor r = (self.kind and getattr(self,'_'+self.kind[6:]) or Group)() self.fillColor = old return r def _doNgon(self,n): P = [] size = float(self.size)/2 for i in range(n): r = (2.*i/n+0.5)*pi P.append(size*cos(r)) P.append(size*sin(r)) return self._doPolygon(P) _FilledCircle = _doFill _FilledSquare = _doFill _FilledDiamond = _doFill _FilledCross = _doFill _FilledTriangle = _doFill _FilledStarSix = _doFill _FilledPentagon = _doFill _FilledHexagon = _doFill _FilledHeptagon = _doFill _FilledOctagon = _doFill _FilledStarFive = _doFill _FilledArrowHead = _doFill def draw(self): if self.kind: m = getattr(self,'_'+self.kind) if self.angle: _x, _dx, _y, _dy = self.x, self.dx, self.y, self.dy self.x, self.dx, self.y, self.dy = 0,0,0,0 try: m = m() finally: self.x, self.dx, self.y, self.dy = _x, _dx, _y, _dy if not isinstance(m,Group): _m, m = m, Group() m.add(_m) if self.angle: m.rotate(self.angle) x, y = _x+_dx, _y+_dy if x or y: m.shift(x,y) else: m = m() else: m = Group() return m def uSymbol2Symbol(uSymbol,x,y,color): if isClass(uSymbol) and issubclass(uSymbol,Widget): size = 10. symbol = uSymbol() symbol.x = x - (size/2) symbol.y = y - (size/2) try: symbol.size = size symbol.color = color except: pass elif isinstance(uSymbol,Marker) or isinstance(uSymbol,_Symbol): symbol = uSymbol.clone() if isinstance(uSymbol,Marker): symbol.fillColor = symbol.fillColor or color symbol.x, symbol.y = x, y elif callable(uSymbol): symbol = uSymbol(x, y, 5, color) else: symbol = None return symbol class _isSymbol(Validator): def test(self,x): return hasattr(x,'__call__') or isinstance(x,Marker) or isinstance(x,_Symbol) or (isClass(x) and issubclass(x,Widget)) isSymbol = _isSymbol() def makeMarker(name,**kw): if Marker._attrMap['kind'].validate(name): m = Marker(**kw) m.kind = name elif name[-5:]=='_Flag' and Flag._attrMap['kind'].validate(name[:-5]): m = Flag(**kw) m.kind = name[:-5] m.size = 10 else: raise ValueError("Invalid marker name %s" % name) return m if __name__=='__main__': D = Drawing() D.add(Marker()) D.save(fnRoot='Marker',formats=['pdf'], outDir='/tmp') ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1691062243.0 reportlab-4.1.0/src/reportlab/graphics/widgets/signsandsymbols.py0000664000175000017500000007564714462707743024763 0ustar00rptlabrptlab#Copyright ReportLab Europe Ltd. 2000-2017 #see license.txt for license details #history https://hg.reportlab.com/hg-public/reportlab/log/tip/src/reportlab/graphics/widgets/signsandsymbols.py # signsandsymbols.py # A collection of new widgets # author: John Precedo (johnp@reportlab.com) __version__='3.3.0' __doc__="""This file is a collection of widgets to produce some common signs and symbols. Widgets include: - ETriangle (an equilateral triangle), - RTriangle (a right angled triangle), - Octagon, - Crossbox, - Tickbox, - SmileyFace, - StopSign, - NoEntry, - NotAllowed (the red roundel from 'no smoking' signs), - NoSmoking, - DangerSign (a black exclamation point in a yellow triangle), - YesNo (returns a tickbox or a crossbox depending on a testvalue), - FloppyDisk, - ArrowOne, and - ArrowTwo - CrossHair """ from reportlab.lib import colors from reportlab.lib.validators import * from reportlab.lib.attrmap import * from reportlab.lib.utils import isStr, asUnicode from reportlab.graphics import shapes from reportlab.graphics.widgetbase import Widget from reportlab.graphics import renderPDF class _Symbol(Widget): """Abstract base widget possible attributes: 'x', 'y', 'size', 'fillColor', 'strokeColor' """ _nodoc = 1 _attrMap = AttrMap( x = AttrMapValue(isNumber,desc='symbol x coordinate'), y = AttrMapValue(isNumber,desc='symbol y coordinate'), dx = AttrMapValue(isNumber,desc='symbol x coordinate adjustment'), dy = AttrMapValue(isNumber,desc='symbol x coordinate adjustment'), size = AttrMapValue(isNumber), fillColor = AttrMapValue(isColorOrNone), strokeColor = AttrMapValue(isColorOrNone), strokeWidth = AttrMapValue(isNumber), ) def __init__(self): assert self.__class__.__name__!='_Symbol', 'Abstract class _Symbol instantiated' self.x = self.y = self.dx = self.dy = 0 self.size = 100 self.fillColor = colors.red self.strokeColor = None self.strokeWidth = 0.1 def demo(self): D = shapes.Drawing(200, 100) s = float(self.size) ob = self.__class__() ob.x=50 ob.y=0 ob.draw() D.add(ob) D.add(shapes.String(ob.x+(s/2),(ob.y-12), ob.__class__.__name__, fillColor=colors.black, textAnchor='middle', fontSize=10)) return D class ETriangle(_Symbol): """This draws an equilateral triangle.""" def __init__(self): _Symbol.__init__(self) def draw(self): # general widget bits s = float(self.size) # abbreviate as we will use this a lot g = shapes.Group() # Triangle specific bits ae = s*0.125 #(ae = 'an eighth') triangle = shapes.Polygon(points = [ self.x, self.y, self.x+s, self.y, self.x+(s/2),self.y+s], fillColor = self.fillColor, strokeColor = self.strokeColor, strokeWidth=s/50.) g.add(triangle) return g class RTriangle(_Symbol): """This draws a right-angled triangle. possible attributes: 'x', 'y', 'size', 'fillColor', 'strokeColor' """ def __init__(self): self.x = 0 self.y = 0 self.size = 100 self.fillColor = colors.green self.strokeColor = None def draw(self): # general widget bits s = float(self.size) # abbreviate as we will use this a lot g = shapes.Group() # Triangle specific bits ae = s*0.125 #(ae = 'an eighth') triangle = shapes.Polygon(points = [ self.x, self.y, self.x+s, self.y, self.x,self.y+s], fillColor = self.fillColor, strokeColor = self.strokeColor, strokeWidth=s/50.) g.add(triangle) return g class Octagon(_Symbol): """This widget draws an Octagon. possible attributes: 'x', 'y', 'size', 'fillColor', 'strokeColor' """ def __init__(self): self.x = 0 self.y = 0 self.size = 100 self.fillColor = colors.yellow self.strokeColor = None def draw(self): # general widget bits s = float(self.size) # abbreviate as we will use this a lot g = shapes.Group() # Octagon specific bits athird=s/3 octagon = shapes.Polygon(points=[self.x+athird, self.y, self.x, self.y+athird, self.x, self.y+(athird*2), self.x+athird, self.y+s, self.x+(athird*2), self.y+s, self.x+s, self.y+(athird*2), self.x+s, self.y+athird, self.x+(athird*2), self.y], strokeColor = self.strokeColor, fillColor = self.fillColor, strokeWidth=10) g.add(octagon) return g class Crossbox(_Symbol): """This draws a black box with a red cross in it - a 'checkbox'. possible attributes: 'x', 'y', 'size', 'crossColor', 'strokeColor', 'crosswidth' """ _attrMap = AttrMap(BASE=_Symbol, crossColor = AttrMapValue(isColorOrNone), crosswidth = AttrMapValue(isNumber), ) def __init__(self): self.x = 0 self.y = 0 self.size = 100 self.fillColor = colors.white self.crossColor = colors.red self.strokeColor = colors.black self.crosswidth = 10 def draw(self): # general widget bits s = float(self.size) # abbreviate as we will use this a lot g = shapes.Group() # crossbox specific bits box = shapes.Rect(self.x+1, self.y+1, s-2, s-2, fillColor = self.fillColor, strokeColor = self.strokeColor, strokeWidth=2) g.add(box) crossLine1 = shapes.Line(self.x+(s*0.15), self.y+(s*0.15), self.x+(s*0.85), self.y+(s*0.85), fillColor = self.crossColor, strokeColor = self.crossColor, strokeWidth = self.crosswidth) g.add(crossLine1) crossLine2 = shapes.Line(self.x+(s*0.15), self.y+(s*0.85), self.x+(s*0.85) ,self.y+(s*0.15), fillColor = self.crossColor, strokeColor = self.crossColor, strokeWidth = self.crosswidth) g.add(crossLine2) return g class Tickbox(_Symbol): """This draws a black box with a red tick in it - another 'checkbox'. possible attributes: 'x', 'y', 'size', 'tickColor', 'strokeColor', 'tickwidth' """ _attrMap = AttrMap(BASE=_Symbol, tickColor = AttrMapValue(isColorOrNone), tickwidth = AttrMapValue(isNumber), ) def __init__(self): self.x = 0 self.y = 0 self.size = 100 self.tickColor = colors.red self.strokeColor = colors.black self.fillColor = colors.white self.tickwidth = 10 def draw(self): # general widget bits s = float(self.size) # abbreviate as we will use this a lot g = shapes.Group() # tickbox specific bits box = shapes.Rect(self.x+1, self.y+1, s-2, s-2, fillColor = self.fillColor, strokeColor = self.strokeColor, strokeWidth=2) g.add(box) tickLine = shapes.PolyLine(points = [self.x+(s*0.15), self.y+(s*0.35), self.x+(s*0.35), self.y+(s*0.15), self.x+(s*0.35), self.y+(s*0.15), self.x+(s*0.85) ,self.y+(s*0.85)], fillColor = self.tickColor, strokeColor = self.tickColor, strokeWidth = self.tickwidth) g.add(tickLine) return g class SmileyFace(_Symbol): """This draws a classic smiley face. possible attributes: 'x', 'y', 'size', 'fillColor' """ def __init__(self): _Symbol.__init__(self) self.x = 0 self.y = 0 self.size = 100 self.fillColor = colors.yellow self.strokeColor = colors.black def draw(self): # general widget bits s = float(self.size) # abbreviate as we will use this a lot g = shapes.Group() # SmileyFace specific bits g.add(shapes.Circle(cx=self.x+(s/2), cy=self.y+(s/2), r=s/2, fillColor=self.fillColor, strokeColor=self.strokeColor, strokeWidth=max(s/38.,self.strokeWidth))) for i in (1,2): g.add(shapes.Ellipse(self.x+(s/3)*i,self.y+(s/3)*2, s/30, s/10, fillColor=self.strokeColor, strokeColor = self.strokeColor, strokeWidth=max(s/38.,self.strokeWidth))) # calculate a pointslist for the mouth # THIS IS A HACK! - don't use if there is a 'shapes.Arc' centerx=self.x+(s/2) centery=self.y+(s/2) radius=s/3 yradius = radius xradius = radius startangledegrees=200 endangledegrees=340 degreedelta = 1 pointslist = [] a = pointslist.append from math import sin, cos, pi degreestoradians = pi/180.0 radiansdelta = degreedelta*degreestoradians startangle = startangledegrees*degreestoradians endangle = endangledegrees*degreestoradians while endangle= searchto: break # EXIT LOOP match = m.group(0) end = start + len(match) c = match[0] if c not in "#'\"": # Must have matched a keyword. if start != searchfrom: # there's still a redundant char before and after it, strip! match = match[1:-1] start = start + 1 else: # this is the first keyword in the text. # Only a space at the end. match = match[:-1] end = end - 1 tags_append((keywordTag, start, end, None)) # If this was a defining keyword, look ahead to the # following identifier. if match in ["def", "class"]: m = idSearch(pytext, end) if m is not None: start = m.start() if start == end: match = m.group(0) end = start + len(match) tags_append((identifierTag, start, end, None)) elif c == "#": tags_append((commentTag, start, end, None)) else: tags_append((stringTag, start, end, None)) return tags def test(path): f = open(path) text = f.read() f.close() tags = fontify(text) for tag, start, end, sublist in tags: print(tag, repr(text[start:end])) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1691062243.0 reportlab-4.1.0/src/reportlab/lib/__init__.py0000664000175000017500000000040014462707743020552 0ustar00rptlabrptlab#!/bin/env python #Copyright ReportLab Europe Ltd. 2000-2017 #see license.txt for license details #history https://hg.reportlab.com/hg-public/reportlab/log/tip/src/reportlab/lib/__init__.py __version__='3.3.0' import os RL_DEBUG = 'RL_DEBUG' in os.environ ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1691062243.0 reportlab-4.1.0/src/reportlab/lib/abag.py0000664000175000017500000000214214462707743017712 0ustar00rptlabrptlab#Copyright ReportLab Europe Ltd. 2000-2017 #see license.txt for license details #history https://hg.reportlab.com/hg-public/reportlab/log/tip/src/reportlab/lib/abag.py __version__='3.3.0' __doc__='''Data structure to hold a collection of attributes, used by styles.''' class ABag: """ 'Attribute Bag' - a trivial BAG class for holding attributes. This predates modern Python. Doing this again, we'd use a subclass of dict. You may initialize with keyword arguments. a = ABag(k0=v0,....,kx=vx,....) ==> getattr(a,'kx')==vx c = a.clone(ak0=av0,.....) copy with optional additional attributes. """ def __init__(self,**attr): self.__dict__.update(attr) def clone(self,**attr): n = self.__class__(**self.__dict__) if attr: n.__dict__.update(attr) return n def __repr__(self): D = self.__dict__ K = list(D.keys()) K.sort() return '%s(%s)' % (self.__class__.__name__,', '.join(['%s=%r' % (k,D[k]) for k in K])) if __name__=="__main__": AB = ABag(a=1, c="hello") CD = AB.clone() print(AB) print(CD) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1691062243.0 reportlab-4.1.0/src/reportlab/lib/arciv.py0000664000175000017500000001615014462707743020130 0ustar00rptlabrptlab#copyright ReportLab Europe Limited. 2000-2016 #see license.txt for license details ''' Arciv Stream ciphering ''' __all__='''ArcIV encode decode'''.split() __version__="1.0" from reportlab.lib.utils import isUnicode class ArcIV: ''' performs 'ArcIV' Stream Encryption of S using key Based on what is widely thought to be RSA's ArcIV algorithm. It produces output streams that are identical. NB there is no separate decoder arciv(arciv(s,key),key) == s ''' def __init__(self,key): self._key = key self.reset() def reset(self): '''restore the cipher to it's start state''' #Initialize private key, k With the values of the key mod 256. #and sbox With numbers 0 - 255. Then compute sbox key = self._key if isUnicode(key): key = key.encode('utf8') sbox = list(range(256)) k = list(range(256)) lk = len(key) for i in sbox: k[i] = key[i % lk] % 256 #Re-order sbox using the private key, k. #Iterating each element of sbox re-calculate the counter j #Then interchange the elements sbox[a] & sbox[b] j = 0 for i in range(256): j = (j+sbox[i]+k[i]) % 256 sbox[i], sbox[j] = sbox[j], sbox[i] self._sbox, self._i, self._j = sbox, 0, 0 def _encode(self, B): ''' return the list of encoded bytes of B, B might be a string or a list of integers between 0 <= i <= 255 ''' sbox, i, j = self._sbox, self._i, self._j C = list(B.encode('utf8')) if isinstance(B,str) else (list(B) if isinstance(B,bytes) else B[:]) n = len(C) p = 0 while p -1: # it is an EUC family encoding. for col in range(1, 95): ch = int2Byte(row + 160) + int2Byte(col+160) cells.append(ch) ## elif self.encodingName.find('GB') > -1: ## # it is an EUC family encoding. ## for col in range(1, 95): ## ch = int2Byte(row + 160) + int2Byte(col+160) else: cells.append([None] * 94) return cells def draw(self): self.drawLabels(topLeft= 'R%d' % self.row) # work out which characters we need for the row #assert self.encodingName.find('EUC') > -1, 'Only handles EUC encoding today, you gave me %s!' % self.encodingName # pad out by 1 to match Ken Lunde's tables charList = [None] + self.makeRow(self.row) self.drawChars(charList) self.canv.grid(self.xlist, self.ylist) class Big5CodeChart(CodeChartBase): """Formats one 'row' of the 94x160 space used in Big 5 These deliberately resemble the code charts in Ken Lunde's "Understanding CJKV Information Processing", to enable manual checking.""" def __init__(self, row, faceName, encodingName): self.row = row self.codePoints = 160 self.boxSize = 18 self.charsPerRow = 16 self.rows = 10 self.hex = 1 self.faceName = faceName self.encodingName = encodingName self.rowLabels = ['4','5','6','7','A','B','C','D','E','F'] try: # the dependent files might not be available font = cidfonts.CIDFont(self.faceName, self.encodingName) pdfmetrics.registerFont(font) except: # fall back to English and at least show we can draw the boxes self.faceName = 'Helvetica' self.encodingName = 'WinAnsiEncoding' self.fontName = self.faceName + '-' + self.encodingName self.calcLayout() def makeRow(self, row): """Works out the character values for this Big5 row. Rows start at 0xA1""" cells = [] if self.encodingName.find('B5') > -1: # big 5, different row size for y in [4,5,6,7,10,11,12,13,14,15]: for x in range(16): col = y*16+x ch = int2Byte(row) + int2Byte(col) cells.append(ch) else: cells.append([None] * 160) return cells def draw(self): self.drawLabels(topLeft='%02X' % self.row) charList = self.makeRow(self.row) self.drawChars(charList) self.canv.grid(self.xlist, self.ylist) def hBoxText(msg, canvas, x, y, fontName): """Helper for stringwidth tests on Asian fonts. Registers font if needed. Then draws the string, and a box around it derived from the stringWidth function""" canvas.saveState() try: font = pdfmetrics.getFont(fontName) except KeyError: font = cidfonts.UnicodeCIDFont(fontName) pdfmetrics.registerFont(font) canvas.setFillGray(0.8) canvas.rect(x,y,pdfmetrics.stringWidth(msg, fontName, 16),16,stroke=0,fill=1) canvas.setFillGray(0) canvas.setFont(fontName, 16,16) canvas.drawString(x,y,msg) canvas.restoreState() class CodeWidget(Widget): """Block showing all the characters""" def __init__(self): self.x = 0 self.y = 0 self.width = 160 self.height = 160 def draw(self): dx = self.width / 16.0 dy = self.height / 16.0 g = Group() g.add(Rect(self.x, self.y, self.width, self.height, fillColor=None, strokeColor=colors.black)) for x in range(16): for y in range(16): charValue = y * 16 + x if charValue > 32: s = String(self.x + x * dx, self.y + (self.height - y*dy), int2Byte(charValue)) g.add(s) return g def test(): c = Canvas('codecharts.pdf') c.setFont('Helvetica-Bold', 24) c.drawString(72, 750, 'Testing code page charts') cc1 = SingleByteEncodingChart() cc1.drawOn(c, 72, 500) cc2 = SingleByteEncodingChart(charsPerRow=32) cc2.drawOn(c, 72, 300) cc3 = SingleByteEncodingChart(charsPerRow=25, hex=0) cc3.drawOn(c, 72, 100) ## c.showPage() ## ## c.setFont('Helvetica-Bold', 24) ## c.drawString(72, 750, 'Multi-byte Kuten code chart examples') ## KutenRowCodeChart(1, 'HeiseiMin-W3','EUC-H').drawOn(c, 72, 600) ## KutenRowCodeChart(16, 'HeiseiMin-W3','EUC-H').drawOn(c, 72, 450) ## KutenRowCodeChart(84, 'HeiseiMin-W3','EUC-H').drawOn(c, 72, 300) ## ## c.showPage() ## c.setFont('Helvetica-Bold', 24) ## c.drawString(72, 750, 'Big5 Code Chart Examples') ## #Big5CodeChart(0xA1, 'MSungStd-Light-Acro','ETenms-B5-H').drawOn(c, 72, 500) c.save() print('saved codecharts.pdf') if __name__=='__main__': test() ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1691062243.0 reportlab-4.1.0/src/reportlab/lib/colors.py0000664000175000017500000011424214462707743020326 0ustar00rptlabrptlab#Copyright ReportLab Europe Ltd. 2000-2017 #see license.txt for license details #history https://hg.reportlab.com/hg-public/reportlab/log/tip/src/reportlab/lib/colors.py __version__='3.3.0' __doc__='''Defines standard colour-handling classes and colour names. We define standard classes to hold colours in two models: RGB and CMYK. rhese can be constructed from several popular formats. We also include - pre-built colour objects for the HTML standard colours - pre-built colours used in ReportLab's branding - various conversion and construction functions These tests are here because doctest cannot find them otherwise. >>> toColor('rgb(128,0,0)')==toColor('rgb(50%,0%,0%)') True >>> toColor('rgb(50%,0%,0%)')!=Color(0.5,0,0,1) True >>> toColor('hsl(0,100%,50%)')==toColor('rgb(255,0,0)') True >>> toColor('hsl(-120,100%,50%)')==toColor('rgb(0,0,255)') True >>> toColor('hsl(120,100%,50%)')==toColor('rgb(0,255,0)') True >>> toColor('rgba( 255,0,0,0.5)')==Color(1,0,0,0.5) True >>> toColor('cmyk(1,0,0,0 )')==CMYKColor(1,0,0,0) True >>> toColor('pcmyk( 100 , 0 , 0 , 0 )')==PCMYKColor(100,0,0,0) True >>> toColor('cmyka(1,0,0,0,0.5)')==CMYKColor(1,0,0,0,alpha=0.5) True >>> toColor('pcmyka(100,0,0,0,0.5)')==PCMYKColor(100,0,0,0,alpha=0.5) True >>> toColor('pcmyka(100,0,0,0)') Traceback (most recent call last): .... ValueError: css color 'pcmyka(100,0,0,0)' has wrong number of components ''' import math, re, functools from reportlab.lib.rl_accel import fp_str from reportlab.lib.utils import asNative, isStr, rl_safe_eval, rl_extended_literal_eval from reportlab import rl_config from ast import literal_eval class Color: """This class is used to represent color. Components red, green, blue are in the range 0 (dark) to 1 (full intensity).""" def __init__(self, red=0, green=0, blue=0, alpha=1): "Initialize with red, green, blue in range [0-1]." self.red = red self.green = green self.blue = blue self.alpha = alpha def __repr__(self): return "Color(%s)" % fp_str(*(self.red, self.green, self.blue,self.alpha)).replace(' ',',') @property def __key__(self): '''simple comparison by component; cmyk != color ever >>> from reportlab import cmp >>> cmp(Color(0,0,0),None) -1 >>> cmp(Color(0,0,0),black) 0 >>> cmp(Color(0,0,0),CMYKColor(0,0,0,1)),Color(0,0,0).rgba()==CMYKColor(0,0,0,1).rgba() (1, True) ''' return self.red, self.green, self.blue, self.alpha def __hash__(self): return hash(self.__key__) def __comparable__(self,other): return not isinstance(other,CMYKColor) and isinstance(other,Color) def __lt__(self,other): if not self.__comparable__(other): return True try: return self.__key__ < other.__key__ except: pass return True def __eq__(self,other): if not self.__comparable__(other): return False try: return self.__key__ == other.__key__ except: return False def rgb(self): "Returns a three-tuple of components" return (self.red, self.green, self.blue) def rgba(self): "Returns a four-tuple of components" return (self.red, self.green, self.blue, self.alpha) def bitmap_rgb(self): return tuple([int(x*255)&255 for x in self.rgb()]) def bitmap_rgba(self): return tuple([int(x*255)&255 for x in self.rgba()]) def hexval(self): return '0x%02x%02x%02x' % self.bitmap_rgb() def hexvala(self): return '0x%02x%02x%02x%02x' % self.bitmap_rgba() def int_rgb(self): v = self.bitmap_rgb() return v[0]<<16|v[1]<<8|v[2] def int_rgba(self): v = self.bitmap_rgba() return int((v[0]<<24|v[1]<<16|v[2]<<8|v[3])&0xffffff) _cKwds='red green blue alpha'.split() def cKwds(self): for k in self._cKwds: yield k,getattr(self,k) cKwds=property(cKwds) def clone(self,**kwds): '''copy then change values in kwds''' D = dict([kv for kv in self.cKwds]) D.update(kwds) return self.__class__(**D) def _lookupName(self,D={}): if not D: for n,v in getAllNamedColors().items(): if not isinstance(v,CMYKColor): t = v.red,v.green,v.blue if t in D: n = n+'/'+D[t] D[t] = n t = self.red,self.green,self.blue return t in D and D[t] or None @property def normalizedAlpha(self): return self.alpha Color = functools.total_ordering(Color) def opaqueColor(c): '''utility to check we have a color that's not fully transparent''' return isinstance(c,Color) and c.alpha>0 class CMYKColor(Color): """This represents colors using the CMYK (cyan, magenta, yellow, black) model commonly used in professional printing. This is implemented as a derived class so that renderers which only know about RGB "see it" as an RGB color through its 'red','green' and 'blue' attributes, according to an approximate function. The RGB approximation is worked out when the object in constructed, so the color attributes should not be changed afterwards. Extra attributes may be attached to the class to support specific ink models, and renderers may look for these.""" _scale = 1.0 def __init__(self, cyan=0, magenta=0, yellow=0, black=0, spotName=None, density=1, knockout=None, alpha=1): """ Initialize with four colors in range [0-1]. the optional spotName, density & knockout may be of use to specific renderers. spotName is intended for use as an identifier to the renderer not client programs. density is used to modify the overall amount of ink. knockout is a renderer dependent option that determines whether the applied colour knocksout (removes) existing colour; None means use the global default. """ self.cyan = cyan self.magenta = magenta self.yellow = yellow self.black = black self.spotName = spotName self.density = max(min(density,1),0) # force into right range self.knockout = knockout self.alpha = alpha # now work out the RGB approximation. override self.red, self.green, self.blue = cmyk2rgb( (cyan, magenta, yellow, black) ) if density<1: #density adjustment of rgb approximants, effectively mix with white r, g, b = self.red, self.green, self.blue r = density*(r-1)+1 g = density*(g-1)+1 b = density*(b-1)+1 self.red, self.green, self.blue = (r,g,b) def __repr__(self): return "%s(%s%s%s%s%s)" % (self.__class__.__name__, fp_str(self.cyan, self.magenta, self.yellow, self.black).replace(' ',','), (self.spotName and (',spotName='+repr(self.spotName)) or ''), (self.density!=1 and (',density='+fp_str(self.density)) or ''), (self.knockout is not None and (',knockout=%d' % self.knockout) or ''), (self.alpha is not None and (',alpha=%s' % self.alpha) or ''), ) def fader(self, n, reverse=False): '''return n colors based on density fade *NB* note this dosen't reach density zero''' scale = self._scale dd = scale/float(n) L = [self.clone(density=scale - i*dd) for i in range(n)] if reverse: L.reverse() return L @property def __key__(self): """obvious way to compare colours Comparing across the two color models is of limited use. >>> cmp(CMYKColor(0,0,0,1),None) -1 >>> cmp(CMYKColor(0,0,0,1),_CMYK_black) 0 >>> cmp(PCMYKColor(0,0,0,100),_CMYK_black) 0 >>> cmp(CMYKColor(0,0,0,1),Color(0,0,1)),Color(0,0,0).rgba()==CMYKColor(0,0,0,1).rgba() (-1, True) """ return self.cyan, self.magenta, self.yellow, self.black, self.density, self.spotName, self.alpha def __comparable__(self,other): return isinstance(other,CMYKColor) def cmyk(self): "Returns a tuple of four color components - syntactic sugar" return (self.cyan, self.magenta, self.yellow, self.black) def cmyka(self): "Returns a tuple of five color components - syntactic sugar" return (self.cyan, self.magenta, self.yellow, self.black, self.alpha) def _density_str(self): return fp_str(self.density) _cKwds='cyan magenta yellow black density alpha spotName knockout'.split() def _lookupName(self,D={}): if not D: for n,v in getAllNamedColors().items(): if isinstance(v,CMYKColor): t = v.cyan,v.magenta,v.yellow,v.black if t in D: n = n+'/'+D[t] D[t] = n t = self.cyan,self.magenta,self.yellow,self.black return t in D and D[t] or None @property def normalizedAlpha(self): return self.alpha*self._scale class PCMYKColor(CMYKColor): '''100 based CMYKColor with density and a spotName; just like Rimas uses''' _scale = 100. def __init__(self,cyan,magenta,yellow,black,density=100,spotName=None,knockout=None,alpha=100): CMYKColor.__init__(self,cyan/100.,magenta/100.,yellow/100.,black/100.,spotName,density/100.,knockout=knockout,alpha=alpha/100.) def __repr__(self): return "%s(%s%s%s%s%s)" % (self.__class__.__name__, fp_str(self.cyan*100, self.magenta*100, self.yellow*100, self.black*100).replace(' ',','), (self.spotName and (',spotName='+repr(self.spotName)) or ''), (self.density!=1 and (',density='+fp_str(self.density*100)) or ''), (self.knockout is not None and (',knockout=%d' % self.knockout) or ''), (self.alpha is not None and (',alpha=%s' % (fp_str(self.alpha*100))) or ''), ) def cKwds(self): K=self._cKwds S=K[:6] for k in self._cKwds: v=getattr(self,k) if k in S: v*=100 yield k,v cKwds=property(cKwds) class CMYKColorSep(CMYKColor): '''special case color for making separating pdfs''' _scale = 1. def __init__(self, cyan=0, magenta=0, yellow=0, black=0, spotName=None, density=1,alpha=1): CMYKColor.__init__(self,cyan,magenta,yellow,black,spotName,density,knockout=None,alpha=alpha) _cKwds='cyan magenta yellow black density alpha spotName'.split() class PCMYKColorSep(PCMYKColor,CMYKColorSep): '''special case color for making separating pdfs''' _scale = 100. def __init__(self, cyan=0, magenta=0, yellow=0, black=0, spotName=None, density=100, alpha=100): PCMYKColor.__init__(self,cyan,magenta,yellow,black,density,spotName,knockout=None,alpha=alpha) _cKwds='cyan magenta yellow black density alpha spotName'.split() def cmyk2rgb(cmyk,density=1): "Convert from a CMYK color tuple to an RGB color tuple" c,m,y,k = cmyk # From the Adobe Postscript Ref. Manual 2nd ed. r = 1.0 - min(1.0, c + k) g = 1.0 - min(1.0, m + k) b = 1.0 - min(1.0, y + k) return (r,g,b) def rgb2cmyk(r,g,b): '''one way to get cmyk from rgb''' c = 1 - r m = 1 - g y = 1 - b k = min(c,m,y) c = min(1,max(0,c-k)) m = min(1,max(0,m-k)) y = min(1,max(0,y-k)) k = min(1,max(0,k)) return (c,m,y,k) def color2bw(colorRGB): "Transform an RGB color to a black and white equivalent." col = colorRGB r, g, b, a = col.red, col.green, col.blue, col.alpha n = (r + g + b) / 3.0 bwColorRGB = Color(n, n, n, a) return bwColorRGB def HexColor(val, htmlOnly=False, hasAlpha=False): """This function converts a hex string, or an actual integer number, into the corresponding color. E.g., in "#AABBCC" or 0xAABBCC, AA is the red, BB is the green, and CC is the blue (00-FF). An alpha value can also be given in the form #AABBCCDD or 0xAABBCCDD where DD is the alpha value if hasAlpha is True. For completeness I assume that #aabbcc or 0xaabbcc are hex numbers otherwise a pure integer is converted as decimal rgb. If htmlOnly is true, only the #aabbcc form is allowed. >>> HexColor('#ffffff') Color(1,1,1,1) >>> HexColor('#FFFFFF') Color(1,1,1,1) >>> HexColor('0xffffff') Color(1,1,1,1) >>> HexColor('16777215') Color(1,1,1,1) An '0x' or '#' prefix is required for hex (as opposed to decimal): >>> HexColor('ffffff') Traceback (most recent call last): ValueError: invalid literal for int() with base 10: 'ffffff' >>> HexColor('#FFFFFF', htmlOnly=True) Color(1,1,1,1) >>> HexColor('0xffffff', htmlOnly=True) Traceback (most recent call last): ValueError: not a hex string >>> HexColor('16777215', htmlOnly=True) Traceback (most recent call last): ValueError: not a hex string """ #" for emacs if isStr(val): val = asNative(val) b = 10 if val[:1] == '#': val = val[1:] b = 16 if len(val) == 8: alpha = True else: if htmlOnly: raise ValueError('not a hex string') if val[:2].lower() == '0x': b = 16 val = val[2:] if len(val) == 8: alpha = True val = int(val,b) if hasAlpha: return Color(((val>>24)&0xFF)/255.0,((val>>16)&0xFF)/255.0,((val>>8)&0xFF)/255.0,(val&0xFF)/255.0) return Color(((val>>16)&0xFF)/255.0,((val>>8)&0xFF)/255.0,(val&0xFF)/255.0) def linearlyInterpolatedColor(c0, c1, x0, x1, x): """ Linearly interpolates colors. Can handle RGB, CMYK and PCMYK colors - give ValueError if colours aren't the same. Doesn't currently handle 'Spot Color Interpolation'. """ if c0.__class__ != c1.__class__: raise ValueError("Color classes must be the same for interpolation!\nGot %r and %r'"%(c0,c1)) if x1x0 if xx1+1e-8: # fudge factor for numerical problems raise ValueError("Can't interpolate: x=%f is not between %f and %f!" % (x,x0,x1)) if x<=x0: return c0 elif x>=x1: return c1 cname = c0.__class__.__name__ dx = float(x1-x0) x = x-x0 if cname == 'Color': # RGB r = c0.red+x*(c1.red - c0.red)/dx g = c0.green+x*(c1.green- c0.green)/dx b = c0.blue+x*(c1.blue - c0.blue)/dx a = c0.alpha+x*(c1.alpha - c0.alpha)/dx return Color(r,g,b,alpha=a) elif cname == 'CMYKColor': if cmykDistance(c0,c1)<1e-8: #colors same do density and preserve spotName if any assert c0.spotName == c1.spotName, "Identical cmyk, but different spotName" c = c0.cyan m = c0.magenta y = c0.yellow k = c0.black d = c0.density+x*(c1.density - c0.density)/dx a = c0.alpha+x*(c1.alpha - c0.alpha)/dx return CMYKColor(c,m,y,k, density=d, spotName=c0.spotName, alpha=a) elif cmykDistance(c0,_CMYK_white)<1e-8: #special c0 is white c = c1.cyan m = c1.magenta y = c1.yellow k = c1.black d = x*c1.density/dx a = x*c1.alpha/dx return CMYKColor(c,m,y,k, density=d, spotName=c1.spotName, alpha=a) elif cmykDistance(c1,_CMYK_white)<1e-8: #special c1 is white c = c0.cyan m = c0.magenta y = c0.yellow k = c0.black d = x*c0.density/dx d = c0.density*(1-x/dx) a = c0.alpha*(1-x/dx) return PCMYKColor(c,m,y,k, density=d, spotName=c0.spotName, alpha=a) else: c = c0.cyan+x*(c1.cyan - c0.cyan)/dx m = c0.magenta+x*(c1.magenta - c0.magenta)/dx y = c0.yellow+x*(c1.yellow - c0.yellow)/dx k = c0.black+x*(c1.black - c0.black)/dx d = c0.density+x*(c1.density - c0.density)/dx a = c0.alpha+x*(c1.alpha - c0.alpha)/dx return CMYKColor(c,m,y,k, density=d, alpha=a) elif cname == 'PCMYKColor': if cmykDistance(c0,c1)<1e-8: #colors same do density and preserve spotName if any assert c0.spotName == c1.spotName, "Identical cmyk, but different spotName" c = c0.cyan m = c0.magenta y = c0.yellow k = c0.black d = c0.density+x*(c1.density - c0.density)/dx a = c0.alpha+x*(c1.alpha - c0.alpha)/dx return PCMYKColor(c*100,m*100,y*100,k*100, density=d*100, spotName=c0.spotName, alpha=100*a) elif cmykDistance(c0,_CMYK_white)<1e-8: #special c0 is white c = c1.cyan m = c1.magenta y = c1.yellow k = c1.black d = x*c1.density/dx a = x*c1.alpha/dx return PCMYKColor(c*100,m*100,y*100,k*100, density=d*100, spotName=c1.spotName, alpha=a*100) elif cmykDistance(c1,_CMYK_white)<1e-8: #special c1 is white c = c0.cyan m = c0.magenta y = c0.yellow k = c0.black d = x*c0.density/dx d = c0.density*(1-x/dx) a = c0.alpha*(1-x/dx) return PCMYKColor(c*100,m*100,y*100,k*100, density=d*100, spotName=c0.spotName, alpha=a*100) else: c = c0.cyan+x*(c1.cyan - c0.cyan)/dx m = c0.magenta+x*(c1.magenta - c0.magenta)/dx y = c0.yellow+x*(c1.yellow - c0.yellow)/dx k = c0.black+x*(c1.black - c0.black)/dx d = c0.density+x*(c1.density - c0.density)/dx a = c0.alpha+x*(c1.alpha - c0.alpha)/dx return PCMYKColor(c*100,m*100,y*100,k*100, density=d*100, alpha=a*100) else: raise ValueError("Can't interpolate: Unknown color class %s!" % cname) def obj_R_G_B(c): '''attempt to convert an object to (red,green,blue)''' if isinstance(c,Color): return c.red,c.green,c.blue elif isinstance(c,(tuple,list)): if len(c)==3: return tuple(c) elif len(c)==4: return toColor(c).rgb() else: raise ValueError('obj_R_G_B(%r) bad argument' % (c)) # special case -- indicates no drawing should be done # this is a hangover from PIDDLE - suggest we ditch it since it is not used anywhere transparent = Color(0,0,0,alpha=0) _CMYK_white=CMYKColor(0,0,0,0) _PCMYK_white=PCMYKColor(0,0,0,0) _CMYK_black=CMYKColor(0,0,0,1) _PCMYK_black=PCMYKColor(0,0,0,100) # Special colors ReportLabBlueOLD = HexColor(0x4e5688) ReportLabBlue = HexColor(0x00337f) ReportLabBluePCMYK = PCMYKColor(100,65,0,30,spotName='Pantone 288U') ReportLabLightBlue = HexColor(0xb7b9d3) ReportLabFidBlue=HexColor(0x3366cc) ReportLabFidRed=HexColor(0xcc0033) ReportLabGreen = HexColor(0x336600) ReportLabLightGreen = HexColor(0x339933) # color constants -- mostly from HTML standard aliceblue = HexColor(0xF0F8FF) antiquewhite = HexColor(0xFAEBD7) aqua = HexColor(0x00FFFF) aquamarine = HexColor(0x7FFFD4) azure = HexColor(0xF0FFFF) beige = HexColor(0xF5F5DC) bisque = HexColor(0xFFE4C4) black = HexColor(0x000000) blanchedalmond = HexColor(0xFFEBCD) blue = HexColor(0x0000FF) blueviolet = HexColor(0x8A2BE2) brown = HexColor(0xA52A2A) burlywood = HexColor(0xDEB887) cadetblue = HexColor(0x5F9EA0) chartreuse = HexColor(0x7FFF00) chocolate = HexColor(0xD2691E) coral = HexColor(0xFF7F50) cornflowerblue = cornflower = HexColor(0x6495ED) cornsilk = HexColor(0xFFF8DC) crimson = HexColor(0xDC143C) cyan = HexColor(0x00FFFF) darkblue = HexColor(0x00008B) darkcyan = HexColor(0x008B8B) darkgoldenrod = HexColor(0xB8860B) darkgray = HexColor(0xA9A9A9) darkgrey = darkgray darkgreen = HexColor(0x006400) darkkhaki = HexColor(0xBDB76B) darkmagenta = HexColor(0x8B008B) darkolivegreen = HexColor(0x556B2F) darkorange = HexColor(0xFF8C00) darkorchid = HexColor(0x9932CC) darkred = HexColor(0x8B0000) darksalmon = HexColor(0xE9967A) darkseagreen = HexColor(0x8FBC8B) darkslateblue = HexColor(0x483D8B) darkslategray = HexColor(0x2F4F4F) darkslategrey = darkslategray darkturquoise = HexColor(0x00CED1) darkviolet = HexColor(0x9400D3) deeppink = HexColor(0xFF1493) deepskyblue = HexColor(0x00BFFF) dimgray = HexColor(0x696969) dimgrey = dimgray dodgerblue = HexColor(0x1E90FF) firebrick = HexColor(0xB22222) floralwhite = HexColor(0xFFFAF0) forestgreen = HexColor(0x228B22) fuchsia = HexColor(0xFF00FF) gainsboro = HexColor(0xDCDCDC) ghostwhite = HexColor(0xF8F8FF) gold = HexColor(0xFFD700) goldenrod = HexColor(0xDAA520) gray = HexColor(0x808080) grey = gray green = HexColor(0x008000) greenyellow = HexColor(0xADFF2F) honeydew = HexColor(0xF0FFF0) hotpink = HexColor(0xFF69B4) indianred = HexColor(0xCD5C5C) indigo = HexColor(0x4B0082) ivory = HexColor(0xFFFFF0) khaki = HexColor(0xF0E68C) lavender = HexColor(0xE6E6FA) lavenderblush = HexColor(0xFFF0F5) lawngreen = HexColor(0x7CFC00) lemonchiffon = HexColor(0xFFFACD) lightblue = HexColor(0xADD8E6) lightcoral = HexColor(0xF08080) lightcyan = HexColor(0xE0FFFF) lightgoldenrodyellow = HexColor(0xFAFAD2) lightgreen = HexColor(0x90EE90) lightgrey = HexColor(0xD3D3D3) lightpink = HexColor(0xFFB6C1) lightsalmon = HexColor(0xFFA07A) lightseagreen = HexColor(0x20B2AA) lightskyblue = HexColor(0x87CEFA) lightslategray = HexColor(0x778899) lightslategrey = lightslategray lightsteelblue = HexColor(0xB0C4DE) lightyellow = HexColor(0xFFFFE0) lime = HexColor(0x00FF00) limegreen = HexColor(0x32CD32) linen = HexColor(0xFAF0E6) magenta = HexColor(0xFF00FF) maroon = HexColor(0x800000) mediumaquamarine = HexColor(0x66CDAA) mediumblue = HexColor(0x0000CD) mediumorchid = HexColor(0xBA55D3) mediumpurple = HexColor(0x9370DB) mediumseagreen = HexColor(0x3CB371) mediumslateblue = HexColor(0x7B68EE) mediumspringgreen = HexColor(0x00FA9A) mediumturquoise = HexColor(0x48D1CC) mediumvioletred = HexColor(0xC71585) midnightblue = HexColor(0x191970) mintcream = HexColor(0xF5FFFA) mistyrose = HexColor(0xFFE4E1) moccasin = HexColor(0xFFE4B5) navajowhite = HexColor(0xFFDEAD) navy = HexColor(0x000080) oldlace = HexColor(0xFDF5E6) olive = HexColor(0x808000) olivedrab = HexColor(0x6B8E23) orange = HexColor(0xFFA500) orangered = HexColor(0xFF4500) orchid = HexColor(0xDA70D6) palegoldenrod = HexColor(0xEEE8AA) palegreen = HexColor(0x98FB98) paleturquoise = HexColor(0xAFEEEE) palevioletred = HexColor(0xDB7093) papayawhip = HexColor(0xFFEFD5) peachpuff = HexColor(0xFFDAB9) peru = HexColor(0xCD853F) pink = HexColor(0xFFC0CB) plum = HexColor(0xDDA0DD) powderblue = HexColor(0xB0E0E6) purple = HexColor(0x800080) red = HexColor(0xFF0000) rosybrown = HexColor(0xBC8F8F) royalblue = HexColor(0x4169E1) saddlebrown = HexColor(0x8B4513) salmon = HexColor(0xFA8072) sandybrown = HexColor(0xF4A460) seagreen = HexColor(0x2E8B57) seashell = HexColor(0xFFF5EE) sienna = HexColor(0xA0522D) silver = HexColor(0xC0C0C0) skyblue = HexColor(0x87CEEB) slateblue = HexColor(0x6A5ACD) slategray = HexColor(0x708090) slategrey = slategray snow = HexColor(0xFFFAFA) springgreen = HexColor(0x00FF7F) steelblue = HexColor(0x4682B4) tan = HexColor(0xD2B48C) teal = HexColor(0x008080) thistle = HexColor(0xD8BFD8) tomato = HexColor(0xFF6347) turquoise = HexColor(0x40E0D0) violet = HexColor(0xEE82EE) wheat = HexColor(0xF5DEB3) white = HexColor(0xFFFFFF) whitesmoke = HexColor(0xF5F5F5) yellow = HexColor(0xFFFF00) yellowgreen = HexColor(0x9ACD32) fidblue=HexColor(0x3366cc) fidred=HexColor(0xcc0033) fidlightblue=HexColor("#d6e0f5") ColorType=type(black) ################################################################ # # Helper functions for dealing with colors. These tell you # which are predefined, so you can print color charts; # and can give the nearest match to an arbitrary color object # ################################################################# def colorDistance(col1, col2): """Returns a number between 0 and root(3) stating how similar two colours are - distance in r,g,b, space. Only used to find names for things.""" return math.sqrt( (col1.red - col2.red)**2 + (col1.green - col2.green)**2 + (col1.blue - col2.blue)**2 ) def cmykDistance(col1, col2): """Returns a number between 0 and root(4) stating how similar two colours are - distance in r,g,b, space. Only used to find names for things.""" return math.sqrt( (col1.cyan - col2.cyan)**2 + (col1.magenta - col2.magenta)**2 + (col1.yellow - col2.yellow)**2 + (col1.black - col2.black)**2 ) _namedColors = None def getAllNamedColors(): #returns a dictionary of all the named ones in the module # uses a singleton for efficiency global _namedColors if _namedColors is not None: return _namedColors from reportlab.lib import colors _namedColors = {} for name, value in colors.__dict__.items(): if isinstance(value, Color): _namedColors[name] = value return _namedColors def describe(aColor,mode=0): '''finds nearest colour match to aColor. mode=0 print a string desription mode=1 return a string description mode=2 return (distance, colorName) ''' namedColors = getAllNamedColors() closest = (10, None, None) #big number, name, color for name, color in namedColors.items(): distance = colorDistance(aColor, color) if distance < closest[0]: closest = (distance, name, color) if mode<=1: s = 'best match is %s, distance %0.4f' % (closest[1], closest[0]) if mode==0: print(s) else: return s elif mode==2: return (closest[1], closest[0]) else: raise ValueError("Illegal value for mode "+str(mode)) def hue2rgb(m1, m2, h): if h<0: h += 1 if h>1: h -= 1 if h*6<1: return m1+(m2-m1)*h*6 if h*2<1: return m2 if h*3<2: return m1+(m2-m1)*(4-6*h) return m1 def hsl2rgb(h, s, l): if l<=0.5: m2 = l*(s+1) else: m2 = l+s-l*s m1 = l*2-m2 return hue2rgb(m1, m2, h+1./3),hue2rgb(m1, m2, h),hue2rgb(m1, m2, h-1./3) import re _re_css = re.compile(r'^\s*(pcmyk|cmyk|rgb|hsl)(a|)\s*\(\s*([^)]*)\)\s*$') class cssParse: def pcVal(self,v): v = v.strip() try: c=float(v[:-1]) c=min(100,max(0,c))/100. except: raise ValueError('bad percentage argument value %r in css color %r' % (v,self.s)) return c def rgbPcVal(self,v): return int(self.pcVal(v)*255+0.5)/255. def rgbVal(self,v): v = v.strip() try: c=float(v) if 01 and PCMYKColor or CMYKColor)(C,M,Y,K,alpha=a) else: if hsl: R,G,B= hsl2rgb(self.hueVal(n[0]),self.pcVal(n[1]),self.pcVal(n[2])) else: R,G,B = list(map('%' in n[0] and self.rgbPcVal or self.rgbVal,n)) return Color(R,G,B,a) cssParse=cssParse() class toColor: """Accepot an expression returnng a Color subclass. This used to accept arbitrary Python expressions, which resulted in increasngly devilish CVEs and security holes from tie to time. In April 2023 we are creating explicit, "dumb" parsing code to replace this. Acceptable patterns are a Color instance passed in by the Python programmer a named list of colours ('pink' etc') list of 3 or 4 numbers all CSS colour expression """ _G = {} #globals we like (eventually) def __init__(self): self.extraColorsNS = {} #used for overriding/adding to existing color names #make case insensitive if that's your wish def setExtraColorsNameSpace(self,NS): self.extraColorsNS = NS def __call__(self,arg,default=None): '''try to map an arbitrary arg to a color instance ''' if isinstance(arg,Color): return arg if isinstance(arg,(tuple,list)): assert 3<=len(arg)<=4, 'Can only convert 3 and 4 sequences to color' assert 0<=min(arg) and max(arg)<=1 return len(arg)==3 and Color(arg[0],arg[1],arg[2]) or CMYKColor(arg[0],arg[1],arg[2],arg[3]) elif isStr(arg): arg = asNative(arg) C = cssParse(arg) if C: return C if arg in self.extraColorsNS: return self.extraColorsNS[arg] C = getAllNamedColors() s = arg.lower() if s in C: return C[s] # allow expressions like 'Blacker(red, 0.5)' # >>> re.compile(r"(Blacker|Whiter)\((\w+)\,\s?([0-9.]+)\)").match(msg).groups() # ('Blacker', 'red', '0.5') # >>> pat = re.compile(r"(Blacker|Whiter)\((\w+)\,\s?([0-9.]+)\)") m = pat.match(arg) if m: funcname, rootcolor, num = m.groups() if funcname == 'Blacker': return Blacker(rootcolor, float(num)) else: return Whiter(rootcolor, float(num)) try: import ast expr = ast.literal_eval(arg) #safe probably only a tuple or list of values return toColor(expr) except (SyntaxError, ValueError): pass if rl_config.toColorCanUse=='rl_safe_eval': #the most dangerous option G = C.copy() G.update(self.extraColorsNS) if not self._G: C = globals() self._G = {s:C[s] for s in '''Blacker CMYKColor CMYKColorSep Color ColorType HexColor PCMYKColor PCMYKColorSep Whiter _chooseEnforceColorSpace _enforceCMYK _enforceError _enforceRGB _enforceSEP _enforceSEP_BLACK _enforceSEP_CMYK _namedColors _re_css asNative cmyk2rgb cmykDistance color2bw colorDistance cssParse describe fade fp_str getAllNamedColors hsl2rgb hue2rgb isStr linearlyInterpolatedColor literal_eval obj_R_G_B opaqueColor rgb2cmyk setColors toColor toColorOrNone'''.split()} G.update(self._G) try: return toColor(rl_safe_eval(arg,g=G,l={})) except: pass elif rl_config.toColorCanUse=='rl_extended_literal_eval': C = globals() S = getAllNamedColors().copy() C = {k:C[k] for k in '''Blacker CMYKColor CMYKColorSep Color ColorType HexColor PCMYKColor PCMYKColorSep Whiter _chooseEnforceColorSpace _enforceCMYK _enforceError _enforceRGB _enforceSEP _enforceSEP_BLACK _enforceSEP_CMYK _namedColors _re_css asNative cmyk2rgb cmykDistance color2bw colorDistance cssParse describe fade fp_str getAllNamedColors hsl2rgb hue2rgb linearlyInterpolatedColor obj_R_G_B opaqueColor rgb2cmyk setColors toColor toColorOrNone'''.split() if callable(C.get(k,None))} try: return rl_extended_literal_eval(arg,C,S) except (ValueError, SyntaxError): pass try: return HexColor(arg) except: if default is None: raise ValueError('Invalid color value %r' % arg) return default toColor = toColor() def toColorOrNone(arg,default=None): '''as above but allows None as a legal value''' if arg is None: return None else: return toColor(arg, default) def setColors(**kw): UNDEF = [] progress = 1 assigned = {} while kw and progress: progress = 0 for k, v in kw.items(): if isinstance(v,(tuple,list)): c = list(map(lambda x,UNDEF=UNDEF: toColor(x,UNDEF),v)) if isinstance(v,tuple): c = tuple(c) ok = UNDEF not in c else: c = toColor(v,UNDEF) ok = c is not UNDEF if ok: assigned[k] = c del kw[k] progress = 1 if kw: raise ValueError("Can't convert\n%s" % str(kw)) getAllNamedColors() for k, c in assigned.items(): globals()[k] = c if isinstance(c,Color): _namedColors[k] = c def Whiter(c,f): '''given a color combine with white as c*f w*(1-f) 0<=f<=1''' c = toColor(c) if isinstance(c,CMYKColorSep): c = c.clone() if isinstance(c,PCMYKColorSep): c.__class__ = PCMYKColor else: c.__class__ = CMYKColor if isinstance(c,PCMYKColor): w = _PCMYK_white elif isinstance(c,CMYKColor): w = _CMYK_white else: w = white return linearlyInterpolatedColor(w, c, 0, 1, f) def Blacker(c,f): '''given a color combine with black as c*f+b*(1-f) 0<=f<=1''' c = toColor(c) if isinstance(c,CMYKColorSep): c = c.clone() if isinstance(c,PCMYKColorSep): c.__class__ = PCMYKColor else: c.__class__ = CMYKColor if isinstance(c,PCMYKColor): b = _PCMYK_black elif isinstance(c,CMYKColor): b = _CMYK_black else: b = black return linearlyInterpolatedColor(b, c, 0, 1, f) def fade(aSpotColor, percentages): """Waters down spot colors and returns a list of new ones e.g fade(myColor, [100,80,60,40,20]) returns a list of five colors """ out = [] for percent in percentages: frac = percent * 0.01 #assume they give us numbers from 0 to 100 newCyan = frac * aSpotColor.cyan newMagenta = frac * aSpotColor.magenta newYellow = frac * aSpotColor.yellow newBlack = frac * aSpotColor.black newDensity = frac * aSpotColor.density newSpot = CMYKColor( newCyan, newMagenta, newYellow, newBlack, spotName = aSpotColor.spotName, density = newDensity) out.append(newSpot) return out def _enforceError(kind,c,tc): if isinstance(tc,Color): xtra = tc._lookupName() xtra = xtra and '(%s)'%xtra or '' else: xtra = '' raise ValueError('Non %s color %r%s' % (kind,c,xtra)) def _enforceSEP(c): '''pure separating colors only, this makes black a problem''' tc = toColor(c) if not isinstance(tc,CMYKColorSep): _enforceError('separating',c,tc) return tc def _enforceSEP_BLACK(c): '''separating + blacks only''' tc = toColor(c) if not isinstance(tc,CMYKColorSep): if isinstance(tc,Color) and tc.red==tc.blue==tc.green: #ahahahah it's a grey tc = _CMYK_black.clone(density=1-tc.red) elif not (isinstance(tc,CMYKColor) and tc.cyan==tc.magenta==tc.yellow==0): #ie some shade of grey _enforceError('separating or black',c,tc) return tc def _enforceSEP_CMYK(c): '''separating or cmyk only''' tc = toColor(c) if not isinstance(tc,CMYKColorSep): if isinstance(tc,Color) and tc.red==tc.blue==tc.green: #ahahahah it's a grey tc = _CMYK_black.clone(density=1-tc.red) elif not isinstance(tc,CMYKColor): _enforceError('separating or CMYK',c,tc) return tc def _enforceCMYK(c): '''cmyk outputs only (rgb greys converted)''' tc = toColor(c) if not isinstance(tc,CMYKColor): if isinstance(tc,Color) and tc.red==tc.blue==tc.green: #ahahahah it's a grey tc = _CMYK_black.clone(black=1-tc.red,alpha=tc.alpha) else: _enforceError('CMYK',c,tc) elif isinstance(tc,CMYKColorSep): tc = tc.clone() tc.__class__ = CMYKColor return tc def _enforceRGB(c): tc = toColor(c) if isinstance(tc,CMYKColor): if tc.cyan==tc.magenta==tc.yellow==0: #ahahahah it's grey v = 1-tc.black*tc.density tc = Color(v,v,v,alpha=tc.alpha) else: _enforceError('RGB',c,tc) return tc def _chooseEnforceColorSpace(enforceColorSpace): if enforceColorSpace is not None and not callable(enforceColorSpace): if isinstance(enforceColorSpace,str): enforceColorSpace=enforceColorSpace.upper() if enforceColorSpace=='CMYK': enforceColorSpace = _enforceCMYK elif enforceColorSpace=='RGB': enforceColorSpace = _enforceRGB elif enforceColorSpace=='SEP': enforceColorSpace = _enforceSEP elif enforceColorSpace=='SEP_BLACK': enforceColorSpace = _enforceSEP_BLACK elif enforceColorSpace=='SEP_CMYK': enforceColorSpace = _enforceSEP_CMYK else: raise ValueError('Invalid value for Canvas argument enforceColorSpace=%r' % enforceColorSpace) return enforceColorSpace if __name__ == "__main__": import doctest doctest.testmod() ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1691062243.0 reportlab-4.1.0/src/reportlab/lib/corp.py0000664000175000017500000006500514462707743017772 0ustar00rptlabrptlab#!/bin/env python #Copyright ReportLab Europe Ltd. 2000-2017 #see license.txt for license details __version__='3.3.0' __doc__="""Generate ReportLab logo in a variety of sizes and formats. This module includes some reusable routines for ReportLab's 'Corporate Image' - the logo, standard page backdrops and so on - you are advised to do the same for your own company!""" from reportlab.lib.units import inch,cm from reportlab.lib.validators import * from reportlab.lib.attrmap import * from reportlab.lib.formatters import DecimalFormatter from reportlab.graphics.shapes import definePath, Group, Drawing, Rect, PolyLine, String from reportlab.graphics.widgetbase import Widget from reportlab.lib.colors import Color, black, white, ReportLabBlue from reportlab.pdfbase.pdfmetrics import stringWidth class RL_CorpLogo(Widget): '''Dinu's fat letter logo as hacked into decent paths by Robin''' _attrMap = AttrMap( x = AttrMapValue(isNumber,'Logo x-coord'), y = AttrMapValue(isNumber,'Logo y-coord'), angle = AttrMapValue(isNumber,'Logo rotation'), strokeColor = AttrMapValue(isColorOrNone, 'Logo lettering stroke color'), fillColor = AttrMapValue(isColorOrNone, 'Logo lettering fill color'), strokeWidth = AttrMapValue(isNumber,'Logo lettering stroke width'), background = AttrMapValue(isColorOrNone,desc="Logo background color"), border = AttrMapValue(isColorOrNone,desc="Logo border color"), borderWidth = AttrMapValue(isNumber,desc="Logo border width (1)"), shadow = AttrMapValue(isNumberOrNone,desc="None or fraction of background for shadowing" ), width = AttrMapValue(isNumber, desc="width in points of the logo (default 129)"), height = AttrMapValue(isNumber, desc="height in points of the logo (default 86)"), skewX = AttrMapValue(isNumber, desc="x-skew of the logo (default 10)"), skewY = AttrMapValue(isNumber, desc="y-skew of the logo (default 0)"), showPage = AttrMapValue(EitherOr((isBoolean,SequenceOf(isBoolean,lo=2,hi=2))), desc="If true or (true(top),true(bottom)) show the page lines"), xFlip = AttrMapValue(isBoolean, desc="If true do x reversal"), yFlip = AttrMapValue(isBoolean, desc="If true do y reversal"), oColors = AttrMapValue(NoneOr(EitherOr((isColor,SequenceOf(isColorOrNone,lo=2,hi=2)))),desc="None or fill/stroke colors for the o in ReportLab"), pageColors = AttrMapValue(NoneOr(EitherOr((isColor,SequenceOf(isColorOrNone,lo=2,hi=2)))),desc="None or fill/stroke colors for the page outline"), prec = AttrMapValue(NoneOr(isInt),desc="None or precision negative means strip excess"), ) def __init__(self): self.fillColor = white self.strokeColor = None self.strokeWidth = 0.1 self.background = ReportLabBlue self.border = None self.borderWidth = 1 self.shadow = 0.5 self.height = 86 self.width = 130 self.x = self.y = self.angle = self.skewY = self._dx = 0 self.skewX = 10 self._dy = 35.5 self.showPage = 1 self.oColors = None #ie use the default self.pageColors = None #ie use the default self.prec = None def demo(self): D = Drawing(self.width, self.height) D.add(self) return D def _paintLogo(self, g, dx=0, dy=0, strokeColor=None, strokeWidth=0.1, fillColor=white, _ocolors=None, _pagecolors=None): OP = [('moveTo' ,62.10648,6.51392 ), ('curveTo' ,62.10648,4.44205 ,61.47118,2.79288 ,60.2003,1.56631 ), ('curveTo' ,58.92971,0.33978 ,57.22626,-0.27348 ,55.08965,-0.27348 ), ('curveTo' ,52.99018,-0.27348 ,51.31914,0.35221 ,50.07595,1.60362 ), ('curveTo' ,48.8419,2.8633 ,48.22517,4.55394 ,48.22517,6.67551 ), ('curveTo' ,48.22517,8.79709 ,48.85575,10.50016 ,50.1175,11.78472 ), ('curveTo' ,51.36982,13.07755 ,53.03172,13.72396 ,55.1035,13.72396 ), ('curveTo' ,57.28608,13.72396 ,58.99866,13.08168 ,60.24185,11.79712 ), ('curveTo' ,61.48503,10.51259 ,62.10648,8.75154 ,62.10648,6.51392 ), 'closePath', ('moveTo' ,56.73358,6.67551 ), ('curveTo' ,56.73358,7.17276 ,56.69675,7.62236 ,56.62308,8.02428 ), ('curveTo' ,56.54942,8.42623 ,56.44334,8.77016 ,56.30544,9.05607 ), ('curveTo' ,56.16724,9.34198 ,56.00134,9.56369 ,55.80804,9.72113 ), ('curveTo' ,55.61474,9.8786 ,55.39817,9.95733 ,55.1589,9.95733 ), ('curveTo' ,54.68921,9.95733 ,54.31174,9.65898 ,54.02621,9.06229 ), ('curveTo' ,53.74068,8.54018 ,53.59807,7.75702 ,53.59807,6.71282 ), ('curveTo' ,53.59807,5.68515 ,53.74068,4.90202 ,54.02621,4.36332 ), ('curveTo' ,54.31174,3.76663 ,54.69392,3.46828 ,55.17275,3.46828 ), ('curveTo' ,55.62388,3.46828 ,55.99692,3.7625 ,56.29159,4.35088 ), ('curveTo' ,56.58625,5.0056 ,56.73358,5.78047 ,56.73358,6.67551 ), 'closePath'] P = [ ('moveTo' ,15.7246,0 ), ('lineTo' ,9.49521,0 ), ('lineTo' ,6.64988,6.83711 ), ('curveTo' ,6.62224,6.95315 ,6.57391,7.10646 ,6.50485,7.29708 ), ('curveTo' ,6.43578,7.48767 ,6.35059,7.71559 ,6.24931,7.98079 ), ('lineTo' ,6.29074,6.71282 ), ('lineTo' ,6.29074,0 ), ('lineTo' ,0.55862,0 ), ('lineTo' ,0.55862,19.19365 ), ('lineTo' ,6.45649,19.19365 ), ('curveTo' ,9.05324,19.19365 ,10.99617,18.73371 ,12.28532,17.8138 ), ('curveTo' ,13.92439,16.63697 ,14.7439,14.96293 ,14.7439,12.79161 ), ('curveTo' ,14.7439,10.47114 ,13.64354,8.86755 ,11.44276,7.98079 ), 'closePath', ('moveTo' ,6.31838,10.30542 ), ('lineTo' ,6.70513,10.30542 ), ('curveTo' ,7.36812,10.30542 ,7.92062,10.53331 ,8.36261,10.98912 ), ('curveTo' ,8.80461,11.44491 ,9.0256,12.02504 ,9.0256,12.72947 ), ('curveTo' ,9.0256,14.16321 ,8.19227,14.88004 ,6.52556,14.88004 ), ('lineTo' ,6.31838,14.88004 ), 'closePath', ('moveTo' ,25.06173,4.54978 ), ('lineTo' ,30.47611,4.45033 ), ('curveTo' ,30.08951,2.88402 ,29.33668,1.70513 ,28.21787,0.91369 ), ('curveTo' ,27.09906,0.12223 ,25.63726,-0.27348 ,23.83245,-0.27348 ), ('curveTo' ,21.69611,-0.27348 ,20.02024,0.32322 ,18.80475,1.5166 ), ('curveTo' ,17.59846,2.72658 ,16.99531,4.37988 ,16.99531,6.47662 ), ('curveTo' ,16.99531,8.6065 ,17.64451,10.34269 ,18.94286,11.68527 ), ('curveTo' ,20.24124,13.03612 ,21.91711,13.71152 ,23.97056,13.71152 ), ('curveTo' ,26.01482,13.71152 ,27.64466,13.06096 ,28.86015,11.75985 ), ('curveTo' ,30.07566,10.45042 ,30.68326,8.71423 ,30.68326,6.5512 ), ('lineTo' ,30.65586,5.66859 ), ('lineTo' ,22.53407,5.66859 ), ('curveTo' ,22.59855,4.29287 ,23.03132,3.60503 ,23.83245,3.60503 ), ('curveTo' ,24.45861,3.60503 ,24.86837,3.91994 ,25.06173,4.54978 ), 'closePath', ('moveTo' ,25.18604,8.35371 ), ('curveTo' ,25.18604,8.60235 ,25.15384,8.83024 ,25.08937,9.03742 ), ('curveTo' ,25.02489,9.24463 ,24.93514,9.42278 ,24.82001,9.57197 ), ('curveTo' ,24.70492,9.72113 ,24.56911,9.83923 ,24.41255,9.92624 ), ('curveTo' ,24.25603,10.01326 ,24.08568,10.05678 ,23.90152,10.05678 ), ('curveTo' ,23.51474,10.05678 ,23.20169,9.89725 ,22.96225,9.57819 ), ('curveTo' ,22.72283,9.25913 ,22.60314,8.85096 ,22.60314,8.35371 ), 'closePath', ('moveTo' ,38.36308,-5.99181 ), ('lineTo' ,32.82428,-5.99181 ), ('lineTo' ,32.82428,13.43804 ), ('lineTo' ,38.36308,13.43804 ), ('lineTo' ,38.23873,11.53608 ), ('curveTo' ,38.46886,11.93387 ,38.70371,12.27159 ,38.94327,12.54922 ), ('curveTo' ,39.18254,12.82685 ,39.44037,13.05268 ,39.71676,13.22671 ), ('curveTo' ,39.99286,13.40074 ,40.28988,13.52712 ,40.60753,13.60585 ), ('curveTo' ,40.92518,13.68459 ,41.27759,13.72396 ,41.66419,13.72396 ), ('curveTo' ,43.10068,13.72396 ,44.2702,13.07755 ,45.17246,11.78472 ), ('curveTo' ,46.06588,10.50844 ,46.51229,8.81368 ,46.51229,6.70038 ), ('curveTo' ,46.51229,4.55394 ,46.08415,2.85502 ,45.22785,1.60362 ), ('curveTo' ,44.38983,0.35221 ,43.23416,-0.27348 ,41.76084,-0.27348 ), ('curveTo' ,40.41659,-0.27348 ,39.24235,0.42679 ,38.23873,1.82739 ), ('curveTo' ,38.2847,1.40472 ,38.31239,1.04007 ,38.32153,0.73345 ), ('curveTo' ,38.34923,0.41851 ,38.36308,0.04146 ,38.36308,-0.3978 ), 'closePath', ('moveTo' ,40.7802,6.84954 ), ('curveTo' ,40.7802,7.72802 ,40.66734,8.40964 ,40.44193,8.89448 ), ('curveTo' ,40.21621,9.37929 ,39.89621,9.62168 ,39.48191,9.62168 ), ('curveTo' ,38.62533,9.62168 ,38.19718,8.68108 ,38.19718,6.79983 ), ('curveTo' ,38.19718,4.87712 ,38.61177,3.91581 ,39.44037,3.91581 ), ('curveTo' ,39.85466,3.91581 ,40.18174,4.1727 ,40.42101,4.68654 ), ('curveTo' ,40.66057,5.20037 ,40.7802,5.92135 ,40.7802,6.84954 ), 'closePath', ('moveTo' ,69.78629,0 ), ('lineTo' ,64.2475,0 ), ('lineTo' ,64.2475,13.43804 ), ('lineTo' ,69.78629,13.43804 ), ('lineTo' ,69.49605,10.81507 ), ('curveTo' ,70.33407,12.77921 ,71.71988,13.76126 ,73.65346,13.76126 ), ('lineTo' ,73.65346,8.16725 ), ('curveTo' ,73.04586,8.4656 ,72.5302,8.61478 ,72.10647,8.61478 ), ('curveTo' ,71.36068,8.61478 ,70.78756,8.37236 ,70.38711,7.88755 ), ('curveTo' ,69.98637,7.40274 ,69.78629,6.69623 ,69.78629,5.76804 ), 'closePath', ('moveTo' ,81.55427,0 ), ('lineTo' ,76.00163,0 ), ('lineTo' ,76.00163,9.42278 ), ('lineTo' ,74.42725,9.42278 ), ('lineTo' ,74.42725,13.43804 ), ('lineTo' ,76.00163,13.43804 ), ('lineTo' ,76.00163,17.39113 ), ('lineTo' ,81.55427,17.39113 ), ('lineTo' ,81.55427,13.43804 ), ('lineTo' ,83.39121,13.43804 ), ('lineTo' ,83.39121,9.42278 ), ('lineTo' ,81.55427,9.42278 ), 'closePath', ('moveTo' ,95.17333,0 ), ('lineTo' ,85.09024,0 ), ('lineTo' ,85.09024,19.19365 ), ('lineTo' ,90.85002,19.19365 ), ('lineTo' ,90.85002,4.61196 ), ('lineTo' ,95.17333,4.61196 ), 'closePath', ('moveTo' ,110.00787,0 ), ('lineTo' ,104.45523,0 ), ('curveTo' ,104.5012,0.44754 ,104.53803,0.87433 ,104.56573,1.2804 ), ('curveTo' ,104.59313,1.68651 ,104.62083,2.01385 ,104.64853,2.26246 ), ('curveTo' ,103.69087,0.57182 ,102.40644,-0.27348 ,100.79492,-0.27348 ), ('curveTo' ,99.39527,-0.27348 ,98.28557,0.35637 ,97.46611,1.61605 ), ('curveTo' ,96.65578,2.86746 ,96.25062,4.59952 ,96.25062,6.81227 ), ('curveTo' ,96.25062,8.95041 ,96.66963,10.63276 ,97.50765,11.8593 ), ('curveTo' ,98.34538,13.10242 ,99.4872,13.72396 ,100.93312,13.72396 ), ('curveTo' ,102.41557,13.72396 ,103.61249,12.92008 ,104.52418,11.31231 ), ('curveTo' ,104.50591,11.47806 ,104.49206,11.62309 ,104.48293,11.74741 ), ('curveTo' ,104.4735,11.87173 ,104.46437,11.9753 ,104.45523,12.05819 ), ('lineTo' ,104.39983,12.84135 ), ('lineTo' ,104.35858,13.43804 ), ('lineTo' ,110.00787,13.43804 ), 'closePath', ('moveTo' ,104.39983,6.88685 ), ('curveTo' ,104.39983,7.38409 ,104.37921,7.80676 ,104.33766,8.15481 ), ('curveTo' ,104.29641,8.5029 ,104.22952,8.78672 ,104.13758,9.00636 ), ('curveTo' ,104.04535,9.22598 ,103.92572,9.38341 ,103.77839,9.47874 ), ('curveTo' ,103.63106,9.57403 ,103.45161,9.62168 ,103.23974,9.62168 ), ('curveTo' ,102.30036,9.62168 ,101.83096,8.49875 ,101.83096,6.25285 ), ('curveTo' ,101.83096,4.64508 ,102.24967,3.8412 ,103.0877,3.8412 ), ('curveTo' ,103.96255,3.8412 ,104.39983,4.85641 ,104.39983,6.88685 ), 'closePath', ('moveTo' ,118.22604,0 ), ('lineTo' ,112.5629,0 ), ('lineTo' ,112.5629,20.99616 ), ('lineTo' ,118.10169,20.99616 ), ('lineTo' ,118.10169,13.63694 ), ('curveTo' ,118.10169,13.01538 ,118.07399,12.30268 ,118.01889,11.49877 ), ('curveTo' ,118.52542,12.31096 ,119.03636,12.88693 ,119.55202,13.22671 ), ('curveTo' ,120.08625,13.55821 ,120.75838,13.72396 ,121.5687,13.72396 ), ('curveTo' ,123.07885,13.72396 ,124.24837,13.09827 ,125.07697,11.84686 ), ('curveTo' ,125.90586,10.60373 ,126.32015,8.85099 ,126.32015,6.5885 ), ('curveTo' ,126.32015,4.42546 ,125.89201,2.74314 ,125.03571,1.54147 ), ('curveTo' ,124.18826,0.3315 ,123.01432,-0.27348 ,121.51331,-0.27348 ), ('curveTo' ,120.78608,-0.27348 ,120.16905,-0.12432 ,119.66252,0.17403 ), ('curveTo' ,119.41383,0.3315 ,119.15835,0.54283 ,118.8961,0.80803 ), ('curveTo' ,118.63356,1.07322 ,118.36866,1.40472 ,118.10169,1.80252 ), ('curveTo' ,118.11112,1.64505 ,118.12025,1.51039 ,118.12939,1.3985 ), ('curveTo' ,118.13852,1.28662 ,118.14766,1.19339 ,118.15709,1.11881 ), 'closePath', ('moveTo' ,120.58806,6.70038 ), ('curveTo' ,120.58806,8.62306 ,120.11837,9.5844 ,119.17898,9.5844 ), ('curveTo' ,118.35039,9.5844 ,117.93609,8.67693 ,117.93609,6.86198 ), ('curveTo' ,117.93609,4.96417 ,118.36424,4.01526 ,119.22053,4.01526 ), ('curveTo' ,120.13222,4.01526 ,120.58806,4.91027 ,120.58806,6.70038 ), 'closePath', ] showPage = self.showPage PP = [] if showPage: if not isSeq(showPage): showPage = (showPage,showPage) if showPage[0]: #top PP.extend([('moveTo' ,32.70766,14.52164 ), ('lineTo' ,32.70766,47.81862 ), ('lineTo' ,80.14849,47.81862 ), ('lineTo' ,90.46172,37.21073 ), ('lineTo' ,90.46172,20.12025 ), ('lineTo' ,85.15777,20.12025 ), ('lineTo' ,85.15777,30.72814 ), ('lineTo' ,73.66589,30.72814 ), ('lineTo' ,73.66589,42.22002 ), ('lineTo' ,38.30626,42.22002 ), ('lineTo' ,38.30626,14.52164 ), 'closePath', ('moveTo' ,79.2645,36.32674 ), ('lineTo' ,85.15777,36.32674 ), ('lineTo' ,79.2645,42.22002 ), 'closePath']) if showPage[1]: #bottom PP.extend([('moveTo',38.30626,-7.28346),('lineTo',38.30626,-25.55261),('lineTo',85.15777,-25.55261),('lineTo',85.15777,-1.39019),('lineTo',90.46172,-1.39019),('lineTo',90.46172,-31.15121),('lineTo',32.70766,-31.15121),('lineTo',32.70766,-7.28346), 'closePath']) if _ocolors: OP = self.applyPrec(OP,self.prec) g.add(definePath(OP,strokeColor=_ocolors[0],strokeWidth=strokeWidth,fillColor=_ocolors[1], dx=dx, dy=dy)) else: P += OP if self.showPage and _pagecolors: PP = self.applyPrec(PP,self.prec) g.add(definePath(PP,strokeColor=_pagecolors[0],strokeWidth=strokeWidth,fillColor=_pagecolors[1], dx=dx, dy=dy)) else: P += PP P = self.applyPrec(P,self.prec) g.add(definePath(P,strokeColor=strokeColor,strokeWidth=strokeWidth,fillColor=fillColor, dx=dx, dy=dy)) @staticmethod def applyPrec(P,prec): if prec is None: return P R = [].append f = DecimalFormatter(places=prec) for p in P: if isSeq(p): n = [].append for e in p: if isinstance(e,float): e = float(f(e)) n(e) p = n.__self__ R(p) return R.__self__ def draw(self): fillColor = self.fillColor strokeColor = self.strokeColor g = Group() bg = self.background bd = self.border bdw = self.borderWidth shadow = self.shadow x, y = self.x, self.y if bg: if shadow is not None and 0<=shadow<1: shadow = Color(bg.red*shadow,bg.green*shadow,bg.blue*shadow) self._paintLogo(g,dy=-2.5, dx=2,fillColor=shadow) self._paintLogo(g,fillColor=fillColor,strokeColor=strokeColor, _ocolors=self.oColors or None,_pagecolors=self.pageColors or None) g.skew(kx=self.skewX, ky=self.skewY) g.shift(self._dx,self._dy) G = Group() G.add(g) _w, _h = 130, 86 w, h = self.width, self.height if bg or (bd and bdw): G.insert(0,Rect(0,0,_w,_h,fillColor=bg,strokeColor=bd,strokeWidth=bdw)) if w!=_w or h!=_h: G.scale(w/float(_w),h/float(_h)) angle = self.angle if self.angle: w, h = w/2., h/2. G.shift(-w,-h) G.rotate(angle) G.shift(w,h) xFlip = getattr(self,'xFlip',0) and -1 or 0 yFlip = getattr(self,'yFlip',0) and -1 or 0 if xFlip or yFlip: sx = xFlip or 1 sy = yFlip or 1 G.shift(sx*x+w*xFlip,sy*y+yFlip*h) G = Group(G,transform=(sx,0,0,sy,0,0)) else: G.shift(x,y) return G class RL_CorpLogoReversed(RL_CorpLogo): def __init__(self): RL_CorpLogo.__init__(self) self.background = white self.fillColor = ReportLabBlue class RL_CorpLogoThin(Widget): """The ReportLab Logo. New version created by John Precedo on 7-8 August 2001. Based on bitmapped imaged from E-Id. Improved by Robin Becker.""" _attrMap = AttrMap( x = AttrMapValue(isNumber), y = AttrMapValue(isNumber), height = AttrMapValue(isNumberOrNone), width = AttrMapValue(isNumberOrNone), fillColor = AttrMapValue(isColorOrNone), strokeColor = AttrMapValue( isColorOrNone) ) _h = 90.5 _w = 136.5 _text='R e p o r t L a b' _fontName = 'Helvetica-Bold' _fontSize = 16 def __init__(self): self.fillColor = ReportLabBlue self.strokeColor = white self.x = 0 self.y = 0 self.height = self._h self.width = self._w def demo(self): D = Drawing(self.width, self.height) D.add(self) return D def _getText(self, x=0, y=0, color=None): return String(x,y, self._text, fontName=self._fontName, fontSize=self._fontSize, fillColor=color) def _sw(self,f=None,l=None): text = self._text if f is None: f = 0 if l is None: l = len(text) return stringWidth(text[f:l],self._fontName,self._fontSize) def _addPage(self, g, strokeWidth=3, color=None, dx=0, dy=0): x1, x2 = 31.85+dx, 80.97+dx fL = 10 # fold length y1, y2 = dy-34, dy+50.5 L = [[x1,dy-4,x1,y1, x2, y1, x2, dy-1], [x1,dy+11,x1,y2,x2-fL,y2,x2,y2-fL,x2,dy+14], [x2-10,y2,x2-10,y2-fL,x2,y2-fL]] for l in L: g.add(PolyLine(l, strokeWidth=strokeWidth, strokeColor=color, strokeLineJoin=0)) def draw(self): sx = 0.5 fillColor = self.fillColor strokeColor = self.strokeColor shadow = Color(fillColor.red*sx,fillColor.green*sx,fillColor.blue*sx) g = Group() g2= Group() g.add(Rect(fillColor=fillColor, strokeColor=fillColor, x=0, y=0, width=self._w, height=self._h)) sx = (self._w-2)/self._sw() g2.scale(sx,1) self._addPage(g2,strokeWidth=3,dx=2,dy=-2.5,color=shadow) self._addPage(g2,strokeWidth=3,color=strokeColor) g2.scale(1/sx,1) g2.add(self._getText(x=1,y=0,color=shadow)) g2.add(self._getText(x=0,y=1,color=strokeColor)) g2.scale(sx,1) g2.skew(kx=10, ky=0) g2.shift(0,38) g.add(g2) g.scale(self.width/self._w,self.height/self._h) g.shift(self.x,self.y) return g class ReportLabLogo: """vector reportlab logo centered in a 250x by 150y rectangle""" def __init__(self, atx=0, aty=0, width=2.5*inch, height=1.5*inch, powered_by=0): self.origin = (atx, aty) self.dimensions = (width, height) self.powered_by = powered_by def draw(self, canvas): from reportlab.graphics import renderPDF canvas.saveState() (atx,aty) = self.origin (width, height) = self.dimensions logo = RL_CorpLogo() logo.width, logo.height = width, height renderPDF.draw(logo.demo(),canvas,atx,aty,0) canvas.restoreState() class RL_BusinessCard(Widget): """Widget that creates a single business card. Uses RL_CorpLogo for the logo. For a black border around your card, set self.border to 1. To change the details on the card, over-ride the following properties: self.name, self.position, self.telephone, self.mobile, self.fax, self.email, self.web The office locations are set in self.rh_blurb_top ("London office" etc), and self.rh_blurb_bottom ("New York office" etc). """ # for items where it 'isString' the string can be an empty one... _attrMap = AttrMap( fillColor = AttrMapValue(isColorOrNone), strokeColor = AttrMapValue(isColorOrNone), altStrokeColor = AttrMapValue(isColorOrNone), x = AttrMapValue(isNumber), y = AttrMapValue(isNumber), height = AttrMapValue(isNumber), width = AttrMapValue(isNumber), borderWidth = AttrMapValue(isNumber), bleed=AttrMapValue(isNumberOrNone), cropMarks=AttrMapValue(isBoolean), border=AttrMapValue(isBoolean), name=AttrMapValue(isString), position=AttrMapValue(isString), telephone=AttrMapValue(isString), mobile=AttrMapValue(isString), fax=AttrMapValue(isString), email=AttrMapValue(isString), web=AttrMapValue(isString), rh_blurb_top=AttrMapValue(isListOfStringsOrNone), rh_blurb_bottom=AttrMapValue(isListOfStringsOrNone) ) _h = 5.35*cm _w = 8.5*cm _fontName = 'Helvetica-Bold' _strapline = "strategic reporting solutions for e-business" def __init__(self): self.fillColor = ReportLabBlue self.strokeColor = black self.altStrokeColor = white self.x = 0 self.y = 0 self.height = self._h self.width = self._w self.borderWidth = self.width/6.15 self.bleed=0.2*cm self.cropMarks=1 self.border=0 #Over-ride these with your own info self.name="Joe Cool" self.position="Freelance Demonstrator" self.telephone="020 8545 7271" self.mobile="-" self.fax="020 8544 1311" self.email="info@reportlab.com" self.web="www.reportlab.com" self.rh_blurb_top = ["London office:", "ReportLab Europe Ltd", "Media House", "3 Palmerston Road", "Wimbledon", "London SW19 1PG", "United Kingdom"] def demo(self): D = Drawing(self.width, self.height) D.add(self) return D def draw(self): fillColor = self.fillColor strokeColor = self.strokeColor g = Group() g.add(Rect(x = 0, y = 0, fillColor = self.fillColor, strokeColor = self.fillColor, width = self.borderWidth, height = self.height)) g.add(Rect(x = 0, y = self.height-self.borderWidth, fillColor = self.fillColor, strokeColor = self.fillColor, width = self.width, height = self.borderWidth)) g2 = Group() rl=RL_CorpLogo() rl.height = 1.25*cm rl.width = 1.9*cm rl.draw() g2.add(rl) g.add(g2) g2.shift(x=(self.width-(rl.width+(self.width/42))), y=(self.height - (rl.height+(self.height/42)))) g.add(String(x = self.borderWidth/5.0, y = ((self.height - (rl.height+(self.height/42)))+((38/90.5)*rl.height)), fontSize = 6, fillColor = self.altStrokeColor, fontName = "Helvetica-BoldOblique", textAnchor = 'start', text = self._strapline)) leftText=["Tel:", "Mobile:", "Fax:", "Email:", "Web:"] leftDetails=[self.telephone,self.mobile,self.fax,self.email,self.web] leftText.reverse() leftDetails.reverse() for f in range(len(leftText),0,-1): g.add(String(x = self.borderWidth+(self.borderWidth/5.0), y = (self.borderWidth/5.0)+((f-1)*(5*1.2)), fontSize = 5, fillColor = self.strokeColor, fontName = "Helvetica", textAnchor = 'start', text = leftText[f-1])) g.add(String(x = self.borderWidth+(self.borderWidth/5.0)+self.borderWidth, y = (self.borderWidth/5.0)+((f-1)*(5*1.2)), fontSize = 5, fillColor = self.strokeColor, fontName = "Helvetica", textAnchor = 'start', text = leftDetails[f-1])) ty = (self.height-self.borderWidth-(self.borderWidth/5.0)+2) # g.add(Line(self.borderWidth, ty, self.borderWidth+(self.borderWidth/5.0), ty)) # g.add(Line(self.borderWidth+(self.borderWidth/5.0), ty, self.borderWidth+(self.borderWidth/5.0), # ty+(self.borderWidth/5.0))) # g.add(Line(self.borderWidth, ty-10, # self.borderWidth+(self.borderWidth/5.0), ty-10)) rightText=self.rh_blurb_top for f in range(1,(len(rightText)+1)): g.add(String(x = self.width-(self.borderWidth/5.0), y = ty-((f)*(5*1.2)), fontSize = 5, fillColor = self.strokeColor, fontName = "Helvetica", textAnchor = 'end', text = rightText[f-1])) g.add(String(x = self.borderWidth+(self.borderWidth/5.0), y = ty-10, fontSize = 10, fillColor = self.strokeColor, fontName = "Helvetica", textAnchor = 'start', text = self.name)) ty1 = ty-10*1.2 g.add(String(x = self.borderWidth+(self.borderWidth/5.0), y = ty1-8, fontSize = 8, fillColor = self.strokeColor, fontName = "Helvetica", textAnchor = 'start', text = self.position)) if self.border: g.add(Rect(x = 0, y = 0, fillColor=None, strokeColor = black, width = self.width, height = self.height)) g.shift(self.x,self.y) return g def test(formats=['pdf','eps','jpg','gif','svg']): """This function produces a pdf with examples. """ #white on blue rl = RL_CorpLogo() rl.width = 129 rl.height = 86 D = Drawing(rl.width,rl.height) D.add(rl) D.__dict__['verbose'] = 1 D.save(fnRoot='corplogo_whiteonblue',formats=formats) #blue on white rl = RL_CorpLogoReversed() rl.width = 129 rl.height = 86 D = Drawing(rl.width,rl.height) D.add(rl) D.__dict__['verbose'] = 1 D.save(fnRoot='corplogo_blueonwhite',formats=formats) #gray on white rl = RL_CorpLogoReversed() rl.fillColor = Color(0.2, 0.2, 0.2) rl.width = 129 rl.height = 86 D = Drawing(rl.width,rl.height) D.add(rl) D.__dict__['verbose'] = 1 D.save(fnRoot='corplogo_grayonwhite',formats=formats) rl = RL_BusinessCard() rl.x=25 rl.y=25 rl.border=1 D = Drawing(rl.width+50,rl.height+50) D.add(rl) D.__dict__['verbose'] = 1 D.save(fnRoot='RL_BusinessCard',formats=formats) if __name__=='__main__': test() ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1691062243.0 reportlab-4.1.0/src/reportlab/lib/enums.py0000664000175000017500000000045014462707743020147 0ustar00rptlabrptlab#Copyright ReportLab Europe Ltd. 2000-2017 #see license.txt for license details #history https://hg.reportlab.com/hg-public/reportlab/log/tip/src/reportlab/lib/enums.py __version__='3.3.0' __doc__=""" Container for constants. Hardly used! """ TA_LEFT = 0 TA_CENTER = 1 TA_RIGHT = 2 TA_JUSTIFY = 4././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1691062243.0 reportlab-4.1.0/src/reportlab/lib/extformat.py0000664000175000017500000000426214462707743021036 0ustar00rptlabrptlab#Copyright ReportLab Europe Ltd. 2000-2017 #see license.txt for license details __version__='3.3.0' __doc__='''Apparently not used anywhere, purpose unknown!''' try: from tokenize import tokenprog except ImportError: from tokenize import Token import re tokenprog = re.compile(Token) del Token, re import sys def _matchorfail(text, pos): match = tokenprog.match(text, pos) if match is None: raise ValueError(text, pos) return match, match.end() ''' Extended dictionary formatting We allow expressions in the parentheses instead of just a simple variable. ''' def dictformat(_format, L={}, G={}): format = _format S = {} chunks = [] pos = 0 n = 0 while 1: pc = format.find("%", pos) if pc < 0: break nextchar = format[pc+1] if nextchar == "(": chunks.append(format[pos:pc]) pos, level = pc+2, 1 while level: match, pos = _matchorfail(format, pos) tstart, tend = match.regs[3] token = format[tstart:tend] if token == "(": level = level+1 elif token == ")": level = level-1 vname = '__superformat_%d' % n n += 1 S[vname] = eval(format[pc+2:pos-1],G,L) chunks.append('%%(%s)' % vname) else: nc = pc+1+(nextchar=="%") chunks.append(format[pos:nc]) pos = nc if pos < len(format): chunks.append(format[pos:]) return (''.join(chunks)) % S def magicformat(format): """Evaluate and substitute the appropriate parts of the string.""" frame = sys._getframe(1) return dictformat(format,frame.f_locals, frame.f_globals) if __name__=='__main__': from reportlab.lib.formatters import DecimalFormatter _DF={} def df(n,dp=2,ds='.',ts=','): try: _df = _DF[dp,ds] except KeyError: _df = _DF[dp,ds] = DecimalFormatter(places=dp,decimalSep=ds,thousandSep=ts) return _df(n) from reportlab.lib.extformat import magicformat Z={'abc': ('ab','c')} x = 300000.23 percent=79.2 class dingo: a=3 print((magicformat(''' $%%(df(x,dp=3))s --> $%(df(x,dp=3))s $%%(df(x,dp=2,ds=',',ts='.'))s --> $%(df(x,dp=2,ds=',',ts='.'))s %%(percent).2f%%%% --> %(percent).2f%% %%(dingo.a)s --> %(dingo.a)s %%(Z['abc'][0])s --> %(Z['abc'][0])s '''))) def func0(aa=1): def func1(bb=2): print((magicformat('bb=%(bb)s Z=%(Z)r'))) func1('BB') func0('AA') ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1691062243.0 reportlab-4.1.0/src/reportlab/lib/fontfinder.py0000664000175000017500000003207114462707743021162 0ustar00rptlabrptlab#Copyright ReportLab Europe Ltd. 2000-2019 #see license.txt for license details __version__='3.4.22' #modification of users/robin/ttflist.py. __doc__="""This provides some general-purpose tools for finding fonts. The FontFinder object can search for font files. It aims to build a catalogue of fonts which our framework can work with. It may be useful if you are building GUIs or design-time interfaces and want to present users with a choice of fonts. There are 3 steps to using it 1. create FontFinder and set options and directories 2. search 3. query >>> import fontfinder >>> ff = fontfinder.FontFinder() >>> ff.addDirectories([dir1, dir2, dir3]) >>> ff.search() >>> ff.getFamilyNames() #or whichever queries you want... Because the disk search takes some time to find and parse hundreds of fonts, it can use a cache to store a file with all fonts found. The cache file name For each font found, it creates a structure with - the short font name - the long font name - the principal file (.pfb for type 1 fonts), and the metrics file if appropriate - the time modified (unix time stamp) - a type code ('ttf') - the family name - bold and italic attributes One common use is to display families in a dialog for end users; then select regular, bold and italic variants of the font. To get the initial list, use getFamilyNames; these will be in alpha order. >>> ff.getFamilyNames() ['Bitstream Vera Sans', 'Century Schoolbook L', 'Dingbats', 'LettErrorRobot', 'MS Gothic', 'MS Mincho', 'Nimbus Mono L', 'Nimbus Roman No9 L', 'Nimbus Sans L', 'Vera', 'Standard Symbols L', 'URW Bookman L', 'URW Chancery L', 'URW Gothic L', 'URW Palladio L'] One can then obtain a specific font as follows >>> f = ff.getFont('Bitstream Vera Sans', bold=False, italic=True) >>> f.fullName 'Bitstream Vera Sans' >>> f.fileName 'C:\\code\\reportlab\\fonts\\Vera.ttf' >>> It can also produce an XML report of fonts found by family, for the benefit of non-Python applications. Future plans might include using this to auto-register fonts; and making it update itself smartly on repeated instantiation. """ import sys, os, pickle from hashlib import md5 from xml.sax.saxutils import quoteattr from time import process_time as clock from reportlab.lib.utils import asBytes, asNative as _asNative def asNative(s): try: return _asNative(s) except: return _asNative(s,enc='latin-1') EXTENSIONS = ['.ttf','.ttc','.otf','.pfb','.pfa'] # PDF font flags (see PDF Reference Guide table 5.19) FF_FIXED = 1 << 1-1 FF_SERIF = 1 << 2-1 FF_SYMBOLIC = 1 << 3-1 FF_SCRIPT = 1 << 4-1 FF_NONSYMBOLIC = 1 << 6-1 FF_ITALIC = 1 << 7-1 FF_ALLCAP = 1 << 17-1 FF_SMALLCAP = 1 << 18-1 FF_FORCEBOLD = 1 << 19-1 class FontDescriptor: """This is a short descriptive record about a font. typeCode should be a file extension e.g. ['ttf','ttc','otf','pfb','pfa'] """ def __init__(self): self.name = None self.fullName = None self.familyName = None self.styleName = None self.isBold = False #true if it's somehow bold self.isItalic = False #true if it's italic or oblique or somehow slanty self.isFixedPitch = False self.isSymbolic = False #false for Dingbats, Symbols etc. self.typeCode = None #normally the extension minus the dot self.fileName = None #full path to where we found it. self.metricsFileName = None #defined only for type='type1pc', or 'type1mac' self.timeModified = 0 def __repr__(self): return "FontDescriptor(%s)" % self.name def getTag(self): "Return an XML tag representation" attrs = [] for k, v in self.__dict__.items(): if k not in ['timeModified']: if v: attrs.append('%s=%s' % (k, quoteattr(str(v)))) return '' from reportlab.lib.utils import rl_isdir, rl_isfile, rl_listdir, rl_getmtime class FontFinder: def __init__(self, dirs=[], useCache=True, validate=False, recur=False, fsEncoding=None, verbose=0): self.useCache = useCache self.validate = validate if fsEncoding is None: fsEncoding = sys.getfilesystemencoding() self._fsEncoding = fsEncoding or 'utf8' self._dirs = set() self._recur = recur self.addDirectories(dirs) self._fonts = [] self._skippedFiles = [] #list of filenames we did not handle self._badFiles = [] #list of filenames we rejected self._fontsByName = {} self._fontsByFamily = {} self._fontsByFamilyBoldItalic = {} #indexed by bold, italic self.verbose = verbose def addDirectory(self, dirName, recur=None): #aesthetics - if there are 2 copies of a font, should the first or last #be picked up? might need reversing if rl_isdir(dirName): self._dirs.add(dirName) if recur if recur is not None else self._recur: for r,D,F in os.walk(dirName): for d in D: self._dirs.add(os.path.join(r,d)) def addDirectories(self, dirNames,recur=None): for dirName in dirNames: self.addDirectory(dirName,recur=recur) def getFamilyNames(self): "Returns a list of the distinct font families found" if not self._fontsByFamily: fonts = self._fonts for font in fonts: fam = font.familyName if fam is None: continue if fam in self._fontsByFamily: self._fontsByFamily[fam].append(font) else: self._fontsByFamily[fam] = [font] fsEncoding = self._fsEncoding names = list(asBytes(_,enc=fsEncoding) for _ in self._fontsByFamily.keys()) names.sort() return names def getFontsInFamily(self, familyName): "Return list of all font objects with this family name" return self._fontsByFamily.get(familyName,[]) def getFamilyXmlReport(self): """Reports on all families found as XML. """ lines = [] lines.append('') lines.append("") for dirName in self._dirs: lines.append(" " % quoteattr(asNative(dirName))) for familyName in self.getFamilyNames(): if familyName: #skip null case lines.append(' ' % quoteattr(asNative(familyName))) for font in self.getFontsInFamily(familyName): lines.append(' ' + font.getTag()) lines.append(' ') lines.append("") return '\n'.join(lines) def getFontsWithAttributes(self, **kwds): """This is a general lightweight search.""" selected = [] for font in self._fonts: OK = True for k, v in kwds.items(): if getattr(font, k, None) != v: OK = False if OK: selected.append(font) return selected def getFont(self, familyName, bold=False, italic=False): """Try to find a font matching the spec""" for font in self._fonts: if font.familyName == familyName: if font.isBold == bold: if font.isItalic == italic: return font raise KeyError("Cannot find font %s with bold=%s, italic=%s" % (familyName, bold, italic)) def _getCacheFileName(self): """Base this on the directories...same set of directories should give same cache""" fsEncoding = self._fsEncoding hash = md5(b''.join(asBytes(_,enc=fsEncoding) for _ in sorted(self._dirs))).hexdigest() from reportlab.lib.utils import get_rl_tempfile fn = get_rl_tempfile('fonts_%s.dat' % hash) return fn def save(self, fileName): f = open(fileName, 'wb') pickle.dump(self, f) f.close() def load(self, fileName): f = open(fileName, 'rb') finder2 = pickle.load(f) f.close() self.__dict__.update(finder2.__dict__) def search(self): if self.verbose: started = clock() if not self._dirs: raise ValueError("Font search path is empty! Please specify search directories using addDirectory or addDirectories") if self.useCache: cfn = self._getCacheFileName() if rl_isfile(cfn): try: self.load(cfn) if self.verbose>=3: print("loaded cached file with %d fonts (%s)" % (len(self._fonts), cfn)) return except: pass #pickle load failed. Ho hum, maybe it's an old pickle. Better rebuild it. for dirName in self._dirs: try: fileNames = rl_listdir(dirName) except: continue for fileName in fileNames: root, ext = os.path.splitext(fileName) if ext.lower() in EXTENSIONS: #it's a font f = FontDescriptor() f.fileName = fileName = os.path.normpath(os.path.join(dirName, fileName)) try: f.timeModified = rl_getmtime(fileName) except: self._skippedFiles.append(fileName) continue ext = ext.lower() if ext[0] == '.': ext = ext[1:] f.typeCode = ext #strip the dot #what to do depends on type. We only accept .pfb if we #have .afm to go with it, and don't handle .otf now. if ext in ('otf', 'pfa'): self._skippedFiles.append(fileName) elif ext in ('ttf','ttc'): #parsing should check it for us from reportlab.pdfbase.ttfonts import TTFontFile, TTFError try: font = TTFontFile(fileName,validate=self.validate) except TTFError: self._badFiles.append(fileName) continue f.name = font.name f.fullName = font.fullName f.styleName = font.styleName f.familyName = font.familyName f.isBold = (FF_FORCEBOLD == FF_FORCEBOLD & font.flags) f.isItalic = (FF_ITALIC == FF_ITALIC & font.flags) elif ext == 'pfb': # type 1; we need an AFM file or have to skip. if rl_isfile(os.path.join(dirName, root + '.afm')): f.metricsFileName = os.path.normpath(os.path.join(dirName, root + '.afm')) elif rl_isfile(os.path.join(dirName, root + '.AFM')): f.metricsFileName = os.path.normpath(os.path.join(dirName, root + '.AFM')) else: self._skippedFiles.append(fileName) continue from reportlab.pdfbase.pdfmetrics import parseAFMFile (info, glyphs) = parseAFMFile(f.metricsFileName) f.name = info['FontName'] f.fullName = info.get('FullName', f.name) f.familyName = info.get('FamilyName', None) f.isItalic = (float(info.get('ItalicAngle', 0)) > 0.0) #if the weight has the word bold, deem it bold f.isBold = ('bold' in info.get('Weight','').lower()) self._fonts.append(f) if self.useCache: self.save(cfn) if self.verbose: finished = clock() print("found %d fonts; skipped %d; bad %d. Took %0.2f seconds" % ( len(self._fonts), len(self._skippedFiles), len(self._badFiles), finished - started )) def test(): #windows-centric test maybe from reportlab import rl_config ff = FontFinder(verbose=rl_config.verbose) ff.useCache = True ff.validate = True import reportlab ff.addDirectory('C:\\windows\\fonts') rlFontDir = os.path.join(os.path.dirname(reportlab.__file__), 'fonts') ff.addDirectory(rlFontDir) ff.search() print('cache file name...') print(ff._getCacheFileName()) print('families...') for familyName in ff.getFamilyNames(): print('\t%s' % familyName) print() outw = sys.stdout.write outw('fonts called Vera:') for font in ff.getFontsInFamily('Bitstream Vera Sans'): outw(' %s' % font.name) print() outw('Bold fonts\n\t') for font in ff.getFontsWithAttributes(isBold=True, isItalic=False): outw(font.fullName+' ') print() print('family report') print(ff.getFamilyXmlReport()) if __name__=='__main__': test() ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1691062243.0 reportlab-4.1.0/src/reportlab/lib/fonts.py0000664000175000017500000000665714462707743020170 0ustar00rptlabrptlab#!/bin/env python #Copyright ReportLab Europe Ltd. 2000-2017 #see license.txt for license details #history https://hg.reportlab.com/hg-public/reportlab/log/tip/src/reportlab/lib/fonts.py __version__='3.3.0' __doc__='''Utilities to associate bold and italic versions of fonts into families Bold, italic and plain fonts are usually implemented in separate disk files; but non-trivial apps want this to do the right thing. We therefore need to keep 'mappings' between the font family name and the right group of up to 4 implementation fonts to use. Most font-handling code lives in pdfbase, and this probably should too. ''' ############################################################################### # A place to put useful font stuff ############################################################################### # # Font Mappings # The brute force approach to finding the correct postscript font name; # much safer than the rule-based ones we tried. # preprocessor to reduce font face names to the shortest list # possible. Add any aliases you wish; it keeps looking up # until it finds no more translations to do. Any input # will be lowercased before checking. _family_alias = { 'serif':'times', 'sansserif':'helvetica', 'monospaced':'courier', 'arial':'helvetica' } #maps a piddle font to a postscript one. _tt2ps_map = { #face, bold, italic -> ps name ('times', 0, 0) :'Times-Roman', ('times', 1, 0) :'Times-Bold', ('times', 0, 1) :'Times-Italic', ('times', 1, 1) :'Times-BoldItalic', ('courier', 0, 0) :'Courier', ('courier', 1, 0) :'Courier-Bold', ('courier', 0, 1) :'Courier-Oblique', ('courier', 1, 1) :'Courier-BoldOblique', ('helvetica', 0, 0) :'Helvetica', ('helvetica', 1, 0) :'Helvetica-Bold', ('helvetica', 0, 1) :'Helvetica-Oblique', ('helvetica', 1, 1) :'Helvetica-BoldOblique', # there is only one Symbol font ('symbol', 0, 0) :'Symbol', ('symbol', 1, 0) :'Symbol', ('symbol', 0, 1) :'Symbol', ('symbol', 1, 1) :'Symbol', # ditto for dingbats ('zapfdingbats', 0, 0) :'ZapfDingbats', ('zapfdingbats', 1, 0) :'ZapfDingbats', ('zapfdingbats', 0, 1) :'ZapfDingbats', ('zapfdingbats', 1, 1) :'ZapfDingbats', } _ps2tt_map={} for k in sorted(_tt2ps_map.keys()): v = _tt2ps_map[k].lower() if v not in _ps2tt_map: _ps2tt_map[v] = k v = k[0].lower() if v not in _ps2tt_map: _ps2tt_map[v] = k def ps2tt(psfn): 'ps fontname to family name, bold, italic' psfn = psfn.lower() if psfn in _ps2tt_map: return _ps2tt_map[psfn] raise ValueError("Can't map determine family/bold/italic for %s" % psfn) def tt2ps(fn,b,i): 'family name + bold & italic to ps font name' K = (fn.lower(),b,i) if K in _tt2ps_map: return _tt2ps_map[K] else: fn, b1, i1 = ps2tt(K[0]) K = fn, b1|b, i1|i if K in _tt2ps_map: return _tt2ps_map[K] raise ValueError("Can't find concrete font for family=%s, bold=%d, italic=%d" % (fn, b, i)) def addMapping(face, bold, italic, psname): 'allow a custom font to be put in the mapping' k = face.lower(), bold, italic _tt2ps_map[k] = psname _ps2tt_map[psname.lower()] = k ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1691062243.0 reportlab-4.1.0/src/reportlab/lib/formatters.py0000664000175000017500000000733414462707743021216 0ustar00rptlabrptlab#!/bin/env python #Copyright ReportLab Europe Ltd. 2000-2017 #see license.txt for license details #history https://hg.reportlab.com/hg-public/reportlab/log/tip/src/reportlab/lib/formatters.py __all__=('Formatter','DecimalFormatter') __version__='3.3.0' __doc__=""" These help format numbers and dates in a user friendly way. Used by the graphics framework. """ import re class Formatter: "Base formatter - simply applies python format strings" def __init__(self, pattern): self.pattern = pattern def format(self, obj): return self.pattern % obj def __repr__(self): return "%s('%s')" % (self.__class__.__name__, self.pattern) def __call__(self, x): return self.format(x) _ld_re=re.compile(r'^\d*\.') _tz_re=re.compile('0+$') class DecimalFormatter(Formatter): """lets you specify how to build a decimal. A future NumberFormatter class will take Microsoft-style patterns instead - "$#,##0.00" is WAY easier than this.""" def __init__(self, places=2, decimalSep='.', thousandSep=None, prefix=None, suffix=None): if places=='auto': self.calcPlaces = self._calcPlaces else: self.places = places self.dot = decimalSep self.comma = thousandSep self.prefix = prefix self.suffix = suffix def _calcPlaces(self,V): '''called with the full set of values to be formatted so we can calculate places''' self.places = max([len(_tz_re.sub('',_ld_re.sub('',str(v)))) for v in V]) def format(self, num): # positivize the numbers sign=num<0 if sign: num = -num places, sep = self.places, self.dot strip = places<=0 if places and strip: places = -places strInt = ('%.' + str(places) + 'f') % num if places: strInt, strFrac = strInt.split('.') strFrac = sep + strFrac if strip: while strFrac and strFrac[-1] in ['0',sep]: strFrac = strFrac[:-1] else: strFrac = '' if self.comma is not None: strNew = '' while strInt: left, right = strInt[0:-3], strInt[-3:] if left == '': #strNew = self.comma + right + strNew strNew = right + strNew else: strNew = self.comma + right + strNew strInt = left strInt = strNew strBody = strInt + strFrac if sign: strBody = '-' + strBody if self.prefix: strBody = self.prefix + strBody if self.suffix: strBody = strBody + self.suffix return strBody def __repr__(self): return "%s(places=%d, decimalSep=%s, thousandSep=%s, prefix=%s, suffix=%s)" % ( self.__class__.__name__, self.places, repr(self.dot), repr(self.comma), repr(self.prefix), repr(self.suffix) ) if __name__=='__main__': def t(n, s, places=2, decimalSep='.', thousandSep=None, prefix=None, suffix=None): f=DecimalFormatter(places,decimalSep,thousandSep,prefix,suffix) r = f(n) print("places=%2d dot=%-4s comma=%-4s prefix=%-4s suffix=%-4s result=%10s %s" %(f.places, f.dot, f.comma, f.prefix, f.suffix,r, r==s and 'OK' or 'BAD')) t(1000.9,'1,000.9',1,thousandSep=',') t(1000.95,'1,001.0',1,thousandSep=',') t(1000.95,'1,001',-1,thousandSep=',') t(1000.9,'1,001',0,thousandSep=',') t(1000.9,'1000.9',1) t(1000.95,'1001.0',1) t(1000.95,'1001',-1) t(1000.9,'1001',0) t(1000.1,'1000.1',1) t(1000.55,'1000.6',1) t(1000.449,'1000.4',-1) t(1000.45,'1000',0) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1691062243.0 reportlab-4.1.0/src/reportlab/lib/geomutils.py0000664000175000017500000000221314462707743021027 0ustar00rptlabrptlab#Copyright ReportLab Europe Ltd. 2000-2017 #see license.txt for license details __version__='3.3.0' __doc__='''Utility functions for geometrical operations.''' def normalizeTRBL(p): ''' Useful for interpreting short descriptions of paddings, borders, margin, etc. Expects a single value or a tuple of length 2 to 4. Returns a tuple representing (clockwise) the value(s) applied to the 4 sides of a rectangle: If a single value is given, that value is applied to all four sides. If two or three values are given, the missing values are taken from the opposite side(s). If four values are given they are returned unchanged. >>> normalizeTRBL(1) (1, 1, 1, 1) >>> normalizeTRBL((1, 1.2)) (1, 1.2, 1, 1.2) >>> normalizeTRBL((1, 1.2, 0)) (1, 1.2, 0, 1.2) >>> normalizeTRBL((1, 1.2, 0, 8)) (1, 1.2, 0, 8) ''' if not isinstance(p, (tuple, list)): return (p,)*4 elif len(p)==1: return (p[0],)*4 l = len(p) if l < 2 or l > 4: raise ValueError('A padding must have between 2 and 4 values but got %d.' % l) return tuple(p) + tuple([ p[i-2] for i in range(l, 4) ]) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1691062243.0 reportlab-4.1.0/src/reportlab/lib/logger.py0000664000175000017500000000332314462707743020301 0ustar00rptlabrptlab#!/bin/env python #Copyright ReportLab Europe Ltd. 2000-2017 #see license.txt for license details #history https://hg.reportlab.com/hg-public/reportlab/log/tip/src/reportlab/lib/logger.py __version__='3.3.0' __doc__="Logging and warning framework, predating Python's logging package" from sys import stderr class Logger: ''' An extended file type thing initially equivalent to sys.stderr You can add/remove file type things; it has a write method ''' def __init__(self): self._fps = [stderr] self._fns = {} def add(self,fp): '''add the file/string fp to the destinations''' if isinstance(fp,str): if fp in self._fns: return fp = open(fn,'wb') self._fns[fn] = fp self._fps.append(fp) def remove(self,fp): '''remove the file/string fp from the destinations''' if isinstance(fp,str): if fp not in self._fns: return fn = fp fp = self._fns[fn] del self.fns[fn] if fp in self._fps: del self._fps[self._fps.index(fp)] def write(self,text): '''write text to all the destinations''' if text[-1]!='\n': text=text+'\n' for fp in self._fps: fp.write(text) def __call__(self,text): self.write(text) logger=Logger() class WarnOnce: def __init__(self,kind='Warn'): self.uttered = {} self.pfx = '%s: '%kind self.enabled = 1 def once(self,warning): if warning not in self.uttered: if self.enabled: logger.write(self.pfx + warning) self.uttered[warning] = 1 def __call__(self,warning): self.once(warning) warnOnce=WarnOnce() infoOnce=WarnOnce('Info') ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1691062243.0 reportlab-4.1.0/src/reportlab/lib/normalDate.py0000664000175000017500000005300114462707743021106 0ustar00rptlabrptlab#!/usr/bin/env python # normalDate.py - version 1.0 - 20000717 #hacked by Robin Becker 10/Apr/2001 #major changes include # using Types instead of type(0) etc # BusinessDate class # __radd__, __rsub__ methods # formatMS stuff # derived from an original version created # by Jeff Bauer of Rubicon Research and used # with his kind permission __version__='3.3.18' __doc__="Jeff Bauer's lightweight date class, extended by us. Predates Python's datetime module." _bigBangScalar = -4345732 # based on (-9999, 1, 1) BC/BCE minimum _bigCrunchScalar = 2958463 # based on (9999,12,31) AD/CE maximum _daysInMonthNormal = [31,28,31,30,31,30,31,31,30,31,30,31] _daysInMonthLeapYear = [31,29,31,30,31,30,31,31,30,31,30,31] _dayOfWeekName = '''Monday Tuesday Wednesday Thursday Friday Saturday Sunday''' _dayOfWeekNameLower = _dayOfWeekName.lower().split() _dayOfWeekName = _dayOfWeekName.split() _monthName = '''January February March April May June July August September October November December''' _monthNameLower = _monthName.lower().split() _monthName = _monthName.split() import re, time, datetime from .utils import isStr if hasattr(time,'struct_time'): _DateSeqTypes = (list,tuple,time.struct_time) else: _DateSeqTypes = (list,tuple) _fmtPat = re.compile('\\{(m{1,5}|yyyy|yy|d{1,4})\\}',re.MULTILINE|re.IGNORECASE) _iso_re = re.compile(r'(\d\d\d\d|\d\d)-(\d\d)-(\d\d)') def getStdMonthNames(): return _monthNameLower def getStdShortMonthNames(): return [x[:3] for x in getStdMonthNames()] def getStdDayNames(): return _dayOfWeekNameLower def getStdShortDayNames(): return [x[:3] for x in getStdDayNames()] def isLeapYear(year): """determine if specified year is leap year, returns Python boolean""" if year < 1600: if year % 4: return 0 else: return 1 elif year % 4 != 0: return 0 elif year % 100 != 0: return 1 elif year % 400 != 0: return 0 else: return 1 class NormalDateException(Exception): """Exception class for NormalDate""" pass class NormalDate: """ NormalDate is a specialized class to handle dates without all the excess baggage (time zones, daylight savings, leap seconds, etc.) of other date structures. The minimalist strategy greatly simplifies its implementation and use. Internally, NormalDate is stored as an integer with values in a discontinuous range of -99990101 to 99991231. The integer value is used principally for storage and to simplify the user interface. Internal calculations are performed by a scalar based on Jan 1, 1900. Valid NormalDate ranges include (-9999,1,1) B.C.E. through (9999,12,31) C.E./A.D. 1.0 No changes, except the version number. After 3 years of use by various parties I think we can consider it stable. 0.8 Added Prof. Stephen Walton's suggestion for a range method - module author resisted the temptation to use lambda <0.5 wink> 0.7 Added Dan Winkler's suggestions for __add__, __sub__ methods 0.6 Modifications suggested by Kevin Digweed to fix: - dayOfWeek, dayOfWeekAbbrev, clone methods - Permit NormalDate to be a better behaved superclass 0.5 Minor tweaking 0.4 - Added methods __cmp__, __hash__ - Added Epoch variable, scoped to the module - Added setDay, setMonth, setYear methods 0.3 Minor touch-ups 0.2 - Fixed bug for certain B.C.E leap years - Added Jim Fulton's suggestions for short alias class name =ND and __getstate__, __setstate__ methods Special thanks: Roedy Green """ def __init__(self, normalDate=None): """ Accept 1 of 4 values to initialize a NormalDate: 1. None - creates a NormalDate for the current day 2. integer in yyyymmdd format 3. string in yyyymmdd format 4. tuple in (yyyy, mm, dd) - localtime/gmtime can also be used 5. string iso date format see _iso_re above 6. datetime.datetime or datetime.date """ if normalDate is None: self.setNormalDate(time.localtime(time.time())) else: self.setNormalDate(normalDate) def add(self, days): """add days to date; use negative integers to subtract""" if not isinstance(days,int): raise NormalDateException( \ 'add method parameter must be integer type') self.normalize(self.scalar() + days) def __add__(self, days): """add integer to normalDate and return a new, calculated value""" if not isinstance(days,int): raise NormalDateException( \ '__add__ parameter must be integer type') cloned = self.clone() cloned.add(days) return cloned def __radd__(self,days): '''for completeness''' return self.__add__(days) def clone(self): """return a cloned instance of this normalDate""" return self.__class__(self.normalDate) def __lt__(self,other): if not hasattr(other,'normalDate'): return False return self.normalDate < other.normalDate def __le__(self,other): if not hasattr(other,'normalDate'): return False return self.normalDate <= other.normalDate def __eq__(self,other): if not hasattr(other,'normalDate'): return False return self.normalDate == other.normalDate def __ne__(self,other): if not hasattr(other,'normalDate'): return True return self.normalDate != other.normalDate def __ge__(self,other): if not hasattr(other,'normalDate'): return True return self.normalDate >= other.normalDate def __gt__(self,other): if not hasattr(other,'normalDate'): return True return self.normalDate > other.normalDate def day(self): """return the day as integer 1-31""" return int(repr(self.normalDate)[-2:]) def dayOfWeek(self): """return integer representing day of week, Mon=0, Tue=1, etc.""" return dayOfWeek(*self.toTuple()) @property def __day_of_week_name__(self): return getattr(self,'_dayOfWeekName',_dayOfWeekName) def dayOfWeekAbbrev(self): """return day of week abbreviation for current date: Mon, Tue, etc.""" return self.__day_of_week_name__[self.dayOfWeek()][:3] def dayOfWeekName(self): """return day of week name for current date: Monday, Tuesday, etc.""" return self.__day_of_week_name__[self.dayOfWeek()] def dayOfYear(self): """day of year""" if self.isLeapYear(): daysByMonth = _daysInMonthLeapYear else: daysByMonth = _daysInMonthNormal priorMonthDays = 0 for m in range(self.month() - 1): priorMonthDays = priorMonthDays + daysByMonth[m] return self.day() + priorMonthDays def daysBetweenDates(self, normalDate): """ return value may be negative, since calculation is self.scalar() - arg """ if isinstance(normalDate,NormalDate): return self.scalar() - normalDate.scalar() else: return self.scalar() - NormalDate(normalDate).scalar() def equals(self, target): if isinstance(target,NormalDate): if target is None: return self.normalDate is None else: return self.normalDate == target.normalDate else: return 0 def endOfMonth(self): """returns (cloned) last day of month""" return self.__class__(self.__repr__()[-8:-2]+str(self.lastDayOfMonth())) def firstDayOfMonth(self): """returns (cloned) first day of month""" return self.__class__(self.__repr__()[-8:-2]+"01") def formatUS(self): """return date as string in common US format: MM/DD/YY""" d = self.__repr__() return "%s/%s/%s" % (d[-4:-2], d[-2:], d[-6:-4]) def formatUSCentury(self): """return date as string in 4-digit year US format: MM/DD/YYYY""" d = self.__repr__() return "%s/%s/%s" % (d[-4:-2], d[-2:], d[-8:-4]) def _fmtM(self): return str(self.month()) def _fmtMM(self): return '%02d' % self.month() def _fmtMMM(self): return self.monthAbbrev() def _fmtMMMM(self): return self.monthName() def _fmtMMMMM(self): return self.monthName()[0] def _fmtD(self): return str(self.day()) def _fmtDD(self): return '%02d' % self.day() def _fmtDDD(self): return self.dayOfWeekAbbrev() def _fmtDDDD(self): return self.dayOfWeekName() def _fmtYY(self): return '%02d' % (self.year()%100) def _fmtYYYY(self): return str(self.year()) def formatMS(self,fmt): '''format like MS date using the notation {YY} --> 2 digit year {YYYY} --> 4 digit year {M} --> month as digit {MM} --> 2 digit month {MMM} --> abbreviated month name {MMMM} --> monthname {MMMMM} --> first character of monthname {D} --> day of month as digit {DD} --> 2 digit day of month {DDD} --> abrreviated weekday name {DDDD} --> weekday name ''' r = fmt[:] f = 0 while 1: m = _fmtPat.search(r,f) if m: y = getattr(self,'_fmt'+(m.group()[1:-1].upper()))() i, j = m.span() r = (r[0:i] + y) + r[j:] f = i + len(y) else: return r def __getstate__(self): """minimize persistent storage requirements""" return self.normalDate def __hash__(self): return hash(self.normalDate) def __int__(self): return self.normalDate def isLeapYear(self): """ determine if specified year is leap year, returning true (1) or false (0) """ return isLeapYear(self.year()) def _isValidNormalDate(self, normalDate): """checks for date validity in [-]yyyymmdd format""" if not isinstance(normalDate,int): return 0 if len(repr(normalDate)) > 9: return 0 if normalDate < 0: dateStr = "%09d" % normalDate else: dateStr = "%08d" % normalDate if len(dateStr) < 8: return 0 elif len(dateStr) == 9: if (dateStr[0] != '-' and dateStr[0] != '+'): return 0 year = int(dateStr[:-4]) if year < -9999 or year > 9999 or year == 0: return 0 # note: zero (0) is not a valid year month = int(dateStr[-4:-2]) if month < 1 or month > 12: return 0 if isLeapYear(year): maxDay = _daysInMonthLeapYear[month - 1] else: maxDay = _daysInMonthNormal[month - 1] day = int(dateStr[-2:]) if day < 1 or day > maxDay: return 0 if year == 1582 and month == 10 and day > 4 and day < 15: return 0 # special case of 10 days dropped: Oct 5-14, 1582 return 1 def lastDayOfMonth(self): """returns last day of the month as integer 28-31""" if self.isLeapYear(): return _daysInMonthLeapYear[self.month() - 1] else: return _daysInMonthNormal[self.month() - 1] def localeFormat(self): """override this method to use your preferred locale format""" return self.formatUS() def month(self): """returns month as integer 1-12""" return int(repr(self.normalDate)[-4:-2]) @property def __month_name__(self): return getattr(self,'_monthName',_monthName) def monthAbbrev(self): """returns month as a 3-character abbreviation, i.e. Jan, Feb, etc.""" return self.__month_name__[self.month() - 1][:3] def monthName(self): """returns month name, i.e. January, February, etc.""" return self.__month_name__[self.month() - 1] def normalize(self, scalar): """convert scalar to normalDate""" if scalar < _bigBangScalar: msg = "normalize(%d): scalar below minimum" % \ _bigBangScalar raise NormalDateException(msg) if scalar > _bigCrunchScalar: msg = "normalize(%d): scalar exceeds maximum" % \ _bigCrunchScalar raise NormalDateException(msg) from math import floor if scalar >= -115860: year = 1600 + int(floor((scalar + 109573) / 365.2425)) elif scalar >= -693597: year = 4 + int(floor((scalar + 692502) / 365.2425)) else: year = -4 + int(floor((scalar + 695058) / 365.2425)) days = scalar - firstDayOfYear(year) + 1 if days <= 0: year = year - 1 days = scalar - firstDayOfYear(year) + 1 daysInYear = 365 if isLeapYear(year): daysInYear = daysInYear + 1 if days > daysInYear: year = year + 1 days = scalar - firstDayOfYear(year) + 1 # add 10 days if between Oct 15, 1582 and Dec 31, 1582 if (scalar >= -115860 and scalar <= -115783): days = days + 10 if isLeapYear(year): daysByMonth = _daysInMonthLeapYear else: daysByMonth = _daysInMonthNormal dc = 0; month = 12 for m in range(len(daysByMonth)): dc = dc + daysByMonth[m] if dc >= days: month = m + 1 break # add up the days in prior months priorMonthDays = 0 for m in range(month - 1): priorMonthDays = priorMonthDays + daysByMonth[m] day = days - priorMonthDays self.setNormalDate((year, month, day)) def range(self, days): """Return a range of normalDates as a list. Parameter may be an int or normalDate.""" if not isinstance(days,int): days = days - self # if not int, assume arg is normalDate type r = [] for i in range(days): r.append(self + i) return r def __repr__(self): """print format: [-]yyyymmdd""" # Note: When disassembling a NormalDate string, be sure to # count from the right, i.e. epochMonth = int(repr(Epoch)[-4:-2]), # or the slice won't work for dates B.C. if self.normalDate < 0: return "%09d" % self.normalDate else: return "%08d" % self.normalDate def scalar(self): """days since baseline date: Jan 1, 1900""" (year, month, day) = self.toTuple() days = firstDayOfYear(year) + day - 1 if self.isLeapYear(): for m in range(month - 1): days = days + _daysInMonthLeapYear[m] else: for m in range(month - 1): days = days + _daysInMonthNormal[m] if year == 1582: if month > 10 or (month == 10 and day > 4): days = days - 10 return days def setDay(self, day): """set the day of the month""" maxDay = self.lastDayOfMonth() if day < 1 or day > maxDay: msg = "day is outside of range 1 to %d" % maxDay raise NormalDateException(msg) (y, m, d) = self.toTuple() self.setNormalDate((y, m, day)) def setMonth(self, month): """set the month [1-12]""" if month < 1 or month > 12: raise NormalDateException('month is outside range 1 to 12') (y, m, d) = self.toTuple() self.setNormalDate((y, month, d)) def setNormalDate(self, normalDate): """ accepts date as scalar string/integer (yyyymmdd) or tuple (year, month, day, ...)""" if isinstance(normalDate,int): self.normalDate = normalDate elif isStr(normalDate): try: self.normalDate = int(normalDate) except: m = _iso_re.match(normalDate) if m: self.setNormalDate(m.group(1)+m.group(2)+m.group(3)) else: raise NormalDateException("unable to setNormalDate(%s)" % repr(normalDate)) elif isinstance(normalDate,_DateSeqTypes): self.normalDate = int("%04d%02d%02d" % normalDate[:3]) elif isinstance(normalDate,NormalDate): self.normalDate = normalDate.normalDate elif isinstance(normalDate,(datetime.datetime,datetime.date)): self.normalDate = (normalDate.year*100+normalDate.month)*100+normalDate.day else: self.normalDate = None if not self._isValidNormalDate(self.normalDate): raise NormalDateException("unable to setNormalDate(%s)" % repr(normalDate)) def setYear(self, year): if year == 0: raise NormalDateException('cannot set year to zero') elif year < -9999: raise NormalDateException('year cannot be less than -9999') elif year > 9999: raise NormalDateException('year cannot be greater than 9999') (y, m, d) = self.toTuple() self.setNormalDate((year, m, d)) __setstate__ = setNormalDate def __sub__(self, v): if isinstance(v,int): return self.__add__(-v) return self.scalar() - v.scalar() def __rsub__(self,v): if isinstance(v,int): return NormalDate(v) - self else: return v.scalar() - self.scalar() def toTuple(self): """return date as (year, month, day) tuple""" return (self.year(), self.month(), self.day()) def year(self): """return year in yyyy format, negative values indicate B.C.""" return int(repr(self.normalDate)[:-4]) ################# Utility functions ################# def bigBang(): """return lower boundary as a NormalDate""" return NormalDate((-9999, 1, 1)) def bigCrunch(): """return upper boundary as a NormalDate""" return NormalDate((9999, 12, 31)) def dayOfWeek(y, m, d): """return integer representing day of week, Mon=0, Tue=1, etc.""" if m == 1 or m == 2: m = m + 12 y = y - 1 return (d + 2*m + 3*(m+1)//5 + y + y//4 - y//100 + y//400) % 7 def firstDayOfYear(year): """number of days to the first of the year, relative to Jan 1, 1900""" if not isinstance(year,int): msg = "firstDayOfYear() expected integer, got %s" % type(year) raise NormalDateException(msg) if year == 0: raise NormalDateException('first day of year cannot be zero (0)') elif year < 0: # BCE calculation firstDay = (year * 365) + int((year - 1) / 4) - 693596 else: # CE calculation leapAdjust = int((year + 3) / 4) if year > 1600: leapAdjust = leapAdjust - int((year + 99 - 1600) / 100) + \ int((year + 399 - 1600) / 400) firstDay = year * 365 + leapAdjust - 693963 if year > 1582: firstDay = firstDay - 10 return firstDay def FND(d): '''convert to ND if required''' return isinstance(d,NormalDate) and d or ND(d) Epoch=bigBang() ND=NormalDate BDEpoch=ND(15821018) BDEpochScalar = -115857 class BusinessDate(NormalDate): """ Specialised NormalDate """ def add(self, days): """add days to date; use negative integers to subtract""" if not isinstance(days,int): raise NormalDateException('add method parameter must be integer') self.normalize(self.scalar() + days) def __add__(self, days): """add integer to BusinessDate and return a new, calculated value""" if not isinstance(days,int): raise NormalDateException('__add__ parameter must be integer') cloned = self.clone() cloned.add(days) return cloned def __sub__(self, v): return isinstance(v,int) and self.__add__(-v) or self.scalar() - v.scalar() def asNormalDate(self): return ND(self.normalDate) def daysBetweenDates(self, normalDate): return self.asNormalDate.daysBetweenDates(normalDate) def _checkDOW(self): if self.dayOfWeek()>4: raise NormalDateException("%r isn't a business day" % self.normalDate) def normalize(self, i): i = int(i) NormalDate.normalize(self,(i//5)*7+i%5+BDEpochScalar) def scalar(self): d = self.asNormalDate() i = d - BDEpoch #luckily BDEpoch is a Monday so we don't have a problem #concerning the relative weekday return 5*(i//7) + i%7 def setNormalDate(self, normalDate): NormalDate.setNormalDate(self,normalDate) self._checkDOW() if __name__ == '__main__': today = NormalDate() print("NormalDate test:") print(" Today (%s) is: %s %s" % (today, today.dayOfWeekAbbrev(), today.localeFormat())) yesterday = today - 1 print(" Yesterday was: %s %s" % (yesterday.dayOfWeekAbbrev(), yesterday.localeFormat())) tomorrow = today + 1 print(" Tomorrow will be: %s %s" % (tomorrow.dayOfWeekAbbrev(), tomorrow.localeFormat())) print(" Days between tomorrow and yesterday: %d" % (tomorrow - yesterday)) print(today.formatMS('{d}/{m}/{yy}')) print(today.formatMS('{dd}/{m}/{yy}')) print(today.formatMS('{ddd} {d}/{m}/{yy}')) print(today.formatMS('{dddd} {d}/{m}/{yy}')) print(today.formatMS('{d}/{mm}/{yy}')) print(today.formatMS('{d}/{mmm}/{yy}')) print(today.formatMS('{d}/{mmmm}/{yy}')) print(today.formatMS('{d}/{m}/{yyyy}')) b = BusinessDate('20010116') print('b=',b,'b.scalar()', b.scalar()) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1691062243.0 reportlab-4.1.0/src/reportlab/lib/pagesizes.py0000664000175000017500000000372114462707743021016 0ustar00rptlabrptlab#!/bin/env python #Copyright ReportLab Europe Ltd. 2000-2017 #see license.txt for license details #history https://hg.reportlab.com/hg-public/reportlab/log/tip/src/reportlab/lib/pagesizes.py """This module defines a few common page sizes in points (1/72 inch). To be expanded to include things like label sizes, envelope windows etc.""" __version__='3.4.18' from reportlab.lib.units import mm, inch #ISO 216 standard paer sizes; see eg https://en.wikipedia.org/wiki/ISO_216 A0 = (841*mm,1189*mm) A1 = (594*mm,841*mm) A2 = (420*mm,594*mm) A3 = (297*mm,420*mm) A4 = (210*mm,297*mm) A5 = (148*mm,210*mm) A6 = (105*mm,148*mm) A7 = (74*mm,105*mm) A8 = (52*mm,74*mm) A9 = (37*mm,52*mm) A10 = (26*mm,37*mm) B0 = (1000*mm,1414*mm) B1 = (707*mm,1000*mm) B2 = (500*mm,707*mm) B3 = (353*mm,500*mm) B4 = (250*mm,353*mm) B5 = (176*mm,250*mm) B6 = (125*mm,176*mm) B7 = (88*mm,125*mm) B8 = (62*mm,88*mm) B9 = (44*mm,62*mm) B10 = (31*mm,44*mm) C0 = (917*mm,1297*mm) C1 = (648*mm,917*mm) C2 = (458*mm,648*mm) C3 = (324*mm,458*mm) C4 = (229*mm,324*mm) C5 = (162*mm,229*mm) C6 = (114*mm,162*mm) C7 = (81*mm,114*mm) C8 = (57*mm,81*mm) C9 = (40*mm,57*mm) C10 = (28*mm,40*mm) #American paper sizes LETTER = (8.5*inch, 11*inch) LEGAL = (8.5*inch, 14*inch) ELEVENSEVENTEEN = (11*inch, 17*inch) # From https://en.wikipedia.org/wiki/Paper_size JUNIOR_LEGAL = (5*inch, 8*inch) HALF_LETTER = (5.5*inch, 8*inch) GOV_LETTER = (8*inch, 10.5*inch) GOV_LEGAL = (8.5*inch, 13*inch) TABLOID = ELEVENSEVENTEEN LEDGER = (17*inch, 11*inch) # lower case is deprecated as of 12/2001, but here # for compatability letter=LETTER legal=LEGAL elevenSeventeen = ELEVENSEVENTEEN #functions to mess with pagesizes def landscape(pagesize): """Use this to get page orientation right""" a, b = pagesize if a < b: return (b, a) else: return (a, b) def portrait(pagesize): """Use this to get page orientation right""" a, b = pagesize if a >= b: return (b, a) else: return (a, b) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1691062243.0 reportlab-4.1.0/src/reportlab/lib/pdfencrypt.py0000664000175000017500000007375314462707743021216 0ustar00rptlabrptlab#copyright ReportLab Europe Limited. 2000-2016 #see license.txt for license details __version__='3.3.0' """helpers for pdf encryption/decryption""" import sys, os from binascii import hexlify, unhexlify from hashlib import md5 from io import BytesIO from reportlab.lib.utils import asBytes, int2Byte, rawBytes, asNative from reportlab.pdfgen.canvas import Canvas from reportlab.pdfbase.pdfdoc import PDFObject from reportlab.platypus.flowables import Flowable from reportlab import rl_config try: import pyaes from hashlib import sha256 except ImportError: pyaes = None def xorKey(num,key): "xor's each byte of the key with the number, which is <256" if num==0: return key return bytes(num^k for k in key) #AR debug hooks - leaving in for now CLOBBERID = 0 # set a constant Doc ID to allow comparison with other software like iText CLOBBERPERMISSIONS = 0 DEBUG = rl_config.debug # print stuff to trace calculations # permission bits reserved1 = 1 # bit 1 must be 0 reserved2 = 1<<1 # bit 2 must be 0 printable = 1<<2 modifiable = 1<<3 copypastable = 1<<4 annotatable = 1<<5 # others [7..32] are reserved, must be 1 higherbits = 0 for i in range(6,31): higherbits = higherbits | (1<\x99\x89i\xf7\xc4\xb4\'\xe9k\xc9\xfa\xa6p\x80\xcd\xaa\xaf|\x97\xf7\xcc \xc1\xef\xc7\x97\xd2;\xaf\xe1\xfc\x16,\xd3\x0b\x19\xa1\x02\xe6\x01\xcb\x1c\xd8\xe6\\H}\r\xdc\x85\xe1\xbc\xc4\x02>|\xc5\x97\xb5T\xad\x0cT\x95\xb1\xdc!\xb6+E#\xa1\xa4O\xf3j\x98"\xc2\x1a\xcb\x8cHB\xd8B~\xa7\x7f7\xd2\xe8\x131.\xd7\xa9\x0b\r\xdd2\x0b}\xc0\xffm\x9e3\xe2/\xea\x84W\x82\xbd\xc8K\xc2;?\xbe#\x84`W\xf3\xe0\xec\x9e\x85\x9c\xcb\xc7\xc9#\x19\xff\xde\x17\xea\xb2\xd4\x0e\x9a\xbd\xbaz\xbd\x87O\xd4\xf4\xac\xb3(z\x92\xfc\xbc\x85i\x8d\x1f\xfb!\t|w,\x8bI\xc9_D`A\xbc}\x0e+r\x1b-%F(@\xc8\\cL\x172(\x9c\x95BM\xa1\x89UG\x9d\xfd\xed\xce\xd8\x1f\xb1' def os_urandom(n): global _os_random_x b = [_os_random_b[(i+_os_random_x)%256] for i in range(n)] b = bytes(b) _os_random_x = (_os_random_x + n) % 256 return b else: os_urandom = os.urandom # no encryption class StandardEncryption: prepared = 0 def __init__(self, userPassword, ownerPassword=None, canPrint=1, canModify=1, canCopy=1, canAnnotate=1, strength=None): ''' This class defines the encryption properties to be used while creating a pdf document. Once initiated, a StandardEncryption object can be applied to a Canvas or a BaseDocTemplate. The userPassword parameter sets the user password on the encrypted pdf. The ownerPassword parameter sets the owner password on the encrypted pdf. The boolean flags canPrint, canModify, canCopy, canAnnotate determine wether a user can perform the corresponding actions on the pdf when only a user password has been supplied. If the user supplies the owner password while opening the pdf, all actions can be performed regardless of the flags. Note that the security provided by these encryption settings (and even more so for the flags) is very weak. ''' self.userPassword = userPassword if ownerPassword: self.ownerPassword = ownerPassword else: self.ownerPassword = userPassword if strength is None: strength = rl_config.encryptionStrength if strength == 40: self.revision = 2 elif strength == 128: self.revision = 3 elif strength == 256: if not pyaes: raise ValueError('strength==256 is not supported as package pyaes is not importable') self.revision = 5 else: raise ValueError('Unknown encryption strength=%s' % repr(strength)) self.canPrint = canPrint self.canModify = canModify self.canCopy = canCopy self.canAnnotate = canAnnotate self.O = self.U = self.P = self.key = self.OE = self.UE = self.Perms = None def setAllPermissions(self, value): self.canPrint = \ self.canModify = \ self.canCopy = \ self.canAnnotate = value def permissionBits(self): p = 0 if self.canPrint: p = p | printable if self.canModify: p = p | modifiable if self.canCopy: p = p | copypastable if self.canAnnotate: p = p | annotatable p = p | higherbits return p def encode(self, t): "encode a string, stream, text" if not self.prepared: raise ValueError("encryption not prepared!") if self.objnum is None: raise ValueError("not registered in PDF object") return encodePDF(self.key, self.objnum, self.version, t, revision=self.revision) def prepare(self, document, overrideID=None): # get ready to do encryption if DEBUG: print('StandardEncryption.prepare(...) - revision %d' % self.revision) if self.prepared: raise ValueError("encryption already prepared!") # get the unescaped string value of the document id (first array element). # we allow one to be passed in instead to permit reproducible tests # of our algorithm, but in real life overrideID will always be None if overrideID: internalID = overrideID else: externalID = document.ID() # initialize it... internalID = document.signature.digest() #AR debugging if CLOBBERID: internalID = "xxxxxxxxxxxxxxxx" if DEBUG: print('userPassword = %r' % self.userPassword) print('ownerPassword = %r' % self.ownerPassword) print('internalID = %r' % internalID) self.P = int(self.permissionBits() - 2**31) if CLOBBERPERMISSIONS: self.P = -44 # AR hack if DEBUG: print("self.P = %s" % repr(self.P)) if self.revision == 5: # Init vectro for AES cipher (should be 16 bytes null array) iv = b'\x00' * 16 # Random User salts uvs = os_urandom(8) uks = os_urandom(8) # the main encryption key self.key = asBytes(os_urandom(32)) if DEBUG: print("uvs (hex) = %s" % hexText(uvs)) print("uks (hex) = %s" % hexText(uks)) print("self.key (hex) = %s" % hexText(self.key)) # Calculate the sha-256 hash of the User password (U) md = sha256(asBytes(self.userPassword[:127]) + uvs) self.U = md.digest() + uvs + uks if DEBUG: print("self.U (hex) = %s" % hexText(self.U)) # Calculate the User encryption key (UE) md = sha256(asBytes(self.userPassword[:127]) + uks) encrypter = pyaes.Encrypter(pyaes.AESModeOfOperationCBC(md.digest(), iv=iv)) self.UE = encrypter.feed(self.key) self.UE += encrypter.feed() if DEBUG: print("self.UE (hex) = %s" % hexText(self.UE)) # Random Owner salts ovs = os_urandom(8) oks = os_urandom(8) # Calculate the hash of the Owner password (U) md = sha256(asBytes(self.ownerPassword[:127]) + ovs + self.U ) self.O = md.digest() + ovs + oks if DEBUG: print("self.O (hex) = %s" % hexText(self.O)) # Calculate the User encryption key (OE) md = sha256(asBytes(self.ownerPassword[:127]) + oks + self.U) encrypter = pyaes.Encrypter(pyaes.AESModeOfOperationCBC(md.digest(), iv=iv)) self.OE = encrypter.feed(self.key) self.OE += encrypter.feed() if DEBUG: print("self.OE (hex) = %s" % hexText(self.OE)) # Compute permissions array permsarr = [ self.P & 0xFF, # store the permission value in the first 32-bits self.P >> 8 & 0xFF, self.P >> 16 & 0xFF, self.P >> 24 & 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, ord('T'), # 'T' if EncryptMetaData is True (default), 'F' otherwise ord('a'), # a, d, b are magic values ord('d'), ord('b'), 0x01, # trailing zeros will be ignored 0x01, 0x01, 0x01 ] # the permission array should be enrypted in the Perms field encrypter = pyaes.Encrypter(pyaes.AESModeOfOperationCBC(self.key, iv=iv)) self.Perms = encrypter.feed(bytes(permsarr)) self.Perms += encrypter.feed() if DEBUG: print("self.Perms (hex) = %s" % hexText(self.Perms)) elif self.revision in (2, 3): self.O = computeO(self.userPassword, self.ownerPassword, self.revision) if DEBUG: print("self.O (as hex) = %s" % hexText(self.O)) #print "\nself.O", self.O, repr(self.O) self.key = encryptionkey(self.userPassword, self.O, self.P, internalID, revision=self.revision) if DEBUG: print("self.key (hex) = %s" % hexText(self.key)) self.U = computeU(self.key, revision=self.revision, documentId=internalID) if DEBUG: print("self.U (as hex) = %s" % hexText(self.U)) self.objnum = self.version = None self.prepared = 1 def register(self, objnum, version): # enter a new direct object if not self.prepared: raise ValueError("encryption not prepared!") self.objnum = objnum self.version = version def info(self): # the representation of self in file if any (should be None or PDFDict) if not self.prepared: raise ValueError("encryption not prepared!") return StandardEncryptionDictionary(O=self.O, OE=self.OE, U=self.U, UE=self.UE, P=self.P, Perms=self.Perms, revision=self.revision) class StandardEncryptionDictionary(PDFObject): __RefOnly__ = 1 def __init__(self, O, OE, U, UE, P, Perms, revision): self.O, self.OE, self.U, self.UE, self.P, self.Perms = O, OE, U, UE, P, Perms self.revision = revision def format(self, document): # use a dummy document to bypass encryption from reportlab.pdfbase.pdfdoc import DummyDoc, PDFDictionary, PDFName dummy = DummyDoc() dict = {"Filter": PDFName("Standard"), "O": hexText(self.O), "U": hexText(self.U), "P": self.P} if self.revision == 5: dict['Length'] = 256 dict['R'] = 5 dict['V'] = 5 dict['O'] = hexText(self.O) dict['U'] = hexText(self.U) dict['OE'] = hexText(self.OE) dict['UE'] = hexText(self.UE) dict['Perms'] = hexText(self.Perms) dict['StrF'] = PDFName("StdCF") dict['StmF'] = PDFName("StdCF") stdcf = { "Length": 32, "AuthEvent": PDFName("DocOpen"), "CFM": PDFName("AESV3") } cf = { "StdCF": PDFDictionary(stdcf) } dict['CF'] = PDFDictionary(cf) elif self.revision == 3: dict['Length'] = 128 dict['R'] = 3 dict['V'] = 2 else: dict['R'] = 2 dict['V'] = 1 pdfdict = PDFDictionary(dict) return pdfdict.format(dummy) # from pdf spec padding = """ 28 BF 4E 5E 4E 75 8A 41 64 00 4E 56 FF FA 01 08 2E 2E 00 B6 D0 68 3E 80 2F 0C A9 FE 64 53 69 7A """ def hexText(text): "a legitimate way to show strings in PDF" return '<%s>' % asNative(hexlify(rawBytes(text))).upper() def unHexText(hexText): equalityCheck(hexText[0], '<', 'bad hex text') equalityCheck(hexText[-1], '>', 'bad hex text') return unhexlify(hexText[1:-1]) PadString = rawBytes(''.join(chr(int(c, 16)) for c in padding.strip().split())) def checkRevision(revision): if revision is None: strength = rl_config.encryptionStrength if strength == 40: revision = 2 elif strength == 128: revision = 3 elif strength == 256: if not pyaes: raise ValueError('strength==256 is not supported as package pyaes is not importable') revision = 5 else: raise ValueError('Unknown encryption strength=%s' % repr(strength)) return revision def encryptionkey(password, OwnerKey, Permissions, FileId1, revision=None): revision = checkRevision(revision) # FileId1 is first string of the fileid array # add padding string #AR force same as iText example #Permissions = -1836 #int(Permissions - 2**31) password = asBytes(password) + PadString # truncate to 32 bytes password = password[:32] # translate permissions to string, low order byte first p = Permissions# + 2**32L permissionsString = b"" for i in range(4): byte = (p & 0xff) # seems to match what iText does p = p>>8 permissionsString += int2Byte(byte % 256) hash = md5(asBytes(password)) hash.update(asBytes(OwnerKey)) hash.update(asBytes(permissionsString)) hash.update(asBytes(FileId1)) md5output = hash.digest() if revision==2: key = md5output[:5] elif revision==3: #revision 3 algorithm - loop 50 times for x in range(50): md5output = md5(md5output).digest() key = md5output[:16] if DEBUG: print('encryptionkey(%s,%s,%s,%s,%s)==>%s' % tuple([hexText(str(x)) for x in (password, OwnerKey, Permissions, FileId1, revision, key)])) return key def computeO(userPassword, ownerPassword, revision): from reportlab.lib.arciv import ArcIV #print 'digest of hello is %s' % md5('hello').digest() assert revision in (2,3), 'Unknown algorithm revision %s' % revision if not ownerPassword: ownerPassword = userPassword ownerPad = asBytes(ownerPassword) + PadString ownerPad = ownerPad[0:32] password = asBytes(userPassword) + PadString userPad = password[:32] digest = md5(ownerPad).digest() if DEBUG: print('PadString=%s\nownerPad=%s\npassword=%s\nuserPad=%s\ndigest=%s\nrevision=%s' % (ascii(PadString),ascii(ownerPad),ascii(password),ascii(userPad),ascii(digest),revision)) if revision == 2: O = ArcIV(digest[:5]).encode(userPad) elif revision == 3: for i in range(50): digest = md5(digest).digest() digest = digest[:16] O = userPad for i in range(20): thisKey = xorKey(i, digest) O = ArcIV(thisKey).encode(O) if DEBUG: print('computeO(%s,%s,%s)==>%s' % tuple([hexText(str(x)) for x in (userPassword, ownerPassword, revision,O)])) return O def computeU(encryptionkey, encodestring=PadString,revision=None,documentId=None): revision = checkRevision(revision) from reportlab.lib.arciv import ArcIV if revision == 2: result = ArcIV(encryptionkey).encode(encodestring) elif revision == 3: assert documentId is not None, "Revision 3 algorithm needs the document ID!" h = md5(PadString) h.update(rawBytes(documentId)) tmp = h.digest() tmp = ArcIV(encryptionkey).encode(tmp) for n in range(1,20): thisKey = xorKey(n, encryptionkey) tmp = ArcIV(thisKey).encode(tmp) while len(tmp) < 32: tmp += b'\0' result = tmp if DEBUG: print('computeU(%s,%s,%s,%s)==>%s' % tuple([hexText(str(x)) for x in (encryptionkey, encodestring,revision,documentId,result)])) return result def checkU(encryptionkey, U): decoded = computeU(encryptionkey, U) #print len(decoded), len(U), len(PadString) if decoded!=PadString: if len(decoded)!=len(PadString): raise ValueError("lengths don't match! (password failed)") raise ValueError("decode of U doesn't match fixed padstring (password failed)") def encodePDF(key, objectNumber, generationNumber, string, revision=None): "Encodes a string or stream" revision = checkRevision(revision) #print 'encodePDF (%s, %d, %d, %s)' % (hexText(key), objectNumber, generationNumber, string) # extend 3 bytes of the object Number, low byte first if revision in (2,3): newkey = key n = objectNumber for i in range(3): newkey += int2Byte(n & 0xff) n = n>>8 # extend 2 bytes of the generationNumber n = generationNumber for i in range(2): newkey += int2Byte(n & 0xff) n = n>>8 md5output = md5(newkey).digest() if revision == 2: key = md5output[:10] elif revision == 3: key = md5output #all 16 bytes from reportlab.lib.arciv import ArcIV encrypted = ArcIV(key).encode(string) #print 'encrypted=', hexText(encrypted) elif revision == 5: iv = os_urandom(16) encrypter = pyaes.Encrypter(pyaes.AESModeOfOperationCBC(key, iv=iv)) # pkcs7 style padding so that the size of the encrypted block is multiple of 16 string_len = len(string) padding = "" padding_len = (16 - (string_len % 16)) if string_len > 16 else (16 - string_len) if padding_len > 0: padding = chr(padding_len) * padding_len if isinstance(string, str): string = (string + padding).encode("utf-8") else: string += asBytes(padding) encrypted = iv + encrypter.feed(string) encrypted += encrypter.feed() if DEBUG: print('encodePDF(%s,%s,%s,%s,%s)==>%s' % tuple([hexText(str(x)) for x in (key, objectNumber, generationNumber, string, revision,encrypted)])) return encrypted def equalityCheck(observed,expected,label): assert observed==expected,'%s\n expected=%s\n observed=%s' % (label,expected,observed) ###################################################################### # # quick tests of algorithm, should be moved elsewhere # ###################################################################### def test(): # do a 40 bit example known to work in Acrobat Reader 4.0 enc = StandardEncryption('User','Owner', strength=40) enc.prepare(None, overrideID='xxxxxxxxxxxxxxxx') expectedO = '' expectedU = '<09F26CF46190AF8F93B304AD50C16B615DC43C228C9B2D2EA34951A80617B2B1>' expectedKey = '' # 5 byte key = 40 bits equalityCheck(hexText(enc.O),expectedO, '40 bit O value') equalityCheck(hexText(enc.U),expectedU, '40 bit U value') equalityCheck(hexText(enc.key),expectedKey, '40 bit key value') # now for 128 bit example enc = StandardEncryption('userpass','ownerpass', strength=128) enc.prepare(None, overrideID = 'xxxxxxxxxxxxxxxx') expectedO = '<68E5704AC779A5F0CD89704406587A52F25BF61CADC56A0F8DB6C4DB0052534D>' expectedU = '' expectedKey = '<13DDE7585D9BE366C976DDD56AF541D1>' # 16 byte key = 128 bits equalityCheck(hexText(enc.O), expectedO, '128 bit O value') equalityCheck(hexText(enc.U), expectedU, '128 bit U value') equalityCheck(hexText(enc.key), expectedKey, '128 key value') ###################################################################### # # These represent the higher level API functions # ###################################################################### def encryptCanvas(canvas, userPassword, ownerPassword=None, canPrint=1, canModify=1, canCopy=1, canAnnotate=1, strength=40): "Applies encryption to the document being generated" enc = StandardEncryption(userPassword, ownerPassword, canPrint, canModify, canCopy, canAnnotate, strength=strength) canvas._doc.encrypt = enc # Platypus stuff needs work, sadly. I wanted to do it without affecting # needing changes to latest release. class EncryptionFlowable(StandardEncryption, Flowable): """Drop this in your Platypus story and it will set up the encryption options. If you do it multiple times, the last one before saving will win.""" def wrap(self, availWidth, availHeight): return (0,0) def draw(self): encryptCanvas(self.canv, self.userPassword, self.ownerPassword, self.canPrint, self.canModify, self.canCopy, self.canAnnotate) ## I am thinking about this one. Needs a change to reportlab to ## work. def encryptDocTemplate(dt, userPassword, ownerPassword=None, canPrint=1, canModify=1, canCopy=1, canAnnotate=1, strength=40): "For use in Platypus. Call before build()." raise Exception("Not implemented yet") def encryptPdfInMemory(inputPDF, userPassword, ownerPassword=None, canPrint=1, canModify=1, canCopy=1, canAnnotate=1, strength=40): """accepts a PDF file 'as a byte array in memory'; return encrypted one. This is a high level convenience and does not touch the hard disk in any way. If you are encrypting the same file over and over again, it's better to use pageCatcher and cache the results.""" try: from rlextra.pageCatcher.pageCatcher import storeFormsInMemory, restoreFormsInMemory except ImportError: raise ImportError('''reportlab.lib.pdfencrypt.encryptPdfInMemory failed because rlextra cannot be imported. See https://www.reportlab.com/downloads''') (bboxInfo, pickledForms) = storeFormsInMemory(inputPDF, all=1, BBoxes=1) names = list(bboxInfo.keys()) firstPageSize = bboxInfo['PageForms0'][2:] #now make a new PDF document buf = BytesIO() canv = Canvas(buf, pagesize=firstPageSize) # set a standard ID while debugging if CLOBBERID: canv._doc._ID = "[(xxxxxxxxxxxxxxxx)(xxxxxxxxxxxxxxxx)]" formNames = restoreFormsInMemory(pickledForms, canv) for formName in formNames: canv.setPageSize(bboxInfo[formName][2:]) canv.doForm(formName) canv.showPage() encryptCanvas(canv, userPassword, ownerPassword, canPrint, canModify, canCopy, canAnnotate, strength=strength) canv.save() return buf.getvalue() def encryptPdfOnDisk(inputFileName, outputFileName, userPassword, ownerPassword=None, canPrint=1, canModify=1, canCopy=1, canAnnotate=1, strength=40): "Creates encrypted file OUTPUTFILENAME. Returns size in bytes." inputPDF = open(inputFileName, 'rb').read() outputPDF = encryptPdfInMemory(inputPDF, userPassword, ownerPassword, canPrint, canModify, canCopy, canAnnotate, strength=strength) open(outputFileName, 'wb').write(outputPDF) return len(outputPDF) def scriptInterp(): sys_argv = sys.argv[:] # copy usage = """PDFENCRYPT USAGE: PdfEncrypt encrypts your PDF files. Line mode usage: % pdfencrypt.exe pdffile [-o ownerpassword] | [owner ownerpassword], \t[-u userpassword] | [user userpassword], \t[-p 1|0] | [printable 1|0], \t[-m 1|0] | [modifiable 1|0], \t[-c 1|0] | [copypastable 1|0], \t[-a 1|0] | [annotatable 1|0], \t[-s savefilename] | [savefile savefilename], \t[-v 1|0] | [verbose 1|0], \t[-e128], [encrypt128], \t[-h] | [help] -o or owner set the owner password. -u or user set the user password. -p or printable set the printable attribute (must be 1 or 0). -m or modifiable sets the modifiable attribute (must be 1 or 0). -c or copypastable sets the copypastable attribute (must be 1 or 0). -a or annotatable sets the annotatable attribute (must be 1 or 0). -s or savefile sets the name for the output PDF file -v or verbose prints useful output to the screen. (this defaults to 'pdffile_encrypted.pdf'). '-e128' or 'encrypt128' allows you to use 128 bit encryption (in beta). '-e256' or 'encrypt256' allows you to use 256 bit encryption (in beta AES). -h or help prints this message. See PdfEncryptIntro.pdf for more information. """ known_modes = ['-o', 'owner', '-u', 'user', '-p', 'printable', '-m', 'modifiable', '-c', 'copypastable', '-a', 'annotatable', '-s', 'savefile', '-v', 'verbose', '-h', 'help', '-e128', 'encrypt128', '-e256', 'encryptAES', ] OWNER = '' USER = '' PRINTABLE = 1 MODIFIABLE = 1 COPYPASTABLE = 1 ANNOTATABLE = 1 SAVEFILE = 'encrypted.pdf' #try: caller = sys_argv[0] # may be required later - eg if called by security.py argv = list(sys_argv)[1:] if len(argv)>0: if argv[0] == '-h' or argv[0] == 'help': print(usage) return if len(argv)<2: raise ValueError("Must include a filename and one or more arguments!") if argv[0] not in known_modes: infile = argv[0] argv = argv[1:] if not os.path.isfile(infile): raise ValueError("Can't open input file '%s'!" % infile) else: raise ValueError("First argument must be name of the PDF input file!") # meaningful name at this stage STRENGTH = 40 for (s,_a) in ((128,('-e128','encrypt128')),(256,('-e256','encrypt256'))): for a in _a: if a in argv: STRENGTH = s argv.remove(a) if ('-v' in argv) or ('verbose' in argv): if '-v' in argv: pos = argv.index('-v') arg = "-v" elif 'verbose' in argv: pos = argv.index('verbose') arg = "verbose" try: verbose = int(argv[pos+1]) except: verbose = 1 argv.remove(argv[pos+1]) argv.remove(arg) else: from reportlab.rl_config import verbose #argument, valid license variable, invalid license variable, text for print arglist = (('-o', 'OWNER', OWNER, 'Owner password'), ('owner', 'OWNER', OWNER, 'Owner password'), ('-u', 'USER', USER, 'User password'), ('user', 'USER', USER, 'User password'), ('-p', 'PRINTABLE', PRINTABLE, "'Printable'"), ('printable', 'PRINTABLE', PRINTABLE, "'Printable'"), ('-m', 'MODIFIABLE', MODIFIABLE, "'Modifiable'"), ('modifiable', 'MODIFIABLE', MODIFIABLE, "'Modifiable'"), ('-c', 'COPYPASTABLE', COPYPASTABLE, "'Copypastable'"), ('copypastable', 'COPYPASTABLE', COPYPASTABLE, "'Copypastable'"), ('-a', 'ANNOTATABLE', ANNOTATABLE, "'Annotatable'"), ('annotatable', 'ANNOTATABLE', ANNOTATABLE, "'Annotatable'"), ('-s', 'SAVEFILE', SAVEFILE, "Output file"), ('savefile', 'SAVEFILE', SAVEFILE, "Output file"), ) binaryrequired = ('-p', 'printable', '-m', 'modifiable', 'copypastable', '-c', 'annotatable', '-a') for thisarg in arglist: if thisarg[0] in argv: pos = argv.index(thisarg[0]) if thisarg[0] in binaryrequired: if argv[pos+1] not in ('1', '0'): raise ValueError("%s value must be either '1' or '0'!" % thisarg[1]) try: if argv[pos+1] not in known_modes: if thisarg[0] in binaryrequired: exec(thisarg[1] +' = int(argv[pos+1])',vars()) else: exec(thisarg[1] +' = argv[pos+1]',vars()) if verbose: print("%s set to: '%s'." % (thisarg[3], argv[pos+1])) argv.remove(argv[pos+1]) argv.remove(thisarg[0]) except: raise "Unable to set %s." % thisarg[3] if verbose>4: #useful if feeling paranoid and need to double check things at this point... print("\ninfile:", infile) print("STRENGTH:", STRENGTH) print("SAVEFILE:", SAVEFILE) print("USER:", USER) print("OWNER:", OWNER) print("PRINTABLE:", PRINTABLE) print("MODIFIABLE:", MODIFIABLE) print("COPYPASTABLE:", COPYPASTABLE) print("ANNOTATABLE:", ANNOTATABLE) print("SAVEFILE:", SAVEFILE) print("VERBOSE:", verbose) if SAVEFILE == 'encrypted.pdf': if infile[-4:] == '.pdf' or infile[-4:] == '.PDF': tinfile = infile[:-4] else: tinfile = infile SAVEFILE = tinfile+"_encrypted.pdf" filesize = encryptPdfOnDisk(infile, SAVEFILE, USER, OWNER, PRINTABLE, MODIFIABLE, COPYPASTABLE, ANNOTATABLE, strength=STRENGTH) if verbose: print("wrote output file '%s'(%s bytes)\n owner password is '%s'\n user password is '%s'" % (SAVEFILE, filesize, OWNER, USER)) if len(argv)>0: raise ValueError("\nUnrecognised arguments : %s\nknown arguments are:\n%s" % (str(argv)[1:-1], known_modes)) else: print(usage) def main(): scriptInterp() if __name__=="__main__": #NO RUNTESTS a = [x for x in sys.argv if x[:7]=='--debug'] if a: sys.argv = [x for x in sys.argv if x[:7]!='--debug'] DEBUG = len(a) if '--test' in sys.argv: test() else: main() ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1691062243.0 reportlab-4.1.0/src/reportlab/lib/pygments2xpre.py0000664000175000017500000000471514462707743021657 0ustar00rptlabrptlab"""Helps you output colourised code snippets in ReportLab documents. Platypus has an 'XPreformatted' flowable for handling preformatted text, with variations in fonts and colors. If Pygments is installed, calling 'pygments2xpre' will return content suitable for display in an XPreformatted object. If it's not installed, you won't get colours. For a list of available lexers see http://pygments.org/docs/ """ __all__ = ('pygments2xpre',) import re from io import StringIO def _2xpre(s,styles): "Helper to transform Pygments HTML output to ReportLab markup" s = s.replace('
','') s = s.replace('
','') s = s.replace('
','')
    s = s.replace('
','') for k,c in styles+[('p','#000000'),('n','#000000'),('err','#000000')]: s = s.replace('' % k,'' % c) s = re.sub(r''% k,'' % c,s) s = re.sub(r'','',s) return s def pygments2xpre(s, language="python"): "Return markup suitable for XPreformatted" try: from pygments import highlight from pygments.formatters import HtmlFormatter except ImportError: return s from pygments.lexers import get_lexer_by_name rconv = lambda x: x out = StringIO() l = get_lexer_by_name(language) h = HtmlFormatter() highlight(s,l,h,out) styles = [(cls, style.split(';')[0].split(':')[1].strip()) for cls, (style, ttype, level) in h.class2style.items() if cls and style and style.startswith('color:')] return rconv(_2xpre(out.getvalue(),styles)) def convertSourceFiles(filenames): "Helper function - makes minimal PDF document" from reportlab.platypus import Paragraph, SimpleDocTemplate, XPreformatted from reportlab.lib.styles import getSampleStyleSheet styT=getSampleStyleSheet()["Title"] styC=getSampleStyleSheet()["Code"] doc = SimpleDocTemplate("pygments2xpre.pdf") S = [].append for filename in filenames: S(Paragraph(filename,style=styT)) src = open(filename, 'r').read() fmt = pygments2xpre(src) S(XPreformatted(fmt, style=styC)) doc.build(S.__self__) print('saved pygments2xpre.pdf') if __name__=='__main__': import sys filenames = sys.argv[1:] if not filenames: print('usage: pygments2xpre.py file1.py [file2.py] [...]') sys.exit(0) convertSourceFiles(filenames) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1691062243.0 reportlab-4.1.0/src/reportlab/lib/randomtext.py0000664000175000017500000005451314462707743021216 0ustar00rptlabrptlab#!/bin/env python #Copyright ReportLab Europe Ltd. 2000-2017 #see license.txt for license details #history https://hg.reportlab.com/hg-public/reportlab/log/tip/src/reportlab/lib/randomtext.py __version__='3.3.0' ############################################################################### # generates so-called 'Greek Text' for use in filling documents. ############################################################################### __doc__="""Like Lorem Ipsum, but more fun and extensible. This module exposes a function randomText() which generates paragraphs. These can be used when testing out document templates and stylesheets. A number of 'themes' are provided - please contribute more! We need some real Greek text too. There are currently six themes provided: STARTUP (words suitable for a business plan - or not as the case may be), COMPUTERS (names of programming languages and operating systems etc), BLAH (variations on the word 'blah'), BUZZWORD (buzzword bingo), STARTREK (Star Trek), PRINTING (print-related terms) PYTHON (snippets and quotes from Monty Python) CHOMSKY (random lingusitic nonsense) EXAMPLE USAGE: from reportlab.lib import randomtext print randomtext.randomText(randomtext.PYTHON, 10) This prints a random number of random sentences (up to a limit of ten) using the theme 'PYTHON'. """ #theme one :-) STARTUP = ['strategic', 'direction', 'proactive', 'venture capital', 'reengineering', 'forecast', 'resources', 'SWOT analysis', 'forward-thinking', 'profit', 'growth', 'doubletalk', 'B2B', 'B2C', 'venture capital', 'IPO', "NASDAQ meltdown - we're all doomed!"] #theme two - computery things. COMPUTERS = ['Python', 'Perl', 'Pascal', 'Java', 'Javascript', 'VB', 'Basic', 'LISP', 'Fortran', 'ADA', 'APL', 'C', 'C++', 'assembler', 'Larry Wall', 'Guido van Rossum', 'XML', 'HTML', 'cgi', 'cgi-bin', 'Amiga', 'Macintosh', 'Dell', 'Microsoft', 'firewall', 'server', 'Linux', 'Unix', 'MacOS', 'BeOS', 'AS/400', 'sendmail', 'TCP/IP', 'SMTP', 'RFC822-compliant', 'dynamic', 'Internet', 'A/UX', 'Amiga OS', 'BIOS', 'boot managers', 'CP/M', 'DOS', 'file system', 'FreeBSD', 'Freeware', 'GEOS', 'GNU', 'Hurd', 'Linux', 'Mach', 'Macintosh OS', 'mailing lists', 'Minix', 'Multics', 'NetWare', 'NextStep', 'OS/2', 'Plan 9', 'Realtime', 'UNIX', 'VMS', 'Windows', 'X Windows', 'Xinu', 'security', 'Intel', 'encryption', 'PGP' , 'software', 'ActiveX', 'AppleScript', 'awk', 'BETA', 'COBOL', 'Delphi', 'Dylan', 'Eiffel', 'extreme programming', 'Forth', 'Fortran', 'functional languages', 'Guile', 'format your hard drive', 'Icon', 'IDL', 'Infer', 'Intercal', 'J', 'Java', 'JavaScript', 'CD-ROM', 'JCL', 'Lisp', '"literate programming"', 'Logo', 'MUMPS', 'C: drive', 'Modula-2', 'Modula-3', 'Oberon', 'Occam', 'OpenGL', 'parallel languages', 'Pascal', 'Perl', 'PL/I', 'PostScript', 'Prolog', 'hardware', 'Blue Screen of Death', 'Rexx', 'RPG', 'Scheme', 'scripting languages', 'Smalltalk', 'crash!', 'disc crash', 'Spanner', 'SQL', 'Tcl/Tk', 'TeX', 'TOM', 'Visual', 'Visual Basic', '4GL', 'VRML', 'Virtual Reality Modeling Language', 'difference engine', '...went into "yo-yo mode"', 'Sun', 'Sun Microsystems', 'Hewlett Packard', 'output device', 'CPU', 'memory', 'registers', 'monitor', 'TFT display', 'plasma screen', 'bug report', '"mis-feature"', '...millions of bugs!', 'pizza', '"illiterate programming"','...lots of pizza!', 'pepperoni pizza', 'coffee', 'Jolt Cola[TM]', 'beer', 'BEER!'] #theme three - 'blah' - for when you want to be subtle. :-) BLAH = ['Blah', 'BLAH', 'blahblah', 'blahblahblah', 'blah-blah', 'blah!', '"Blah Blah Blah"', 'blah-de-blah', 'blah?', 'blah!!!', 'blah...', 'Blah.', 'blah;', 'blah, Blah, BLAH!', 'Blah!!!'] #theme four - 'buzzword bingo' time! BUZZWORD = ['intellectual capital', 'market segment', 'flattening', 'regroup', 'platform', 'client-based', 'long-term', 'proactive', 'quality vector', 'out of the loop', 'implement', 'streamline', 'cost-centered', 'phase', 'synergy', 'synergize', 'interactive', 'facilitate', 'appropriate', 'goal-setting', 'empowering', 'low-risk high-yield', 'peel the onion', 'goal', 'downsize', 'result-driven', 'conceptualize', 'multidisciplinary', 'gap analysis', 'dysfunctional', 'networking', 'knowledge management', 'goal-setting', 'mastery learning', 'communication', 'real-estate', 'quarterly', 'scalable', 'Total Quality Management', 'best of breed', 'nimble', 'monetize', 'benchmark', 'hardball', 'client-centered', 'vision statement', 'empowerment', 'lean & mean', 'credibility', 'synergistic', 'backward-compatible', 'hardball', 'stretch the envelope', 'bleeding edge', 'networking', 'motivation', 'best practice', 'best of breed', 'implementation', 'Total Quality Management', 'undefined', 'disintermediate', 'mindset', 'architect', 'gap analysis', 'morale', 'objective', 'projection', 'contribution', 'proactive', 'go the extra mile', 'dynamic', 'world class', 'real estate', 'quality vector', 'credibility', 'appropriate', 'platform', 'projection', 'mastery learning', 'recognition', 'quality', 'scenario', 'performance based', 'solutioning', 'go the extra mile', 'downsize', 'phase', 'networking', 'experiencing slippage', 'knowledge management', 'high priority', 'process', 'ethical', 'value-added', 'implement', 're-factoring', 're-branding', 'embracing change'] #theme five - Star Trek STARTREK = ['Starfleet', 'Klingon', 'Romulan', 'Cardassian', 'Vulcan', 'Benzite', 'IKV Pagh', 'emergency transponder', 'United Federation of Planets', 'Bolian', "K'Vort Class Bird-of-Prey", 'USS Enterprise', 'USS Intrepid', 'USS Reliant', 'USS Voyager', 'Starfleet Academy', 'Captain Picard', 'Captain Janeway', 'Tom Paris', 'Harry Kim', 'Counsellor Troi', 'Lieutenant Worf', 'Lieutenant Commander Data', 'Dr. Beverly Crusher', 'Admiral Nakamura', 'Irumodic Syndrome', 'Devron system', 'Admiral Pressman', 'asteroid field', 'sensor readings', 'Binars', 'distress signal', 'shuttlecraft', 'cloaking device', 'shuttle bay 2', 'Dr. Pulaski', 'Lwaxana Troi', 'Pacifica', 'William Riker', "Chief O'Brian", 'Soyuz class science vessel', 'Wolf-359', 'Galaxy class vessel', 'Utopia Planitia yards', 'photon torpedo', 'Archer IV', 'quantum flux', 'spacedock', 'Risa', 'Deep Space Nine', 'blood wine', 'quantum torpedoes', 'holodeck', 'Romulan Warbird', 'Betazoid', 'turbolift', 'battle bridge', 'Memory Alpha', '...with a phaser!', 'Romulan ale', 'Ferrengi', 'Klingon opera', 'Quark', 'wormhole', 'Bajoran', 'cruiser', 'warship', 'battlecruiser', '"Intruder alert!"', 'scout ship', 'science vessel', '"Borg Invasion imminent!" ', '"Abandon ship!"', 'Red Alert!', 'warp-core breech', '"All hands abandon ship! This is not a drill!"'] #theme six - print-related terms PRINTING = ['points', 'picas', 'leading', 'kerning', 'CMYK', 'offset litho', 'type', 'font family', 'typography', 'type designer', 'baseline', 'white-out type', 'WOB', 'bicameral', 'bitmap', 'blockletter', 'bleed', 'margin', 'body', 'widow', 'orphan', 'cicero', 'cursive', 'letterform', 'sidehead', 'dingbat', 'leader', 'DPI', 'drop-cap', 'paragraph', 'En', 'Em', 'flush left', 'left justified', 'right justified', 'centered', 'italic', 'Latin letterform', 'ligature', 'uppercase', 'lowercase', 'serif', 'sans-serif', 'weight', 'type foundry', 'fleuron', 'folio', 'gutter', 'whitespace', 'humanist letterform', 'caption', 'page', 'frame', 'ragged setting', 'flush-right', 'rule', 'drop shadows', 'prepress', 'spot-colour', 'duotones', 'colour separations', 'four-colour printing', 'Pantone[TM]', 'service bureau', 'imagesetter'] #it had to be done!... #theme seven - the "full Monty"! PYTHON = ['Good evening ladies and Bruces','I want to buy some cheese', 'You do have some cheese, do you?', "Of course sir, it's a cheese shop sir, we've got...",'discipline?... naked? ... With a melon!?', 'The Church Police!!' , "There's a dead bishop on the landing", 'Would you like a twist of lemming sir?', '"Conquistador Coffee brings a new meaning to the word vomit"','Your lupins please', 'Crelm Toothpaste, with the miracle ingredient Fraudulin', "Well there's the first result and the Silly Party has held Leicester.", 'Hello, I would like to buy a fish license please', "Look, it's people like you what cause unrest!", "When we got home, our Dad would thrash us to sleep with his belt!", 'Luxury', "Gumby Brain Specialist", "My brain hurts!!!", "My brain hurts too.", "How not to be seen", "In this picture there are 47 people. None of them can be seen", "Mrs Smegma, will you stand up please?", "Mr. Nesbitt has learned the first lesson of 'Not Being Seen', not to stand up.", "My hovercraft is full of eels", "Ah. You have beautiful thighs.", "My nipples explode with delight", "Drop your panties Sir William, I cannot wait 'til lunchtime", "I'm a completely self-taught idiot.", "I always wanted to be a lumberjack!!!", "Told you so!! Oh, coitus!!", "", "Nudge nudge?", "Know what I mean!", "Nudge nudge, nudge nudge?", "Say no more!!", "Hello, well it's just after 8 o'clock, and time for the penguin on top of your television set to explode", "Oh, intercourse the penguin!!", "Funny that penguin being there, isn't it?", "I wish to register a complaint.", "Now that's what I call a dead parrot", "Pining for the fjords???", "No, that's not dead, it's ,uhhhh, resting", "This is an ex-parrot!!", "That parrot is definitely deceased.", "No, no, no - it's spelt Raymond Luxury Yach-t, but it's pronounced 'Throatwobbler Mangrove'.", "You're a very silly man and I'm not going to interview you.", "No Mungo... never kill a customer." "And I'd like to conclude by putting my finger up my nose", "egg and Spam", "egg bacon and Spam", "egg bacon sausage and Spam", "Spam bacon sausage and Spam", "Spam egg Spam Spam bacon and Spam", "Spam sausage Spam Spam Spam bacon Spam tomato and Spam", "Spam Spam Spam egg and Spam", "Spam Spam Spam Spam Spam Spam baked beans Spam Spam Spam", "Spam!!", "I don't like Spam!!!", "You can't have egg, bacon, Spam and sausage without the Spam!", "I'll have your Spam. I Love it!", "I'm having Spam Spam Spam Spam Spam Spam Spam baked beans Spam Spam Spam and Spam", "Have you got anything without Spam?", "There's Spam egg sausage and Spam, that's not got much Spam in it.", "No one expects the Spanish Inquisition!!", "Our weapon is surprise, surprise and fear!", "Get the comfy chair!", "Amongst our weaponry are such diverse elements as: fear, surprise, ruthless efficiency, an almost fanatical devotion to the Pope, and nice red uniforms - Oh damn!", "Nobody expects the... Oh bugger!", "What swims in the sea and gets caught in nets? Henri Bergson?", "Goats. Underwater goats with snorkels and flippers?", "A buffalo with an aqualung?", "Dinsdale was a looney, but he was a happy looney.", "Dinsdale!!", "The 127th Upper-Class Twit of the Year Show", "What a great Twit!", "thought by many to be this year's outstanding twit", "...and there's a big crowd here today to see these prize idiots in action.", "And now for something completely different.", "Stop that, it's silly", "We interrupt this program to annoy you and make things generally irritating", "This depraved and degrading spectacle is going to stop right now, do you hear me?", "Stop right there!", "This is absolutely disgusting and I'm not going to stand for it", "I object to all this sex on the television. I mean, I keep falling off", "Right! Stop that, it's silly. Very silly indeed", "Very silly indeed", "Lemon curry?", "And now for something completely different, a man with 3 buttocks", "I've heard of unisex, but I've never had it", "That's the end, stop the program! Stop it!"] leadins=[ "To characterize a linguistic level L,", "On the other hand,", "This suggests that", "It appears that", "Furthermore,", "We will bring evidence in favor of the following thesis: ", "To provide a constituent structure for T(Z,K),", "From C1, it follows that", "For any transformation which is sufficiently diversified in application to be of any interest,", "Analogously,", "Clearly,", "Note that", "Of course,", "Suppose, for instance, that", "Thus", "With this clarification,", "Conversely,", "We have already seen that", "By combining adjunctions and certain deformations,", "I suggested that these results would follow from the assumption that", "If the position of the trace in (99c) were only relatively inaccessible to movement,", "However, this assumption is not correct, since", "Comparing these examples with their parasitic gap counterparts in (96) and (97), we see that", "In the discussion of resumptive pronouns following (81),", "So far,", "Nevertheless,", "For one thing,", "Summarizing, then, we assume that", "A consequence of the approach just outlined is that", "Presumably,", "On our assumptions,", "It may be, then, that", "It must be emphasized, once again, that", "Let us continue to suppose that", "Notice, incidentally, that", "A majority of informed linguistic specialists agree that", "There is also a different approach to the [unification] problem,", "This approach divorces the cognitive sciences from a biological setting,", "The approach relies on the \"Turing Test,\" devised by mathematician Alan Turing,", "Adopting this approach,", "There is no fact, no meaningful question to be answered,", "Another superficial similarity is the interest in simulation of behavior,", "A lot of sophistication has been developed about the utilization of machines for complex purposes,", ] subjects = [ "the notion of level of grammaticalness", "a case of semigrammaticalness of a different sort", "most of the methodological work in modern linguistics", "a subset of English sentences interesting on quite independent grounds", "the natural general principle that will subsume this case", "an important property of these three types of EC", "any associated supporting element", "the appearance of parasitic gaps in domains relatively inaccessible to ordinary extraction", "the speaker-hearer's linguistic intuition", "the descriptive power of the base component", "the earlier discussion of deviance", "this analysis of a formative as a pair of sets of features", "this selectionally introduced contextual feature", "a descriptively adequate grammar", "the fundamental error of regarding functional notions as categorial", "relational information", "the systematic use of complex symbols", "the theory of syntactic features developed earlier", ] verbs= [ "can be defined in such a way as to impose", "delimits", "suffices to account for", "cannot be arbitrary in", "is not subject to", "does not readily tolerate", "raises serious doubts about", "is not quite equivalent to", "does not affect the structure of", "may remedy and, at the same time, eliminate", "is not to be considered in determining", "is to be regarded as", "is unspecified with respect to", "is, apparently, determined by", "is necessary to impose an interpretation on", "appears to correlate rather closely with", "is rather different from", ] objects = [ "problems of phonemic and morphological analysis.", "a corpus of utterance tokens upon which conformity has been defined by the paired utterance test.", "the traditional practice of grammarians.", "the levels of acceptability from fairly high (e.g. (99a)) to virtual gibberish (e.g. (98d)).", "a stipulation to place the constructions into these various categories.", "a descriptive fact.", "a parasitic gap construction.", "the extended c-command discussed in connection with (34).", "the ultimate standard that determines the accuracy of any proposed grammar.", "the system of base rules exclusive of the lexicon.", "irrelevant intervening contexts in selectional rules.", "nondistinctness in the sense of distinctive feature theory.", "a general convention regarding the forms of the grammar.", "an abstract underlying order.", "an important distinction in language use.", "the requirement that branching is not tolerated within the dominance scope of a complex symbol.", "the strong generative capacity of the theory.", ] def format_wisdom(text,line_length=72): try: import textwrap return textwrap.fill(text, line_length) except: return text def chomsky(times = 1): if not isinstance(times, int): return format_wisdom(__doc__) import random prevparts = [] newparts = [] output = [] for i in range(times): for partlist in (leadins, subjects, verbs, objects): while 1: part = random.choice(partlist) if part not in prevparts: break newparts.append(part) output.append(' '.join(newparts)) prevparts = newparts newparts = [] return format_wisdom(' '.join(output)) from reportlab import rl_config if rl_config.invariant: import random #monkey patch random.randrange class RLMonkeyPatchRandom(random.Random): def randrange(self, start, stop=None, step=1, _int=int, _maxwidth=1< 0: if istart >= _maxwidth: return self._randbelow(istart) return _int(self.random() * istart) raise ValueError("empty range for randrange()") # stop argument supplied. istop = _int(stop) if istop != stop: raise ValueError("non-integer stop for randrange()") width = istop - istart if step == 1 and width > 0: # Note that # int(istart + self.random()*width) # instead would be incorrect. For example, consider istart # = -2 and istop = 0. Then the guts would be in # -2.0 to 0.0 exclusive on both ends (ignoring that random() # might return 0.0), and because int() truncates toward 0, the # final result would be -1 or 0 (instead of -2 or -1). # istart + int(self.random()*width) # would also be incorrect, for a subtler reason: the RHS # can return a long, and then randrange() would also return # a long, but we're supposed to return an int (for backward # compatibility). if width >= _maxwidth: return _int(istart + self._randbelow(width)) return _int(istart + _int(self.random()*width)) if step == 1: raise ValueError("empty range for randrange() (%d,%d, %d)" % (istart, istop, width)) # Non-unit step argument supplied. istep = _int(step) if istep != step: raise ValueError("non-integer step for randrange()") if istep > 0: n = (width + istep - 1) // istep elif istep < 0: n = (width + istep + 1) // istep else: raise ValueError("zero step for randrange()") if n <= 0: raise ValueError("empty range for randrange()") if n >= _maxwidth: return istart + istep*self._randbelow(n) return istart + istep*_int(self.random() * n) def choice(self, seq): """Choose a random element from a non-empty sequence.""" return seq[int(self.random() * len(seq))] random.Random.randrange = RLMonkeyPatchRandom.randrange random.Random.choice = RLMonkeyPatchRandom.choice random.randrange = random._inst.randrange random.choice = random._inst.choice del RLMonkeyPatchRandom if not getattr(rl_config,'_random',None): rl_config._random = 1 random.seed(2342471922) del random del rl_config def randomText(theme=STARTUP, sentences=5): #this may or may not be appropriate in your company if type(theme)==type(''): if theme.lower()=='chomsky': return chomsky(sentences) elif theme.upper() in ('STARTUP','COMPUTERS','BLAH','BUZZWORD','STARTREK','PRINTING','PYTHON'): theme = globals()[theme.upper()] else: raise ValueError('Unknown theme "%s"' % theme) from random import randint, choice RANDOMWORDS = theme #sentences = 5 output = "" for sentenceno in range(randint(1,sentences)): output = output + 'Blah' for wordno in range(randint(10,25)): if randint(0,4)==0: word = choice(RANDOMWORDS) else: word = 'blah' output = output + ' ' +word output = output+'. ' return output if __name__=='__main__': import sys argv = sys.argv[1:] if argv: theme = argv.pop(0) if argv: sentences = int(argv.pop(0)) else: sentences = 5 try: print(randomText(theme,sentences)) except: sys.stderr.write("Usage: randomtext.py [theme [#sentences]]\n") sys.stderr.write(" theme in chomsky|STARTUP|COMPUTERS|BLAH|BUZZWORD|STARTREK|PRINTING|PYTHON\n") raise else: print(chomsky(5)) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1704966359.0 reportlab-4.1.0/src/reportlab/lib/rl_accel.py0000664000175000017500000003225114547734327020572 0ustar00rptlabrptlab#this is the interface module that imports all from the C extension _rl_accel _c_funcs = {} _py_funcs = {} ### NOTE! FP_STR SHOULD PROBABLY ALWAYS DO A PYTHON STR() CONVERSION ON ARGS ### IN CASE THEY ARE "LAZY OBJECTS". ACCELLERATOR DOESN'T DO THIS (YET) __all__ = list(filter(None,''' fp_str unicode2T1 instanceStringWidthT1 instanceStringWidthTTF asciiBase85Encode asciiBase85Decode escapePDF sameFrag calcChecksum add32 hex32 '''.split())) import reportlab testing = getattr(reportlab,'_rl_testing',False) del reportlab for fn in __all__: D={} try: exec('from _rl_accel import %s as f' % fn,D) _c_funcs[fn] = D['f'] if testing: _py_funcs[fn] = None except ImportError: _py_funcs[fn] = None del D if _py_funcs: from reportlab.lib.utils import isUnicode, isSeq, rawBytes, asNative, asBytes from math import log from struct import unpack if 'fp_str' in _py_funcs: _log_10 = lambda x,log=log,_log_e_10=log(10.0): log(x)/_log_e_10 _fp_fmts = "%.0f", "%.1f", "%.2f", "%.3f", "%.4f", "%.5f", "%.6f" def fp_str(*a): '''convert separate arguments (or single sequence arg) into space separated numeric strings''' if len(a)==1 and isSeq(a[0]): a = a[0] s = [] A = s.append for i in a: sa =abs(i) if sa<=1e-7: A('0') else: l = sa<=1 and 6 or min(max(0,(6-int(_log_10(sa)))),6) n = _fp_fmts[l]%i if l: j = len(n) while j: j -= 1 if n[j]!='0': if n[j]!='.': j += 1 break n = n[:j] A((n[0]!='0' or len(n)==1) and n or n[1:]) return ' '.join(s) #hack test for comma users if ',' in fp_str(0.25): _FP_STR = _fp_str def _fp_str(*a): return _FP_STR(*a).replace(',','.') _py_funcs['fp_str'] = fp_str if 'unicode2T1' in _py_funcs: def unicode2T1(utext,fonts): '''return a list of (font,string) pairs representing the unicode text''' R = [] font, fonts = fonts[0], fonts[1:] enc = font.encName if 'UCS-2' in enc: enc = 'UTF16' while utext: try: if isUnicode(utext): s = utext.encode(enc) else: s = utext R.append((font,s)) break except UnicodeEncodeError as e: i0, il = e.args[2:4] if i0: R.append((font,utext[:i0].encode(enc))) if fonts: R.extend(unicode2T1(utext[i0:il],fonts)) else: R.append((font._notdefFont,font._notdefChar*(il-i0))) utext = utext[il:] return R _py_funcs['unicode2T1'] = unicode2T1 if 'instanceStringWidthT1' in _py_funcs: def instanceStringWidthT1(self, text, size, encoding='utf8'): """This is the "purist" approach to width""" if not isUnicode(text): text = text.decode(encoding) return sum((sum(map(f.widths.__getitem__,t)) for f, t in unicode2T1(text,[self]+self.substitutionFonts)))*0.001*size _py_funcs['instanceStringWidthT1'] = instanceStringWidthT1 if 'instanceStringWidthTTF' in _py_funcs: def instanceStringWidthTTF(self, text, size, encoding='utf-8'): "Calculate text width" if not isUnicode(text): text = text.decode(encoding or 'utf-8') g = self.face.charWidths.get dw = self.face.defaultWidth return 0.001*size*sum((g(ord(u),dw) for u in text)) _py_funcs['instanceStringWidthTTF'] = instanceStringWidthTTF if 'hex32' in _py_funcs: def hex32(i): return '0X%8.8X' % (int(i)&0xFFFFFFFF) _py_funcs['hex32'] = hex32 if 'add32' in _py_funcs: def add32(x, y): "Calculate (x + y) modulo 2**32" return (x+y) & 0xFFFFFFFF _py_funcs['add32'] = add32 if 'calcChecksum' in _py_funcs: def calcChecksum(data): """Calculates TTF-style checksums""" data = rawBytes(data) if len(data)&3: data = data + (4-(len(data)&3))*b"\0" return sum(unpack(">%dl" % (len(data)>>2), data)) & 0xFFFFFFFF _py_funcs['calcChecksum'] = calcChecksum if 'escapePDF' in _py_funcs: _ESCAPEDICT={} for c in range(256): if c<32 or c>=127: _ESCAPEDICT[c]= '\\%03o' % c elif c in (ord('\\'),ord('('),ord(')')): _ESCAPEDICT[c] = '\\'+chr(c) else: _ESCAPEDICT[c] = chr(c) del c #Michael Hudson donated this def escapePDF(s): r = [] for c in s: if not type(c) is int: c = ord(c) r.append(_ESCAPEDICT[c]) return ''.join(r) _py_funcs['escapePDF'] = escapePDF if 'asciiBase85Encode' in _py_funcs: def asciiBase85Encode(input): """Encodes input using ASCII-Base85 coding. This is a compact encoding used for binary data within a PDF file. Four bytes of binary data become five bytes of ASCII. This is the default method used for encoding images.""" doOrd = isUnicode(input) # special rules apply if not a multiple of four bytes. whole_word_count, remainder_size = divmod(len(input), 4) cut = 4 * whole_word_count body, lastbit = input[0:cut], input[cut:] out = [].append for i in range(whole_word_count): offset = i*4 b1 = body[offset] b2 = body[offset+1] b3 = body[offset+2] b4 = body[offset+3] if doOrd: b1 = ord(b1) b2 = ord(b2) b3 = ord(b3) b4 = ord(b4) if b1<128: num = (((((b1<<8)|b2)<<8)|b3)<<8)|b4 else: num = 16777216 * b1 + 65536 * b2 + 256 * b3 + b4 if num == 0: #special case out('z') else: #solve for five base-85 numbers temp, c5 = divmod(num, 85) temp, c4 = divmod(temp, 85) temp, c3 = divmod(temp, 85) c1, c2 = divmod(temp, 85) assert ((85**4) * c1) + ((85**3) * c2) + ((85**2) * c3) + (85*c4) + c5 == num, 'dodgy code!' out(chr(c1+33)) out(chr(c2+33)) out(chr(c3+33)) out(chr(c4+33)) out(chr(c5+33)) # now we do the final bit at the end. I repeated this separately as # the loop above is the time-critical part of a script, whereas this # happens only once at the end. #encode however many bytes we have as usual if remainder_size > 0: lastbit += (4-len(lastbit))*('\0' if doOrd else b'\000') b1 = lastbit[0] b2 = lastbit[1] b3 = lastbit[2] b4 = lastbit[3] if doOrd: b1 = ord(b1) b2 = ord(b2) b3 = ord(b3) b4 = ord(b4) num = 16777216 * b1 + 65536 * b2 + 256 * b3 + b4 #solve for c1..c5 temp, c5 = divmod(num, 85) temp, c4 = divmod(temp, 85) temp, c3 = divmod(temp, 85) c1, c2 = divmod(temp, 85) #print 'encoding: %d %d %d %d -> %d -> %d %d %d %d %d' % ( # b1,b2,b3,b4,num,c1,c2,c3,c4,c5) lastword = chr(c1+33) + chr(c2+33) + chr(c3+33) + chr(c4+33) + chr(c5+33) #write out most of the bytes. out(lastword[0:remainder_size + 1]) #terminator code for ascii 85 out('~>') return ''.join(out.__self__) _py_funcs['asciiBase85Encode'] = asciiBase85Encode if 'asciiBase85Decode' in _py_funcs: def asciiBase85Decode(input): """Decodes input using ASCII-Base85 coding. This is not normally used - Acrobat Reader decodes for you - but a round trip is essential for testing.""" #strip all whitespace stripped = ''.join(asNative(input).split()) #check end assert stripped[-2:] == '~>', 'Invalid terminator for Ascii Base 85 Stream' stripped = stripped[:-2] #chop off terminator #may have 'z' in it which complicates matters - expand them stripped = stripped.replace('z','!!!!!') # special rules apply if not a multiple of five bytes. whole_word_count, remainder_size = divmod(len(stripped), 5) #print '%d words, %d leftover' % (whole_word_count, remainder_size) #assert remainder_size != 1, 'invalid Ascii 85 stream!' cut = 5 * whole_word_count body, lastbit = stripped[0:cut], stripped[cut:] out = [].append for i in range(whole_word_count): offset = i*5 c1 = ord(body[offset]) - 33 c2 = ord(body[offset+1]) - 33 c3 = ord(body[offset+2]) - 33 c4 = ord(body[offset+3]) - 33 c5 = ord(body[offset+4]) - 33 num = ((85**4) * c1) + ((85**3) * c2) + ((85**2) * c3) + (85*c4) + c5 temp, b4 = divmod(num,256) temp, b3 = divmod(temp,256) b1, b2 = divmod(temp, 256) assert num == 16777216 * b1 + 65536 * b2 + 256 * b3 + b4, 'dodgy code!' out(chr(b1)) out(chr(b2)) out(chr(b3)) out(chr(b4)) #decode however many bytes we have as usual if remainder_size > 0: while len(lastbit) < 5: lastbit = lastbit + '!' c1 = ord(lastbit[0]) - 33 c2 = ord(lastbit[1]) - 33 c3 = ord(lastbit[2]) - 33 c4 = ord(lastbit[3]) - 33 c5 = ord(lastbit[4]) - 33 num = (((85*c1+c2)*85+c3)*85+c4)*85 + (c5 +(0,0,0xFFFFFF,0xFFFF,0xFF)[remainder_size]) temp, b4 = divmod(num,256) temp, b3 = divmod(temp,256) b1, b2 = divmod(temp, 256) assert num == 16777216 * b1 + 65536 * b2 + 256 * b3 + b4, 'dodgy code!' #print 'decoding: %d %d %d %d %d -> %d -> %d %d %d %d' % ( # c1,c2,c3,c4,c5,num,b1,b2,b3,b4) #the last character needs 1 adding; the encoding loses #data by rounding the number to x bytes, and when #divided repeatedly we get one less if remainder_size == 2: lastword = chr(b1) elif remainder_size == 3: lastword = chr(b1) + chr(b2) elif remainder_size == 4: lastword = chr(b1) + chr(b2) + chr(b3) else: lastword = '' out(lastword) r = ''.join(out.__self__) return asBytes(r,enc='latin1') _py_funcs['asciiBase85Decode'] = asciiBase85Decode if 'sameFrag' in _py_funcs: def sameFrag(f,g): 'returns 1 if two ParaFrags map out the same' if (hasattr(f,'cbDefn') or hasattr(g,'cbDefn') or hasattr(f,'lineBreak') or hasattr(g,'lineBreak')): return 0 for a in ('fontName', 'fontSize', 'textColor', 'rise', 'us_lines', 'link', "backColor", "nobr"): if getattr(f,a,None)!=getattr(g,a,None): return 0 return 1 _py_funcs['sameFrag'] = sameFrag G=globals() for fn in __all__: f = _c_funcs[fn] if fn in _c_funcs else _py_funcs[fn] if not f: raise RuntimeError('function %s is not properly defined' % fn) G[fn] = f del fn, f, G if __name__=='__main__': import sys, subprocess funclist = ','.join("""add32 asciiBase85Decode asciiBase85Encode calcChecksum escapePDF fp_str hex32 instanceStringWidthT1 instanceStringWidthTTF sameFrag unicode2T1""".split()) for cmd,xs in ( ("instanceStringWidthTTF(font,text,10)",("font=TTFont('Vera','Vera.ttf')","text='abcde fghi . jkl ; mno'")), ("instanceStringWidthT1(font,'abcde fghi . jkl ; mno',10)", ("fonts=[getFont('Helvetica')]+getFont('Helvetica').substitutionFonts""", "font=fonts[0]","text='abcde fghi . jkl ; mno'")), ("escapePDF(text)",("text='\x11abcdefghijkl\xf3'",)), ("fp_str(1.23456,2.7891666,2,13,11)",()), ("calcChecksum(text)",("text=5*' abcdefgiijklMnoPQrstuvwxyz1234567890'",)), ("hex32(0x12345678)",()), ("add32(0x12345678,123456789)",()), ("asciiBase85Encode(src)",("src=5*' abcdefgiijklMnoPQrstuvwxyz1234567890'",)), ("asciiBase85Decode(_85text)",("_85text=asciiBase85Encode(5*' abcdefgiijklMnoPQrstuvwxyz1234567890')",)), ): for modname in '_rl_accel','reportlab.lib.rl_accel': s = ';'.join(( "from reportlab.pdfbase.pdfmetrics import getFont", "from reportlab.pdfbase.ttfonts import TTFont", f"from {modname} import {funclist}", )+xs) if modname!='_rl_accel': s = "import sys;sys.modules['_rl_accel']=None;"+s print(f'timing {modname} {cmd}') for i in range(2): subprocess.check_call([sys.executable,'-mtimeit','-s',s,cmd]) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1691062243.0 reportlab-4.1.0/src/reportlab/lib/rl_safe_eval.py0000664000175000017500000011520614462707743021450 0ustar00rptlabrptlab#this code is copied/stolen/borrowed/modified from various sources including #https://github.com/zopefoundation/AccessControl #https://github.com/zopefoundation/RestrictedPython #https://github.com/danthedeckie/simpleeval #hopefully we are standing on giants' shoulders import sys, os, ast, re, weakref, time, copy, math, types eval_debug = int(os.environ.get('EVAL_DEBUG','0')) strTypes = (bytes,str) isPy39 = sys.version_info[:2]>=(3,9) haveNameConstant = hasattr(ast,'NameConstant') import textwrap class BadCode(ValueError): pass # For AugAssign the operator must be converted to a string. augOps = { ast.Add: '+=', ast.Sub: '-=', ast.Mult: '*=', ast.Div: '/=', ast.Mod: '%=', ast.Pow: '**=', ast.LShift: '<<=', ast.RShift: '>>=', ast.BitOr: '|=', ast.BitXor: '^=', ast.BitAnd: '&=', ast.FloorDiv: '//=', ast.MatMult: '@=', } # For creation allowed magic method names. See also # https://docs.python.org/3/reference/datamodel.html#special-method-names __allowed_magic_methods__ = frozenset([ '__init__', '__contains__', '__lt__', '__le__', '__eq__', '__ne__', '__gt__', '__ge__', ]) __rl_unsafe__ = frozenset('''builtins breakpoint __annotations__ co_argcount co_cellvars co_code co_consts __code__ co_filename co_firstlineno co_flags co_freevars co_kwonlyargcount co_lnotab co_name co_names co_nlocals co_posonlyargcount co_stacksize co_varnames cr_await cr_code cr_frame cr_origin cr_running __defaults__ f_back f_builtins f_code f_exc_traceback f_exc_type f_exc_value f_globals f_lasti f_lineno f_locals f_restricted f_trace __func__ func_code func_defaults func_doc func_globals func_name gi_code gi_frame gi_running gi_yieldfrom __globals__ im_class im_func im_self __iter__ __kwdefaults__ __module__ __name__ next __qualname__ __self__ tb_frame tb_lasti tb_lineno tb_next globals vars locals type eval exec aiter anext compile open dir print classmethod staticmethod __import__ super property'''.split() ) __rl_unsafe_re__ = re.compile(r'\b(?:%s)' % '|'.join(__rl_unsafe__),re.M) def copy_locations(new_node, old_node): ast.copy_location(new_node, old_node) ast.fix_missing_locations(new_node) class UntrustedAstTransformer(ast.NodeTransformer): def __init__(self, names_seen=None, nameIsAllowed=None): super(UntrustedAstTransformer, self).__init__() self.names_seen = {} if names_seen is None else names_seen self.nameIsAllowed = nameIsAllowed # Global counter to construct temporary variable names. self._tmp_idx = 0 self._tmp_pfx = '_tmp%s' % repr(time.time()).replace('.','') @property def tmpName(self): name = '%s%s' % (self._tmp_pfx,self._tmp_idx) self._tmp_idx += 1 return name def error(self, node, msg): raise BadCode('Line %s: %s' % (getattr(node, 'lineno', '??'), msg)) def guard_iter(self, node): """ Converts: for x in expr to for x in __rl_getiter__(expr) Also used for * list comprehensions * dict comprehensions * set comprehensions * generator expresions """ node = self.visit_children(node) if isinstance(node.target, ast.Tuple): spec = self.gen_unpack_spec(node.target) new_iter = ast.Call( func=ast.Name('__rl_iter_unpack_sequence__', ast.Load()), args=[node.iter, spec, ast.Name('__rl_getiter__', ast.Load())], keywords=[]) else: new_iter = ast.Call( func=ast.Name('__rl_getiter__', ast.Load()), args=[node.iter], keywords=[]) copy_locations(new_iter, node.iter) node.iter = new_iter return node def is_starred(self, ob): return isinstance(ob, ast.Starred) def gen_unpack_spec(self, tpl): """Generate a specification for '__rl_unpack_sequence__'. This spec is used to protect sequence unpacking. The primary goal of this spec is to tell which elements in a sequence are sequences again. These 'child' sequences have to be protected again. For example there is a sequence like this: (a, (b, c), (d, (e, f))) = g On a higher level the spec says: - There is a sequence of len 3 - The element at index 1 is a sequence again with len 2 - The element at index 2 is a sequence again with len 2 - The element at index 1 in this subsequence is a sequence again with len 2 With this spec '__rl_unpack_sequence__' does something like this for protection (len checks are omitted): t = list(__rl_getiter__(g)) t[1] = list(__rl_getiter__(t[1])) t[2] = list(__rl_getiter__(t[2])) t[2][1] = list(__rl_getiter__(t[2][1])) return t The 'real' spec for the case above is then: spec = { 'min_len': 3, 'childs': ( (1, {'min_len': 2, 'childs': ()}), (2, { 'min_len': 2, 'childs': ( (1, {'min_len': 2, 'childs': ()}) ) } ) ) } So finally the assignment above is converted into: (a, (b, c), (d, (e, f))) = __rl_unpack_sequence__(g, spec) """ spec = ast.Dict(keys=[], values=[]) spec.keys.append(ast.Str('childs')) spec.values.append(ast.Tuple([], ast.Load())) # starred elements in a sequence do not contribute into the min_len. # For example a, b, *c = g # g must have at least 2 elements, not 3. 'c' is empyt if g has only 2. min_len = len([ob for ob in tpl.elts if not self.is_starred(ob)]) offset = 0 for idx, val in enumerate(tpl.elts): # After a starred element specify the child index from the back. # Since it is unknown how many elements from the sequence are # consumed by the starred element. # For example a, *b, (c, d) = g # Then (c, d) has the index '-1' if self.is_starred(val): offset = min_len + 1 elif isinstance(val, ast.Tuple): el = ast.Tuple([], ast.Load()) el.elts.append(ast.Num(idx - offset)) el.elts.append(self.gen_unpack_spec(val)) spec.values[0].elts.append(el) spec.keys.append(ast.Str('min_len')) spec.values.append(ast.Num(min_len)) return spec def protect_unpack_sequence(self, target, value): spec = self.gen_unpack_spec(target) return ast.Call( func=ast.Name('__rl_unpack_sequence__', ast.Load()), args=[value, spec, ast.Name('__rl_getiter__', ast.Load())], keywords=[]) def gen_unpack_wrapper(self, node, target, ctx='store'): """Helper function to protect tuple unpacks. node: used to copy the locations for the new nodes. target: is the tuple which must be protected. ctx: Defines the context of the returned temporary node. It returns a tuple with two element. Element 1: Is a temporary name node which must be used to replace the target. The context (store, param) is defined by the 'ctx' parameter.. Element 2: Is a try .. finally where the body performs the protected tuple unpack of the temporary variable into the original target. """ # Generate a tmp name to replace the tuple with. tnam = self.tmpName # Generates an expressions which protects the unpack. # converter looks like 'wrapper(tnam)'. # 'wrapper' takes care to protect sequence unpacking with __rl_getiter__. converter = self.protect_unpack_sequence( target, ast.Name(tnam, ast.Load())) # Assign the expression to the original names. # Cleanup the temporary variable. # Generates: # try: # # converter is 'wrapper(tnam)' # arg = converter # finally: # del tmp_arg try_body = [ast.Assign(targets=[target], value=converter)] finalbody = [self.gen_del_stmt(tnam)] cleanup = ast.Try( body=try_body, finalbody=finalbody, handlers=[], orelse=[]) if ctx == 'store': ctx = ast.Store() elif ctx == 'param': ctx = ast.Param() else: # pragma: no cover # Only store and param are defined ctx. raise NotImplementedError('bad ctx "%s"' % type(ctx)) # This node is used to catch the tuple in a tmp variable. tmp_target = ast.Name(tnam, ctx) copy_locations(tmp_target, node) copy_locations(cleanup, node) return (tmp_target, cleanup) def gen_none_node(self): return ast.NameConstant(value=None) if hasNameConstant else ast.Name(id='None', ctx=ast.Load()) def gen_lambda(self, args, body): return ast.Lambda( args=ast.arguments( args=args, vararg=None, kwarg=None, defaults=[]), body=body) def gen_del_stmt(self, name_to_del): return ast.Delete(targets=[ast.Name(name_to_del, ast.Del())]) def transform_slice(self, slice_): """Transform slices into function parameters. ast.Slice nodes are only allowed within a ast.Subscript node. To use a slice as an argument of ast.Call it has to be converted. Conversion is done by calling the 'slice' function from builtins """ if isinstance(slice_, ast.Index): return slice_.value elif isinstance(slice_, ast.Slice): # Create a python slice object. args = [] if slice_.lower: args.append(slice_.lower) else: args.append(self.gen_none_node()) if slice_.upper: args.append(slice_.upper) else: args.append(self.gen_none_node()) if slice_.step: args.append(slice_.step) else: args.append(self.gen_none_node()) return ast.Call( func=ast.Name('slice', ast.Load()), args=args, keywords=[]) elif isinstance(slice_, ast.ExtSlice): dims = ast.Tuple([], ast.Load()) for item in slice_.dims: dims.elts.append(self.transform_slice(item)) return dims elif isPy39: return slice_ else: # pragma: no cover # Index, Slice and ExtSlice are only defined Slice types. raise NotImplementedError("Unknown slice type: %s" % slice_) def isAllowedName(self, node, name): if name is None: return self.nameIsAllowed(name) def check_function_argument_names(self, node): # In python3 arguments are always identifiers. # In python2 the 'Python.asdl' specifies expressions, but # the python grammer allows only identifiers or a tuple of # identifiers. If its a tuple 'tuple parameter unpacking' is used, # which is gone in python3. # See https://www.python.org/dev/peps/pep-3113/ for arg in node.args.args: self.isAllowedName(node, arg.arg) if node.args.vararg: self.isAllowedName(node, node.args.vararg.arg) if node.args.kwarg: self.isAllowedName(node, node.args.kwarg.arg) for arg in node.args.kwonlyargs: self.isAllowedName(node, arg.arg) def check_import_names(self, node): """Check the names being imported. This is a protection against rebinding dunder names like __rl_getitem__,__rl_set__ via imports. => 'from _a import x' is ok, because '_a' is not added to the scope. """ for name in node.names: if '*' in name.name: self.error(node, '"*" imports are not allowed.') self.isAllowedName(node, name.name) if name.asname: self.isAllowedName(node, name.asname) return self.visit_children(node) def gen_attr_check(self, node, attr_name): """Check if 'attr_name' is allowed on the object in node. It generates (_getattr_(node, attr_name) and node). """ call_getattr = ast.Call( func=ast.Name('__rl_getattr__', ast.Load()), args=[node, ast.Str(attr_name)], keywords=[]) return ast.BoolOp(op=ast.And(), values=[call_getattr, node]) def visit_Constant(self, node): """Allow constant literals with restriction for Ellipsis. Constant replaces Num, Str, Bytes, NameConstant and Ellipsis in Python 3.8+. :see: https://docs.python.org/dev/whatsnew/3.8.html#deprecated """ if node.value is Ellipsis: # Deny using `...`. # Special handling necessary as ``self.not_allowed(node)`` # would return the Error Message: # 'Constant statements are not allowed.' # which is only partial true. self.error(node, 'Ellipsis statements are not allowed.') return return self.visit_children(node) # ast for Variables def visit_Name(self, node): node = self.visit_children(node) if isinstance(node.ctx, ast.Load): if node.id == 'print': self.error(node,'print function is not allowed') self.names_seen[node.id] = True self.isAllowedName(node, node.id) return node def visit_Call(self, node): """Checks calls with '*args' and '**kwargs'. Note: The following happens only if '*args' or '**kwargs' is used. Transfroms 'foo()' into __rl_apply__(foo, ) The thing is that '__rl_apply__' has only '*args', '**kwargs', so it gets Python to collapse all the myriad ways to call functions into one manageable from. From there, '__rl_apply__()' wraps args and kws in guarded accessors, then calls the function, returning the value. """ if isinstance(node.func, ast.Name): if node.func.id == 'exec': self.error(node, 'Exec calls are not allowed.') elif node.func.id == 'eval': self.error(node, 'Eval calls are not allowed.') needs_wrap = False for pos_arg in node.args: if isinstance(pos_arg, ast.Starred): needs_wrap = True for keyword_arg in node.keywords: if keyword_arg.arg is None: needs_wrap = True node = self.visit_children(node) #if not needs_wrap: # return node node.args.insert(0, node.func) node.func = ast.Name('__rl_apply__', ast.Load()) copy_locations(node.func, node.args[0]) return node def visit_Attribute(self, node): """Checks and mutates attribute access/assignment. 'a.b' becomes '__rl_getattr__(a, "b")' """ if node.attr.startswith('__') and node.attr != '__': self.error(node, '"%s" is an invalid attribute'%node.attr) if isinstance(node.ctx, ast.Load): node = self.visit_children(node) new_node = ast.Call( func=ast.Name('__rl_getattr__', ast.Load()), args=[node.value, ast.Str(node.attr)], keywords=[]) copy_locations(new_node, node) return new_node elif isinstance(node.ctx, (ast.Store, ast.Del)): node = self.visit_children(node) new_value = ast.Call( func=ast.Name('__rl_sd__', ast.Load()), args=[node.value], keywords=[]) copy_locations(new_value, node.value) node.value = new_value return node else: # pragma: no cover # Impossible Case only ctx Load, Store and Del are defined in ast. raise NotImplementedError("Unknown ctx type: %s" % type(node.ctx)) # Subscripting def visit_Subscript(self, node): """Transforms all kinds of subscripts. 'v[a]' becomes '__rl_getitem__(foo, a)' 'v[:b]' becomes '__rl_getitem__(foo, slice(None, b, None))' 'v[a:]' becomes '__rl_getitem__(foo, slice(a, None, None))' 'v[a:b]' becomes '__rl_getitem__(foo, slice(a, b, None))' 'v[a:b:c]' becomes '__rl_getitem__(foo, slice(a, b, c))' 'v[a,b:c] becomes '__rl_getitem__(foo, (a, slice(b, c, None)))' #'v[a] = c' becomes '_rl_write__(v)[a] = c' #'del v[a]' becomes 'del __rl_sd__(v)[a]' """ node = self.visit_children(node) # 'AugStore' and 'AugLoad' are defined in 'Python.asdl' as possible # 'expr_context'. However, according to Python/ast.c # they are NOT used by the implementation => No need to worry here. # Instead ast.c creates 'AugAssign' nodes, which can be visit_ed. if isinstance(node.ctx, ast.Load): new_node = ast.Call( func=ast.Name('__rl_getitem__', ast.Load()), args=[node.value, self.transform_slice(node.slice)], keywords=[]) copy_locations(new_node, node) return new_node elif isinstance(node.ctx, (ast.Del, ast.Store)): #new_value = ast.Call( # func=ast.Name('__rl_sd__', ast.Load()), # args=[node.value], # keywords=[]) #copy_locations(new_value, node) #node.value = new_value return node else: # pragma: no cover # Impossible Case only ctx Load, Store and Del are defined in ast. raise NotImplementedError("Unknown ctx type: %s" % type(node.ctx)) # Statements def visit_Assign(self, node): node = self.visit_children(node) if not any(isinstance(t, ast.Tuple) for t in node.targets): return node # Handle sequence unpacking. # For briefness this example omits cleanup of the temporary variables. # Check 'transform_tuple_assign' how its done. # # - Single target (with nested support) # (a, (b, (c, d))) = # is converted to # (a, t1) = __rl_getiter__() # (b, t2) = __rl_getiter__(t1) # (c, d) = __rl_getiter__(t2) # # - Multi targets # (a, b) = (c, d) = # is converted to # (c, d) = __rl_getiter__() # (a, b) = __rl_getiter__() # Why is this valid ? The original bytecode for this multi targets # behaves the same way. # ast.NodeTransformer works with list results. # He injects it at the rightplace of the node's parent statements. new_nodes = [] # python fills the right most target first. for target in reversed(node.targets): if isinstance(target, ast.Tuple): wrapper = ast.Assign( targets=[target], value=self.protect_unpack_sequence(target, node.value)) new_nodes.append(wrapper) else: new_node = ast.Assign(targets=[target], value=node.value) new_nodes.append(new_node) for new_node in new_nodes: copy_locations(new_node, node) return new_nodes def visit_AugAssign(self, node): """Forbid certain kinds of AugAssign According to the language reference (and ast.c) the following nodes are are possible: Name, Attribute, Subscript Note that although augmented assignment of attributes and subscripts is disallowed, augmented assignment of names (such as 'n += 1') is allowed. 'n += 1' becomes 'n = __rl_augAssign__("+=", n, 1)' """ node = self.visit_children(node) if isinstance(node.target, ast.Attribute): self.error(node, "Augmented assignment of attributes is not allowed.") elif isinstance(node.target, ast.Subscript): self.error(node, "Augmented assignment of object items and slices is not allowed.") elif isinstance(node.target, ast.Name): new_node = ast.Assign( targets=[node.target], value=ast.Call( func=ast.Name('__rl_augAssign__', ast.Load()), args=[ ast.Str(augOps[type(node.op)]), ast.Name(node.target.id, ast.Load()), node.value ], keywords=[])) copy_locations(new_node, node) return new_node else: # pragma: no cover # Impossible Case - Only Node Types: # * Name # * Attribute # * Subscript # defined, those are checked before. raise NotImplementedError("Unknown target type: %s" % type(node.target)) def visit_While(node): self.visit_children(node) return node def visit_ExceptHandler(self, node): """Protect tuple unpacking on exception handlers. try: ..... except Exception as (a, b): .... becomes try: ..... except Exception as tmp: try: (a, b) = __rl_getiter__(tmp) finally: del tmp """ node = self.visit_children(node) self.isAllowedName(node, node.name) return node def visit_With(self, node): """Protect tuple unpacking on with statements.""" node = self.visit_children(node) items = node.items for item in reversed(items): if isinstance(item.optional_vars, ast.Tuple): tmp_target, unpack = self.gen_unpack_wrapper( node, item.optional_vars) item.optional_vars = tmp_target node.body.insert(0, unpack) return node # Function and class definitions def visit_FunctionDef(self, node): """Allow function definitions (`def`) with some restrictions.""" self.isAllowedName(node, node.name) self.check_function_argument_names(node) return node def visit_Lambda(self, node): """Allow lambda with some restrictions.""" self.check_function_argument_names(node) node = self.visit_children(node) return node def visit_ClassDef(self, node): """Check the name of a class definition.""" self.isAllowedName(node, node.name) node = self.visit_children(node) if any(keyword.arg == 'metaclass' for keyword in node.keywords): self.error(node, 'The keyword argument "metaclass" is not allowed.') CLASS_DEF = textwrap.dedent('''\ class %s(metaclass=__metaclass__): pass ''' % node.name) new_class_node = ast.parse(CLASS_DEF).body[0] new_class_node.body = node.body new_class_node.bases = node.bases new_class_node.decorator_list = node.decorator_list return new_class_node # Imports def visit_Import(self, node): return self.check_import_names(node) node = self.visit_children(node) new_node = ast.Call( func=ast.Name('__rl_add__', ast.Load()), args=[node.left, node.right], keywords=[]) copy_locations(new_node, node) return new_node def visit_BinOp(self,node): node = self.visit_children(node) op = node.op if isinstance(op,(ast.Mult,ast.Add,ast.Pow)): opf = ('__rl_mult__' if isinstance(op,ast.Mult) else '__rl_add__' if isinstance(op,ast.Add) else '__rl_pow__') new_node = ast.Call( func=ast.Name(opf, ast.Load()), args=[node.left, node.right], keywords=[]) copy_locations(new_node, node) return new_node return node visit_ImportFrom = visit_Import visit_For = guard_iter visit_comprehension = guard_iter def generic_visit(self, node): """Reject nodes which do not have a corresponding `visit` method.""" self.not_allowed(node) def not_allowed(self, node): self.error(node, '%s statements are not allowed.'%node.__class__.__name__) def visit_children(self, node): """Visit the contents of a node.""" return super(UntrustedAstTransformer, self).generic_visit(node) if eval_debug>=2: def visit(self, node): method = 'visit_' + node.__class__.__name__ visitor = getattr(self, method, self.generic_visit) print('visitor=%s=%r node=%r' % (method,visitor,node)) return visitor(node) visit_Ellipsis = not_allowed visit_MatMult = not_allowed visit_Exec = not_allowed visit_Nonlocal = not_allowed visit_AsyncFunctionDef = not_allowed visit_Await = not_allowed visit_AsyncFor = not_allowed visit_AsyncWith = not_allowed visit_Print = not_allowed visit_Num = visit_children visit_Str = visit_children visit_Bytes = visit_children visit_List = visit_children visit_Tuple = visit_children visit_Set = visit_children visit_Dict = visit_children visit_FormattedValue = visit_children visit_JoinedStr = visit_children visit_NameConstant = visit_children visit_Load = visit_children visit_Store = visit_children visit_Del = visit_children visit_Starred = visit_children visit_Expression = visit_children visit_Expr = visit_children visit_UnaryOp = visit_children visit_UAdd = visit_children visit_USub = visit_children visit_Not = visit_children visit_Invert = visit_children visit_Add = visit_children visit_Sub = visit_children visit_Mult = visit_children visit_Div = visit_children visit_FloorDiv = visit_children visit_Pow = visit_children visit_Mod = visit_children visit_LShift = visit_children visit_RShift = visit_children visit_BitOr = visit_children visit_BitXor = visit_children visit_BitAnd = visit_children visit_BoolOp = visit_children visit_And = visit_children visit_Or = visit_children visit_Compare = visit_children visit_Eq = visit_children visit_NotEq = visit_children visit_Lt = visit_children visit_LtE = visit_children visit_Gt = visit_children visit_GtE = visit_children visit_Is = visit_children visit_IsNot = visit_children visit_In = visit_children visit_NotIn = visit_children visit_keyword = visit_children visit_IfExp = visit_children visit_Index = visit_children visit_Slice = visit_children visit_ExtSlice = visit_children visit_ListComp = visit_children visit_SetComp = visit_children visit_GeneratorExp = visit_children visit_DictComp = visit_children visit_Raise = visit_children visit_Assert = visit_children visit_Delete = visit_children visit_Pass = visit_children visit_alias = visit_children visit_If = visit_children visit_Break = visit_children visit_Continue = visit_children visit_Try = visit_children visit_TryFinally = visit_children visit_TryExcept = visit_children visit_withitem = visit_children visit_arguments = visit_children visit_arg = visit_children visit_Return = visit_children visit_Yield = visit_children visit_YieldFrom = visit_children visit_Global = visit_children visit_Module = visit_children visit_Param = visit_children def astFormat(node): return ast.dump(copy.deepcopy(node),annotate_fields=True, include_attributes=True,indent=4) class __rl_SafeIter__: def __init__(self, it, owner): self.__rl_iter__ = owner().__rl_real_iter__(it) self.__rl_owner__ = owner def __iter__(self): return self def __next__(self): self.__rl_owner__().__rl_check__() return next(self.__rl_iter__) next = __next__ # Python 2 compat __rl_safe_builtins__ = {} #constructed below def safer_globals(g=None): if g is None: g = sys._getframe(1).f_globals.copy() for name in ('__annotations__', '__doc__', '__loader__', '__name__', '__package__', '__spec__'): if name in g: del g[name] g['__builtins__'] = __rl_safe_builtins__.copy() return g math_log10 = math.log10 __rl_undef__ = object() class __RL_SAFE_ENV__: __time_time__ = time.time __weakref_ref__ = weakref.ref __slicetype__ = type(slice(0)) def __init__(self, timeout=None, allowed_magic_methods=None): self.timeout = timeout if timeout is not None else self.__rl_tmax__ self.allowed_magic_methods = (__allowed_magic_methods__ if allowed_magic_methods==True else allowed_magic_methods) if allowed_magic_methods else [] import builtins self.__rl_gen_range__ = builtins.range self.__rl_real_iter__ = builtins.iter class __rl_dict__(dict): def __new__(cls, *args,**kwds): if len(args)==1 and not isinstance(args[0],dict): try: it = self.__real_iter__(args[0]) except TypeError: pass else: args = (self.__rl_getiter__(it),) return dict.__new__(cls,*args,**kwds) class __rl_missing_func__: def __init__(self,name): self.__name__ = name def __call__(self,*args,**kwds): raise BadCode('missing global %s' % self.__name__) self.real_bi = builtins self.bi_replace = ( ('open',__rl_missing_func__('open')), ('iter',self.__rl_getiter__), ) __rl_safe_builtins__.update({_:getattr(builtins,_) for _ in ('''None False True abs bool callable chr complex divmod float hash hex id int isinstance issubclass len oct ord range repr round slice str tuple setattr classmethod staticmethod property divmod next object getattr dict iter pow list type max min sum enumerate zip hasattr filter map any all sorted reversed range set frozenset ArithmeticError AssertionError AttributeError BaseException BufferError BytesWarning DeprecationWarning EOFError EnvironmentError Exception FloatingPointError FutureWarning GeneratorExit IOError ImportError ImportWarning IndentationError IndexError KeyError KeyboardInterrupt LookupError MemoryError NameError NotImplementedError OSError OverflowError PendingDeprecationWarning ReferenceError RuntimeError RuntimeWarning StopIteration SyntaxError SyntaxWarning SystemError SystemExit TabError TypeError UnboundLocalError UnicodeDecodeError UnicodeEncodeError UnicodeError UnicodeTranslateError UnicodeWarning UserWarning ValueError Warning ZeroDivisionError __build_class__''' ).split()}) self.__rl_builtins__ = __rl_builtins__ = {_:__rl_missing_func__(_) for _ in dir(builtins) if callable(getattr(builtins,_))} __rl_builtins__.update(__rl_safe_builtins__) #these are used in the tree visitor __rl_builtins__['__rl_add__'] = self.__rl_add__ __rl_builtins__['__rl_mult__'] = self.__rl_mult__ __rl_builtins__['__rl_pow__'] = self.__rl_pow__ __rl_builtins__['__rl_sd__'] = self.__rl_sd__ __rl_builtins__['__rl_augAssign__'] = self.__rl_augAssign__ __rl_builtins__['__rl_getitem__'] = self.__rl_getitem__ __rl_builtins__['__rl_getattr__'] = self.__rl_getattr__ __rl_builtins__['__rl_getiter__'] = self.__rl_getiter__ __rl_builtins__['__rl_max_len__'] = self.__rl_max_len__ __rl_builtins__['__rl_max_pow_digits__'] = self.__rl_max_pow_digits__ __rl_builtins__['__rl_iter_unpack_sequence__'] = self.__rl_iter_unpack_sequence__ __rl_builtins__['__rl_unpack_sequence__'] = self.__rl_unpack_sequence__ __rl_builtins__['__rl_apply__'] = lambda func,*args,**kwds: self.__rl_apply__(func,args,kwds) __rl_builtins__['__rl_SafeIter__'] = __rl_SafeIter__ #these are tested builtins __rl_builtins__['getattr'] = self.__rl_getattr__ __rl_builtins__['dict'] = __rl_dict__ __rl_builtins__['iter'] = self.__rl_getiter__ __rl_builtins__['pow'] = self.__rl_pow__ __rl_builtins__['list'] = self.__rl_list__ __rl_builtins__['type'] = self.__rl_type__ __rl_builtins__['max'] = self.__rl_max__ __rl_builtins__['min'] = self.__rl_min__ __rl_builtins__['sum'] = self.__rl_sum__ __rl_builtins__['enumerate'] = self.__rl_enumerate__ __rl_builtins__['zip'] = self.__rl_zip__ __rl_builtins__['hasattr'] = self.__rl_hasattr__ __rl_builtins__['filter'] = self.__rl_filter__ __rl_builtins__['map'] = self.__rl_map__ __rl_builtins__['any'] = self.__rl_any__ __rl_builtins__['all'] = self.__rl_all__ __rl_builtins__['sorted'] = self.__rl_sorted__ __rl_builtins__['reversed'] = self.__rl_reversed__ __rl_builtins__['range'] = self.__rl_range__ __rl_builtins__['set'] = self.__rl_set__ __rl_builtins__['frozenset'] = self.__rl_frozenset__ def __rl_type__(self,*args): if len(args)==1: return type(*args) raise BadCode('type call error') def __rl_check__(self): if self.__time_time__() >= self.__rl_limit__: raise BadCode('Resources exceeded') def __rl_sd__(self,obj): return obj def __rl_getiter__(self,it): return __rl_SafeIter__(it,owner=self.__weakref_ref__(self)) def __rl_max__(self,arg,*args,**kwds): if args: arg = [arg] arg.extend(args) return max(self.__rl_args_iter__(arg),**kwds) def __rl_min__(self,arg,*args,**kwds): if args: arg = [arg] arg.extend(args) return min(self.__rl_args_iter__(arg),**kwds) def __rl_sum__(self, sequence, start=0): return sum(self.__rl_args_iter__(sequence), start) def __rl_enumerate__(self, seq): return enumerate(self.__rl_args_iter__(seq)) def __rl_zip__(self,*args): return zip(*[self.__rl_args_iter__(self.__rl_getitem__(args, i)) for i in range(len(args))]) def __rl_hasattr__(self, obj, name): try: self.__rl_getattr__(obj, name) except (AttributeError, BadCode, TypeError): return False return True def __rl_filter__(self, f, seq): return filter(f,self.__rl_args_iter__(seq)) def __rl_map__(self, f, seq): return map(f,self.__rl_args_iter__(seq)) def __rl_any__(self, seq): return any(self.__rl_args_iter__(seq)) def __rl_all__(self, seq): return all(self.__rl_args_iter__(seq)) def __rl_sorted__(self, seq, **kwds): return sorted(self.__rl_args_iter__(seq),**kwds) def __rl_reversed__(self, seq): return self.__rl_args_iter__(reversed(seq)) def __rl_range__(self,start,*args): return self.__rl_getiter__(range(start,*args)) def __rl_set__(self, it): return set(self.__rl_args_iter__(it)) def __rl_frozenset__(self, it): return frozenset(self.__rl_args_iter__(it)) def __rl_iter_unpack_sequence__(self, it, spec, _getiter_): """Protect sequence unpacking of targets in a 'for loop'. The target of a for loop could be a sequence. For example "for a, b in it" => Each object from the iterator needs guarded sequence unpacking. """ # The iteration itself needs to be protected as well. for ob in _getiter_(it): yield self.__rl_unpack_sequence__(ob, spec, _getiter_) def __rl_unpack_sequence__(self, it, spec, _getiter_): """Protect nested sequence unpacking. Protect the unpacking of 'it' by wrapping it with '_getiter_'. Furthermore for each child element, defined by spec, __rl_unpack_sequence__ is called again. Have a look at transformer.py 'gen_unpack_spec' for a more detailed explanation. """ # Do the guarded unpacking of the sequence. ret = list(self.__rl__getiter__(it)) # If the sequence is shorter then expected the interpreter will raise # 'ValueError: need more than X value to unpack' anyway # => No childs are unpacked => nothing to protect. if len(ret) < spec['min_len']: return ret # For all child elements do the guarded unpacking again. for (idx, child_spec) in spec['childs']: ret[idx] = self.__rl_unpack_sequence__(ret[idx], child_spec, _getiter_) return ret def __rl_is_allowed_name__(self, name): """Check names if they are allowed. If ``allow_magic_methods is True`` names in `__allowed_magic_methods__` are additionally allowed although their names start with `_`. """ if isinstance(name,strTypes): if name in __rl_unsafe__ or (name.startswith('__') and name!='__' and name not in self.allowed_magic_methods): raise BadCode('unsafe access of %s' % name) def __rl_getattr__(self, obj, a, *args): if isinstance(obj, strTypes) and a=='format': raise BadCode('%s.format is not implemented' % type(obj)) self.__rl_is_allowed_name__(a) return getattr(obj,a,*args) def __rl_getitem__(self, obj, a): if type(a) is self.__slicetype__: if a.step is not None: v = obj[a] else: start = a.start stop = a.stop if start is None: start = 0 if stop is None: v = obj[start:] else: v = obj[start:stop] return v elif isinstance(a,strTypes): self.__rl_is_allowed_name__(a) return obj[a] return obj[a] __rl_tmax__ = 5 __rl_max_len__ = 100000 __rl_max_pow_digits__ = 100 def __rl_add__(self, a, b): if (hasattr(a, '__len__') and hasattr(b, '__len__') and (len(a) + len(b)) > self.__rl_max_len__): raise BadCode("excessive length") return a + b def __rl_mult__(self, a, b): if ((hasattr(a, '__len__') and b * len(a) > self.__rl_max_len__) or (hasattr(b, '__len__') and a * len(b) > self.__rl_max_len__)): raise BadCode("excessive length") return a * b def __rl_pow__(self, a, b): try: if b>0: if int(b*math_log10(a)+1)>self.__rl_max_pow_digits__: raise BadCode except: raise BadCode('%r**%r invalid or too large' % (a,b)) return a ** b def __rl_augAssign__(self,op,v,i): if op=='+=': return self.__rl_add__(v,i) if op=='-=': return v-i if op=='*=': return self.__rl_mult__(v,i) if op=='/=': return v/i if op=='%=': return v%i if op=='**=': return self.__rl_pow__(v,i) if op=='<<=': return v<>=': return v>>i if op=='|=': return v|i if op=='^=': return v^i if op=='&=': return v&i if op=='//=': return v//i def __rl_apply__(self, func, args, kwds): obj = getattr(func,'__self__',None) if obj: if isinstance(obj,dict) and func.__name__ in ('pop','setdefault','get', 'popitem'): self.__rl_is_allowed_name__(args[0]) return func(*[a for a in self.__rl_getiter__(args)], **{k:v for k,v in kwds.items()}) def __rl_args_iter__(self,*args): if len(args) == 1: i = args[0] # Don't double-wrap if isinstance(i, __rl_SafeIter__): return i if not isinstance(i,self.__rl_gen_range__): return self.__rl_getiter__(i) return self.__rl_getiter__(iter(*args)) def __rl_list__(self,it): return list(self.__rl_getiter__(it)) def __rl_compile__(self, src, fname='', mode="eval", flags=0, inherit=True, visit=None): names_seen = {} if not visit: bcode = compile(src, fname, mode=mode, flags=flags, dont_inherit=not inherit) else: astc = ast.parse(src, fname, mode) if eval_debug>0: print('pre:\n%s\n'%astFormat(astc)) astc = visit(astc) if eval_debug>0: print('post:\n%s\n'%astFormat(astc)) bcode = compile(astc, fname, mode=mode) return bcode, names_seen def __rl_safe_eval__(self, expr, g, l, mode, timeout=None, allowed_magic_methods=None, __frame_depth__=3): bcode, ns = self.__rl_compile__(expr, fname='', mode=mode, flags=0, inherit=True, visit=UntrustedAstTransformer(nameIsAllowed=self.__rl_is_allowed_name__).visit) if None in (l,g): G = sys._getframe(__frame_depth__) L = G.f_locals.copy() if l is None else l G = G.f_globals.copy() if g is None else g else: G = g L = l obi = (G['__builtins__'],) if '__builtins__' in G else False G['__builtins__'] = self.__rl_builtins__ self.__rl_limit__ = self.__time_time__() + (timeout if timeout is not None else self.timeout) if allowed_magic_methods is not None: self.allowed_magic_methods = ( __allowed_magic_methods__ if allowed_magic_methods==True else allowed_magic_methods) if allowed_magic_methods else [] sbi = [].append bi = self.real_bi bir = self.bi_replace for n, r in bir: sbi(getattr(bi,n)) setattr(bi,n,r) try: return eval(bcode,G,L) finally: sbi = sbi.__self__ for i, (n, r) in enumerate(bir): setattr(bi,n,sbi[i]) if obi: G['__builtins__'] = obi[0] class __rl_safe_eval__: '''creates one environment and re-uses it''' mode = 'eval' def __init__(self): self.env = None def __call__(self, expr, g=None, l=None, timeout=None, allowed_magic_methods=None): if not self.env: self.env = __RL_SAFE_ENV__(timeout=timeout, allowed_magic_methods=allowed_magic_methods) return self.env.__rl_safe_eval__(expr, g, l, self.mode, timeout=timeout, allowed_magic_methods=allowed_magic_methods, __frame_depth__=2) class __rl_safe_exec__(__rl_safe_eval__): mode = 'exec' def rl_extended_literal_eval(expr, safe_callables=None, safe_names=None): if safe_callables is None: safe_callables = {} if safe_names is None: safe_names = {} safe_names = safe_names.copy() safe_names.update({'None': None, 'True': True, 'False': False}) #make these readonly with MappingProxyType safe_names = types.MappingProxyType(safe_names) safe_callables = types.MappingProxyType(safe_callables) if isinstance(expr, str): expr = ast.parse(expr, mode='eval') if isinstance(expr, ast.Expression): expr = expr.body try: # Python 3.4 and up ast.NameConstant safe_test = lambda n: isinstance(n, ast.NameConstant) or isinstance(n,ast.Name) and n.id in safe_names safe_extract = lambda n: n.value if isinstance(n,ast.NameConstant) else safe_names[n.id] except AttributeError: # Everything before safe_test = lambda n: isinstance(n, ast.Name) and n.id in safe_names safe_extract = lambda n: safe_names[n.id] def _convert(node): if isinstance(node, (ast.Str, ast.Bytes)): return node.s elif isinstance(node, ast.Num): return node.n elif isinstance(node, ast.Tuple): return tuple(map(_convert, node.elts)) elif isinstance(node, ast.List): return list(map(_convert, node.elts)) elif isinstance(node, ast.Dict): return dict((_convert(k), _convert(v)) for k, v in zip(node.keys, node.values)) elif safe_test(node): return safe_extract(node) elif isinstance(node, ast.UnaryOp) and \ isinstance(node.op, (ast.UAdd, ast.USub)) and \ isinstance(node.operand, (ast.Num, ast.UnaryOp, ast.BinOp)): operand = _convert(node.operand) if isinstance(node.op, ast.UAdd): return + operand else: return - operand elif isinstance(node, ast.BinOp) and \ isinstance(node.op, (ast.Add, ast.Sub)) and \ isinstance(node.right, (ast.Num, ast.UnaryOp, ast.BinOp)) and \ isinstance(node.right.n, complex) and \ isinstance(node.left, (ast.Num, ast.UnaryOp, astBinOp)): left = _convert(node.left) right = _convert(node.right) if isinstance(node.op, ast.Add): return left + right else: return left - right elif isinstance(node, ast.Call) and \ isinstance(node.func, ast.Name) and \ node.func.id in safe_callables: return safe_callables[node.func.id]( *[_convert(n) for n in node.args], **{kw.arg: _convert(kw.value) for kw in node.keywords}) raise ValueError('Bad expression') return _convert(expr) rl_safe_exec = __rl_safe_exec__() rl_safe_eval = __rl_safe_eval__() ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1691062243.0 reportlab-4.1.0/src/reportlab/lib/rltempfile.py0000664000175000017500000000214114462707743021162 0ustar00rptlabrptlab#Copyright ReportLab Europe Ltd. 2000-2017 #see license.txt for license details # $URI:$ __version__='3.3.0' __doc__='''Helper for the test suite - determines where to write output. When our test suite runs as source, a script "test_foo.py" will typically create "test_foo.pdf" alongside it. But if you are testing a package of compiled code inside a zip archive, this won't work. This determines where to write test suite output, creating a subdirectory of /tmp/ or whatever if needed. ''' _rl_tempdir=None __all__ = ('get_rl_tempdir', 'get_rl_tempdir') import os, tempfile def _rl_getuid(): if hasattr(os,'getuid'): return os.getuid() else: return '' def get_rl_tempdir(*subdirs): global _rl_tempdir if _rl_tempdir is None: _rl_tempdir = os.path.join(tempfile.gettempdir(),'ReportLab_tmp%s' % str(_rl_getuid())) d = _rl_tempdir if subdirs: d = os.path.join(*((d,)+subdirs)) try: os.makedirs(d) except: pass return d def get_rl_tempfile(fn=None): if not fn: fn = tempfile.mktemp() return os.path.join(get_rl_tempdir(),fn) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1704966359.0 reportlab-4.1.0/src/reportlab/lib/rparsexml.py0000664000175000017500000004374714547734327021057 0ustar00rptlabrptlab"""Very simple and fast XML parser, used for intra-paragraph text. Devised by Aaron Watters in the bad old days before Python had fast parsers available. Constructs the lightest possible in-memory representation; parses most files we have seen in pure python very quickly. The output structure is the same as the one produced by pyRXP, our validating C-based parser, which was written later. It will use pyRXP if available. This is used to parse intra-paragraph markup. Example parse:: text in xml ( "this", {"type": "xml"}, [ "text ", ("b", None, ["in"], None), " xml" ] None ) { 0: "this" "type": "xml" 1: ["text ", {0: "b", 1:["in"]}, " xml"] } Ie, xml tag translates to a tuple: (name, dictofattributes, contentlist, miscellaneousinfo) where miscellaneousinfo can be anything, (but defaults to None) (with the intention of adding, eg, line number information) special cases: name of "" means "top level, no containing tag". Top level parse always looks like this:: ("", list, None, None) contained text of None means In order to support stuff like:: AT THE MOMENT & ETCETERA ARE IGNORED. THEY MUST BE PROCESSED IN A POST-PROCESSING STEP. PROLOGUES ARE NOT UNDERSTOOD. OTHER STUFF IS PROBABLY MISSING. """ RequirePyRXP = 0 # set this to 1 to disable the nonvalidating fallback parser. try: #raise ImportError, "dummy error" simpleparse = 0 import pyRXPU def warnCB(s): print(s) pyRXP_parser = pyRXPU.Parser( ErrorOnValidityErrors=1, NoNoDTDWarning=1, ExpandCharacterEntities=1, ExpandGeneralEntities=1, warnCB = warnCB, srcName='string input', ReturnUTF8 = 0, ) def parsexml(xmlText, oneOutermostTag=0,eoCB=None,entityReplacer=None,parseOpts={}): pyRXP_parser.eoCB = eoCB p = pyRXP_parser.parse(xmlText,**parseOpts) return oneOutermostTag and p or ('',None,[p],None) except ImportError: simpleparse = 1 class smartDecode: @staticmethod def __call__(s): #print('initial') import chardet def __call__(s): if isinstance(s,str): return s cdd = chardet.detect(s) #print('final') return s.decode(cdd["encoding"]) smartDecode.__class__.__call__ = staticmethod(__call__) return __call__(s) smartDecode = smartDecode() NONAME = "" NAMEKEY = 0 CONTENTSKEY = 1 CDATAMARKER = "" replacelist = [("<", "<"), (">", ">"), ("&", "&")] # amp must be last #replacelist = [] def unEscapeContentList(contentList): result = [] for e in contentList: if "&" in e: for (old, new) in replacelist: e = e.replace(old, new) result.append(e) return result def parsexmlSimple(xmltext, oneOutermostTag=0,eoCB=None,entityReplacer=unEscapeContentList): """official interface: discard unused cursor info""" if RequirePyRXP: raise ImportError("pyRXP not found, fallback parser disabled") (result, cursor) = parsexml0(xmltext,entityReplacer=entityReplacer) if oneOutermostTag: return result[2][0] else: return result if simpleparse: parsexml = parsexmlSimple def parseFile(filename): raw = open(filename, 'r').read() return parsexml(raw) verbose = 0 def skip_prologue(text, cursor): """skip any prologue found after cursor, return index of rest of text""" ### NOT AT ALL COMPLETE!!! definitely can be confused!!! prologue_elements = ("!DOCTYPE", "?xml", "!--") done = None while done is None: #print "trying to skip:", repr(text[cursor:cursor+20]) openbracket = text.find("<", cursor) if openbracket<0: break past = openbracket+1 found = None for e in prologue_elements: le = len(e) if text[past:past+le]==e: found = 1 cursor = text.find(">", past) if cursor<0: raise ValueError("can't close prologue %r" % e) cursor = cursor+1 if found is None: done=1 #print "done skipping" return cursor def parsexml0(xmltext, startingat=0, toplevel=1, # snarf in some globals entityReplacer=unEscapeContentList, #len=len, None=None #LENCDATAMARKER=LENCDATAMARKER, CDATAMARKER=CDATAMARKER ): """simple recursive descent xml parser... return (dictionary, endcharacter) special case: comment returns (None, endcharacter)""" xmltext = smartDecode(xmltext) #print "parsexml0", repr(xmltext[startingat: startingat+10]) # DEFAULTS NameString = NONAME ContentList = AttDict = ExtraStuff = None if toplevel is not None: #if verbose: print "at top level" #if startingat!=0: # raise ValueError, "have to start at 0 for top level!" xmltext = xmltext.strip() cursor = startingat #look for interesting starting points firstbracket = xmltext.find("<", cursor) afterbracket2char = xmltext[firstbracket+1:firstbracket+3] #print "a", repr(afterbracket2char) #firstampersand = xmltext.find("&", cursor) #if firstampersand>0 and firstampersand0: #afterbracket2char = xmltext[firstbracket:firstbracket+2] if toplevel is not None: #print "toplevel with no outer tag" NameString = name = NONAME cursor = skip_prologue(xmltext, cursor) #break elif firstbracket<0: raise ValueError("non top level entry should be at start tag: %s" % repr(xmltext[:10])) # special case: CDATA elif afterbracket2char=="![" and xmltext[firstbracket:firstbracket+9]=="": raise ValueError("invalid comment: contains double dashes %s" % repr(xmltext[cursor:cursor+20])) return (None, endcomment+1) # shortcut exit else: # get the rest of the tag #if verbose: print "parsing start tag" # make sure the tag isn't in doublequote pairs closebracket = xmltext.find(">", firstbracket) noclose = closebracket<0 startsearch = closebracket+1 pastfirstbracket = firstbracket+1 tagcontent = xmltext[pastfirstbracket:closebracket] # shortcut, no equal means nothing but name in the tag content if '=' not in tagcontent: if tagcontent[-1]=="/": # simple case #print "simple case", tagcontent tagcontent = tagcontent[:-1] docontents = None name = tagcontent.strip() NameString = name cursor = startsearch else: if '"' in tagcontent: # check double quotes stop = None # not inside double quotes! (the split should have odd length) if noclose or len((tagcontent+".").split('"'))% 2: stop=1 while stop is None: closebracket = xmltext.find(">", startsearch) startsearch = closebracket+1 noclose = closebracket<0 tagcontent = xmltext[pastfirstbracket:closebracket] # not inside double quotes! (the split should have odd length) if noclose or len((tagcontent+".").split('"'))% 2: stop=1 if noclose: raise ValueError("unclosed start tag %s" % repr(xmltext[firstbracket:firstbracket+20])) cursor = startsearch #cursor = closebracket+1 # handle simple tag /> syntax if xmltext[closebracket-1]=="/": #if verbose: print "it's a simple tag" closebracket = closebracket-1 tagcontent = tagcontent[:-1] docontents = None #tagcontent = xmltext[firstbracket+1:closebracket] tagcontent = tagcontent.strip() taglist = tagcontent.split("=") #if not taglist: # raise ValueError, "tag with no name %s" % repr(xmltext[firstbracket:firstbracket+20]) taglist0 = taglist[0] taglist0list = taglist0.split() #if len(taglist0list)>2: # raise ValueError, "bad tag head %s" % repr(taglist0) name = taglist0list[0] #print "tag name is", name NameString = name # now parse the attributes attributename = taglist0list[-1] # put a fake att name at end of last taglist entry for consistent parsing taglist[-1] = taglist[-1]+" f" AttDict = D = {} taglistindex = 1 lasttaglistindex = len(taglist) #for attentry in taglist[1:]: while taglistindexlasttaglistindex: raise ValueError("unclosed value " + repr(attentry)) nextattentry = taglist[taglistindex] taglistindex = taglistindex+1 attentry = "%s=%s" % (attentry, nextattentry) attentry = attentry.strip() # only needed for while loop... attlist = attentry.split() nextattname = attlist[-1] attvalue = attentry[:-len(nextattname)] attvalue = attvalue.strip() try: first = attvalue[0]; last=attvalue[-1] except: raise ValueError("attvalue,attentry,attlist="+repr((attvalue, attentry,attlist))) if first==last=='"' or first==last=="'": attvalue = attvalue[1:-1] #print attributename, "=", attvalue D[attributename] = attvalue attributename = nextattname # pass over other tags and content looking for end tag if docontents is not None: #print "now looking for end tag" ContentList = L while docontents is not None: nextopenbracket = xmltext.find("<", cursor) if nextopenbracket", nextopenbracket) if nextclosebracket\n%s\n" % (name, attributes, textpprint, name) # otherwise must be a simple tag return "<%s %s/>" % (name, attributes) def testparse(s,dump=0): from time import time from pprint import pprint now = time() D = parsexmlSimple(s,oneOutermostTag=1) print("DONE", time()-now) if dump&4: pprint(D) #pprint(D) if dump&1: print("============== reformatting") p = pprettyprint(D) print(p) def test(dump=0): testparse("""text <>in xml text in xml ]]> just testing brackets feature """,dump=dump) if __name__=="__main__": test(dump=1) import sys, os from time import time import reportlab now = time() seen = 0 for f in sys.argv[1:]: if not os.path.isfile(f): print("!!!!! no file at {f!r}") else: with open(f) as _f: t = _f.read() print(f"parsing {f!r} |t|={len(t)}") testparse(t,dump=1) seen += 1 if seen: print(f"timed at {time()-now:.2f} secs.") ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1691062243.0 reportlab-4.1.0/src/reportlab/lib/sequencer.py0000664000175000017500000002265714462707743021027 0ustar00rptlabrptlab#Copyright ReportLab Europe Ltd. 2000-2017 #see license.txt for license details __version__='3.3.0' __doc__="""A Sequencer class counts things. It aids numbering and formatting lists.""" __all__='''Sequencer getSequencer setSequencer'''.split() # # roman numbers conversion thanks to # # fredrik lundh, november 1996 (based on a C hack from 1984) # # fredrik@pythonware.com # http://www.pythonware.com _RN_TEMPLATES = [ 0, 0o1, 0o11, 0o111, 0o12, 0o2, 0o21, 0o211, 0o2111, 0o13 ] _RN_LETTERS = "IVXLCDM" def _format_I(value): if value < 0 or value > 3999: raise ValueError("illegal value") str = "" base = -1 while value: value, index = divmod(value, 10) tmp = _RN_TEMPLATES[index] while tmp: tmp, index = divmod(tmp, 8) str = _RN_LETTERS[index+base] + str base += 2 return str def _format_i(num): return _format_I(num).lower() def _format_123(num): """The simplest formatter""" return str(num) def _format_ABC(num): """Uppercase. Wraps around at 26.""" n = (num -1) % 26 return chr(n+65) def _format_abc(num): """Lowercase. Wraps around at 26.""" n = (num -1) % 26 return chr(n+97) _type2formatter = { 'I':_format_I, 'i':_format_i, '1':_format_123, 'A':_format_ABC, 'a':_format_abc, } class _Counter: """Private class used by Sequencer. Each counter knows its format, and the IDs of anything it resets, as well as its value. Starts at zero and increments just before you get the new value, so that it is still 'Chapter 5' and not 'Chapter 6' when you print 'Figure 5.1'""" def __init__(self): self._base = 0 self._value = self._base self._formatter = _format_123 self._resets = [] def setFormatter(self, formatFunc): self._formatter = formatFunc def reset(self, value=None): if value: self._value = value else: self._value = self._base def next(self): self._value += 1 v = self._value for counter in self._resets: counter.reset() return v __next__ = next def _this(self): return self._value def nextf(self): """Returns next value formatted""" return self._formatter(next(self)) def thisf(self): return self._formatter(self._this()) def chain(self, otherCounter): if not otherCounter in self._resets: self._resets.append(otherCounter) class Sequencer: """Something to make it easy to number paragraphs, sections, images and anything else. The features include registering new string formats for sequences, and 'chains' whereby some counters are reset when their parents. It keeps track of a number of 'counters', which are created on request: Usage:: >>> seq = layout.Sequencer() >>> seq.next('Bullets') 1 >>> seq.next('Bullets') 2 >>> seq.next('Bullets') 3 >>> seq.reset('Bullets') >>> seq.next('Bullets') 1 >>> seq.next('Figures') 1 >>> """ def __init__(self): self._counters = {} #map key to current number self._formatters = {} self._reset() def _reset(self): self._counters.clear() self._formatters.clear() self._formatters.update({ # the formats it knows initially '1':_format_123, 'A':_format_ABC, 'a':_format_abc, 'I':_format_I, 'i':_format_i, }) d = dict(_counters=self._counters,_formatters=self._formatters) self.__dict__.clear() self.__dict__.update(d) self._defaultCounter = None def _getCounter(self, counter=None): """Creates one if not present""" try: return self._counters[counter] except KeyError: cnt = _Counter() self._counters[counter] = cnt return cnt def _this(self, counter=None): """Retrieves counter value but does not increment. For new counters, sets base value to 1.""" if not counter: counter = self._defaultCounter return self._getCounter(counter)._this() def __next__(self): """Retrieves the numeric value for the given counter, then increments it by one. New counters start at one.""" return next(self._getCounter(self._defaultCounter)) def next(self,counter=None): if not counter: return next(self) else: dc = self._defaultCounter try: self._defaultCounter = counter return next(self) finally: self._defaultCounter = dc def thisf(self, counter=None): if not counter: counter = self._defaultCounter return self._getCounter(counter).thisf() def nextf(self, counter=None): """Retrieves the numeric value for the given counter, then increments it by one. New counters start at one.""" if not counter: counter = self._defaultCounter return self._getCounter(counter).nextf() def setDefaultCounter(self, default=None): """Changes the key used for the default""" self._defaultCounter = default def registerFormat(self, format, func): """Registers a new formatting function. The funtion must take a number as argument and return a string; fmt is a short menmonic string used to access it.""" self._formatters[format] = func def setFormat(self, counter, format): """Specifies that the given counter should use the given format henceforth.""" func = self._formatters[format] self._getCounter(counter).setFormatter(func) def reset(self, counter=None, base=0): if not counter: counter = self._defaultCounter self._getCounter(counter)._value = base def chain(self, parent, child): p = self._getCounter(parent) c = self._getCounter(child) p.chain(c) def __getitem__(self, key): """Allows compact notation to support the format function. s['key'] gets current value, s['key+'] increments.""" if key[-1:] == '+': counter = key[:-1] return self.nextf(counter) else: return self.thisf(key) def format(self, template): """The crowning jewels - formats multi-level lists.""" return template % self def dump(self): """Write current state to stdout for diagnostics""" counters = list(self._counters.items()) counters.sort() print('Sequencer dump:') for (key, counter) in counters: print(' %s: value = %d, base = %d, format example = %s' % ( key, counter._this(), counter._base, counter.thisf())) """Your story builder needs to set this to""" _sequencer = None def getSequencer(): global _sequencer if _sequencer is None: _sequencer = Sequencer() return _sequencer def setSequencer(seq): global _sequencer s = _sequencer _sequencer = seq return s def _reset(): global _sequencer if _sequencer: _sequencer._reset() from reportlab.rl_config import register_reset register_reset(_reset) del register_reset def test(): s = Sequencer() print('Counting using default sequence: %d %d %d' % (next(s),next(s), next(s))) print('Counting Figures: Figure %d, Figure %d, Figure %d' % ( s.next('figure'), s.next('figure'), s.next('figure'))) print('Back to default again: %d' % next(s)) s.setDefaultCounter('list1') print('Set default to list1: %d %d %d' % (next(s),next(s), next(s))) s.setDefaultCounter() print('Set default to None again: %d %d %d' % (next(s),next(s), next(s))) print() print('Creating Appendix counter with format A, B, C...') s.setFormat('Appendix', 'A') print(' Appendix %s, Appendix %s, Appendix %s' % ( s.nextf('Appendix'), s.nextf('Appendix'),s.nextf('Appendix'))) def format_french(num): return ('un','deux','trois','quatre','cinq')[(num-1)%5] print() print('Defining a custom format with french words:') s.registerFormat('french', format_french) s.setFormat('FrenchList', 'french') print(' ' +(' '.join(str(s.nextf('FrenchList')) for i in range(1,6)))) print() print('Chaining H1 and H2 - H2 goes back to one when H1 increases') s.chain('H1','H2') print(' H1 = %d' % s.next('H1')) print(' H2 = %d' % s.next('H2')) print(' H2 = %d' % s.next('H2')) print(' H2 = %d' % s.next('H2')) print(' H1 = %d' % s.next('H1')) print(' H2 = %d' % s.next('H2')) print(' H2 = %d' % s.next('H2')) print(' H2 = %d' % s.next('H2')) print() print('GetItem notation - append a plus to increment') print(' seq["Appendix"] = %s' % s["Appendix"]) print(' seq["Appendix+"] = %s' % s["Appendix+"]) print(' seq["Appendix+"] = %s' % s["Appendix+"]) print(' seq["Appendix"] = %s' % s["Appendix"]) print() print('Finally, string format notation for nested lists. Cool!') print('The expression ("Figure %(Chapter)s.%(Figure+)s" % seq) gives:') print(' Figure %(Chapter)s.%(Figure+)s' % s) print(' Figure %(Chapter)s.%(Figure+)s' % s) print(' Figure %(Chapter)s.%(Figure+)s' % s) if __name__=='__main__': test() ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1704966359.0 reportlab-4.1.0/src/reportlab/lib/styles.py0000664000175000017500000004151714547734327020356 0ustar00rptlabrptlab#Copyright ReportLab Europe Ltd. 2000-2017 #see license.txt for license details #history https://hg.reportlab.com/hg-public/reportlab/log/tip/src/reportlab/lib/styles.py __version__='3.3.0' __doc__='''Classes for ParagraphStyle and similar things. A style is a collection of attributes, but with some extra features to allow 'inheritance' from a parent, and to ensure nobody makes changes after construction. ParagraphStyle shows all the attributes available for formatting paragraphs. getSampleStyleSheet() returns a stylesheet you can use for initial development, with a few basic heading and text styles. ''' __all__=( 'PropertySet', 'ParagraphStyle', 'str2alignment', 'LineStyle', 'ListStyle', 'StyleSheet1', 'getSampleStyleSheet', ) from reportlab.lib.colors import black from reportlab.lib.enums import TA_LEFT, TA_CENTER, TA_RIGHT, TA_JUSTIFY from reportlab.lib.fonts import tt2ps from reportlab.rl_config import canvas_basefontname as _baseFontName, \ underlineWidth as _baseUnderlineWidth, \ underlineOffset as _baseUnderlineOffset, \ underlineGap as _baseUnderlineGap, \ strikeWidth as _baseStrikeWidth, \ strikeOffset as _baseStrikeOffset, \ strikeGap as _baseStrikeGap, \ spaceShrinkage as _spaceShrinkage, \ platypus_link_underline as _platypus_link_underline, \ hyphenationLang as _hyphenationLang, \ hyphenationMinWordLength as _hyphenationMinWordLength, \ uriWasteReduce as _uriWasteReduce, \ embeddedHyphenation as _embeddedHyphenation _baseFontNameB = tt2ps(_baseFontName,1,0) _baseFontNameI = tt2ps(_baseFontName,0,1) _baseFontNameBI = tt2ps(_baseFontName,1,1) ########################################################### # This class provides an 'instance inheritance' # mechanism for its descendants, simpler than acquisition # but not as far-reaching ########################################################### class PropertySet: defaults = {} def __init__(self, name, parent=None, **kw): """When initialized, it copies the class defaults; then takes a copy of the attributes of the parent if any. All the work is done in init - styles should cost little to use at runtime.""" # step one - validate the hell out of it assert 'name' not in self.defaults, "Class Defaults may not contain a 'name' attribute" assert 'parent' not in self.defaults, "Class Defaults may not contain a 'parent' attribute" if parent: assert parent.__class__ == self.__class__, "Parent style %s must have same class as new style %s" % (parent.__class__.__name__,self.__class__.__name__) #step two self.name = name self.parent = parent self.__dict__.update(self.defaults) #step two - copy from parent if any. Try to be # very strict that only keys in class defaults are # allowed, so they cannot inherit self.refresh() self._setKwds(**kw) def _setKwds(self,**kw): #step three - copy keywords if any for key, value in kw.items(): self.__dict__[key] = value def __repr__(self): return "<%s '%s'>" % (self.__class__.__name__, self.name) def refresh(self): """re-fetches attributes from the parent on demand; use if you have been hacking the styles. This is used by __init__""" if self.parent: for key, value in self.parent.__dict__.items(): if (key not in ['name','parent']): self.__dict__[key] = value def listAttrs(self, indent=''): print(indent + 'name =', self.name) print(indent + 'parent =', self.parent) keylist = list(self.__dict__.keys()) keylist.sort() keylist.remove('name') keylist.remove('parent') for key in keylist: value = self.__dict__.get(key, None) print(indent + '%s = %s' % (key, value)) def clone(self, name, parent=None, **kwds): r = self.__class__(name,parent) r.__dict__ = self.__dict__.copy() r.name = name r.parent = parent is None and self or parent r._setKwds(**kwds) return r class ParagraphStyle(PropertySet): defaults = { 'fontName':_baseFontName, 'fontSize':10, 'leading':12, 'leftIndent':0, 'rightIndent':0, 'firstLineIndent':0, 'alignment':TA_LEFT, 'spaceBefore':0, 'spaceAfter':0, 'bulletFontName':_baseFontName, 'bulletFontSize':10, 'bulletIndent':0, #'bulletColor':black, 'textColor': black, 'backColor':None, 'wordWrap':None, #None means do nothing special #CJK use Chinese Line breaking #LTR RTL use left to right / right to left #with support from pyfribi2 if available 'borderWidth': 0, 'borderPadding': 0, 'borderColor': None, 'borderRadius': None, 'allowWidows': 1, 'allowOrphans': 0, 'textTransform':None, #uppercase lowercase (captitalize not yet) or None or absent 'endDots':None, #dots on the last line of left/right justified paras #string or object with text and optional fontName, fontSize, textColor & backColor #dy 'splitLongWords':1, #make best efforts to split long words 'underlineWidth': _baseUnderlineWidth, #underline width default 'bulletAnchor': 'start', #where the bullet is anchored ie start, middle, end or numeric 'justifyLastLine': 0, #n allow justification on the last line for more than n words 0 means don't bother 'justifyBreaks': 0, #justify lines broken with
'spaceShrinkage': _spaceShrinkage, #allow shrinkage of percentage of space to fit on line 'strikeWidth': _baseStrikeWidth, #stroke width default 'underlineOffset': _baseUnderlineOffset, #fraction of fontsize to offset underlines 'underlineGap': _baseUnderlineGap, #gap for double/triple underline 'strikeOffset': _baseStrikeOffset, #fraction of fontsize to offset strikethrough 'strikeGap': _baseStrikeGap, #gap for double/triple strike 'linkUnderline': _platypus_link_underline, 'underlineColor': None, 'strikeColor': None, 'hyphenationLang': _hyphenationLang, #'hyphenationMinWordLength': _hyphenationMinWordLength, 'embeddedHyphenation': _embeddedHyphenation, 'uriWasteReduce': _uriWasteReduce, } def str2alignment(v,__map__=dict( centre=TA_CENTER, center=TA_CENTER, left=TA_LEFT,right=TA_RIGHT, justify=TA_JUSTIFY)): _ = __map__.get(v.lower(),None) if _ is not None: return _ else: raise ValueError(f'{v!r} is illegal value for alignment') class LineStyle(PropertySet): defaults = { 'width':1, 'color': black } def prepareCanvas(self, canvas): """You can ask a LineStyle to set up the canvas for drawing the lines.""" canvas.setLineWidth(1) #etc. etc. class ListStyle(PropertySet): defaults = dict( leftIndent=18, rightIndent=0, bulletAlign='left', bulletType='1', bulletColor=black, bulletFontName='Helvetica', bulletFontSize=12, bulletOffsetY=0, bulletDedent='auto', bulletDir='ltr', bulletFormat=None, start=None, #starting value for a list; if a list then the start sequence ) _stylesheet1_undefined = object() class StyleSheet1: """ This may or may not be used. The idea is to: 1. slightly simplify construction of stylesheets; 2. enforce rules to validate styles when added (e.g. we may choose to disallow having both 'heading1' and 'Heading1' - actual rules are open to discussion); 3. allow aliases and alternate style lookup mechanisms 4. Have a place to hang style-manipulation methods (save, load, maybe support a GUI editor) Access is via getitem, so they can be compatible with plain old dictionaries. """ def __init__(self): self.byName = {} self.byAlias = {} def __getitem__(self, key): try: return self.byAlias[key] except KeyError: try: return self.byName[key] except KeyError: raise KeyError("Style '%s' not found in stylesheet" % key) def get(self,key,default=_stylesheet1_undefined): try: return self[key] except KeyError: if default!=_stylesheet1_undefined: return default raise def __contains__(self, key): return key in self.byAlias or key in self.byName def has_key(self,key): return key in self def add(self, style, alias=None): key = style.name if key in self.byName: raise KeyError("Style '%s' already defined in stylesheet" % key) if key in self.byAlias: raise KeyError("Style name '%s' is already an alias in stylesheet" % key) if alias: if alias in self.byName: raise KeyError("Style '%s' already defined in stylesheet" % alias) if alias in self.byAlias: raise KeyError("Alias name '%s' is already an alias in stylesheet" % alias) #passed all tests? OK, add it self.byName[key] = style if alias: self.byAlias[alias] = style def list(self): styles = list(self.byName.items()) styles.sort() alii = {} for (alias, style) in list(self.byAlias.items()): alii[style] = alias for (name, style) in styles: alias = alii.get(style, None) print(name, alias) style.listAttrs(' ') print() def testStyles(): pNormal = ParagraphStyle('Normal',None) pNormal.fontName = _baseFontName pNormal.fontSize = 12 pNormal.leading = 14.4 pNormal.listAttrs() print() pPre = ParagraphStyle('Literal', pNormal) pPre.fontName = 'Courier' pPre.listAttrs() return pNormal, pPre def getSampleStyleSheet(): """Returns a stylesheet object""" stylesheet = StyleSheet1() stylesheet.add(ParagraphStyle(name='Normal', fontName=_baseFontName, fontSize=10, leading=12) ) stylesheet.add(ParagraphStyle(name='BodyText', parent=stylesheet['Normal'], spaceBefore=6) ) stylesheet.add(ParagraphStyle(name='Italic', parent=stylesheet['BodyText'], fontName = _baseFontNameI) ) stylesheet.add(ParagraphStyle(name='Heading1', parent=stylesheet['Normal'], fontName = _baseFontNameB, fontSize=18, leading=22, spaceAfter=6), alias='h1') stylesheet.add(ParagraphStyle(name='Title', parent=stylesheet['Normal'], fontName = _baseFontNameB, fontSize=18, leading=22, alignment=TA_CENTER, spaceAfter=6), alias='title') stylesheet.add(ParagraphStyle(name='Heading2', parent=stylesheet['Normal'], fontName = _baseFontNameB, fontSize=14, leading=18, spaceBefore=12, spaceAfter=6), alias='h2') stylesheet.add(ParagraphStyle(name='Heading3', parent=stylesheet['Normal'], fontName = _baseFontNameBI, fontSize=12, leading=14, spaceBefore=12, spaceAfter=6), alias='h3') stylesheet.add(ParagraphStyle(name='Heading4', parent=stylesheet['Normal'], fontName = _baseFontNameBI, fontSize=10, leading=12, spaceBefore=10, spaceAfter=4), alias='h4') stylesheet.add(ParagraphStyle(name='Heading5', parent=stylesheet['Normal'], fontName = _baseFontNameB, fontSize=9, leading=10.8, spaceBefore=8, spaceAfter=4), alias='h5') stylesheet.add(ParagraphStyle(name='Heading6', parent=stylesheet['Normal'], fontName = _baseFontNameB, fontSize=7, leading=8.4, spaceBefore=6, spaceAfter=2), alias='h6') stylesheet.add(ParagraphStyle(name='Bullet', parent=stylesheet['Normal'], firstLineIndent=0, spaceBefore=3), alias='bu') stylesheet.add(ParagraphStyle(name='Definition', parent=stylesheet['Normal'], firstLineIndent=0, leftIndent=36, bulletIndent=0, spaceBefore=6, bulletFontName=_baseFontNameBI), alias='df') stylesheet.add(ParagraphStyle(name='Code', parent=stylesheet['Normal'], fontName='Courier', fontSize=8, leading=8.8, firstLineIndent=0, leftIndent=36, hyphenationLang='')) stylesheet.add(ListStyle(name='UnorderedList', parent=None, leftIndent=18, rightIndent=0, bulletAlign='left', bulletType='1', bulletColor=black, bulletFontName='Helvetica', bulletFontSize=12, bulletOffsetY=0, bulletDedent='auto', bulletDir='ltr', bulletFormat=None, #start='circle square blackstar sparkle disc diamond'.split(), start=None, ), alias='ul') stylesheet.add(ListStyle(name='OrderedList', parent=None, leftIndent=18, rightIndent=0, bulletAlign='left', bulletType='1', bulletColor=black, bulletFontName='Helvetica', bulletFontSize=12, bulletOffsetY=0, bulletDedent='auto', bulletDir='ltr', bulletFormat=None, #start='1 a A i I'.split(), start=None, ), alias='ol') return stylesheet ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1704966359.0 reportlab-4.1.0/src/reportlab/lib/testutils.py0000664000175000017500000003153114547734327021066 0ustar00rptlabrptlab#Copyright ReportLab Europe Ltd. 2000-2017 #see license.txt for license details import reportlab reportlab._rl_testing=True del reportlab __version__='4.0.1' __doc__="""Provides support for the test suite. The test suite as a whole, and individual tests, need to share certain support functions. We have to put these in here so they can always be imported, and so that individual tests need to import nothing more than "reportlab.whatever..." """ import sys, os, fnmatch, re, functools from configparser import ConfigParser import unittest from reportlab.lib.utils import isCompactDistro, __rl_loader__, rl_isdir, asUnicode def haveRenderPM(): from reportlab.graphics.renderPM import _getPMBackend, RenderPMError try: return _getPMBackend() except RenderPMError: return False # Helper functions. def isWritable(D): try: fn = '00DELETE.ME' f = open(fn, 'w') f.write('test of writability - can be deleted') f.close() if os.path.isfile(fn): os.remove(fn) return 1 except: return 0 _OUTDIR = None RL_HOME = None testsFolder = None def setOutDir(name): """Is it a writable file system distro being invoked within test directory? If so, can write test output here. If not, it had better go in a temp directory. Only do this once per process""" global _OUTDIR, RL_HOME, testsFolder if _OUTDIR: return _OUTDIR D = [d[9:] for d in sys.argv if d.startswith('--outdir=')] if not D: D = os.environ.get('RL_TEST_OUTDIR','') if D: D=[D] if D: _OUTDIR = D[-1] try: os.makedirs(_OUTDIR) except: pass for d in D: if d in sys.argv: sys.argv.remove(d) else: assert name=='__main__',"setOutDir should only be called in the main script" scriptDir=os.path.dirname(sys.argv[0]) if not scriptDir: scriptDir=os.getcwd() _OUTDIR = scriptDir if not isWritable(_OUTDIR): _OUTDIR = get_rl_tempdir('reportlab_test') import reportlab RL_HOME=reportlab.__path__[0] if not os.path.isabs(RL_HOME): RL_HOME=os.path.normpath(os.path.abspath(RL_HOME)) topDir = os.path.dirname(RL_HOME) testsFolder = os.path.join(topDir,'tests') if not os.path.isdir(testsFolder): testsFolder = os.path.join(os.path.dirname(topDir),'tests') if not os.path.isdir(testsFolder): if name=='__main__': scriptDir=os.path.dirname(sys.argv[0]) if not scriptDir: scriptDir=os.getcwd() testsFolder = os.path.abspath(scriptDir) else: testsFolder = None if testsFolder: sys.path.insert(0,os.path.dirname(testsFolder)) return _OUTDIR _mockumap = ( None if os.environ.get('OFFLINE_MOCK','1')!='1' else'http://www.reportlab.com/rsrc/encryption.gif', ) def mockUrlRead(name): if name in _mockumap: with open(os.path.join(testsFolder,os.path.basename(name)),'rb') as f: return f.read() else: from urllib.request import urlopen return urlopen(name).read() def outputfile(fn): """This works out where to write test output. If running code in a locked down file system, this will be a temp directory; otherwise, the output of 'test_foo.py' will normally be a file called 'test_foo.pdf', next door. """ D = setOutDir(__name__) if fn: D = os.path.join(D,fn) return D def printLocation(depth=1): if sys._getframe(depth).f_locals.get('__name__')=='__main__': outDir = outputfile('') if outDir!=_OUTDIR: print('Logs and output files written to folder "%s"' % outDir) def makeSuiteForClasses(*classes,testMethodPrefix=None): "Return a test suite with tests loaded from provided classes." suite = unittest.TestSuite() loader = unittest.TestLoader() if testMethodPrefix: loader.testMethodPrefix = testMethodPrefix for C in classes: suite.addTest(loader.loadTestsFromTestCase(C)) return suite def getCVSEntries(folder, files=1, folders=0): """Returns a list of filenames as listed in the CVS/Entries file. 'folder' is the folder that should contain the CVS subfolder. If there is no such subfolder an empty list is returned. 'files' is a boolean; 1 and 0 means to return files or not. 'folders' is a boolean; 1 and 0 means to return folders or not. """ join = os.path.join # If CVS subfolder doesn't exist return empty list. try: f = open(join(folder, 'CVS', 'Entries')) except IOError: return [] # Return names of files and/or folders in CVS/Entries files. allEntries = [] for line in f.readlines(): if folders and line[0] == 'D' \ or files and line[0] != 'D': entry = line.split('/')[1] if entry: allEntries.append(join(folder, entry)) return allEntries # Still experimental class extending ConfigParser's behaviour. class ExtConfigParser(ConfigParser): "A slightly extended version to return lists of strings." pat = re.compile(r'\s*\[.*\]\s*') def getstringlist(self, section, option): "Coerce option to a list of strings or return unchanged if that fails." value = ConfigParser.get(self, section, option) # This seems to allow for newlines inside values # of the config file, but be careful!! val = value.replace('\n', '') if self.pat.match(val): return eval(val,{__builtins__:None}) else: return value # This class as suggested by /F with an additional hook # to be able to filter filenames. class GlobDirectoryWalker: "A forward iterator that traverses files in a directory tree." def __init__(self, directory, pattern='*'): self.index = 0 self.pattern = pattern directory.replace('/',os.sep) if os.path.isdir(directory): self.stack = [directory] self.files = [] else: if not isCompactDistro() or not __rl_loader__ or not rl_isdir(directory): raise ValueError('"%s" is not a directory' % directory) self.directory = directory[len(__rl_loader__.archive)+len(os.sep):] pfx = self.directory+os.sep n = len(pfx) self.files = list(map(lambda x, n=n: x[n:],list(filter(lambda x,pfx=pfx: x.startswith(pfx),list(__rl_loader__._files.keys()))))) self.files.sort() self.stack = [] def __getitem__(self, index): while 1: try: file = self.files[self.index] self.index = self.index + 1 except IndexError: # pop next directory from stack self.directory = self.stack.pop() self.files = os.listdir(self.directory) # now call the hook self.files = self.filterFiles(self.directory, self.files) self.index = 0 else: # got a filename fullname = os.path.join(self.directory, file) if os.path.isdir(fullname) and not os.path.islink(fullname): self.stack.append(fullname) if fnmatch.fnmatch(file, self.pattern): return fullname def filterFiles(self, folder, files): "Filter hook, overwrite in subclasses as needed." return files class RestrictedGlobDirectoryWalker(GlobDirectoryWalker): "An restricted directory tree iterator." def __init__(self, directory, pattern='*', ignore=None): GlobDirectoryWalker.__init__(self, directory, pattern) if ignore == None: ignore = [] ip = [].append if isinstance(ignore,(tuple,list)): for p in ignore: ip(p) elif isinstance(ignore,str): ip(ignore) self.ignorePatterns = ([_.replace('/',os.sep) for _ in ip.__self__] if os.sep != '/' else ip.__self__) def filterFiles(self, folder, files): "Filters all items from files matching patterns to ignore." fnm = fnmatch.fnmatch indicesToDelete = [] for i,f in enumerate(files): for p in self.ignorePatterns: if fnm(f, p) or fnm(os.path.join(folder,f),p): indicesToDelete.append(i) indicesToDelete.reverse() for i in indicesToDelete: del files[i] return files class CVSGlobDirectoryWalker(GlobDirectoryWalker): "An directory tree iterator that checks for CVS data." def filterFiles(self, folder, files): """Filters files not listed in CVS subfolder. This will look in the CVS subfolder of 'folder' for a file named 'Entries' and filter all elements from the 'files' list that are not listed in 'Entries'. """ join = os.path.join cvsFiles = getCVSEntries(folder) if cvsFiles: indicesToDelete = [] for i in range(len(files)): f = files[i] if join(folder, f) not in cvsFiles: indicesToDelete.append(i) indicesToDelete.reverse() for i in indicesToDelete: del files[i] return files # An experimental untested base class with additional 'security'. class SecureTestCase(unittest.TestCase): """Secure testing base class with additional pre- and postconditions. We try to ensure that each test leaves the environment it has found unchanged after the test is performed, successful or not. Currently we restore sys.path and the working directory, but more of this could be added easily, like removing temporary files or similar things. Use this as a base class replacing unittest.TestCase and call these methods in subclassed versions before doing your own business! """ def setUp(self): "Remember sys.path and current working directory." self._initialPath = sys.path[:] self._initialWorkDir = os.getcwd() def tearDown(self): "Restore previous sys.path and working directory." sys.path = self._initialPath os.chdir(self._initialWorkDir) class NearTestCase(unittest.TestCase): def assertNear(a,b,accuracy=1e-5): if isinstance(a,(float,int)): if abs(a-b)>accuracy: raise AssertionError("%s not near %s" % (a, b)) else: for ae,be in zip(a,b): if abs(ae-be)>accuracy: raise AssertionError("%s not near %s" % (a, b)) assertNear = staticmethod(assertNear) class ScriptThatMakesFileTest(unittest.TestCase): """Runs a Python script at OS level, expecting it to produce a file. It CDs to the working directory to run the script.""" def __init__(self, scriptDir, scriptName, outFileName, verbose=0): self.scriptDir = scriptDir self.scriptName = scriptName self.outFileName = outFileName self.verbose = verbose # normally, each instance is told which method to run) unittest.TestCase.__init__(self) def setUp(self): self.cwd = os.getcwd() global testsFolder scriptDir=self.scriptDir if not os.path.isabs(scriptDir): scriptDir=os.path.join(testsFolder,scriptDir) os.chdir(scriptDir) assert os.path.isfile(self.scriptName), "Script %s not found!" % self.scriptName if os.path.isfile(self.outFileName): os.remove(self.outFileName) def tearDown(self): os.chdir(self.cwd) def runTest(self): fmt = sys.platform=='win32' and '"%s" %s' or '%s %s' import subprocess out = subprocess.check_output((sys.executable,self.scriptName)) #p = os.popen(fmt % (sys.executable,self.scriptName),'r') #out = p.read() if self.verbose: print(out) #status = p.close() assert os.path.isfile(self.outFileName), "File %s not created!" % self.outFileName def equalStrings(a,b,enc='utf8'): return a==b if type(a)==type(b) else asUnicode(a,enc)==asUnicode(b,enc) def eqCheck(r,x): if r!=x: print('Strings unequal\nexp: %s\ngot: %s' % (ascii(x),ascii(r))) def rlextraNeeded(): try: import rlextra return False except: return True def rlSkipIf(cond,reason,__module__=None): def inner(func): @functools.wraps(func) def wrapper(*args,**kwds): if cond and os.environ.get('RL_indicateSkips','0')=='1': print(f''' skipping {func.__module__ or __module__}.{func.__name__} {reason}''') return unittest.skipIf(cond,reason)(func)(*args,**kwds) return wrapper return inner def rlSkipUnless(cond,reason,__module__=None): return rlSkipIf(not cond,reason,__module__=__module__) def rlSkip(reason,__module__=None): return rlSkipIf(True,reason,__module__=__module__) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1691062243.0 reportlab-4.1.0/src/reportlab/lib/textsplit.py0000664000175000017500000002277314462707743021074 0ustar00rptlabrptlab#Copyright ReportLab Europe Ltd. 2000-2017 #see license.txt for license details #history https://hg.reportlab.com/hg-public/reportlab/log/tip/src/reportlab/lib/textsplit.py """Helpers for text wrapping, hyphenation, Asian text splitting and kinsoku shori. How to split a 'big word' depends on the language and the writing system. This module works on a Unicode string. It ought to grow by allowing ore algoriths to be plugged in based on possible knowledge of the language and desirable 'niceness' of the algorithm. """ __version__='3.3.0' from unicodedata import category from reportlab.pdfbase.pdfmetrics import stringWidth from reportlab.rl_config import _FUZZ from reportlab.lib.utils import isUnicode CANNOT_START_LINE = [ #strongly prohibited e.g. end brackets, stop, exclamation... u'!\',.:;?!")]\u3001\u3002\u300d\u300f\u3011\u3015\uff3d\u3011\uff09', #middle priority e.g. continuation small vowels - wrapped on two lines but one string... u'\u3005\u2015\u3041\u3043\u3045\u3047\u3049\u3063\u3083\u3085\u3087\u308e\u30a1\u30a3' u'\u30a5\u30a7\u30a9\u30c3\u30e3\u30e5\u30e7\u30ee\u30fc\u30f5\u30f6', #weakly prohibited - continuations, celsius symbol etc. u'\u309b\u309c\u30fb\u30fd\u30fe\u309d\u309e\u2015\u2010\xb0\u2032\u2033\u2103\uffe0\uff05\u2030' ] ALL_CANNOT_START = u''.join(CANNOT_START_LINE) CANNOT_END_LINE = [ #strongly prohibited u'\u2018\u201c\uff08[{\uff08\u3014\uff3b\uff5b\u3008\u300a\u300c\u300e\u3010', #weaker - currency symbols, hash, postcode - prefixes u'$\u00a3@#\uffe5\uff04\uffe1\uff20\u3012\u00a7' ] ALL_CANNOT_END = u''.join(CANNOT_END_LINE) def is_multi_byte(ch): "Is this an Asian character?" return (ord(ch) >= 0x3000) def getCharWidths(word, fontName, fontSize): """Returns a list of glyph widths. >>> getCharWidths('Hello', 'Courier', 10) [6.0, 6.0, 6.0, 6.0, 6.0] >>> from reportlab.pdfbase.cidfonts import UnicodeCIDFont >>> from reportlab.pdfbase.pdfmetrics import registerFont >>> registerFont(UnicodeCIDFont('HeiseiMin-W3')) >>> getCharWidths(u'\u6771\u4EAC', 'HeiseiMin-W3', 10) #most kanji are 100 ems [10.0, 10.0] """ #character-level function call; the performance is going to SUCK return [stringWidth(uChar, fontName, fontSize) for uChar in word] def wordSplit(word, maxWidths, fontName, fontSize, encoding='utf8'): """Attempts to break a word which lacks spaces into two parts, the first of which fits in the remaining space. It is allowed to add hyphens or whatever it wishes. This is intended as a wrapper for some language- and user-choice-specific splitting algorithms. It should only be called after line breaking on spaces, which covers western languages and is highly optimised already. It works on the 'last unsplit word'. Presumably with further study one could write a Unicode splitting algorithm for text fragments whick was much faster. Courier characters should be 6 points wide. >>> wordSplit('HelloWorld', 30, 'Courier', 10) [[0.0, 'Hello'], [0.0, 'World']] >>> wordSplit('HelloWorld', 31, 'Courier', 10) [[1.0, 'Hello'], [1.0, 'World']] """ if not isUnicode(word): uword = word.decode(encoding) else: uword = word charWidths = getCharWidths(uword, fontName, fontSize) lines = dumbSplit(uword, charWidths, maxWidths) if not isUnicode(word): lines2 = [] #convert back for (extraSpace, text) in lines: lines2.append([extraSpace, text.encode(encoding)]) lines = lines2 return lines def dumbSplit(word, widths, maxWidths): """This function attempts to fit as many characters as possible into the available space, cutting "like a knife" between characters. This would do for Chinese. It returns a list of (text, extraSpace) items where text is a Unicode string, and extraSpace is the points of unused space available on the line. This is a structure which is fairly easy to display, and supports 'backtracking' approaches after the fact. Test cases assume each character is ten points wide... >>> dumbSplit(u'Hello', [10]*5, 60) [[10, u'Hello']] >>> dumbSplit(u'Hello', [10]*5, 50) [[0, u'Hello']] >>> dumbSplit(u'Hello', [10]*5, 40) [[0, u'Hell'], [30, u'o']] """ _more = """ #>>> dumbSplit(u'Hello', [10]*5, 4) # less than one character #(u'', u'Hello') # this says 'Nihongo wa muzukashii desu ne!' (Japanese is difficult isn't it?) in 12 characters >>> jtext = u'\u65e5\u672c\u8a9e\u306f\u96e3\u3057\u3044\u3067\u3059\u306d\uff01' >>> dumbSplit(jtext, [10]*11, 30) # (u'\u65e5\u672c\u8a9e', u'\u306f\u96e3\u3057\u3044\u3067\u3059\u306d\uff01') """ if not isinstance(maxWidths,(list,tuple)): maxWidths = [maxWidths] assert isUnicode(word) lines = [] i = widthUsed = lineStartPos = 0 maxWidth = maxWidths[0] nW = len(word) while i maxWidth + _FUZZ and widthUsed>0: extraSpace = maxWidth - widthUsed if ord(c)<0x3000: # we appear to be inside a non-Asian script section. # (this is a very crude test but quick to compute). # This is likely to be quite rare so the speed of the # code below is hopefully not a big issue. The main # situation requiring this is that a document title # with an english product name in it got cut. # we count back and look for # - a space-like character # - reversion to Kanji (which would be a good split point) # - in the worst case, roughly half way back along the line limitCheck = (lineStartPos+i)>>1 #(arbitrary taste issue) for j in range(i-1,limitCheck,-1): cj = word[j] if category(cj)=='Zs' or ord(cj)>=0x3000: k = j+1 if k if c not in ALL_CANNOT_START and i>lineStartPos+1: #otherwise we need to push the character back #the i>lineStart+1 condition ensures progress i -= 1 extraSpace += w #lines.append([maxWidth-sum(widths[lineStartPos:i]), word[lineStartPos:i].strip()]) lines.append([extraSpace, word[lineStartPos:i].strip()]) try: maxWidth = maxWidths[len(lines)] except IndexError: maxWidth = maxWidths[-1] # use the last one lineStartPos = i widthUsed = 0 #any characters left? if widthUsed > 0: lines.append([maxWidth - widthUsed, word[lineStartPos:]]) return lines def kinsokuShoriSplit(word, widths, availWidth): #NOT USED OR FINISHED YET! """Split according to Japanese rules according to CJKV (Lunde). Essentially look for "nice splits" so that we don't end a line with an open bracket, or start one with a full stop, or stuff like that. There is no attempt to try to split compound words into constituent kanji. It currently uses wrap-down: packs as much on a line as possible, then backtracks if needed This returns a number of words each of which should just about fit on a line. If you give it a whole paragraph at once, it will do all the splits. It's possible we might slightly step over the width limit if we do hanging punctuation marks in future (e.g. dangle a Japanese full stop in the right margin rather than using a whole character box. """ lines = [] assert len(word) == len(widths) curWidth = 0.0 curLine = [] i = 0 #character index - we backtrack at times so cannot use for loop while 1: ch = word[i] w = widths[i] if curWidth + w < availWidth: curLine.append(ch) curWidth += w else: #end of line. check legality if ch in CANNOT_END_LINE[0]: pass #to be completed # This recipe refers: # # http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/148061 import re rx=re.compile("([\u2e80-\uffff])", re.UNICODE) def cjkwrap(text, width, encoding="utf8"): return reduce(lambda line, word, width=width: '%s%s%s' % (line, [' ','\n', ''][(len(line)-line.rfind('\n')-1 + len(word.split('\n',1)[0] ) >= width) or line[-1:] == '\0' and 2], word), rx.sub(r'\1\0 ', str(text,encoding)).split(' ') ).replace('\0', '').encode(encoding) if __name__=='__main__': import doctest from reportlab.lib import textsplit doctest.testmod(textsplit) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1691062243.0 reportlab-4.1.0/src/reportlab/lib/units.py0000664000175000017500000000162514462707743020167 0ustar00rptlabrptlab#!/bin/env python #Copyright ReportLab Europe Ltd. 2000-2017 #see license.txt for license details #history https://hg.reportlab.com/hg-public/reportlab/log/tip/src/reportlab/lib/units.py __version__='3.3.0' __doc__='''Defines inch, cm, mm etc as multiples of a point You can now in user-friendly units by doing:: from reportlab.lib.units import inch r = Rect(0, 0, 3 * inch, 6 * inch) ''' inch = 72.0 cm = inch / 2.54 mm = cm * 0.1 pica = 12.0 def toLength(s): '''convert a string to a length''' try: if s[-2:]=='cm': return float(s[:-2])*cm if s[-2:]=='in': return float(s[:-2])*inch if s[-2:]=='pt': return float(s[:-2]) if s[-1:]=='i': return float(s[:-1])*inch if s[-2:]=='mm': return float(s[:-2])*mm if s[-4:]=='pica': return float(s[:-4])*pica return float(s) except: raise ValueError("Can't convert '%s' to length" % s) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1691062243.0 reportlab-4.1.0/src/reportlab/lib/utils.py0000664000175000017500000012435614462707743020174 0ustar00rptlabrptlab#Copyright ReportLab Europe Ltd. 2000-2019 #see license.txt for license details # $URI:$ __version__='3.5.34' __doc__='''Gazillions of miscellaneous internal utility functions''' import os, pickle, sys, time, types, datetime, importlib from ast import literal_eval from base64 import decodebytes as base64_decodebytes, encodebytes as base64_encodebytes from io import BytesIO from hashlib import md5 from reportlab.lib.rltempfile import get_rl_tempfile, get_rl_tempdir from . rl_safe_eval import rl_safe_exec, rl_safe_eval, safer_globals, rl_extended_literal_eval from PIL import Image class __UNSET__: @staticmethod def __bool__(): return False @staticmethod def __str__(): return '__UNSET__' __repr__ = __str__ __UNSET__ = __UNSET__() try: import platform isPyPy = platform.python_implementation()=='PyPy' except: isPyPy = False def isFunction(v): return type(v) == type(isFunction) class c: def m(self): pass def isMethod(v,mt=type(c.m)): return type(v) == mt del c def isModule(v): return type(v) == type(sys) def isSeq(v,_st=(tuple,list)): return isinstance(v,_st) def isNative(v): return isinstance(v, str) #isStr is supposed to be for arbitrary stringType #isBytes for bytes strings only #isUnicode for proper unicode _rl_NoneType=type(None) strTypes = (str,bytes) def _digester(s): return md5(s if isBytes(s) else s.encode('utf8')).hexdigest() def asBytes(v,enc='utf8'): if isinstance(v,bytes): return v try: return v.encode(enc) except: annotateException('asBytes(%s,enc=%s) error: ' % (ascii(v),ascii(enc))) def asUnicode(v,enc='utf8'): if isinstance(v,str): return v try: return v.decode(enc) except: annotateException('asUnicode(%s,enc=%s) error: ' % (ascii(v),ascii(enc))) def asUnicodeEx(v,enc='utf8'): if isinstance(v,str): return v try: return v.decode(enc) if isinstance(v,bytes) else str(v) except: annotateException('asUnicodeEx(%s,enc=%s) error: ' % (ascii(v),ascii(enc))) def asNative(v,enc='utf8'): return asUnicode(v,enc=enc) def int2Byte(i): return bytes([i]) def isStr(v): return isinstance(v, (str,bytes)) def isBytes(v): return isinstance(v, bytes) def isUnicode(v): return isinstance(v, str) def isClass(v): return isinstance(v, type) def isNonPrimitiveInstance(x): return not isinstance(x,(float,int,type,tuple,list,dict,str,bytes,complex,bool,slice,_rl_NoneType, types.FunctionType,types.LambdaType,types.CodeType, types.MappingProxyType,types.SimpleNamespace, types.GeneratorType,types.MethodType,types.BuiltinFunctionType, types.BuiltinMethodType,types.ModuleType,types.TracebackType, types.FrameType,types.GetSetDescriptorType,types.MemberDescriptorType)) def instantiated(v): return not isinstance(v,type) def bytestr(x,enc='utf8'): if isinstance(x,str): return x.encode(enc) elif isinstance(x,bytes): return x else: return str(x).encode(enc) def encode_label(args): return base64_encodebytes(pickle.dumps(args)).strip().decode('latin1') def decode_label(label): return pickle.loads(base64_decodebytes(label.encode('latin1'))) def rawUnicode(s): '''converts first 256 unicodes 1-1''' return s.decode('latin1') if not isinstance(s,str) else s def rawBytes(s): '''converts first 256 unicodes 1-1''' return s.encode('latin1') if isinstance(s,str) else s import builtins rl_exec = getattr(builtins,'exec') del builtins def char2int(s): return s if isinstance(s,int) else ord(s if isinstance(s,str) else s.decode('latin1')) def rl_reraise(t, v, b=None): if v.__traceback__ is not b: raise v.with_traceback(b) raise v def rl_add_builtins(**kwd): import builtins for k,v in kwd.items(): setattr(builtins,k,v) def zipImported(ldr=None): try: if not ldr: ldr = sys._getframe(1).f_globals['__loader__'] from zipimport import zipimporter return ldr if isinstance(ldr,zipimporter) and len(ldr._files) else None except: return None def _findFiles(dirList,ext='.ttf'): from os.path import isfile, isdir, join as path_join from os import listdir ext = ext.lower() R = [] A = R.append for D in dirList: if not isdir(D): continue for fn in listdir(D): fn = path_join(D,fn) if isfile(fn) and (not ext or fn.lower().endswith(ext)): A(fn) return R class CIDict(dict): def __init__(self,*args,**kwds): for a in args: self.update(a) self.update(kwds) def update(self,D): for k,v in D.items(): self[k] = v def __setitem__(self,k,v): try: k = k.lower() except: pass dict.__setitem__(self,k,v) def __getitem__(self,k): try: k = k.lower() except: pass return dict.__getitem__(self,k) def __delitem__(self,k): try: k = k.lower() except: pass return dict.__delitem__(self,k) def get(self,k,dv=None): try: return self[k] except KeyError: return dv def __contains__(self,k): try: self[k] return True except: return False def pop(self,k,*a): try: k = k.lower() except: pass return dict.pop(*((self,k)+a)) def setdefault(self,k,*a): try: k = k.lower() except: pass return dict.setdefault(*((self,k)+a)) if os.name == 'mac': #with the Mac, we need to tag the file in a special #way so the system knows it is a PDF file. #This supplied by Joe Strout import macfs, macostools _KNOWN_MAC_EXT = { 'BMP' : ('ogle','BMP '), 'EPS' : ('ogle','EPSF'), 'EPSF': ('ogle','EPSF'), 'GIF' : ('ogle','GIFf'), 'JPG' : ('ogle','JPEG'), 'JPEG': ('ogle','JPEG'), 'PCT' : ('ttxt','PICT'), 'PICT': ('ttxt','PICT'), 'PNG' : ('ogle','PNGf'), 'PPM' : ('ogle','.PPM'), 'TIF' : ('ogle','TIFF'), 'TIFF': ('ogle','TIFF'), 'PDF' : ('CARO','PDF '), 'HTML': ('MSIE','TEXT'), } def markfilename(filename,creatorcode=None,filetype=None,ext='PDF'): try: if creatorcode is None or filetype is None and ext is not None: try: creatorcode, filetype = _KNOWN_MAC_EXT[ext.upper()] except: return macfs.FSSpec(filename).SetCreatorType(creatorcode,filetype) macostools.touched(filename) except: pass else: def markfilename(filename,creatorcode=None,filetype=None): pass import reportlab __RL_DIR=os.path.dirname(reportlab.__file__) #possibly relative _RL_DIR=os.path.isabs(__RL_DIR) and __RL_DIR or os.path.abspath(__RL_DIR) del reportlab #Attempt to detect if this copy of reportlab is running in a #file system (as opposed to mostly running in a zip or McMillan #archive or Jar file). This is used by test cases, so that #we can write test cases that don't get activated in frozen form. try: __file__ except: __file__ = sys.argv[0] import glob, fnmatch try: __rl_loader__ = __loader__ _isFSD = not __rl_loader__ if not zipImported(ldr=__rl_loader__): raise NotImplementedError("can't handle compact distro type %r" % __rl_loader__) _archive = os.path.normcase(os.path.normpath(__rl_loader__.archive)) _archivepfx = _archive + os.sep _archivedir = os.path.dirname(_archive) _archivedirpfx = _archivedir + os.sep _archivepfxlen = len(_archivepfx) _archivedirpfxlen = len(_archivedirpfx) def __startswith_rl(fn, _archivepfx=_archivepfx, _archivedirpfx=_archivedirpfx, _archive=_archive, _archivedir=_archivedir, os_path_normpath=os.path.normpath, os_path_normcase=os.path.normcase, os_getcwd=os.getcwd, os_sep=os.sep, os_sep_len = len(os.sep)): '''if the name starts with a known prefix strip it off''' fn = os_path_normpath(fn.replace('/',os_sep)) nfn = os_path_normcase(fn) if nfn in (_archivedir,_archive): return 1,'' if nfn.startswith(_archivepfx): return 1,fn[_archivepfxlen:] if nfn.startswith(_archivedirpfx): return 1,fn[_archivedirpfxlen:] cwd = os_path_normcase(os_getcwd()) n = len(cwd) if nfn.startswith(cwd): if fn[n:].startswith(os_sep): return 1, fn[n+os_sep_len:] if n==len(fn): return 1,'' return not os.path.isabs(fn),fn def _startswith_rl(fn): return __startswith_rl(fn)[1] def rl_glob(pattern,glob=glob.glob,fnmatch=fnmatch.fnmatch, _RL_DIR=_RL_DIR,pjoin=os.path.join): c, pfn = __startswith_rl(pattern) r = glob(pfn) if c or r==[]: r += list(map(lambda x,D=_archivepfx,pjoin=pjoin: pjoin(_archivepfx,x),list(filter(lambda x,pfn=pfn,fnmatch=fnmatch: fnmatch(x,pfn),list(__rl_loader__._files.keys()))))) return r except: _isFSD = os.path.isfile(__file__) #slight risk of wrong path __rl_loader__ = None def _startswith_rl(fn): return fn def rl_glob(pattern,glob=glob.glob): return glob(pattern) del glob, fnmatch _isFSSD = _isFSD and os.path.isfile(os.path.splitext(__file__)[0] +'.py') def isFileSystemDistro(): '''return truth if a file system distribution''' return _isFSD def isCompactDistro(): '''return truth if not a file system distribution''' return not _isFSD def isSourceDistro(): '''return truth if a source file system distribution''' return _isFSSD def normalize_path(p): return os.path.normcase(os.path.abspath(os.path.normpath(p))) _importlib_invalidate_caches = getattr(importlib,'invalidate_caches',lambda :None) def recursiveImport(modulename, baseDir=None, noCWD=0, debug=0): """Dynamically imports possible packagized module, or raises ImportError""" path = [normalize_path(p) for p in sys.path] if baseDir: for p in baseDir if isinstance(baseDir,(list,tuple)) else (baseDir,): if p: p = normalize_path(p) if p not in path: path.insert(0,p) if noCWD: for p in ('','.',normalize_path('.')): while p in path: if debug: print('removed "%s" from path' % p) path.remove(p) else: p = os.getcwd() if p not in path: path.insert(0,p) #make import errors a bit more informative opath = sys.path try: sys.path = path _importlib_invalidate_caches() if debug: print() print(20*'+') print('+++++ modulename=%s' % ascii(modulename)) print('+++++ cwd=%s' % ascii(os.getcwd())) print('+++++ sys.path=%s' % ascii(sys.path)) print('+++++ os.paths.isfile(%s)=%s' % (ascii('./%s.py'%modulename), ascii(os.path.isfile('./%s.py'%modulename)))) print('+++++ opath=%s' % ascii(opath)) print(20*'-') return importlib.import_module(modulename) except ImportError: annotateException("Could not import %r\nusing sys.path %r in cwd=%r" % ( modulename,sys.path,os.getcwd()) ) except: annotateException("Exception %s while importing %r\nusing sys.path %r in cwd=%r" % ( str(sys.exc_info()[1]), modulename,sys.path,os.getcwd())) finally: sys.path = opath _importlib_invalidate_caches() if debug: print('===== restore sys.path=%s' % repr(opath)) haveImages = Image is not None class ArgvDictValue: '''A type to allow clients of getArgvDict to specify a conversion function''' def __init__(self,value,func): self.value = value self.func = func def getArgvDict(**kw): ''' Builds a dictionary from its keyword arguments with overrides from sys.argv. Attempts to be smart about conversions, but the value can be an instance of ArgDictValue to allow specifying a conversion function. ''' def handleValue(v,av,func): if func: v = func(av) else: if isStr(v): v = av elif isinstance(v,float): v = float(av) elif isinstance(v,int): v = int(av) elif isinstance(v,list): v = list(literal_eval(av),{}) elif isinstance(v,tuple): v = tuple(literal_eval(av),{}) else: raise TypeError("Can't convert string %r to %s" % (av,type(v))) return v A = sys.argv[1:] R = {} for k, v in kw.items(): if isinstance(v,ArgvDictValue): v, func = v.value, v.func else: func = None handled = 0 ke = k+'=' for a in A: if a.startswith(ke): av = a[len(ke):] A.remove(a) R[k] = handleValue(v,av,func) handled = 1 break if not handled: R[k] = handleValue(v,v,func) return R def getHyphenater(hDict=None): try: from reportlab.lib.pyHnj import Hyphen if hDict is None: hDict=os.path.join(os.path.dirname(__file__),'hyphen.mashed') return Hyphen(hDict) except ImportError as errMsg: if str(errMsg)!='No module named pyHnj': raise return None def _className(self): '''Return a shortened class name''' try: name = self.__class__.__name__ i=name.rfind('.') if i>=0: return name[i+1:] return name except AttributeError: return str(self) def open_for_read_by_name(name,mode='b'): if 'r' not in mode: mode = 'r'+mode try: return open(name,mode) except IOError: if _isFSD or __rl_loader__ is None: raise #we have a __rl_loader__, perhaps the filename starts with #the dirname(reportlab.__file__) or is relative name = _startswith_rl(name) s = __rl_loader__.get_data(name) if 'b' not in mode and os.linesep!='\n': s = s.replace(os.linesep,'\n') return BytesIO(s) from urllib.parse import unquote, urlparse from urllib.request import urlopen def rlUrlRead(name): return urlopen(name).read() def open_for_read(name,mode='b'): #auto initialized function` #copied here from urllib.URLopener.open_data because # 1) they want to remove it # 2) the existing one is borken def datareader(url, unquote=unquote): """Use "data" URL.""" # ignore POSTed data # # syntax of data URLs: # dataurl := "data:" [ mediatype ] [ ";base64" ] "," data # mediatype := [ type "/" subtype ] *( ";" parameter ) # data := *urlchar # parameter := attribute "=" value try: typ, data = url.split(',', 1) except ValueError: raise IOError('data error', 'bad data URL') if not typ: typ = 'text/plain;charset=US-ASCII' semi = typ.rfind(';') if semi >= 0 and '=' not in typ[semi:]: encoding = typ[semi+1:] typ = typ[:semi] else: encoding = '' if encoding == 'base64': # XXX is this encoding/decoding ok? data = base64_decodebytes(data.encode('ascii')) else: data = unquote(data).encode('latin-1') return data from reportlab.rl_config import trustedHosts, trustedSchemes if trustedHosts: import re, fnmatch def xre(s): s = fnmatch.translate(s) return s[4:-3] if s.startswith('(?s:') else s[:-7] trustedHosts = re.compile(''.join(('^(?:', '|'.join(map(xre,trustedHosts)), ')\\Z'))) def open_for_read(name,mode='b'): '''attempt to open a file or URL for reading''' if hasattr(name,'read'): return name try: return open_for_read_by_name(name,mode) except: try: if trustedHosts is not None: purl = urlparse(name) if purl[0] and not ((purl[0] in ('data','file') or trustedHosts.match(purl[1])) and (purl[0] in trustedSchemes)): raise ValueError('Attempted untrusted host access') return BytesIO((datareader if name[:5].lower()=='data:' else rlUrlRead)(name)) except: raise IOError('Cannot open resource "%s"' % name) globals()['open_for_read'] = open_for_read return open_for_read(name,mode) def open_and_read(name,mode='b'): f = open_for_read(name,mode) if name is not f and hasattr(f,'__exit__'): with f: return f.read() else: return f.read() def open_and_readlines(name,mode='t'): return open_and_read(name,mode).split('\n') def rl_isfile(fn,os_path_isfile=os.path.isfile): if hasattr(fn,'read'): return True if os_path_isfile(fn): return True if _isFSD or __rl_loader__ is None: return False fn = _startswith_rl(fn) return fn in list(__rl_loader__._files.keys()) def rl_isdir(pn,os_path_isdir=os.path.isdir,os_path_normpath=os.path.normpath): if os_path_isdir(pn): return True if _isFSD or __rl_loader__ is None: return False pn = _startswith_rl(os_path_normpath(pn)) if not pn.endswith(os.sep): pn += os.sep return len(list(filter(lambda x,pn=pn: x.startswith(pn),list(__rl_loader__._files.keys()))))>0 def rl_listdir(pn,os_path_isdir=os.path.isdir,os_path_normpath=os.path.normpath,os_listdir=os.listdir): if os_path_isdir(pn) or _isFSD or __rl_loader__ is None: return os_listdir(pn) pn = _startswith_rl(os_path_normpath(pn)) if not pn.endswith(os.sep): pn += os.sep return [x[len(pn):] for x in __rl_loader__._files.keys() if x.startswith(pn)] def rl_getmtime(pn,os_path_isfile=os.path.isfile,os_path_normpath=os.path.normpath,os_path_getmtime=os.path.getmtime,time_mktime=time.mktime): if os_path_isfile(pn) or _isFSD or __rl_loader__ is None: return os_path_getmtime(pn) p = _startswith_rl(os_path_normpath(pn)) try: e = __rl_loader__._files[p] except KeyError: return os_path_getmtime(pn) s = e[5] d = e[6] return time_mktime((((d>>9)&0x7f)+1980,(d>>5)&0xf,d&0x1f,(s>>11)&0x1f,(s>>5)&0x3f,(s&0x1f)<<1,0,0,0)) from importlib import util as importlib_util def __rl_get_module__(name,dir): for ext in ('.py','.pyw','.pyo','.pyc','.pyd'): path = os.path.join(dir,name+ext) if os.path.isfile(path): spec = importlib_util.spec_from_file_location(name,path) return spec.loader.load_module() raise ImportError('no suitable file found') def rl_get_module(name,dir): if name in sys.modules: om = sys.modules[name] del sys.modules[name] else: om = None try: try: return __rl_get_module__(name,dir) except: if isCompactDistro(): #attempt a load from inside the zip archive import zipimport dir = _startswith_rl(dir) dir = (dir=='.' or not dir) and _archive or os.path.join(_archive,dir.replace('/',os.sep)) zi = zipimport.zipimporter(dir) return zi.load_module(name) raise ImportError('%s[%s]' % (name,dir)) finally: if om: sys.modules[name] = om def _isPILImage(im): try: return isinstance(im,Image.Image) except AttributeError: return 0 class ImageReader: "Wraps up PIL to get data from bitmaps" _cache={} _max_image_size = None def __init__(self, fileName,ident=None): if isinstance(fileName,ImageReader): self.__dict__ = fileName.__dict__ #borgize return self._ident = ident #start wih lots of null private fields, to be populated by #the relevant engine. self.fileName = fileName self._image = None self._width = None self._height = None self._transparent = None self._data = None if _isPILImage(fileName): self._image = fileName self.fp = getattr(fileName,'fp',None) try: self.fileName = self._image.fileName except AttributeError: self.fileName = 'PILIMAGE_%d' % id(self) else: try: from reportlab.rl_config import imageReaderFlags if imageReaderFlags != 0: raise ValueError('imageReaderFlags values other than 0 are no longer supported; all images are interned now') fp = open_for_read(fileName,'b') if not isinstance(fp, BytesIO): tfp, fp = fp, BytesIO(fp.read()) tfp.close() del tfp self.fp = fp self._image = self._read_image(self.fp) self._image.fileName = fileName if isinstance(fileName,str) else repr(fileName) self.check_pil_image_size(self._image) if getattr(self._image,'format',None)=='JPEG': self.jpeg_fh = self._jpeg_fh except: annotateException('\nfileName=%r identity=%s'%(fileName,self.identity())) def identity(self): '''try to return information that will identify the instance''' fn = self.fileName if not isStr(fn): fn = getattr(getattr(self,'fp',None),'name',None) ident = self._ident return '[%s@%s%s%s]' % (self.__class__.__name__,hex(id(self)),ident and (' ident=%r' % ident) or '',fn and (' filename=%r' % fn) or '') def _read_image(self,fp): return Image.open(fp) @classmethod def check_pil_image_size(cls, im): max_image_size = cls._max_image_size if max_image_size is None: return w, h = im.size m = im.mode size = max(1,((1 if m=='1' else 8*len(m))*w*h)>>3) if size>max_image_size: raise MemoryError('PIL %s %s x %s image would use %s > %s bytes' %(m,w,h,size,max_image_size)) @classmethod def set_max_image_size(cls,max_image_size=None): cls._max_image_size = max_image_size if max_image_size is not None: from reportlab.rl_config import register_reset register_reset(cls.set_max_image_size) def _jpeg_fh(self): fp = self.fp fp.seek(0) return fp def jpeg_fh(self): return None def getSize(self): if (self._width is None or self._height is None): self._width, self._height = self._image.size return (self._width, self._height) def getRGBData(self): "Return byte array of RGB data as string" try: if self._data is None: self._dataA = None im = self._image mode = self.mode = im.mode if mode in ('LA','RGBA'): if getattr(Image,'VERSION','').startswith('1.1.7'): im.load() self._dataA = ImageReader(im.split()[3 if mode=='RGBA' else 1]) nm = mode[:-1] im = im.convert(nm) self.mode = nm elif mode not in ('L','RGB','CMYK'): if im.format=='PNG' and im.mode=='P' and 'transparency' in im.info: im = im.convert('RGBA') self._dataA = ImageReader(im.split()[3]) im = im.convert('RGB') else: im = im.convert('RGB') self.mode = 'RGB' self._data = (im.tobytes if hasattr(im, 'tobytes') else im.tostring)() #make pillow and PIL both happy, for now return self._data except: annotateException('\nidentity=%s'%self.identity()) def getImageData(self): width, height = self.getSize() return width, height, self.getRGBData() def getTransparent(self): if "transparency" in self._image.info: transparency = self._image.info["transparency"] * 3 palette = self._image.palette try: palette = palette.palette except: try: palette = palette.data except: return None return palette[transparency:transparency+3] else: return None class LazyImageReader(ImageReader): pass #now same as base class since we intern everything def getImageData(imageFileName): "Get width, height and RGB pixels from image file. Wraps PIL" try: return imageFileName.getImageData() except AttributeError: return ImageReader(imageFileName).getImageData() class DebugMemo: '''Intended as a simple report back encapsulator Typical usages: 1. To record error data:: dbg = DebugMemo(fn='dbgmemo.dbg',myVar=value) dbg.add(anotherPayload='aaaa',andagain='bbb') dbg.dump() 2. To show the recorded info:: dbg = DebugMemo(fn='dbgmemo.dbg',mode='r') dbg.load() dbg.show() 3. To re-use recorded information:: dbg = DebugMemo(fn='dbgmemo.dbg',mode='r') dbg.load() myTestFunc(dbg.payload('myVar'),dbg.payload('andagain')) In addition to the payload variables the dump records many useful bits of information which are also printed in the show() method. ''' def __init__(self,fn='rl_dbgmemo.dbg',mode='w',getScript=1,modules=(),capture_traceback=1, stdout=None, **kw): import socket self.fn = fn if not stdout: self.stdout = sys.stdout else: if hasattr(stdout,'write'): self.stdout = stdout else: self.stdout = open(stdout,'w') if mode!='w': return self.store = store = {} if capture_traceback and sys.exc_info() != (None,None,None): import traceback s = BytesIO() traceback.print_exc(None,s) store['__traceback'] = s.getvalue() cwd=os.getcwd() lcwd = os.listdir(cwd) pcwd = os.path.dirname(cwd) lpcwd = pcwd and os.listdir(pcwd) or '???' exed = os.path.abspath(os.path.dirname(sys.argv[0])) project_version='???' md=None try: import marshal md=marshal.loads(__rl_loader__.get_data('meta_data.mar')) project_version=md['project_version'] except: pass env = os.environ K=list(env.keys()) K.sort() store.update({ 'gmt': time.asctime(time.gmtime(time.time())), 'platform': sys.platform, 'version': sys.version, 'hexversion': hex(sys.hexversion), 'executable': sys.executable, 'exec_prefix': sys.exec_prefix, 'prefix': sys.prefix, 'path': sys.path, 'argv': sys.argv, 'cwd': cwd, 'hostname': socket.gethostname(), 'lcwd': lcwd, 'lpcwd': lpcwd, 'byteorder': sys.byteorder, 'maxint': getattr(sys,'maxunicode','????'), 'api_version': getattr(sys,'api_version','????'), 'version_info': getattr(sys,'version_info','????'), 'winver': getattr(sys,'winver','????'), 'environment': '\n\t\t\t'.join(['']+['%s=%r' % (k,env[k]) for k in K]), '__rl_loader__': repr(__rl_loader__), 'project_meta_data': md, 'project_version': project_version, }) for M,A in ( (sys,('getwindowsversion','getfilesystemencoding')), (os,('uname', 'ctermid', 'getgid', 'getuid', 'getegid', 'geteuid', 'getlogin', 'getgroups', 'getpgrp', 'getpid', 'getppid', )), ): for a in A: if hasattr(M,a): try: store[a] = getattr(M,a)() except: pass if exed!=cwd: try: store.update({'exed': exed, 'lexed': os.listdir(exed),}) except: pass if getScript: fn = os.path.abspath(sys.argv[0]) if os.path.isfile(fn): try: store['__script'] = (fn,open(fn,'r').read()) except: pass module_versions = {} for n,m in sys.modules.items(): if n=='reportlab' or n=='rlextra' or n[:10]=='reportlab.' or n[:8]=='rlextra.': v = [getattr(m,x,None) for x in ('__version__','__path__','__file__')] if [_f for _f in v if _f]: v = [v[0]] + [_f for _f in v[1:] if _f] module_versions[n] = tuple(v) store['__module_versions'] = module_versions self.store['__payload'] = {} self._add(kw) def _add(self,D): payload = self.store['__payload'] for k, v in D.items(): payload[k] = v def add(self,**kw): self._add(kw) def _dump(self,f): try: pos=f.tell() pickle.dump(self.store,f) except: S=self.store.copy() ff=BytesIO() for k,v in S.items(): try: pickle.dump({k:v},ff) except: S[k] = '' % v f.seek(pos,0) pickle.dump(S,f) def dump(self): f = open(self.fn,'wb') try: self._dump(f) finally: f.close() def dumps(self): f = BytesIO() self._dump(f) return f.getvalue() def _load(self,f): self.store = pickle.load(f) def load(self): f = open(self.fn,'rb') try: self._load(f) finally: f.close() def loads(self,s): self._load(BytesIO(s)) def _show_module_versions(self,k,v): self._writeln(k[2:]) K = list(v.keys()) K.sort() for k in K: vk = vk0 = v[k] if isinstance(vk,tuple): vk0 = vk[0] try: __import__(k) m = sys.modules[k] d = getattr(m,'__version__',None)==vk0 and 'SAME' or 'DIFFERENT' except: m = None d = '??????unknown??????' self._writeln(' %s = %s (%s)' % (k,vk,d)) def _banner(self,k,what): self._writeln('###################%s %s##################' % (what,k[2:])) def _start(self,k): self._banner(k,'Start ') def _finish(self,k): self._banner(k,'Finish ') def _show_lines(self,k,v): self._start(k) self._writeln(v) self._finish(k) def _show_file(self,k,v): k = '%s %s' % (k,os.path.basename(v[0])) self._show_lines(k,v[1]) def _show_payload(self,k,v): if v: import pprint self._start(k) pprint.pprint(v,self.stdout) self._finish(k) def _show_extensions(self): for mn in ('_rl_accel','_renderPM','sgmlop','pyRXP','pyRXPU','_imaging','Image'): try: A = [mn].append __import__(mn) m = sys.modules[mn] A(m.__file__) for vn in ('__version__','VERSION','_version','version'): if hasattr(m,vn): A('%s=%r' % (vn,getattr(m,vn))) except: A('not found') self._writeln(' '+' '.join(A.__self__)) specials = {'__module_versions': _show_module_versions, '__payload': _show_payload, '__traceback': _show_lines, '__script': _show_file, } def show(self): K = list(self.store.keys()) K.sort() for k in K: if k not in list(self.specials.keys()): self._writeln('%-15s = %s' % (k,self.store[k])) for k in K: if k in list(self.specials.keys()): self.specials[k](self,k,self.store[k]) self._show_extensions() def payload(self,name): return self.store['__payload'][name] def __setitem__(self,name,value): self.store['__payload'][name] = value def __getitem__(self,name): return self.store['__payload'][name] def _writeln(self,msg): self.stdout.write(msg+'\n') def _flatten(L,a): for x in L: if isSeq(x): _flatten(x,a) else: a(x) def flatten(L): '''recursively flatten the list or tuple L''' R = [] _flatten(L,R.append) return R def find_locals(func,depth=0): '''apply func to the locals at each stack frame till func returns a non false value''' while 1: _ = func(sys._getframe(depth).f_locals) if _: return _ depth += 1 class _FmtSelfDict: def __init__(self,obj,overrideArgs): self.obj = obj self._overrideArgs = overrideArgs def __getitem__(self,k): try: return self._overrideArgs[k] except KeyError: try: return self.obj.__dict__[k] except KeyError: return getattr(self.obj,k) class FmtSelfDict: '''mixin to provide the _fmt method''' def _fmt(self,fmt,**overrideArgs): D = _FmtSelfDict(self, overrideArgs) return fmt % D def _simpleSplit(txt,mW,SW): L = [] ws = SW(' ') O = [] w = -ws for t in txt.split(): lt = SW(t) if w+ws+lt<=mW or O==[]: O.append(t) w = w + ws + lt else: L.append(' '.join(O)) O = [t] w = lt if O!=[]: L.append(' '.join(O)) return L def simpleSplit(text,fontName,fontSize,maxWidth): from reportlab.pdfbase.pdfmetrics import stringWidth lines = asUnicode(text).split(u'\n') SW = lambda text, fN=fontName, fS=fontSize: stringWidth(text, fN, fS) if maxWidth: L = [] for l in lines: L.extend(_simpleSplit(l,maxWidth,SW)) lines = L return lines def escapeTextOnce(text): "Escapes once only" from xml.sax.saxutils import escape if text is None: return text if isBytes(text): s = text.decode('utf8') text = escape(text) text = text.replace(u'&amp;',u'&') text = text.replace(u'&gt;', u'>') text = text.replace(u'&lt;', u'<') return text def fileName2FSEnc(fn): if isUnicode(fn): return fn else: for enc in fsEncodings: try: return fn.decode(enc) except: pass raise ValueError('cannot convert %r to filesystem encoding' % fn) import itertools def prev_this_next(items): """ Loop over a collection with look-ahead and look-back. From Thomas Guest, http://wordaligned.org/articles/zippy-triples-served-with-python Seriously useful looping tool (Google "zippy triples") lets you loop a collection and see the previous and next items, which get set to None at the ends. To be used in layout algorithms where one wants a peek at the next item coming down the pipe. """ extend = itertools.chain([None], items, [None]) prev, this, next = itertools.tee(extend, 3) try: next(this) next(next) next(next) except StopIteration: pass return zip(prev, this, next) def commasplit(s): ''' Splits the string s at every unescaped comma and returns the result as a list. To escape a comma, double it. Individual items are stripped. To avoid the ambiguity of 3 successive commas to denote a comma at the beginning or end of an item, add a space between the item seperator and the escaped comma. >>> commasplit(u'a,b,c') == [u'a', u'b', u'c'] True >>> commasplit('a,, , b , c ') == [u'a,', u'b', u'c'] True >>> commasplit(u'a, ,,b, c') == [u'a', u',b', u'c'] ''' if isBytes(s): s = s.decode('utf8') n = len(s)-1 s += u' ' i = 0 r=[u''] while i<=n: if s[i]==u',': if s[i+1]==u',': r[-1]+=u',' i += 1 else: r[-1] = r[-1].strip() if i!=n: r.append(u'') else: r[-1] += s[i] i+=1 r[-1] = r[-1].strip() return r def commajoin(l): ''' Inverse of commasplit, except that whitespace around items is not conserved. Adds more whitespace than needed for simplicity and performance. >>> commasplit(commajoin(['a', 'b', 'c'])) == [u'a', u'b', u'c'] True >>> commasplit((commajoin([u'a,', u' b ', u'c'])) == [u'a,', u'b', u'c'] True >>> commasplit((commajoin([u'a ', u',b', u'c'])) == [u'a', u',b', u'c'] ''' return u','.join([ u' ' + asUnicode(i).replace(u',', u',,') + u' ' for i in l ]) def findInPaths(fn,paths,isfile=True,fail=False): '''search for relative files in likely places''' exists = isfile and os.path.isfile or os.path.isdir if exists(fn): return fn pjoin = os.path.join if not os.path.isabs(fn): for p in paths: pfn = pjoin(p,fn) if exists(pfn): return pfn if fail: raise ValueError('cannot locate %r with paths=%r' % (fn,paths)) return fn def annotateException(msg,enc='utf8',postMsg='',sep=' '): '''add msg to the args of an existing exception''' t,v,b=sys.exc_info() rl_reraise(t,t(sep.join((_ for _ in (msg,str(v),postMsg) if _))),b) def escapeOnce(data): """Ensure XML output is escaped just once, irrespective of input >>> escapeOnce('A & B') 'A & B' >>> escapeOnce('C & D') 'C & D' >>> escapeOnce('E &amp; F') 'E & F' """ data = data.replace("&", "&") #...but if it was already escaped, make sure it # is not done twice....this will turn any tags # back to how they were at the start. data = data.replace("&amp;", "&") data = data.replace("&gt;", ">") data = data.replace("&lt;", "<") data = data.replace("&#", "&#") #..and just in case someone had double-escaped it, do it again data = data.replace("&amp;", "&") data = data.replace("&gt;", ">") data = data.replace("&lt;", "<") return data class IdentStr(str): '''useful for identifying things that get split''' def __new__(cls,value): if isinstance(value,IdentStr): inc = value.__inc value = value[:-(2+len(str(inc)))] inc += 1 else: inc = 0 value += '[%d]' % inc self = str.__new__(cls,value) self.__inc = inc return self class RLString(str): '''allows specification of extra properties of a string using a dictionary of extra attributes eg fontName = RLString('proxima-nova-bold', svgAttrs=dict(family='"proxima-nova"',weight='bold')) ''' def __new__(cls,v,**kwds): self = str.__new__(cls,v) for k,v in kwds.items(): setattr(self,k,v) return self def makeFileName(s): '''force filename strings to unicode so python can handle encoding stuff''' if not isUnicode(s): s = s.decode('utf8') return s class FixedOffsetTZ(datetime.tzinfo): """Fixed offset in minutes east from UTC.""" def __init__(self, h, m, name): self.__offset = datetime.timedelta(hours=h, minutes = m) self.__name = name def utcoffset(self, dt): return self.__offset def tzname(self, dt): return self.__name def dst(self, dt): return datetime.timedelta(0) class TimeStamp: def __init__(self,invariant=None): if invariant is None: from reportlab.rl_config import invariant t = os.environ.get('SOURCE_DATE_EPOCH','').strip() if invariant or t: t = int(t) if t else 946684800.0 lt = time.gmtime(t) dhh = dmm = 0 self.tzname = 'UTC' else: t = time.time() lt = tuple(time.localtime(t)) dhh = int(time.timezone / (3600.0)) dmm = (time.timezone % 3600) % 60 self.tzname = '' self.t = t self.lt = lt self.YMDhms = tuple(lt)[:6] self.dhh = dhh self.dmm = dmm @property def datetime(self): if self.tzname: return datetime.datetime.fromtimestamp(self.t,FixedOffsetTZ(self.dhh,self.dmm,self.tzname)) else: return datetime.datetime.now() @property def asctime(self): return time.asctime(self.lt) def recursiveGetAttr(obj, name, g=None): "Can call down into e.g. object1.object2[4].attr" if not isStr(name): raise TypeError('invalid recursive access of %s.%s' % (repr(obj),name)) name = asNative(name) name = name.strip() if not name: raise ValueError('empty recursive access of %s' % repr(obj)) dot = '.' if name and name[0] not in '[.(' else '' return rl_safe_eval('obj%s%s'%(dot,name), g={}, l=dict(obj=obj)) def recursiveSetAttr(obj, name, value): "Can call down into e.g. object1.object2[4].attr = value" #get the thing above last. tokens = name.split('.') if len(tokens) == 1: setattr(obj, name, value) else: most = '.'.join(tokens[:-1]) last = tokens[-1] parent = recursiveGetAttr(obj, most) setattr(parent, last, value) def recursiveDelAttr(obj, name): tokens = name.split('.') if len(tokens) == 1: delattr(obj, name) else: most = '.'.join(tokens[:-1]) last = tokens[-1] parent = recursiveGetAttr(obj, most) delattr(parent, last) def yieldNoneSplits(L): '''yield sublists of L separated by None; the Nones disappear''' i = 0 n = len(L) while i
  • ReportLab Homepage »