pisa-3.0.32/0000755000175000017500000000000011201057433010663 5ustar wmbwmbpisa-3.0.32/test/0000755000175000017500000000000011201057433011642 5ustar wmbwmbpisa-3.0.32/test/test-collapse.html0000644000175000017500000000315211160170351015307 0ustar wmbwmb Unbenanntes Dokument
yyy
xxx
x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x
x x

x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x
x x

xxx

xxx

xxx

xxx

xxx pisa-3.0.32/test/test-list.html0000644000175000017500000001246211160170351014464 0ustar wmbwmb Unbenanntes Dokument

Sitemap

Lorem ipsum...

  • 1
  • 2
    • a
      • i
      • ii
      ccc
    • b
  • 3 Lorem ipsum... Lorem ipsum... Lorem ipsum... Lorem ipsum... Lorem ipsum... Lorem ipsum... Lorem ipsum... Lorem ipsum... Lorem ipsum... Lorem ipsum... Lorem ipsum... Lorem ipsum... Lorem ipsum... Lorem ipsum... Lorem ipsum... Lorem ipsum... Lorem ipsum... Lorem ipsum... Lorem ipsum...
  • 4

Lorem...

  1. 1
  2. 2
    1. a
      1. i
      2. iii
    2. b
  3. 3 Lorem ipsum... Lorem ipsum... Lorem ipsum... Lorem ipsum... Lorem ipsum... Lorem ipsum... Lorem ipsum... Lorem ipsum... Lorem ipsum... Lorem ipsum... Lorem ipsum... Lorem ipsum... Lorem ipsum... Lorem ipsum... Lorem ipsum... Lorem ipsum... Lorem ipsum... Lorem ipsum... Lorem ipsum...
  4. 4

 

pisa-3.0.32/test/helloworld.py0000644000175000017500000000121711160170351014367 0ustar wmbwmb# -*- coding: ISO-8859-1 -*- ############################################# ## (C)opyright by Dirk Holtwick ## ## All rights reserved ## ############################################# __version__ = "$Revision: 194 $" __author__ = "$Author: holtwick $" __date__ = "$Date: 2008-04-18 18:59:53 +0200 (Fr, 18 Apr 2008) $" import ho.pisa as pisa def helloWorld(): filename = __file__ + ".pdf" pdf = pisa.CreatePDF( u"Hello World", file(filename, "wb") ) if not pdf.err: pisa.startViewer(filename) if __name__=="__main__": pisa.showLogging() helloWorld() pisa-3.0.32/test/cookbook.html0000644000175000017500000000113011160170351014330 0ustar wmbwmb HTML to PDF conversion example

Hello Wörld


Amount Description Total
1 Good weather 0 EUR
Sum 0 EUR
pisa-3.0.32/test/test-template.html0000644000175000017500000000114611160170351015321 0ustar wmbwmb Template Das ist ein Test

Etwas Text Nochwas Neue Seite DREI Nochwas pisa-3.0.32/test/test-unicode-greek.html0000644000175000017500000000627011160170351016232 0ustar wmbwmb Greek Test and Resource Link Following are the names of the books of the New Testament in Greek (and Ojibwe).

ΜΑΤΘΑΙΟΝ - ᒪᑎᔪ
ΜΑΡΚΟΝ - ᒪᕒᒃ
ΛΟΥΚΑΝ - ᓫᐅᒃ
ΙΩΑΝΝΗΝ - ᒜᓐ
ΠΡΑΞΕΙΣ - ᐃᔑᒋᑫᐎᓇᓐ
ΡΩΜΑΙΟΥΣ - ᐅᕒᐅᒪᓇᒃ
ΚΟΡΙΝΘΙΟΥΣ Α' - 1 ᑲᕒᐃᑎᔭᓇᒃ
ΚΟΡΙΝΘΙΟΥΣ Β' - 2 ᑲᕒᐃᑎᔭᓇᒃ
ΓΑΛΑΤΑΣ - ᑲᓫᐁᔑᔭᓇᒃ
ΕΦΕΣΙΟΥΣ - ᐃᐱᔑᔭᓇᒃ
ΦΙΛΙΠΠΗΣΙΟΥΣ - ᐱᓫᐃᐱᔭᓇᒃ
ΚΟΛΟΣΣΑΕΙΣ - ᑲᓫᐊᔑᔭᓇᒃ
ΘΕΣΣΑΛΟΝΙΚΕΙΣ Α' - 1 ᑌᓴᓫᐅᓂᔭᓇᒃ
ΘΕΣΣΑΛΟΝΙΚΕΙΣ Β' - 2 ᑌᓴᓫᐅᓂᔭᓇᒃ
ΤΙΜΟΘΕΟΝ Α' - 1 ᑎᒪᑎ
ΤΙΜΟΘΕΟΝ Β' - 2 ᑎᒪᑎ
ΤΙΤΟΝ - ᑕᐃᑕᔅ
ΦΙΛΗΜΟΝΑ - ᐸᐃᓫᐃᒪᓐ
ΕΒΡΑΙΟΥΣ - ᐃᐸᕒᐅᐗᒃ
ΙΑΚΩΒΟΥ - ᒉᒥᔅ
ΠΕΤΡΟΥ Α' - 1 ᐱᑕᕒ
ΠΕΤΡΟΥ Β' - 2 ᐱᑕᕒ
ΙΩΑΝΝΟΥ Α' - 1 ᒐᓐ
ΙΩΑΝΝΟΥ Β' - 2 ᒐᓐ
ΙΩΑΝΝΟΥ Γ' - 3 ᒐᓐ
ΙΟΥΔΑ - ᒍᑦ
ΑΠΟΚΑΛΥΨΙΣ - ᑭᑫᑕᒧᔑᐌᐎᓐ

Many thanks to Birger Langker for providing the following link to The New Testament in Modern Greek. http://www.gospel.gr
My home page
pisa-3.0.32/test/test-cdata.xml0000644000175000017500000000170411160170351014416 0ustar wmbwmb CSS 2.1 Test Suite: Inheritance

This uld]]> be blue and underlined.

This sentence should be underlined, including this part, this part, this part, and this part.

This sentence should also be underlined, as well as italics, including this part.

This sentence should be blue but not underlined, like this part, but this part should be underlined.

pisa-3.0.32/test/test-cdata.html0000644000175000017500000000225711160170351014566 0ustar wmbwmb CSS 2.1 Test Suite: Inheritance

This be blue and underlined.

This sentence should be underlined, including this part, this part, this part, and this part.

This sentence should also be underlined, as well as italics, including this part.

This sentence should be blue but not underlined, like this part, but this part should be underlined.

pisa-3.0.32/test/test-css-media-2.css0000644000175000017500000000005511160170351015334 0ustar wmbwmb/* CSS Document */ .green5 { color: green; }pisa-3.0.32/test/test-css-border.html0000644000175000017500000000122111160170351015543 0ustar wmbwmb

green text, green border

normal text, green border

normal text, green border, thick blue on top

normal text, green border, thick blue on top

normal text, no border

pisa-3.0.32/test/._test-bidirectional-text.html0000644000175000017500000000027211163174620017522 0ustar wmbwmbMac OS X  2ATTR&'""com.macromates.caret{ column = 0; line = 50; }pisa-3.0.32/test/test-css-media-4.css0000644000175000017500000000005511160170351015336 0ustar wmbwmb/* CSS Document */ .green7 { color: green; }pisa-3.0.32/test/test-css-media.html0000644000175000017500000000162511160170351015355 0ustar wmbwmb Test Media

Normal

Green

Green only in PDF

Green only on screen

Green only in PDF (external)

Green only on screen (external)

Green only in PDF (external)

Green only in PDF (sub-external)

pisa-3.0.32/test/pdfjoiner.py0000644000175000017500000000202411164163333014177 0ustar wmbwmb# -*- coding: ISO-8859-1 -*- ############################################# ## (C)opyright by Dirk Holtwick, 2002-2007 ## ## All rights reserved ## ############################################# __reversion__ = "$Revision: 20 $" __author__ = "$Author: holtwick $" __date__ = "$Date: 2007-10-09 12:58:24 +0200 (Di, 09 Okt 2007) $" from sx.pisa3 import pisa from sx.pisa3 import pisa_pdf if __name__=="__main__": pdf = pisa_pdf.pisaPDF() subPdf = pisa.pisaDocument( u""" Hello World """) pdf.addDocument(subPdf) raw = open("test-loremipsum.pdf", "rb").read() pdf.addFromString(raw) pdf.addFromURI("test-loremipsum.pdf") pdf.addFromFile(open("test-loremipsum.pdf", "rb")) datauri = pisa.makeDataURIFromFile("test-loremipsum.pdf") pdf.addFromURI(datauri) # Write the result to a file and open it filename = __file__ + ".pdf" result = pdf.getvalue() open(filename, "wb").write(result) pisa.startViewer(filename) pisa-3.0.32/test/test-all.html0000644000175000017500000000404711160170351014261 0ustar wmbwmb Test all features of pisa

This document will try to test all features of pisa in an easy way. On the left side you see the rendered snippet an on the right an Image showing how it should look like

# Rendered Sample
01 Normal Bold Italic Underlined Red Bigger Times Normal
02 Normal 1 2 3 4 5 6 7
Normal smaller larger -4 -3 -2 -1 +2 +3 +4 +5

Normal smaller larger -4 -3 -2 -1 +2 +3 +4 +5

pisa-3.0.32/test/test-pisa-toc-entities.html0000644000175000017500000000426211160170351017051 0ustar wmbwmb

Table of Contents

1. Blender

Blender is a software that is used for creating 3D content. Primarily this means you can make three dimensional images. However, you can also add sound, and make it time-based and interactive. This makes Blender ideal for a wide range of uses including creating 3D models, rendering, post -production, story boarding, creating animations, making movies, creating 3D 'programs', and making interactive environments and games.

2. Blender & it's Unique Interface

­It's no secret that the Blender interface breaks a lot of rules. Luckily Blender has good reasons for it and after time these reasons become clear. Blender's interface is built around providing you with the shortest routes to the most results. It's also particularly focused on reducing the kind of stress on wrists and hands that's often felt when using mouse-intensive graphical applications every day.

3. < Installing Blender on OSX

Software Name: Blender
Homepage: http://www.blender.org
Software version used for this installation: Blender 2.43
Operating System used for thisinstalltion: OSX (10.4.8)
Reccomended Hardware: Powerbook G4, Powermac G5, Mac Pro, MacBookPro, iMac (core Duo)

Downloading

The latest stable version of Blender for OSX can be downloaded at http://www.blender.org/download/get-blender/

pisa-3.0.32/test/test-font-img-error.html0000644000175000017500000000130411163674033016362 0ustar wmbwmb Bidirectional Text Hallo Welt

hallo

hallo

See this?

Next line pisa-3.0.32/test/test-para-border.html0000644000175000017500000000151111160170351015700 0ustar wmbwmb

Hello World: class=c1

Goodbye: class=c2

Mixed colors: class=c3

Hello World: class=c1
Goodbye: class=c2 
Mixed colors: class=c3
pisa-3.0.32/test/test-keep-with-next.html0000644000175000017500000006352211160170351016365 0ustar wmbwmb

Without "Keep Next"

Header 2

Lorem ipsum sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu Lorem ipsum sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu Lorem ipsum sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu Lorem ipsum sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu Lorem ipsum sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu Lorem ipsum sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu Lorem ipsum sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu

Lorem ipsum sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu Lorem ipsum sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu Lorem ipsum sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu Lorem ipsum sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu Lorem ipsum sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu Lorem ipsum sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu Lorem ipsum sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu

Lorem ipsum sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu Lorem ipsum sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu Lorem ipsum sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu Lorem ipsum sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu Lorem ipsum sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu Lorem ipsum sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu Lorem ipsum sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu

Header 2

Lorem ipsum sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu Lorem ipsum sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu Lorem ipsum sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu

Header 2

Lorem ipsum sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu Lorem ipsum sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu Lorem ipsum sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu Lorem ipsum sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu Lorem ipsum sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu Lorem ipsum sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu Lorem ipsum sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu Lorem ipsum sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu Lorem ipsum sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu

Lorem ipsum sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu Lorem ipsum sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu Lorem ipsum sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu

Lorem ipsum sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu Lorem ipsum sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu Lorem ipsum sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu

With "Keep Next"

Header 2

Lorem ipsum sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu Lorem ipsum sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu Lorem ipsum sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu Lorem ipsum sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu Lorem ipsum sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu Lorem ipsum sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu Lorem ipsum sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu

Lorem ipsum sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu Lorem ipsum sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu Lorem ipsum sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu Lorem ipsum sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu Lorem ipsum sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu Lorem ipsum sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu Lorem ipsum sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu

Lorem ipsum sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu Lorem ipsum sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu Lorem ipsum sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu Lorem ipsum sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu Lorem ipsum sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu Lorem ipsum sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu Lorem ipsum sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu

Header 2

Lorem ipsum sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu Lorem ipsum sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu Lorem ipsum sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu

Header 2

Lorem ipsum sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu Lorem ipsum sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu Lorem ipsum sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu Lorem ipsum sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu Lorem ipsum sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu Lorem ipsum sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu Lorem ipsum sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu Lorem ipsum sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu Lorem ipsum sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu

Lorem ipsum sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu Lorem ipsum sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu Lorem ipsum sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu

Lorem ipsum sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu Lorem ipsum sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu Lorem ipsum sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu

pisa-3.0.32/test/test-css.html0000644000175000017500000000324311160170351014276 0ustar wmbwmb Standardfarbe: grau
(mit div#eins > p :display inline;) grau

blau gruen blau

(mit div.zwei > p :display inline;) grau

blau gruen blau

(ohne div > p :display inline;) grau

blau gruen blau

grau

blau rot blau

dick und fett

fett und underlined

hier nicht mehr

hier nur noch dick

xx

underlined

hier nicht

pisa-3.0.32/test/simple-css.html0000644000175000017500000000072411160170351014611 0ustar wmbwmb

Paragraph without styles

Paragraph with styles

pisa-3.0.32/test/pdf.css0000644000175000017500000000164511160170351013132 0ustar wmbwmb .rand_oben{ border-top: 1px solid #333; } .rand_unten{ border-bottom: 1px solid #333; } .rand_links{ border-left: 1px solid #333; } .rand_rechts{ border-right: 1px solid #333; } td{ font-family:Arial, Helvetica, sans-serif; font-size: 8px; } h1{ font-size:20px; margin:0; padding:0; font-weight:normal; } h3{ margin:0; padding:0; font-size: 10px; } h4{ margin:0; margin-bottom:5px; padding:0; } .gueltig_bis{ font-size: 20px; color:white; margin: auto 0; } .grauer_bg{ background-color:#CCCCCC; font-family:Arial, Helvetica, sans-serif; font-size: 10px; border:solid 1px #000000; } .dunkel_grauer_bg{ background-color:#999999; } .niedrig{ font-size:1px; } .duenn{ margin-left:0; margin-right:0; padding-left:0; padding-right:0; font-size:1px; width:0.1cm; } pisa-3.0.32/test/test-image-align.html0000644000175000017500000000273011160170351015660 0ustar wmbwmb Grafiken ausrichten mit CSS

Denkt der Denker Denker an das Oben?

Woran der Denker denkt

Denkt der Denker an das Oben?

Denkt der Denker Denker an das Oben?


Denkt der Denker Denker an die Mitte?


Denkt der Denker Denker an das Unten?


Woran der Denker denkt

Denkt der Denker Denker an das Oben?


Denkt der Denker Denker an die Mitte?


Denkt der Denker Denker an das Unten?


Text?Oder denkt er an ...?

Manche Texte erschließen sich nur aus der nötigen Distanz. Aber das hier, das ist richtiger Text. Und er fließt sogar, nämlich um die Grafik.

pisa-3.0.32/test/test-css-fontface.html0000644000175000017500000000501511160170351016060 0ustar wmbwmb Test Media

Standard

This is normal becomes bold then also italic and then just italic

TTF (DejaVu Mono)

This is normal becomes bold then also italic and then just italic

Some text in "Farsi": به گفته وزیرخارجه روسیه، قطعنامه ای که اعضای دائم شورای امنیت سازمان ملل متحد و آلمان دیروز بر سر تصویب آن علیه ایران به توافق رسیدند، تحریمهای تازه و سختی بر این کشور اعمال نخواهد کرد

Some text in "Korean": 박응용

Postscript (XXX)

This is normal becomes bold then also italic and then just italic

pisa-3.0.32/test/test-css-media-1.css0000644000175000017500000000005511160170351015333 0ustar wmbwmb/* CSS Document */ .green4 { color: green; }pisa-3.0.32/test/test-page-box.html0000644000175000017500000000311511160170351015206 0ustar wmbwmb Unbenanntes Dokument

Lorem ipsum... 1

Lorem ipsum... 2

Lorem ipsum... 3

pisa-3.0.32/test/linkloading.py0000644000175000017500000002760111160170351014514 0ustar wmbwmb# -*- coding: ISO-8859-1 -*- ############################################# ## (C)opyright by Dirk Holtwick ## ## All rights reserved ## ############################################# __version__ = "$Revision: 194 $" __author__ = "$Author: holtwick $" __date__ = "$Date: 2008-04-18 18:59:53 +0200 (Fr, 18 Apr 2008) $" import ho.pisa as pisa import logging log = logging.getLogger(__file__) def dummyLoader(name): return '\x89PNG\r\n\x1a\n\x00\x00\x00\rIHDR\x00\x00\x00F\x00\x00\x00\x89\x04\x03\x00\x00\x00c\xbeS\xd6\x00\x00\x000PLTE\x00\x00\x00\n\x06\x04\x18\x14\x0f-&\x1eLB6w`E\x8f\x80q\xb2\x9c\x82\xbe\xa1{\xc7\xb0\x96\xd1\xbd\xa9\xd9\xd0\xc6\xef\xeb\xe6\xf8\xf3\xef\xff\xfb\xf7\xff\xff\xffZ\x83\x0b|\x00\x00\x0c\xedIDATx^u\x97]l\x1bWv\xc7g\xe2`\x81\xbe\xcd%Gr\xd3\xa7P\x12e\xb7\x01\x8a\xd0")E\x01\x02\x8f\xf8!\x8bI\x17\x10\xc5!))5`\xf1C\xb4\xb25`S\xb2l\xb95\x90H\xa4.\xb9/u$K3\xe3\xa2\x80W\x12\xc59L\xf6a\xb3\x8dcN\xd6@\xb7\x1f\x01\x8a\x85\x16\x9b-\xfa\x81M\xb8@\x83l\xd1\xd8\xbc|)\xd0\x97\x82\xea\xb93\x92\xec"\xce\x11 \t3?\xfe\xcf\xff\x9e{\xce\x01(\x1c>7\x18\xfb\xc2\xfaE\xffk_\xb6\x18\xeb\x1e>\x8f\xe92d\xfe%T\xa8\x98\xfa\x07\x1f $<\x0f\xe1\x91\xabT\xc1\xacT\xf2\xbfd\xec\xbb\x98\xdfM\xeb\x86aYP\xfa\xd3\xd6\xf3\x98C[\xa6\xaaU\xa1a5\xe9\x1b\xad\xef\xd0i}\x91\xccy+\xc8X\xf5E\xf6]:\xff0\xd8\x97\xce7\xb9P\xf1\xd1\xb7\x98\xaec\xe7/\xd3\xa1\xeb\x81{\x96e5\xd7.\xb6\x85\xe7\x99aO\x94\xf1R(\xfeC\xce\xd4F\xbf\xc50\x1b\xfa\xefS\xa9\xb2\x12p\x98({\x8eN\x9b\xb1\xbf\xf5O\xa5\xd7\x0b\xb4\xc9\x0f\x96\xeca\x9c\xd2\xb5\xad\x07\xdbS\x0b\xb0\xa5z\xeb\x94\xd2y\x80kD\xeeh._\x9dh4\x8d\xa7:\x8f#X\x13At\xdb3nF\xee\xc8\x19wV^\xf4\x1b\xd6\xdc\xed\x13\xe6w\x01I\x90\x90\xa1F\x05\x99\xdc}B\x88(\x87}\xb7\xac\xda\x99\x13\xe6\xa7\xa1\xf3\x02fs\xa5)\xbd\xd70\r\xceH"\x91\xc2\x15\xc8\x1e\x9f\xbd\xbd\x17\xf7\x8b\x04m\x07\xd2\xb4\x02\xc8 !\xcf\xe1\x83\x0b\xc6\x9d+\\\x87u;\xedl\xdc{^\x12\x05\x89$\x0b\xd40\xef\x12\tu\xd2\x99!\xec\xc4\xab\x17\x8f\x98\xc7/\xc6\x07\xc6$;\xc1YZ\xd1+\n\x11E\x12\xa0\xe0\x1b\x18G\xd3\x0e\xf3\xb57\xeeN\xbc,\x89\xa2@z\xd0\x12]\xc34C\x11d\xbct\x809\x0c\xfbU N"\x1eA\x92\xf0l\x03\xd8]\xeb\nq/\xc9\xb4\xe6\x91\x13\xf2\x97\xc8t\x1dF\xea#\xa2\xc0\xebH\x06)\x98\x8b\xc4\xbd\xd73\x12\x17e\xe5\x956g\xb0C~\x15P\x89(\t<\x08\xe9\xbda\xc0]\xcf\x1f\xed\x91\xbcBd\xe5\rv\xc4\xfc:\xac\xe2Qlf\xc8G\x82\x95\xc6\'\xf1\x18(><\xa6\xfb\xc0\xf6\x83\xcc\xe7\t\xd5G\x1c&\x8d\xc3E\x1b\x0fK\x00\x8a"\xc8\xd9\xde\x93\xfb\xfa\\U\xa7\x08\xcf\x85\x96\xd3\xf9\xb1\xf4\x0f\x9b\x9c\x11\xa4q_\xf8\xe0)3\xa5\x9e\x97\x1c;^\xbaU\xa8Z[1x\x9f\xbcX$3_v9\xd3\xedt?W\xe3^\x14r\xa04T\xc0\xfad\x14\xc6r\x83\xf7\xa5\xc4\x91\x1f\xc6\x90!r\x9fs0\xb1\xa76\xdd\xb0\x1e\xc66\xcf\\\x9ay\xf5\x85\xc4\xc1aW\xb0\x97\xd355A\x88,8AjA\x1d\x1b-S\x98Ly\xe4\xe4m\xe7\xec-\xe6WU\x82%\x94\x1cF\xed\xa1Uk/\xa2\xb9\xb3\xe4T\xee\r\xf6[dZ-\x16@F\xc2{w\x92\x05C#\xd4\x1a\x1f\xae\xcbe\x8f\xff\\\xaf\xe3\xa7\xfd\xf5\xd9\xb2:\x89wu\x14\xb2\xe2\xbeqO_\xa9\x0f\xaf\xfb\xfa\x06\xe7\xae\xb4m?\xff\xdc[\x8a\xa8\xca1$\x8a!\xf2Zc\x13\xea\x17\xd6\\I(\xcd\xb4\x84\xeea\x9b}\xe4\xce\x8f\x85\x13\xce\x8d\x89\xc8HR\x10\xb2P\xa7\x19w\x0c\xf6\x93\xbf\xe4L\xeb\x12\x89\x95\\\x11\xc5\xbe1" *\xca\xc6\x80Ik\xbe\xf0\x02\xd4s\x8f\xb8\x9fo|\xbd\x83\xda\x80+\xc7\xdbPD\x10\x8f\xf8\xc2B?\xadlD\x8b\x00\x943]\xf6?\xa9\xfe\x1e\xdc\xd6\x83\x08\t\xbc\x00\xc3\x8aH\xd2\xfd\x85\x8a_\x1b?a~\xb4\xb0\x99\xf1-g\xfc\x86\x11\x1a\x1a:\xd7G\x00\xce\x8b\xbd\xef\x176a\xed\xb5f\xb3\x9e{\x9b\xe7\xda\xbde\xc1^h\x1cj\x97s*\xc69\x80]B2\x05]\xcb.\x00\xd4\xcb\xafs\x9d\xfb\xef\xe0\x90\xefG\r\x8d\xaa\xe10\x9aA\x8eH\xee\x02-\xab^\x00\xd3f\xba\xbb\xc6\xa7V\xb3\xa9Uu]\xcf\x86\xb1\xda\xf6\x8c\xbe\x90,\xe4\x16]Q\xd08s\xd8\xde\xc5=\xd0\x040\xa0\x01e\x1f\x8e\xab\xcd\x90Hr\xdd\xf4yS\xb0\xc5\x99\xc71\x04@\xdf\x1c6\x00\xeeb\x89$\xde\xb5\xc4C\xfa\x01v\x86\xd2\xb0\x8f\x9e\xbb\xffV\x05\x93\x96\t\x99\x9b\x013DPG$R\xdf\xa9bx\x85\x7f\x12\xac\x07\x9c\xf9\xa4\n:\x8d\xe3h\xcfC.\xcb\xcbH\xdc\x03j\x90\xa2]\xdd\xc0\x9de\xfe\x00\x99T\x15\xa0\xe6!\x0159\x9f\xcf\xc7\t"I\x7f\xb9@\xab\x1a\xa5Z\xf5SK{\x13\x99\xf1*\xd4\xe7\xc8 \x8e\xf0\xe5\x89p\xde#{\xe3\xe9<\xb5\xa3R\xbfgY\x9a\x1f=GQg{\xfe\x06\xc5X\xd0\xebD.\xac\xf3\xff\xcb\xaa\x9a\xac\\\xc0\x9a\x94\\\x8e\x0e\x0f\xcd\xf9\xa4G.P\x8cuU\x8dxw\x0b\r0Koq\x86\x1aO!\x9a\x90\xd3\x1c\xc9*\x84\x8c\x16/7\xabu\xfa\xe7\xc8Di\xc5fL\x8a&\xe9v8\x89\x7fscD\x92\x17&W\x1e\xde\xd3J\xaf\xd8\x0c\xad\xd8\x14\xbe\x03C_T\xf3\xf9\\\xe2eB\xdc\xb1\x84F\xf5\xf0\x1a?{\x84[D\xa4\x01u\x8a\xbf\xf6T\x1e\xb83\xce\x04\xbd\xa6\xaa\xcd\xaf}\x88\xe7:?L\xb5\xfcM\'\x1b`(X*\xf5UQL-\xf5>\x18\xce\x8c$\x99\xc0\x98\x12\xa4tJ\xbd\xac\xeb<\x1bX\xcd\x1d{w\xf2\xae\x1d\xfeI\x94,q\xa6\xa3\x04\n\xebJ\x00\x97.\xcc\xeb\xb4\n\xf0>2|d%\x12\xfbI\xbe\'\x94\xecp\x9d@j]q\x0f\x8d\xd3\x9a?\xa6\x1b\x00\xef\x11I\xe0\xbb\x91\xb8\xa6wj\xd3\xc1 \xcf\xf5sY\xcdM\x11\x12(\x94\x88\\\xb1>K\xbf\xe7\x91\x88\xc8\xb5\xdc\xc9\xd0\xb5\xec\x99\xb78\xf3\xebS\xaa\x8a\x03\x88\x8c\x87\\\xf8\xf4\xfe\xcc5\xb4\x83\x86\x029\xf7\xd4\xe9\x9b\xa1\xa5/\xb9\x9f\xff\x15#jbh(\x92\xc6\x06\t6\xe6.\xfb\xb1\xc4\xfdb\x8fV\xf2\x89\xa2\x1c\xb9\xd2\xe6\xcc\x93\xc9\x80\x8a\x81\xf5\xc5d\xd5D\xed\x0f\xefr\xdd\x0b\xb4<\x89\xae\xc8\x15\xc6\x84\x0e\xeb~\x16Bh\x8a\xa8\xe5\xb0+Y\xd9\xdc\x9b\xb5,S!7hi\nG\x92\x1cp\xe6\xf0\xb7\x1fo\xf7\xf5\xf5\xbdL\x06K\x02\xb9P\x9d\xd8\xbbeY;\xa4\x07\xef,!\x89\xd2\xe9N\xf7\x10\x99v\x13\xee\xa0K\xd2["nZ\x81M\xec\xab;\x9e42\x93\x82$\xbe\xd29\xe4\xcc\x93\x18lp\xd5`\x89\x04\x0bU\x98Z\xb1\x9a\xfex\x9a\x96\xf9\xfa#\xb79\xc3\xba\xc8\x94\xf9|\xde(\x91\xe84@\xb2a}\x9c\x0c\xdb\xa9\x04\xe1\xd4#\x9ba\xc8`k\x89\xb2^"\x91\n\xec\xa7,kiKFF\xc1\x91\xc5m\x88\xcc!{2\x08\xb4\xe4\x11\'\x00sU\xeb\xc5\xd9fx\xa6&\xd3r\x02\'Q|\xb3c3\x87\xed\xbbP_#d\xc6\x98\x93\xd3\xd5\xd5\xc0\xec\xc3\x01(\xcbeu\n\x19r\x91ul\xa6\xb3\x07u\xac\xde\xeeK\x97\x08\xf6Vpv\'\x06\xef\x8e\xe4T\x85\x88\x92\xcc\x1c\xa6\xcb\x90YC\xe6\xb4B\xc2!wa=\x07\xf5w\xc7U,\x0e\x91\xfe\xa4\xd5:a\xcc\xb2O\xde\xed%\x18=t{\x06\xb4w\x83\t\x9f\x84%\xfbY\xf7(\x17\xdbY\x00\xaa\xc8\xbbI>\xea\x11\xdee\x9a\x12T\xb0b\xe2\xf7\x0eP\xc7\xf1|\x9f3$Q\xe4\xdb9J\rd\xce\xe5}\x9c\xf9\xb36;\xd6\xb9?\x83\x8c\x18\xbe\x86\x0c\x19__\x01s\xcd\xbd\xf8\x02\xf6*\x16\x87\xb5\x8f\xfc\xd8:b\xe2\x9a$H\xaedy\x01\xccLOv@\xb2\xdb\x82u\x1d\xa6\xbd\xb3b3s(\xe3N\xa1\x9fm_$\x11\x97D^c\xac\xa0\xe3g\x0f\x00\xeb<4\x87\x1f\x95SK\xbcX\xc3XA\xe9-4s\xc4t\x9f\xf8\x01\xd6\xf0H\xd8\xc7DNfM:\xd7sF\x9d\x12\xe5\x1f?\xcb\x8c\xa2K\x91\xb8\xe6DI\x94\xd3\xa3Z\x9ex\x83\x81\xb1\x84\xf7g\xfcP\xc7L\x8c\xdf\xa9\xf0\xa2\xffUQ\x08\xa4\xce\xe6|$\x91\x95U5\xf8\x08\x99\xae\xc3`\x8f\x99\x94*\x828\x91\x11p\x80\x06}\xe2)\xf5\xd2@^M\x7f\x88\x9e\x9f\xea\xd4)\x9d#\xe2BV\x10\x02\xd9~\\\x18\xd7\xc7\x92TM\xbf\xdd:a\x0e\xbf\x18EfU +\x8b\xc8d\xb0\xbe\xc1\xa4/J\xf37^G\xe4X\xe7q\xcc\x04Z&\xc2K\x0eC\\Y\x1a\xb8`,\x9a\xb7Z\xad\xa7\xb9Fu\x13u\xa4\x97\xb26#}\xcfK#\xd4\xd85W\xdb\xec\x19\xc6\x00\r\xeb\xfaR\xc9a\xc6F\xea\xab\x9aQ\x87U\xf6\x8cN\x0c\x1a\xday"\xfe\x9e\xc3\x90k#\xf52gJWX\x17\xef\xeb\x98\x01\x9a\xc7\xfa\x95\x88\xcd\xcc\x05\xa3U\xce\xd4\xdf\xc0+\xed:3\xf8x\x14\x99u\t\xbd\x12\x11\x19W1\xd0c\xd8\x8c\xcaX\x8b9\xf3\xf5\x1f1\xa8\xd3UIt\xe1p\xb8\xb3~Z\xf1\x91\r\xcd\xa85\xcc\xdc\x01k\x1f33\x00\xda\xaa\xe4\x0e/\x12\x89\xa4\xb1V\x8b\xbe\xa2\x06\xc5\x15(\xf1\x9b?\xb4\x99\xaf\x00\x80\xc6\xdd)\xc8\x12B\xfc\xcd\n\xad\x14s\xbay\x15\'|\x98\xb1\x13\x1d\x03h$U\x1b?\'\x86C\xa4\x01\x94\xee\x8e\xe8p\x15\x1b8\x8c\xd7\xeax\xfe\xeaF\xb5^\xd1k\xe7z\xb13\xae\xfb\x1aVS\xd39\x13\x03\x9ayttv\x16\xa2\x06\x98EQ\xec\x15"xo\xb8\xa1\x00Ftc\xaf\x17\x05\xdf\xec:\xf3\xce\xa2\x94\xc2&\x1f?\x92\xa6\xd5\xcd3M\x1d`\xa62\xbf\x13Df\x03\r\xd9~\xc2i\n\x97H8\xac\x88i\xdd0\x07,]\xdfZ\xd9^\xd9\xcf\x1b\x94\x96n\x1f1\xf7\xbdUXR)}\xcf\xfe\xa27`\x81V6\xf6rZn\x85\xd2\xf2\xf7\x8f\xcf%\xc3\x05\n\xf8@\xec\x1f1`\xee\x9df}j\xc5\xdc\x18Voit\xf5\xfb-\xc7\xf3\xcf\'\x8a\x7f\x00\x1a\xa5\xeb\xc4C&\xe0\xfdY\x0b&\x0bK\x99A\xafQ\xa7k\x07-\x9e\xab\xc3\xc6\xb6\x94\xd3\x00uZ\x96T%X\xd9\x8b!\x93t\'\x06\xaf\x83I\xd7o\xb7\x9c\\\x91\xc5p\xbfa\xeat]I\xff\xc8O\xf7\x83M\xc8\x10w\xc0\xbb\xb4b\xd2\xf2\xa8\xc3\xfc\xe7|\x94\xc6\xa7ML\x86_m\xb3\x14\x96\x8cz9G\xc8\xd9\xaca\x96\xe6C\x1fr\xa6\xf5@+\x18\xa5A\xd3\x04\x9a\xed\xd9\xc8j\xb0\x1f\xa6\xd4X"\xeei0\xd6\n\xea\x01g\xday\x8dB=~\x06\x1d\x95zV\xb7\xab`\xea\x1aB\xba\xc9\x1d\x06\xdf\xb6\xeb\xf3\x9b\n4\xf9N\xd8\xc6c(Y\xb3\x02{\xf3\x0f\n\x15@\xc3\x18\xfeN\xd7f(>\xc0\x9e\xbf3\x0e\x1a\xda\xd2\xa1\xe6\xc9O\xa0\xa8\x81H\xeeb\xdb\xd6\xf9G.\x0c\xb0zU\x9e\x81\xcd\xdf7\x00\x96<\xde( \xab\xd1l\xe0\xc0\xe9\xc3\x8f\x90G\xa9\xf8\xc6\xbc\x1fv\xe5J\xb5\xba\xd9#\'\x81K\xaf\xc5>hu\xed>\xfc)\xe5a\x8cm\xc2F\xcc\x1cZ\xde\xdc\x9f\x0ef\xd1\xf8:-\xfd\xd5\x01;\xea\xc3S\xd4\x8e\xdd\xe5\x19\x80\x86\x8fd\xca\x13\xd1\x1e\xa3\x9e\x0fEX\x1b\x7f\x1c\x1dU-\xd8\xd9F5t\x95 \xa1\xa5\x89\xa8:\xddTg\xf9N\xc5\xc9\xb1\x99\xc7J\xc4\x16\x9a\xd6\xd0\x95\x99 J4\xb5\x7f\xab\x85D\x8b\xffr\xf6<{\xb8\x1d\x0e\xf9\xa9\x13\xb0GnZ\xd6/Z\xfc%\xb3\x99\xae\xcd0f\xe1c\x1e\x9f\r\r\x05\xad\x16{&\x10\xc0\xf8?Z\n\xf1+\xfb\x81\xd5F\x00\x00\x00\x00IEND\xaeB`\x82' class myLinkLoader: """ This object is just a wrapper to track additional informations and handle temporary files after they are not needed any more. """ def __init__(self, **kw): """ The self.kw could be used in getFileName if you like """ self.kw = kw self.tmpFileList = [] def __del__(self): for path in self.tmpFileList: os.remove(path) self.tmpFileList = [] def getFileName(self, path, relative=None): import os import tempfile log.info("myLinkLoader.getFileName: %r %r %r", path, relative, self.kw) try: if "." in path: new_suffix = "." + path.split(".")[-1].lower() if new_suffix in (".css", ".gif", ".jpg", ".png"): suffix = new_suffix tmpPath = tempfile.mktemp(prefix="pisa-", suffix = suffix) tmpFile = file(tmpPath, "wb") try: # Here you may add your own stuff tmpFile.write(dummyLoader(path)) finally: tmpFile.close() self.tmpFileList.append(tmpPath) return tmpPath except Exception, e: log.exception("myLinkLoader.getFileName") return None def helloWorld(): filename = __file__ + ".pdf" lc = myLinkLoader(database="some_name", port=666).getFileName pdf = pisa.CreatePDF( u"""

Hello World

""", file(filename, "wb"), link_callback = lc, ) if not pdf.err: pisa.startViewer(filename) if __name__=="__main__": pisa.showLogging() helloWorld() # print repr(open("img/denker.png", "rb").read()) pisa-3.0.32/test/visualdiff.py0000644000175000017500000000534011160170351014351 0ustar wmbwmbimport sys import glob import subprocess import tempfile import os import os.path CONVERT = r"C:\Programme\ImageMagick-6.3.8-Q16\convert.exe" DIFF = "tortoiseidiff.exe" __version__ = "0.1" class VisualObject: def __init__(self): self.files = [] self.files4del = [] self.folder4del = None def __del__(self): for file in self.files4del: os.remove(file) self.files4del = [] if self.folder4del: os.rmdir(self.folder4del) self.folder4del = None def execute(self, *a): print "EXECUTE", " ".join(a) return subprocess.Popen(a, stdout=subprocess.PIPE).communicate()[0] def getFiles(self, folder, pattern="*.*"): pattern = os.path.join(folder, pattern) self.files = [x for x in glob.glob(pattern) if not x.startswith(".")] self.files.sort() print "FILES", self.files return self.files def loadFile(self, file, folder=None, delete=True): if folder is None: folder = self.folder4del = tempfile.mkdtemp(prefix="visualdiff-tmp-") delete = True print "FOLDER", folder, "DELETE", delete source = os.path.abspath(file) destination = os.path.join(folder, "image.png") self.execute(CONVERT, source, destination) self.files4del = self.getFiles(folder, "*.png") return folder def compare(self, other, chunk=16 * 1024): if len(self.files) <> len(other.files): return False for i in range(len(self.files)): a = open(self.files[i], "rb") b = open(other.files[i], "rb") if a.read() <> b.read(): return False return True def getoptions(): from optparse import OptionParser usage = "usage: %prog [options] arg" description = """ Visual Differences """.strip() version = __version__ parser = OptionParser( usage, description=description, version=version, ) #parser.add_option( # "-c", "--css", # help="Path to default CSS file", # dest="css", # ) parser.add_option("-q", "--quiet", action="store_false", dest="verbose", default=True, help="don't print status messages to stdout") parser.set_defaults( # css=None, ) (options, args) = parser.parse_args() #if not (0 < len(args) <= 2): # parser.error("incorrect number of arguments") return options, args def main(): options, args = getoptions() print args a = VisualObject() b = VisualObject() a.loadFile("expected/test-loremipsum.pdf") b.files = a.files print a.compare(b) if __name__=="__main__": main() pisa-3.0.32/test/test-entities.html0000644000175000017500000020227411160170351015337 0ustar wmbwmb SELFHTML: HTML/XHTML / Referenz /HTML-Zeichenreferenz
SELFHTML

HTML-Zeichenreferenz

Informationsseite

nach unten Allgemeines zur HTML-Zeichenreferenz
nach unten Benannte Zeichen für HTML-eigene Zeichen
nach unten Benannte Zeichen für die Kodierung ISO 8859-1
nach unten Benannte Zeichen für griechische Buchstaben
nach unten Benannte Zeichen für mathematische Symbole
nach unten Benannte Zeichen für technische Symbole
nach unten Benannte Zeichen für Pfeil-Symbole
nach unten Benannte Zeichen für diverse Symbole
nach unten Benannte Zeichen lateinisch erweitert
nach unten Benannte Zeichen für Interpunktion
nach unten Benannte Zeichen diakritische Zeichen

 nach unten 

Allgemeines äöü zur HTML-Zeichenreferenz

In der Zeichenreferenz geht es um Zeichen, die zwischen dem Anfangs- und dem End-Tag eines HTML-Elements als Text stehen können (siehe auch Seite #PCDATA), sowie um Zeichen, die bei Wertzuweisungen an viele Attribute notiert werden können (siehe auch Seite #CDATA). Bei einem HTML-Konstrukt wie <p class="Aussage">Zeichen können viel bedeuten</p> ist zum einen die Zeichenfolge Zeichen können viel bedeuten relevant, und zum anderen die Zeichenfolge Aussage.

Seit HTML 4.0 kann jedes Zeichen aus dem Zeichenvorrat nach ISO 10646 (deckungsgleich mit dem Unicode-Standard) notiert werden. Beliebige Zeichen aus diesem gewaltigen Zeichenvorrat können durch eine spezielle numerische Notation erzeugt werden. Das Schema für solche numerischen Notationen lautet:
&#[x][Nummer];
Beispiele einer Notation in HTML:
&#945;
&#x3B1;
Das x notieren Sie dann, wenn Sie die Nummer hexadezimal angeben. Bei dezimaler Angabe lassen Sie das x weg. Die Unicode-Nummer eines gewünschten Zeichens können Sie aus den Codetabellen ermitteln (siehe Abschnitt über Seite das Unicode-System).

Neben der numerischen Unicode-Notation gibt es in HTML für häufiger verwendete Sonderzeichen auch so genannte named entities, benannte Zeichen. Alle benannten Zeichen werden nach dem folgenden Schema notiert:
&[Name];
Beispiel einer Notation in HTML:
&alpha;
Die verfügbaren benannten Zeichen können Sie den folgenden Tabellen entnehmen.

In der jeweils ersten Spalte der Tabellen wird versucht, das Zeichen mit Hilfe des HTML-Namens darzustellen. Ein WWW-Browser muss jedoch HTML 4.0 interpretieren, und auch dann kann er nur solche Zeichen darstellen, für die er eine geeignete Schriftart vorfindet.

nach obennach unten

Benannte Zeichen für HTML-eigene Zeichen

Zeichen Beschreibung Name in HTML Unicode in HTML
" Anführungszeichen oben &quot; &#34;
& Ampersand-Zeichen, kaufmännisches Und &amp; &#38;
< öffnende spitze Klammer &lt; &#60;
> schließende spitze Klammer &gt; &#62;
 

nach obennach unten

Benannte Zeichen für die Kodierung ISO 8859-1

siehe auch: Seite Codetabelle der Kodierung ISO 8859-1. Die HTML-Namen dieser Zeichen sind seit HTML 3.2 verfügbar.

Zeichen Beschreibung Name in HTML Unicode in HTML
  Erzwungenes Leerzeichen &nbsp; &#160;
¡ umgekehrtes Ausrufezeichen &iexcl; &#161;
¢ Cent-Zeichen &cent; &#162;
£ Pfund-Zeichen &pound; &#163;
¤ Währungszeichen &curren; &#164;
¥ Yen-Zeichen &yen; &#165;
¦ durchbrochener Strich &brvbar; &#166;
§ Paragraph-Zeichen &sect; &#167;
¨ Pünktchen oben &uml; &#168;
© Copyright-Zeichen &copy; &#169;
ª Ordinal-Zeichen weiblich &ordf; &#170;
« angewinkelte Anführungszeichen links &laquo; &#171;
¬ Verneinungs-Zeichen &not; &#172;
­ bedingter Trennstrich &shy; &#173;
® Registriermarke-Zeichen &reg; &#174;
¯ Überstrich &macr; &#175;
° Grad-Zeichen &deg; &#176;
± Plusminus-Zeichen &plusmn; &#177;
² Hoch-2-Zeichen &sup2; &#178;
³ Hoch-3-Zeichen &sup3; &#179;
´ Akut-Zeichen &acute; &#180;
µ Mikro-Zeichen &micro; &#181;
Absatz-Zeichen &para; &#182;
· Mittelpunkt &middot; &#183;
¸ Häkchen unten &cedil; &#184;
¹ Hoch-1-Zeichen &sup1; &#185;
º Ordinal-Zeichen männlich &ordm; &#186;
» angewinkelte Anführungszeichen rechts &raquo; &#187;
¼ ein Viertel &frac14; &#188;
½ ein Halb &frac12; &#189;
¾ drei Viertel &frac34; &#190;
¿ umgekehrtes Fragezeichen &iquest; &#191;
À A mit accent grave (Gravis) &Agrave; &#192;
Á A mit accent aigu (Akut) &Aacute; &#193;
 A mit Zirkumflex &Acirc; &#194;
à A mit Tilde &Atilde; &#195;
Ä A Umlaut &Auml; &#196;
Å A mit Ring &Aring; &#197;
Æ A mit legiertem E &AElig; &#198;
Ç C mit Häkchen &Ccedil; &#199;
È E mit accent grave (Gravis) &Egrave; &#200;
É E mit accent aigu (Akut) &Eacute; &#201;
Ê E mit Zirkumflex &Ecirc; &#202;
Ë E Umlaut &Euml; &#203;
Ì I mit accent grave (Gravis) &Igrave; &#204;
Í I mit accent aigu (Akut) &Iacute; &#205;
Î I mit Zirkumflex &Icirc; &#206;
Ï I Umlaut &Iuml; &#207;
Ð großes Eth (isländisch) &ETH; &#208;
Ñ N mit Tilde &Ntilde; &#209;
Ò O mit accent grave (Gravis) &Ograve; &#210;
Ó O mit accent aigu (Akut) &Oacute; &#211;
Ô O mit Zirkumflex &Ocirc; &#212;
Õ O mit Tilde &Otilde; &#213;
Ö O Umlaut &Ouml; &#214;
× Mal-Zeichen &times; &#215;
Ø O mit Schrägstrich &Oslash; &#216;
Ù U mit accent grave (Gravis) &Ugrave; &#217;
Ú U mit accent aigu (Akut) &Uacute; &#218;
Û U mit Zirkumflex &Ucirc; &#219;
Ü U Umlaut &Uuml; &#220;
Ý Y mit accent aigu (Akut) &Yacute; &#221;
Þ großes Thorn (isländisch) &THORN; &#222;
ß scharfes S &szlig; &#223;
à a mit accent grave (Gravis) &agrave; &#224;
á a mit accent aigu (Akut) &aacute; &#225;
â a mit Zirkumflex &acirc; &#226;
ã a mit Tilde &atilde; &#227;
ä a Umlaut &auml; &#228;
å a mit Ring &aring; &#229;
æ a mit legiertem e &aelig; &#230;
ç c mit Häkchen &ccedil; &#231;
è e mit accent grave (Gravis) &egrave; &#232;
é e mit accent aigu (Akut) &eacute; &#233;
ê e mit Zirkumflex &ecirc; &#234;
ë e Umlaut &euml; &#235;
ì i mit accent grave (Gravis) &igrave; &#236;
í i mit accent aigu (Akut) &iacute; &#237;
î i mit Zirkumflex &icirc; &#238;
ï i Umlaut &iuml; &#239;
ð kleines Eth (isländisch) &eth; &#240;
ñ n mit Tilde &ntilde; &#241;
ò o mit accent grave (Gravis) &ograve; &#242;
ó o mit accent aigu (Akut) &oacute; &#243;
ô o mit Zirkumflex &ocirc; &#244;
õ o mit Tilde &otilde; &#245;
ö o Umlaut &ouml; &#246;
÷ Divisions-Zeichen &divide; &#247;
ø o mit Schrägstrich &oslash; &#248;
ù u mit accent grave (Gravis) &ugrave; &#249;
ú u mit accent aigu (Akut) &uacute; &#250;
û u mit Zirkumflex &ucirc; &#251;
ü u Umlaut &uuml; &#252;
ý y mit accent aigu (Akut) &yacute; &#253;
þ kleines Thorn (isländisch) &thorn; &#254;
ÿ y Umlaut &yuml; &#255;
 

nach obennach unten

Benannte Zeichen für griechische Buchstaben

Die HTML-Namen dieser Zeichen sind seit HTML 4.0 verfügbar.

Zeichen Beschreibung Name in HTML Unicode in HTML
Α Alpha groß &Alpha; &#913;
α alpha klein &alpha; &#945;
Β Beta groß &Beta; &#914;
β beta klein &beta; &#946;
Γ Gamma groß &Gamma; &#915;
γ gamma klein &gamma; &#947;
Δ Delta groß &Delta; &#916;
δ delta klein &delta; &#948;
Ε Epsilon groß &Epsilon; &#917;
ε epsilon klein &epsilon; &#949;
Ζ Zeta groß &Zeta; &#918;
ζ zeta klein &zeta; &#950;
Η Eta groß &Eta; &#919;
η eta klein &eta; &#951;
Θ Theta groß &Theta; &#920;
θ theta klein &theta; &#952;
Ι Iota groß &Iota; &#921;
ι iota klein &iota; &#953;
Κ Kappa groß &Kappa; &#922;
κ kappa klein &kappa; &#954;
Λ Lambda groß &Lambda; &#923;
λ lambda klein &lambda; &#955;
Μ My groß &Mu; &#924;
μ my klein &mu; &#956;
Ν Ny groß &Nu; &#925;
ν ny klein &nu; &#957;
Ξ Xi groß &Xi; &#926;
ξ xi klein &xi; &#958;
Ο Omikron groß &Omicron; &#927;
ο omikron klein &omicron; &#959;
Π Pi groß &Pi; &#928;
π pi klein &pi; &#960;
Ρ Rho groß &Rho; &#929;
ρ rho klein &rho; &#961;
Σ Sigma groß &Sigma; &#931;
ς Schluss-Sigma &sigmaf; &#962;
σ sigma klein &sigma; &#963;
Τ Tau groß &Tau; &#932;
τ tau klein &tau; &#964;
Υ Ypsilon groß &Upsilon; &#933;
υ ypsilon klein &upsilon; &#965;
Φ Phi groß &Phi; &#934;
φ phi klein &phi; &#966;
Χ Chi groß &Chi; &#935;
χ chi klein &chi; &#967;
Ψ Psi groß &Psi; &#936;
ψ psi klein &psi; &#968;
Ω Omega groß &Omega; &#937;
ω omega klein &omega; &#969;
ϑ theta Symbol &thetasym; &#977;
ϒ ypsilon mit Haken &upsih; &#978;
ϖ pi Symbol &piv; &#982;
 

nach obennach unten

Benannte Zeichen für mathematische Symbole

Die HTML-Namen dieser Zeichen sind seit HTML 4.0 verfügbar.

Zeichen Beschreibung Name in HTML Unicode in HTML
für alle &forall; &#8704;
partiell &part; &#8706;
existiert &exist; &#8707;
leere Menge &empty; &#8709;
Nabla &nabla; &#8711;
Element von &isin; &#8712;
kein Element von &notin; &#8713;
Element von (gespiegelt) &ni; &#8715;
Produkt &prod; &#8719;
Summe &sum; &#8721;
minus &minus; &#8722;
Asterisk &lowast; &#8727;
Wurzel &radic; &#8730;
proportional zu &prop; &#8733;
unendlich &infin; &#8734;
Winkel &ang; &#8736;
und &and; &#8743;
oder &or; &#8744;
Schnittmenge &cap; &#8745;
Vereinigungsmenge &cup; &#8746;
Integral &int; &#8747;
deshalb &there4; &#8756;
ähnlich wie &sim; &#8764;
kongruent &cong; &#8773;
beinahe gleich &asymp; &#8776;
ungleich &ne; &#8800;
identisch mit &equiv; &#8801;
kleiner gleich &le; &#8804;
größer gleich &ge; &#8805;
Untermenge von &sub; &#8834;
Obermenge von &sup; &#8835;
keine Untermenge von &nsub; &#8836;
Untermenge von oder gleich mit &sube; &#8838;
Obermenge von oder gleich mit &supe; &#8839;
Restklassenaddition &oplus; &#8853;
Kronecker-Produkt &otimes; &#8855;
senkrecht zu &perp; &#8869;
Punkt-Operator &sdot; &#8901;
Raute &loz; &#9674;
 

nach obennach unten

Benannte Zeichen für technische Symbole

Die HTML-Namen dieser Zeichen sind seit HTML 4.0 verfügbar.

Zeichen Beschreibung Name in HTML Unicode in HTML
links oben &lceil; &#8968;
rechts oben &rceil; &#8969;
links unten &lfloor; &#8970;
rechts unten &rfloor; &#8971;
spitze Klammer links &lang; &#9001;
spitze Klammer rechts &rang; &#9002;
 

nach obennach unten

Benannte Zeichen für Pfeil-Symbole

Die HTML-Namen dieser Zeichen sind seit HTML 4.0 verfügbar.

Zeichen Beschreibung Name in HTML Unicode in HTML
Pfeil links &larr; &#8592;
Pfeil oben &uarr; &#8593;
Pfeil rechts &rarr; &#8594;
Pfeil unten &darr; &#8595;
Pfeil links/rechts &harr; &#8596;
Pfeil unten-Knick-links &crarr; &#8629;
Doppelpfeil links &lArr; &#8656;
Doppelpfeil oben &uArr; &#8657;
Doppelpfeil rechts &rArr; &#8658;
Doppelpfeil unten &dArr; &#8659;
Doppelpfeil links/rechts &hArr; &#8660;
 

nach obennach unten

Benannte Zeichen für diverse Symbole

Die HTML-Namen dieser Zeichen sind seit HTML 4.0 verfügbar.

Zeichen Beschreibung Name in HTML Unicode in HTML
Bullet-Zeichen &bull; &#8226;
Minutenzeichen &prime; &#8242;
Sekundenzeichen &Prime; &#8243;
Überstrich &oline; &#8254;
Bruchstrich &frasl; &#8260;
Weierstraß p &weierp; &#8472;
Zeichen für "imaginär" &image; &#8465;
Zeichen für "real" &real; &#8476;
Trademark-Zeichen &trade; &#8482;
Euro-Zeichen &euro; &#8364;
Alef-Symbol &alefsym; &#8501;
Pik-Zeichen &spades; &#9824;
Kreuz-Zeichen &clubs; &#9827;
Herz-Zeichen &hearts; &#9829;
Karo-Zeichen &diams; &#9830;
 

nach obennach unten

Benannte Zeichen lateinisch erweitert

Die HTML-Namen dieser Zeichen sind seit HTML 4.0 verfügbar.

Zeichen Beschreibung Name in HTML Unicode in HTML
Œ OE-Ligatur &OElig; &#338;
œ oe-Ligatur &oelig; &#339;
Š S mit Zirkumflex &Scaron; &#352;
š s mit Zirkumflex &scaron; &#353;
Ÿ Y Umlaut &Yuml; &#376;
ƒ Funktion &fnof; &#402;
 

nach obennach unten

Benannte Zeichen für Interpunktion

Die HTML-Namen dieser Zeichen sind seit HTML 4.0 verfügbar.

Zeichen Beschreibung Name in HTML Unicode in HTML
Leerzeichen Breite n &ensp; &#8194;
Leerzeichen Breite m &emsp; &#8195;
Schmales Leerzeichen &thinsp; &#8201;
null breiter Nichtverbinder &zwnj; &#8204;
null breiter Verbinder &zwj; &#8205;
links-nach-rechts-Zeichen &lrm; &#8206;
rechts-nach-links-Zeichen &rlm; &#8207;
Gedankenstrich Breite n &ndash; &#8211;
Gedankenstrich Breite m &mdash; &#8212;
einfaches Anführungszeichen links &lsquo; &#8216;
einfaches Anführungszeichen rechts &rsquo; &#8217;
einfaches low-9-Zeichen &sbquo; &#8218;
doppeltes Anführungszeichen links &ldquo; &#8220;
doppeltes Anführungszeichen rechts &rdquo; &#8221;
doppeltes low-9-Zeichen rechts &bdquo; &#8222;
Kreuz &dagger; &#8224;
Doppelkreuz &Dagger; &#8225;
Horizontale Ellipse (Auslassungszeichen) &hellip; &#8230;
Promille &permil; &#8240;
angewinkeltes einzelnes Anf.zeichen links &lsaquo; &#8249;
angewinkeltes einzelnes Anf.zeichen rechts &rsaquo; &#8250;
 

nach obennach unten

Benannte Zeichen für diakritische Zeichen

Die HTML-Namen dieser Zeichen sind seit HTML 4.0 verfügbar.

Zeichen Beschreibung Name in HTML Unicode in HTML
ˆ Zirkumflex &circ; &#710;
˜ kleine Tilde &tilde; &#732;
 
 nach oben
weiter Seite HTML-Varianten (Strict, Transitional, Frameset)
zurück Seite HTML-Attribut-Referenz
 

© 2005 Seite Impressum

pisa-3.0.32/test/test-blocks.html0000644000175000017500000000146311160170351014765 0ustar wmbwmb Test

Block 1
Neue Zeile

Und noch eine!

Block 2

DIV 1 BEGIN
INNERDIV A

INNERP

DIV 1 END
(NEW PAGE?) AFTERDIV

Heading 1(NEW PAGE?)

AFTERH1
Oben links Oben rechts
Unten links
xxx links yyy rechts
xxx links yyy rechts

ENDEpisa-3.0.32/test/test-helloworld.html0000644000175000017500000000142111160170351015655 0ustar wmbwmb HTML to PDF conversion example

Hello Wörld


Amount Description Total
1 Good weather 0 EUR
2 More sub 0 EUR
Sum 0 EUR
pisa-3.0.32/test/simple.py0000644000175000017500000000613411160170351013510 0ustar wmbwmb# -*- coding: ISO-8859-1 -*- ############################################# ## (C)opyright by Dirk Holtwick ## ## All rights reserved ## ############################################# __version__ = "$Revision: 194 $" __author__ = "$Author: holtwick $" __date__ = "$Date: 2008-04-18 18:59:53 +0200 (Fr, 18 Apr 2008) $" import os import sys import cgi import cStringIO import logging import ho.pisa as pisa # Shortcut for dumping all logs to the screen pisa.showLogging() def dumpErrors(pdf, showLog=True): #if showLog and pdf.log: # for mode, line, msg, code in pdf.log: # print "%s in line %d: %s" % (mode, line, msg) #if pdf.warn: # print "*** %d WARNINGS OCCURED" % pdf.warn if pdf.err: print "*** %d ERRORS OCCURED" % pdf.err def testSimple( data="""Hello World
""", dest="test.pdf"): """ Simple test showing how to create a PDF file from PML Source String. Also shows errors and tries to start the resulting PDF """ pdf = pisa.CreatePDF( cStringIO.StringIO(data), file(dest, "wb") ) if pdf.err: dumpErrors(pdf) else: pisa.startViewer(dest) def testCGI(data="Hello World"): """ This one shows, how to get the resulting PDF as a file object and then send it to STDOUT """ result = cStringIO.StringIO() pdf = pisa.CreatePDF( cStringIO.StringIO(data), result ) if pdf.err: print "Content-Type: text/plain" print dumpErrors(pdf) else: print "Content-Type: application/octet-stream" print sys.stdout.write(result.getvalue()) def testBackgroundAndImage( src="test-background.html", dest="test-background.pdf"): """ Simple test showing how to create a PDF file from PML Source String. Also shows errors and tries to start the resulting PDF """ pdf = pisa.CreatePDF( file(src, "r"), file(dest, "wb"), log_warn = 1, log_err = 1, path = os.path.join(os.getcwd(), src) ) dumpErrors(pdf) if not pdf.err: pisa.startViewer(dest) def testURL( url="http://www.htmltopdf.org", dest="test-website.pdf"): """ Loading from an URL. We open a file like object for the URL by using 'urllib'. If there have to be loaded more data from the web, the pisaLinkLoader helper is passed as 'link_callback'. The pisaLinkLoader creates temporary files for everything it loads, because the Reportlab Toolkit needs real filenames for images and stuff. Then we also pass the url as 'path' for relative path calculations. """ import urllib pdf = pisa.CreatePDF( urllib.urlopen(url), file(dest, "wb"), log_warn = 1, log_err = 1, path = url, link_callback = pisa.pisaLinkLoader(url).getFileName ) dumpErrors(pdf) if not pdf.err: pisa.startViewer(dest) if __name__=="__main__": testSimple() # testCGI() #testBackgroundAndImage() #testURL() pisa-3.0.32/test/pdf/0000755000175000017500000000000011201057433012413 5ustar wmbwmbpisa-3.0.32/test/pdf/background-sample.pdf0000644000175000017500000006220211160170350016504 0ustar wmbwmb%PDF-1.4 % 1 0 obj << /Length 2 0 R /Filter /FlateDecode >> stream x1 1ĕ\/W bkFI|T$ɜz?\'*81n_k3UXp*p\{4endstream endobj 2 0 obj 95 endobj 3 0 obj << /Type /XObject /Subtype /Image /Width 486 /Height 1846 /BitsPerComponent 8 /ColorSpace /DeviceRGB /Filter /DCTDecode /Length 22627 /Mask 4 0 R >> stream JFIFC    ' .)10.)-,3:J>36F7,-@WAFLNRSR2>ZaZP`JQROC&&O5-5OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO6" }!1AQa"q2#BR$3br %&'()*456789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz w!1AQaq"2B #3Rbr $4%&'()*56789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz ?( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( *;Y!rgzȥ 3S-QHaEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEP7Ŷ. @q؅# 'x2`\ύ%Iu=6otF O ֺ]6`  uR;pJQ1Ke ?~ע[peȮט lzLs;V 3vA՝ j`exp:dsZ5U{z)^/f (:Š((((((((((((((((((((((((((({UyxJ崌_u;713Hh ~ u< '06%R8?\^ ~ w5袊=`((((((((((((((((((((((((((e۟v i]M\򻫷uK7<͸ aUAUV^%d|"WgE *]5W5cWGoڰnFe0L&s8϶kX+;P@;1s-ѱEU~۷jsӏVKz%P)QEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQE|LAie`6y @=5ה*AFKdXTApGZW"\̫qҵ-VuZV< S{Mt6 N9~\0wEU\qVݨgC\vg4+o!y9<{`~uX6oџ BO?P+z!ZwVYS/g`+ ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( (#Q ,@IwP瑤`''~49]!s*^ՆS-zҴ"֕zQj3QmAXgs[C//ݨSOOMj[ĵx&YT Ѱ`LkVWPC)+ 2hht`t`Lt1[VWc,%i}u/QE{aEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEP6&OI?4Sjx*&)na (FG˶? πp+J|ձOsr׷5oұ;VqU*_#QJVNvn!Y-ٽW9j[gZ/m~]1\!O;!tһ2|Y.ndK+v$*BB:U؅zeEiZpz|5kֺ:RڴZh:V=T"F5#W žR:r8"eZɽRTM YFanoE6ݾbsԕWr8'9H+N*Gn'iF}QEEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEP^}6u͍b43/6^^Ar?0qִUsehX͈UȅVU5A5F\VQT"h+g6m{V=6p+JPv*(S\sۧ8ʚͺ\ZmTnGZ֓81J V,$&G#'򮂹1'ٵgݱU(GRte9vŠ(S ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( (!K;9 RF Ԁ2qWyeievwrYI'&OǷdE{XTSbG^[]Xu \HpM+N՝jZ9歿j҇f({WCJr:#W$=_TZjS Lor+Ӯ Մ3K2VM^ܻ&7==]5+8EWaEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEP|MߨlǕI=wc?Z⛏PfͲ?5F1^(1,%\qUcn:2cj[ Yuoڪ[J*ͷZ1WCJn:ګVJi'T梔eirk+řPhyz®˜*ڲ"9689.h<%?e^3Ɗ(,((((((((((((((((((((((?bno"i6q¬W3 ųweHmݟƜUD\lYT8%FOqf:',qpEh۞ZqDކV5J̅\w4u5qVU+.)*ZVELqKN9Wl3YkebfmyUcM?sqߺ᳞kjǖG{JQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQE_.wV61Dn]Ƕֽw7?kF.͛e19nkj*92,g P%N ̙5f3U#5` 3 "msҲbli[EI DY01R'g$rV /x׎JKYZeZ!-=e/=eĶ^i*`i%Ddɭ^-hk s.};Ji<ۻp31KߓԽ9CŠ(3 ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( (+Oٿȉۜn  z+#i#qv}?WVis-R&J5S]h{jB  U\ao#|-eկ2)w̩#ʒ9*^A{ƪHjR,:/J`Y}ͳDZguoiNjVJ ߘǾ@Oh.#-9-/Ԍ3(VW@A Zϫ ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( _3G%A2Sp$<(8$ \ċ#Cd2EsUy$EIrų8oj3wPn4()jLQ@L҃Q+O PnN世U@I]I}UWFrFINWIRU ]!0񎟦+N/]d]Z3Hk̯ZA=+#(((((((((((((((((((+>"ߛy,mA7H=zm5kϷw+4.~P~𭨭nsbehبM%qQH(((\pzebez^zRdezS+VJ'I[k[v|?\½&j9ъC)WN6\FIP:3rb㪑ߗGJ(D(((((((((((((((((((-<;}pEaThYU#^/^:fci>l&1{+knpey۰QEQEQEQEQEQEQEPժejOSTEj]ð]h1*F/o-v̈I=6c/ҦxWUyQ\QEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEyW+?Ϳg#s#v}? +ssGq(uBqUBXueGy* ( ( ( ( ( ( ( riMmxZ#n҈}?sXJkOA?>ӿ/S !i$e+=(((((((((((((((((((u/C5]ě<7$ɀOG탼S<ʑAEUQEQEQEQEQEQEQEPih'w}E χvhemLw[#4O+B((((((((((((((((((( Oixv(*ttieZQGa[u%EV8QEQEQEQEQEQEVƃratlI~s=Fq֯|>$Wmszcr=& +XbXaQ{Zum:)Pr[ Oq(x>SjW)ݰQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQExGKշ|2y嗡8^uxkTѲPoxdr{WQZFF~G^u} o@3(sf~ǨO3A&}1[*{Mlyx]o;*P6wc?*=V!~"F?#GSq{90(BE@V-| ϻ͎ mǛ(;sq99+ѭ~٦j˜mG\v{zV+MVo|e8*h#-Zd[~cq޽EMҌʯA3ַeU(((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((nn]E4zGl!?ƕ~Vh?)c 4]+_mi?? YBA?ZO,!?Ə'v_Er*ΕA;/KNt>Yv.T4 ?4 Y9r˱vJJ̃]U/}/VƗ_L_wIv.QT?9pbO[M_WM_wIv.QU?tZ?tZ9pbSSN_SN_G2[jiki4pb^+9wz* ?X{ ((((((((((((((((#Q: ,ԓN:ο˃;`b'=O\?RW.ݑmmK 6C=z>ހsHZxZxZnJ`ZpAO O HDb:p O @]:-<' ea8GVBSt>r#"?jpڋ#ա8GJsDt:#l>rGVt+U҈Ў#bʢ:QZӄt?hU҈Ў#bʢ:QZӄt52;%t`qЎ]I0c{W# ^?q?ƶSZsXnʊE`H*FA -z'QEQEQEQEQEQEQEQEQEQEQEQEQEQEQY~!#Ѵ֛(}x:͏8[1-c^Ox pAO/U% gs(Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@/A_+yH7|*,a^n+zg*1OONSF)Gx'F*D񤋎yTרכ|FU~|;\S0Ss*1O> stream xA0a\#pGQr.({q%HxMW cTX0 `0 `0 `0 `0 `0 `0 `0 `0 `0 `0 `0 `0 `0 `0 `0 `0 `0 `0 `0 `0 `0 `0 `S)nW>_T>INFsߚ;!*q:VKW/J.ݪmӥ[[tJ/?ķ}c—;N&w,M8Y:tMI|{Hx|HSN$vI<q{|yD,bĉXՎbsM;ljdqSo5xׅ,f5kroVn!,'N<,ԉp|{1c+{S%b1boa+{cO+s68uҙ×)Jg)Jg)JgS,T:k>C /!JW!!be   #+R%Ū>F1F1J1cǪ>bblH+[XHP7P7p+[I8)U pmUO4}_{UUؾXuK׆׾|o/ǯyn˜[NєK3pfV=OzGҼg}z2Lv#5e),Ygm0!X,p~/s5 ť\dpi4`pi`.n9 .pƧ$.Xl27DWO0bz߮Zk^| Ul{0X;롺t o{sXu+ 5] `{  :W8:TO :eW=(WEZq5e`𶸯F sXlM<Բŵ endstream endobj 5 0 obj 1358 endobj 7 0 obj << /Im3 3 0 R >> endobj 8 0 obj << /XObject 7 0 R /ProcSet [ /PDF /ImageC /ImageI ] >> endobj 9 0 obj << /Type /Page /Parent 6 0 R /Resources 8 0 R /MediaBox [ 0 0 595 842 ] /Contents 1 0 R >> endobj 6 0 obj << /Type /Pages /Resources 8 0 R /MediaBox [ 0 0 595 842 ] /Kids [ 9 0 R ] /Count 1 >> endobj 10 0 obj << /Type /Catalog /Pages 6 0 R >> endobj 11 0 obj << /Author /Creator /Producer /CreationDate (D:20050825184240+02'00') >> endobj xref 0 12 0000000000 65535 f 0000000017 00000 n 0000000197 00000 n 0000000222 00000 n 0000023072 00000 n 0000024652 00000 n 0000024930 00000 n 0000024677 00000 n 0000024718 00000 n 0000024802 00000 n 0000025066 00000 n 0000025126 00000 n trailer << /Size 12 /Root 10 0 R /Info 11 0 R >> startxref 25393 %%EOF pisa-3.0.32/test/pdf/test-invoice-bg.pdf0000644000175000017500000002325211160170350016107 0ustar wmbwmb%PDF-1.4 % 6 0 obj <> endobj xref 6 13 0000000016 00000 n 0000000717 00000 n 0000000793 00000 n 0000000925 00000 n 0000001033 00000 n 0000001067 00000 n 0000001513 00000 n 0000001673 00000 n 0000004342 00000 n 0000004856 00000 n 0000005055 00000 n 0000005113 00000 n 0000000556 00000 n trailer <]>> startxref 0 %%EOF 18 0 obj<>stream xb``b```AT,  lHb\Pæ8R-0#f fe`Pɂ30; endstream endobj 7 0 obj<> endobj 8 0 obj<> endobj 9 0 obj<>/Font<>/ProcSet[/PDF/Text]/ExtGState<>>> endobj 10 0 obj[/ICCBased 13 0 R] endobj 11 0 obj<>stream HlRMK0S~wr (h{RtuqITB&|KTO8|~? x:8 ztЍ OQ6>Fau@AT!8y0A" ^xLA{HVKT&R`u)Dbz].A;đ#']7@y5 ckN MH"'(%؊F&FZʈAh@bhBS~Ekv$yPڣSAOv$Ⲋ3KLפ9ړF׊!)bfS` LqnrG YĺL.$rՊ&}gᢖyN lmvǑ=}5!v<$.Vv#[(~? endstream endobj 12 0 obj<> endobj 13 0 obj<>stream HyTSwoɞc [5laQIBHADED2mtFOE.c}08׎8GNg9w߽'0 ֠Jb  2y.-;!KZ ^i"L0- @8(r;q7Ly&Qq4j|9 V)gB0iW8#8wթ8_٥ʨQQj@&A)/g>'Kt;\ ӥ$պFZUn(4T%)뫔0C&Zi8bxEB;Pӓ̹A om?W= x-[0}y)7ta>jT7@tܛ`q2ʀ&6ZLĄ?_yxg)˔zçLU*uSkSeO4?׸c. R ߁-25 S>ӣVd`rn~Y&+`;A4 A9=-tl`;~p Gp| [`L`< "A YA+Cb(R,*T2B- ꇆnQt}MA0alSx k&^>0|>_',G!"F$H:R!zFQd?r 9\A&G rQ hE]a4zBgE#H *B=0HIpp0MxJ$D1D, VĭKĻYdE"EI2EBGt4MzNr!YK ?%_&#(0J:EAiQ(()ӔWT6U@P+!~mD eԴ!hӦh/']B/ҏӿ?a0nhF!X8܌kc&5S6lIa2cKMA!E#ƒdV(kel }}Cq9 N')].uJr  wG xR^[oƜchg`>b$*~ :Eb~,m,-ݖ,Y¬*6X[ݱF=3뭷Y~dó ti zf6~`{v.Ng#{}}jc1X6fm;'_9 r:8q:˜O:ϸ8uJqnv=MmR 4 n3ܣkGݯz=[==<=GTB(/S,]6*-W:#7*e^YDY}UjAyT`#D="b{ų+ʯ:!kJ4Gmt}uC%K7YVfFY .=b?SƕƩȺy چ k5%4m7lqlioZlG+Zz͹mzy]?uuw|"űNwW&e֥ﺱ*|j5kyݭǯg^ykEklD_p߶7Dmo꿻1ml{Mś nLl<9O[$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 endstream endobj 14 0 obj<>stream EAGPFB+Arial-BoldItalicMT ~lQg1g2g3Arial-BoldItalicMT3Khh '*`%^flm|Оȱ¯ѝpTUC3HP~pXWp`fi]i]rTzL~\^a]^^Nθŭ{kk^SXWsVsVmcfpqge~cZdmm|ۢո1MusnijkkVcop}ɖĢvwlc{jYYH89Cv`MNa\Oj>oK}HF"> endobj 16 0 obj<> endobj 17 0 obj<> endobj 1 0 obj<> endobj 2 0 obj<> endobj 3 0 obj<> endobj 4 0 obj<>stream Acrobat Distiller 7.0.5 (Windows) 2008-04-19T14:28:19+02:00 2008-04-19T14:28:19+02:00 2008-04-19T14:27:54+01:00 PScript5.dll Version 5.2.2 uuid:423E97B50B0EDD119FE6EBA055536CAB uuid:1a0ef036-b8fe-44de-a3ce-ed2f07604deb uuid:c1632a51-681a-4087-bc2b-276f55b2e2cc uuid:843540af-a4a1-4aca-91a3-bd63f9c1b05f application/postscript Korrespondenz test-invoice-bg.pdf holtwick endstream endobj 5 0 obj<> endobj xref 0 6 0000000000 65535 f 0000005189 00000 n 0000005222 00000 n 0000005245 00000 n 0000005295 00000 n 0000009483 00000 n trailer <> startxref 116 %%EOF pisa-3.0.32/test/test-margins.html0000644000175000017500000000072111160170351015144 0ustar wmbwmb MARGINS

Heading 1

Para 1

Para 2

Heading 1

Para 1

Para 2 pisa-3.0.32/test/unicode.css0000644000175000017500000000015511160170351014002 0ustar wmbwmb@font-face { font-family: "code2000"; src: url("font/code2000.ttf") } html { font-family: code2000; } pisa-3.0.32/test/test-loremipsum.html0000644000175000017500000006026011160170351015704 0ustar wmbwmb Lorem ipsum - TEST

Ausreier

CSS Testsuite

Lorem ipsum sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu

INDENT? Lorem ipsum sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum. H2O -> x2 Das ist weg und das ist neu!

Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.

<h1>Pre + code test</h1>
<hr>

nochmal:

1: Eins
   2: Zwei

Lorem ipsum dolor sit amet, consectetur adipisicing elit.

DADO App Server

Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.

Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.

Und noch mehr Zitate

Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.

Und noch mehr Zitate

DADO App ServerLorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.

DADO App ServerLorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.

Lorem Ipsum 1

Lorem Ipsum 2

Lorem Ipsum 3

Lorem Ipsum 4

Lorem Ipsum 5
Lorem Ipsum 6

Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.

Doppelte Einrckung
Und raus

Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.

Header Header Header Header
DataData Data DataData
Data DataDataDataData
Data Data
Header Header Header Header
DataData Data DataData
Data DataDataDataData on Page
Data Data
     
     
     
Header Header Header Header
DataData Data DataData
Data DataDataDataData
Data Data
     
     
     
Header Header Header Header
DataData Data DataData
Data DataDataDataData
Data Data
     
     
     
  • Lorem Ipsum
  • Dolor sit amet
    • Lorem Ipsum
    • Dolor sit amet
    • Consectetur adipisicing
  • Consectetur adipisicing

Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.

Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.

Überschrift1

Überschrift2

Überschrift3

Überschrift4

Überschrift5
Überschrift6

Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Fusce bibendum nisl pharetra ipsum. Curabitur ac diam. Aliquam vel lorem. Cras diam. Nunc placerat. Morbi ac metus eget sapien varius consectetuer. Aliquam sagittis luctus nunc.

Nullam ante nulla, mattis ac, imperdiet nec, cursus nec, urna. Nulla euismod, sem nec sagittis bibendum, nisl neque bibendum urna, non ultrices felis dui quis justo. Ut in diam vel urna vulputate tempor. Cras vehicula lectus quis nibh. Vestibulum dignissim tincidunt eros. Mauris eros diam, sagittis nec, tempus eget, iaculis sed, purus.

Überschrift1

Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Fusce bibendum nisl pharetra ipsum. Curabitur ac diam. Aliquam vel lorem. Cras diam. Nunc placerat. Morbi ac metus eget sapien varius consectetuer. Aliquam sagittis luctus nunc. Nullam ante nulla, mattis ac, imperdiet nec, cursus nec, urna. Nulla euismod, sem nec sagittis bibendum, nisl neque bibendum urna, non ultrices felis dui quis justo. Ut in diam vel urna vulputate tempor. Cras vehicula lectus quis nibh. Vestibulum dignissim tincidunt eros. Mauris eros diam, sagittis nec, tempus eget, iaculis sed, purus.

Überschrift2

Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Fusce bibendum nisl pharetra ipsum. Curabitur ac diam. Aliquam vel lorem. Cras diam. Nunc placerat. Morbi ac metus eget sapien varius consectetuer. Aliquam sagittis luctus nunc. Nullam ante nulla, mattis ac, imperdiet nec, cursus nec, urna. Nulla euismod, sem nec sagittis bibendum, nisl neque bibendum urna, non ultrices felis dui quis justo. Ut in diam vel urna vulputate tempor. Cras vehicula lectus quis nibh. Vestibulum dignissim tincidunt eros. Mauris eros diam, sagittis nec, tempus eget, iaculis sed, purus.


Etiam vitae massa sed velit vestibulum euismod. Maecenas condimentum, felis et semper ornare, ipsum turpis ultrices pede, eget vulputate nisl lectus at turpis. Integer vitae justo. Pellentesque ultrices, felis non dictum dictum, sagittis luctus nunc lacus est dapibus magna, in elementum justo risus vel odio. sagittis luctus nunc Etiam volutpat tincidunt augue. Nam nec ligula. Fusce eget eros. Sed blandit. In vel magna. Nullam luctus malesuada dui. Praesent ultricies urna. Phasellus nulla. Donec iaculis venenatis metus. Proin non leo vel arcu scelerisque malesuada. Sed rhoncus odio non ligula. Ut pharetra cursus massa. Nunc nibh sem, pulvinar eget, faucibus ac, posuere quis, nibh. Mauris nisi metus, facilisis at, ornare sed, semper nec, tortor. Integer nec mauris id tellus mollis pellentesque.

  1. erster Punkt
  2. zweiter Punkt
  3. dritter Punkt
Text im Div
  • erster Punkt
  • zweiter Punkt
  • dritter Punkt

Das ist ein Testtext für strong Tags und underline Tags und kursive Schrift und ..

Hier ist ein Blockquote. Hier ist ein Blockquote. Hier ist ein Blockquote. Hier ist ein Blockquote. Hier ist ein Blockquote. Hier ist ein Blockquote. Hier ist ein Blockquote. Hier ist ein Blockquote. Hier ist ein Blockquote. Hier ist ein Blockquote.

Donec est ipsum, rhoncus nec, rhoncus at, posuere vitae, odio. Donec venenatis suscipit turpis. Aliquam viverra lorem nec pede. Quisque pellentesque. Phasellus nec ante. Donec a arcu. Proin feugiat odio lacinia velit. Nullam sagittis luctus nunc vitae nulla in risus dapibus imperdiet. Aliquam iaculis nonummy dolor. Sed in nisl sit amet sapien tristique malesuada. Pellentesque habitant morbi sagittis luctus nunc tristique senectus et netus et malesuada fames ac turpis egestas. Morbi vulputate purus ut enim. Quisque rhoncus, metus a molestie aliquet, ipsum est ullamcorper erat, at elementum velit velit in nisi. Nulla risus orci, consectetuer id, adipiscing id, semper adipiscing, tortor. Aliquam ullamcorper.  

Kopfzelle Kopfzelle Kopfzelle
Datenzelle

Datenzelle

Donec est ipsum, rhoncus nec, rhoncus at, posuere vitae Donec est ipsum, rhoncus nec, rhoncus at, posuere Donec est ipsum, rhoncus nec, rhoncus at, posuere,

Datenzelle
Datenzelle
HeaderHeader Header Header
Data Data
Data

Data

Data

Data Data Data
Datenzelle
Datenzelle Datenzelle Datenzelle
Datenzelle Datenzelle Datenzelle
Datenzelle Datenzelle Datenzelle

Donec est ipsum, rhoncus nec, rhoncus at, posuere vitae, odio. Donec venenatis suscipit turpis. Aliquam viverra lorem nec pede. Quisque pellentesque. Phasellus nec ante. Donec a arcu. Proin feugiat odio lacinia velit. Nullam sagittis luctus nunc vitae nulla in risus dapibus imperdiet. Aliquam iaculis nonummy dolor. Sed in nisl sit amet sapien tristique malesuada. Pellentesque habitant morbi sagittis luctus nunc tristique senectus et netus et malesuada fames ac turpis egestas. Morbi vulputate purus ut enim. Quisque rhoncus, metus a molestie aliquet, ipsum est ullamcorper erat, at elementum velit velit in nisi. Nulla risus orci, consectetuer id, adipiscing id, semper adipiscing, tortor. Aliquam ullamcorper.

Donec est ipsum, rhoncus nec, rhoncus at, posuere vitae, odio. Donec venenatis suscipit turpis. Aliquam viverra lorem nec pede. Quisque pellentesque. Phasellus nec ante. Donec a arcu. Proin feugiat odio lacinia velit. Nullam sagittis luctus nunc vitae nulla in risus dapibus imperdiet. Aliquam iaculis nonummy dolor. Sed in nisl sit amet sapien tristique malesuada. Pellentesque habitant morbi sagittis luctus nunc tristique senectus et netus et malesuada fames ac turpis egestas. Morbi vulputate purus ut enim. Quisque rhoncus, metus a molestie aliquet, ipsum est ullamcorper erat, at elementum velit velit in nisi. Nulla risus orci, consectetuer id, adipiscing id, semper adipiscing, tortor. Aliquam ullamcorper.

Donec est ipsum, rhoncus nec, rhoncus at, posuere vitae, odio. Donec venenatis suscipit turpis. Aliquam viverra lorem nec pede. Quisque pellentesque. Phasellus nec ante. Donec a arcu. Proin feugiat odio lacinia velit. Nullam sagittis luctus nunc vitae nulla in risus dapibus imperdiet. Aliquam iaculis nonummy dolor. Sed in nisl sit amet sapien tristique malesuada. Pellentesque habitant morbi sagittis luctus nunc tristique senectus et netus et malesuada fames ac turpis egestas. Morbi vulputate purus ut enim. Quisque rhoncus, metus a molestie aliquet, ipsum est ullamcorper erat, at elementum velit velit in nisi. Nulla risus orci, consectetuer id, adipiscing id, semper adipiscing, tortor. Aliquam ullamcorper.

Formular:


Zweite Zeile

Mastercard
Visa
American Express

Salami
Pilze
Sardellen

Fieldset mit Legend


Hobbies

Hobbies

Geschlecht

Geschlecht

IFrame

pisa-3.0.32/test/test-error.html0000644000175000017500000000016011160170351014632 0ustar wmbwmb

Image

Deprecation

Bidi

A sentence.pisa-3.0.32/test/._test-font-img-error.html0000644000175000017500000000027311163674033016603 0ustar wmbwmbMac OS X  2ATTRE##com.macromates.caret{ column = 15; line = 22; }pisa-3.0.32/test/test-unicode-japanese.html0000644000175000017500000002676011160170351016731 0ustar wmbwmb Konnichiwa Around the World

こんにちは (万国X参加の言Xから)


英語 ◈ Good afternoon グダフタヌーン
---- ◈ Good morning グッモーニンゲ (おはよう)
フランス語 ◈ Bonjour ボンジュール
中国語 ◈ 您好啊 ニンハォア
ロシア語 ◈ Здравствуйте! ズラーストウィチェ
ドイツ語 ◈ Guten Tag グーテン ターク
------- ◈ Guten Morgen グーテン モルゲン (おはよう)
スペイン語 ◈ Buenos días ブエノス ディアス
--------- ◈ Buenas tardes ブエナス タルデス
イタリア語 ◈ Buon giorno ブオン ジョルノ
ポルトガル語 ◈ Bom dia ボン ディア ◈ Boa tarde ボア タルデ
ギリシャ語 ◈ Xairete ヒエレテ
オランダ語 ◈ Goeden middag フーデン ミッダハ
---------- ◈ Goeden morgen フーデン モルヘン (おはよう)
スワェーデン語 ノルウェー語 ◈ God dag ゴッダーグ
デンマーク語 ◈ God dag ゴッダー
アイスランド語 ◈ Godan daginn ゴダン ダギン
フィンランド語 ◈ Hyvää Päivää ヒュヴェーペイヴェー
チェコ語 ◈ Dobrý den ドブリー デン
ブルガリア語 ◈ Dobar den ドーバル デン
アラビア語 ◈ سالم عليكم サラーム アレークム
トルコ語 ◈ Günaydin [* Günaydın] ギュンアイディン
ペルシャ語 (イラン) ◈ Rouz bekhayr ルーズベケイル
朝鮮語 ◈ 안녕하십니까 アンニョンハシムニカ
ヒンディー語 ◈ Namaskar ナマスカル
タイ語 ◈ Sawasdi サワスディー
ビルマ語 ◈ Ne kong ye la ネ コン イェ ラ
カンボジア語 ◈ Chom reap sour チョム ラプスーア
シンハリ語 (セイロン) ◈ Ayubowan アユボーワン
マレー語 (マレーシア インドネシア) ◈ Selamat siang スラマット シアン
タガログ語 (フィリピン) ◈ Magandang hapon マガンダン ハポン
ベトナム語 ◈ Chào チャオ
スワヒリ語 ◈ Habari ya mchana ? ハバリ ヤ ムチャーナ
アムハラ語 (エチオピア) ◈ Endeminwalu インダメンワルー
エスペラント語 (国際語) ◈ Bonan tagon ボーナン ターゴン

(参加国のおもな言Xを拾った。 カタカ
ナの発音は似た音をつけたもの。 カッ
コ内の国名は、その言Xを使うおもな
国。 中国語、ロシア語、アラビア語、 朝
鮮語はそれぞれの文字を使った)


[* The source apparently didn't have U+0131 dotless i available.]
Note how the first line of the paragraph at the end of the chart is broken: “カタカ” at the end of the first line, and “ナ” on the beginning of the next line. This is the way the lines broke in the original newspaper column, so it must be OK.

The information on this page comes from:


毎日新聞 - 昭和 45年 (1970年) 3月 14日 (土曜日)
This was on two pages of a newspaper which I found blowing down a street in San Diego, probably in 1970.

The letter “X” represents kanji which I couldn't find on the Unicode charts. (This doesn't mean codepoints don't exist for those characters, it just means I didn't find them.) Also, the newspaper is old, tattered, and faded; so some of the characters are indecipherable.

Many thanks to Philip Newton, who figured out the newspaper's name and also called my attention to numerous typographic errors on this page.


Some additions to the list (from various places):

(Abenaki) アベナキ語 ◈ kuai (hello)
(Albanian) アルバニア語 ◈ mirëdita / mirë mëngjes
(Armenian) アルメニア語 ◈ պարեվ (?)
(Aymará) アイマラ語 ◈ chai
(Azerbaijani) アゼリ語(?) ◈ салам ◈ сабаhыныз хејир (おはよう)
(Braille English) 英語(てんじ) ◈ ⠓⠑⠇⠇⠕
(Bulgarian) ブルガリア語 ◈ добро утро ◈ добар ден (おはよう)
(Cherokee) チェロキー語 (ツァラギ語) ◈ ᎣᏏᏲ オスィヨ
(Deseret) 英語(デサレト文) ◈  
(Dyola) デョラ語 ◈ sāf i
(Galla) ガラ語 ◈ nagumbulte
(Georgian) ジョルジア語 ◈ გამარძობატ (?)
(Greek) ギリシャ語 ◈ καλό μεσημέρι ◈ καλημέρα (おはよう)
(Hawaiian) ハワイ語 ◈ aloha kakahiaka
(Hebrew) イスラエル語 ◈ ב׀ט ם׀ב ◈ ב׀ט רקב (おはよう)
(Icelandic) アイスランド語 ◈ góðan daginn
(Javanese) ジァワ語 ◈ nuwun (おはよう)
(Kisanga) キサンガ語 ◈ hayambo (おはよう)
(Laotian) ラオ語 ◈ ສບາຍດີ (?) (sa³ bay¹ di)
(Malayalam) マレアラム語 (?) ◈ നമസ്കാരം (?)
(Mandinka) マンディンカ語 ◈ i saama (おはよう)
----------------------- ◈ i tiinaŋ
(Maori) マオリ語 ◈ kia ora
(Pangasinan) パンガシナン語 ◈ masantós a kabuasán
(Punjabi) プンザビ語 ◈ ਸਤਿ ਸ੍ਰੀ ਅਕਾਲ
(Shona) ショナ語 ◈ Mangwanani (おはよう)
(Tamil) タミル語 ◈ வாங்க !
(Tarahumara) タラフマラ語 ◈ diosi kuira
(Tengwar Sindarin) テングヮール スィンダリン語 ◈  (?)
(Thai) タイ語 ◈ สวัสดี !
(Ukrainian) ウクライナ語 ◈ добрий день ◈ добрий ранок (おはよう)
(Yorùbá) ヨルパ語 ◈ Ku aro̩ (to peer) E̩ ku aro̩ (to elder) (おはよう)
------------------ ◈ Ku o̩san (to peer) E̩ ku o̩san (to elder)


Note: The names of some of the languages in Japanese in this addendum are guesses.

My home page
pisa-3.0.32/test/test-unicode-thaana.html0000644000175000017500000000366311160170351016374 0ustar wmbwmb Thaana Unicode Support Test and Resource Links

މަހަށް  ގޮސް  އުޅޭއިރު  އެންމެ  އުނދަގޫ  ކަމަކަށް
ދިމާވަނީ ކޮން  ކަމެއް؟  މަހަށް  ގޮސް  އުޅޭ  އިރު  އެންމެ އުނދަގޫ
ކަމަކަށް  އަޅުގަނޑުމެންނަށް  ވަނީ  އެން  ދަތި  އިރުގައި  އެން
ނިހިފިގެން  އެ  އުޅޭ.  އެން  ހިފަން  އުޅެނީ  ކިހިނެއް؟



Translation:
Cuando vas a pescar ¿qué es lo peor que nos pasa ? Cuando vamos a pescar lo peor es cuando los cebos son escasos y no tenemos cebos. ¿Cómo haces para coger cebos ?

The sample Thaana text on this page is from The World's Writing Systems by Daniels and Bright. The Spanish translation is borrowed from a web site which used the same sample text but failed to cite its source.

Thaana is a right-to-left script.

In order to make the spaces between the words a bit larger, I used two spaces between each word.

For more information about the Thaana script and the history and culture of the Maldives, please visit:
http://www.haveeru.com.mv/
http://www.maldivesculture.com/main.html



Maldivian Internet Task Force
http://www.mitf.net
Links to Thaana and Thaana/Unicode material, including free Thaana Unicode fonts, text editors, Unicode sample documents, and more.


My home page pisa-3.0.32/test/cookbook.py0000644000175000017500000000330411160170351014021 0ustar wmbwmb# -*- coding: ISO-8859-1 -*- ############################################# ## (C)opyright by Dirk Holtwick ## ## All rights reserved ## ############################################# __version__ = "$Revision: 176 $" __author__ = "$Author: holtwick $" __date__ = "$Date: 2008-03-15 00:11:47 +0100 (Sa, 15 Mrz 2008) $" """ HTML/CSS to PDF converter Most people know how to write a page with HTML and CSS. Why not using these skills to dynamically generate PDF documents using it? The "pisa" project http://www.htmltopdf.org enables you to to this quite simple. """ import cStringIO import ho.pisa as pisa import os # Shortcut for dumping all logs to the screen pisa.showLogging() def HTML2PDF(data, filename, open=False): """ Simple test showing how to create a PDF file from PML Source String. Also shows errors and tries to start the resulting PDF """ pdf = pisa.CreatePDF( cStringIO.StringIO(data), file(filename, "wb")) if open and (not pdf.err): pisa.startViewer(filename) return not pdf.err if __name__=="__main__": HTMLTEST = """

Hello World


Amount Description Total
1 Good weather 0 EUR
Sum 0 EUR
""" HTML2PDF(HTMLTEST, "test.pdf", open=True) pisa-3.0.32/test/default.css0000644000175000017500000000431211160170351013777 0ustar wmbwmb html { font-family: Helvetica; font-size: 10px; font-weight: normal; color: #000000; background-color: transparent; margin: 0; padding: 0; line-height: 150%; border: 1px none; display: inline; width: auto; height: auto; white-space: normal; } b, strong { font-weight: bold; } i, em { font-style: italic; } u { text-decoration: underline; } s, strike { text-decoration: line-through; } a { text-decoration: underline; color: blue; } ins { color: green; text-decoration: underline; } del { color: red; text-decoration: line-through; } pre, code, kbd, samp, tt { font-family: "Courier New"; } h1, h2, h3, h4, h5, h6 { font-weight:bold; -pdf-outline: true; -pdf-outline-open: false; } h1 { /*18px via YUI Fonts CSS foundation*/ font-size:138.5%; -pdf-outline-level: 0; } h2 { /*16px via YUI Fonts CSS foundation*/ font-size:123.1%; -pdf-outline-level: 1; } h3 { /*14px via YUI Fonts CSS foundation*/ font-size:108%; -pdf-outline-level: 2; } h4 { -pdf-outline-level: 3; } h5 { -pdf-outline-level: 4; } h6 { -pdf-outline-level: 5; } h1, h2, h3, h4, h5, h6, p, pre, hr { margin:1em 0; } address, blockquote, body, center, dl, dir, div, fieldset, form, h1, h2, h3, h4, h5, h6, hr, isindex, menu, noframes, noscript, ol, p, pre, table, th, tr, td, ul, li, dd, dt, pdftoc { display: block; } table { -pdf-keep-in-frame-mode: shrink; } tr, th, td { vertical-align: middle; width: auto; } th { text-align: center; font-weight: bold; } center { text-align: center; } big { font-size: 125%; } small { font-size: 75%; } ul { margin-left: 1.5em; list-style-type: disc; } ul ul { list-style-type: circle; } ul ul ul { list-style-type: square; } ol { list-style-type: decimal; margin-left: 1.5em; } pre { white-space: pre; } blockquote { margin-left: 1.5em; margin-right: 1.5em; } pisa-3.0.32/test/test-background-img.html0000644000175000017500000000160111160170351016373 0ustar wmbwmb Background

Hello World

Hello World

Hello World

pisa-3.0.32/test/img/0000755000175000017500000000000011201057433012416 5ustar wmbwmbpisa-3.0.32/test/img/beach.jpg0000644000175000017500000050010111160170350014155 0ustar wmbwmbJFIFHHPhotoshop 3.08BIMxHH(FG(HH(d'h8BIMHH8BIM8BIM 8BIM' 8BIMH/fflff/ff2Z5-8BIMp8BIM@@8BIM'File written by Adobe Photoshop 4.0Adobed@hD     u!"1A2# QBa$3Rqb%C&4r 5'S6DTsEF7Gc(UVWdte)8fu*9:HIJXYZghijvwxyzm!1"AQ2aqB#Rb3 $Cr4%ScD&5T6Ed' sFtUeuV7)(GWf8vgwHXhx9IYiy*:JZjz ?EiBبTA*Bk}?EM(i:呜jI?gUU quiV?nϪj }z םbٸ\ /Iu#%nOP/`,/k?OHgVQ뿶R q_Jy3O5 0+v :G?,BT:^"?eׄ#M@7}߼0Fwur(?_Z{_H_݂h#ép,m~Xln,Ƿ⍑O]'Uu:6bldu K*8[2Fŀ(#}"C"*륇AcքS|ЍWU\"qou(+Z:iWX p-kZlǎӂ\^7nC,QϽյЫpGbIm{!?R [S54׫m^Hc7#?x֊P蒸4?uɨ,,[{ZԊJҶ7ukܩ8\zh+OyQ?Վc+v#Xa{opʪ{B*i\Wc늨# K(,nx[ajX~αX9bC Qib?_^}q_GP\+RT Q$) x _/*_Y4]'~Iĵ>fky@`9!EĨ-#ݔqdМwpʋoǨ[ Ȱ$ϷN* }zmxHE$X㛟nkp/M1띬Gӛ?[>p8^$Ǭ{Uk۠Vg+P?$ so}/P6?{ ˪W=k[ [c΢[۠b5SV\'{*-oϻHM#C/㏨REP?piê/,o Zwk_^ XHn/#ݾT굠2'~ A_wt`:c:Ϩ-ao{ǪWC{ݩzaLuX7?KֵӦMOY49o>N=SU3V6ZX~^Z?uJ༖>[+r 6^9߸}V㎹K{]h8>H{ꤎ m`4zNW"jU7y6wS <ÈN>L B4i6FfFY$UT?#[k06~ӣbrJa|@OʀpE$FQ q{[MզqWk3 9SoWsVFbPGzj$赁$ݮ.n?>뢵%sĔ_]p1(!T-- md\ H97k~O4NsյSW \YyOtd)cW5u  !cZOŽ@$W䎱ЧʕNk#Π~}rзbnX:p?ְy p=:! M6Ll,/aݧ/xZWb>u\mǻGT$-k}HU X @$nADϬj&͈O ~=+R}6xR(\ sO9AYā{_sɥsNj}g _}G~4Aæ@OYVʎtkG6 ~}3xWTm[}mLOY&q`y{s|hTtߍvs~@?P9wTՎN*iO. }.&MpIoL/g`ֹ-?AaCzeu?]7$jxq$$hs ar{M:54gk[H=5ݏJ̪lPSWQ5k-n&t~y8[X~:hdQ~yo-ǽӪ\Oo^ߩzo_~{:z Z~^=z}Q{?z+׫O>h?[pI{Ӟ)͏܀9>J u)S"l>OOUZu֋,no<~#~ uT JNm{jKZ:m>OuѠv PַA\ ?RMԒ=F|럈Žn ZnyvGd#_=Iɮ:- ?^JzEN65w Q m> qϯ]4|MFk^Z~)Z0@#@ _~Uc3\_恁Dʤ:Sb@kihFsuءIz6`mb@&}@+ /u):UX6SMGQ$vX[ۿGt[-զ>8,(?z3!$g wb@%U7z.`W?I䭵7H?}HH?:@zn~tT`> ^=b-\ۛZN _uĤ܋MHGW p?gW|zib@m$ ?V#Q=x1ZPuaakqΕQrtzQEouR}CRzx14?u{ߟ͚Ït(|sW vkrl-?Od8CQ [ReM$+յh?zF9qEm\{S] urš_'?SZoƜ?ܒT^_@<ƞOsqOm\(A?2 ll ہph|hH"Ņɸi?"=Tce@,~@sa}_폷@>/M5'_YV56 31e#@Ǚ:9sUđ#܏aӟnҘӃzhӬr!EZ3N\NZ귷8N}4nM\ b6NGU '񺏨1Lt٦j)5Rmq~A-nZ4?P6?[<}ӏn(?EM0/rlA~-`G$aƽTөl};ԯ]?^ , ǧI8'_vU$g=fդiI¦f+oozWN46pnI>>JcϦW#Y͏ v?.c\W.~G<}}t95M% I?퇻uWIr8Ӫr 8؃9 QpO"X~yꤚh??{up밶/x?:j\۞~_ߩkLE p/{8]\3a?<\88݇/U9\qO{_߀Z՟^ qkֱ$~=:֬H_mo{Z׌bŚ\{3=r_I[ߴU ~ϺӏWՊX[W_uюo_|ҡUIZN9N"\"*or`4+LEz~I<ߏk{M)pI?GhZǗ]_$rG!E:?a}:qAf3q7?nm`~0m9Z{Eup^n?$}. 'S˭I돊pAj>5o_?k5OZO~CO>Pk<ʚO'5Ez2Q=QT#t d3,9QfE:+h.8^Zzh#,CHXCxC4!:vM gf'Q-c~m6C'bjNzZW+pH'i?Ac{FI8t (+HiG#XWjyGЕ ck>ֆ:sW\Ymdn{kX /VSZׂ-_PaBO:~}BZuJioȾOlqOˬXmn%Aç*k_`h8kskZX}{CONWϬL[,5[Tx#g q\ V3},r?7?@:X]OR}觠4ζOuǦְ p5_BBϫkkDIߒ@$65H?ZD"GB7E35{ I &ߴQu@/]h 9{֐c?V:ުN:J]HGW\>8 8Vz7oˮ+a} &܏X7R۟uxSsąZO5>\i\%Ò?ޑZpVֹ U$q$Rf),47~{ WO3 ~=:#?Li1YҢE,/cVX"<mߟS _{ I| $f6$^-bHPWX뚐SkO'6a@hG p7pԱ4Iz[8}$g6M:,ydkJ|染o$ÏwTo!eB qosoc6XZskPXԡMp:ˤ,nn-~9p.$-[,ƑqOzը~޳#X<\MqdRp-6?tp8)$?G`=eU}+uB Ooܟt) |'/r[[vU':?O~}P~}r ȱ?ǻ։z?6MOZ-[~o{ϭj-/?[uu)Ca`O֋ anG_vVx_o_ϿSW:q 8Cֵu?Q͈=kV~}rs͹$X=jz@"7?j{oͿ<)p }[{PqZpzӢ_ ?\qp \o}EN:㷈8'-^6oMzx}^ .-o߁݀֌^1^M-p&n8ߴ'Q}=I4~ <Ͻae<@i6"?o^^X \ُ)=h"gFP iMߍŸMԴ=Hr HiLК^:\/`mq[{G"j#Gki >_ҕVb+ V$up`gz}!J!aJcIoˮ~XO3u##}oWX1ZąGOA9z~y ok[H7R/[`\ r_vZq:C}9 t{~`UG^ *(zuIbx"H 8޼Wu# }.K?e:eM6&n8c}c6H:?~K{ӐFs~޼\uI[yR~@v4 U?뚀yO,4wUΙWT_k7 P_'"U/\fUGIh\q@dA0[Z?R ۀ8lWj.9^mkR]T9뚢'UpO$_֙ꅍ~]eZ@^/~+=s]F߫I$h+ì\\ \؛{5:44'}/"⃬ȱGsk~}CQE_J!I?O ŏo=6XS:ߏ'3,:?R9ԏ݀ziӬʢ^ߛ{6'=eE< ovM5 N/7M6?vBxa|}O?OvRs nlH{wk\-В.8tUO\G X|ו:l/?ӛ<{ޞZ}wOp9{:s+qЎ}- }k6Qoz#րEO x~#Wӏ]i\-p ?o[ >P+^=zzԣcr}La둊܀o~W~_ݴ_w[p{׼SB+m s{7ԁ6<|z#&?ȷӨr{ޟ0:#z4To{1^'}HGǻ3׋o~Gz[{ߴ|Z놆ԒlTz+յ.*nG$Wk}oq{ϯ[@76y}uxc̀,o͸ZNۊʿUs8I>}ahɶ-b-RӡZqWx4ebH7'޴Lumu9?X;jbn94ִD(nx_t*q%pa)ňPotxSCgXl XsŁӓE:piS'IbI/n?Ź'&WW SzX_H?i|`x$#/sk֚lu6@M'H{lsZ8 SX R p}Vnת@]O )*x'q`G?[ސ;rxu}Móx׃uI6$srl>~VG\k*nmI$_uC=w#bE #WZ!^hOԐICZ~#NuU EywTE:>rx:k}-ov?R\zH vΟ5kurU(i^O&opU$I6͏N,?nPp<+:e@-mCy ׁ݀f H#5n8o=6HOu}#O?S~~q鳞' ~yaa~?q=sX=HOr#W_"2yu"1rHx6'l}g>FJ$-n==0H#'ȂCp,{zi9'OY~~[?׹ꅼ?Ky l~wϦVE?No?nI\X CGauyNMNza?"3k?m{/k~q{Z3 ~.:>gyuza[ny݆pzO/}y{ޟ^'ZS>O֏zqoӭ(&"l.7u<:E6{:θ$ ?{"`O&ZsǿS˭uPnX^}luAo^osc:%~>Fߴ?]ip~zM~݀[զp@>-krOUOc{.,?-zz:''?Ƒs\z0"_[7{Tz[g\nA⸨2&>b=Ԏ=\ @[͹3ֵ8~^ym y6~յpA^E>oW7~BESjxX P~s{NAX6u#X)Tf:̂jrT ^>X48t.x~~xp=:i9JZdSm `8u|EKGGӭ$uOsao7=nχ\g N. Rr&ߎM{^밃r ?} ~#˭ЎNS'ϽiuĢH_GډnO?_Sժzc~进ި}:6:t9aW8Vp X^p@E׫W2ۅ'yZp׏X"l~ޞ>M8'ϫu+{\ɿᩐzŤ8 G~=MQ\4m@r8>]]_zkp?< >r/J>]8<x.O+O^:c7pߞH'JTporǑ&{lsQqhp>V]l9-Ź&Op?{_Z׫S?/~>8c/>&_#u\u@7no^A}sW'uȡS0$7h##A4\ȱ=VLW\a$kGsk뎛?<~yR+^ZvP'8GZ'i+snN+׫\xPn8#(5:ozʫ ňo<&ߟnQ!PopM# \={kCîa܋/I}F:=r^ 8Bm{oU zȣ9H6\>T>vB@C,o2MY1-b.T k.,Mqc5l@+q_Nf5Z" &{?Q =gUoW[{HS˦BZ@9>}fP~q&8{d#Qk_~M:l׬s[9-~y`?oT'd\6Hs=WzWj?؎XzP[ElOB=u\ě~?{: 8~.OM1O>כmatk K[p?>JgׅxӬȄ}@?O7$~-Y>~™zɣ~[ WNTc\ V6a}lEOϺϫpu O>~E<ՉWӏW1NnG$MXiՁi:m\O{B:W\ >a q:JO^ӬX؋Aab?ß>קFEA뢄~X~>M3VӮ:]?SS˭l?P"WO`{E@at:numanl'jie?[-IwQDҽd f?6ҝT5Xؒ86v1 hyc} gA9_vZ*Qaq>݀]d"Ğyo{~,/o&_½x =f~M@~ެuCS{Ã޸=dT6 sŸW-{?~[ _:゙QN)?O_Х?9_XǮ'|%ߨzj[??[ZOa e/s{:j-or9}~@zׯi ^}^zny8[ߩëWӮ_۞,/TXO\ #? ީՃpzS~\[lG>NE/< H]X׬Z@<?Bzi;&OWqzSsr> )gzǦ ߞn/߀խI]?Nȹ\{e]<ăecc:*:7ָC{>#VqQè$Y\H3鎝/Z /*p:sP}:%,(o/Ƿ eT㦒tv>h?K?מ)CN^O"$O?^Xߛy/ʣX렪A?ckqz(1SqrN>XOtPG:9x})O^Պu֖?O e &_~E+ïT4@꧸\JT"OZzE-rA#0:+LJX4ek8aG7Z~]4X'omwϦRokHqo=0Oq8^x9q{`u꤁{ONll:~/ksco2:J${43Ӫ2G.o_׫Q_RGoqukr r4ZiZ>G?(ě0B.I>QCF4^ٞ"@yuqp}z\%<ׯѦ?Q}>qiOߋ}Sj:q/{zN׷~$=:Ӯ%XXOgWG޴BΝq?uXxa6?Ͻi8z:mŮ-^"W`޼:n?O^:Ǣ?{ONce}n NE@q{pϽzޮo:p1X}.G?S"9Ӯ@ܑ8ӫj:V׷ou#^=cd$ }?BL㫆:v`_nמ(AZ`WyeeDTr@ÐDƊzM WOdsAe 69rj`̌H"nonʛuą48lAu +|;&M--Z2@$Pof)b{iF ͶW~=β\% zO!7Y*}(/o&I_/gl6P8Q#ǠU7% l>LÏIa8 {b/{GӐJLuTlI7rO'-oL֛~U}OuUVn= }?oti@4Px ^M#oz~x"Po?m4+f rx7 s) Hj[b#qkkUom#*O$~ہo$[=nzh5AoVpy?bcPiQSHʭϡoc%%”w(Z໅k j8"i QSNmmw+ح?A^7UVl1} %['QiLL>W{b_1P '^J{ylv~2dc@O *i?oˢcWbkj)jxFΓRlٳ%@t5=GNZL1 (>G)7U:"{Ӫ(.E SǨo~?ӮK6ǀ)׉z0R7's^[}dr~^8Z}ê9ԕ[p.W?}æYT(Mq~~ݺlOY`>^O/qæ8[/$q}tj {?7?ǻZ<:ʊO^_۪+P-7$Xku?O}Z뒎G[OyD@[p<}y?P}Ɲh]d ?,Gד?sWTf <\`,m6_}j|̠-sߏz5Nc*lH&k~ΞR\p,XYn.b܀9<D:qdzpǯRVʹkbK~Q?z'WNOY|/Ic?A׋{xjM?'~ja`DJ~}8#- k ؈i6asmKbJAk_~}˭%80gּ8rX- o)kH[M@qz#=sxl%HH<Υ -ZTGĺt@rAݫ^=6QC-0|~}=M|ִt4ҧ ?N~IﭴU㎼7ۃqohN9Nx~/ }׆sZy>N\u[{3í q`>?ij׬n<}^NQC $kuk<Fxu`NOn~t:R_?^,EAV ^{ ~~.P~I[?QZzupq׏Ou%R=\5>ް??PNR.umpI}puor}\0U5 L37py~ i馑'">]Xl. u#:YۅIܚN=:}m)4=iV =4t|ѕE-*$}-s٥vJĕ"gD[.$!:Ab\Gzpj)*ah2D Щ1 _fcpTI֧t NNZ[yAPGW҃tUCSl6GW%ecE$F02ǎG~7Ѯio7iߩ?tZ}x$3ïWϮ$ao~=^ޛ~y{c=:kǮAlMb ^A8{U&I%hͽ7"-<</ h%hǟCX1JVVfZWDVË"i,G>t'w-b qEN?3Nd1IYZ=)³E - \G ]*WoS4wR]YF!:(o޷9Zd꒒MEす$6[ .~]Cŷ]Y2n7u&bByLPpc!بOdFP olҤbxo?kRlYm̀._+<8 c_,-O/`8t5YP}~EO:HPoIZ}ޜOLm?Q`O?:oW\u_~?9YqST~M?G@_H'uS׮@XM_vG&}e?{vj}zȪC$[݇Z^"s{[ݳAdhI_H_l~}?#=ԚW <(Վ_\m[k҅JTW_RR+,oNARG\D`4ou=aPTĀH -Ziì ulh_UXkl#T?/>Qn5Xvb ߐ O#ӅA+3ُ?[p/XdĭR>{֞'Ӯ6^߃ީCa}M\{î\u`}zRb?>u#\J_X?}78uӑ?o=OyAӏW :WH{x~=VqìEy^/}~OzNm›$~lx>=l$crd0)eUXHKۥD)2>Ki%dVjJ'|1Ymq}>o#UTxt3Ԟ$oitȩe9-EQPLuR"\]~*\_>}g>aǦAx sy裍3YEnoZCmā̳Q!Y xf UWIYe1EK!cRF'IHU~_kK}z ;JӪ0VEO=UNѓ0I~OieAӰJw3Hy&o#V_F(Čp?X'>=:p5op= 禚>eP@ꄎ onO'>Szlu~E߻}T/%Scsc@\zֿp=ۭq"߃_nGe^?H{㎲,>6˧ΦFX7 _ޏN$_.D~Zӂy>ZtWH$ִWD-1k!|}..BP?[޸R?f?."jT -otÇN! kC㎤+/ޯU}=ԓ^q?#ԁ1 \G,MPGVh$ጟQP&@6o:]@*}?g\7$Z̦$\X ~MgCCGg_U/#Mԟ^VI(>S?>N"$r~sb~~?>MjA Pk?dX:ly$ҠI,~EëԒ5w|*~̊@ YIU7?qUzh)P?OQ{Oѫm:{֯?Ok׏_8O_Ԩ=Qaaԟ׍>p_^/ܟ-o^[u__~^E ׽M[zi׼_{oVzS?\}Ak{^=uy Z?z+zxS]iٿ?Nk=zk^׷{1^^ˮ%^VXȷqu`~}c#qOGW\J_}}O[Ou#2?OqR:q {q^EmË?~WNX-as~#ՃVˮC\s-T!:n#矧7q9<קVE:WcT~ޱb5͹: X +7<~/\@4];HH㖷mʼn[U@ $$?$p8R,.x't3Ǯ: l^G[8ߓȷ>k5n>=ϿS=x6yuv<,8# o~[xu!'H>o4Ԙ' ZAFzbI\!qѠ鎽xs5JJ!F߹luVp>=Z!XN佽OvPOO΀_^ ;mYbVaM5uZ'"By[W{E\#']mA 4Ƭ fhzAJ,TjTVMUAĪneLCʙ?/?REghxp #JgN?gE;暲y$ҳ >m"P=Q\I\;$GA{nA[dj5=yPXLkpG??[=קP [ Z߂/{uoz7?݇M[?_{˪L=eU-kP-͸?63êVY?xGTW>4OY`=:>]sa۞y'[۔˭Wvߛ "S`Sr><݀^sU`MZYK"[}OR">Z<qӊ<:gH$~7[kOR BPRVunm?=־@yg_ m_VYx}OWӫij>zSϬ7UKf?AqϽW/?憝d1]./? bWTf_Mi¿!,.0eEy%'59ǥ:ܹ$1B מE7 bVZW?>]dko4צ_To״:iNUzը?O?p}\DX`W5ZǞ:Gl>nmڼ>rۀA~ʽx""߈`/bߏߴ%# kXp-s$mEzj16joߩ׃Rzc~$~?_DuzXg^܁y'DupT!؎-}֟^_i^)^}OMZzuj׬z6~A<{}c}~NZbc*>NIS{8pzHlOӫ\O׏ ou+L`z>$8\J}Om?ǟz.EiՁxAÞÏ{=:qXoVz+qOϺ˫zS?$]ީӁzROյcm$Z~ޜՑuECuӛǛ<յW on?>OՔӇ\|O?6ި ]7 y=x5F:/p <ۂE~O׋g:MW:i5 'A<m͇ uVRBFv>[QFXc֪=FOܒ+k 2{6&l |Α/SigIR 35EϷjUTQ@ERӱiK;ݜoqbm$xPD_>lnmW>}s#7ǽҘum~~K_yuL}wnEHy7ZY@q$sa.^9~c{[˪*x$Z } >u Q{͉np:>c@OO"xd?VQ{٭{\7'_/?oScUc,bO gБ}z#e)}(7Eŏ^:Նp?3O\&(lu i)(X'ϯRR R5X X0' \:Sԑ<=?>Vu~:TzJO?z-P:QVbaFA׷W:6c `t՘=>޲$L75}@b R@F @jW~BņrMƏW=W}-[&<@$TXHm$q{pj+|5Hp n?k?>ZzM:U<=>UOΝwk[?O{-/ǿUxS+i[ž?֪E6װ@ bn/} pA/р&}[{8u'/ ?X{?gZՒIo^0\H ao߼1NmŖO*u`U_C~l-r6s߱5 -Z8qoc'F#Xů޺ja1\'T4:u#?yTWPzumZp/XJ}< kqmWzVcq ma$W=c+A}֝\\Z_`UQX7>W垬6^I7{rxt#:S-nx6>WX},#8R8c䛟uVl?=z4g>yR+Ճ~A:RgR:bN>ןԃ~VMk'ɷS^d-8'=^ ^~bG&ߩϮw rl/׎~}vG&yuyM>ZKZ,:始qßstuwW珡6yX\~ߋKZ77_2:?6EckON:HQ6[:xP-p/.?:>u"8&&}RPì"~@XlI=s sŹ$֋SY,}N1DR7xRkӪ~SzRߐ  Σxe igzr%bHjOkԚtZ_d}ϩq~rY[{HA( ?éJ_ i4'3ӋRA_ϩI {Pդ0X&IiV8n? H {bhkՕǭx}NԀ@ߛ5^ğz8?oSp@Ϩ}8u|8`p*G?bQRlH\t-WduH$(IJz: ⳟ@-fPt?CڀDlNLJGs>f]@9E%=Wqz 4+_˯׫Oߎ?7{ piucb}Eb>}O}{Q= &MbEſ>zef5QƜzMM>?&=q4鶫/p }DP< Λ`ܰ~/bm狋8*N qqqçW|z$c7-?uI eAo:&O._?Ž֞\ '?ވu`zS-"R,?>2m_VR\JK8&Cot#V\ Otjp#o._*ޮ9ܞcotՃ>Ïu#u`>?SO\ ~#{.>BySZumgoީzޯ\tێ<8mCs mqoz[Nh?Z{:ޮm?Zqz]6qu.i$ֹ#o{Zv,?yyu\oo}.[=r /#{֋5OmOoO{u]^\/qͿ{ޞ[O~?:n"sH\{|0@E'l?=Vp8랛[8?>Ϫ ,/o[ovDsk}mZuE#9'<:>Yx-H_=ڔfIerO'~:e:]s[$iҘִ>|?=N3{ۂFG J"O<n[fI'/ץ* _hWzr[H)^CÏN"&p1?:ȰOʁqk1Շsi@stY?MJ\VOOV R8u@7X,8!G!HSZ@\ |`]rnگ~-pE u8Qn?Μ?o\jҠnPU>iRG^ @R~*p.O{kZUӟ{+OuMz p_*}ЭIk\zo ,7\=zPIeO^Zv%Rl~ts~o[hJTzz/cmFI Hksb{4-$O4ߖ\ }OO_ҩW Sϟ޽"e*Զ:x |ϬbxT#M?>Zy_?ʟ eǏ<`-sȿWq"6W/saVREzǣ@-{EO:?ߏuul.H}OWuA^?>յ`zz:xE莭=tW>ÏzanJS:壎~?~ySj8)6?{?oZ'8?Q6'E'L]\Y-8~~}T:ȋ'k} ZPs xO5yy?ݩO@??O7vQ-##~_`>]V >qϽj:&-ovW玹_jgyapm}>t$ u}gTku1#ǎ7ͽԚt 94}}OU ܛ~MϺϥjW}:p [5؁m@~|RA@3ZgϧB$@opCBF*GJUXWHbI *^X'LkTA~ځKxkA76a=П^JgScHkk i@!K{#fJWNSl QX qt i=W|Qܨ 7H?MԀO=Oϥ Q%kS=<I }@'uމm3_ӇlQ7sa{ dT:1˩  &P5 ?K6xT PMƞJX@#9Py#~+AՅIeZkI ͍}zՃӅ 1?/Ogf,H 7В?"ߋO+oWPE<3Cc/HI-\@=WEz8=+? ەbAMJ:aZՕj*Om>n2ح͆RO}b0OOC\|cSOU~jJ:}>ѯ-rʷ77>RNjzWCenu[.7z&'NҪx׬crß qoX_uՂq?Sun>ߵg^ak /bM.M~')D`ľǐzhXb@U607a~mŨsí*j_B=i叞zhBkV sbzsxdž28/Mfx(@G~>^,ZBIkSORT\h<=ϯ2F(j))QH]@ kYxװ$~oeR~ΣKHO]Jkaxc8>fzoŃl@ ~xz֔6A]Ch,pl/s~Ք\_.NWO?Kk~IS:xH?QQT\ F~>|W[m>~1Չ|~QkXJ`<x$~6]^?/aZ|z?x?}Mz7;u+յcm~?޿ۑϺյp\ _R:nh/G'TںDmb?oz ?}O^q 6ս][W փ~m^)xuCˮ ?mo׎-o~NMkׂc}I^\_~ϭ^+ϿS^"rUstU-uI{++Ǯmju=r so$?{ZWzqj>*n}TNU|'amoZÃ>O^Z-}juqonEmoϯ`ש <.?[މ< S':9n,m_Ca =N[7MͽBzD W@eRO:|- '>+v@M`Mkʘ?mkU,[/HQn-cpE?sjg?􌯧Hr^_m~G=>UWӄQ(6i?SvC_t\ #>9/a*F m_FXmD"P`߳Tj}JV\Zˬ[W{98hˠy㈵ ?Ax< q=X ֿOsH(?ԸdG?qӵnէ AԥT"Oz ܤ`?g۞GN_z!A~ $ޙMxuHCC_8 qb@"H\pT [?>$):qW>}s4 7]mU: 1CʵOr@*O:.H ߍ#kiR{iJgWxEl8>R|QQ_sC?^6z7kۏW5zvOҵxҕ>uxc$c"6 -<{븐c\2{wSA\azl Ф nhkk[D>]8`H?ASz_!}MAod'% UM=|x/ҡrQ$2+ŷ.# p<}q$6%\ h^޼O1UϦiϧ}3za6+͇z )Ӟ ME5'iAwU j!nW X?WZ4ВΕVΟ9V`=76xs~_u(goH aQ?aȠum_^+/6I?}[zЈx-)( $ Ϩj?Kop韦bB:_?y hIA6 :k<>K{zT怱?fgiM߃n~ϻMqzo1>9#~|ф ZJ"A@x6}@}h3QϨJ~ H86ßvU>:Bsͮ-b8}y˭ \)W~.MnqǽJSAg},.7\~/~½(|$&p&.8_R?I7qb, za͍}{VR GXZ+8?[b8hycnoMaOoR[Rxyu?޿ފWj)~8ϺՔϮ:M׿?::㧏[ީ?:=q(/s/{֑ՃusaooqZz!׬?_ziE[EڍO]Zm׫N#9$n>Gu7~>K^Zu$Z_v^[~k0}E~oc>NO]b./O{z4_l{<ކn>[u%VO?-{ŏST##"z^L֔,iq{}? \\_/oOn By}D<|:$?*nki$>HSPKȹoϺקREiϩΛ~_u'BaZֿt8E uMZd()gt 0 XʂOӂe'9JB3_m}ON rEȹ[9iH:PZ>R }7}ez}RSo8E ې@[-e#~?{l( R{E@ӔP Xy-arP-_m>\:PīT> M ?ES=o۟ç8 RKYq}Z?'dӣMC ltǒ 1ؒǂT}?Z:P4jcU`ssMk_\ݽ'>ӧBv\~oz8TN KXlESk~oN! 4_/IXT~ n@75)B>~8HIA }'>_Q?UO4/~}㞪>>?g6 7*/kp?ޥsNqjQe`>lI:_^$Wҕpq}Z=VmF߫MO#W|_+cV ~/`܆Q>%qî&}8R 5N9)žrF`e\sp,o=mauѭB#ˏz GmO}- @n3S?yre3OJul2_R/&$Drڿ'޼NuEi_u셆u<[Iޡa?{ٓ́5Qz-7fQp]Ex, /owLU,u^?ϏMP9b.wg- ~_??)(W c`HO`hƣħ)zu\}t*>A<_OX;Z(0?æ(!J~m 9gCzSb^-P<3#=e }kI $\RxW?o~@#ˍ(:p[ X~_ g49Wqmc ~W{>}>PIS_c^]Gh@?OӏuVR(1Z|Qco-́?{ԁv[X8CUzFX $8݅/j4Пؒ8n>J{#F?<@H 9O}n=q)lmǽiZ3|Zzn#yx6_zzMpzHSksSZqzZMO6"KGSW׮ ~p}oWq{_GSz~_։\<#떋m\\^[>Tyu\m?ݩ֫^'[ۏ֏ElAsͿ6@Czq"HII7ׂ::BĎnm[[ IR39㏥xQ8^]JXMP.NrܯUӡ4ձI%]\_{\{'Oc_t :Qb=<ى/k~' ?oO=Hʟ׍~ަKR,6դ0܏B5kSwFT>S [ aځ~],Hv~cqme _ =(Xk٭GʃӜT-<Џ,NƆ:_gzpX--_^ҺuR.RrM"@7&OGpW8IR&l?t-|@֤yq\c ylo-p|QբvY*fPY~}6nS%wŊpN$"%A/̛۴}+MLxiS:um}B)Cxg<+ 2hk]"yHޥoxq}wݣnV[v 5( jhEt>̯mwJ' N Սij RwsqCGIv $AM6nmù.DdWM H/,P]C/[o^P E*eX K+c-?n~o\ۺ{h0/2+%({H6;ǎΊf FuX'xBpU;]oܬuyWRDʺ^)B-LTphM+ Ej:WAʯ, }/ϗT4ZGY>fH?_qa{>\u U\mb_PkrT}muk*{i_/嘄NO rI7"K>ZSQ=w7SiNjy~Z}:`?Gyt}j}xiQk:>1uv#H7@ޣ^=q>>tWA뀡,, uXX~x*iJ|qE}JUɶxe?[oz/._n:Eݬ ]>ӎ:Tz~f@(i7 J{؃ tF(#z c/C齘@ÖGſyQ(ʿ/z&8k#7/[skëN~cB@<^$_Gt߅֕zC~ΰ5!Ie՘-`Z־9BF0@zu >Kxؐ&nIop<*>ߑ)_)cqb~<#kfNW_cG=E>G  qoo+ZW?*~]AlhX A8~/t 'OsbQoQө~I vߛ{pJ釶Cֿˆq69Ym|z:Ёsbl@?Oկ:񌎱O}u>_"{[A6~˭]p/͍~JTON17I=:د)Z8}E7?{ϯzNE,uQ!Pnx_ǯP~[]hBiA:y<~Aq}=X rX?:y?O}騨o 6,9ߟz>GYD$ I$m{~~߫\((zȑ\EȽoϽWՄx=IH{_?Ou&8Ԕo&-n@>[ƀ#֕jSY_݉"^=;u'qCS1CK5zCoŭaN6 @T8u.*qR}7V 7R)'#chiz!P06{C֓,Vq.vࣅOI}qq [_BK4Os*qzT&b#UYK) 5 w{"%qUt``e$MKmqGqQWRE@e`c"T}(h!G )<*''MuvyXH^Y\XRߐχJll7M2D_2@ʽ?GY[ep*onޤj vK!Z))+ _yA*Gm3aqr%VP~'M&rB'B{Uod4Y5ʸ RケtsQ BXqM@|5UƱ 6-omoCY@YiR8&Ђ@ E um `T)`AREs )*xss?{2TZ@/|XZNXCHZZo@\Һ]G7էY_?>SU >q@i_9}R4F?ˬb-\ ]MyB2kW^n \ܱ{1^D$Y^f+u n}&ǽyR5JS뿲TTP\WjxS<D\ hk\7a{]btr,.?ۛߋ[oz\upgo.6}8dS5aOOǃsn @Uk&}}Yռ 0U4:}Kp>z~$o=8#=[֣_u I]!>#UŅ'yՑ*a|_ǕPAܔbI$OZ?g1WPԟO?{zЍh(@~_>'25zoce~T0#{LNa &?zm.Yca{Xbǻxh_IղkS>T0d,,H ln=%.=`EqOzt=#R}3/ w?}>cM%E@9{\4:iy ֣8yl}]yò]A{qduI MxR)6kp=s\tM@^>^T?䯗Pe#G:@Mv MI ‘ۜ|Qw$\TMGU~^_|OQ~ѭ,lI$zTtH?_>MN8u]+V\ &?^,i6zW)UhhNiӨ pߖۋ~O/>8^?>~ $AN 8:U,oߪ=:ޜ؏&y#:5 O^Һq_Tu}/k[C城yx \E1Ooůo_{&z)o$sUϯxf1nn#e< r=u Izu${:0q_}s/GM@>ZuԍDa >_.xuiHϬlx67'UW8JAr_*H5\ qq<*@ޫsHV)^}gJ`@{_{o[5WtoM oS~ $n-ǺSՂPN==>MpFmGEp&Oub h<>]NZ~}+o6:'9O+|_>R$L ?WF'Z؝Zsm@<$< T!{ [bɯEh>ϲ yۉtZX]xvqN?Tb(ij憢y!$hIYx $rAϹ%Y#zzK A$*P5}=.*2txexfW,#TSyMdP5h)  >;İIoHꚘq-7-~$΃QҬ't)b4[O2K]cIwT2qkt.8`AI E ,px#Ȃo bɆV(hxkZ,4PfiK$@"HMmxCkkɮXIKyXf-VФj4H([`x7c*D")(Jԝ5<j*iҦr5QfT,YaPV2 F4 1c)B* jA*jZ16J l^zY񙬞.\%.LiFc):CU (t,`xP^XWOe&Lgwo`mퟹ*lT5jt㞮7Q"XxZLkiwVy+\x('*xN*Dq<=I)dC,ђAQJ۝[E9A$+dUVSS}̔Mz+%]C27_r˷ȑ#,2@ V$Rb׸4r_ͧi(RH`cpC-O]#e> !#ir0^\E% X%J!9f|rc:.N s^n |8ݨPU'ƙ!xmyanZqW]ABLq4VJ)aA!jvhm<.OgyȊ|FQcP46*M [Z0>̛Ynrk#r kP=smR҅HO@ՓLTpu { }vko Xrf#T6K,(r䤆1W {Oo?eͻV2D:I@UX+pzv9{~WvdAr BM ?4uPCKFM6[1 wHOTzPEE1BAңQ}99ϯe2?o]_8=P4W(O6E<^~'|ڟ?_o\>}W $p}B~׫MCX InGj  gpj@qb5(6ɤ}?Rb$6 GrA7+ӧۻ&0ZaQ/s**( 'Klb4bl֠4^9Eٽ{`N9r*C*cr KY*pE>;ٽ$}}?e=oGZ5V*cϠlpBlڭe )x|"ӕhjF>}7M$ Z$P[HmxsjʝBAԑ-[{|x1zzjI ܟRIPs͏~op&Fzя 6\pPP}r:c[۫)sim۞>|Glb8 @P/G 7IۂOIB;i_/5 u %6ßvfQIV^>Ρ=խ_Noȿ Oϫ.?_p1@mp~ȼǿ| pxyϬb ׋ޫzp)gka6P9}zi@WXsb@697Qՙjk^mD fOP9W\ knITgZP?'4BPoI}Ԝzy }kJ'u"PAG5uVѧ5ɠ1QL׸bZ'IHZbmkzx 5pF="W^o>\u$(8֟aWUqJ>}N#\1 coOhtyS\z$p A`ĵ>/O8+?1Rk.?@ uKۑh]?Gxž\&m:u! zVe?tH\ni)8^Tcp8:Gg=+L+: W?^WBt]6 Qyے ^k&o"C]/7[:mӹE@AQ8598uϋ?}Ӽ*x96s+n\1Lڲ6ya&i#O}@}OD{ߧL<ڀ $-NNhfgY|˛l6ʔ/3Di ?o4[wVe|~:STtݵ5%E^7v_DfIFߟ9Pn$,ѥҠ ӀE@$I%]ɴ^JgVX` xHQ\k$u}3+w6J m>ɓ-nu\}5 9\K2=xپA'ގknAd׶@'""2\1%O=Cc_^IGŪE +4]ߛ݋q3lf9 1֦<>I-}0la "Dj+67<s~hl,1F?e5 MsJP3ԣc$M9w/2I >jT*GB/EfksmݿT[ofK;uUO]CBLOk`I䌂۾XrͲIJɮq ±p8*PThw}i Mxff 3[vnS5&4MC;^@91nԲM,miD YnQ9oy ߹>vmkxԳCo@ ;nl6H_ VEF_#wbD}B7wnIu-FrunA)e=n?OdiJG, noKmfAu<La_?qMbWR!o}ެ=ה[GhU,|> Q @KL7fGlfU8S֜bi2d4Bj},S4K0b@c {σc@tEQ ^R_KPM05/a0J4jkH"WKIɻ d=s2*\F;}`r|-]5vK?x꒚j4fhPǒg=/n.\MnQ):"m?]Hvq\]GjT2Q5PB)` [nw-tM1L1&I)\|-;1um)~$M>".F*B:*$f߲ pLfGUuYЕm@(PA:M(]r; XdcTIc՚D u"@"Js0r[,y3i FYJTPZUtVD,Z2U=JJWc]4%O&vV|m~?Ⳑl j룙H+4XH5qs^aع}ƾ*K.\OC?jkCWv &9GT!Gb+1dn^HjV#MJ*cP s.LF-G&~ RS &(<}p`TR@>]nji!8+|5T81:HԽ$jYt:IuU7 }AyTCJ|:"6{" _GE:[?X: tꖍnU<+ScE=$tq<onͮc](ϋ4P>ś')tZt]ڴuUW̆j UI! (A}<+Xe r{ݒU9yy~ޡԝ7u겛kZ[wYjPEJqqBnauk]JZMz߆y^}yh) i-zm`ߋ\_)ǰ(uj{ռ23LXui'\%VSΐGSߵ֣WV@V+?_77 Xn5I{>UI#Mi\>Ăk@ZŠ^}?d) G:X8.U$\C$FVѕ챨l2?oC\mw+T,4JV0娐.ŽkͶKnpgt1l;i#4iqnMKIQH0[F=m,Ms>Ỳa!Nq V𤡣tiCAȼ@RC2+SR>΄]'{fŁUA NCɂjyzI  r>OeWu\A7!_}~Ðz8YvkpPO"G0G5:S 1*jjJ' P,$@M@sOmln> 騩#]c+^]-8mT4+C>CS6#n8)!? Z&guSI~¼tPEj@:S]n/Z'MOPP|'U'g`oܚg #Ugw1'AK [ }/*9[nm SNF*3OP7r%Ѻ] sB0'e~slS\nI ܛH_baZ O3O^o\m=q ~}nݸ5QG0LTuLj! jW5ۏfn8HEtևtY>}o5@U*+_QQz@ɍ@eX}8 -=|Ẻpё"]vo݊"%YH_~~PeOȎc SH0'rma,41\{x;|FXV8Mb4L׫Ԇ2Bkܭkۋ)8=2*?}3όm,;.X὾}$lSPi^?}66<`M귧p~Ooo kL9S xgOæ $-(/_Vy=B xQnt>҇u_eB'yMcAoSk-ϻ,y$:JB3d "]D̫YZ'rݼJqbر}xMlPx>-=%zLցH ,Cz.4X5i$qb*>_{zWcA?<.=Bj;XfQը\پ6j EhHGˍ</؆F X[o{޺SӪKNN?mGE `GޛHV yڳӂ.jkOZ`uvϤq{޺.P@@gzԒqWuА]9ታp-Q47ǗAO&">$ ?Oǽ@5hC>gE ]uzzg)ǫ$euGZu~"ЏP"ߵ]o g^]s뵮< =_ PQ:zȔWSX -$q{{nuuƧOz(YT[XI}x C犏>IZUzSr9`oSݭn?IEe"`?>cJC/YOkrycaZyuc \~ }1-]%(bKz`mkӞK!Z1|Ե oG$ ${z& .DUMbOnpMtO, :|1J8|TXHW xF@C?) Al$S1~/3=gۛ 2~#)d_5;}+,C}UrwkHQ;lWFf$QU*:A־ZZfy)ow]#EjO927uV{lPlB,)8T3K,ksU2]=E]O*čo2}N۸2YJ5sQEMh&/o6 ܡcsŁ 4&N2:mvO/n:9049S[_+:BGI{(*n{W]Ec$ܴG.Y~g{Oeu>(fOe+.mzaۛJ4w% $j~zNcK-;kE+CVS-4"K##5R;Ll2j8֯@K͏Ǒ,xXRU7TQ gy'e?wV=oՉF@5=k(-!Yx `B(xkk]#qSc+7QBejPUU I)a{]X+RU+15祳ʰFm$YHB$p rzUݑc6]k1[ΑCPE2)Q&R *S+G dtY6`AթF?5"'|6VH?xFð ƒMA_ M+ZP==l[-tQz TqTҚzu+Xa'5EJ2{a{wK}ϼ%JǤiZ-$Z |Ɲjq8yC|BF\Qde (nu+wz`cԦYlRI4V?s ED=^k}H[Wp)o3PTT |]&PߴMz‹xgqUt LQNI4{'FkWɕ}iR=XzW :J _@փ}a\Ŝ<_Mԏi1V`nK8n$LaܫVLٳc mmXej2KxЭEf5RF;K7nHrCe2UIO#!?B̊eWP^0ݶ6niDU! -r#:y ?Dm fukm2e jBN(NkblnzCq=Xeh(9o1}=}^bDY;J2mfvK9,UAU ^)#P|DMl=#Kͧ6iUxn Z gYbOح] 7/n}W?w]n7!&3)C=Qdn3>I+AU2}QX*`~p޹Ol-kfKQA5"b=$ 5)寢ܹM;{;0S$n&W/&d,x,;pR튍.G U _;cR>:TC*ŔƬ@2]Ӗۮff# -$P VSq'kqn*@5bb-1*TH`X/c3Ftf|u%&.jɣ4K:4 '&i>.+Yw9&r< B<M]:֧ueء$-(lR-%w~^+qmJύ]gjOS,qdHê $`՜W^ Q>kÅiƞ^xhM]R)R(G p9*(mgr4x*L4)P#wuhlUI)xuEe@kBǀGϥԏ5TXL,S+dUYL: TZeeBBhW)0$:h:g%̐C$Ϭhِ[ i]/[?گ[ALs;C-&SğԈ**ë19wm[x&xn JAhը?aYAAnE g/ ?c9u*JeoF?ÿ~<}wϼ[W}%7|ť+iOSE{l/7xwj]+_kLiկOo_в{~N`v1Sj5?W7T #KM e`_x|xI.) 8xNRz)53OQO{u/m^m|fw1M4U?noo,}&kS:SXdJY _O }I,ݾ0;OݗU }רmҽԋX$T5>Q05k_C=m"7?'YQ%0U$+ybM+D7dʛIa1Sb ymŅL W4opgJKESCӤ$fYDk.&}E7(_]&frY~}FX*`*18yxTk%d<~=Siy۠_/i>> p9 DREϷӦ=4͊fR-!An#݃5Z E)SSb&Z)"'Fh }=d>ɂ( ?Limŀ E͈?@>LBR/鱱?q€O<{p?hè|pLoJ%H&u} >%Uks^ҿg BkkM-xςd$SO>ApPMoaa"۞}8 ["|Ly*XSmeIBA!96e戼lY;A3OP͗Y}7ߏ2P t-!2~uתv\Q$I0&ѥ22hWCm6?,g|nBop {A5'S!ε;Pv5qĂ9} du_ 62GYŨlkM޼C-M?=p\i^zS(?U}zq-vM LH؛R-~!Tu5`~c<1cG*:V@G9>]X[sZyTW^\x pt5=9E ?|Z|g6b`o?}SST/'x~ϮBA,6S`J?y[ތWXhƤ1_OyӬ@ ]@ Nj{ְ(8o[ q?}|UM5 i}d3#h.,l)#PMn0mpu/p=1v_T?7=Eq70Uc# H3jBA*#nŷޮg$q-U2cu.v:dЛg .Ĉk++)=n{rn.54)fv-MUFoՒRѾ܏u6L) GZa,R'EZ @db"0ҢTSh HIi?E&"c^nn,:QImzvFiUfI$n>{-k"+5Y5Z5\>̳X+Q 5 [G}v lzknvjmoݻ<>mNBl.Js8bbja:UoaܪvO1{fyJ.O 4 xJJb( 6.6t1> Nd¸5P-Z5_|-WQCjꮤ MYG55%tY4KO.SjhMĠj܅Hle}JYXQHOPD7]Vfdg Dݠ: [J2YiEbKBRVT'RuL`T~O7q۷NjTF;u~ w 2P FGxԺYkaPݽmwVԮ6k?jY Z-.gMPs*0GI 7E}\n#`(WG &@xPOCjy d3RbӻcV$"jvbag\I.J7J2O=laVG&VEcYg7R I!QAGk=1z)#S0!ك+8;sK`E;=Ń*(YE=U^Yh`. a!>ϾXsyijƘyCԂےW<i7y#>%SH4օ*맷U&z'og|nJ~?iqnzxgkj᪪9悚SU`}yӘ+mV{tE*M?]fv( c$-ɛ%^\\mi+O~UV=%da\t MzoWctO_1VvCU6v(bdjvAJs"3hv#NCPUir298"Bc[L)~B>zX6)oa[D&$M-JdTP:K C*68:X%GU|#E{03k)*r x(u|Se7U d'@?2Z4c35{'CPYbxt'-w-$oڊn{X /P(*q=͎خgEZJP2h*iRH[Sc7Iswreyz Eyw] ad(, M4$/"6gC9Nda=[nLGXuv1f]]I 㠶{g8nf h GVRuRH"p;GFXO?Py?67ο{O+/߼Mî. V]1{wϥI?_iϋWѲ Y*wEUtF@ 2M̓\[}6ȑ:ޫ$8xz*+ӊI׆L6 ̺@>и–ף- <)VFi)kX3 ^ 䀤t u\:QJbȺc tOY8K@}m*dc5 D-ھDV2YdMJo.p[9>X# :O5;S48qG<.X\#dUۛ-e%~_gZneTB=G?c<Tqma Z5!&ֵy4jz YT}E)sMLC$nC#̢Ȫ~މ'DP珗,B l2ȉ"1J$RM !I,QMʤG:JPoWtljaG-eH+MNAӭP{By Gym}aAc~_R(bq4=D|x׬]%ou(_~? ?@S7Y)!Czc*Q`n*Q>Vh֊QÅ?ӵ;OP(yIHI( G#=.@KvgUW%#|xm\0[X1GZ%[vwQƵ+_ZܬdeYHp>\=1\0[b:#_`O?Ӗ毧ui` lߨAm 2_=k*@?@8 k6_~A=Y` QE] E %?z@ ;M$ Xz BcِBf+e o,MO=ȚǠV=@wu։:5VmJC"54x6XBiQ}$E̜ӳж Η3GPWC6*R_%.n;Q ZR(NSyU8Ҷ>Dn.犓i>Z+Cn$y ,|T4INKLI1)\G̲-kA,7CX&7]}C$a{FOmp1VD>uqLVSIx}=^cOZ%Y$OO!cpjUT$ L(8u6CHEU;4('k[}?J%H@LSM6ٻq*"V aXjij<*01%DX=-c{vw.j+Aeo/o e^DVB*;u%hGf֫݋RI+6}}~\G?O]*jI%(O4s70s&ױ\\FoJU"ԲDYDژ#HWAk'k^_6-{Qa&2H˥==GPga_~ Y`q99jM͏Z袬4M+AE5D}7ܭ/mV#c@+iEuKT]*k9jǔ6jRmVG|Βnc~#R%U7/#k8꾻Cd|%vv3{RLfqUTWhW.iiaVcՂ31cj9H(YFp_%/jaj5QYEG[6T֚ Fj&jn|b48xH6F !ɦBT HZߙ9Ws'cmA°>,A^)0@5 iRf-{& AoqTRՓfq2:<dj?!Rğ[%]mEu!!y'HYhĸ CIt7m ?D TĸEr*-F(o4ٶ+vn٘EwP9󕙚H" (q*!r YjBB>~ya.ayVu-d]A$Pybaݬ $l Ҕ#Wbϭs0=}U%-EH\@khfI#z@_ښA?,HeO[:v||jΫASEON&hLiJ {<LKa6ܻgL.r#1xt^a^}Ӝ7Fۆ[#AhjBf޻tnQ7vKtw6c+vN2BɊAbXHTs;Z@nϭTQApՌ&(U t26z6C{zaŔkPP",jDZk.`nv%r2k30< Uyj FZ'c@mN r+qw C+A+! !k(Yָ, J{05bq"$d+PCPT5 z&;k)+q}v{mR&JEhaڛȲ) J`7d7+3&(I 騩0|H.. o"FJRM #Gk>vx}㫫0}<^Jry*3tRU* Ն@ @o.bv0L$EBR`A )s,J5GR!h@jo޻cinvF id1=Չ{ ,mJYToT-D*; s3[6ܿ)DIB=5Xtd;d16|G4^5Y"w*r Utl> oޟxџgV޿y]OK`x_jZO8Y}RߍM#4^=)OJj;U9h*LPB$F/kGxwDHʟ.pfF(/`P5GpVJ?tO_@[ԮY*UKR{JK25~C^A 3N K-6Iu( dI#tH YIt"4 n2G$!RtrᲚ@sJ \3 %*. `=<ە<OϴwQMᾣRqN`Pcʝ%kvWl}Y2LcVߩF?[{_fTk\>ڷ lAL~X5XY A2DXBHQ7+C˩sit⵭++ᮢnj1L!'׮kO4R ߚ<:YddيpaPQxaϨI"5A RNMxH1$EZiq? ]j{zPfҍ';MWǪ4T/$ir_{{323puqN5"I05NtmvG c (VXG q$Zd~4#ܻܹ{-F2!|?P;sMV ~"0i_A2dajX5I0P2VQXXZc!+BC^E5O{O[0i.޲Ƨ&),5X')6T$Y$)Wu{]V4#8uuܻq̯4]]\( Q ɽ[jƞRiRMO:a5 Yo +!ԡӦ'Ƽp&8t^Y)Y?U1H8yu )*K1S s)ܚ]F d/-a#?!n qu[XS\ȧe6(A6o2&Wb҃xdCB2rtc{0IS{4%=A˷І[-di)!%x ][߾-A wuae2򪒞=5msaX&M 0IQQE~\HrIu=kE A}OR!1}*A#,HDvg(l>ْYYh,4U䶒EcD3@Hi>a_&4kX]<W^$x]U5sM-TyqhjExpS|I"x ߞMN ʪIy4o; t F D5q%[A#^Qe߭ UjY D;t2xҖi:ubۋsVc0= PM<뻩jDYmRO3 s^nvߖFpT+r)K/0=RDC5<+ʀe_qysg-co>ݶ[Ij,Hd#H\Mz a\HoKt$sw#h&B#>Qlô;5M&##AagtU45SM#Ƒ@ etdwm~g{˲uGW5-0 Uj)fRGoWn$RKs C"b1| ,ojyJú0X^6Uz:Iꢯ jZIɪPtqA%Øaw2 ЕRX;'*E1tFAh-d\U| rH'=Zŭ;)D`z9?o[j5d;ecmL4:CP*2?zyRNM9-{a x9 U?6ZZ֝c>k[1gyE $UU,hBZ U6O_]S~is&WgcӼdyaJ*ZLl*G]$]@(#߹KxpwWEm:*@#Rո˵s5$-ŵYC.<4Ҍu. rI%4#+[@ n53S5%wVZ0C=L֜:.oUXШ QԩJ5 ';5@4z N*IMH(pc+]j:,SXY* x2M\76!!gkƵOSJ^m)SZa 0jj*=:3ۧG=5EzRA$TTu3;O ;R)F:K[onzԓgDzHMɩ:ISm:7coUv67W[[}n]sUGO>vjZЈI^/"=m-b mҮH!fSPE5%ZL+s޷ X,e3hQᰡN"[T>?:Ӽv/Z#oةc9MɴeaXXLJd dbȫ(b+1w.;#QB͟ :LEP?c)8i*ڃRy\Qkn15|vU=,X׆M$SCCSV) ^mWpÍq@7POo6RRp S ώ8|d7obۇ|=ej/ ҙFO5`43hFH?ϼ-{}468\a+ ӸѦ0;N=Ɂcs dZ+L9^誤TR+D\iyˉ&|j#UvE!JNOP~G]GG}%"=H"Ύ7 {@`=QE*]M곓4l֊ /K9 |CKie>X,[+/@ۉ|oR6 Nc=c䰸hv1ţH,#Iƻ]1Vl {>ɥ\me+o2R$)S `&%&mѫo;.$S@VԲDIu ev}ط vfLZ}D`F2RZ(<:>o:{~b( iYmib$SoEȬL{.s*A Md1Io  Z?Vt5=cf!\ ԑnqRD0̦lR"(Z8N^ ӭ!W*MAAdSYG5TZ ^xͰsnop%{I,XPX,̺7m)%mYo\<^-{9J6jrg)}3>o޿x~GiU*~_*3I7 ~N;*J&*yzI0cU ٟsH`w]kE$<}C=GHGCK#XsyAҕK >)LizKT'BEHMjtOpi#}Q,CH?_ds<ۅ[+H}'muI]K~ ~^@עY6Ҋy꠆GUFRuHFr-y=PY@H#26 %qQdzzk-ӑ*::8kP4w!D!W{ce Vg#gTIXn{vZ8,`w\bSG8OIdԢPcKu,/kq6so.Ei\Cg淸QiZWN3GAyc*S]STLeu6{8"HhDϳ\A3?âѥ 9VHfQŸu)C.`t PEW]I15]SY/k}/ܫGΊnuD >tǤԶI`Tk(">@ٕAW=8Wd\Gk?Ջt҈Z 'O*^3'=gMΟӏq'11 .|:y~X~%UANЏ!%#hK0b P^IՍ9RDWKR:I*Ie*=M!1F\~/1L|ܬQ5E\JTrí\E->lw+kwSmZIoXXo[n:Q:cQcXHԦX 4oϹCo;1#,ܹ'oĽ>`=Cl7YԦy"Jz)c[r$w6>hysV606c#U Ҡ>YLAxGh3{L?ᒎi)1T5f(%kS Nk\_IӜȐۏx4){&+:HM @v zgҷi!X`3h]W@Y'/9>JHG>]"WkٍE3]"I i2W>,ͦotDWm`5ՓϘ~dW0$fc72 LmtGq 6C:֕tPֿχz`{! E^?I?t+FӾ1A'Du*KVdG"ߓ~3;I/u38 :jTZI*k:O x 5>Mo6@c9ݵu Wc[o, zjX}FAkq9j+V?:3 b^ڔ#zcfRM`t+k ~GUqç"aiiq9C"m p2jab'cHFG~Tt˼rPke,ԱYokTٺ1S!{lA sZ˧z)%H@*,c`~H2՞=Ȩgcw.?8HeeFmTr}W;-q#!= !`kVcEɿa2]EH)o4)PjpJb[{{̓P!$q駴MC3>~X7:Io3KC"2 FucDOP.-nDfe4zT4 іmwlk+]vVvG#= "JeΤ1g\Οu|Kmw ]r$3Hʿe-C7V=/n?u_AIZG*993DJ_׈Xm6UW?+]oEU;-^}.ٛoQ$4@9$eJ1cwvtQ4HD{IPVF>ҽL%;dٓih'P՞!ޕ3'`e-G T͙U OTDq*Tkb &IH ɠfRT<8:j$lmnmh#iWdUZH2(I4P8rptĴ9}0Yh2nH: w}QpSdd@)%Qd`J!]tIhȥ3RJ:mȘ9a|pܽY 9=vC 4ɵ=RL= F6lqg)U4B|vL1F[+BH-L{XKl]TjABpȊIݟ"FO+`u5vˎ[vUJ\5v K *cA,:#']ǚ#j3Se=QUb6fTA.#S9|BMHQ.ٽGGzGj!erp` UUS`d㩱/A% n u; fSR疕c7 ,;Ŧ h劎-z \n϶2l3H-RjX,+Tv4M, JOR6Nc1O.+07.oWɆxvsg%ƶbzm82=:م*)(0TM썽>#kk>͢6켦⨤3}>%ZXXW^2+o\`ĊZR *  QSuUqdٵXܬGLmfuvH n'sPE\Z?AN:,efj4F<KܤrT3Y/qZU,2OWQ鶆:>O|tSRSsؼTWrP:[+͜T j QYU1>V(5Jjml7B-$2RGgMttȫgx%X΢45*H:7]1غՉ6M%Um>kSkWMύ8 Xaj|(L0z:Zr=,}Uڭ(dRedFͩ`Y#Zn<߳ov˸MyyI"H"iBTeF>!ĭWiS[,t5SF8a @yM;1S){icu$~>g U`kT]`m5XeeDS; * ]MO ȶm>cU‰ #Eݽc!H"ۤ a^ 5дn٤꯼~/B>ȷT񭤵 Qӡ6+V5b{Coz YP=L񇁢G>2 }o>yRP@zm#rc`I<()үtx$,ʰ*E`~V;]͌*O_n(5G Qv*}.d$,ԟb./'j;@"|2;)1ıLUyi;t.~~$;7pSmtVcA@jk|Gn,tSVZ4$ #- 5@ǏgvuXV|Τ lS^ctõTSVOS9 ;fF3"XXp??w(X_F ^"gw8ȶ239NC^]W dPկHѲk=1P9_0-Y~Ρոj+ 4W~r֭ղ`[`f~M}&rRʆeUd%$6jT񞃆x^ci34ߋ-cS$`xҰR+ W%5&ޅhazuZI`(|(ѷ ,س"Y.kۀ|󞂜;GhVXC"Z){ ĥO>c$TzGFW;,#ce&,}B@ SB~.x6ʇQǐnPF$/.d*l)DS3FrOosZh鷼)Hc,dUư̊|/oSVǸkSS1JJ5%=\R6^$X\!޹m'5 z.K}pw*iQCQ ?yfb۔u_'M2+H+̀n=\[[)CtÃE,nV,6[E?T llH`->E[:1?S=9Tz΍rmk<5V?}8TWϯTE,%=Ε,3[/sPuyWLa{'x6ot>ҴܩJ~y}_zYܲYNrE}>)ӉSˠ;[3;?;wVܕlDPYᄯ+$\G>{w.ln7RAf*ơ +5;i)R+0 zmK2T@Chhk#6sgfσ8i18K& 1ZJJy SQF*}ߺ|׸ol8ZRBBt,T(VVI'^nkmI4$Th c뿓;K6Vcgx3&??ҎTObԀ29ϗi] %jDޤQ#5]6KKi3BdFd։KPЯtDVwQ=mؽMrml۵}6opKO4MU.wtQe#p8lӽh_KoݤvΨPj$t,@fy/L8Y/ jh"Ǧz,YxLc'ީw1#4qH0T$FU-$i"IǴ\Ar"jW˸Ҽxte}.m|8YI]%Qx1Z]K{V-ǹiLTC ;ct8*5k: U0i Oe{\E"VVEJmF^nj#dƐVz#h)R uH_>bک!&I==dVy"^HES 3.]_nućxB$z= ((jb.Mvu֗Di+)UU+JC VPvR[in|>vn:a2J)Z'/zMGUJG2}0P7>KKnܙnN#Bnc_ ~VR ϵ<{LesFuָ8=nk6Ưo>!9NbM,E]4 dx 2Xs7r켿up\W 3Ɗ(Tuө3Q;é rcüѶ2i̵KKtհ:>[սuKO/2{eqpT6_Sڹ(0uFiڟN>%A m:_ݖlV\o :j4h,lR1*(A=ŹX%-*i w|KQH` cB(iQЭ?#2䷍VRlfJlMfعU]>^d 1A$gHmoVHin!Ӕ:YM8WϪo_R.?2N A"}mk=ü𽏻1[b4>84B<~‚k$eR_]!K>E JPFB)M2¸ۋd%'}'I[}: *? O+@ %FŻRQp[OocqU`n:9$2VUNeVG.aݶvݬQTEFRX5RMZ\mw6۽qs6f1Hʌ4j=(!Hۻ=_ۙͳ^ipTS"J̜4J I0ܷ>i޶͚MgY E".AjSjh 9ol卻y#vѦәX0m$ ,R0%t] ,>eSV144̦faKWW“*VOXGK.ڑhkQQ8zN C;+oo` HSJ`PZPzggA]ݳ1جr%5e&n%E-]e2$RuO&E`5rΗv@$hNM*HV_2$APըV IӚgM iѪᅪ 1v-ŹvN..N렎|mJXyˏE1*w]n[; d UfZ4tHĀKn\OPpeR*7..))=y۷p,'-pRłw щ,k_-rM=1iHẘ\͗[\tHٝP ;BH 9P 4ez 4Unlmy#thA]2V⭐ ާE`;/6_;wl+U-2/-O,6NI7&ϪRqz$d27ۮ\ܶw8l@߫W-PrF94cE^R-8+r/b>5ע+u-ش2fCbQۧ#9c7=4]lzgR%=rcy,.<x !&i\J{lkmM2]#F c$FLhhȬݝ{-{힒*Cd{qfr*` ~z^`޹s2ڼmM !NҧKI),iB^ K;һ{]9Eu2چRGUj&Z痤?"cVRk^K vmlI G53U@WY,OwSvpY'!!@gROoV + V@i ?n::Z<읿98p7 X +n%xŊ:|*n> @ZWbhvāERx&5|myx#oh-b$QIǟV9 *;*gZvWTա2S@*b3 !o1m1[m C/"U(VI $֤Tmc6}}rf`!J#HY] J VAlW|'iFaLJ X쬑iLcI(x^<1Ru{iZTRWoܭ(Jt&$TGVqޡu勍I")THTTPQdӖud _0T FT|jf>A㱴ݽ>RﭷO Xtص9\ 1SG1!Sa;~ bp60/ԻDK0rNw/-0Xb Dh@ i,WOƶ&_ax~>:zKkիX{eRHF`2djZpJ z%h܁¼zu h+B}=> hGR@g]+qf'}nR5=E??FoEBU*"[/IۛwϨkvMAtHNhm:JߓHvgǥR_,P}"+2%< @- <OقB(UΒ4MUOr1VD$PHo,!1K0HP^cwI25=+.mw=bPiҽHȨbG:$5Y1JqO#!e,rdQ,Ⱥ*:wҵ\iJz` 1)C9sڊs_e*M?*>$W(BCWxu~_o`*Q+Pjt{'X9[)Ok ZrNi7^g jytOhn U4zRXCI3 @'Pi,љM <% XTTylEM<M%L{pnڨxTڅa~ΐM5<;e$_>!D-J͢ߋ_ڸXI62r^~@׮X nrIlcxz=L[T:$?7cRYʥ&`k@ӰPH[ݩ4*ճo>pzVSd} Ftbc[alҫMqjm( 4)nl#kVv6箩qPd4y Q7ٿ}}m=V4xg9nD3k\NFN:&3`:jaQ Z+jYt$m?]mҢ*Gj,7duTՏESU; &H^~F]{%i|1#)=KK_f1BSTڀ?a.b=VlU(}@?CWOow5+9 (O|AF"tt2JjiA9 }["6Zy9b#:,1:+C|U}W65pU;+U3Qi%1@KX}QH9?-dC+NAϨmʲ!A~GAłlg^X X"̟fW1VPG{Lyct$S)55:7o}ɶnP+)FM+̞VT4J'gy!)hbg2|)'>_ڪ#T d3oAkldtɧ$q͋תn6g7Ua}Uv.B\>'^*52ZNNmTKG*KyQL %o;&׶E3=rIIpQQ P*44a_lvnfح7}r;xѪᣏHjО4 EW;sn7Nc|mݺ۟qN o*Xh=6:(!4Nj"` 8Ao}{LQF%9'Jp&y[cdVT+5qOQlmLfJ![rY8zM8͗b z ݗﵛ)\= re< k/-v;ݺ^oig)a-n-^2 Emͥɻls]Z,BhB#1B 1\jpNO][uW ,.G\,JN3,JI?#{}}^ۣ5d "H@}99K{b_ҒPky$]{EӺ^{/k7:l&/s~ۓdkCYM WL1`% pȅ܏t^`"۞ ^G]VTTb|JH"k?9?`u~$n +O<c:E ڴU&a rle9}JZ  ,Iۯ7(g@WEY C{7츴n"C"LQ!IPRu1oMK9^ӧCۭI8 j]x=NY zU@ͷ6;HY,}% W{ۧr˳"w+vH&SvG7M ~T+<;5e=\1Vݴ$t+" 4[3FZn[d u]j!09C$n]j`srJX&DtɡՃ0uk27uk!mFCo'#xvWdprF<.TbrTM9"AI-(c~0ZEEWC Px]f4z[赌xU EX #ARQ1HCm\F|̓awULiIv.ݨSޙRGJ{H°;0M+mmU!!J# RN"„n U;L/M}۽c7&u;'ܹ=zeݛ1F{sVɒj*)3QːI @P&λ'"mp:#`wc9.P 0zUm[K Ԩ,Pv H**v:}Es)*lL0S QPxՔ`UxopܷW$+ff!P"jY*Ԡ|V"6t ,M:h+CCbutp,;bTbr9i77]&ٛ9JřMR"LPr ZF . BPj`]v_:JF,A u*=*BrA/u:;umxi(x>ܲGdctY}&R*6jW15Y˱FS{aٶb;h a*dV4 R@&Rzrٹkܼ{(- cj&)5K t7}!ص{gv.7)U7*0Una"IiRBIi-Һ}m^6i 8CIEu jVU`I(t}.}{) " Q*`EO!iCkWǹ3 [QmlV'UU2tr#VE 唪UEۧ,1CGAR S>V]mzEƀ\ǔ^“-k[oVUf6Ev:9jgmfUMR*Cx&x|"n/y;|ZdF:V#:$pXTeM rjӖ6{OmJrYePjd`Mp"6kLN7 ް5UQW:O||*w8$]1c ˯f;1E^̮V5IV#I$BT.;QYdKhv42* Kj*1LSQ:(*:Z5p2fb d㲴o,Ut#ڔ/kEͪO:+R#[QĂBs7t;ng{ >^!EYOQ1īB+v|,]ϰ{A&qeV*8i:Y h&w  |ɩgOndf^Ok45|Ij awM#ɤ2H[muqocg-6ºu#"rC ҇D#FhKb@kNTzh_ >cz}}[ĝپ);oWClԠ R* ԍr&nSnOt0v4HA+.E8F_\K-n.nӹ`mM&zu@Q?'f ;mΤ^ Ksf39&^%Vfe>̛햷35Ux8 R cVϱOi&yanCXX{Bҹoh:qbt YoU4w93ݷ@km}K3{pd#n\m*PT%HWm7Ss}nk=4*WӞ:tUfbA/tIeA^hyqkpd%IZ_˥+㪩2eHZE<{Fupy~=YvҔ*{IcVy"\¡"hoY YT-i$"j^NX+_%O:#V2H%.}.x9.'ϣf"Ɵ/.Z&GU`c`-S;Tۅ%t1Ei(& UJzFt#xTqʢVsI%N(i׹(* - [ DR [- (̼ˡ>8E<5}IQSLDE[@ek~{qq#!?Vz̩mj ZWˠSuo1tP5BN["ǟbKXʡ WvХZʙϐj7,"@vdOS&kϠr\IDFw:xf""; УG{-c&u ?8N-cv-.$z- %dL>]"IDtffK43?=HI2)Iph*+ q[vjTP|rGE0}Fǂl/kDT[p8WN*d7jG\Xai+ yUoIbuquklE2rE2x=ɎPaUeyF' B9e#sl杖xqdɥ3S*W øm,o.T7Ќu[?>tm|#tg3%K&Kt|C-29qT[A]lA~_}IYy=狣v>NO;ŷ[R lX~ 0{=6v4YQZTq CSGө[P| Iz29LE|F~99:ldp͎Kr2RTTĩȾr7Ńڬc3dV&3NxWN&#WxmP0.vvݵbygմSnZE#jgj [˶EC, ՌZ2GFU$!pN >];JݣG15+J|e^+N 0Q᧩JC4*mmxl wMJv:fmXxғԪg,q$),U߈6IZJbdqٿͷ#cT7Pww[5 GVB8u RU^C,I@CSGi?#ҿpAq8]7Uvn԰SGܛ3NE5&.)P%snXn7[Hho @c,k:61=u.dҘ $Tfs**;D41MT66m7f[HzGucs{nnG휆6 =ngd2Rm_WKNeHr%Pxx-tO4ڲ( 0,EIPNH53Z\<A+*溴H: YO*V| >[36^xnZ-6yZ G$nA$"C0ntƲêXؚ^xϢ87/uiChĀ' f[wwxuz<.bvWjQO)\J)G_毎RE^nېOEcmш u5âIM択HNbޮ7Z=GN*-89zTS(2HXړlj+ ^MBN;#_af |=\_imÏdqgBZtS D]w'}.lP PX08$nMq( 2\*HsM>'ѽ+)cC1= U+a]͑Lxjʊ&+KISA n ]^˯ҶIL@\(R@kZy(]Q~Gy<f}C p=)X7C%rTս<Z+mmʢ @ꉠ^)GB f/mw}\_ƣKTdŨPB ?h:n÷n側p $ j>+G!Z9ٹ\Tovedj)owԚ\2 (ߕUw>Ő{",6!A5ZpH5ExD_J';`H&9=_{6 :簱{oUS%^-YS4fs=nRU@BILU܇yy;Ԏo[3MEPID{o0-<# R)1@M._;qwN~eUuf28|<y¥S-vopKN R#R!j6?n6 z w8jEՉ P zT6KlwlUuEgbT4HM? n8n.ϰ2{g;ջXpS+3WdjY6h c# l;sm8oçFܥ̌hH'R1m{u3LBfE@T R1lj,JvmϖuTmVRSm|AqK1ZzexA=o{{ #.c..Jңsҫ}54Sj8X1j8<2iZt9nZ̮4dsEzIk#f*4,r Ht~`uU5R3sAO_Zrd2Yd `珧ۢfRN 4#Uae )I$yWI+:]k4J1: oSFvKNLfA9.Ce $"G}|9:P\U?o yu ԵTSG f/Mmk={t0vfMjiz[ae3G4){ S#}͵$m#V:QعhY Jr\}}6PB:n EbdՔn>RO/6d =94` Oϧ1! rMĎ} uVG&*?zCʳv4,,3]7ŭY6wƙNEESFs?|xޔ:Ɣึ@FUm?D{F?WL璥oрy`tрy= u~_,qO1NJ*cMkY~Oc8P!??E+OWSM0yh Dèie TR_fWR^^ Dny`B5,Ij|oDY_ j.T-kŸ}}7aMs_Q M.x!-E$%4OX3V߷C6GhCDbpI4k۫m@+"jae$|x۫sfw+^bI_4 GFhRX̲X#,[4]Mxn!X5K#Q*5 93bڡKֵ.N憱 8Mqh;Vbq?qj3eQR%NR -34x5XP8 uwn?SSGVй9&1.no;aU򑁨pE0ztW 1Y'RfT6M!=Ԭ^oSt5yG;Vi`mAKK=DlSw]<^CS$)OEX0͖*"TTtW2_h,/viS+5'8p·$K3,EsZhI>smc`a x$qESU20 e5bh5Pp<~ڨ>ၡb@ NIЭ["jL^ɵ6nJxjV:b LP1eVa#"Y% n%Hi^ZVzpʗ P}+OWY+fdovUq]U{pQvMn.Yjcm-푣J)>MEY) >JlI%%bn&pYSvNB2Fpӭh)4AtU'jn6J^좯QU˜{[xbv.w9WŔ+=t8PQU͵ոű׳4B9T]I#^* 6}<] i @ĭxH\=v>;s7{]A-2IQib5TM&RZ \E&6wIU+JҹKfڐ"A==NڟKejU-nHcD13,2KSOp4],Ǐm\[HRUf~CtK8[\]yT|kϱ{=Kbka18z|c*E3djIJM(}M3]7 l٭!pH`]܊h (^l+hfԏ1Zңv^GQn7X~^rG-lS*%nj )$fG !v}φcƭ,b~Q rGv $dDkҥj5tj$Pf'ȋzqhݫ3 *第5֡4'R,*y\ oIw4׻P$qF慀¤ tD7[ئ6W̃Q@ @\WMs;KAQOa)Pr*)isx4 5{*YZ6k뻻6QhI~.R5J$QN cQݖԬPqkd}u[t,-xL'`ܘ\E]OmZhZzL3C5F"b;8wyZљx.ѕé# ;j3BeZѐCs1۔Z z;dzKgn,uΕ g#eTWO*S 1WHu2%2x.;\f(WP@5niz*VR2xVjPM7N6=K3Fq e#W&_=x0Dh4( oeQZIj/R*jkɦiQ_Jֽ#FYxj8 zӠ:6N# N2taΜ3]bSROH<[I"$(H^զջ̓:>zG4w{{KiRN[pH%؝v/x+qځUKOS;˪;KA۰KbSO @ ֦'oet.hfVXj: P@PUs5^_&C+MZwWWMlvjTU#S*dYC$F Ȁk"[\2d+@( S>|Fqj簀 Դ^ MCһ0gMlE6C?୨ܔT2-R&."&9# rk*bkQ[ۊ:%#WE 8ք" VXƎ> )gؘ[1*-d :ԙ*ǎ ײ~;6\Kw: NA@4ž-MkEu xzӏB|?]T_lgZ.Cۇod Y+) (jx G2Ĉ̣ݧ-CxePDGc-CPeoE  PXH QjT5W^#ޏǵ)oFo:.1)*yJ 9 j*zI[!I! +_ےVm+Hylhap]A*H}o*Ppf=׋Ic@E$4=sɌt;Scu+mm;g Z=UfM ɘH5| 70}pHVNB4h*IQ,N%js^z GCIqYA[44@UA C誅kZmjޣsbSZmҩVqBМdQz^2jj1Z8lJ0fRF&䚆]PxҢi)d&I kUj A5C|2åH*HB?\6~uҎMCUBMM*(I\g/AeZ0%K6Io}3ƽRuhIUKM\p(x-0 g2{j=_]K3ȴuOA:QK^2HRښ$ VZT=iOoody R]$SS\%-W%%W$ )"rk%䒚:]'o5EtO=}:U [dB+ GG1~#zh16"-<=W<2 緄RNIklJOdHcQY \=CrMY ^[߅^m<.,sO<;{q#^T_Kƕi?_"I x_e}DA$}o1U~ަMm{X>p}zණ?H,_G^8 ֘!tkܭԃ{rMȷӃ?n7 BS@=ШjqŚT1X؃rGOJ ji`)Rߋo1+?WRiWrl`/Y<}}ԅ]V2 BսzXi.tp'QYٛE<>$m qգ!5CN>Y=ZYjYY2FO"cX3p}1S pSO1dYʍ@ ~="!`x^\z]Ro85TX),D!W&lk{ӸS9;lhF \ XX#F- Ic^34P{6LE}$Xxr ؉r dVMu571%-4$Dw}ncuL˫@3PEJTc[i$PɺX 2jE j3QsrWP>wܝ*;=f)1ɶyi2Taq0giLlA;?۶/ F1I&baANc K-)%k5&ݝ夆"*p|MS]U6⥫|#a:H3"ZJpQ-4ٻMq̗[KVkxj+T)*-@#8EFL WHG~3kMԴ{UژV±](>Y (mȷ>'sT(0XW秫I|51OӶ}ܹrAڵ .BKj1TZ× i_:$@XEY5Ph(f5TT4f:7v {'hMܛ|7>W{nϓi"RH]/EZIX(\F-EJA'Oփ.o(x(@цĊW )5 fSw+*#T",3N3WPp / RH<*q@(-//9xA׽w;;paEG2ےլSGCxj4w)] `ujP=K v@O-yk i@F@`5քִkW#+g3YjRgi1ՙBRy2 P)1 cb&XQ)K0*iquZc 1컗LKef&bgpJ񆧕jJ&~IFS$ϴ`{)F5SJҕ#HhQJgSCJzIL[fji"Id(ԩ%T &*+nC5Z7Үc@Zh@ykgiDnjMtXQW$`/d1XʞݎRDj+;Cbm>#Lxך:$M/Fmc=s]ٞwe1ꑃ$a# VRv݉Ԩ 豈MjĮ*ePB.vJ]mZv[bd'ί8PQ8 mE4UG Keĭ{b7+$ݢ0xL%)N;NIj@= ef>,+CP ҕ5ƪgVkۛhj^ci.o;u՘C% ,EDeBy\=V !UnN"jUj=z9t-Yy$n ݋\'*Jl"IL8ꚊVM%*y!YY@ fmus dtIpWO6InZܖiFS|ƀt1~4XMw %Fȭ\~R 1D=@HյPC!$MIioaj mewn"1*1! փx  TS eZ3ӉʏLFxfq5L؉<+TTQWKyV*:XpTɞHbbSIʦHTU@E1h #_8&ˆ|\lvWoɺ)(|L_mSPУR#&zy^ qUW+gVzؖ+BbҬ @OHJGp-JzbYGy{~llqCUr%=[Ù\WA=N.:y N@ƚ?HwXV= mBV.n/$$Ϥ,>~m:_$0h)!"ROE.k$cQ=6*-V6xvI@*CP.E+Zҝ ;!;je'-o^19Eve^TԮ&"zq^IMb,O2;vт` j*?1{pVtD0©b*kV<:綶ߥoLZc(i\-$kKIJLm 1&UeWIAHŖA *>T I Fu5.hkL5 Qj.6Jd2I|h-e;GKG7T<ɩ@mTEsJ5,5Ƞ1V^Ƴ6ԇnڵ$q-3SMAsblj*K7Za>-eL}Cb)*5<Ʒ}$ MoZkuov5ijp P.CK}Ŵ2oiVP] Z%)+hKe3]I(X#>] &kPFPn!AM)Ѫۙz,}͛y[XBQCPIQGUF-M)xLU8>7P X5XSI{s´s Bo()PXfƵQKpv8v6lɷ/jME]2^?J8K U([{GsY=Z7և`PjG95?+^1LmY&j@{*I5j椐/lŏ\XVԣmNWI)hoU<:Ii*#Rn4嫣4ӴV#zE <0{Ox<~ZYu,I3ɩTjI(D0HCwKJTUܖO[OCy0 B+&F9b?<8u&H1tKk 2G}EӤ~I>xZu&?Zn_ַ}o{N0,uW}DXS厹<TWN(N}'E)$g[iO?z=Nsߔ ێ.@{}z1\ tjsp,vyƕW>[I+a@.,m?t8[ sSbs,䷤ [oj*GSc` ( ?ןt>]8>9D8mZ>MP?WO "zxH fԤ-M}-~oZNϧmAI9^]cVX t}-o͋\CϽp:,H<)|pWTzG" ޯPgJNH ^Ot+kӡ> lKbے b9cOz׭Z3.RĊH`b# QީMGV,1AF?I;!a} ]ي\_{ˆ3O?tM'VaWr(zggY#a+k sk{/;ط-d۔"VLĐMEz)[LcjȸMe{wk Pv];y.khXy~ΕT+s#$mQ1Bm"@Z4-*jC)|o$pHѤHeO$cªK! O{TTS48jP h3TAZgzOzq.8C* N LZH&*K{3i!^G;8]B:# T']oOmL3iB?RE;l0Sj+fLJU25pS풢RC#r4p56)yvCbtԧ YI҂YRhUF [4#$5f}uV?dwu&45kWO9}~zzD2UfhCαD Br ט=F nF#a4 0jWHP*hi׶?j77q1GF+PVPROvM84b'%(x54-!Dyz{g+2]zN(IY-]Cą4(G-ň92/&%&{M_](KEEJ~IHsWפNG[UOGI.?5dtFiuN7)%ML,5*KnMggʐN;P:V,\%``iE nٵrc03Z۽ncUK-`Px2)Y\SC d)|odtbŒlo{7]C4襕JpU<CJt6vr~1)TSJj66ԫ}š걔`7&mQ[ u 2Y#w}Tt1%6Ҭ+"zw0q,86-*8SYEժ\]ɢEPtGR Uv6L*ݼ^ٯVP5E1Șw'k$2IDbs2Ū9NG.AҖ+,W9(=grzIy/9J$Rb:Z}sifG9r[CwbqCGZdGcG%b)DØ$.BRx+[tBrjZ ujhHZaJ{\^69uaB?P"4xV[ 6(tc)G`⯨mQYؘN1cMM8+qcV(e9 S#m!̲M 1m\rT g>A]J|EsSJ#`j qSae7.?k',C Z4mIkMVm 2&7+,鷺tyHP FpVzNmdaS" jM>aF-Y:,7 ۃve[wju\gWncL>Kh֊bާ-}k*I#E ŽӖ *h:bv+@* A#ʿoE+'{uPkql}GVfUM5<zͽ[EEdbG.#R]A$(I,hARt[*xҵD~TNWhj~gE:^mfuT=3>Nw.O >^kNzI,"KSlVGiLZ$T *ODxg~icOԑ?$hjbqPPh sdH(2xHA9488R)ԇqQgp꽟Y݁MW.Uʙے)OξJ:$žPIxAzlvߦ)s3"jJH@ba^] %BRJvHBWV^_<PE^3MAlLmerW,-.3xT_nכS$QDdec 8`@`P½n6D5W ˓^$W>f4b+72CYU4՘w1z9dg(k*Xʭ9RA RZpFIxRSC" WKԊO\z9bƪC973S'LIX=3 ,b}# R `џOĻ!QBɪ|,Mj>#SxCqT䦠< ZzҐR DЇBW)RBǭ:1(":8ڶ+5UxgVQSGц(Ce<tzq^GB<23O?|q[LXdc|v :c"KM@PUTc<G.vA:q41֬mD1oFb~mBJʍJ^&#d+޲ufi饧,YalT7=6%3:']]!p)B7?>Eht?i~=RAREg Ev^rjM[ݰahTT<4jgx6@TaVm6&=!;f/:*2-8cVAWOEMEY?}T?MQ%ʠ)mR3)6=>D %;9:Jh o'UrT.ە[3WVKH咛#Z]2c?\!+:Mltb Ozb ʃJFɩV^ܦ9JJ8aVC_ ELvhFbHkGYdf+AR>ބvwB$q(W+:yHE c z,)bI}8})v.RyuA$QG#u"l-M7Ŗ5kۋδӫSS}j?՞ҸX1}jE5FJ/kǼuE{pl)_32@:[شg*},!\Fe|ؙY^x F}-w>_&~hn8# Oz_֊mcO)e~XNE<*zg”e{Zb/본TgO85K)!U-_)(=<| xS9).I$YNdU{{Pȅ@)'/MMJXI ~u_6 ޛ;>'$}+C;Je⮘F`-n-_u7ʩna~+z1|{Qiep(+pxDk:繨m+I_ N ~3X]iz,ڍF>4/=Oyj6zұoJGXs g:E?/"ka!5c:zc6˅r|OQdִƠw9 6sT/?̮c}ۑזjv?~\DA6Qљn|W))hXhUtޟGJZju!]sG4ݹS_P֟2knQ[DG ۓBV0JixGMH)ykp4) ㎰PUƎ@RߤUbI!c@{^sEu)ZȩOZqZ~C6MOSL_ˤn['V5tWm%pFfĸ d$|HiV@RM:{{488G?>b&F_Unkv~lQNjMO&w1Ĕ⍩<(yL e[%<\3;;EM|NH"m .W `SʕLΫܸ*ձ^*g(nGؐS%IA?_־&YS;ee)#nu5 И*fEo,12_؇`n^)#E)+!iYFijք7^]wY$P?QθQJn*AZP"%v^2;tU8̖B7w_-d A&AZ]ibCK-ƯeK5_%U'sJ5@⥅*GN7"37{}٥hd1[ٻ2{wvVwf*Ǽ%FrLM5 MEOhc]$;݉9ر-T4UPAҊ(F* 8$Q6+].Dn h0㤢CW)$@]%smfa.Ҭrx=/bYUn fHƐJWECjS*]5TFsݻ{wb|%s,V2JO["[{-*!G&o0'I8QFC2` ^OiP6US7JY0ZMet<ڣg^ܪI扔\'1IQ< 8dq*:**5@4B,|e7^͑0# Nےd%gM%lΪRb$Y ٚ YN PχF{5lH8#J'|y|~ܸIi0+9Zz䩮gh,my70zOPA6{$4my"0H(iJW˦yGB#S@J ׆1'^y6o7y|^ۂ⥋ɑI4ܕyA=¨?pQG24\j+SWX_p HPNqJQҞ} X?1)Cvp 7^cd_gʜ>㮓R/'+1[^\{xʌ5+T´LD( jH>d~].p{?Gp%ڐQEm6k&ib9 zjd5ͤ]:&lGO85\:ńZ>G'U+'פj|M6GV?|j]Y&Do2RV嬱H"# EUlu_T|2٩ҍ3j*k-I?ŁYjI7HJ5 sa9: ڹ ~3tl"u4DqUJUDŃXtw;= Tj:N=>2,@/0xq2+ǣ_܍^N |*]MU]A[jbf`tkIwC+-mOV^bR#@-IN[zyEx[>W`Io6ӳ ʪ,^KoSQSTNԬ55n6a{;5vSMMsB|M# X`]qQEsh.wqBn2sjK73׭$x ~?W,- #X"hn /N"e@prAtY#H,U< ^U_|EO032v՜VjM8=!WS%TΌ%ߓoSEU{z ){+uqx!=U44lhueVHK̻+M1 H [$P#EfFLk@)\c+YշTPWSfhޠdjq?ﺫ3i;fڶ3 ݶ)%- PaSZHWy 10|؂F+P*}}:Ih6m=QW+Ӣ2qdRmgj%YHQ>cgmL0&Ǒ8=z=+ ..J̀>VKҵ)wuꃇmo=@݃ ,T5|vC 3C8 Dhc2ȷfn6{!Bǃ`yT<)/os)R82āBGLtH{[`pSՎ#y)ᖺZGLISQ1XEvɱYPmCVT<|ӥ) wJPdTONX9bMә15rTSᢩ1n$qIW-șX066aq↲Ml(M(* ^#oBа!6ܕrVչ*kDK |D򵡢NUmQ$cHۤj<2P #׸y~<,(V@kJpj|_#CS:6؊:Z Y]zެc_,qT8"JirER9As8tu*N3}mɠ Ԡ!@EϦߑC>|jbqS"D*u"PMce7Rb\6']+xy?@#rg(dJ5$ @l. B/#TƊ~)%c )JSpNXd$yJij'Y^E% u[ {ԀjTׯH QZu6zг$ĕ2&QISY=JI5zphC Wa0ub**`;MbxCsL5O=(FSpI,=)Ӣ@T]K#_(ƂxZ%體GU?m;Ȃ7' ے3S|4,yqϨ7,j1q6M**EU45*YIksqڋzPKNWKJM?6tRJNL H96xP־!O3 -m%}5LՐʙ A 'zFuTUu$Tp*~\*h=|ڙ l̸5Hⲕ*磦AO>b*W<5PyDp(`2M5:jX-( j{OʠM>^(nEx PІ`Yc^(<~~a?Տ) p[l bzQb{^HEjF%ny}&?ϭ8ì} e'$W}K>cˬm|TCp0*@ 3ǗT;|-B} }Ie[rMk0{u7{j~N{8Hjq6HL 9&PIBs&ܧPO gIߖYH2m</%7tpmRcj7 v_{VzG'%#n οlz~0u|Uewlە;6DY7EQ1 0v[ܑ3In6J*4xT FOA9Gek~AqH1`tӉWkTpKWSM2Sa!P?M=3L|_/O>K$@>d tBSZ1rl OvrUT< gP_i^9MqEhF~d<,8T{ʧSS$?h,DAsL {_]y>E1qZtq 5uŞeHmLl,pnݜMtӊVJ%kA:_mJ *bV%uS W{do);l?ўl6f4yq2(4Ȯ}QC/jIcxWKS@Afnqѷ2yT0Ext\AA7N_**Ŷp{kS=5?9*0;nLm Xٚ4KD=`bHM"y5Į)F.) [j]ВfEJz L coutOit4B2'^FXe[ ?9Ӕv%k@=.8_1IPV駮6=:zu_ {.7Dq dg'<a!G@6:n6 r1KkdC"QBS߹Slt[ՆDu*A 0SPCiUԹ:c =r<@ s^EHnOZjӁ }F]i$D]_ciܚ#%-jhAPiįqS'RXGoퟋ#S-4[]켆f[Ɠ-6k $!fHgsr2C^ɧ0aS꾙,c,€RE0Wϴ\t=m;s͐MښʤIM[?i@c_GCVf`M.<=Whەb1+53t4Ejkt-%H<(ї?7>nm&!|rRWU>zgU_sH/$zK0 `B s'/63 WyEC_%d>IFG}|߻ʮzfCOO%ePc)dx۟hce8G"UZGSgKzwVY)@eXAA˫}r-,-&nέX1Rщa vhf2E31Wgm/A(5@ )\ h|F9l]&mU>Ex|FʼGB^/(TN|N; \FJE_MMĎ!}s? e$ETf:>src](Mx0>c=w6cQG~lNu_`벩$׽7kaj"RI,w .ޓH|QK!a ՠ1BP$Pp=;*mg{"*9) IlΛ]O ؽW6]i&JjFܙ8PI#Bi%4M\[)$V;88%t=KDhg4BjN;uyIܵ83~c#WV{"icCfz67_COa̮k_SPcji 2jrxW%,]]jO-kR+4" |Q'4T?c$iquۗq v\)cU"0OG*on:#]J,Uڞ_io< : {vc1}KnR!+3i"1,vc坮&h,6eb4TUd ? z.טwQ5`)n T#bM|1, w 1h Jl9Ź;SenDxJ6˹եd\3[&&REaZE9дsDRǺUUd@촠8PھCjd#w>z>(m-M]SYOCWচH^JՕxĽ,Ch z[Q9(h*)^_ԞgYuIüƦT7ܲfSo#>s%)$Ði')L1@>r}K-E(-ZxQ#xGVNdPtoB@|Y841jk\A2׻BozҍL碪Q[^#\M GY^W&%o''IJ)yGA ק]jA^_ TNfy\KQGR O5CO)HEzZ ~c0͌kJVu)1^VN USk3 Zjj4 X\vGKmLNuj5-QOCQASzz۹<9j;P8TiJ3![IZ<}-L2;3=2T"&ňf^@瓹/vMcP:UqN*k”C'm96u!M'W~F3N*:C|&|$J6&dJj|/w[;WD+EŠGGjd%zSnHdY69 Tn&(5 W|&ۘZ$)!WZ=%zS$ ̶ ǵrsJ|`!^8ޤm{uvޖ%¤ù4/QMWOTiҊjܭ<TFN'dU J sɞx-ՅTʧ>XI9ӶϞrx,H@*)I.MiǃS$m;ԥo%Dad%EG&UXMEd{}>aڸZ>\N~uu#S HǯJgg2hR7Y|UUMJdeW F/h4yF r+\?*\ t&7i [6ޘ9hrђO`⩍<%lHui'wZuO |^Zj "=IVX,t^@U '߽Mvx!_cbƀnm{ ^q\3HK1'XϗSxt'am)*H#AfG+u5!3J8CVI]M-tU$RQۂGvń0R8eX$fc9j+GcBkRUsZsMwFG.ո, D6-nUH.@}h<#;<迆QA,?.W^oҖeH=jr8@bPq}¼zK> :vI1Mnq$`*e1!4(76>.=wyX$(Ѭ>s*+WkZ+.5f3JH|5ꋳ&@t,KF1hmO7m:+2p)58RO kwJi_JcZֽN*8 U%)U앗H,xuFF xm?=$g ݇ MS5 vQ}[V$(p?L}t@jky،^/x0y@[Qb-a?lZ2Fj>_#^w[%@G8:;lB]^/ Y504y!C4stmpCSh|?fi/tv.Q+)_-4uk;SCG5b$P%=|,d'8_9|&h tȴ UAX?9%nŜv#015{'[^zFbAoR*Ըaw**QH yؖٹLo`=Uϼv:Y_\c֊۞ڻjuV K"ǎ b?f?{vKݥ!0mnS[eF.mӝ9uykp~\zLJ/Q<ٮM]H ===:8rZ>gOm8)a,,%EU }B2 q_i_q1ԈYWҨH2ݏ+TX蝅tfK԰u-]xitf?oKh J5St 4OsX>Jm) #A7EBP΢>UuWD^f~}@T^Û=EJJ:H?,7s4O3}>ujjٔpL{KEKe!A)HpxXP=2oν6#clھA~")9 ![TkJXtN{qWia W=e?o P~t:)ӶۛZ2>2s^Ww^E15%XFB9#beTrMe2U ܭJ'u9$JFSZݨVziPZL\ۋpmsm%YS9+پo`yXȒĹ1&RN8ֻHwgf2) Sf`ͧ[Ues5*/kSREyB0eqY#2S5:86#o>2g?ҎbӾ.cMy)mK;*Ufy=l'R -2,|3fG~o.Vbʾ-SZV$Z#֝4s82! "qJ`*1Nܚzedezd$qR?^HƂrIM#զ,CE>LP=n(, V kQ (s妮Ẇ2ӲKi{&&e&=Mau`kR8\& FRZnUaLqԳv |-=e *k\z~46o}0GA{nn}븢*Ԑ- Wψyyl-ڼd+r~?&M{o9wl@UAVF<[rTߐ=e5%ŠEχF U%cJJFу qTAJ: hAԾEFӟeRs'M9NOG v[| p{q4qބ O&!90bN;΅XhhƩUCv],6*>l2= )yP7H;ik?J﯈>tue\:MO4)vuԟlEv⢠ 2$ay*(fn ~.@ܔVÄh Nj} MIΛuJKC(#r~@X*5PEH l4@* ʳDi)O$89,6ZU]>VN:%f*|`S_ >P_WQrAW##jjBɪv:P ;,0kJZu(vhO|ɧǗQ𞆌)`d*ԙ}Ż*4FS[LT55!$G{<&U9DthAor,r20Iyj}4nQf? L}.jz5PWVQ0]q`-neخ.T!R&3ӭ2JcP>V| 01O=_ GYTղ')K.Op$8b%B+JXWDvxY|Պx+?I[Xm7y*#D1AR΂I񀠪J4@O^3yRjz50 Ugohb4$ǁFi I5*†I:{󥦩*z:\2&_ %4ZjLy)*k{2MsBkEkA@5FJhj NK Bvl-5R@fQ1unre9,|fUZ %/_mM6 zF2`ȑ~nf&q4I.F_IqC<t>|e!&Bcp.jO5C3dqv>5" dg܏sTS8p2( p!\^M^"kxSĕK-QDQ4ԼYqD˭R &8IFߒ*7P|8fP L)Mu&LymS뫪qoJi9Gm{2ZOL&ux!ΕT Vb`Z}o7X-˖D<V妞8t6oϺҒ=ֻ:4#|ڎX±5[U 4BT^۶^y E()TWh}]Jp\iDZVMjxz(ENxz`ic~s ;.Gvdju[4_dzQ1#F)S4h:/ofvDDrAL=szȡ Kf@-A$HOY@qSSfjVԯ0CT!'F8yt_qi.SiƔ>G4=_v_}z??F/˧ǣkh^ =>/WCZpuSqO 4ץxT-*34?kĦ4K$W(,n~kE0>#>GEYc/BUH&Y^8YHB-ًV]mJ'^x:s|_ 2>VWn7,,{P]5JFK4\ *}|<lϏzj']Ŏ2&FR/ŭXn12a{bq#ڽ_W B8 NZ3V?Sϗ­k8O^o5ܡ_OA}w͐f Mˢ;^XaF̀m آnwE…HD}WqNsȎV_4i |X6v,cmLcF_EgJPͻ=h9>MEj6O\~|1'wfy9wZUg^I*v2 r&; q8Bʑ L?k2$E-ޒ:E!Phӧ?Ip,WZܱD*}R Ißߏ|-Ym:~Ļ ]|>UUz s{Civei'M3$z"٤;% (#GEsmGJLΤqN֗/4h H(FdPN.ogPͱ5֜HV:(2WЀ.Z2N (b6sʟկ`_/Iݕhִc]3_n$k1mmZIX}bX-<wu_8E=xtY쫓YgrBThq,Saͬ=NHUZ}]*m\T]&†y*V wE+ X2S ''O,I!nPDLO@W^g:T2g M˺)^2ǏϽ>DWt$,҂~g^u7fM{P,nH)ET ak28lc?\RI4&wP9جrQM&}E[[EJ`g6$fSqxtFN cmg a^ܟn$d(^֊Is^'O-[5e&ei+_M%${˗\5ݭ܂:}û@,lЌ\)OqB7ϳ'57SE[ 2F!"I^(ʌAeQE3u?1d:] L ~Z?*z=M-T&ys9#  !M @36ѲLxUcq'5ACCL|v-vq=<<=A OКxıù1< щ04r H<]|$&sZ紎"*3՚KVdcZ4:BiZwNʈ%45;eɢ<Λ7"Cn *{"8qmdEz"Ǻv&*UB"BSގ7wa/ap dBlg+E֕$Wճ\OݺJR@!qIL`WX.K}fo%0#"{ r kKs'z `}<Ro_ReInePR;evQYTRSF 6  zc)ĩU$ǧH0r 6+k. ղ(+?Oui$>um&TYW.׹ td'2A2M<:t JR4zKvŋM3ҔXA|4I{Բmf,F(q:i;pi_\u8풰[5>~M<򲮏)QIk)4ʑAPcNI$VeΥlpOPc:meEbx@n\b~MAto6:*\Zա U|Go8J2UR92JdT}u*G*(2r>X)ZV`NhǦN>G(6__: t=f 4Ⱦ>8[u䦣ÁZ:9۶4rxc##ЁIJRi-gJaK,Q(L/{a6#|@<T]m9xg=*i2H5g1y9AV)_razʌ#Գϲ˹!"F] j 4a}Cyv+V?ϏGjmXAK[;1LílIk);ͤtWJ+SD(= Ds-K_vmHkJk(>U[k0HMuW2i7NA+]ƻnjM̡)LdV:#W1l-Qbw>Ct0=;Y f\3vi2~Qoq݂& :RSiq0571}-<-P Oz,w/S+oK$meW70Q#'am/sy#+A}qSOA۾ݣ X"˅3P~΋N ',ϻ*h̔XW?nidY ~n=/-)Ҕ-<|^W\+ֵ Z|Zt yBUdPgDbI i"JvFwg$ __frCANȦ'w#i|ʙ~F{TÑH-doIux7whDgZ &O#=3:KYC!pN8cg<1|(K|oe*X:Ћq`?{A'%ڕ%֊jVj0+Mh8J{ cv.j<3R酾lofuj) sTdꖢK0)Sjt:>@ۚQx<ֆfFP`>NA)Aʙ)%O1)Cm.|&6Ԏ>Oov0;uX'Yi)}ugKNWJq#ʽ%2>B"o r2(cb'T%͉$Z2[FիSđO)Np FZH 2H3Z?x7^E6ӧzS5~_.ֶo lZ0𪗌h+y$+?kk 94^{-pOsS? [BJh7 cUڋ#YKj^Bu}?|lf$qPS?>w*>:Kp8e9CW=s̍mF",cEo˻u}(㢞y9sfJRq-&I =TXibD`5gbno>IJI#fwߝOB+|JEEK*EeBDұ%pG{(lHi\;rkAz,d(5p0Yܖ^}-U!yˢ'edq,VāǢyYm܄砍k_G +r;,I<X\6HϤڠbGq?x_yXUmDH?l5]tWǦuPF?=.{Cl/AQYDq3uYs5Fj1z6ݭP't"vUQ/K]GMRV l?Cl3?owPBzgV՗Q-L\Ž+_ֿ0Oot/ze[7xdJmK ~=xiGZSe%X>i`jrt4訚 B~>8sr"|=, ST鎳V ٯpljXKNZ@Jr?˰ 8a<U; p<<ߗI{'M@TH`DHđ+]sP>*Mc?:a]?#_z;bL Q _CIPӘ*?~+wqbc8À>-b`GR*#OSmr~GyqJ&Cu8J̾!F8'Bx4Ҹ?=>O:g>S %EL$,3>X(WTSG=GtZ=*tǯN4IUsIZÐ]V 51CB(AeQ I 8OCBcHgPW,{ + *CSJobZ刿oGqF.C86֛KE(x?N@vT5N9CfY;6 Q_ƔO\ V2$9|;TIXeX+HY>0N|i:FyB_RHH_^ؘzsEUd!I%k-huJj矮Tm xni|}xrdvu,iSZSzq Pj }E<-<ew_K3d,&9KyyT$o1nVO& 'ƌtj`^94 3dzJT|WG^b=HQ*DISiUJUbjB;'?>N|5kĞᯕiN*["MisA~δeq.8 "İ!8EZh+P5c3Vˢ;UdAָs|N*)f.X* 2UI5]DiU-R2-:tOS?׫f԰y+D0Y#VY gfhZ`d1O!qJ֞|m>jeznF01J8>:f-ưWuU]^*8MHRqd[.H&65w瞒Nhʒ%93G,53$DMJ-H*e4Y FIrZ* 1?m/GSu=IJϠ_qaLQWg1jfȁUǟMb#z4M 6$tndEs@e"r+'rⱕ#<vhZl@qO* &#]mm#)CxĭR7me>nm.8 i_8`Tuum*OJ1S?ȦNc?G;>M) _*qd ?M+r áaZ5?GJD dtm?ĴG(~=**X1b4ybβ;Dxy L,Xi[-*DAAjj< 1ь1)$&x"hs^US$kOۓL~7VӬXfK#Υ>nNp^`J|@,Phhfҹ p#4YaS!1ST$1+`1DSM5?mOCRO?/LJTEzWb .q!G! Q5(Mn >RE#鉠1@Ϧ挩7j+S^]%ՔMV',V9S7>6F,nD1C\:x&^Ixu2dG<#~ -Bb^Ox5DTyB{awHIb3 _KlE`JIǣ?_[&3mlh|ey4"XT,G?_KƾyZdz\=ў!:@ 5ߚHd&Ykf`+-u]uSEDq~xޏ|kHp% ='귷`ftBR%PWf8˪H>o$f7 |Fw JHPV5O[27ff1: E?yB[PhqA&.7*rkJp|cMՕ\G4a`۟icč 7!āՎѸJRjN1gO=?|q ̱3d1h20stɹ mۭe }F@(qӱrNu f0j?{8ᕿsΕLڝ 3_odݫA 5 ҀSԜdti3r.A5NNƾ\EMj0gPAiLaTykJrycNa@=IXPWb4#,PW?נsmfkUckagDP9h$s~g-7XBO:εygmqגTzS@sJ^?r~/i^7suVmkJR5Wӿi^<<]bdÑgnٮxӫMͽVW^_F@H}() +3ʆ*UuȨHpH;ΩSqՙ#9fWY#(SF@Xi@ {{HϭFJ\*#5x$v\ɱC!q vyt(`hqcʼ2*Zߋq>M,>Ҩ∏=@/ x<+(dꄎԢQr,@r >_* P|O>-Of֎Ѭ/n.} E?f=:G}vgFTX #tVRdK^%{-P ىQgA=\n~C:RU@$>1W )wzђx4iuF)ZN/v9Q7 o!P+^'h᫵2PM)_o3]ӼZ5>I Z8Q1'cS} j3.FYʦGWAji*t ,j]\i!fo$Ȱ䟭%C_O_H", 1\tdq?9̂!WPJ !,]WZJ9ئ \pWwFI>o7S1sm+7ϐo˯$nm?$xց6^轚Ct6ؕ/8?TTz<u"\fS4{d32Tȭ4H mZNJc}:;|rÍ*(k۪k]fZYY}(>dbl~ny{pZ5`.GGQ_S H*tWHjտM۴LfqґtŤ+;'E>KGtR87_xO?3̥C OWFtkr?>(CD?#._"E?:ܻ,JmhTiY\=T櫃q:𾞕=?hRbmE7]R餀]Y1ӆ#`b+fX#ӵ z߽theS*!Y R8, X" PTP< Tx=Y5庒Lm{KSS5*x,(sn:$ਨ暟;U4#(Ut5GP.降yJ1{@$E{CHOE'w+)3<$4 h4)AU-j PH R2çRHk(k*E43KBcbGuwphB#RB|Xܘ"ڪQZh8`TW#9A*J(1ckI(jW⧴RWVCQgYjj,D`<ЂBPS%=À U"FE5*BGv' |/3kG\NR7QRU2fr&CQ y*ڱQX{"x?+v=5Q VT0%jIA1ybA'iV B N@r?.WC7KD]zZezTg@UUeǕw#(]Pƪ( I$ae?SSiS4P5N|ɲE tjȡִ5c*嚝Lm4`H+%A !tҪk$:*ބ6.V KLjf\ʮW%j͹#F$JSЪH@L(Y1O/`+A4̶-c%IEx +K4 Mz1آF}E$pAQxݾ"W8ص[U]Q Xmsukl4*EQr@%Z2dg$HPTӴljrS{!f3CKc'Hb1L%Ȯ/J ;PF j+EI\egjGoiΝ8Sr)Ӗ>4PAʢd &;;4U SD<^%,HknϕusL㴎֠SMz3O4=6^V=EHS8O]. EG6dU;ĕ !K]u{_p3Р$OEYs^gCX_uPJ>gzR!骢cMyd -[0H^+4UqUH#\5YlES5w:js3:`e 4ጌyӅd&gb)6Dž0OOSR$dx<"ReE5 S55zʃEqAYE5-E/[O59 D"sW>{*jwfMI]'+ 6k@B'*-@M*F)Ǥ^Ej~ٺxr4  S] {2-7F).n*X_{)X\^)xF-ljhEMj8TvxKSS͏Y'2ٵKR0%=8eY ڒruJZpiJ5'iQգM&sZupJ֙_鯴 gO4](jj#Zך0xb<߭6]^Yw*YiG 04#$JyܬQ1n 4rH$q ˤouݿ=KPwβT5UaZ'2HI&d1$?8YQk)SZ& sHA{NxC<\.'*C G^%zq4."9,^Rj)m)Y㙢`yG {5M`F$dz(o+;!:EFB%lReCX)kbA"J4U4Tg g%XO,eQ5$l tZp DB;7REuzPdd%|UliG4MG]Ki'0۳T#&1Jvִzb/^2*]֔^8'4UEk!I ͨY‘ h ?CtPmU/P @@Fh?ٷK)ѓ,sJL3 XJ$6BI 1+H^MfF{Ds#?s8sk&£*VW3Q{֝ z)I!w]ZUb I?ԞE-P$,C JTuVwhbf`)B E:nRK>UDuDeokWCߞ}![FHK`TS׷5&GmE jqK. 32TKwfZ M)2 p./ohfz͚UC_{V`c^4:\2{L?y1RJ߲8VH٭o{f]UԢ*>OpsN4\z~fсu6MSOJFNP؃1㽣_çߞc$3dR@ǤFﬓ3Oi(1MUBe0[~ 3D ,?HWtCh8)+8 d},ДTfjT\1Шikh(Ψ0qZk 2ASo\Ÿ+mD*tP`֔5=Ċ5ٌ|~򵐖kW7Of0]YޢMǙ נ%Ŵq&,H#P SY=OjEOŭo~]tꮜ{Z꿺Fӯ5iJSˏ_^+U b˩=N0bUKzBS>~R4Baab ?W8"A/<՞mJU銪/N(ATi=L,ů,-?,@žM<%wP)ZBnltp?s$fJ0i4WSɇ!=$|j@<J[>e*;8S_OϽ+#񾺀4uziXe{_~g˫(AU}:eR?˫"TK*3XmwH)NTmGWϤN}9Y&*\ف"N 2)@ Ujcz3k1I#)wfemEؠV6{nFPW%5 ޔRCMjY4uR[]'?{N`d.8GzqAB1~BJ,I"9bP@*pB j= n? ݳcA1j'Ył i7ܖRj?WxzKoB%J|D7OZO'ef`dlH[pa~ P&Njj"^](FZH}a-R̍H(j 0S$j Rx~6>gΟ`*t.Vw2WϨZ6T48GXfa",>]~x.FE8/޴`t$_8O,?\RNG 2- zө&Z&o: V6+~yuRXT*48zӪ}5uEs v̘^׀;K <4D8FPXjcW*7+mo3AZPyg8v= 7MոA{jI'xTġxNNEB23w BCLT? r) zMW 1[l('nν6DJ_:SӤG z "AMD塞0F6VjYu\ >j,(ZkN;׫5gut:NAo3i!#AtXf3'pod;aݝ88$<12m3)SZ8=#Bh3ȿhc7[C `CXr=]3 >uc .Kzr\,cHxgFxx缲*b8ϫkL5*Ҟ\~gCviIрI׋[h7 ߟ" yτڌc]*0{;8cJO3n[/kIFR>Jc'U u#.?{"wM43UzzzCYS5R$!G$j Ƅ21 `}UHr3_<1SN>G>]g䭊:dhciRiQ Q*bI {Pťi\ңִ8oT VGN+pGOz.OAQ 8咢S]M9J*$QuXhnd0Fbc˴y問 GtAd@E~:c)*Ѣ?Ĥ9 Q~^h c,!k9௹0R$) A`կZRA'qެZ)"9RzIϲ2t5]UukFeR)I$y&IuC) qG(~CxcaG5Vj4ШRH^$f8# = S PsCiš.Ub]sPRQ*Ԉiw+5E٧e.UG _I$|YI5P(؊9MF:h P׬0eZf h)]qsU`ӳBG, VFWL g X(HK!H+J{eDP` i]B 0U9l=4PVH5~|p3AU SZ-\?Eo˶VV56"%}JR^KyKZP;A @* 8 ?&J"NReX䫼fڡFuԕ.@J:Zooi޶xU\@+ k 4&(m1ɥMGBT$ "eNO^s=Bxxх#H j-ѡBjk 8/pOkx̮kaƠyH8,[o)@љXt,L[+ȞX !zY6EBu,[\h[H1]֙+M(ҝB/Tfej@oh^QR2`cK riL ft8 8:ꢹ+#J*7Z6j?JSJg' 6iZI/wI0X1ۅ hS{[ OM(-6Y*m5)6} 7YSOS*~TA55XHf:*QgC6)mqԌ0>ѻuLӁ5HB()4Fi^ '؟ jXmAEɊvRY,4]Te `c2\b+uJ3$5`H=]\u5(8=G[QMLSn U4gLZB"ܴVSm]o[<TD@:]hBGLCs؞51;U"ԔH-jmmH]L/悉)\ƴY<# YF> +nn%K)X:PTF@dA6̄Af:J+CSv>T4;vH`@DM%1F$4޵y6|^rY-,AH֜y[P@@'ކ(cpIת޵ 500G^msfCBpE}GZA :sOF$4e{yփoj)P͡^yC).fIvnъ4H 8'6d炭 rhsP*j=?21^5Wy[P8_LUd '}<)yD,JNOCʛ*RR_hA#+ĕa$l8kf!K$Bj;hMA<8hfpoOtQA:PW$uLSvlL'z*) U4%#lm'"[%ɂ&Ei45Z+SVݭCӫďxFI`<ɥG\PiLjj3oC F) &xJde{D"؇eթȞ8=[V4>ٿF#^h˨|+w40,h`F c %"-fMx>SO0 .h.5ZaQ(:Ake&gur8W~ΧGJG.YbqXҏNH{Ԣu5^Ah=}|x%ic+v5‘:H]4K0 c~Z^>Þx(%0VӀ)oP*ڄw ss϶>I'5j?]2j8=:J*V4P[K'"<`)#<}Q)w'B[Y i8A˴52! Mch"i{n0LCp#8鿥?$8',u|!Z^;H*GS4b9r4(~7.abNx`"8צ_ Zqp?H:.T(Gγe^_{70(7NPJ׏^;w '֞RHK."<*%5 ;Fу'Kp-WoP(8au͓ 5<*2>u:MOP3$i8/NLd},E~~:&Fw*h-$8g·M^rĈuM",*]@]AW7K +As`IeHF ]mT*\8M;72,;ڙOP R3FSoepp ` 05y9[zPVA }OEzkbpQZwݫu/_34N .Xjvտ+^=&{xUo8W0ˊ2NHSNRD (/ oojV+ 7|E Qϗä! <=`>L9Q6 ݉nS\p?:lI(}?=62QAQJE|NV 4HYg zX䋋Z5짧VQL^JW5uSg3J#HVu4!mjR[-@ m~ė$_Zc?g'1 SL:ktRcO5BL7EA?_mVnØi_tkR֧]>G@pSX-\\hu#UNujt>,((Y'IR)傊UPzUKc0y**/C#F:6r QN"|uV.5 Ca#jp Ӵ,րȐ0@)vrL5=T8)C 2+6ET/?641uA1R+jhc dʦ*G)fdcwIZN0a^ J_nqء *PNHƵ (E)>^ i>>lYh+N=[%q_̲uDR(*sr[mik$|#`XVXP+e2kV\F*AAӠ(HRӺ竕J)<-X9=@H+rS6y9ñ ՔՅK4,ʤbVIOuWwԤA ϓD5vyi0Z u jhT[s+HuϓC@@7)zOcPE $5 P0ΞT|3j-GUJ1iUX髌$AV$>%fhR5H=[{`VPt+\n43)d ]UzNp-W'2G\`*2hI58'3%J"ʅ &HeMqف9nU#ͦDSRP'=*z,mqYkyd/6r0AQxRw\ż؉ŌA&%u.iGƽesX!8YC8c4HŬ[MZ ɍO|˖xJ%T㤑Nz%nt$FV5F;P$ Y+.:#)zԡ`dJ JU A5)(h:7|AnYX3(!Hνpn\.GE+:GG0+!S@bU#sR>I=1p%)Ƥ&d7sN*qxY(|4 B#8uWQP<"m$10"RMFkP8GOIz*< (9mTAgdi#Z+ح[6w}Cs H֙Tv*}x7;魣o*(+@|Mȷ,?RNJ~ӶQ%J `i멅<ڴ>]?H-uMN0U FZTn )॑MQ *UA)¹J'c)4fS^4ȭ[KtqHq!Ie7 n ڨGr3ZWc7wʑ@0TB S5utdW^T4kYے3"<<֩C_LTԾ <;|J igxr2sTuQP@ {*-/&@cN+,vTVxrۤP{PwTtMY FO,13$[Jfk}2,eJ 0 1тnIuB< ֦I2]=iOqKyA?r'k:ϯ3qL Xeҷk)2:ld6Ӏ<}` ׏ј#9eY!|č*.RY]5?Zƃ &y"ʃ1* hf<[" Si^1c5<GК`J'i8q#4:PQ4Ăs$ʼnđ;TDҙ :Ab54:f m4 ҃:(OA$MXvmr NLhՐ F0޳sqov[ ]rCv5ւT60TE{CCN*5I"z5%4EKV>t(ڸ.L/EݚH3ʹlfYy )Ƹ<81-1K b}%X 5c@czBqpu*LK@5Wo@+5ទQ 4)G)f\VTz"TY֘ x#t)gXC6K xlic5ȡ>32:'h`л1DV4j9pHrzٳ"gTw*)C郔4|:UO-+bikZj,<8M2LE-" 4MS!+@K!H( ГMEO!Fi瞮ֈ+)!**h>$$MZ)b̙Gjw+18 ~OqtA  1'h>ɷ|[gJp~ UA-n9y)?O]ښ؅iQT_wWF PSV>di"%քSֹ>9􃊆Tq54YYqկS㣑aLSQo]+Jp=h$8UPTʻ7MHs)GR2ejl|H#JL%d4}IY9u0O5E8c?)Jj"zt]KP Jq-umDU1[UC3!)X䃆f{R$bPgӀGʆ4ySoge6HyzϟI>$UƣAKvjVT>97>$P@$qr2AbrH>Tru*N{kn<MWgA ,O-:F<<˒dLO:x}p  ČVs:`t'ZƮTǟN|gȴɶ-5䍵^JEX2~U8$0x\h4x: U8fMic7 ai~2uYE֨4Gf] 祋&E/F5_[9{(ݞ4"|D4Azu7gGP$b%_(#2q:i=Bf@)(1TX.M4C5jb a9hbqyZ+gS15+rȲʯm!oJCZH2q$r ),|9J^h_pJ͆>޻fC b\Z(mO hI 8$FVdɁCݵKGcrԮjFd #1mM9fF2zxc/,ZUfO iOl52F6]&k/5=( 4X,Eb6b@.(z_m1鑭-FViQ 2pTq^"[2I!ڭ>f?+Rl)sQ59bwOIsrH=x>kVeqi=-DYOS:LJ_M 3~cٮSr"b\Wi"`4QkQ*ۛI@ "`2i@ˊ%7ǽUL}uQVYҁ[Y)xƊuS"1Qy>؛}Xmb!^m 8Ja$F[uP QA4+UW#N;|;tfH1o!U]SQ%D-< 0@oIk{O?7C47 ,(tI58qJfzbYRTGTf2cX&Vp"1ef܀ ssF}r1厊"^Y񍵚E \gV*>c>}5d:'j&ç$xj$agyd 9״$@F'´*kNn_CH\1+µ _Ҵq72T ٟOՔtfǵժ:!>t|;AM*2 ׉'1]F $aW$dk6Hm^&"˩@ ƕz'k~8Ji@xJ1y#J6-[ݓvhHDCV5˪GAS8 Tzdz,<vFfiC#\\*aϻ}(cIOq!]8X>"L55R%j}t8d$T$Rۗ(&RlءH[{u h)Pj0G/_ϭD6?oNSY Xbq,m$r,TD+ LGM{`Dd|q<;k#qǷ8 xSE8TLb&S}Z.Q$+Uj Ҙ#ƴJJB.$p>J`֝9GRчty&VITU,n T8UX6+P0 x&UNJSK ҄Г#=I$TD4>9 Ҁ඄c45<V'(t*ƾ\)1rL)}~ ^QhatȸbZM1N qW ==cjdUqF-$2#Okܞ5[o:I(׻b<tF$ڒ~9Tz9=!o5 h(>4TT:w<$:07$DE iLI$ZD:iZz9aHU'ZRGP+\SNX8 1S5T),G TuKG=5=]*Kj`b2E :uU,I5d\'tD:]XSQ)`8 B!3G-2 ^x*G]Uj)q^XD.p3AVȡ188 Zzy(@ꡞirl=+Zb\cRPZZ3N#b:}(PH~-BQJ~J$МZMt(@P̴y~EJZIgv9'cM~Tl_sRRzqP(QBi51SRu%|Uʍ_%# 9(!r`$-ԻW`(@`pP88ݐɦF4֗Z4t}#NTHY|q \z"IXȥFHET B?%}F *j (H1@$j .M&j@4zƱw3Dzيgf))s|ZG/Ib5M;MSۈv&{)2v$Inj(+:6lc ;40QGsmڍGqg̥-]Dn9+UYE1EHAgO)U{T †hN:W]iBR*q_,Tq麗/K9ێX6-rBz1Syh櫅֪Ujug]LJ+ A*t9P*(9q3@00-P*A8 sn\&"*}2ɖմӶj)s l}ÈyE"Uyriۥ#]LՄk5R)R(JRg's,ӸJМ=3qB'E4.z g7"U9t/5𤐼3hV@gO %Kxeuk=PЃJ@ DS[ڌM 2@Tji PV>G5R x,q9&I4uU@ Ml--@04e 4ពoߤ 1Ag<:jU?b4j XG#OE,t(Ք57|s`6{MT l$P GEnW "[CGbK1@h8 ֢'+$E>AePVP6bO⢊v)V+\ uI m~ZlUi.y H 5iE;[ˤ;T55iAL&U[R1\˙ռf96B \e|SMWNbHiꤎ2M=(tKDf2ڃ(jdfGZ-IV8Zn QHXM}Tb8)&0טiѨ&F;H_*t-RͤVPAK șn52"'VKՒn8,UtXf%|/B~7VӐpj6Hvgl3-#O=vYjj4I+[TLj3z-.mK)*aLTdH9oz,srWV_Q=O/~ElViT+_YՔO%Ti/6@I&NVz$RYOˢ99W ,Tb'̜A ݟ#g)pQM* 520W >HZ坔`i(AA0Eq1[iF\ֆ5|ȧ@|? 顒Y5(Jg$3QDo$MdkM3pJ5Ďg5'2$2//@TWEiyʜDW.uDDn#v]e3Q; 0($R)3`|g,q,@҄R i".}ϳR>(0!Doa{Kq˛ 4frF4₤҇8J~m.du$HViӠ'&ܝfe )2)bUAplQy l;_SujF”Cݟ6M4~X*xz% ]-LYծP7vBZǰF$1$ӡA Đ>T$yK*:}R$QI/M3/Вxk;JIRk>g81L9Qs0kt鏣%Đ㨩`5xJ{䝖Y aX8֝Qøχ-pD Qk¬r{E)W`jMK4n`I/$ATH"@&w M# "2bg5=mJ2H.fb[ „/ʝ%*vʎ&H9tcP H(E Rs^>ykfi.h1Aq>wOiק~-ωLx\<.})SϣZxZ|ZW~]pisa-3.0.32/test/img/denker.png0000644000175000017500000000654211160170350014401 0ustar wmbwmbPNG  IHDRFcS0PLTE -&LB6w`Eq{ǰѽZ | IDATx^u]lWvg`%GrӧPe")E!I!))5`C5`Sl5H./u$K3㢀W9LacN@-M@lؼ|)З3" 3?{(>7Ek_>2d%T $<ᑫTTd컘MaYPC[Ua5i}y+XE]:0ؗ7Pѷc/ӡ{e5.aOR(CF0Sp({NO aҵS zykDh._h4:#XAt3nFwV^wIF}B(}ڙ槡fs)0 H"mҴ ! Ɲ+\u;l{^$ 0 uҙ!ī/$;YZ+ EG7N,@z]4Cdt9 U N"Al] q/ɴtF#H)Ľ3e6gC~P( <a]푼Bd v:QlfG'(>< G&EK"ޓ\Uυq_)3;^UZ[1xX$3_v9t?W^r4TdrđƐ!rs06ݰ6\yaW55A,8AjA-SLym-WU%FUk/T [dZ-@F{wC#e\ٲ:wuqO_箴m?[1$!Zc\I(ʹa}Ώ΍HRPw L\ž1" *ƀIkso|ڀ+PDB?lD3]?փ ÊH_?a~-g:G΋6af{ڽe^hjs*9]B2].˯sG 0AH-^fƧVUu]φ,]Q8s=0e͐HrySř1@6b$޵CvҰV 3DPG$Rߩbx :hC.Hj]eT!59 "I@ZSK{* p#{Ό$tJ<X{wI,q J. >2|d%I'p@j]qӚ?I໑wj sYM(\>K瑈ȵе왷8S\59雡/#jbh( 6.bV̓ɀdDr <Ƅ~Bh+Yܛ,S!7hi GpoLKPػeY;,!NvK["nZM;42$9̓lp` UZx#9úȔ|(4@a} ۩#a`k^" ,kiKFFm!{2'sUfx&r'Q|c3P_#dƘ(eu ruluKVpv'TːYCB!wa=wU,:a̲O%=t{w %Y(YȻI>eTbP|3$Q9J d}6;ֹ? __sͽ*:b$HdyLOv@ۂub3s(Nm_$D^cg<4SKXXA-4stHDNfM:sF?ˌKDIӣZxgPLߩUQ|$U5`*8p})@^M)#BV~\ǒTM:aEfU +d/J7^GXqZ&KC\Y`,ZFuu6#}K#5W RaF꫚QUN y"Ðk#2gJWXU+:3xu W1c،X91UItp~Z ͨ5k33ڪ/V(?)B sy'|h$U?'Cp8xF^kz3VS9yttvEQ"xoFtc:΢&?3M`2Df ~i H8i0,]Z^n1UXR)}7`V6rZn% @1`f}jVoit-'C&Y & KAQk-ƶuZT%Xً!t'Io\pat]IOMwb|ƧML_mz9G٬aCr@+AjX"i0 gyB=~zV`B߶ 4Nc(Y{ @Nf(>3ҡOHbG. zU7<( lÏGƼvJ#'K>hu>)amFZܟf:-;SԎdEXU-F5t :TgNɱJЕ J4Dr<{GnZ/Z%0fc {&?Z +FIENDB`pisa-3.0.32/test/img/test.jpg0000644000175000017500000022040311160170350014076 0ustar wmbwmbExifMM* (12<i CASIO COMPUTER CO.,LTD EX-Z40 HHQuickTime 7.0.42006:02:05 20:17:26Mac OS X 10.4.4dl"0220t   |\0100 >  @# 2005:02:27 11:57:202005:02:27 11:57:20< dQVC=@^ ^      f   $ !( " # 1 2p 3 4 A, B C0 D E F G ) H Q R S T U, V W X Y Z0000000000 0000200000000000406071224!@ &9@* 3 P4 P@xBerlin  $ ""&*-*%-"&&%  %%%%%%%%%%%%@" }!1AQa"q2#BR$3br %&'()*456789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz w!1AQaq"2B #3Rbr $4%&'()*56789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz ?dC\<I2~ioƸmP4ֽMh˹-O_D b]$8k'}0KL~mdpjh)GW qd ю[ssW3vrLj,DM=:L0Wճs1VHydI<6[7 !ىwG^Vf݃?1O  wW*KFNF%x$VϹ"~Ǎ>8D*PX'p`MܗS GO`2sX3Ze\,ب܃pNڝ[u \[Y6;u+GjN_4Q]P\ i'y"~8x_kea_ƾ/cuc21r}:(LܐF2^UFz+ڝ?O*Сjj#;vn5D6ǵeb<+CB+,7*~r+t#$6GK?x!t=+sY7G.Nz7c?l<㣲!O!r;m0CA-2p &.g!FaդS&?oDyY7|Js+go#_I4l¸yG+k~.`dYn +g7QdO:$f_' :d[,V""ž^g6wWe7G%rBLr_@x ~.Lpʽ_qzM֖uXn:=I\p?AmmZʸڊr:$@)5E- :2<~e$.ݺP;^)|7mEK{4TfsrGhU=yR ͪK$8"1m;rrOlxj ^DK{i-卣݂ r1ڽM;.|Do|u3i^#l\aX F>u<%/q@"lrȭ I55?ϸ.~:SܝKU0/$6qO<5[evxFgSx|#g<4udC}SĚRY|YP0#RB#|q  FN<zG4gi}Kf`7o-CE'#*ӟҾ_Zk;hO|ݛr|9$}ؚ˙[S>RҦA%p&sJ"%zמ/՞MY6^#tnB>(W JMݘvߥhz iiŨIbv<^\nyqcfwq616UT'=kx2;{,'b Hq|64S,Ab aOA8ϭf淬jWk#F0@ ;`kºA'scUHR ,NpaГF\ݭ&ubs?QeRHZPێp:w9'{馛[m76 !X˯f"M8t:%nۉX"1Alcy˶xۀA$I/]S^$owPA Vp @pw7\qpMm3!SJ4폺 }NֿhZ-.dY@a}7"xշDfu#Xvo3'}Nဥֵ3 vx]I% u>|LbhlrKN'|%G2G8 Z u+6vF?B? ^-ZdgLGclZq,yl5\X۴[rI: 3 IvzSj:}ףOSii.Qa\;~l` 9 2YdNwܳy$IɫXi8V~|Lc^=8dmbqqpj8]FISb;{<Y`y!gX2nzʾP;q]?xW_Il#;^@?PHH>OV&G}b)ʂ[$dwֻf?zUFkhCȌv,'1rII*>Ɏ\1y jc:=-˸m35<,_1ɮIP~g;zlO\VEH9\s^rf$,U{H,z 98Zޑc8b *c }9'kqV--NMfȶtXV:dd=+/5 n'oajBLuR|Q$@nP#gp_0;#>s^KZ]OO֌ω1c ,"@1N93My# h Ɍz޼*U!V1wzK];GY/<ķO-62}kzPqR4]x~~4kwUbtI%ʓwd5oiu ?XEL0FvPUv_w/ߵ޳cs5B;h%]_̡'8<9Jvwr,2=Y#V ^莺,녗kZH:b?_nBtyŜ"Y-?xBz7t?67ze& Ř ĐHx>JI&iG 6IU'@lL&p.CF dqIwu]Jz"ڍ  @䀸J14dgy~%xcҰad2 *\gpYIԝ;cr[s;29Dm{6 &Xs 9 w.\`ݸmon9+ 5nI`@G`-zr1gBJRi5dp'R`q23=>]b[c8Oa=+W[L`B3GZ\;`qv#qx|>f>8yuƩ `uy{%sIy=8׊)Y&Է\rN3~5_dQzs̑AdzJG?UV|Ei$z~ m -7 LdG=O'+Xn>yX$)!Gyd%wGKh lF6'w'f D$Jr38$NInikV]Yce'!ޜ3,+d?_RI\Ìuw|vW71iZ2 dGޯCH1o8d~JI]"F  cb<.ER@FYs{ ܟ\ר#K4c<`9s765yt9YLR6Hє(`~Rb%pM{M:4HcQx}9gN"dl%NVʒm9Fz.,4@9:p?{\t@w21T觹eI6ot[H #pU%1ڹfyYmĩl'Vi䎼#k@m2Q#m1@*I@<~U#_OkX^D=ը ʂi8II_.d+iiu(b*s9 zY`#9\FGhڜi upX }f8~ţy$vF޽5c};K]ˉѓ/~Fm)to\_\2̬ 03=8# k\|BמIk. 4H"RHbÑ6^5uH]SI#Y69GOӔ[e?zeܶt[^ m+ ABr''u|]^i^0$x; 1b@nkYU-}HRT >K,%!/?i/p7۩˓Gp qܛMOšލ jG:8W\2 ӿ?,iEYL03sܘ8z}*jT[˃|@i`ŔmmFG dکZC 8<z*Jr9,Wr`!I4Br,X$$/'5K]F m! ]6K<qf%xx=QIూ b5 s;h$Ia圾@b ?6Js t#ϭR|7kB8AR g=4>z5Hm_{yb&_I>I^p#$Kw'Ņ 5K,,2 8Gޛ$wzmmtc-Cϻ#(s$;p>lPM淾i{Xq|ආ+{ɨAN,E[V$a /"j:{ͮ}LxfeH.;w7~WU,qiiq;KUi"M㜜?=ԣު;Z; k,_cHw9S\ q7I~zP`kzzUbaZ'p@iqJj|RWma=ķII\ %W2ktm>!4M 4ᙇ^pp8Fax4PeH3: q+K &#w';Fqtv9"+t;x(4Ӝ"KpXdSMdJ2cB켑Fsp+SDtsqaa##>r7@;#8?yֵ^71$ܡ% Ѱ!I_y#=5嚮\x!,=HI9t9,9|hpˬ%żQ0nS#~P^H#o9eXXEqs-TKiqpWɹdtbAee6)-* dR;9& t;XYui(csorF)U.+I'wʿүd_ sddp:zVƭSq*č*Ijx\ *:GLn}y%tIKg!G\ȃUE.{sy#p˓p_Lt}Bcw99|`Ĩ*߶2 =*W5WH `ѹ ,B#02Uj5fдGRI$d.#O\xͻ Ah/U}711Oۤ .k_w"|=:v,X$tgzW$G{<2ϑ mr9eDԂA2rɴ<`qӽi`:Gn۲Bmb'>궨,^[3y]:ɩ@@mn773[8<: ocMjBpG3Pf'/[`XZ`m^#ҿ9|KZ]>ԲYBV6;RA985=o>l~٥jBY!][iBH##2B֚e"-%#T 9eu9]4yǟxRLXdldV(fg$j]`zFqɡ[xu4=> #K6hfYw\F,QXn\'Hq_ /Z28f"C=kr}>{ ͜.z9^|p4j-qbIu,B\喯3q;#*m91)?,wq޿/:>5}^HdEk#vAk;w(rkڜQ>uk4mW(k+?Ǣ^O&뫋qqsp]p!;Dy>_Br0x/]Yi7k=Ea1 ;Y8|ۋ.ۘl pf'O1cḳKrsuCcv%ȒFYJI ]?{:g#ҽ!$eH&c3'wFvcrPC:n% qSO5T\7/Pp߷KyeϹd~ I|dڋIakb]]TW5;xb_JѦD0[v~_kXFm%V2}#G1K6|e c GN\0#OnQȟ>FT䓴y89?Je6W M$Ǧ>}"5nz w1 3bNIȯWĒZ> igEC}&C QHZE07~]>-u;D~ _PgY쥂d8Q`ϩ7kR]=%W0\JDwerBr-0 hzF HW2,E1H*o'&^dTQSLMSPEIoes)LpP.wd _"mp`Wڟt[-9_`QwF7.mrk?.mEqck!qq:ݎu"4Xsjh*hİ&.s(YǼ\HͰ郵x!B'k['X7 fc*#=H'i8hUI2||6g.4養9n#3mH<¹.`Q x?om#RRQF@Wvj-OZDIv>Sg_1YCo+V Uk `psׅ }%e},E!aSA;~-& 66l¢fvNA8 潮YVl,D:ھ)Nudŕ~mst5֌ڦ&rd/p3@M"=O+9s1<Hq\4i-Nl6̑@SC7%cᙖ䉈;eqdz}BYiuX-4M82q–|nP)$j~3uYYMhH@DqĊbB1qF[}nOռQKkX$~\1d?60G?/.a[v閲m>vc,+OYhϩ)M](A$}xvkn|S S@PI9,Awd,֧St]&Gnbe7PiM>bFԂ9fun$n"bToF?.ڝub^MC p= g{nos;K̅Yw`qһ{k=O-+¾~u-;r{~b$rC[}rc-ZdV8w@#3#ə<ܒs9ۧ^7#bh=Pv_fe?K<'^Z\knu~a#ÝVO4okZ.kG͇R-vX$c>h!ҖUӵIK+V`b|žU;w,{,zd$+y '=@m ae&w'nƑ=T {*eae mS^c9M99! msSŬgA#;hcȼO)*7I9p^dXL.Wh8b{ r3ֵ徇1"FIvDž봎yR ǰ:5ȭ@@^zw LBs󪓟LcG#/`|#f^ ֡# `OQ54U!4&uħ=litPڲ\$W2ڣFB_3napT0]#o:'.潨3o+ )ۃӵqU)p ެ7cqPӴ|*92BמUK ;vcFK(7|۰A37xJKy-φh`iLY7G-t;VohO"ͻfwAVG\t 9'}Wk[Oz3۟ɜQ>VfNp XXN9V v.eqwP;zWiM%tIÃ,sY_CjdS >K~,v1+.d`^HRLs\ӥ;[ˋ'+)P0'kb0'To1?@<R-7hn0(Bu^'xkH1ypѰQq b$@ ZMyG4+Tu wKxQMlG#p³+A-x;L6WęEڢ5Qt~c6Z3">d%7$vP ۚ_EՎV]:;b@Us p0pIKŽ/-cϐP1 d.3VË7a͢jOym8b6B./#ך{O5LS:vī#1\je_ ?!y:F)sa4yCĂPuѭ58Gj {Vp*v pďlX4ii\\%͋pe1,A`ׁ>VI-ryҖ p#c; ؽcҴ2mm җ@0lws ZdA5وAyc]C0q9ݜqðKgHɑ•S 9  z^2țA1Uqmn%sET;쵕/(]_ wasOS[Dxݙ8Mʍdx\icWp'aa"T,Wv7my 1'+Il81tK<7 ,ʥP,^g*>,BaSyrh$%Cln 9䎙zW>aRF 1 9\VCXٮ[9+fy#6aw##rp?y߈uk.E4GQo'.:nsyZk8 pGZWKF2J>}zX~exֽG6$Pry#'r+]SiZ0H/ T8_7qӼh:*ڙ$Y\1 ',3ca(sԐxI'kɼHU>YA 9\`zv?XKo]mer`r"|/8 3^]xk[$l~؞aVs{Is-u(a:U 9 H!ӵwڞki}5M]e#)T3=K~l_2A!Ӯ"3Ўzg:QGq)rGi\MorA,nX:3ʎ}~ruxq|]"ٰ"bw7d0cnhJ#byPO'{׆IX|')$dϾ:rVZhK$2 oe(0bc_.O _OTr;˛rv .H$^&$/bYRDPT*g(J.gs\8H;gnϊ'1\2_Ch#&TEU[drI g8m_kK++0@ ~`Š"j)+rτ,oa۶ףi>OGc@Ԥ2%"9$efʊՑͫ9-b[i[WFM5y7]+8bR|17+\j% W(.дl?ܒ2ILeoP4Z4ve1!x8W[_sƭsig+*4ۜl n^qN+k Ƨ0íAcm.mW 1WM׷SeLfeV3x pYA9Y-;뻘db#9n# #Ҵ-!E]Ѩ 9Cp?\d6"A1s F0'0H$pq\7?gEDB ™ lׄpp0ޣ!bn 97"s4b!^KC1,.`^HӲnex9N}I1#̆R)Ůl"`o,_zd{֯ZX $IzXrAp}}StM(T8!@=Npsӎk?/E6G ULQ݌P7k= i|2y1d|#o?ϊōiۈxbVl#=y8_92z;̸98ȯ?kz1Vl gpvPx]I:7z:Nss9cX<ۥ+&KGQivmB2Fs'>Iv$bBsF=WcSFX)dM^$~^ZZGŒŌq+G Sw,ee\7͕"-m'MM-/{X%K, SGnj<7qmŕv1g Azx+y'َ#gLsq ?kq0$ IX e,,[dxN2rG1hYV8ugXv9my~{Mo=1[*#ӎ"~ܷrV@3W&Ba:=M,RFC ێ\u"374oou>"_y.{drqs{cin|'Y el!`GF-9c{xb +(fN _:s_o_t^U.4"X wm9 WH"ϽwĒmlĬ[r)bdrpr}ʾ |n+^x_xB{mvYI1$ /`{ ƛ )y?vY<͛͡^3vƖNmx,' 6c''$}ܩyḎ$i ־mHK)˛1lrUDdɷpEbKqpGa_j +fDLG*;pc0F|?}bA$.Nv&1 4|qQ꺶qGn>$;㌮k%Z8E$/8=sN4u&[(MSIe#zUeks=h[ɉyT:xۓm+~RGܩ3X9;@g9$AY:lۉeU %HmcWCg/o,ajmI<=nKYeGS3.p6 .I'w˖u+=qht}af* rdڣ0WZuW:q,4.rZ0i5$܍bCѷsQKAi2yjcr21Ã`b$+6s+\Fv1%[S@ghEO$Klw`:b۸.XG랇coii0AdUUBNIF N-;Tt[; 9f]h%}ZUp1{QEbQz"/3RrI,Xby4΂&fV(ܣ=~K&ܢyyr['$ȿs00,l8,q!`'8n +' {yWi#ۥpZltcp9H bzm$_7K_sIY !RN#893T& 6w4I,N1咥33^C{gfmnUD,YBv;گgk'Y-jqͶ8q_ MȒ H@(|$%>c>[\bXt"A[I,Ǻ8pa[s:KkN /"@ xV*x,HbOC_S['¿~̲n)f,s|pa7-o-6e;$oyѱcQVtsQX[BmPM;4 ?98\u.IjCK2G~que$ҥ,V0d@+5V7&lu s(ze,ݐfAۡ}z?Js;9i=f/H!$x'5xoIBU`x_ ¿;-7G}UWCPBӧ[mamdЌ 9|Ihgll/-X< ESH |$F1b>PI^[{?FGĿɻ啀/"pt p3߈ nkn|`DS$g^%=ap3Ϳ.2sOqކX_hg积$ӏ\$p \0sx c?Ҹt4?S }ԳFVy@\`3- u.i]Kxv/̗G$ʥ(X6Krx $~#$܋m'n(V`3Q5i`vw Ǩ1u|T]_R63V#c-:q%ٍ5 *1RZ|vQod$S9z"<YT#[Sr=Nޭ_X3ĆIc'`b88<]=?VWSuY$ ?nܲ88榒)eWy$9Wϛu=Kv?m啢Yc 'iKFz99_)"92$9 1|dny5 t*UtQ#2av@Nq ;hbX,Zd7VDH2Hs-pm%}W[9{_)ZX cxmݧi2o&_/Pl[x#ySqPw`ǜqkɵk-~qZ\zAnB-e`0AV9Atf?AIK# ӏN`Wͣ5r9\=N:ux7֯ ԡ?! B/. n28lo^[\׏B 4-bAH۳BnOL?}Z4۴0 @r<YEǒ&mn$6F@ jզHg:ڪ.ѼGGc"Y~Rm uZjGqo TI@Q2'DĎXфvFdN:?u 24.6NI$=}[SOIKy*HS15q7M\>&@Uy)uʿJ 3~!klI&x%XApO5=0$$XGhoc ]=>;eP`qt 9_kڞ]֔hʔx3߁zh:eH|';]C}+_mfhKK""Y޽x 9#t7?gΕAPg>·x7V!ed[ V#r~_־wMYBES2=35)u-nc-.dw(UU+6:tҝ@sw׼'O dƌQ/.~V|Mqiч@j-F/Ű[8L!q_ɴV|w Fe0 @bbdiecV[˯FY y=nk.md*@n^9֮6ic\O3|UH#9H5v$wY/o&ڹ<d͂>);Y0K}+rk;mg":c׌Bx?H𶡦ή-pŎvueW>|>=! >5M ėssdos4ٕ^g*q$?giBc!#c]j,Aҭ_^]hx }~pywcUs=}B:^AzQH+xu*%~>b(;۟z:*q0lփs/' 1 Zc6(wG ^ky˲*@nC_W /zzE$4r  )rN85AZͽ uh^*Cr$ Pg~\x{La<$ A[~x Bxn?1g {'2M+ ![p6猀0N{iYf%9* Ǥc[K;5a}Ιfp=ό/.n-#HmvUd?)ܴ0ǹ8WˈD%L+k5haOnAec~[ФO~5d.g.vqv0;O2@YG[I{ҌĒ߰Q iRѕ`T%WM \]KP]zOشī",6w(WNΛf4UQ0:GA^$sBk yItI|e&2T4F W5rëkmqjVqqhcTP7`s?|"qLCHI)C`Als+Na9WPYb$ı7J`aʬ 8<dCt sN %Vnd p9@ʰ\$v]feѷ{T"Ɨ+S-W!I%Wo-L?"Gbho25f85~ Z7}RȲ[EI?2e[7dApgQWX ȯeg/KX/℀ 8 qAOc ~,i`# {xM^K|~vYcI^IG;N`mv! q޼i-FO.!`$|Ǔ얒xm'i,tSXaI8#9z|?j sbvvmd!y6q9ir[dBrV\ *p8|. Xb;W^ce՟ynTw~7^ZDgy{%۷݌`}:?KZO~lt*ֱUF~URBHmV+zK Rmմ4C rZJ.oyuwe>5]Z!+2^'>-N$u(`FfIUV7Vr?pg22^B6Hs~%uc[i2[H.dx?#썕wr޶uc >n b = }/ks2W Eu©mXsm"tZ\ҼM5Ѝ%g &Qɓ;|aYƄ [f^8vb@qf' ٯ>i:}#OV j)+BT vTgXNȽ!6$$+ǑHu;;şmΚu1E­ DH 3( u9yb9f']oYd+[K:I(0x89o,؏i*`p`c8"tl^N2u?}iųT~ڶmyn+ I83k^3mtyL؆HLUb8rϗ4sʍoO2|k`?=O|a-æA"mm*#(K9ƒNITV:y[UV s5uKC`U?>ƃ׵v ǽWH9#y]_G{,%%|oǽ|xn N$gi~^Eo%QV}MzM1Db>F00zgߍsqGV72Wmmly\ŖguIS< =?ҵH)QA շ-99sH9c޻K&-Tnr2AV5(X) SKy(f߳p(۟VmV? lK/EbhF*88@1jZ1$BymʒA#q܃+O6xtcg>0F7 WOL视ɞ)f^W@S_T<:U^7G0*|| 85$bpJ0ftu#EP`}A5nkH`JO3~6cvlF Y@*N;}=G"Ari_Udq-7?4,#YpGoaYgq4EgxCڳ1a-Ylֽx5Hc /!iv($p9~<=c50 FG.ӷcv.PKva2?V9cצxM%rñϸs ⾋UϘnhX9]϶1W9%ƧXβڬsrx=woI"e9 1t *; #:y[v+ᰉH^$o*MتP808>U}}>ʲFL%pUFK6 v ^ēXh?-CUmaёK*JrF`#5H<[TVe1!,ۅ9c=?&a(Rz_BL#?*#8 9W^Gͭqm;zҖH$,B $qך5rdjw7sF zo<+ vͺ1!E}u`]_۸ [GW^"_1^[nUooD2<щV0xRUˮ0e.Txf!O^ǩ'wv !&6I p WCݭf gۯvK1ddI'ls_OKwgz}rU'2#2#7 7xk ydx,7*IdrNB uq.{I=KfMXZA#%J\|Ϲ.FAIRtɻKb c''OֽnM$$_| JLkڥ <ڊ2jǖɱk(u"\H0APGrN3Os\Əy-${e7'HkdԣT vaџ18H>ax- ͹dS Yy#Ţy )D6U|0Gce V\(20,y?H^kJ]yA)߽[N9\fRψO嵻F' Y; <1UVa`GʯFy&kdEKvN+.<2FJW=̷GRGg $`ׯ_{g܈W;H Դq#$|!O'T{k{ۉ#e8򬦙B.eMJ9=GUaJCO|q޶b`&(O[VHee qޠoH#o|㼷u),89;?whtԴ=e͔ J1`>dʹ-%͠nM%#L `\zj=2L&Oa瞣*S&[.^LؒGu ֿ]\:H[+q:v[8Q&|ධ,Fy{bߊ,eԔx=jW)'$G}Y&-s\[)n"0cpdUW2W%x|aHh !e1GZp-3JEZX7g 9V H> pz2[FH>5ĩm`Q(D9-A5HWg?TV!XnoƍC6u9`1r$WxbH4tO3tSQ).|q[H@,hZY[UKDɰMOLy ?|ٮQ3Z埒2+'漦c@\;zܓ⤏iتa,?3l8$qWPNO) 3%;Tuq] VKi&##VtP-9R$x4O#>ZE Dt1:a Y b2k^F5l%[pY%-9c$SPcW$BNHe;?7ċ,Ij9`:.zjz0}t>biBkEEnf[ir adt?3uFʍ.;HF d@܏Wr5#%FbLYeunjay>U4=#P}>n҆ژ32z&%>gy@݉N@gӁ^i]! %6''ӥzuRH.t3΀d88e pL(+T v}cȊ6HfQ {G9NASдnvֽffdG} 1^O?nڑ#>fçޥmZ<#~7fd`uq,P@Nu,p{d* ׶g9"4b®1ߧ +N2K sw[0pYX`znݒU`T6s4gܬ^xI8]꩹MRͥVu$cvv>:m&QLI9h׌~x`O#..,Yq`Uz1SOmH)u'd9m`TI;B{2p UXR>Cz>y1߆^yǧS:mGC +3ӮGQ\Ƒ97+RCo\Ouf ň23knj"!KAQ sBB >_`#\ù2} zW0}!^9k>mcYa4z/R\N0y_KxR+6wwd%Aِ@<Ϧk[fZ҅̌|= 烌~|Jb,v-g<3F0O\ajiZ,k*X@`ڿ@Glc%'^0Dnd*9?5]3XnQ7]Շ!W* 8W<^g.ēSk-ܚ̃e\Gc1ڼ{ {`fYmdm?jJf\[*U$H'WИ%,l8H19b}mbx4_gl3،c]{n|\ͶT8{VI\l(s+m6&5`pr6q5)#7ZˈvS3 u p8xW1Tp\Z@?^;2B1z`usNG*:`QD7s؄ꌯS^eg,YK<W/h׈{]*KA+T O=@5%vxWw=@e^s\}s`?*yyM棬ڮis\,FF@^@:=x#\qa^;1prFS釻-Amool2 TH㓜ׂޚhUu:s<$9<g6$ۙK,1<+6[r0vmCZrK8S`kMc3'-?g](؞Y`y;:F8ھX>v7DOoycgX$rqԼ}e[x}܂9"O;Ӽ11\,sym#y;sDyu(.UtZ,L 0^L.u/?#$vI'ž#&o;--"-y\H?՜ͨZHpw+S󓒊i]Fj3ܫ[=U;uFN:gX8HF~uWd~.6?;B[ǯju Yob[)()ف$ݬP({$~̋#Yo -neތ\IټD+r"U$=03׸igvhňgq؀A9gcISaAXdTC[i SD#t xs\l̊AꢼgLDЭbzT Œ|#>%.A*%9xYGבk v)4.ЃBME3M-14}cWPQb85C:듸gzn_߸eFW{ GW uaX.7$H\3TK\MNv>a~ͮ,ut흤9Q[CRt-i^Ȅ{}!fS&milG8Uct?Ʌ%_&o6vѥWys2ska_í丏As3n9±#} 8,%:fypą L+Jewm^t)|-hؤ3KX|[D_$ Iג*@mlE(*cx&hw!LsAQ sNq+o> h7*Z>~o=Va@~$˚즞?IPde "x\۔/`kǶW }\Eq)w)!v~k,WYHt+ռE>l0'Aǭh>F@W{{޻~Md-YA7=z۽}|"0G_j:ϖI*-l\G4ޯbq)A- KnI[zZQTkouVQizmZYۨ/9'zssjn_i#Q%7fXe|ŁFͱG ZYvXo#޹mH7*Î=땶FzP˜όy-y ͭ[R`2v#Vwnouvr\#7,0Wh<?Zjx<Ҿ/l]«|s9FgX8$vȭ3Fwq>:qWpXqVXz厕8lc{E6sv\AeY'kpG^!9Kʓ\u:{ 籹0A_Q\Nh\y Gnv_xp JRXbC&с;uW +^-ZTw-/!9#Wg [N uj-;Mֵݗ1z:7R51lwd0kv$Z&f(t`qGB b;kfuE;##WEsWv6Be* 8efp]Ew&yv~ r]=kn~kkڷ>vu_ X%ċnke 9=kڎ2[.PKF`-@ռSH.MBywl$B@15H|A`lEv?x_Fn/ MCmǧq&Ir\H8@5U0!^־I'M[MDYXk#i%c+kE :5煮Pi6D'1yl`OL8:ju͊k*dF*'x9ay}/þյ~PFypC 1`<Fr;ͧكq>ERFvGVQ=xQԮc-fo+ 4.O$⿠ci-sl-4R\ujoXwMN«-^Ȭ!8_5:*>[J !^!Eal*d#'@r{yn2]ۣdf]Bkwd17:TxY𞱰2`~;kVF4Ozwg?%E}0dM5SϨ|IxqXd #_TcYt>\Q(pjY}ŅI3*`17F ]/͗uFGco({y6 H+Vm6-"$b6 FN|idY|v$n ޹|Qu!J<gWuFm9;x%O7?=+]#[In9`{Wy]Cc5Ll,ʹMni:;$Y2p?JTCǾA\~ 6G#"|)('B/SYBug<׵i uLjuafO&{+9)Gk67z(XHHJFIFHH AppleMark    % #!,!#'(***.1-)1%)*(  (((((((((((((((((((((((((((((((((((((((((((((((((((  }!1AQa"q2#BR$3br %&'()*456789:CDEFGHIJSTUVWXYZcdefghijstuvwxyzw!1AQaq"2B #3Rbr $4%&'()*56789:CDEFGHIJSTUVWXYZcdefghijstuvwxyzx" ?{h#'" MYѢ֠U\0n/_֙q&Ps35qʄl[.7likxmcBJ([*lbn[铃V|L#I|-*@Yĩִ#@$Ӿ"E8.MvR8w1}?2L?p|ZG$l դgjV0X1.淗M@FѱM/N'ar`n1O]=sr saliwnueEeCLƋ&KID:\^i , sx'|Sȅ̷-X;8d~$OW׎ulbn.TwI UIhv;eۆ#$sҹFKۉ.J) >Ⲟ#'B9?A29xOB3/kmEk9;xje.F?];@¤ks8-z0'Kr"g$Uy8f!VL6#?#]6gqOPy1s?B[6 "fXr@ЁVRg2G!8TS-<= bI<cz "/Q٣Un,az|X% R7nz`|['إѵJ""o;:ٴ:3UmN-gHYnbh2`}PwZKr*Q ?xf2T'Gq'8k4M[Gm)]ZZr88:'?f&UFI-b~bzk~8R{^ihFd#x>RAq4pWPL @2S,Ұ+$|@zuP3mG"rx coqŭ.׵{yfYC#^ߐLi:G-$'+QAw^ʐK!c q@k^SeӔ2H<@ic5,۟NJMTࣕsӚK}Ӫ$P*$Vb9Z޵鋧Eu"Ilq)vIb~bG'Ŕd-@@q-(,۪۰AބdI^ZzjRDd_3r۴K]eSci^zt+EDl$yUlҴ1f#H3ijM5kf;rj톮En*[TeBLHslMӊ%Cd+~Ԍ'p՗]nEgɴ@s?hG\Sj7vBca2xz&yaoq1Y^GuByi g$ghi,&9fGLM;RES =3$s[Ro-d3ddϧuQxOT]G#̏?5Z7}J#.̓Vn7;q|~}LwRKӅsݏUd+DUnXsbI0Hi~kn>}mHukѭO0Yz~}ZHi %WYW,;%wӎ+3@ޱ ieLĜsU?/iu 68Qxx\m{xI\!N^8KD$ztz֩s*;dGB;x8ۉPb~\F:bc%dSXN:'pc&"KvS Zbm2)U9#z]6r%f< zqFk/i5,Kp[ΎcQ2]OFNj:}Bl\.pA'8 ףhյ 7Myc^ۆtM3XT vrn 8⇨kH1O[=9[ vVw{yL9q;;D*a $N+ZݭlAdo?R)XGK+>\\܂q€Cְf;оy˜iCًy|Hǿb%~y 16;zE065F)U1NG5 k3~GTD<~qe_|QIӭ䵚I].@P|RΫJSr]֖1'x2F77o(o\pHrSk# Azqsas[@*4!.נHw3 ү^"y,Lc<j[Q,HIpۈ=ե7piIylG~pOSϥh<)+=?a(0O=jИ@4A=>RDd[FKeI=&Rnp@@@Ȭ"Z_ShBnfbk eTl4LD`zc𤝃su 8Dib@׽q]6ȸW#5#gDyW(~G"alƫ82sѱJ5| Y&y|Gn#^H]*F 瓏B+ǴO'RPq*S [yWeK)aڲYXN{m1WM{VW?VӜ/dsC#o?õ#ۨ&2gWC4'c866&i4-":UlE$.,n!bO~S墊b¶sl)޴r-Ǩ_X[; c- )VEkxmP*I<I4Cw|@_,tkFҧ@Ǔ-Hn;G=y i 0S8Q~ 3QibPŌ5ZDU!-w&!6GOOupErA*9ta{tqM$H7rH6\}:mp]+: )U B8'~QUU  T-tWQG݈hTn%s^|8@v8z u+.c5™#r*Ĺۛ q"'T#v@Czi ~TsW&܃9XcSt,z`Y>BtV H&=X1r`gF߹ֱhƩi2$5xUI.$ | @3խseԮfOSfKLΆ\p=ExwVyuͳ~X,[:Ƴ,v3[Aǖ ÿkN7LJmWĞ7s\? I,2\F=y)XҮXQKnKm- ة#*j4ZUq8Ǧ~oYLĒ Uc$Srp+ѠMwK^dl~xwH{ ܍﷧FDyh(a7å<)9+#y#CJp'as9 ׊kNN B)}hv5>}Cgۿ+5؟QKxb;"cG~̟ƺ!wԩnwJEg}'5z/vmLLKtU?1/ڡfu>@@WjdY+@dg%xi)|aXhnr~qT73RCg.zVmw+У": HZqj9]F 0TtQҩ,b\,F$'?ڢHp; s+WK˷8t $gI#6W`;T{UI,`U&W1H$pERq-Uz-[ $dv9BOb-%Xmd5?A-9{?NF2􎳬*ͮ$x`^_`IE[ 0/Ŀ/?W] RU^~ iZ|]Q)q0,G{ F\G,3p#'Jg2ʸǮ\ZO fG '{r>X,֩\f镑9=s-~Iuw[ZۂT 1?]A֪Ro7Z币&G<~ǥ=ݶۀR36ܒz_o?5o5ϫ:6ikj.EG U'8osɤH"{k:nɘdqҺ#<%1o~UmIC\߳^K#ZḆ94l5*>A'=Wq^k_CBqKQކ}Ölؾ#kY2Ƀ^q B%d=:]NgEl9S<gmav:G#MdS_Cu_BB?Jt?C']GhPI9;]uѫ'g&N{zM,ڇ[i]oHLN-0k^ ^x3\oƝ[QHY5> %BhgI<#uWų]O5D(FHbI{݅ե>Vyto.q'?1qj_\wV .[|/S+ Mw4& "Gy}X|,`tn057^޺;i-{ Z% = Ձ YqGY3,_jI20/)MRU{WۼxFF#0C0$oݱϮG5]j%Q5r%ŢcZ.Of^s*e*Lh$*?+2ڻH/<^ۛV=&6x MyNMqҫ:)g8QpƝV9H̍,w 7>fFݐGǽ[(m25iRH2+ g=cu Kz#z^GP|%¯w¿ ;oBѼŧ/ VZtq'彝F%#?߶֞ƨ5Odžuw{gӥkB.I5|9*ƫ~U) ]>?#O Iaη;ZAխಸqn?}B';+MIklsE6+[.J`g`[9ԓII?_2M#Vjz]># Zh6Ֆ]M)$H-.s.:VWk+mii <\yV;%r2J 1tP^LZV蟖:TcoWŭkM%.NVy 9 ܎3ҽg?_xMr(Fiwy!('ޫ:jI.ړ/|]m]C" 9Gx-}&g1ֿ^ c=[׆0ЮUJvˠ9m_Vrّs7߇åiܼd]mć%aR&TgR+9O=O"G$Y=עZ*&?xgT}8~?pN_qtς< ^^[ $JĀ''9|O.Ѿ'|!Ԭ;ն7}ַ=GĥX:@@;r2'IKq?de|1cma,YZbב@~ 2ġ-J{ûoqmN+]GV6)bՁw"6P;]\w~&U]i2E )(0+!OcRbm!^R#7eT1ax=q[: \YXTH_:tOR۟ -c}C) $L_#Y <GygLE}'T&&])Kef>|Uz~v__|_ໝAm๭qG.4/a@ɚůmg EI7NKȪist% .547בė5m$yO QWai;$fЌw,Di9$MkNPMJvM;?"Yf|C[Od5r rG$кʇh {FG OO <> UddE+6zgv ,MzFPCÖ/g^/omF׷6[țrKݰnnq:nqeeeC]_'3.k vh.4Cb:+K ߅'12-oL!O0ڱ"`(j)[%oLLmgGu4f=xgI& [w`ŦE% arbP1{<9qy+Iu.' ʟ6Mw$NW('9549 r1M?OBF1o}6ój)pF vӭ+'u㴍uQ+m+QMUJaҥ&?',CS/}wIDb$b(0bIBZ%<-[9ڦ5nV)_OC{mf]6-RZ3[6[\&Ǹ}Ɵ ǏRMZm 1s^설}k'2?Iܓy` Lx.t-ujZI5 *>WcXaҭ8 3<᫏iT^/fmoect +ܳD12W|ӼkezfYV]v5Ku`%Dy↠.ks{9<-i&+c"c\7ϵ{1Q222HVMr^U1kJIKp$XNӴm9',,/ ?w*+vPcfx wDA 0ݏ~AWa"x} 싩jw<218 (>aduǾk9u mN;oQX$F$c<}}M>j[~HĊDJ0@| o]>%{9mX_] "h{9fE9PՓr ׹_ҨmƼ~?l? (/w_ZG|y k-kMKM[&Y h |r?jOVҿQ|6EhޝMqwoK6c܊Z8f_rmU{}DZ]|UPѼ%x{z,gM}0XUpeVeHgqaۚO y7;>Sm,l͵ʴe4쪣riy#䓿z(񭕽7 !f;;)㌞+K|V? n$73xn؟m2E`{0e(%fRmw&xZQL&Y`\ ~Sx*SGN[$!IRU&e[sYs.cu|@S5@,Ƨ!DytUߞ88烊l7wWuffK刦+&$:QiñVs^+k_Yi5Ӵ(f^O3D xث#9}KK>, ǫ0PiBUUWbX)-khoCϵ]ŧK@V&N3Z:KZZo-7JUpOS׷s7"þ3Ǐ|Y]/v,iJiS1i#rFS86m枷1 цQVBT`A}ZOhym%l7dsӌ7ǡqZv׺\Y0\\$4bfTm^jE|VNp^<ǀNNH+rGECƷ'cѡGݤ5+8.!Ea#['_ |دw9gGytuK%  L.a5;h[co,9dVoM#@ש[<9a;SHu=B(`D}>gS B h&ֿ7=Sg >O ZͱMǹ0f+Я||rৌ>$.~zZ>fL/`XIHˉy.Y5ZѬ4a m|ko'$W6׺6*%}1TO)"Ҽ]hS*زŸ`;,w8xʝ9k枿sv.JSZU[\Ü閤ƌ99Ư^]׵Mmt{ 3M]Na8fV N.lT+/b^^i9M~! >ď0dIFI|ϴմGP-cgQhfL\q5fego|U*7W:z4ixGDo:_nPo|kGKEŢImr@{Ss9ʫ[t+OeаP9GȆ au{9gzwo/$S cu xAΥ`X7>}?>UӤ]^Y!K 퐡\51s~.cUӣ%z Wf@Nnu}E0Ntf[o 0qe0j?14|X;:V;0$MII nb-ɒ#tW'Ýau* j n"C,BT>]A# >Jm7=-E#QԝN3֩YdUtIlZjF;Ϡ4]Ǐ|1m5s N1sWh*-NJmoNm^=BG 6Ud(r<`Cᙲ6VKK/6[0,$$`grgO[ӝz,`p1̡&zloN2豁LYi&H=oVM[onCK&Xʧkn-F7_'~>+_YEf⻝.FmWF[_^I&^720V1dlg:t YwXz.NHN>)O&m.65oZ Gi7tZ]|B»A\*~9-G#}|u^M# ]O:IJX:|wij>5K;\4~|e5-1>$.k0@TmgvzT+L%{:lo~$l:{}x:$Xǃ"*aӣƟ-QrAqrjoܗd COlHEwRO%➽x]kz~öjvQ0zKġRȎW=8[M[K )Cqo* B1 xY_]šzu%&u߾iP ݽB:&|t׈>-n(uHCiu#"#6BJb|cGJi4uHI47- Gh0WA.gKaoo(( HV c'T\ɝ&w<3  yϑ69oO Ÿ ~ I Vz5V=X[%bYn f"u>dm[>r:~c0@gb΄Dc1=K.Fm[~' ]}RQrS\r{:?ZsV L2m+iw8f}ogE՜W^yHn*͹@+(N9 g%{ۍG>{ixwa/۝o3u+vᅽˈΣ`FGngc=אqk^(|$ִQYh7CbW*j Fŭ෉ O2]NI&5'U@3@s8)M9KmW ~izߊ7KV>Im6yc%6˩m]UfuG(D@!BiS9xM-o]j&cɍZ P'3ғx?FDNև o'/5/h1xvo/I8Y!)%Cp${n!DžmxnMBucdܑl+M4Wct__E#_w< uua}gh,54:fq6Q*D|Ry+׾8x8<0ǢF[AuL% , #ՄQEo_9M*kM36_w{hZDw\60do?-Ɵix]E|7-bte[Y y'rC2ab!Sgߡ N-s-O+h x|7'HҬZMM;ح}0O,8>b9+AO,,-t_ ]Z[$S#QM 2W``ϓì3^gS\Z/}|ַzF$Dsc 8Wq[v2vi%ͳe1m'lB:SԍFM[$D`꾿J|#ۡA)]ɟmOi .54z7>7`3uk̯Ath`kF𮋬w:ŨUN`YF`nh#qzjw.[X};ڝt$SGmWK18iX?z?ė[&':B rq4QiЛMh@eXc6tabt<Jddq/~[|*.#_.?I#nrE"8ʌ1UЕ|A4;%4iv:ޙ GcL"ѣc "D#_ޫ{ZI®3$DCtL>Y ݍcm!5~f.%['PT_'fLoCt:NڤO ;.3ڪ!-Nk;Hv|$yQF{yD1C0U.-K( KԝdyU!VMWNk+t=/T4QjwIr >Yܱ30w$Ihpխ.{>3CQFIGIU ow N͕B=A]ÿK_26iby!-1pͽ rH1*SZ^C5 ^\H\S֬v21~B>hs` Ȅ qqXct˛K{i#WaO`AGg#cJ׭/QoG/(e W4_]F Kq5 QpnlySźSxM6fQFDm(t-b&V@%KRS6&[ج)%C.[$rXe㟘}w?^"cO{ D+̎\)tʊ8=̫'8OxOY;t>]BcrV?8w Q*HUEv0迶Ⴕd"+ytiHw8noFX1pF08B'{QܧF2l}Dx !o6I̞[tR@|6`xH z6QKk;ia0rEy\I[Pc0E`֗7{|&~h2^~/us"ZmqeȃrGCrc 7~jwR|1Fmw<0+Mܑv0A*6 |ceïxGTҠX]Zk O͸ΌBp''꿃$t?OӮIZg$H&a${ Yn۵p'W> /2ș|cAnct+е=N;}S2m4nvf`%ja .x:R$ox%K"c`"e? g* ]/uK hM4N"|+pύKQᘎ\dǠ@|~iZ2OIԖ9.&i!0LFY8.EXNMJYS4Ru(Y9\RP+:a8f g t)RSSSlR|7]'-5{;o,}}kŗ:\ki&.\r\/xdbw.S5={Z<Xi]Y[oA9$c>'xĚ{x#T`pܠ"=|<ͫٳ\=?7g /<9_.f]f !1TE+)'GH4:>xJYX6R%K,mٌ@Hq3[J ̺SVR\ܬ<'>7?8Ck%Q]jSZD.yoYe0$.O1kO'՞~#"-Beoet.X$rhPѣ׼a:hKἙZ[D*kr~K|'a\'=fEmډ&̕VPNHQQq-~yٿ'?g^AlB 0ᘰbFp3ֿL Þ0toL]ɈwÀ`\c E95|74]:OMi[Jr}yqg$pCc,>_kb[⾯j <U eT&+ oτ>-\6{MӢS4Q%myal1y$nVqؼswi~$摌s#N<ڔuO"g-4W<'Z|FYk\ եŮklS勋)MH9+4Q6I?O~ҚټWiZu^xĚ~0ă|%eLdsUspP3 ~?m?D%sgyBNe;vY"E` n*;{ 7I k, F?ṛFDo1]&Pb }Z5q>(xuxI;K]& .g#Χf * =׶qEyI{ge T'_Iڲe_k*ӼG+ YkzK_\HdHT#KÛM*[9W*ԂHl8ۻyl棕}Z>IG ׳vpX7pegWO|(񾍤x{k2Ѡk#$+! IJ׏WڗMeElO޺XdFnfw b|*+Ε~mNJ{;ѭjɭI,/ _e+ Xέui7f}r٠,GxaW7ZmrJeY'O:]3v77d/OjxDO/Ó[DToEB)apNMV7<+oR-5Y2!0rwI'9wUP|Ic?1acZ%چίhV˘[uu#*TSp};ݟڏSNFcN[}+p$l #i#:E_džmM AoAm.Qc:Uƛ%W 12ϕs]RFRr}!?>o4iipeV_d+ Cď5kh>ʃ -"kFX剥U77&T,iXMwC@{d\(eveRǜzB.u˂tXivfݒI#g ԟA#m)&t6 p{3naN;nVi+p>vB# L'M\y@[eʤw8 xLK ޢ3`YTy$m<_'7Vd&Ȏ2 q2^{|PgL/hk-6[t>ܖr$-bۂ[ G\VqU<ݑZ>,nŭm PAI5#M3xL&oI/&TM.0H!:;6LUa¿oπta/Z|8Xn=F+0ZXVfmVf'q"J^jtRv? 5~O\RlfI"1 g''+kk? `\7kFY g8pk/#ьkºMC]+/RdaĠ2I+nXT\cwӢ Ф R Pnx#;Ӟ1Z0kHuo}XȟB[;`GzXd?q`[Ǟ!/[:v^;ML:B.`b@N0>:֡ z;k\WQPa#J?2Pل4(uFo2{~es-?rUմXp>%+;ຓO/I|\Am\$I*yљ#L;RzjG~+|BuKmo.u)^Bij(!@ n?ÚV5ܚe\RIen80m0v%O)_Ӽy 4_HMՑnnM>C >k"  "uCCψy{]:dJkHčA57H6oI6Ԛ_}şq xz`w/C6vn'^><9t[{5xpަZ;yX8 k'iEπaİe@푚=|:?~zF^\[5RǨDH)vGGbFw#gcZI)Z ?~xOGxbY4絋kC,Y.c _ ޿Phz'nɞ[CnF'fYiK aI2@5SM0AkwQ0u9-ҽGx“%Ժƥ Srʑ]m՗F.sN;)aWXZow妛soR,$o)vg ,wrN~oýN㮳hpA(&ϖ CsJ Zd~IQ5<+3|/$dܙP@q\ߋ J&NpF7sW xXuEKbi8XuDHTrІ'**ՈzJռO&_7W,7I$%`o*b &ln%˶$`!C&YY& K`2vhWz/?Ãzv'ѥ Yfc2@  Tد]'GM6k?˩zs4\$\($df# BS>]sn:wƆ^ *- >UFذەyFfۅ?[7~&iZMr"DtA?4.r2&RB1KCo?~?&A"o߻ơUgs1`6s{+xG;{coii-YM^sNlX[F3l\fvʖsVHT:?<9KQ$Ggl>ԅ9,ؒIbIaKk)'^H+ώ#[3?1%@1Db+o~>ֹ \ҦsϾRٴsܜ0T솏>8xEƧ>4y [*vk+Y,A`2~5ՏLXǁ5- Ѷk7PGtAk4YK4(lqNfO#^ S~xc[5'6:Vmʟg&M߼~@;翆ু9ƿfIumRh-8Ț-܌/ N)q#NǦjg]J5WСY'6>ZwQ#O]=-?_ .m5T!Kg*vKe{׺20xܟC~aiOȈ-ւݢWQ!0E|"l灵Z29H{ VU;W*/A[$q_ oN6b~}s^kxCmY|6[]]^%IoL3˨酣& ^$vr˹ ElxfjqwLRI! yw HIfHtx0qܭmʕ?[?d_? >ڞrz}ƲvW7#fVA Ӧ3EηXŨi- 9N93#(0F@*@c1IO|[7ltKx`ibKHq"kl`]JtK2cs d}&qy`'GOyo˜o+1KV>>8zԒnY.dٍq+Bv(f {>^~ xM)m'OoX9#&%bd9prZ;O?S|8n 3ⷈMBMHVwE4qEu x *ѩ'78dB4-7D𥥄,Z[{4\Hdoo:Ip_irqwi~J_sNju_ #j >~O×b]WO]I,۩h-N;7BfN5/@oÛR[5a:vᐆ (Ŝ`Hj,}Q{GjY{k1>vf%@ĀH#'$My~Zu]m@cVj v]By b'_k'x?Tc?~߳j[o>/Tna).we)Vue#~ӿ꺾1-֡{KEֳKwQd+XkSZ 6^^2_XO ǭx{ƞ#O%P|&ei  uSiwi-,6AѳLd$nTU6(~eN;X㎶h--s5ڻɵmI.ʪ*~~^1#_[ CƷ68.F{Rr=)bS[-9U_3􏅟xB%uXŬ:xef†;m|?Y[\կ$xkvGH$ٸyaq=Fo4C|A(/1n6@`޹/9^+5([QvOr@ j ,{0ve?ňD.K[[( 2Q2l;qO=el#\P1cmɪYtIɹC#qRy88Ul-mWzpN})R\G|#Ʒ6i"Xt5Xoi wVgx9t TKCY%X̀7x@[D:v\y6o%?y$DB.z6 w>}*^ jww^$Ȗ!mgr y9H&DwUb$8R>>'i_xCĺܿcj7yV՞\F$,o]c~Ku;D>)u|*`%=[|o=X9>xjJt+uzsr`nd(FmH$ GNu'4} ';D-ůZi>iK$[ߍioQx:qecJʏklYK^1k7% [V?5~!kR4:*,ZNo..S$F_(Q|Y~xE5K-~}>*Ew`ڌ֓NSg 4+o=டOx? < {u5kuui ~giYf \b)I?m,ߍ~.v]׉4kmti7& Ѭ!N+95*MxK75C~־,x{lYl㳂37 DhŁc' rG钬#12ztؚ1WB҅ވa|9ό<~뷶׶(N7s\fݓ$($6No7'&].JY$*"eRʩogԶ:\+~}V7[joPuD~r `9^ sG=nх^Ěޤb7@@'x&QδqvsI,K[ eRʆSZ0qju%2 1B(vL; Ea~kA!ݸ7|=go12S62蚤VQ$gWa#q bjEm$BkFig? K!gw:moVتt+g:}<4lلr62s:KNp₴_0Eid]vtMr~l+ ^ԾjR%rxmd6wwWH|Nܷ~'4=~_]uYVV7(ffya;V;#̯Hv;KQ{+٨חs5[Wn_tm5Ōm+]+,#Yੵ[k9f%3m:v+,rH x9J[|$ssm<)waΕiJ%GE$,6@dW~ddzi*Q3 + uT-n߭*VR3{GtLM޸!FøPڥP0kt]O{({).DI2a fWˈtrZtch!񥖣5:^ay"Y8-8T .l]Dt9VFkyRpzlgR4+/&-7xe1~F:ڿZe|C7) [ADf{ VP+y mL~ 4xkɯt VViwKg4%:-ρCi|G/-쯖|M Zp`m;Hј:œu;?>zN'O),Ago;ZfA0$s. )fF~_uPx{oƥ⸣{.Hī-ChM¤hFerס ^x'ÑiCa`&_64cw[~^1]n=~UEܬ@x~c]Br <8ZN3-zYoMT}ZMkHRgub 1H9f^Mz<,76%rD:h ~`;Ue({<:Iz_.l[__OwUhKv+Hc8@~7hW8=sYsþ#4woך-WMY4SnLV6$XW rM*XB{gkvi.IԇEu~>0ӼKm^9|CK>4&[` .19wV^>H4%J \9;!G95BYͻkt-89%k%]|sZOo51*IPPfA*T3vzl|/[I VWYL240%-<~Ҍ<ӻUo5͕W0\#yd ]@+44w4fg< GEjPJq_q*n2gn×--XX^ׂ|wmn+KNt`6 fu#nEE^n"^(_KyJѓZ_ʰU6›fpXn>5KKh1h<3O"ly.2v&JU"mƜŵS⯃|Oڅ{Fn啥A,HP{WKzx[Ӡh@3JJeϦkڝ -NgŖ˧Jf偰6:^sӀC\^k&|NH}> g&R\ܺ%%G޹wy@'0;V-k{?M/xS|Owqq c[ěO0!s)WB%Ŕw FR[0ds s\yZo3"Y,.$QWhUN8ǁsJįx K tb< HH/NnߨUYZ)S"@_xC@Pu[x*$ PWˑ̍pTi=ǎ >="8 І<yfy$֩\%M{S FUb[mݵOZ%~G Bxwz g,ł40h!r$U4w ïH|IdHYq^6iU?滴zUJp勵Lj|Ue$w> z.@.C5_;=CM[)XH, ( g;z׼G(;v} өN_pok*C*,c8 G+23mhO2F ӭwBa)sGÜӓ+=? W3lwW}.DMD>k$jtwicj 9gBT+;y$uw0qzz _*~.4o~O$v%JTIS"4h r~V_1v<7t$@xu|+&چ`e#XRj=O5QocO#zpb.#g6;ʪSk&͊Y+F)\uKRQOV_=׊5}gy[<awv-xRS"ndxźF⋑uepdi ҙ}0s*>y7;J1#+}g^ .JPC>SY ^1&$}[%cۂ0 Nswyq]jn4K/]<=k'L穉R)Mq˧^Z1,<(r Tm+=0oq;tԒzߠ2m sv-tʉ2BA\W/S|:cXC펉%rS^ml](FN?_ث燾kp0\vJTw(Xs9=+Ou8ZE97GDwwRpS o`U8ʩ<(p-yovH_WMY|E{#-R"iRJ=^p~趚%ҵ-E]}1I00yXZcF?v7A|4ޯ"?'VѾACo1*VQ`Drcn&ו4x+h"PRK3!2dt8#<B jvS+mC5Za]K~5@# (߸6YIw{Ogѭ$ԓef laZB+A+-oGjNT}júNoi/źM^k]d)͹@!`Q^t YTb|sԇ$d4|Jo?_9l}NfVq"lp>u'8eZ~qĺ/֟r>ק۪γ\ۻW۲9/ʤx9J%yG_қgi yGux}i[)r!$1yRggJAF| 4m/~ u'n O]0ڙ#%I]UUON-nj.8{j*6Vz?S_EU?K:i\Aiݬw+10OJS>OÓh1ܼ|b#޻ptzN͵i_sg+ҿSD`AiF ކ*9)̃?x+A8ou_[ $֏ׇ.oԽCc A8kKubw|4Up^W[_ƙtntn!ƥ tؘ{GF&;$50uA@tKY> o5QV2>)B:y#&~׷*Zj67J:N'( 8YDedFܕ㚟}Zxune⧚TN ƤdMcC gQ >;buǤ&s^KぞpqZƵ; 4G"lj-=;__ #K/xrn;bcbRU<#~^i|$>xa1ĺAG$;GjKF:%ѣv2@g$KT&|Q򤳝ɸ7xLxKT֫sݕӤm0FU *TڊWz_tJ\ʹyW$xM^G$O #xdȝKȮOĞ-lb[V&tuA_4F1dTm v m84smkASz/tɫ]oL4[)|)n "U|)D-IƿءK v&*< `m5U*9-Y1l4 <3j3"Mn;54p(!'wcxG%VM[Ro67W(۵\~_G;O-< v2DNp&IΥ緒!#rbz4Re;/n?pǢiω?f{I&xV&d"A* F3Gcg6 g]E叅`K[ۘVhķWd0I6 2% IH,e?6>:gn<Mf{IZ8bbrI'wc!4/-R>.-t7`2o$ tNM14u4?7__4z5uC!REJ1 d`s?\ֿaC៊|Q^+k+Dx@]J#+v =xz 5mEjRvq~_ƃ펧1l`H4+c[i&ǘׁL9UT 5ږϧ^HD{YMš(V<^Vucjpq(70@RYAqge=0Axֿc#χC8ϵ@t$q+lPPwe ;頾15 {4V)wbich,@$yZaWtg%ZkԫuK20rQOٿ 5CO|:#GmlO~s׭{?|cxz]l|"eq <<6I3p--y ӌgsc׿1OWzmmѐ^9  ~&hm١uuq~thO q*jU(Ϳiڤ?;UI"kmڢ\$^{^3ywYh0]]J+g, (gsptȂGx>+lř,FI^~;m9O(alcݨp֨yTn23ڔmYRoD|߈IyHumz*@!Mۊજe8IU~h3_~_Oc_ڧ5"h'hN緓 ?"9qy|;#~~6|B4J;.5&i|ctY䱖U!7nݚkQ}UiZO~_uxf'QUif#-p0VSB%17;#OvXіY61SnE{.29k%z_Co˿iYk/A#A_By#+q%ڦ0>a{?s2{ G~&6]GT"K:]hZޣ5Qqoڭ03$m5K:hzt_7:a♍DX9N׍B)Fcn:NN2v]WO3s^umEͬHHp'+oG,> |MK{ᶺF6]emP`V0rUA@Ib0(Z[rѮҌaBKE}H(oJឩDVsQ/H/#Ud'?O|+>1J Ęc}ܶFHe$,EJQ̭oE*Z#lm~kzލ{'5n W<8$_sm/GI=ǦInһDߺ !13*g5K^י.4W]ᱚ+V D < \޹i^jW>\/ +\2&7Vjy& Hߞ^k>^\x2+(T#pާ5Ӂx)-[_a{&yֹmqk&mCt%bGg=^G:r\ZȷRH9\ԨBU*7vW}}_bg.?|_O!.{llRȻ0lɋf h^*meצC6 erL>UPIB{BxJWE#:wye>eοz2$ aC3n2zҺ{ G㾱 I2z{q}pxztkueRovMDh^+ų4BthLrwǟ__x1;~} !n$U<6F01_7(=|4T8c?iڷ^3ŸKgLg5´HVQ#_+DŽ^'-7#mvT6[vB6@w5ˇ8Ž.3iE(xoZϥA|E<(@8Mݻ.ax@n<'y] hJ6EĂ#U8Rʶ;qJ^&}1e4~ȿ ?NejK Iws7En#$v"pc?7R$/W6lAieyeف䀹5Ib>p?]3*__ ?gcRuCFkgK m6 q Fk?`&~Һ9tK5易I,֫Y@EIaUI=Z(a{|ogEqV7~XAi/= W"*A<%ެcVw}=ʫ$#(*(';f.rRpp~+ xkNpݼW]4̿tr1 esIj-/)*  r]Duv@=db 9 1_{Ư5cQG6I;)2N1\J\oE*Q?iOA"]"P@% y.dp>_7??>t;Y,P rIS1ZmPJ ǡhzgw^ſ |#\Iu}:_1#t]nx,F{U߈}kPuq,+9>Ӕ F1׵ΜfhgĞ69k6SG).~Ϣ {w/}xTO×~|i͢p'tY ceCJ")Sj%NPѣYTS7g `a'J'e]5oN dc*XnH`:q]+SYEjw06{~KYSVkzYN@;$U#o#s炾"\'H)˥b # `q]1Q"NV?pisa-3.0.32/test/._x.txt0000644000175000017500000000027011163672736013106 0ustar wmbwmbMac OS X  2ATTRFK  com.macromates.caretxR<[k0?'3/«pisa-3.0.32/test/story2canvas.py0000644000175000017500000000162311160170351014653 0ustar wmbwmb# -*- coding: ISO-8859-1 -*- ############################################# ## (C)opyright by Dirk Holtwick ## ## All rights reserved ## ############################################# __version__ = "$Revision: 194 $" __author__ = "$Author: holtwick $" __date__ = "$Date: 2008-04-18 18:59:53 +0200 (Fr, 18 Apr 2008) $" from reportlab.pdfgen.canvas import Canvas from reportlab.lib.units import inch from reportlab.platypus import Frame import ho.pisa as pisa def test(filename): # Convert HTML to "Reportlab Story" structure story = pisa.pisaStory("""

Sample

Hello World!

""" * 20).story # Draw to Canvas c = Canvas(filename) f = Frame(inch, inch, 6*inch, 9*inch, showBoundary=1) f.addFromList(story,c) c.save() # Show PDF pisa.startViewer(filename) if __name__=="__main__": test('story2canvas.pdf') pisa-3.0.32/test/pdfform.html0000644000175000017500000000170711160170351014171 0ustar wmbwmb HTML to PDF conversion example

Form Example

Name

Address

Country

Gender male female

Agree with conditions?

pisa-3.0.32/test/test-invoice.html0000644000175000017500000000676011160170351015151 0ustar wmbwmb Invoice #123
Hans Mustermann
Beispielweg 1

12345 Musterstadt
Rechnung #123 01. Dezember 2007

Sehr geehrte Kundin, sehr geehrter Kunde,
wir lieferten Ihnen die nachfolgend aufgeführten Artikel, die wir Ihnen hiermit in Rechnung stellen:

Artikel Menge Einheit Preis pro Einheit Gesamtpreis
Hosenträger 2 Stück 9,99 € 19,98 €
Zwischensumme 10,00 €
19% MWSt 10,00 €
Rechnungsbetrag 10,00 €

Bitte überweisen Sie den Rechnungsbetrag innerhalb der nächsten 14 Tage auf eines der unten angegebenen Konten. Herzlichen Dank im Voraus.

Mit freundlichen Grüßen

AGB

1.2

pisa-3.0.32/test/datauri.py0000644000175000017500000000260511160170351013647 0ustar wmbwmb# -*- coding: ISO-8859-1 -*- ############################################# ## (C)opyright by Dirk Holtwick ## ## All rights reserved ## ############################################# __version__ = "$Revision: 194 $" __author__ = "$Author: holtwick $" __date__ = "$Date: 2008-04-18 18:59:53 +0200 (Fr, 18 Apr 2008) $" import ho.pisa as pisa import os, os.path import logging log = logging.getLogger(__file__) def helloWorld(): filename = __file__ + ".pdf" datauri = pisa.makeDataURIFromFile('img/denker.png') bguri = os.path.normpath(os.path.join(os.path.abspath(__file__), os.pardir, "pdf/background-sample.pdf")) bguri = pisa.makeDataURIFromFile(bguri) html = u"""

Hello World

""" % (bguri, datauri) pdf = pisa.pisaDocument( html, file(filename, "wb"), path = __file__ ) if not pdf.err: pisa.startViewer(filename) if __name__=="__main__": pisa.showLogging() helloWorld() pisa-3.0.32/test/test-pre.html0000644000175000017500000000112411160170351014270 0ustar wmbwmb Unbenanntes Dokument

Lorem ipsum...

  1. Eins
 2.  Zwei
3.   Drei   

Lorem ipsum...

	
  1. Eins
2. Zwei 3. Drei
Ende

Some space     end of space

Some space end of space

pisa-3.0.32/test/test-linespacing.html0000644000175000017500000000630311160170351016002 0ustar wmbwmb Line Spacing

Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.

Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.

Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.

Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.

Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.

Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.

pisa-3.0.32/test/test-tables.html0000644000175000017500000000766311160170351014772 0ustar wmbwmb Table Test

Lorem ipsum...

1 2
3 4

Lorem ipsum...

1 2
3 4
LOREM

Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Donec euismod ante sed mi. Mauris tortor purus, fermentum sit amet, interdum et, rutrum nec, risus. Suspendisse erat nisi, vestibulum a, mattis at, dignissim quis, ante. Ut in dui. Etiam sed elit nec tellus vulputate tincidunt.

LOREM
In blandit justo sed lorem. Proin malesuada. Pellentesque dignissim sem tempus augue ultrices sagittis. Nulla ac justo quis quam bibendum adipiscing. Curabitur pharetra, ipsum at iaculis faucibus, quam massa egestas mi, et mollis tellus tellus ac sapien. Etiam odio. Vivamus posuere dapibus velit. Etiam eros dui, vulputate non, congue eu, elementum ac, tellus. Vestibulum ac sapien sit amet diam blandit sollicitudin. Aenean in augue. Suspendisse potenti. Proin a leo. Etiam consequat, neque sed vulputate hendrerit, nibh nibh vehicula justo, sed dapibus augue justo bibendum erat. Suspendisse iaculis. Curabitur tempus. Aenean ultricies nonummy pede. Nulla facilisi. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae; Cras sem. Cras dolor risus, consequat ut, viverra eget, viverra a, orci. LOREM In blandit justo sed lorem. Proin malesuada. Pellentesque dignissim sem tempus augue ultrices sagittis. Nulla ac justo quis quam bibendum adipiscing. Curabitur pharetra, ipsum at iaculis faucibus, quam massa egestas mi, et mollis tellus tellus ac sapien. Etiam odio. Vivamus posuere dapibus velit. Etiam eros dui, vulputate non, congue eu, elementum ac, tellus. Vestibulum ac sapien sit amet diam blandit sollicitudin. Aenean in augue. Suspendisse potenti. Proin a leo. Etiam consequat, neque sed vulputate hendrerit, nibh nibh vehicula justo, sed dapibus augue justo bibendum erat. Suspendisse iaculis. Curabitur tempus. Aenean ultricies nonummy pede. Nulla facilisi. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae; Cras sem. Cras dolor risus, consequat ut, viverra eget, viverra a, orci.
LOREM In blandit justo sed lorem. Proin malesuada. Pellentesque dignissim sem tempus augue ultrices sagittis. Nulla ac justo quis quam bibendum adipiscing. Curabitur pharetra, ipsum at iaculis faucibus, quam massa egestas mi, et mollis tellus tellus ac sapien. Etiam odio. Vivamu LOREM

Unten

Unten

xxx yyy

Lorem ipsum...

1 2
3 4

Lorem ipsum...

Lorem ipsum...

Lorem ipsum...

 

pisa-3.0.32/test/test-w3c-css.html0000644000175000017500000000051511160170351014767 0ustar wmbwmbmargin-top

Überschrift erster Ordnung

Bereich mit der Beispiel-Klasse.

Überschrift erster Ordnung

pisa-3.0.32/test/test-barcode.html0000644000175000017500000000011411160170351015077 0ustar wmbwmb

This is a test:

Next Line

pisa-3.0.32/test/css/0000755000175000017500000000000011201057433012432 5ustar wmbwmbpisa-3.0.32/test/css/test-css-media-3.css0000644000175000017500000000012711160170351016125 0ustar wmbwmb/* CSS Document */ @import "../test-css-media-4.css" print; .green6 { color: green; }pisa-3.0.32/test/css/reset.css0000644000175000017500000000612011160170351014264 0ustar wmbwmb* { margin: 0; padding: 0; font-weight: normal; font-style: inherit; font-size: 100%; font-family: inherit; /* vertical-align: baseline; */ list-style: none; } @media screen { html, body { height:100%; } } img, fieldset, legend, table, tr, td, th, tbody, tfoot, thead, applet, object, iframe, frame, frameset { border: 0; } h1, h2, h3, h4, h5, h6, pre, table, blockquote { clear: both; } body { line-height: 1.5; color: #000; background: #fff; font:13px/1.22 arial,helvetica,clean,sans-serif; font-style: normal; *font-size:small; *font:x-small; } input, textarea, select { font:13px/1.22 arial,helvetica,clean,sans-serif; *font-size:13px; } pre, code, kbd, samp, tt { font-family:monospace; *font-size:108%; line-height:99%; } /* Tables still need 'cellspacing="0"' in the markup. */ table { font-size:inherit; font:100%; table-layout: fixed; border-collapse: collapse; border-spacing: 0; empty-cells: show; } caption, th, td { text-align: left; font-weight: normal; empty-cells: show; vertical-align: top; } /* Remove possible quote marks (") from ,
. */ blockquote:before, blockquote:after, q:before, q:after { content: ""; } blockquote, q { quotes: "" ""; } /* CLEAR */ .clear { clear: both; } /* .clear { display: inline-block; height: 0; clear: both; } .clear:after, .container:after { content: "."; display: block; height: 0; clear: both; visibility: hidden; } * html .clear { height: 1%; } .clear { display: block; } */ /* HIDE */ .hide, .hidden { display: none; } /* FORM */ textarea.validation-failed, input.validation-failed, select.validation-failed { background: #FFFFCC; border: 2px solid red; } textarea.sample, input.sample { color: #999; } input.readonly { background: #eee; } input.required { } /* A container should group all your columns. */ .container { text-align: left; position: relative; padding: 0; margin: 0 auto; /* Centers layout */ width: 960px; /* Total width */ } .sidenote { width: 25%; float: right; margin-bottom: 0.5em; margin-left: 0.5em; padding: 0.5em; background: #ccc; overflow: hidden; } /* Print normalize */ @media print { html, body { background: white !important; color: black !important; width: 100% !important; height: inherit !important; } body a:link, body a:visited { background: transparent; text-decoration: underline; } body a[href*="http://"]:link:after, body a[href*="http://"]:visited:after { content: " <" attr(href) "> "; } body .noprint { display: none !important; } body .print { display: block !important; position: static !important; margin: 0 !important; padding: 0 !important; border: none !important; width: auto !important; height: auto !important; float: none !important; clear: both !important; overflow: inherit !important; } } /* CSS Document */ pisa-3.0.32/test/css/content.css0000644000175000017500000001504211160170351014617 0ustar wmbwmb.content * { margin: 0; padding: 0; /* font-weight: normal; */ font-style: inherit; font-size: 100%; font-family: inherit; /* vertical-align: baseline; */ list-style: none; } .content img, .content fieldset, .content legend, .content table, .content tr, .content td, .content th { border: 0; } .content { /* color: #000; background: #fff; */ font: 13px arial,helvetica,clean,sans-serif; font-style: normal; line-height: 150%; } .content h1, .content h2, .content h3, .content h4, .content h5, .content h6, .content pre, .content table, .content blockquote { clear: both; } .content input, .content textarea, .content select { font:13px/1.22 arial,helvetica,clean,sans-serif; } .content table { font-size:inherit; } .content pre, .content code, .content kbd, .content samp, .content tt { font-family:monospace; line-height:99%; background-color: #eee; } /* Tables still need 'cellspacing="0"' in the markup. */ .content table { font-size:100%; table-layout: fixed; border-collapse: collapse; border-spacing: 0; empty-cells: show; } .content caption, .content th, .content td { text-align: left; vertical-align: top; font-weight: normal; } .content blockquote:before, .content blockquote:after, .content q:before, .content q:after { content: ""; } .content blockquote, .content q { quotes: "" ""; } .content h1 { /*18px via YUI Fonts CSS foundation*/ font-size:138.5%; } .content h2 { /*16px via YUI Fonts CSS foundation*/ font-size:123.1%; } .content h3 { /*14px via YUI Fonts CSS foundation*/ font-size:108%; } .content h1, .content h2, .content h3 { margin:1em 0; } .content h1, .content h2, .content h3, .content h4, .content h5, .content h6, .content strong { font-weight:bold; } .content abbr, .content acronym { border-bottom:1px dotted #000; cursor:help; } .content sup, .content sub { line-height:-1px; vertical-align: text-top; font-size: 80%; } .content sub { vertical-align:text-bottom; } .content ins { color: green; text-decoration: underline; } .content del { color: red; text-decoration: line-through; } .content em, .content i { font-style: italic; } .content strong, .content b { font-weight: bold; } .content blockquote.blockquote { font-family: Georgia, "Times New Roman", Times, serif; font-style: italic; color: #111; } .content pre.content-pre { background: #eee; padding: .5em; border: 0; } .content pre { margin-bottom: 1em; } .content blockquote, .content ul, .content ol, .content dl { margin:1em; } .content ol, .content ul, .content dl { margin-left:2em; } .content li ol, .content li ul, .content li dl { margin-top: 0; margin-bottom: 0; } .content ol li { list-style: decimal outside; } .content ul li { list-style: disc outside; } .content dl dd { margin-left:1em; } /*** TABLE ***/ .content table { border-collapse: separate; border-spacing: 0; /* table-layout: fixed; */ } .content caption { margin-bottom:.5em; text-align:center; } /* TABLE BLACK */ .content table.table-black { border-left:1px solid #000; border-top:1px solid #000; border-collapse: separate; border-spacing: 0; margin-bottom:1em; } .content table.table-black th, .content table.table-black td { border-bottom:1px solid #000; border-right:1px solid #000; padding:.5em; } .content table.table-black th, .content table.table-black td.table-th { background: #000; color: #FFFFFF; font-weight: bold; } .content table.table-black tr.row-0 { background: #fff; } .content table.table-black tr.row-1 { background: #eee; } .content table.table-black tr.row-2 { background: #ddd; } /* TABLE RED */ .content table.table-red { border-left:1px solid red; border-top:1px solid red; border-collapse: separate; border-spacing: 0; margin-bottom:1em; } .content table.table-red th, .content table.table-red td { border-bottom:1px solid red; border-right:1px solid red; padding:.5em; } .content table.table-red th, .content table.table-red td.table-th { background: red; color: #FFFFFF; font-weight: bold; } .content table.table-red tr.row-0 { background: #fff; } .content table.table-red tr.row-1 { background-color: #FFDDDD; } .content table.table-red tr.row-2 { background-color: #FFBBBB; } /* TABLE RED */ .content table.table-blue { border-left:1px solid blue; border-top:1px solid blue; border-collapse: separate; border-spacing: 0; margin-bottom:1em; } .content table.table-blue th, .content table.table-blue td { border-bottom:1px solid blue; border-right:1px solid blue; padding:.5em; } .content table.table-blue th, .content table.table-blue td.table-th { background: blue; color: #FFFFFF; font-weight: bold; } .content table.table-blue tr.row-0 { background: #fff; } .content table.table-blue tr.row-1 { background-color: #DDDDFF; } .content table.table-blue tr.row-2 { background-color: #BBBBFF; } /* The above separated solution is a workaround for Firefox who draws the left border 1�x outside of the box */ * html .content table.table-black, * html .content table.table-red, * html .content table.table-blue { border-collapse: collapse; } /* * html .content th, * html .content td { border: 1px solid #000; } */ .content p, .content fieldset { margin-bottom:1em; } .content img.align-right { margin-left: 0.5em; margin-bottom: 0.5em; } /* .content img[align=left] */ .content img.align-left { margin-right: 0.5em; margin-bottom: 0.5em; } /* Helpers */ .content .readonly { background: #eee; } .content hr { background: #000; color: #000; clear: both; float: none; width: 100%; height: 0.1em; margin: 0 0 1.4em 0; border: none; } * html .content hr { margin: 0 0 1.2em 0; } .content label, .content .label { display: block; margin-top: 1em; margin-bottom: 0.25em; font-weight: bold; } .content fieldset legend { display: none; } .content fieldset label { font-weight: normal; margin: 0; } .content .highlight { background: yellow; } /*** COLUMNS ***/ div.col-left { float: left; clear: both; width: 48%; padding-right: 0.5em; overflow-x: hidden; } div.col-right { float: right; width: 48%; padding-left: 0.5em; overflow-x: hidden; } .content .clear { clear: both; } /*** EDIT ***/ .content-edit { margin: 0 !important; padding: 1em !important; width: auto !important; } /* Ob das so Sinn macht, wegen Margin Collapse .content-edit div, .content-edit iframe, .content-edit blockquote, .content-edit fieldset, .content-edit pre { border: 1px dotted #ccc; } */ .content-edit table { border-left: 1px dotted #ccc; border-top: 1px dotted #ccc; } .content-edit td, .content-edit th { border-bottom: 1px dotted #ccc; border-right: 1px dotted #ccc; }pisa-3.0.32/test/test-unicode-all.html0000644000175000017500000023420611160170351015707 0ustar wmbwmb Earth Words: Abuse Information in Languages A-I, Unicode links


Universal Declaration
of Human Rights
(in 366 languages)
     

Domestic Violence Information in Languages A-Z:

A to I J to Z Multi-Lingual Try relevant country


                    A B C | D E F | G H I


A

  Afrikaans Albanian (Shqip) አማርኛ (Amharic) عربي (Arabic)
     

B

  Bahasa Melayu (Malay language) বাংলা (Bengali) Bosanski (Bosnian) Български (Bulgarian)
     

C

  ខ្មែរ (Cambodian (Khmer)) Catalan Castellano 中文 (Chinese) Cree Creole Croatian (Hrvatski) Cymraeg (Welsh) Czech (Cesky)
     

D

  Dansk (Danish) دری Dari Dene Deutsch (German) ދިވެހި Dhivehi Dinka (Thuɔŋjäŋ) Dutch (Nederlands)
     

E

  Eesti (Estonian) Ελληνικα (Greek) English Español (Spanish)
     

F

  فارسى (Farsi) Fijian (Na vosa vaka-Viti) Filipino (Tagalog) Finnish (Suomi) Français (French)
     

G

  ქართული (Georgian (Kartuli)) German (Deutsch) Greek (Ελληνικα) ગુજરાતી (Gujarati)
     

H

  Haitian Creole עברית (Hebrew (Ivrit)) हिन्दी (Hindi) Hmong Hrvatski (Croatian) Hungarian (Magyar)
     

I

  Icelandic Indonesian Inuinnaqtun Inuktitut Irish Italiano (Italian)
     


Afrikaans

Wat jy kan doen as jy verkrag is What to do if you have been raped
Mediese Behandeling ná Verkragting Medical treatment following rape
Inligting vir vriende, familie en ondersteuners van verkragting oorwinners Information for friends, family and supporters of rape survivors

above links from Rape Crisis Cape Town

see also South Africa



አማርኛ Amharic                 

ሚሰትን ማጉሳሳት ሁከትን አቁም Wife Assault: Let's Break the Silence
የባልና የሚሰት ሁከት መሳውን ቤተሰብ ይጎዳል Domestic violence hurts the whole family



                 Arabic عربي

I want the violence to stop! كفى عنفا
Just for Kids للأطفال فقط
Are you being abused? هل تساء معاملتك؟
What is domestic violence? Aus ما هو العنف المنزلي؟
The Survivor's Handbook دﻟﯿﻞ اﻟﻨﺎﺟﯿﺔ ﺑﺘﻤﻮﯾﻞ ﻣﻦ
Stop violence against women أوقڧوا العنف ضدّ النساء
One blow is one too many صفعة واحدة زيادة عن الحد
For Immigrant & Refugee Women للنساء المهاجرات و اللاجئات
Information for young people المعلومات التالية موجهة للشباب
Creating a Safety Plan کﻴﻒ ﺗﻀﻌﻴﻦ ﺧﻄﺔ لﺘﺄﻣﻴﻦ ﺳﻼﻣﺘﻚ
Domestic violence hurts the whole family العنف المنزلي يؤذي العائلة بكاملها
Dating Violence العنف في علاقات المصاحبة العاطفية
Wife Assault: Let's Break the Silence الاعتداء على الزوجة: لنكف عن الصمت
Domestic Violence: Help from NIWAF العنف في المنزل - المسا عدة من اتحاد مساعدة المر أة

see also Middle East, Northern Africa


Bahasa Melayu Malay Langiage

Keganasan Terhadap Wanita Violence Against Women
Penderaan Seksual Kanak - Kanak Child Sexual Abuse

see also Malaysia



বাংলা Bengali                 

আমরাই পারি নারীর বিরুদ্ধে সকল নির্যাতন বন্ধ করতে We can end all violence against women
দ্যা সারভাইভারস্ হ্যান্ডবুক The Survivor's Handbook
নিজের বাড়িতে নিরাপদে থাকার অধিকার আপনার আছে You Have the Right to Be Safe
পারিবারিক নির্যাতন প্রতিরোধ করুন Defend Against Domestic Violence also in

see also Bangladesh



Bosanski Bosnian                


Zaustavi nasilje nad ženama Stop violence against women
Sta je obiteljsko nasilje? What is Domestic volence?
Nasilje u kuci uništava cijelu porodicu Domestic violence hurts the whole family

see also Bosnia Herzegovina



Български Bulgarian                 

Български център за джендър изследвания Bulgarian Gender Research Foundation
 Учебные Програмы Domestic Violence Training Modules
 Въведение Introductory Block:
Примерно упражнение "Запознаване" Sample Acquaintance Exercise
Примерно упражнение "Очаквания" Sample Expectations Exercise
 Дефиниране на проблема Identifying the Problem:
Какво е домашно насилие? What Is Domestic Violence?
 Справяне с проблема Addressing the Problem:
Оценяване на фатално и особено опасно поведение Assessing Dangerous Behavior
Усъвършенстване на полицейските техники за разследване Improving Law Enforcement Investigations
Подобряване на съдебната реакция към домашното насилие Improving Judicial Response to DV

see also Bulgaria



Catalan

see Andorra, Spain



中文 Chinese                 

虐待是有悖文明的惡行。 Abuse is wrong in any language
虐妻 Wife Assault: Let's Break the Silence
不要動武 I want the violence to stop!
約會暴力 Dating Violence
您是否正在受到虐待? Are you being abused?
性侵犯 是甚麼意思? Sexual Assault: What it means
生存者手册 The Survivor's Handbook
家庭暴力 - 婦女援助會提供的協助 Domestic Violence: Help from NIWAF
供移民及難民的受虐婦女參考 For Immigrant & Refugee Women
制訂一項 安全計劃 Creating a Safety Plan
家庭暴力使整個家庭受損 Domestic violence hurts the whole family
甚麼是家庭暴力? What is domestic violence? Aus
儿童园地 Just for Kids
獻給青少年 Information for young people
"藍天網", 一個有關家庭暴力的網址 Project Blue Sky on Wayback Machine
中国妇女网 All-China Women's Federation

参见 China, Taiwan, Macau



Cree Nēhiýawēwin ᓀᐦᐃᔭᐁᐧᐃᐧᐣ                 

(recommended fonts: Canadian Syllabics Fonts)

Kikitimahikawin cī? Are you being abused?
ᑭᑭᑎᒪᐃᑲᐃᐧᐣ ᒌ? Are you being abused?



Cymraeg Welsh

Llinell Gymorth Camdriniaeth yn y Cartref Cymru Wales Domestic Abuse Helpline


Czech Cesky

Týrání je neprijatelné v kazdém jazyce Abuse is wrong in any language

see also Czech Republic



Dansk Danish

Kvinder I Krise Women in Crisis on Wayback Machine Stop volden mod kvinder Stop violence against women
European Campaign to Raise Awareness of Violence Against Women

se også Denmark



                Dari دری




Dene                 

(recommended fonts: one of either Aboriginal Serif, Code2000, TITUS Cyberbit Basic or Arial Unicode MS)


Danelʔa húsą́ ? Edlą́ghę dene daghelʔa bek´ólyą ? Nets´édiį́ hąt´e sį. Are you being abused?
ʔąłnedhe haze, t´ahúk´e ną́dher sí ʔasíe hots´én danįt´a húsą́, danelʔa húsą́ ? Abuse info for teens



Deutsch German

Voreheliche Gewalt Dating Violence
Information zum Thema Gewalt aus Wien Information about violence from Vienna
Notruf und Beratung für verGEWaltigte Frauen und Mädchen e.V. Wuppertal
Europäische Kampagne zur Sensibilisierung gegen Gewalt an Frauen

sehen Sie auch Germany, Austria, Switzerland, Liechtenstein



Dhivehi ދިވެހި

see Maldives



Dinka Thuɔŋjäŋ

Ye ŋo yen ya akɛk baai? What is domestic violence? Aus



Eesti Estonian

Ava silmad! Speaking, Surviving, Healing

see also Estonia



Ελληνικα Greek                 

Η Βία σε Δεσμούς Dating Violence
Η Σεξουαλική Βία: Τι σημαίνει Sexual Assault: What it means
Πληροφορίες για τους νέους Information for young people
Εγχειριδιο Διαβιωσης The Survivor's Handbook
European Campaign to Raise Awareness of Violence Against Women

δείτε επίσης Greece



English

Dragonslippers: This is what an abusive relationship looks like by Rosalind B. Penfold
    "Of any English resource I've ever read, this book does the best job of showing the fundamentals of an abusive relationship. It is very user-friendly and very powerful! Get this book!"—webmom, Hot Peach Pages
 Ai Abuse iNFO & Resources
Learn the warning signs of abuse
Abuse is wrong in any language
Abuse is wrong in any culture
Wife Assault: Let's Break the Silence
I want the violence to stop!
General Info on Abuse
Are you being abused?

Just for Kids
Info for Teens
Information for young people
Dating Violence also in

Sexual Assault: What it means
Sexual Assault: Myths and Facts USA
Acquaintance Rape and Sexual Exploitation: What Adults Can Do To Help Teens USA

What is domestic violence? Aus
What is domestic violence? USA
Stop Violence Against Women
The Survivor's Handbook
Domestic Violence: Help from Northern Ireland Women's Aid Federation
One blow is one too many
Domestic violence hurts the whole family
Power & Control and Equality Wheels
For Immigrant & Refugee Women
You Have the Right to Be Safe

Safety Plan
Creating a Safety Plan
Safety Planning

Spousal Abuse Canada
National Clearinghouse on Family Violence Canada
Project Blue Sky on Wayback Machine
European Campaign to Raise Awareness of Violence Against Women




Español Spanish Castellano

Violencia Doméstica contra las Mujeres UNIFEM Domestic Violence against Women malos tratos España Violencia familiar en Perú
Coalicion Puertorriquena Contra la Violencia Doméstica

Domestica Violencia Información USA
Información Española USA
La violencia doméstica USA
Encontrando seguridad y apoyo USA
Ayude a poner fin a la violencia doméstica USA
Centro de Justicia Para Mujeres USA
Para Mujeres Inmigrantes y Refugiadas USA
¿Qué es la violencia doméstica?  What is domestic violence? USA
Ruedas del Poder y Control y de la Igualdad Power & Control and Equality Wheels
Plan de Seguridad Safety plan
Cómo crear un Plan de Seguridad Creating a Safety Plan
Asalto sexual: Mitos y realidades USA

¿Qué es la violencia doméstica? What is domestic violence? Aus
Cómo apoyar a las víctimas de la violencia en el hogar Supporting someone who experiences domestic violence Aus
Información para los jóvenes, Information for young people

El abuso es concenable en cualquier idioma Abuse is wrong in any language
Agresión a la Mujer: Rompamos el silencio Wife Assault: Let's Break the Silence
Que termine la violencia! I want the violence to stop!
La violencia durante las citas amorasas Dating Violence
La Agresión Sexual: Lo que significa Sexual Assault: What it means
Sólo para Niños Just for Kids
¿Está siendo abusada/abusado? Are you being abused?

El Manual del Superviviente the Survivor's Handbook
European Campaign to Raise Awareness of Violence Against Women

vea también Spain, Central America & Caribbean, South America, USA (some states)



                Farsi فارسى

see also Iran



Fijian Na vosa vaka-Viti

Na Cava Na Veivakalolomataki E Na Loma Ni Vuvale What is domestic violence? Aus



Français French

La violence est inacceptable peu importe la langue Abuse is wrong in any language
La violence est inacceptable peu importe la culture Abuse is wrong in any culture
La violence faite aux femmes: Rompons le silence Wife Assault: Let's Break the Silence
La violence dans les fréquentations aussi en Dating Violence
Pour les enfants seulement Just for kids
Êtes-vous violentée? Are you being abused?
L’élaboration d’un plan de sécurité Creating a Safety Plan
La Violence Conjugale: Dissiper les mythes Family Violence: Dispelling the myths

L'agression sexuelle: Ce qu'elle signifie Sexual Assault: What it means
Agressions sexuelles: mythes et réalités USA
Le viol par un proche et l'exploitation sexuelle: ce que peuvent faire les adultes pour aider les adolescents USA

Roues de pouvoir et contrôle et d'égalité Power & Control and Equality Wheels USA

Un seul coup est de trop One blow is one too many
Site pour des professionnels de santé sur les Violences Conjugales Site for health sector professionals regarding Domestic Violence
Campagne européenne de sensibilisation contre la violence à l'égard des femmes

voir aussi France, Switzerland, Belgium, Canada, Haïti



ગુજરાતી Gujarati                 

ધ સરવાઇવર હેન્ડબુક The Survivor's Handbook
તમને તમારા ધરમા સુરક્ષિત રહેવાનો અધિકાર છે You Have the Right to Be Safe



Haitian Creole

Bat Fanm: Sispann vyolans-la Wife Assault: Let's Break the Silence
Kisa K Vyolans Domestik ( The Domestic Violence Handbook)
Pouvwa avèk kontwòl & egal ego



                Hebrew Ivrit עברית

see also Israel



हिन्दी Hindi                 

हिंसा मुकत जीवन सबका अघिकाट है We can end all violence against women
पत्नी की मारपीट को रोकिए Wife Assault: Stop it
घरेलू हिंसा - ' वीमेन्ज़ एड ' से मदद Domestic Violence: Help from NIWAF
किसी को भी हिंसा या भय के साथ जीने की ज़रूरत नहीं है । No one deserves to live with violence or fear
एक सुरक्षा यीजना की रचना करना Creating a Safety Plan



Hmong

Kev tsim txom Domestic violence



Hrvatski Croatian                


Kućno nasilje vrijeđa cijelu obitelj Domestic violence hurts the whole family
Informacije za mlade ljude Information for young people

see also Croatia, Bosnia Herzegovina



Icelandic

see Iceland



Indonesian






Hot Peach Pages: International by CaNetiq
International directory of abuse hotlines, shelters,
refuges, crisis centres and women's organizations,
plus domestic violence information in over 75 languages.
Email the Hot Peach Pages
Page last modified: November 14, 2008
pisa-3.0.32/test/test-align.html0000644000175000017500000000464511160170351014607 0ustar wmbwmb Unbenanntes Dokument

NORMAL Lorem ipsum...

CENTER Lorem ipsum...

RIGHT Lorem ipsum...

LEFT Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Donec euismod ante sed mi. Mauris tortor purus, fermentum sit amet, interdum et, rutrum nec, risus. Suspendisse erat nisi, vestibulum a, mattis at, dignissim quis, ante. Ut in dui. Etiam sed elit nec tellus vulputate tincidunt. Nunc tortor risus, dignissim in, tempor a, sodales vel, erat. Aenean metus ipsum, vulputate vel, eleifend sed, tristique sed, nibh. Aliquam erat volutpat. Sed lobortis fringilla mauris. Nullam convallis ullamcorper urna. Integer id justo sed pede suscipit convallis. Cras non purus sed nisi faucibus scelerisque. Donec ullamcorper massa id risus. Vivamus tristique hendrerit neque. Maecenas pulvinar ipsum dictum ante. Cras eleifend lacus. Suspendisse et massa. Vestibulum sit amet lacus. In sed libero. Duis quis enim sit amet lorem ultrices rhoncus.

JUSTIFY Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Donec euismod ante sed mi. Mauris tortor purus, fermentum sit amet, interdum et, rutrum nec, risus. Suspendisse erat nisi, vestibulum a, mattis at, dignissim quis, ante. Ut in dui. Etiam sed elit nec tellus vulputate tincidunt. Nunc tortor risus, dignissim in, tempor a, sodales vel, erat. Aenean metus ipsum, vulputate vel, eleifend sed, tristique sed, nibh. Aliquam erat volutpat. Sed lobortis fringilla mauris. Nullam convallis ullamcorper urna. Integer id justo sed pede suscipit convallis. Cras non purus sed nisi faucibus scelerisque. Donec ullamcorper massa id risus. Vivamus tristique hendrerit neque. Maecenas pulvinar ipsum dictum ante. Cras eleifend lacus. Suspendisse et massa. Vestibulum sit amet lacus. In sed libero. Duis quis enim sit amet lorem ultrices rhoncus.

CENTER CLASS Lorem ipsum...

CENTER STYLE Lorem ipsum...

CENTER ID Lorem ipsum...

CENTER STYLE ATTR Lorem ipsum...

 

pisa-3.0.32/test/test-bidirectional-text.html0000644000175000017500000006363411163174620017320 0ustar wmbwmb Bidirectional Text

Bidirectional text · Bidirectional text

This page contains some accompanying examples to Alan Flavell’s “I18n – text direction”. Examples that are supposed to display incorrectly (i.e. not as intended) in either Mozilla or Internet Explorer 6 are in red. Read the source text to understand how it’s done!

You can specify text direction by (paired) Unicode control characters, by (paired) control characters written as numeric references, by HTML markup, or by CSS properties. Control characters are restricted to plain text and are not suitable for use with markup languages (except lrm and rlm). The preferred method for HTML is to use HTML markup. Use control characters written as numeric references only in places where no markup is possible, such as attribute values (alt, title, etc.). Occasionally it may be convenient to specify text direction via CSS; for example, to set the direction of columns in tables rather than to put a dir attribute into each and every <td>.

In the following table, div represents any block-level element, and span represents any inline element.

Plain text HTML 4   CSS 2
control chars control chars markup properties
not applicable not applicable <div dir=ltr>
...... </div>
direction: ltr;
unicode-bidi: normal
not applicable not applicable <div dir=rtl>
...... </div>
direction: rtl;
unicode-bidi: normal
U+202A
...... U+202C
&#8234;
...... &#8236;
<span dir=ltr>
...... </span>
direction: ltr;
unicode-bidi: embed
U+202B
...... U+202C
&#8235;
...... &#8236;
<span dir=rtl>
...... </span>
direction: rtl;
unicode-bidi: embed
U+202D
...... U+202C
&#8237;
...... &#8236;
<bdo dir=ltr>
...... </bdo>
direction: ltr;
unicode-bidi: bidi-override
U+202E
...... U+202C
&#8238;
...... &#8236;
<bdo dir=rtl>
...... </bdo>
direction: rtl;
unicode-bidi: bidi-override
U+200E &lrm; not applicable not applicable
U+200F &rlm; not applicable not applicable

Basic test

If the line below is displayed as “12 11 10 9 8 7 6 5 4 3 2 1 0”, then your browser recognizes the dir attribute and it is probably ready for right-to-left text. Preferably, the line should be right-aligned.

0 1 2 3 4 5 6 7 8 9 10 11 12

Control (formatting) characters

The control or formatting characters U+202A to U+202E are not suitable for use with HTML. If they are written directly into the source text, they interfere with the left-to-right markup and make editing or even viewing the source a nightmare. Furthermore, the bidirectional algorithm stops at newlines. It would no longer be possible to structure the source text by newlines, which could separate, for example, the paired U+202B and U+202C.

The closing U+202C or &#8236; is sometimes implied and may be omitted like the closing </p> and </td> in HTML. Nevertheless, it is safer to close always explicitly.

To write “שבת [שאבעס]”, you can use HTML markup with <span dir=rtl> or, exceptionally, write the control characters &#8235; and &#8236; as numeric references. Inserting the control characters U+202B and U+202C directly results in a mess when viewing the source.

&#8235;<B lang="he">שבת</b> [<I>שאבעס</i>]&#8236;

‫<B lang="he">שבת</b> [<I>שאבעס</i>]‬

Advice

Never use UTF-8-encoded control characters, but only character references like &#8235; and &rlm;.


The dir attribute

Three directional levels

Three or more directional levels (here: Latin > Hebrew > Latin) must be defined by control characters or, preferably, by HTML markup. The third line has no dir markup and is thus displayed as having only two directional levels.

The words mean “Congratulations!”

The words “מזל טוב” mean “Congratulations!”

The words “מזל [mazel] טוב [tov]” mean “Congratulations!”

The words “מזל [mazel] טוב [tov]” mean “Congratulations!”

Letters and digits

Numbers, which are always written from left to right, are likely to mess with right-to-left text. For example, “12 345” denote two numbers and should be displayed as “345 12”. On the other hand, “12&nbsp;345” denotes a single number and should always be displayed as “12 345”.

The first line is from Google’s Urdu interface with overall dir=rtl; the second line has proper dir markup. (Both lines are written in the restricted MacUrdu character set.)

© 2004 Google – 90 00 000 ويب صفحات كى تلاش هو رهى هے

© 2004 Google – 90 00 000 ويب صفحات كى تلاش هو رهى هے

© 2004 Google – 9 000 000 veb safahāt kī talāš ho rahī hai

Advice

Always specify the dir attribute for each piece of text, starting with <body dir=ltr> or <body dir=rtl>.


The bdo element

Left-to-right Hebrew

To write Hebrew letters from left to right, you need the bdo element in addition to the attribute dir=ltr.

The vowels α ε η ι ο derive from א ה ח י ע, resp.

The vowels α ε η ι ο derive from א ה ח י ע, resp.

The next examples assume a right-to-left context (dir=rtl) such as an Arabic-language page. The date 31 December 1999 is to be shown in all-numeric form: 1999-12-31. The first line in each example is the one where Internet Explorer 6 fails.

European (North African) digits

The ASCII hyphen is a European number separator. Therefore, no special markup should be necessary. However, Internet Explorer 6 needs dir=ltr.

1999-12-31

1999-12-31

Arabic-Indic digits with non-breaking hyphen

The non-breaking hyphen (&#8209;) is another neutral. Therefore, markup with <bdo dir=ltr> is necessary for all browsers.

١٩٩٩‑١٢‑٣١

١٩٩٩‑١٢‑٣١

Arabic-Indic digits with slash

The traditional Arabic date format calls for the slash as separator and the suffix م (mīlād = birth), meaning “AD”. The slash is a common number separator. Therefore, no special markup should be necessary. However, Internet Explorer 6 needs <bdo dir=ltr>.

١٩٩٩/١٢/٣١ م

١٩٩٩/١٢/٣١ م

Advice

Use the attribute dir=ltr with European digits and the tag <bdo dir=ltr> with Arabic-Indic digits.


The lrm and rlm characters

The left-to-right mark (&lrm; = &#8206;) and the right-to-left mark (&rlm; = &#8207;) are alternative ways to specify the direction of neutral characters such as punctuation marks or spaces. The above examples are rewritten here using &lrm;.

Left-to-right Hebrew

The vowels α ε η ι ο derive from א ה ח י ע, resp.

The vowels α ε η ι ο derive from א‎ ה‎ ח‎ י‎ ע, resp.

European (North African) digits

1999-12-31

‎1999-12-31‎

Arabic-Indic digits with non-breaking hyphen

١٩٩٩‑١٢‑٣١

١٩٩٩‎‑‎١٢‎‑‎٣١

Arabic-Indic digits with slash

١٩٩٩/١٢/٣١ م

١٩٩٩‎/‎١٢‎/‎٣١ م

Letters and digits

© 2004 Google – 90 00 000 ويب صفحات كى تلاش هو رهى هے

© 2004 Google – ‏90 00 000 ويب صفحات كى تلاش هو رهى هے

© 2004 Google – ‏9000000 ويب صفحات كى تلاش هو رهى هے

The second line does not work in Internet Explorer 5, which needs a number without spaces. This example shows that the explicit markup with the dir attribute is more reliable than the implicit &lrm; and &rlm; marks.


The zwnj character

The zero-width non-joiner (&zwnj; = &#8204;) is necessary for writing Persian where certain affixes and compound words do not join. It is shown by a hyphen in the transliterated words below.

Persian plurals

هفته hafteh week
هفته‌ها hafteh-hā weeks
هفتهها haftehhā wrong
موزه mūzeh museum
موزه‌ها mūzeh-hā museums
موزهها mūzehhā wrong

Compound words

سه seh three
سه‌شنبه seh-šanbeh Tuesday
سهشنبه sehšanbeh wrong
راه rāh way, road
راه‌آهن rāh-āhan railway
راهآهن rāh’āhan wrong
نرم narm soft
نرم‌افزار narm-afzār software
نرمافزار narmāfzār wrong

The zwj character

The zero-width joiner (&zwj; = &#8205;) is necessary to show isolated glyphs of the Arabic letters. At least Mozilla needs it when Arabic letters are separated by HTML markup. (The zero-width joiner does not work with earlier browser versions such as Netscape 7.0 or Internet Explorer 5.)

Markup inside Arabic text

جس‍‍ي‍‍م jasīm gros
جس‍‍ام jisām gros pl.
جس‍‍ي‍‍م‍‍ة jasīmah grosse
جس‍‍ي‍‍م‍‍ات jasīmāt grosses
أجسم ajsam plus gros(se(s))
الأجسم al-ajsam le plus gros
الأج‍‍اسم al-ajāsim les plus gros
ال‍‍جسم‍‍ى al-jusmā la plus grosse
ال‍‍جسم‍‍يات al-jusmayāt les plus grosses

Isolated glyphs

ن · س · ت · ع · ل · ي · ق  ←  ن س ت ع ل ي ق  ←  نستعليق

ن · س · ت · ع · ل · ي · ق  ←  ن‍ ‍س‍ ‍ت‍ ‍ع‍ ‍ل‍ ‍ي‍ ‍ق  ←  ن‍‍س‍‍ت‍‍ع‍‍ل‍‍ي‍‍ق

On the other hand, Internet Explorer 6 joins letters even when they are separated by markup. Therefore you still need an additional &zwnj; if the letters shall not join.

سههزار ، دههزار

سههزار ، دههزار

Urdu aspiration

The zero-width joiner can also be used to write Urdu text in and for the restricted MacUrdu character set where the two-eyed he (&#1726;) is not available.

هفته haftah week
هاته hāth wrong
هاته‍ hāth hand
ديده dīdah eye
دوده dūdh wrong
دوده‍ dūdh milk

Sindhi non-connecting he

The sequence &zwj;&zwnj; is needed for Sindhi where the initial form of the letter he (ﻫ) is used as consonant, while the connecting form (ﻬ) is reserved for aspiration.

جهنگل jhangalu jungle
گهر gharu house
منهن munhun wrong
من‍‌هن munhun mouth
ويه vīha wrong
وي‍‌ه‍ vīha twenty

Further reading

Persian word processing   /   ZWNJ   –   ZWJ


xx Andreas Prilop
30 August 2007

pisa-3.0.32/test/test-css-id.html0000644000175000017500000000121511160170351014665 0ustar wmbwmb Standardfarbe: grau
grau

blau gruen blau

pisa-3.0.32/test/test-all/0000755000175000017500000000000011201057433013367 5ustar wmbwmbpisa-3.0.32/test/test-all/01.jpg0000644000175000017500000001650611160170351014320 0ustar wmbwmbJFIFxxC   %# , #&')*)-0-(0%()(C   (((((((((((((((((((((((((((((((((((((((((((((((((((&?"D  !1A"Q2Uaq#$7Rbru%43Bt5 !A1Qa"2qbB#3 ? d|X"Za\IJ[u?Y$(JnwZH'[?jk<܍4)JJRR|@Lu:|} i o@HR+fjP=2JUhWp,8Ҵ,Wu1_mUuoj,Ȝyy5&O/kK~< gGF|ȩWC 맋hIR;i d% m,{[lGz 0׸⸡ $C`Lܑjq{rZ\[K0mhB *~P Tl=K8ik@R؝JcBZ"oxe 8˜i>GJSo}ԥGxMr${$֎U$)Q7mT}V(hhR>꒠FnQ|_fq\|k{m$JP T %T("zJR4vRO:iiu8,JRR >CGc׻~Ehbg_H@Hҫ{cwri\<W)#32uɹ.6 ~*wk+C5Tr_Ufk R o1&x& 'd4A(*JI@uЊM $lV1o_N]#٬WWM WJi:<bqVf5>q#Nm8rJ6Dؑvv;OjWVY"yKm_#M$)>~~@m3QxJ-]NU(tθ?i J[TԢ];MVk5xqlQZlqD iӨ-UJY\Ӥ@dW 7ۛe&C-+m֜Gs۸>c}y3=C[0±G;).؟ifSEd A_"R\xX:R,>sr G^HNz~5mPDRږ⒄$)J:RkY ˌԈ-PRVGbơL()JJ^Qfo+orr{r7)BS[#aZ|m[+ݾqA#•rqLG+ZRTFA=@HҔ()^]q-4:BR 7`JҲ]a-.vx2'OҀ#U@|!xl'x_6wVŲtO­ dLy_W/DF! Islz}]z}=bŧZ/>$I-%T6PI~*:a"v8ݧ"])R0))J m$QL#go}tk\E,/ncܹ)Iǿ[w fj7 QZ+I*i;ւIQaw2U7;5 9 l~_}[oR2|#78a)EĖCZ։V5r@f#mc>{oBP2|<ƫo9vnj=؍an PZQ ހyw'ZcMv2"\ JZ}D^dV,n(i+쁥RS Us F_i ,b)1G *^;ԣ'sHsV:Qs!+Tu-jRI@$[osv:ӖmQVH/L#NVR'@EZ]{'r3Yvԓp^-kЙ=kYqAM;R?`+O)|eslˋxR61۴ʒP_,q_r;:_`O]-0(V8w=](Hr12n-I$c~`w^U)y*{wպܯ6]bۣ툏nhCJ[qg.8Ő(`3v\;ڀ[|`\p#~? q@waݒx2[Wr<:̛Yd&>/>m2_[3pAN6TG-|*B]b6siy H)5$,iZQ o-V(*yӄe߇B*Vnx\g%BQ9ίu$62?Te1{-ِ)/>1P ;۵J)˿5_^_y&2$+NI$3< -I )BQwQKN7ϓVN3RƎQ'l'tz6u.ɀӎ/N I$Wow -p,H#I=xZ:o<^ḇ܃L yQ=5+]IP>g޴!ԭqm! ׫+J%sy*vR1K[sBA곟6#`3NN]3åOLx>.lNy:-֌+A}D)4AxS̍vZ-5rIӘ0[ìo@(1@kU\v3,De6V1Ku$J-V9ӾZqQь6M/GAP/;r/ǵEc}z:;MmOsܞjM(Hc1Ԗg':n1w-{Gᢊtw+3P+JyEgA}=GRyJ}H a ($qv$})]T:}wuS:*,`JAgFğƫ/zNWV>!z۪4A#ELxZsJ#˹DsGCu#SkHRT t | eJ&ޅKl I#`TtǬvP`cbki;>AmyiCE֞rDKj1Nqu9ؔФ^)!Jhzk~ꋤ{ $: tL\'9%\\^*JF·C:d߳\G>`Q8N)J1|7].bmr95q9(s#:޵]]yN-Ei.Ӯ;6Rḅ|HF)\Ѱ?amK͇B[i! ) *66v[v Xȋ4X YKEaBtuҬצoqڋyׂk \ vX`գ}R-)W#Q:ZzYeej|fWՒCbW{_eWq#T<.\w^D{%cRm߼D#"=0I ;%DхeqL"ԋM*>pwh-z#] ̭X,m&Mdmm9?X%h;@=o-Ers oOZK}>ޘ^&z큹B*$'i!${w|zLb1Uе$yry>Uyvkf.H;vKVP(-Î=79cɷ-` :qPА?Z`s \-ou%=|RJT>'dw\[AfGR_Z;錰jW1N^J\.[KY$k\tG^k%ޯY2D߸YP]@D(lu2n)K]OgRmLγ~-AvT4t:P@]pOvYw^J ) O0|rN%[pkun/\v*^锋|\5kr滌IJi_5$Fʗ!'۴+{h]g2_F.]S.R-rJu!!@ZkCJc6,2^E ro6Sh ln8=LdMBo)G+qH) kZNJ.]q b!XJJ[<i>Dg{cʣYu;%]XIuv%M , %JWzyϛ\y9 *NMM4$S+'!wI=3bm_1y,OB݂_!hm![]ˎY3Lat*÷-F*!C;$G>?ڹ'R}0rO14*`j䟨ciJT?P詃~٥(SW$C]*Oe\|xǏ'_\{( )JJRR(h_r ,Uلȃ-ӭ#)QPʜ9GOl_K}HRζI:(q ?HMl=(Z"T*|HCd=ҕ#RCu;%}"e Z'@ Hߘ):-V'*lwQ$ikcKY?J|:m #@z()JJRR()JJRR()JJRR?pisa-3.0.32/test/test-all/02.jpg0000644000175000017500000002743511160170351014324 0ustar wmbwmbJFIFxxC   %# , #&')*)-0-(0%()(C   ((((((((((((((((((((((((((((((((((((((((((((((((((("H!1"A2QaBq#3$7Vb4Cu%(5Rrs0!1AQ"aqBRbr ?D@DDD@DDD@Ruo4fרo>l/ 4v9c5 {ռ+њ릡x1|T[a1>ItYsrO1sr:o~_' O5U_COYHe=Dm7p8=GCK[xQM-q"Q4t=3CMMX`ց?6؜xF^TDZr""" """ """ """ """ wmgi+NtW"|-Bs0qɋ?3e/3~͛c9sU7kMoݒ(({ :8mq#LNFBd[!GRQ1ANǶHhW+x|lT\'mrg:L09nZY'yR~=VRO?3❮-7 M5&ۇwh1 7bˍ=,x'D=u#>,Î)h1@K v=]:wԗ:-7(ZKzJʡhãqA=V܉$ 8AY%}sg]1itdq'3 kz2)(Hֆ9;=<,w|(C;pT[`50d. c-gXM%DQCxR=!0 {)Q4k#S5eIy!UC+F-"I!)Kms^^$ٵeoΣ.]6ُcђ2qd4Fyg?vA5y󳿦٪xgX)4D uid e-8%hF*䜤fMβ\PO ;s-T3Fc5>F=ctҔ.*M@ ;wGAԂqk(h᷽7x}+ʫuݭ4旽XN(䉮dS`u{8-nqom#>ݶ\溼ni<>¼"--fNI_w6ڳ_/s8jľy$gܖ%(U'/*DZ@DDD@DDD@DDD@DDD@DDD@DDD@DDD@DDD@DDD@DDD@DDD@DDD@DDD@DDD@DDD@DDD@DDD@DDD@DU$Z*<ay{=qg챵lEJ1ݖdU*ݨ<|nͲ96s=՝SN.>Ec[k5'⋐{?]qi;U[_' O5A[]ea}3[8&^:u' ?(J96C)JsHqGGk inj~hN^=Ǻ*^vcsӖZc0 Jxj^1==“A_D4쫺WX[4kG߰tq #l+6Ȉ3H";%iqKu1+"ӷh/}ڍTF@ p#=}R i" "/SE+Hǘݱk@~Fj=*L䩆't66tˆ~UַKu;W4I`HXWznTMCRϧƗSUZ!9z bOaJȯW]i8v#!If u{6[.h<Rw۸#*CѶ?ԶL:y0rCq׺7[αT8掞VЙIo(HsnOu7Ʃ %'9ap=A/~&UyTviA ;I ;UU1h9iZ tUּKh鍾y ^Ք:~ESjKP?0X( )O{5U|sJ&ߪ굽Kp;.mԮ&(ه?i8'OF^'tT.}^w 5 5+gᮡo&q1׹q +g*gj_$QCFH.䎇8V8}՚UJ;n9Dm#=/5tzj)[h< gNָx5eҟC'Z.oNc:W7 x=0뽮OQ6/ArCi8`ߜ{]`φXQfDDD@DDD@gIw )|g⡅as\^c*/$2Utܔ KEQ}1nB\_Kve13\z%u[-Tʚh H2]%]5)I~N}O]JTXL69G1 s샌$m"t?5бx/4ѻHqt*}Nl*E[U0XM34k 6%զKmLe#q$Pէَ{y?G>fXeK"Xi]vqŬL=TTʭAx*h)>x cTmc Zp [.W'.m4އ>Vib5#ie+6nw#ߝHj`Yήi|@E@)J|aoݰoOˍ&G U~kntwP>hfFv1N6UFI_)vkoRX-G=u+sωRdNϨdUr#mvJܗ=XYَ#NOcpkg7+wI~ 5 p\㖴'uٞ]U56\GmG#\3CE-ZIpgz١AQ I6fl.{Z13*/eeLS9ϝf:m؉9nn8㡢֭ZF%Am[8y` 3P/t2 h. cNDII$ORhz|2~1hG|mQ )o9҈NїB/noA:j˭,"*y.Fi#g<7! .88 --E:_tuTzM_W/jDՒ2h!; 66KIqhw1aoVK]h۱g4w.K%%D<֌\:hGT:I^O 0^Xy]kOuP-Psk!UӐ:ièimE9IK~tK{W: ~Yy6T"'$ܛlh!n.>;`vrzcnw߮7"(/uCM7=kk`)ʩGTږeAxzsD^47 T46$52>Ya33/9F=F2rAoor0 I=yӲã󙶲_P&$%T=Z2J6} pyuUN1#8;Cz`:H$GINOpHDDD@DDD@DDD@DDD@DDD@DDD@DDD@DDD@DDD@DDD@DDD@DDD@DDD@DDD@DDD@DDD@DDD@DDD@DDD@DDD@DDD@DDD@DDD@DDD@DDD@DD\&k+'9xd/G^ӌ yOBĵivGv%gP"ŸCaV7 ៏?축|,(uaA IAT'mS^NK\0NԃVmYG4ԶW6Hd|k{ZIc{(\)IemвpOX\5ւ᥆Ik0`ts^ލ"  ^^*4^(hh娍X\֒ 㧱 $UbHEUf՚|UuZC 'JLDDfFW=5E 9)/s*0 8}G).zji}/w^2j%Qm֨##c.ld%=ZB-R1% ^^*4^(hh娍X\֒ 㧱 EW4 q#/4O֩&Z """ """ 6~أ˭Ilnd!wtjMI"PVh⫷UI(HǏpW ՖI5taE}7)#߷o霨..Ѡ=M= ]+IEKh|> tD$]JPmyEq ]ŀq`6_ Wc䃁N;R%=TK)WU6*s72_4?n:͵|A71s_I9} rʾN^k}-S_ptѺYeyƁWz)QeQ\`c:JI3Zg+\k+V ۳=ܽ<˞lɥK~7 OŢ[ xg5}MlOqČ6:{]9|7nA]>eЙk}B?}#J MMѺ-dN|]6s4~ұ^tړ(:zVݛь彻yW$RNzzJ5Y%nqrm5umKOճ [ `t 8Ub{Fo՗O46I$i9h 8Ӊ')ɵ[aqO5j7Vm 6`N#~3䴏q=k.jpSa9Ľ<5ZӅQG4#{L=#B'5]8.ii^\)* 1nO+[?ߴU_sQnw Jq#FPk)Ue3@fA(^F}upo o4^gx{;os}S­Ji*nR^Z}ی'U^prå8oSUZfU$z`n@=XxAlS=K+|ª(c4e#}%Go;E5[v(cWM|I7io>Z.]728M;nS:,:^ #|gHslc? a[NQi:CjdHq=;Z-Ph}cmz`M`%o ݸm=ׯ-2]\96~EM&kk~i ?\8> k>Z#OOW'2fn;$9/n~ۧ8y-`6Ejc3klQ$uƀQ̼/yn6C/:̸d־eWR.Fyv?iH*{SKS̤.1X5.ԕW FMTZWRKAHrt%ln# scQY8glSۙQ4rdp[t''h<jhyYd\3IB|{)p,8 KE>QB`iZѽ%Vt,[Z|3MrӺRi}>ZX6E;}pH 5?F,>/x&s|q9ۓR={CEuϡOn =9h\uC͂ߙh4՛nKu.pSm5-/HݠpI4U[EMB٧69#%|mMkKH>]'oyu 5N}5$vtPl:g@u&.𼍼>"YYv:bb^u=ÛFk+NYfVInu\*r2zGoM7ejj3(EO[&y8E8@h9錍eTVyVlr9s;n;vUKwH$55dt3Z t92GN2ZjjV,$ۓk_j ֖[MDGqU[*˨50[\~I3:STq_M `Rp1J7A$zDž.n`kU`?VV̟Ö$ԣd)+<őGj1D4]Yg7*d$ԌtGc[lfղ\EC/06Q}0;(t"+iYd3PGX#qv=3ds|k'*%ϵe|7j;vJz*fa s㝧#'1svgj.c箖y$s#CN~|&ॶ>4}43&4.29, __4w{{t6s+Mι)*^/yWYt֢[e%e_chp$aWUM/?+m3gy4]iSj_@rۏk \b]%qr93hh_'3w|Goϻۺ;e[U(ns) qLhJCpY?Ǥu;(| kӳvaQMЖ`mij IW;>}8""!]%8K],ړL],T]v;}xwm C7;AN::vURCQyr7=FB&-PMCuVQM(#k$c#^\lkXƱ kF `ů=?IO\4Z~ڸ1&hI;5+uZys3KOfo,`ÏsܕA)pOC~ezO5K+$idTکZHK ed.ZYN**^٘{r%urFRQzU68^r/Ϋ+TZbEqT\!/t#/sW^,<3)t͛w#-_N,%(oa_:RkxttGT[7rTS(*c K4{-ASj~_*G;kCA ةKu3[*⡟վrAA^W#m".6ߠו6n']bN<@iz08Hj-KgӖWݯWzZܶW~pkw8pITN(pOMkʉ./Nf ]0Hq=3/:vU]46pdpskI`Y7 g+ )( RS&vC;.U-~!Y݌n{``tPrr0" """ """ ""uP]GvqTXH9yva3m3chYgdDCmDC" """ """ """ """ ?pisa-3.0.32/test/test-syntax.html0000644000175000017500000000165311160170351015037 0ustar wmbwmb Das ist der Titel

Lorem hidden bold=red normal silverblue silver orange yellow amet nochwas normal

Weiterer sit Absatz

Anfang DIV 1
AD2

Test

ED2

Ende DIV 2
pisa-3.0.32/test/font/0000755000175000017500000000000011201057433012610 5ustar wmbwmbpisa-3.0.32/test/font/README.txt0000644000175000017500000000033711160170351014310 0ustar wmbwmbThe font of this directory have not been included into the SVN because of copyright issues. The names of the fonts are: - CODE2000 (TTF) - DejaVu (TTF) - Forelle (AFM + PFB) - leerc (AFM + PFB) - milano (TTF) - rina (TTF) pisa-3.0.32/test/simple-test.html0000644000175000017500000000617411160170351015005 0ustar wmbwmb

Das ist ein einfaches Beispiel. Etwas Text zum üben und fertig. Das ist ein einfaches Beispiel. Etwas Text zum üben und fertig. Das ist ein einfaches Beispiel. Etwas Text zum üben und fertig. Das ist ein einfaches Beispiel. Etwas Text zum üben und fertig.

Das ist ein einfaches Beispiel. Etwas Text zum üben und fertig.Das ist ein einfaches Beispiel. Etwas Text zum üben und fertig. Das ist ein einfaches Beispiel. Etwas Text zum üben und fertig. Das ist ein einfaches Beispiel. Etwas Text zum üben und fertig.

Das ist ein einfaches Beispiel. Etwas Text zum üben und fertig.Das ist ein einfaches Beispiel. Etwas Text zum üben und fertig. Das ist ein einfaches Beispiel. Etwas Text zum üben und fertig. Das ist ein einfaches Beispiel. Etwas Text zum üben und fertig. g. Das ist ein einfaches Beispiel. Etwas Text zum üben und fertig. g. Das ist ein einfaches Beispiel. Etwas Text zum üben und fertig. g. Das ist ein einfaches Beispiel. Etwas Text zum üben und fertig. g. Das ist ein einfaches Beispiel. Etwas Text zum üben und fertig.

Das ist ein einfaches Beispiel. Etwas Text zum üben und fertig.Das ist ein einfaches Beispiel. Etwas Text zum üben und fertig. Das ist ein einfaches Beispiel. Etwas Text zum üben und fertig. Das ist ein einfaches Beispiel. Etwas Text zum üben und fertig.

Das ist ein einfaches Beispiel. Etwas Text zum üben und fertig.Das ist ein einfaches Beispiel. Etwas Text zum üben und fertig. Das ist ein einfaches Beispiel. Etwas Text zum üben und fertig. Das ist ein einfaches Beispiel. Etwas Text zum üben und fertig.

Das ist ein einfaches Beispiel. Etwas Text zum üben und fertig.Das ist ein einfaches Beispiel. Etwas Text zum üben und fertig. Das ist ein einfaches Beispiel. Etwas Text zum üben und fertig. Das ist ein einfaches Beispiel. Etwas Text zum üben und fertig.

Das ist ein einfaches Beispiel. Etwas Text zum üben und fertig.Das ist ein einfaches Beispiel. Etwas Text zum üben und fertig. Das ist ein einfaches Beispiel. Etwas Text zum üben und fertig. Das ist ein einfaches Beispiel. Etwas Text zum üben und fertig.

pisa-3.0.32/test/test-link.html0000644000175000017500000000063311160170351014443 0ustar wmbwmb Unbenanntes Dokument Lorem ipsum... Test Test Test pisa-3.0.32/test/test-pisa-toc.html0000644000175000017500000000422411160170351015225 0ustar wmbwmb

Table of Contents

1. Blender

Blender is a software that is used for creating 3D content. Primarily this means you can make three dimensional images. However, you can also add sound, and make it time-based and interactive. This makes Blender ideal for a wide range of uses including creating 3D models, rendering, post -production, story boarding, creating animations, making movies, creating 3D 'programs', and making interactive environments and games.

2. Blender's Unique Interface

­It's no secret that the Blender interface breaks a lot of rules. Luckily Blender has good reasons for it and after time these reasons become clear. Blender's interface is built around providing you with the shortest routes to the most results. It's also particularly focused on reducing the kind of stress on wrists and hands that's often felt when using mouse-intensive graphical applications every day.

3. Installing Blender on OSX

Software Name: Blender
Homepage: http://www.blender.org
Software version used for this installation: Blender 2.43
Operating System used for thisinstalltion: OSX (10.4.8)
Reccomended Hardware: Powerbook G4, Powermac G5, Mac Pro, MacBookPro, iMac (core Duo)

Downloading

The latest stable version of Blender for OSX can be downloaded at http://www.blender.org/download/get-blender/

pisa-3.0.32/test/x.txt0000644000175000017500000000104711163672736012674 0ustar wmbwmbConverting test-font-img-error.html to /Users/dirk/work/xhtml2pdf-30/test/test-font-img-error.pdf... code2000 -> code2000_00 code2000 -> code2000_00 code2000 -> code2000_00 code2000 -> code2000_00 Helvetica -> Helvetica code2000 -> code2000_00 code2000 -> code2000_00 code2000 -> code2000_00 code2000 -> code2000_00 code2000 -> code2000_00 code2000 -> code2000_00 code2000 -> code2000_00 code2000 -> code2000_00 code2000 -> code2000_00 code2000 -> code2000_00 code2000 -> code2000_00 code2000 -> code2000_00 code2000 -> code2000_00 *** ERRORS OCCURED pisa-3.0.32/test/test-font.html0000644000175000017500000000164411160170351014457 0ustar wmbwmb Unbenanntes Dokument

Lorem ipsum äöü ÄÖÜ ß @ €...

Lorem ipsum äöü ÄÖÜ ß @ €...

Lorem ipsum äöü ÄÖÜ ß @ €...

Lorem ipsum äöü ÄÖÜ ß @ €...

pisa-3.0.32/test/test-background.html0000644000175000017500000000075511160170351015632 0ustar wmbwmb Background Lorem ipsum... pisa-3.0.32/test/test-css-body.html0000644000175000017500000000110611160170351015225 0ustar wmbwmb

Test bold normal underline normal pisa-3.0.32/test/test-image.html0000644000175000017500000000045511160170351014572 0ustar wmbwmb

Image #0 (BIG!)

Image #1

Image #2

Image #3

Image #4
pisa-3.0.32/test/witherror.py0000644000175000017500000000132611160170351014242 0ustar wmbwmb# -*- coding: ISO-8859-1 -*- ############################################# ## (C)opyright by Dirk Holtwick ## ## All rights reserved ## ############################################# __version__ = "$Revision: 194 $" __author__ = "$Author: holtwick $" __date__ = "$Date: 2008-04-18 18:59:53 +0200 (Fr, 18 Apr 2008) $" import ho.pisa as pisa def helloWorld(): filename = __file__ + ".pdf" pdf = pisa.CreatePDF( u"Hello World ", file(filename, "wb"), show_error_as_pdf=True, ) if not pdf.err: pisa.startViewer(filename) if __name__=="__main__": pisa.showLogging() helloWorld() pisa-3.0.32/test/test-pisa-linkfont.html0000644000175000017500000000047311160170351016266 0ustar wmbwmb xxx pisa-3.0.32/VERSION.txt0000644000175000017500000000000611177602626012561 0ustar wmbwmb3.0.32pisa-3.0.32/setup.cfg0000644000175000017500000000023011201057433012477 0ustar wmbwmb[sdist] formats = gztar, zip [bdist] formats = wininst [egg_info] tag_build = tag_date = 0 tag_svn_revision = 0 [install] compile = 1 optimize = 1 pisa-3.0.32/PKG-INFO0000644000175000017500000000647411201057433011773 0ustar wmbwmbMetadata-Version: 1.1 Name: pisa Version: 3.0.32 Summary: PDF generator using HTML and CSS Home-page: http://www.xhtml2pdf.com Author: Dirk Holtwick Author-email: dirk.holtwick@gmail.com License: GNU General Public License (GPL) Download-URL: http://pypi.python.org/pypi/pisa/ Description: pisa is a html2pdf converter using the ReportLab Toolkit, the HTML5lib and pyPdf. It supports HTML 5 and CSS 2.1 (and some of CSS 3). It is completely written in pure Python so it is platform independent. The main benefit of this tool that a user with Web skills like HTML and CSS is able to generate PDF templates very quickly without learning new technologies. Easy integration into Python frameworks like CherryPy, KID Templating, TurboGears, Django, Zope, Plone, Google AppEngine (GAE) etc. (see 'demo' folder for examples) Keywords: PDF,HTML,XHTML,XML,CSS Platform: UNKNOWN Classifier: Development Status :: 5 - Production/Stable Classifier: Development Status :: 6 - Mature Classifier: Environment :: Console Classifier: Environment :: MacOS X Classifier: Environment :: Other Environment Classifier: Environment :: Web Environment Classifier: Environment :: Win32 (MS Windows) Classifier: Framework :: Django Classifier: Framework :: Plone Classifier: Framework :: Pylons Classifier: Framework :: TurboGears Classifier: Framework :: Zope2 Classifier: Framework :: Zope3 Classifier: Intended Audience :: Customer Service Classifier: Intended Audience :: Developers Classifier: Intended Audience :: Education Classifier: Intended Audience :: Financial and Insurance Industry Classifier: Intended Audience :: Healthcare Industry Classifier: Intended Audience :: Information Technology Classifier: Intended Audience :: Legal Industry Classifier: Intended Audience :: Manufacturing Classifier: Intended Audience :: Science/Research Classifier: Intended Audience :: System Administrators Classifier: Intended Audience :: Telecommunications Industry Classifier: License :: Free for non-commercial use Classifier: License :: OSI Approved :: GNU General Public License (GPL) Classifier: Natural Language :: English Classifier: Natural Language :: German Classifier: Operating System :: MacOS Classifier: Operating System :: MacOS :: MacOS X Classifier: Operating System :: Microsoft Classifier: Operating System :: Microsoft :: MS-DOS Classifier: Operating System :: Microsoft :: Windows Classifier: Operating System :: Other OS Classifier: Operating System :: POSIX Classifier: Operating System :: POSIX :: Linux Classifier: Operating System :: Unix Classifier: Topic :: Documentation Classifier: Topic :: Internet Classifier: Topic :: Multimedia Classifier: Topic :: Office/Business Classifier: Topic :: Office/Business :: Financial Classifier: Topic :: Office/Business :: Financial :: Accounting Classifier: Topic :: Printing Classifier: Topic :: Text Processing Classifier: Topic :: Text Processing :: Filters Classifier: Topic :: Text Processing :: Fonts Classifier: Topic :: Text Processing :: General Classifier: Topic :: Text Processing :: Indexing Classifier: Topic :: Text Processing :: Linguistic Classifier: Topic :: Text Processing :: Markup Classifier: Topic :: Text Processing :: Markup :: HTML Classifier: Topic :: Text Processing :: Markup :: XML Classifier: Topic :: Utilities Requires: html5lib Requires: pypdf Requires: pil pisa-3.0.32/LICENSE.txt0000644000175000017500000004300111160170402012500 0ustar wmbwmb GNU GENERAL PUBLIC LICENSE Version 2, June 1991 Copyright (C) 1989, 1991 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 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 Lesser 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) 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 version 2. 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 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) year 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 Lesser General Public License instead of this License. pisa-3.0.32/sx/0000755000175000017500000000000011201057433011315 5ustar wmbwmbpisa-3.0.32/sx/__init__.py0000644000175000017500000000106211160170354013427 0ustar wmbwmb# -*- coding: ISO-8859-1 -*- ############################################# ## (C)opyright by Dirk Holtwick, 2002-2007 ## ## All rights reserved ## ############################################# __version__ = "$Revision: 128 $" __author__ = "$Author: holtwick $" __date__ = "$Date: 2008-01-10 21:26:42 +0100 (Do, 10 Jan 2008) $" __svnid__ = "$Id: __init__.py 128 2008-01-10 20:26:42Z holtwick $" # Also look in other packages with the same name from pkgutil import extend_path __path__ = extend_path(__path__, __name__) pisa-3.0.32/sx/pisa3/0000755000175000017500000000000011201057433012334 5ustar wmbwmbpisa-3.0.32/sx/pisa3/pisa_turbogears.py0000644000175000017500000000224111072375237016111 0ustar wmbwmb# -*- coding: ISO-8859-1 -*- ############################################# ## (C)opyright by Dirk Holtwick, 2002-2007 ## ## All rights reserved ## ############################################# __reversion__ = "$Revision: 20 $" __author__ = "$Author: holtwick $" __date__ = "$Date: 2007-10-09 12:58:24 +0200 (Di, 09 Okt 2007) $" from turbogears.decorator import weak_signature_decorator import sx.pisa3 as pisa import StringIO import cherrypy def to_pdf(filename=None, content_type="application/pdf"): def entangle(func): def decorated(func, *args, **kw): output = func(*args, **kw) dst = StringIO.StringIO() result = pisa.CreatePDF( StringIO.StringIO(output), dst ) if not result.err: cherrypy.response.headers["Content-Type"] = content_type if filename: cherrypy.response.headers["Content-Disposition"] = "attachment; filename=" + filename output = dst.getvalue() return output return decorated return weak_signature_decorator(entangle) topdf = to_pdf pisa-3.0.32/sx/pisa3/__init__.py0000644000175000017500000000220011114712635014444 0ustar wmbwmb# -*- coding: ISO-8859-1 -*- ############################################# ## (C)opyright by Dirk Holtwick, 2002-2007 ## ## All rights reserved ## ############################################# __reversion__ = "$Revision: 238 $" __author__ = "$Author: holtwick $" __date__ = "$Date: 2008-06-26 20:06:02 +0200 (Do, 26 Jun 2008) $" REQUIRED_INFO = """ **************************************************** IMPORT ERROR! %s **************************************************** The following Python packages are required for PISA: - Reportlab Toolkit >= 2.2 - HTML5lib >= 0.11.1 Optional packages: - pyPDF - PIL """.lstrip() import logging log = logging.getLogger(__name__) try: from pisa import * if not REPORTLAB22: raise ImportError, "Reportlab Toolkit Version 2.2 or higher needed" except ImportError, e: import sys sys.stderr.write(REQUIRED_INFO % e) log.error(REQUIRED_INFO % e) raise __version__ = VERSION pisa-3.0.32/sx/pisa3/._pisa_tables.py0000644000175000017500000000035111200743122015404 0ustar wmbwmbMac OS X  2ATTR9=QQcom.apple.quarantineq/0000;49cba683;Safari.app;9AFF29BE-A1F8-4D2F-A543-8AC395074CD0|com.apple.Safaripisa-3.0.32/sx/pisa3/pisa_reportlab.py0000644000175000017500000007736611200024632015731 0ustar wmbwmb# -*- coding: ISO-8859-1 -*- ############################################# ## (C)opyright by Dirk Holtwick, 2002-2007 ## ## All rights reserved ## ############################################# __reversion__ = "$Revision: 20 $" __author__ = "$Author: holtwick $" __date__ = "$Date: 2007-10-09 12:58:24 +0200 (Di, 09 Okt 2007) $" from reportlab.platypus.doctemplate import BaseDocTemplate, PageTemplate, FrameBreak, NextPageTemplate from reportlab.platypus.tables import Table, TableStyle from reportlab.platypus.flowables import Flowable, Image, CondPageBreak, KeepInFrame, ParagraphAndImage from reportlab.platypus.frames import Frame from reportlab.platypus.tableofcontents import TableOfContents from reportlab_paragraph import Paragraph from reportlab.lib.utils import * try: import PIL.Image as PILImage except: try: import Image as PILImage except: PILImage = None from pisa_util import * from pisa_default import TAGS, STRING import copy import cgi import logging log = logging.getLogger("ho.pisa") MAX_IMAGE_RATIO = 0.95 class PmlMaxHeightMixIn: def setMaxHeight(self, availHeight): self.availHeightValue = availHeight if availHeight < 70000: if hasattr(self, "canv"): if not hasattr(self.canv, "maxAvailHeightValue"): self.canv.maxAvailHeightValue = 0 self.availHeightValue = self.canv.maxAvailHeightValue = max( availHeight, self.canv.maxAvailHeightValue) else: self.availHeightValue = availHeight if not hasattr(self, "availHeightValue"): self.availHeightValue = 0 return self.availHeightValue def getMaxHeight(self): if not hasattr(self, "availHeightValue"): return 0 return self.availHeightValue class PmlBaseDoc(BaseDocTemplate): """ We use our own document template to get access to the canvas and set some informations once. """ def beforePage(self): # Tricky way to set producer, because of not real privateness in Python self.canv._doc.info.producer = "pisa HTML to PDF " ''' # Convert to ASCII because there is a Bug in Reportlab not # supporting other than ASCII. Send to list on 23.1.2007 author = toString(self.pml_data.get("author", "")).encode("ascii","ignore") subject = toString(self.pml_data.get("subject", "")).encode("ascii","ignore") title = toString(self.pml_data.get("title", "")).encode("ascii","ignore") # print repr((author,title,subject)) self.canv.setAuthor(author) self.canv.setSubject(subject) self.canv.setTitle(title) if self.pml_data.get("fullscreen", 0): self.canv.showFullScreen0() if self.pml_data.get("showoutline", 0): self.canv.showOutline() if self.pml_data.get("duration", None) is not None: self.canv.setPageDuration(self.pml_data["duration"]) ''' def afterFlowable(self, flowable): # Does the flowable contain fragments? if getattr(flowable, "outline", False): self.notify('TOCEntry', ( flowable.outlineLevel, cgi.escape(copy.deepcopy(flowable.text), 1), self.page)) class PmlPageTemplate(PageTemplate): def __init__(self, **kw): self.pisaStaticList = [] self.pisaBackgroundList = [] self.pisaBackground = None PageTemplate.__init__(self, **kw) def beforeDrawPage(self, canvas, doc): canvas.saveState() try: # Background pisaBackground = None if (hasattr(self, "pisaBackground") and self.pisaBackground and (not self.pisaBackground.notFound())): # print self.pisaBackground.mimetype # Is image not PDF if self.pisaBackground.mimetype.startswith("image/"): try: img = PmlImageReader(StringIO.StringIO(self.pisaBackground.getData())) iw, ih = img.getSize() pw, ph = canvas._pagesize width = pw # min(iw, pw) # max wfactor = float(width) / iw height = ph # min(ih, ph) # max hfactor = float(height) / ih factor = min(wfactor, hfactor) w = iw * factor h = ih * factor canvas.drawImage(img, 0, ph - h, w, h) # print repr(img) except: log.exception("Draw background") # PDF! else: pisaBackground = self.pisaBackground # print "+", pisaBackground self.pisaBackgroundList.append(pisaBackground) # canvas.saveState() #try: # self.pml_drawing.draw(canvas) #except Exception, e: # # print "drawing exception", str(e) # pass try: # Paint static frames pagenumber = str(canvas.getPageNumber()) for frame in self.pisaStaticList: frame = copy.deepcopy(frame) story = frame.pisaStaticStory # Modify page number for obj in story: if isinstance(obj, PmlParagraph): for frag in obj.frags: if frag.pageNumber: frag.text = pagenumber elif isinstance(obj, PmlTable): # Accessing private member, but is there any other way? for subobj in flatten(obj._cellvalues): if isinstance(subobj, PmlParagraph): for frag in subobj.frags: if frag.pageNumber: frag.text = pagenumber frame.addFromList(story, canvas) except Exception, e: log.debug("PmlPageTemplate", exc_info=1) finally: canvas.restoreState() _ctr = 1 class PmlImageReader(object): "Wraps up either PIL or Java to get data from bitmaps" _cache = {} def __init__(self, fileName): if isinstance(fileName, PmlImageReader): self.__dict__ = fileName.__dict__ #borgize return #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 imageReaderFlags = 0 if PILImage and isinstance(fileName, PILImage.Image): 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: self.fp = open_for_read(fileName, 'b') if isinstance(self.fp, StringIO.StringIO().__class__): imageReaderFlags = 0 #avoid messing with already internal files if imageReaderFlags > 0: #interning data = self.fp.read() if imageReaderFlags & 2: #autoclose try: self.fp.close() except: pass if imageReaderFlags & 4: #cache the data if not self._cache: from rl_config import register_reset register_reset(self._cache.clear) data = self._cache.setdefault(md5(data).digest(), data) self.fp = getStringIO(data) elif imageReaderFlags == - 1 and isinstance(fileName, (str, unicode)): #try Ralf Schmitt's re-opening technique of avoiding too many open files self.fp.close() del self.fp #will become a property in the next statement self.__class__ = LazyImageReader if haveImages: #detect which library we are using and open the image if not self._image: self._image = self._read_image(self.fp) if getattr(self._image, 'format', None) == 'JPEG': self.jpeg_fh = self._jpeg_fh else: from reportlab.pdfbase.pdfutils import readJPEGInfo try: self._width, self._height, c = readJPEGInfo(self.fp) except: raise RuntimeError('Imaging Library not available, unable to import bitmaps only jpegs') self.jpeg_fh = self._jpeg_fh self._data = self.fp.read() self._dataA = None self.fp.seek(0) except: et, ev, tb = sys.exc_info() if hasattr(ev, 'args'): a = str(ev.args[ - 1]) + (' fileName=%r' % fileName) ev.args = ev.args[: - 1] + (a,) raise et, ev, tb else: raise def _read_image(self, fp): if sys.platform[0:4] == 'java': from javax.imageio import ImageIO return ImageIO.read(fp) elif PILImage: return PILImage.open(fp) 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): if sys.platform[0:4] == 'java': self._width = self._image.getWidth() self._height = self._image.getHeight() else: self._width, self._height = self._image.size return (self._width, self._height) def getRGBData(self): "Return byte array of RGB data as string" if self._data is None: self._dataA = None if sys.platform[0:4] == 'java': import jarray from java.awt.image import PixelGrabber width, height = self.getSize() buffer = jarray.zeros(width * height, 'i') pg = PixelGrabber(self._image, 0, 0, width, height, buffer, 0, width) pg.grabPixels() # there must be a way to do this with a cast not a byte-level loop, # I just haven't found it yet... pixels = [] a = pixels.append for i in range(len(buffer)): rgb = buffer[i] a(chr((rgb >> 16) & 0xff)) a(chr((rgb >> 8) & 0xff)) a(chr(rgb & 0xff)) self._data = ''.join(pixels) self.mode = 'RGB' else: im = self._image mode = self.mode = im.mode if mode == 'RGBA': self._dataA = PmlImageReader(im.split()[3]) im = im.convert('RGB') self.mode = 'RGB' elif mode not in ('L', 'RGB', 'CMYK'): im = im.convert('RGB') self.mode = 'RGB' self._data = im.tostring() return self._data def getImageData(self): width, height = self.getSize() return width, height, self.getRGBData() def getTransparent(self): if sys.platform[0:4] == 'java': return None else: if self._image.info.has_key("transparency"): transparency = self._image.info["transparency"] * 3 palette = self._image.palette try: palette = palette.palette except: palette = palette.data return map(ord, palette[transparency:transparency + 3]) else: return None def __str__(self): global _ctr _ctr += 1 " This is needed because of a bug in Reportlab _digester func " return "PmlImageObject_%s_%d" % (id(self), _ctr) # return "PmlImageObject_%s_%s" % (hash(id(self)), hash(self.fileName)) class PmlImage(Flowable, PmlMaxHeightMixIn): #_fixedWidth = 1 #_fixedHeight = 1 def __init__(self, data, width=None, height=None, mask="auto", mimetype=None, **kw): self.kw = kw self.hAlign = 'CENTER' self._mask = mask self._imgdata = data # print "###", repr(data) self.mimetype = mimetype img = self.getImage() if img: self.imageWidth, self.imageHeight = img.getSize() self.drawWidth = width or self.imageWidth self.drawHeight = height or self.imageHeight def wrap(self, availWidth, availHeight): " This can be called more than once! Do not overwrite important data like drawWidth " availHeight = self.setMaxHeight(availHeight) # print "image wrap", id(self), availWidth, availHeight, self.drawWidth, self.drawHeight width = min(self.drawWidth, availWidth) wfactor = float(width) / self.drawWidth height = min(self.drawHeight, availHeight * MAX_IMAGE_RATIO) hfactor = float(height) / self.drawHeight factor = min(wfactor, hfactor) self.dWidth = self.drawWidth * factor self.dHeight = self.drawHeight * factor # print "imgage result", factor, self.dWidth, self.dHeight return (self.dWidth, self.dHeight) def getImage(self): #if self.kw: # print "img", self.kw, hash(self._imgdata) img = PmlImageReader(StringIO.StringIO(self._imgdata)) # print id(self._imgdata), hash(img.getRGBData()) return img def draw(self): img = self.getImage() self.canv.drawImage( img, 0, 0, self.dWidth, self.dHeight, mask=self._mask) def identity(self, maxLen=None): r = Flowable.identity(self, maxLen) return r class PmlParagraphAndImage(ParagraphAndImage, PmlMaxHeightMixIn): def wrap(self, availWidth, availHeight): # print "# wrap", id(self), self.canv # availHeight = self.setMaxHeight(availHeight) self.I.canv = self.canv result = ParagraphAndImage.wrap(self, availWidth, availHeight) del self.I.canv return result def split(self, availWidth, availHeight): # print "# split", id(self) if not hasattr(self, "wI"): self.wI, self.hI = self.I.wrap(availWidth, availHeight) #drawWidth, self.I.drawHeight return ParagraphAndImage.split(self, availWidth, availHeight) # if 1: # import reportlab.platypus.paragraph # Paragraph = reportlab.platypus.paragraph.Paragraph # class PmlParagraph(reportlab.platypus.paragraph.Paragraph): # pass class PmlParagraph(Paragraph, PmlMaxHeightMixIn): def _calcImageMaxSizes(self, availWidth, availHeight): self.hasImages = False availHeight = self.getMaxHeight() for frag in self.frags: if hasattr(frag, "cbDefn") and frag.cbDefn.kind == "img": self.hasImages = True img = frag.cbDefn # print "before", img.width, img.height width = min(img.width, availWidth) wfactor = float(width) / img.width height = min(img.height, availHeight * MAX_IMAGE_RATIO) # XXX 99% because 100% do not work... hfactor = float(height) / img.height factor = min(wfactor, hfactor) img.height = img.height * factor img.width = img.width * factor # print "after", img.width, img.height def wrap(self, availWidth, availHeight): availHeight = self.setMaxHeight(availHeight) style = self.style self.deltaWidth = style.paddingLeft + style.paddingRight + style.borderLeftWidth + style.borderRightWidth self.deltaHeight = style.paddingTop + style.paddingBottom + style.borderTopWidth + style.borderBottomWidth # reduce the available width & height by the padding so the wrapping # will use the correct size availWidth -= self.deltaWidth availHeight -= self.deltaHeight # Modify maxium image sizes self._calcImageMaxSizes(availWidth, self.getMaxHeight() - self.deltaHeight) # call the base class to do wrapping and calculate the size Paragraph.wrap(self, availWidth, availHeight) #self.height = max(1, self.height) #self.width = max(1, self.width) # increase the calculated size by the padding self.width = self.width + self.deltaWidth self.height = self.height + self.deltaHeight return (self.width, self.height) def split(self, availWidth, availHeight): if len(self.frags)<=0: return [] #the split information is all inside self.blPara # if not hasattr(self,'blPara'): if not hasattr(self,'deltaWidth'): self.wrap(availWidth,availHeight) availWidth -= self.deltaWidth availHeight -= self.deltaHeight #if self.hasImages: # return [] return Paragraph.split(self, availWidth, availHeight) def draw(self): # Insert page number ''' if 0: #for line in self.blPara.lines: try: for frag in line.words: #print 111,frag.pageNumber, frag.text if frag.pageNumber: frag.text = str(self.canv.getPageNumber()) except Exception, e: log.debug("PmlParagraph", exc_info=1) ''' # Create outline if getattr(self, "outline", False): # Check level and add all levels last = getattr(self.canv, "outlineLast", - 1) + 1 while last < self.outlineLevel: # print "(OUTLINE", last, self.text key = getUID() self.canv.bookmarkPage(key) self.canv.addOutlineEntry( self.text, key, last, not self.outlineOpen) last += 1 self.canv.outlineLast = self.outlineLevel key = getUID() # print " OUTLINE", self.outlineLevel, self.text self.canv.bookmarkPage(key) self.canv.addOutlineEntry( self.text, key, self.outlineLevel, not self.outlineOpen) last += 1 #else: # print repr(self.text)[:80] # Draw the background and borders here before passing control on to # ReportLab. This is because ReportLab can't handle the individual # components of the border independently. This will also let us # support more border styles eventually. canvas = self.canv style = self.style bg = style.backColor leftIndent = style.leftIndent bp = 0 #style.borderPadding x = leftIndent - bp y = - bp w = self.width - (leftIndent + style.rightIndent) + 2 * bp h = self.height + 2 * bp if bg: # draw a filled rectangle (with no stroke) using bg color canvas.saveState() canvas.setFillColor(bg) canvas.rect(x, y, w, h, fill=1, stroke=0) canvas.restoreState() # we need to hide the bg color (if any) so Paragraph won't try to draw it again style.backColor = None # offset the origin to compensate for the padding canvas.saveState() canvas.translate( (style.paddingLeft + style.borderLeftWidth), -1 * (style.paddingTop + style.borderTopWidth)) # + (style.leading / 4))) # Call the base class draw method to finish up Paragraph.draw(self) canvas.restoreState() # Reset color because we need it again if we run 2-PASS like we # do when using TOC style.backColor = bg canvas.saveState() def _drawBorderLine(bstyle, width, color, x1, y1, x2, y2): # We need width and border style to be able to draw a border if width and getBorderStyle(bstyle): # If no color for border is given, the text color is used (like defined by W3C) if color is None: color = style.textColor # print "Border", bstyle, width, color if color is not None: canvas.setStrokeColor(color) canvas.setLineWidth(width) canvas.line(x1, y1, x2, y2) _drawBorderLine(style.borderLeftStyle, style.borderLeftWidth, style.borderLeftColor, x, y, x, y + h) _drawBorderLine(style.borderRightStyle, style.borderRightWidth, style.borderRightColor, x + w, y, x + w, y + h) _drawBorderLine(style.borderTopStyle, style.borderTopWidth, style.borderTopColor, x, y + h, x + w, y + h) _drawBorderLine(style.borderBottomStyle, style.borderBottomWidth, style.borderBottomColor, x, y, x + w, y) canvas.restoreState() class PmlKeepInFrame(KeepInFrame, PmlMaxHeightMixIn): def wrap(self, availWidth, availHeight): availWidth = max(availWidth, 1.0) self.maxWidth = availWidth self.maxHeight = self.setMaxHeight(availHeight) return KeepInFrame.wrap(self, availWidth, availHeight) class PmlTable(Table, PmlMaxHeightMixIn): def _normWidth(self, w, maxw): " Helper for calculating percentages " if type(w) == type(""): w = ((maxw / 100.0) * float(w[: - 1])) elif (w is None) or (w == "*"): w = maxw return min(w, maxw) def _listCellGeom(self, V, w, s, W=None, H=None, aH=72000): # print "#", self.availHeightValue if aH == 72000: aH = self.getMaxHeight() or aH return Table._listCellGeom(self, V, w, s, W=W, H=H, aH=aH) def wrap(self, availWidth, availHeight): self.setMaxHeight(availHeight) # Strange bug, sometime the totalWidth is not set !? try: self.totalWidth except: self.totalWidth = availWidth # Prepare values totalWidth = self._normWidth(self.totalWidth, availWidth) remainingWidth = totalWidth remainingCols = 0 newColWidths = self._colWidths #print #print "TABLE", newColWidths # Calculate widths that are fix # IMPORTANT!!! We can not substitute the private value # self._colWidths therefore we have to modify list in place for i in range(len(newColWidths)): colWidth = newColWidths[i] if (colWidth is not None) or (colWidth == '*'): colWidth = self._normWidth(colWidth, totalWidth) remainingWidth -= colWidth else: remainingCols += 1 colWidth = None newColWidths[i] = colWidth # Distribute remaining space minCellWidth = totalWidth * 0.01 if remainingCols > 0: for i in range(len(newColWidths)): if newColWidths[i] is None: # print "*** ", i, newColWidths[i], remainingWidth, remainingCols newColWidths[i] = max(minCellWidth, remainingWidth / remainingCols) # - 0.1 # Bigger than totalWidth? Lets reduce the fix entries propotionally # print "New values:", totalWidth, newColWidths, sum(newColWidths) # Call original method "wrap()" # self._colWidths = newColWidths if sum(newColWidths) > totalWidth: quotient = totalWidth / sum(newColWidths) # print quotient for i in range(len(newColWidths)): newColWidths[i] = newColWidths[i] * quotient # To avoid rounding errors adjust one col with the difference diff = sum(newColWidths) - totalWidth if diff > 0: newColWidths[0] -= diff # print "New values:", totalWidth, newColWidths, sum(newColWidths) return Table.wrap(self, availWidth, availHeight) class PmlTableOfContents(TableOfContents): def wrap(self, availWidth, availHeight): "All table properties should be known by now." widths = (availWidth - self.rightColumnWidth, self.rightColumnWidth) # makes an internal table which does all the work. # we draw the LAST RUN's entries! If there are # none, we make some dummy data to keep the table # from complaining if len(self._lastEntries) == 0: _tempEntries = [(0, 'Placeholder for table of contents', 0)] else: _tempEntries = self._lastEntries i = 0 lastMargin = 0 tableData = [] tableStyle = [ ('VALIGN', (0, 0), (- 1, - 1), 'TOP'), ('LEFTPADDING', (0, 0), (- 1, - 1), 0), ('RIGHTPADDING', (0, 0), (- 1, - 1), 0), ('TOPPADDING', (0, 0), (- 1, - 1), 0), ('BOTTOMPADDING', (0, 0), (- 1, - 1), 0), ] for entry in _tempEntries: level, text, pageNum = entry[:3] leftColStyle = self.levelStyles[level] if i: # Not for first element tableStyle.append(( 'TOPPADDING', (0, i), (- 1, i), max(lastMargin, leftColStyle.spaceBefore))) # print leftColStyle.leftIndent lastMargin = leftColStyle.spaceAfter #right col style is right aligned rightColStyle = ParagraphStyle(name='leftColLevel%d' % level, parent=leftColStyle, leftIndent=0, alignment=TA_RIGHT) leftPara = Paragraph(text, leftColStyle) rightPara = Paragraph(str(pageNum), rightColStyle) tableData.append([leftPara, rightPara]) i += 1 self._table = Table( tableData, colWidths=widths, style=TableStyle(tableStyle)) self.width, self.height = self._table.wrapOn(self.canv, availWidth, availHeight) return (self.width, self.height) class PmlRightPageBreak(CondPageBreak): def __init__(self): pass def wrap(self, availWidth, availHeight): if (0 == (self.canv.getPageNumber() % 2)): self.width = availWidth self.height = availHeight return (availWidth, availHeight) self.width = 0 self.height = 0 return (0, 0) class PmlLeftPageBreak(CondPageBreak): def __init__(self): pass def wrap(self, availWidth, availHeight): if (1 == (self.canv.getPageNumber() % 2)): self.width = availWidth self.height = availHeight return (availWidth, availHeight) self.width = 0 self.height = 0 return (0, 0) # --- Pdf Form import reportlab.pdfbase.pdfform as pdfform class PmlInput(Flowable): def __init__(self, name, type="text", width=10, height=10, default="", options=[]): self.width = width self.height = height self.type = type self.name = name self.default = default self.options = options def wrap(self, *args): return (self.width, self.height) def draw(self): c = self.canv c.saveState() c.setFont("Helvetica", 10) if self.type == "text": pdfform.textFieldRelative(c, self.name, 0, 0, self.width, self.height) c.rect(0, 0, self.width, self.height) elif self.type == "radio": #pdfform.buttonFieldRelative(c, "field2", "Yes", 0, 0) c.rect(0, 0, self.width, self.height) elif self.type == "checkbox": if self.default: pdfform.buttonFieldRelative(c, self.name, "Yes", 0, 0) else: pdfform.buttonFieldRelative(c, self.name, "Off", 0, 0) # pdfform.buttonFieldRelative(c, self.name, "Yes" if self.default else "Off", 0, 0) c.rect(0, 0, self.width, self.height) elif self.type == "select": pdfform.selectFieldRelative(c, self.name, self.default, self.options, 0, 0, self.width, self.height) c.rect(0, 0, self.width, self.height) c.restoreState() ''' canvas.setLineWidth(6) canvas.setFillColor(self.fillcolor) canvas.setStrokeColor(self.strokecolor) canvas.translate(self.xoffset+self.size,0) canvas.rotate(90) canvas.scale(self.scale, self.scale) hand(canvas, debug=0, fill=1) ''' """ # --- Flowable example def hand(canvas, debug=1, fill=0): (startx, starty) = (0, 0) curves = [ (0, 2), (0, 4), (0, 8), # back of hand (5, 8), (7, 10), (7, 14), (10, 14), (10, 13), (7.5, 8), # thumb (13, 8), (14, 8), (17, 8), (19, 8), (19, 6), (17, 6), (15, 6), (13, 6), (11, 6), # index, pointing (12, 6), (13, 6), (14, 6), (16, 6), (16, 4), (14, 4), (13, 4), (12, 4), (11, 4), # middle (11.5, 4), (12, 4), (13, 4), (15, 4), (15, 2), (13, 2), (12.5, 2), (11.5, 2), (11, 2), # ring (11.5, 2), (12, 2), (12.5, 2), (14, 2), (14, 0), (12.5, 0), (10, 0), (8, 0), (6, 0), # pinky, then close ] from reportlab.lib.units import inch if debug: canvas.setLineWidth(6) u = inch * 0.2 p = canvas.beginPath() p.moveTo(startx, starty) ccopy = list(curves) while ccopy: [(x1, y1), (x2, y2), (x3, y3)] = ccopy[:3] del ccopy[:3] p.curveTo(x1 * u, y1 * u, x2 * u, y2 * u, x3 * u, y3 * u) p.close() canvas.drawPath(p, fill=fill) if debug: from reportlab.lib.colors import red, green (lastx, lasty) = (startx, starty) ccopy = list(curves) while ccopy: [(x1, y1), (x2, y2), (x3, y3)] = ccopy[:3] del ccopy[:3] canvas.setStrokeColor(red) canvas.line(lastx * u, lasty * u, x1 * u, y1 * u) canvas.setStrokeColor(green) canvas.line(x2 * u, y2 * u, x3 * u, y3 * u) (lastx, lasty) = (x3, y3) from reportlab.lib.colors import tan, green class HandAnnotation(Flowable): '''A hand flowable.''' def __init__(self, xoffset=0, size=None, fillcolor=tan, strokecolor=green): from reportlab.lib.units import inch if size is None: size = 4 * inch self.fillcolor, self.strokecolor = fillcolor, strokecolor self.xoffset = xoffset self.size = size # normal size is 4 inches self.scale = size / (4.0 * inch) def wrap(self, *args): return (self.xoffset, self.size) def draw(self): canvas = self.canv canvas.setLineWidth(6) canvas.setFillColor(self.fillcolor) canvas.setStrokeColor(self.strokecolor) canvas.translate(self.xoffset + self.size, 0) canvas.rotate(90) canvas.scale(self.scale, self.scale) hand(canvas, debug=0, fill=1) """pisa-3.0.32/sx/pisa3/pisa_wsgi.py0000644000175000017500000000546511103556730014712 0ustar wmbwmb# -*- coding: UTF-8 -*- ############################################# ## (C)opyright by Dirk Holtwick, 2008 ## ## All rights reserved ## ############################################# __version__ = "$Revision: 103 $" __author__ = "$Author: holtwick $" __date__ = "$Date: 2007-10-31 17:08:54 +0100 (Mi, 31 Okt 2007) $" __svnid__ = "$Id: pisa.py 103 2007-10-31 16:08:54Z holtwick $" import ho.pisa as pisa import StringIO import logging log = logging.getLogger("ho.pisa.wsgi") class Filter(object): def __init__(self, app): self.app = app def __call__(self, environ, start_response): script_name = environ.get('SCRIPT_NAME', '') path_info = environ.get('PATH_INFO', '') sent = [] written_response = StringIO.StringIO() def replacement_start_response(status, headers, exc_info=None): if not self.should_filter(status, headers): return start_response(status, headers, exc_info) else: sent[:] = [status, headers, exc_info] return written_response.write app_iter = self.app(environ, replacement_start_response) if not sent: return app_iter status, headers, exc_info = sent try: for chunk in app_iter: written_response.write(chunk) finally: if hasattr(app_iter, 'close'): app_iter.close() body = written_response.getvalue() status, headers, body = self.filter( script_name, path_info, environ, status, headers, body) start_response(status, headers, exc_info) return [body] def should_filter(self, status, headers): print headers def filter(self, status, headers, body): raise NotImplementedError class HTMLFilter(Filter): def should_filter(self, status, headers): if not status.startswith('200'): return False for name, value in headers: if name.lower() == 'content-type': return value.startswith('text/html') return False class PisaMiddleware(HTMLFilter): def filter(self, script_name, path_info, environ, status, headers, body): topdf = environ.get("pisa.topdf", "") if topdf: dst = StringIO.StringIO() result = pisa.CreatePDF( body, dst, show_error_as_pdf=True, ) headers = [ ("content-type", "application/pdf"), ("content-disposition", "attachment; filename=" + topdf) ] body = dst.getvalue() return status, headers, body pisa-3.0.32/sx/pisa3/reportlab_paragraph.py0000644000175000017500000020653311164071226016742 0ustar wmbwmb# -*- coding: UTF-8 -*- # Copyright ReportLab Europe Ltd. 2000-2008 # see license.txt for license details # history http://www.reportlab.co.uk/cgi-bin/viewcvs.cgi/public/reportlab/trunk/reportlab/platypus/paragraph.py # Modifications by Dirk Holtwick, 2008 __version__=''' $Id: paragraph.py 3307 2008-10-13 15:28:30Z rgbecker $ ''' from string import join, whitespace from operator import truth from types import StringType, ListType from reportlab.pdfbase.pdfmetrics import stringWidth, getFont, getAscentDescent from reportlab.platypus.paraparser import ParaParser from reportlab.platypus.flowables import Flowable from reportlab.lib.colors import Color from reportlab.lib.enums import TA_LEFT, TA_RIGHT, TA_CENTER, TA_JUSTIFY from reportlab.lib.utils import _className from reportlab.lib.textsplit import wordSplit, ALL_CANNOT_START from copy import deepcopy from reportlab.lib.abag import ABag import re PARAGRAPH_DEBUG = False LEADING_FACTOR = 1.0 _wsc_re_split=re.compile('[%s]+'% re.escape(''.join(( u'\u0009', # HORIZONTAL TABULATION u'\u000A', # LINE FEED u'\u000B', # VERTICAL TABULATION u'\u000C', # FORM FEED u'\u000D', # CARRIAGE RETURN u'\u001C', # FILE SEPARATOR u'\u001D', # GROUP SEPARATOR u'\u001E', # RECORD SEPARATOR u'\u001F', # UNIT SEPARATOR u'\u0020', # SPACE u'\u0085', # NEXT LINE #u'\u00A0', # NO-BREAK SPACE u'\u1680', # OGHAM SPACE MARK u'\u2000', # EN QUAD u'\u2001', # EM QUAD u'\u2002', # EN SPACE u'\u2003', # EM SPACE u'\u2004', # THREE-PER-EM SPACE u'\u2005', # FOUR-PER-EM SPACE u'\u2006', # SIX-PER-EM SPACE u'\u2007', # FIGURE SPACE u'\u2008', # PUNCTUATION SPACE u'\u2009', # THIN SPACE u'\u200A', # HAIR SPACE u'\u200B', # ZERO WIDTH SPACE u'\u2028', # LINE SEPARATOR u'\u2029', # PARAGRAPH SEPARATOR u'\u202F', # NARROW NO-BREAK SPACE u'\u205F', # MEDIUM MATHEMATICAL SPACE u'\u3000', # IDEOGRAPHIC SPACE )))).split def split(text, delim=None): if type(text) is str: text = text.decode('utf8') if type(delim) is str: delim = delim.decode('utf8') elif delim is None and u'\xa0' in text: return [uword.encode('utf8') for uword in _wsc_re_split(text)] return [uword.encode('utf8') for uword in text.split(delim)] def strip(text): if type(text) is str: text = text.decode('utf8') return text.strip().encode('utf8') class ParaLines(ABag): """ class ParaLines contains the broken into lines representation of Paragraphs kind=0 Simple fontName, fontSize, textColor apply to whole Paragraph lines [(extraSpace1,words1),....,(extraspaceN,wordsN)] kind==1 Complex lines [FragLine1,...,FragLineN] """ class FragLine(ABag): """ class FragLine contains a styled line (ie a line with more than one style):: extraSpace unused space for justification only wordCount 1+spaces in line for justification purposes words [ParaFrags] style text lumps to be concatenated together fontSize maximum fontSize seen on the line; not used at present, but could be used for line spacing. """ #our one and only parser # XXXXX if the parser has any internal state using only one is probably a BAD idea! _parser=ParaParser() def _lineClean(L): return join(filter(truth,split(strip(L)))) def cleanBlockQuotedText(text,joiner=' '): """This is an internal utility which takes triple- quoted text form within the document and returns (hopefully) the paragraph the user intended originally.""" L=filter(truth,map(_lineClean, split(text, '\n'))) return join(L, joiner) def setXPos(tx,dx): if dx>1e-6 or dx<-1e-6: tx.setXPos(dx) def _leftDrawParaLine( tx, offset, extraspace, words, last=0): setXPos(tx,offset) tx._textOut(join(words),1) setXPos(tx,-offset) return offset def _centerDrawParaLine( tx, offset, extraspace, words, last=0): m = offset + 0.5 * extraspace setXPos(tx,m) tx._textOut(join(words),1) setXPos(tx,-m) return m def _rightDrawParaLine( tx, offset, extraspace, words, last=0): m = offset + extraspace setXPos(tx,m) tx._textOut(join(words),1) setXPos(tx,-m) return m def _justifyDrawParaLine( tx, offset, extraspace, words, last=0): setXPos(tx,offset) text = join(words) if last: #last one, left align tx._textOut(text,1) else: nSpaces = len(words)-1 if nSpaces: tx.setWordSpace(extraspace / float(nSpaces)) tx._textOut(text,1) tx.setWordSpace(0) else: tx._textOut(text,1) setXPos(tx,-offset) return offset def imgVRange(h,va,fontSize): '''return bottom,top offsets relative to baseline(0)''' if va=='baseline': iyo = 0 elif va in ('text-top','top'): iyo = fontSize-h elif va=='middle': iyo = fontSize - (1.2*fontSize+h)*0.5 elif va in ('text-bottom','bottom'): iyo = fontSize - 1.2*fontSize elif va=='super': iyo = 0.5*fontSize elif va=='sub': iyo = -0.5*fontSize elif hasattr(va,'normalizedValue'): iyo = va.normalizedValue(fontSize) else: iyo = va return iyo,iyo+h _56=5./6 _16=1./6 def _putFragLine(cur_x, tx, line): xs = tx.XtraState cur_y = xs.cur_y x0 = tx._x0 autoLeading = xs.autoLeading leading = xs.leading cur_x += xs.leftIndent dal = autoLeading in ('min','max') if dal: if autoLeading=='max': ascent = max(_56*leading,line.ascent) descent = max(_16*leading,-line.descent) else: ascent = line.ascent descent = -line.descent leading = ascent+descent if tx._leading!=leading: tx.setLeading(leading) if dal: olb = tx._olb if olb is not None: xcy = olb-ascent if tx._oleading!=leading: cur_y += leading - tx._oleading if abs(xcy-cur_y)>1e-8: cur_y = xcy tx.setTextOrigin(x0,cur_y) xs.cur_y = cur_y tx._olb = cur_y - descent tx._oleading = leading ws = getattr(tx,'_wordSpace',0) nSpaces = 0 words = line.words for f in words: if hasattr(f,'cbDefn'): cbDefn = f.cbDefn kind = cbDefn.kind if kind=='img': #draw image cbDefn,cur_y,cur_x w = cbDefn.width h = cbDefn.height txfs = tx._fontsize if txfs is None: txfs = xs.style.fontSize iy0,iy1 = imgVRange(h,cbDefn.valign,txfs) cur_x_s = cur_x + nSpaces*ws # print "draw", id(f), id(cbDefn.image), repr(dal), cur_y, iy0, iy1, h tx._canvas.drawImage(cbDefn.image.getImage(),cur_x_s,cur_y+iy0,w,h,mask='auto') cur_x += w cur_x_s += w setXPos(tx,cur_x_s-tx._x0) else: name = cbDefn.name if kind=='anchor': tx._canvas.bookmarkHorizontal(name,cur_x,cur_y+leading) else: func = getattr(tx._canvas,name,None) if not func: raise AttributeError("Missing %s callback attribute '%s'" % (kind,name)) func(tx._canvas,kind,cbDefn.label) if f is words[-1]: if not tx._fontname: tx.setFont(xs.style.fontName,xs.style.fontSize) tx._textOut('',1) elif kind=='img': tx._textOut('',1) else: cur_x_s = cur_x + nSpaces*ws if (tx._fontname,tx._fontsize)!=(f.fontName,f.fontSize): tx._setFont(f.fontName, f.fontSize) if xs.textColor!=f.textColor: xs.textColor = f.textColor tx.setFillColor(f.textColor) if xs.rise!=f.rise: xs.rise=f.rise tx.setRise(f.rise) text = f.text tx._textOut(text,f is words[-1]) # cheap textOut # XXX Modified for XHTML2PDF # Background colors (done like underline) # print "#", repr(f.text), f.fontSize, f.backColor, f.underline if hasattr(f, "backColor"): if xs.backgroundColor != f.backColor or xs.backgroundFontSize != f.fontSize: if xs.backgroundColor is not None: xs.backgrounds.append((xs.background_x, cur_x_s, xs.backgroundColor, xs.backgroundFontSize)) xs.background_x = cur_x_s xs.backgroundColor = f.backColor xs.backgroundFontSize = f.fontSize # Underline if not xs.underline and f.underline: xs.underline = 1 xs.underline_x = cur_x_s xs.underlineColor = f.textColor elif xs.underline: if not f.underline: xs.underline = 0 xs.underlines.append((xs.underline_x, cur_x_s, xs.underlineColor)) xs.underlineColor = None elif xs.textColor != xs.underlineColor: xs.underlines.append((xs.underline_x, cur_x_s, xs.underlineColor)) xs.underlineColor = xs.textColor xs.underline_x = cur_x_s # Strike if not xs.strike and f.strike: xs.strike = 1 xs.strike_x = cur_x_s xs.strikeColor = f.textColor # XXX Modified for XHTML2PDF xs.strikeFontSize = f.fontSize elif xs.strike: if not f.strike: xs.strike = 0 # XXX Modified for XHTML2PDF xs.strikes.append((xs.strike_x, cur_x_s, xs.strikeColor, xs.strikeFontSize)) xs.strikeColor = None xs.strikeFontSize = None elif xs.textColor != xs.strikeColor: xs.strikes.append((xs.strike_x, cur_x_s, xs.strikeColor, xs.strikeFontSize)) xs.strikeColor = xs.textColor xs.strikeFontSize = f.fontSize xs.strike_x = cur_x_s if f.link and not xs.link: if not xs.link: xs.link = f.link xs.link_x = cur_x_s xs.linkColor = xs.textColor elif xs.link: if not f.link: xs.links.append( (xs.link_x, cur_x_s, xs.link, xs.linkColor) ) xs.link = None xs.linkColor = None elif f.link!=xs.link or xs.textColor!=xs.linkColor: xs.links.append( (xs.link_x, cur_x_s, xs.link, xs.linkColor) ) xs.link = f.link xs.link_x = cur_x_s xs.linkColor = xs.textColor txtlen = tx._canvas.stringWidth(text, tx._fontname, tx._fontsize) cur_x += txtlen nSpaces += text.count(' ') cur_x_s = cur_x+(nSpaces-1)*ws # XXX Modified for XHTML2PDF # Underline if xs.underline: xs.underlines.append((xs.underline_x, cur_x_s, xs.underlineColor)) # XXX Modified for XHTML2PDF # Backcolor if hasattr(f, "backColor"): if xs.backgroundColor is not None: xs.backgrounds.append((xs.background_x, cur_x_s, xs.backgroundColor, xs.backgroundFontSize)) # XXX Modified for XHTML2PDF # Strike if xs.strike: xs.strikes.append((xs.strike_x, cur_x_s, xs.strikeColor, xs.strikeFontSize)) if xs.link: xs.links.append( (xs.link_x, cur_x_s, xs.link,xs.linkColor) ) if tx._x0!=x0: setXPos(tx,x0-tx._x0) def _leftDrawParaLineX( tx, offset, line, last=0): setXPos(tx,offset) _putFragLine(offset, tx, line) setXPos(tx,-offset) def _centerDrawParaLineX( tx, offset, line, last=0): m = offset+0.5*line.extraSpace setXPos(tx,m) _putFragLine(m,tx, line) setXPos(tx,-m) def _rightDrawParaLineX( tx, offset, line, last=0): m = offset+line.extraSpace setXPos(tx,m) _putFragLine(m,tx, line) setXPos(tx,-m) def _justifyDrawParaLineX( tx, offset, line, last=0): setXPos(tx,offset) extraSpace = line.extraSpace nSpaces = line.wordCount - 1 if last or not nSpaces or abs(extraSpace)<=1e-8 or line.lineBreak: _putFragLine(offset, tx, line) #no space modification else: tx.setWordSpace(extraSpace / float(nSpaces)) _putFragLine(offset, tx, line) tx.setWordSpace(0) setXPos(tx,-offset) # XXX Modified for XHTML2PDF # !!! Important, don't import accelerators !!! #try: # from _rl_accel import _sameFrag #except ImportError: # try: # from reportlab.lib._rl_accel import _sameFrag # except ImportError: 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', 'backColor', 'rise', 'underline', 'strike', 'link'): if getattr(f,a,None)!=getattr(g,a,None): return 0 return 1 def _getFragWords(frags): ''' given a Parafrag list return a list of fragwords [[size, (f00,w00), ..., (f0n,w0n)],....,[size, (fm0,wm0), ..., (f0n,wmn)]] each pair f,w represents a style and some string each sublist represents a word ''' R = [] W = [] n = 0 hangingStrip = False for f in frags: text = f.text #del f.text # we can't do this until we sort out splitting # of paragraphs if text!='': if hangingStrip: hangingStrip = False text = text.lstrip() #if type(text) is str: # text = text.decode('utf8') S = split(text) if S==[]: S = [''] if W!=[] and text[0] in whitespace: W.insert(0,n) R.append(W) W = [] n = 0 for w in S[:-1]: W.append((f,w)) n += stringWidth(w, f.fontName, f.fontSize) W.insert(0,n) R.append(W) W = [] n = 0 w = S[-1] W.append((f,w)) n += stringWidth(w, f.fontName, f.fontSize) if text and text[-1] in whitespace: W.insert(0,n) R.append(W) W = [] n = 0 elif hasattr(f,'cbDefn'): w = getattr(f.cbDefn,'width',0) if w: if W!=[]: W.insert(0,n) R.append(W) W = [] n = 0 R.append([w,(f,'')]) else: W.append((f,'')) elif hasattr(f, 'lineBreak'): #pass the frag through. The line breaker will scan for it. if W!=[]: W.insert(0,n) R.append(W) W = [] n = 0 R.append([0,(f,'')]) hangingStrip = True if W!=[]: W.insert(0,n) R.append(W) return R def _split_blParaSimple(blPara,start,stop): f = blPara.clone() for a in ('lines', 'kind', 'text'): if hasattr(f,a): delattr(f,a) f.words = [] for l in blPara.lines[start:stop]: for w in l[1]: f.words.append(w) return [f] def _split_blParaHard(blPara,start,stop): f = [] lines = blPara.lines[start:stop] for l in lines: for w in l.words: f.append(w) if l is not lines[-1]: i = len(f)-1 while i>=0 and hasattr(f[i],'cbDefn') and not getattr(f[i].cbDefn,'width',0): i -= 1 if i>=0: g = f[i] if not g.text: g.text = ' ' elif g.text[-1]!=' ': g.text += ' ' return f def _drawBullet(canvas, offset, cur_y, bulletText, style): '''draw a bullet text could be a simple string or a frag list''' tx2 = canvas.beginText(style.bulletIndent, cur_y+getattr(style,"bulletOffsetY",0)) tx2.setFont(style.bulletFontName, style.bulletFontSize) tx2.setFillColor(hasattr(style,'bulletColor') and style.bulletColor or style.textColor) if isinstance(bulletText,basestring): tx2.textOut(bulletText) else: for f in bulletText: if hasattr(f, "image"): image = f.image width = image.drawWidth height = image.drawHeight gap = style.bulletFontSize * 0.25 img = image.getImage() # print style.bulletIndent, offset, width canvas.drawImage( img, style.leftIndent - width - gap, cur_y+getattr(style,"bulletOffsetY",0), width, height) else: tx2.setFont(f.fontName, f.fontSize) tx2.setFillColor(f.textColor) tx2.textOut(f.text) canvas.drawText(tx2) #AR making definition lists a bit less ugly #bulletEnd = tx2.getX() bulletEnd = tx2.getX() + style.bulletFontSize * 0.6 offset = max(offset,bulletEnd - style.leftIndent) return offset def _handleBulletWidth(bulletText,style,maxWidths): '''work out bullet width and adjust maxWidths[0] if neccessary ''' if bulletText: if isinstance(bulletText,basestring): bulletWidth = stringWidth( bulletText, style.bulletFontName, style.bulletFontSize) else: #it's a list of fragments bulletWidth = 0 for f in bulletText: bulletWidth = bulletWidth + stringWidth(f.text, f.fontName, f.fontSize) bulletRight = style.bulletIndent + bulletWidth + 0.6 * style.bulletFontSize indent = style.leftIndent+style.firstLineIndent if bulletRight > indent: #..then it overruns, and we have less space available on line 1 maxWidths[0] -= (bulletRight - indent) def splitLines0(frags,widths): ''' given a list of ParaFrags we return a list of ParaLines each ParaLine has 1) ExtraSpace 2) blankCount 3) [textDefns....] each text definition is a (ParaFrag, start, limit) triplet ''' #initialise the algorithm lines = [] lineNum = 0 maxW = widths[lineNum] i = -1 l = len(frags) lim = start = 0 while 1: #find a non whitespace character while imaxW and line!=[]: cLen = cLen-w #this is the end of the line while g.text[lim]==' ': lim = lim - 1 nSpaces = nSpaces-1 break if j<0: j = lim if g[0] is f: g[2] = j #extend else: g = (f,start,j) line.append(g) if j==lim: i += 1 def _do_under_line(i, t_off, ws, tx, lm=-0.125): y = tx.XtraState.cur_y - i*tx.XtraState.style.leading + lm*tx.XtraState.f.fontSize textlen = tx._canvas.stringWidth(join(tx.XtraState.lines[i][1]), tx._fontname, tx._fontsize) tx._canvas.line(t_off, y, t_off+textlen+ws, y) _scheme_re = re.compile('^[a-zA-Z][-+a-zA-Z0-9]+$') def _doLink(tx,link,rect): if isinstance(link,unicode): link = link.encode('utf8') parts = link.split(':',1) scheme = len(parts)==2 and parts[0].lower() or '' if _scheme_re.match(scheme) and scheme!='document': kind=scheme.lower()=='pdf' and 'GoToR' or 'URI' if kind=='GoToR': link = parts[1] tx._canvas.linkURL(link, rect, relative=1, kind=kind) else: if link[0]=='#': link = link[1:] scheme='' tx._canvas.linkRect("", scheme!='document' and link or parts[1], rect, relative=1) def _do_link_line(i, t_off, ws, tx): xs = tx.XtraState leading = xs.style.leading y = xs.cur_y - i*leading - xs.f.fontSize/8.0 # 8.0 factor copied from para.py text = join(xs.lines[i][1]) textlen = tx._canvas.stringWidth(text, tx._fontname, tx._fontsize) _doLink(tx, xs.link, (t_off, y, t_off+textlen+ws, y+leading)) # XXX Modified for XHTML2PDF def _do_post_text(tx): """ Try to find out what the variables mean: tx A structure containing more informations about paragraph ??? leading Height of lines ff 1/8 of the font size y0 The "baseline" postion ??? y 1/8 below the baseline """ xs = tx.XtraState leading = xs.style.leading autoLeading = xs.autoLeading f = xs.f if autoLeading=='max': # leading = max(leading, f.fontSize) leading = max(leading, LEADING_FACTOR*f.fontSize) elif autoLeading=='min': leading = LEADING_FACTOR*f.fontSize ff = 0.125*f.fontSize y0 = xs.cur_y y = y0 - ff # Background for x1, x2, c, fs in xs.backgrounds: inlineFF = fs * 0.125 gap = inlineFF * 1.25 tx._canvas.setFillColor(c) tx._canvas.rect(x1, y - gap, x2 - x1, fs + 1, fill=1, stroke=0) # tx._canvas.rect(x1, y, x2 - x1, fs, fill=1, stroke=0) xs.backgrounds = [] xs.background = 0 xs.backgroundColor = None xs.backgroundFontSize = None # Underline yUnderline = y0 - 1.5 * ff tx._canvas.setLineWidth(ff * 0.75) csc = None for x1,x2,c in xs.underlines: if c!=csc: tx._canvas.setStrokeColor(c) csc = c tx._canvas.line(x1, yUnderline, x2, yUnderline) xs.underlines = [] xs.underline=0 xs.underlineColor=None # Strike for x1,x2,c,fs in xs.strikes: inlineFF = fs * 0.125 ys = y0 + 2 * inlineFF if c!=csc: tx._canvas.setStrokeColor(c) csc = c tx._canvas.setLineWidth(inlineFF * 0.75) tx._canvas.line(x1, ys, x2, ys) xs.strikes = [] xs.strike=0 xs.strikeColor=None yl = y + leading for x1,x2,link,c in xs.links: # No automatic underlining for links, never! _doLink(tx, link, (x1, y, x2, yl)) xs.links = [] xs.link=None xs.linkColor=None xs.cur_y -= leading def textTransformFrags(frags,style): tt = style.textTransform if tt: tt=tt.lower() if tt=='lowercase': tt = unicode.lower elif tt=='uppercase': tt = unicode.upper elif tt=='capitalize': tt = unicode.title elif tt=='none': return else: raise ValueError('ParaStyle.textTransform value %r is invalid' % style.textTransform) n = len(frags) if n==1: #single fragment the easy case frags[0].text = tt(frags[0].text.decode('utf8')).encode('utf8') elif tt is unicode.title: pb = True for f in frags: t = f.text if not t: continue u = t.decode('utf8') if u.startswith(u' ') or pb: u = tt(u) else: i = u.find(u' ') if i>=0: u = u[:i]+tt(u[i:]) pb = u.endswith(u' ') f.text = u.encode('utf8') else: for f in frags: t = f.text if not t: continue f.text = tt(t.decode('utf8')).encode('utf8') class cjkU(unicode): '''simple class to hold the frag corresponding to a str''' def __new__(cls,value,frag,encoding): self = unicode.__new__(cls,value) self._frag = frag if hasattr(frag,'cbDefn'): w = getattr(frag.cbDefn,'width',0) self._width = w else: self._width = stringWidth(value,frag.fontName,frag.fontSize) return self frag = property(lambda self: self._frag) width = property(lambda self: self._width) def makeCJKParaLine(U,extraSpace,calcBounds): words = [] CW = [] f0 = FragLine() maxSize = maxAscent = minDescent = 0 for u in U: f = u.frag fontSize = f.fontSize if calcBounds: cbDefn = getattr(f,'cbDefn',None) if getattr(cbDefn,'width',0): descent, ascent = imgVRange(cbDefn.height,cbDefn.valign,fontSize) else: ascent, descent = getAscentDescent(f.fontName,fontSize) else: ascent, descent = getAscentDescent(f.fontName,fontSize) maxSize = max(maxSize,fontSize) maxAscent = max(maxAscent,ascent) minDescent = min(minDescent,descent) if not _sameFrag(f0,f): f0=f0.clone() f0.text = u''.join(CW) words.append(f0) CW = [] f0 = f CW.append(u) if CW: f0=f0.clone() f0.text = u''.join(CW) words.append(f0) return FragLine(kind=1,extraSpace=extraSpace,wordCount=1,words=words[1:],fontSize=maxSize,ascent=maxAscent,descent=minDescent) def cjkFragSplit(frags, maxWidths, calcBounds, encoding='utf8'): '''This attempts to be wordSplit for frags using the dumb algorithm''' from reportlab.rl_config import _FUZZ U = [] #get a list of single glyphs with their widths etc etc for f in frags: text = f.text if not isinstance(text,unicode): text = text.decode(encoding) if text: U.extend([cjkU(t,f,encoding) for t in text]) else: U.append(cjkU(text,f,encoding)) lines = [] widthUsed = lineStartPos = 0 maxWidth = maxWidths[0] for i, u in enumerate(U): w = u.width widthUsed += w lineBreak = hasattr(u.frag,'lineBreak') endLine = (widthUsed>maxWidth + _FUZZ and widthUsed>0) or lineBreak if endLine: if lineBreak: continue extraSpace = maxWidth - widthUsed + w #This is the most important of the Japanese typography rules. #if next character cannot start a line, wrap it up to this line so it hangs #in the right margin. We won't do two or more though - that's unlikely and #would result in growing ugliness. nextChar = U[i] if nextChar in ALL_CANNOT_START: extraSpace -= w i += 1 lines.append(makeCJKParaLine(U[lineStartPos:i],extraSpace,calcBounds)) try: maxWidth = maxWidths[len(lines)] except IndexError: maxWidth = maxWidths[-1] # use the last one lineStartPos = i widthUsed = w i -= 1 #any characters left? if widthUsed > 0: lines.append(makeCJKParaLine(U[lineStartPos:],maxWidth-widthUsed,calcBounds)) return ParaLines(kind=1,lines=lines) class Paragraph(Flowable): """ Paragraph(text, style, bulletText=None, caseSensitive=1) text a string of stuff to go into the paragraph. style is a style definition as in reportlab.lib.styles. bulletText is an optional bullet defintion. caseSensitive set this to 0 if you want the markup tags and their attributes to be case-insensitive. This class is a flowable that can format a block of text into a paragraph with a given style. The paragraph Text can contain XML-like markup including the tags: ... - bold ... - italics ... - underline ... - strike through ... - superscript ... - subscript link text attributes of links size/fontSize=num name/face/fontName=name fg/textColor/color=color backcolor/backColor/bgcolor=color dest/destination/target/href/link=target anchor text attributes of anchors fontSize=num fontName=name fg/textColor/color=color backcolor/backColor/bgcolor=color href=href The whole may be surrounded by tags The and tags will work for the built-in fonts (Helvetica /Times / Courier). For other fonts you need to register a family of 4 fonts using reportlab.pdfbase.pdfmetrics.registerFont; then use the addMapping function to tell the library that these 4 fonts form a family e.g. from reportlab.lib.fonts import addMapping addMapping('Vera', 0, 0, 'Vera') #normal addMapping('Vera', 0, 1, 'Vera-Italic') #italic addMapping('Vera', 1, 0, 'Vera-Bold') #bold addMapping('Vera', 1, 1, 'Vera-BoldItalic') #italic and bold It will also be able to handle any MathML specified Greek characters. """ def __init__(self, text, style, bulletText = None, frags=None, caseSensitive=1, encoding='utf8'): self.caseSensitive = caseSensitive self.encoding = encoding self._setup(text, style, bulletText, frags, cleanBlockQuotedText) def __repr__(self): n = self.__class__.__name__ L = [n+"("] keys = self.__dict__.keys() for k in keys: v = getattr(self, k) rk = repr(k) rv = repr(v) rk = " "+rk.replace("\n", "\n ") rv = " "+rk.replace("\n", "\n ") L.append(rk) L.append(rv) L.append(") #"+n) return '\n'.join(L) def _setup(self, text, style, bulletText, frags, cleaner): if frags is None: text = cleaner(text) _parser.caseSensitive = self.caseSensitive style, frags, bulletTextFrags = _parser.parse(text,style) if frags is None: raise ValueError("xml parser error (%s) in paragraph beginning\n'%s'"\ % (_parser.errors[0],text[:min(30,len(text))])) textTransformFrags(frags,style) if bulletTextFrags: bulletText = bulletTextFrags #AR hack self.text = text self.frags = frags self.style = style self.bulletText = bulletText self.debug = PARAGRAPH_DEBUG #turn this on to see a pretty one with all the margins etc. def wrap(self, availWidth, availHeight): if self.debug: print id(self), "wrap" try: print repr(self.getPlainText()[:80]) except: print "???" # work out widths array for breaking self.width = availWidth style = self.style leftIndent = style.leftIndent first_line_width = availWidth - (leftIndent+style.firstLineIndent) - style.rightIndent later_widths = availWidth - leftIndent - style.rightIndent if style.wordWrap == 'CJK': #use Asian text wrap algorithm to break characters blPara = self.breakLinesCJK([first_line_width, later_widths]) else: blPara = self.breakLines([first_line_width, later_widths]) self.blPara = blPara autoLeading = getattr(self,'autoLeading',getattr(style,'autoLeading','')) leading = style.leading if blPara.kind==1 and autoLeading not in ('','off'): height = 0 if autoLeading=='max': for l in blPara.lines: height += max(l.ascent-l.descent,leading) elif autoLeading=='min': for l in blPara.lines: height += l.ascent - l.descent else: raise ValueError('invalid autoLeading value %r' % autoLeading) else: if autoLeading=='max': leading = max(leading,LEADING_FACTOR*style.fontSize) elif autoLeading=='min': leading = LEADING_FACTOR*style.fontSize height = len(blPara.lines) * leading self.height = height return self.width, height def minWidth(self): 'Attempt to determine a minimum sensible width' frags = self.frags nFrags= len(frags) if not nFrags: return 0 if nFrags==1: f = frags[0] fS = f.fontSize fN = f.fontName words = hasattr(f,'text') and split(f.text, ' ') or f.words func = lambda w, fS=fS, fN=fN: stringWidth(w,fN,fS) else: words = _getFragWords(frags) func = lambda x: x[0] return max(map(func,words)) def _get_split_blParaFunc(self): return self.blPara.kind==0 and _split_blParaSimple or _split_blParaHard def split(self,availWidth, availHeight): if self.debug: print id(self), "split" if len(self.frags)<=0: return [] #the split information is all inside self.blPara if not hasattr(self,'blPara'): # return [] self.wrap(availWidth,availHeight) blPara = self.blPara style = self.style autoLeading = getattr(self,'autoLeading',getattr(style,'autoLeading','')) leading = style.leading lines = blPara.lines if blPara.kind==1 and autoLeading not in ('','off'): s = height = 0 if autoLeading=='max': for i,l in enumerate(blPara.lines): h = max(l.ascent-l.descent,leading) n = height+h if n>availHeight+1e-8: break height = n s = i+1 elif autoLeading=='min': for i,l in enumerate(blPara.lines): n = height+l.ascent-l.descent if n>availHeight+1e-8: break height = n s = i+1 else: raise ValueError('invalid autoLeading value %r' % autoLeading) else: l = leading if autoLeading=='max': l = max(leading,LEADING_FACTOR*style.fontSize) elif autoLeading=='min': l = LEADING_FACTOR*style.fontSize s = int(availHeight/l) height = s*l n = len(lines) allowWidows = getattr(self,'allowWidows',getattr(self,'allowWidows',1)) allowOrphans = getattr(self,'allowOrphans',getattr(self,'allowOrphans',0)) if not allowOrphans: if s<=1: #orphan? del self.blPara return [] if n<=s: return [self] if not allowWidows: if n==s+1: #widow? if (allowOrphans and n==3) or n>3: s -= 1 #give the widow some company else: del self.blPara #no room for adjustment; force the whole para onwards return [] func = self._get_split_blParaFunc() P1=self.__class__(None,style,bulletText=self.bulletText,frags=func(blPara,0,s)) #this is a major hack P1.blPara = ParaLines(kind=1,lines=blPara.lines[0:s],aH=availHeight,aW=availWidth) P1._JustifyLast = 1 P1._splitpara = 1 P1.height = height P1.width = availWidth if style.firstLineIndent != 0: style = deepcopy(style) style.firstLineIndent = 0 P2=self.__class__(None,style,bulletText=None,frags=func(blPara,s,n)) for a in ('autoLeading', #possible attributes that might be directly on self. ): if hasattr(self,a): setattr(P1,a,getattr(self,a)) setattr(P2,a,getattr(self,a)) return [P1,P2] def draw(self): #call another method for historical reasons. Besides, I #suspect I will be playing with alternate drawing routines #so not doing it here makes it easier to switch. self.drawPara(self.debug) def breakLines(self, width): """ Returns a broken line structure. There are two cases A) For the simple case of a single formatting input fragment the output is A fragment specifier with - kind = 0 - fontName, fontSize, leading, textColor - lines= A list of lines Each line has two items. 1. unused width in points 2. word list B) When there is more than one input formatting fragment the output is A fragment specifier with - kind = 1 - lines= A list of fragments each having fields - extraspace (needed for justified) - fontSize - words=word list each word is itself a fragment with various settings This structure can be used to easily draw paragraphs with the various alignments. You can supply either a single width or a list of widths; the latter will have its last item repeated until necessary. A 2-element list is useful when there is a different first line indent; a longer list could be created to facilitate custom wraps around irregular objects.""" if self.debug: print id(self), "breakLines" if not isinstance(width,(tuple,list)): maxWidths = [width] else: maxWidths = width lines = [] lineno = 0 style = self.style #for bullets, work out width and ensure we wrap the right amount onto line one _handleBulletWidth(self.bulletText,style,maxWidths) maxWidth = maxWidths[0] self.height = 0 autoLeading = getattr(self,'autoLeading',getattr(style,'autoLeading','')) calcBounds = autoLeading not in ('','off') frags = self.frags nFrags= len(frags) if nFrags==1 and not hasattr(frags[0],'cbDefn'): f = frags[0] fontSize = f.fontSize fontName = f.fontName ascent, descent = getAscentDescent(fontName,fontSize) words = hasattr(f,'text') and split(f.text, ' ') or f.words spaceWidth = stringWidth(' ', fontName, fontSize, self.encoding) cLine = [] currentWidth = -spaceWidth # hack to get around extra space for word 1 for word in words: #this underscores my feeling that Unicode throughout would be easier! wordWidth = stringWidth(word, fontName, fontSize, self.encoding) newWidth = currentWidth + spaceWidth + wordWidth if newWidth <= maxWidth or not len(cLine): # fit one more on this line cLine.append(word) currentWidth = newWidth else: if currentWidth > self.width: self.width = currentWidth #end of line lines.append((maxWidth - currentWidth, cLine)) cLine = [word] currentWidth = wordWidth lineno += 1 try: maxWidth = maxWidths[lineno] except IndexError: maxWidth = maxWidths[-1] # use the last one #deal with any leftovers on the final line if cLine!=[]: if currentWidth>self.width: self.width = currentWidth lines.append((maxWidth - currentWidth, cLine)) return f.clone(kind=0, lines=lines,ascent=ascent,descent=descent,fontSize=fontSize) elif nFrags<=0: return ParaLines(kind=0, fontSize=style.fontSize, fontName=style.fontName, textColor=style.textColor, ascent=style.fontSize,descent=-0.2*style.fontSize, lines=[]) else: if hasattr(self,'blPara') and getattr(self,'_splitpara',0): #NB this is an utter hack that awaits the proper information #preserving splitting algorithm return self.blPara n = 0 words = [] for w in _getFragWords(frags): f=w[-1][0] fontName = f.fontName fontSize = f.fontSize spaceWidth = stringWidth(' ',fontName, fontSize) if not words: currentWidth = -spaceWidth # hack to get around extra space for word 1 maxSize = fontSize maxAscent, minDescent = getAscentDescent(fontName,fontSize) wordWidth = w[0] f = w[1][0] if wordWidth>0: newWidth = currentWidth + spaceWidth + wordWidth else: newWidth = currentWidth #test to see if this frag is a line break. If it is we will only act on it #if the current width is non-negative or the previous thing was a deliberate lineBreak lineBreak = hasattr(f,'lineBreak') endLine = (newWidth>maxWidth and n>0) or lineBreak if not endLine: if lineBreak: continue #throw it away nText = w[1][1] if nText: n += 1 fontSize = f.fontSize if calcBounds: cbDefn = getattr(f,'cbDefn',None) if getattr(cbDefn,'width',0): descent,ascent = imgVRange(cbDefn.height,cbDefn.valign,fontSize) else: ascent, descent = getAscentDescent(f.fontName,fontSize) else: ascent, descent = getAscentDescent(f.fontName,fontSize) maxSize = max(maxSize,fontSize) maxAscent = max(maxAscent,ascent) minDescent = min(minDescent,descent) if not words: g = f.clone() words = [g] g.text = nText elif not _sameFrag(g,f): if currentWidth>0 and ((nText!='' and nText[0]!=' ') or hasattr(f,'cbDefn')): if hasattr(g,'cbDefn'): i = len(words)-1 while i>=0: wi = words[i] cbDefn = getattr(wi,'cbDefn',None) if cbDefn: if not getattr(cbDefn,'width',0): i -= 1 continue if not wi.text.endswith(' '): wi.text += ' ' break else: if not g.text.endswith(' '): g.text += ' ' g = f.clone() words.append(g) g.text = nText else: if nText!='' and nText[0]!=' ': g.text += ' ' + nText for i in w[2:]: g = i[0].clone() g.text=i[1] words.append(g) fontSize = g.fontSize if calcBounds: cbDefn = getattr(g,'cbDefn',None) if getattr(cbDefn,'width',0): descent,ascent = imgVRange(cbDefn.height,cbDefn.valign,fontSize) else: ascent, descent = getAscentDescent(g.fontName,fontSize) else: ascent, descent = getAscentDescent(g.fontName,fontSize) maxSize = max(maxSize,fontSize) maxAscent = max(maxAscent,ascent) minDescent = min(minDescent,descent) currentWidth = newWidth else: #either it won't fit, or it's a lineBreak tag if lineBreak: g = f.clone() #del g.lineBreak words.append(g) if currentWidth>self.width: self.width = currentWidth #end of line lines.append(FragLine(extraSpace=maxWidth-currentWidth, wordCount=n, lineBreak=lineBreak, words=words, fontSize=maxSize, ascent=maxAscent, descent=minDescent)) #start new line lineno += 1 try: maxWidth = maxWidths[lineno] except IndexError: maxWidth = maxWidths[-1] # use the last one if lineBreak: n = 0 words = [] continue currentWidth = wordWidth n = 1 g = f.clone() maxSize = g.fontSize if calcBounds: cbDefn = getattr(g,'cbDefn',None) if getattr(cbDefn,'width',0): minDescent,maxAscent = imgVRange(cbDefn.height,cbDefn.valign,maxSize) else: maxAscent, minDescent = getAscentDescent(g.fontName,maxSize) else: maxAscent, minDescent = getAscentDescent(g.fontName,maxSize) words = [g] g.text = w[1][1] for i in w[2:]: g = i[0].clone() g.text=i[1] words.append(g) fontSize = g.fontSize if calcBounds: cbDefn = getattr(g,'cbDefn',None) if getattr(cbDefn,'width',0): descent,ascent = imgVRange(cbDefn.height,cbDefn.valign,fontSize) else: ascent, descent = getAscentDescent(g.fontName,fontSize) else: ascent, descent = getAscentDescent(g.fontName,fontSize) maxSize = max(maxSize,fontSize) maxAscent = max(maxAscent,ascent) minDescent = min(minDescent,descent) #deal with any leftovers on the final line if words!=[]: if currentWidth>self.width: self.width = currentWidth lines.append(ParaLines(extraSpace=(maxWidth - currentWidth),wordCount=n, words=words, fontSize=maxSize,ascent=maxAscent,descent=minDescent)) return ParaLines(kind=1, lines=lines) return lines def breakLinesCJK(self, width): """Initially, the dumbest possible wrapping algorithm. Cannot handle font variations.""" if self.debug: print id(self), "breakLinesCJK" if not isinstance(width,(list,tuple)): maxWidths = [width] else: maxWidths = width style = self.style #for bullets, work out width and ensure we wrap the right amount onto line one _handleBulletWidth(self.bulletText, style, maxWidths) if len(self.frags)>1: autoLeading = getattr(self,'autoLeading',getattr(style,'autoLeading','')) calcBounds = autoLeading not in ('','off') return cjkFragSplit(self.frags, maxWidths, calcBounds) #raise ValueError('CJK Wordwrap can only handle one fragment per paragraph for now. Tried to handle:\ntext: %s\nfrags: %s' % (self.text, self.frags)) elif not len(self.frags): return ParaLines(kind=0, fontSize=style.fontSize, fontName=style.fontName, textColor=style.textColor, lines=[],ascent=style.fontSize,descent=-0.2*style.fontSize) f = self.frags[0] if 1 and hasattr(self,'blPara') and getattr(self,'_splitpara',0): #NB this is an utter hack that awaits the proper information #preserving splitting algorithm return f.clone(kind=0, lines=self.blPara.lines) lines = [] lineno = 0 self.height = 0 f = self.frags[0] if hasattr(f,'text'): text = f.text else: text = ''.join(getattr(f,'words',[])) from reportlab.lib.textsplit import wordSplit lines = wordSplit(text, maxWidths[0], f.fontName, f.fontSize) #the paragraph drawing routine assumes multiple frags per line, so we need an #extra list like this # [space, [text]] # wrappedLines = [(sp, [line]) for (sp, line) in lines] return f.clone(kind=0, lines=wrappedLines, ascent=f.fontSize, descent=-0.2*f.fontSize) def beginText(self, x, y): return self.canv.beginText(x, y) def drawPara(self,debug=0): """Draws a paragraph according to the given style. Returns the final y position at the bottom. Not safe for paragraphs without spaces e.g. Japanese; wrapping algorithm will go infinite.""" if self.debug: print id(self), "drawPara", self.blPara.kind #stash the key facts locally for speed canvas = self.canv style = self.style blPara = self.blPara lines = blPara.lines leading = style.leading autoLeading = getattr(self,'autoLeading',getattr(style,'autoLeading','')) #work out the origin for line 1 leftIndent = style.leftIndent cur_x = leftIndent if debug: bw = 0.5 bc = Color(1,1,0) bg = Color(0.9,0.9,0.9) else: bw = getattr(style,'borderWidth',None) bc = getattr(style,'borderColor',None) bg = style.backColor #if has a background or border, draw it if bg or (bc and bw): canvas.saveState() op = canvas.rect kwds = dict(fill=0,stroke=0) if bc and bw: canvas.setStrokeColor(bc) canvas.setLineWidth(bw) kwds['stroke'] = 1 br = getattr(style,'borderRadius',0) if br and not debug: op = canvas.roundRect kwds['radius'] = br if bg: canvas.setFillColor(bg) kwds['fill'] = 1 bp = getattr(style,'borderPadding',0) op(leftIndent-bp, -bp, self.width - (leftIndent+style.rightIndent)+2*bp, self.height+2*bp, **kwds) canvas.restoreState() nLines = len(lines) bulletText = self.bulletText if nLines > 0: _offsets = getattr(self,'_offsets',[0]) _offsets += (nLines-len(_offsets))*[_offsets[-1]] canvas.saveState() #canvas.addLiteral('%% %s.drawPara' % _className(self)) alignment = style.alignment offset = style.firstLineIndent+_offsets[0] lim = nLines-1 noJustifyLast = not (hasattr(self,'_JustifyLast') and self._JustifyLast) if blPara.kind==0: if alignment == TA_LEFT: dpl = _leftDrawParaLine elif alignment == TA_CENTER: dpl = _centerDrawParaLine elif self.style.alignment == TA_RIGHT: dpl = _rightDrawParaLine elif self.style.alignment == TA_JUSTIFY: dpl = _justifyDrawParaLine f = blPara cur_y = self.height - getattr(f,'ascent',f.fontSize) #TODO fix XPreformatted to remove this hack if bulletText: offset = _drawBullet(canvas,offset,cur_y,bulletText,style) #set up the font etc. canvas.setFillColor(f.textColor) tx = self.beginText(cur_x, cur_y) if autoLeading=='max': leading = max(leading,LEADING_FACTOR*f.fontSize) elif autoLeading=='min': leading = LEADING_FACTOR*f.fontSize #now the font for the rest of the paragraph tx.setFont(f.fontName, f.fontSize, leading) ws = lines[0][0] t_off = dpl( tx, offset, ws, lines[0][1], noJustifyLast and nLines==1) if f.underline or f.link or f.strike: xs = tx.XtraState = ABag() xs.cur_y = cur_y xs.f = f xs.style = style xs.lines = lines xs.underlines = [] xs.underlineColor = None # XXX Modified for XHTML2PDF xs.backgrounds = [] xs.backgroundColor = None xs.backgroundFontSize = None xs.strikes = [] xs.strikeColor = None # XXX Modified for XHTML2PDF xs.strikeFontSize = None xs.links = [] xs.link = f.link canvas.setStrokeColor(f.textColor) dx = t_off + leftIndent if dpl != _justifyDrawParaLine: ws = 0 # XXX Never underline! underline = f.underline strike = f.strike link = f.link if underline: _do_under_line(0, dx, ws, tx) if strike: _do_under_line(0, dx, ws, tx, lm=0.125) if link: _do_link_line(0, dx, ws, tx) #now the middle of the paragraph, aligned with the left margin which is our origin. for i in xrange(1, nLines): ws = lines[i][0] t_off = dpl( tx, _offsets[i], ws, lines[i][1], noJustifyLast and i==lim) if dpl!=_justifyDrawParaLine: ws = 0 if underline: _do_under_line(i, t_off+leftIndent, ws, tx) if strike: _do_under_line(i, t_off+leftIndent, ws, tx, lm=0.125) if link: _do_link_line(i, t_off+leftIndent, ws, tx) else: for i in xrange(1, nLines): dpl( tx, _offsets[i], lines[i][0], lines[i][1], noJustifyLast and i==lim) else: f = lines[0] cur_y = self.height - getattr(f,'ascent',f.fontSize) #TODO fix XPreformatted to remove this hack # default? dpl = _leftDrawParaLineX if bulletText: oo = offset offset = _drawBullet(canvas,offset,cur_y,bulletText,style) if alignment == TA_LEFT: dpl = _leftDrawParaLineX elif alignment == TA_CENTER: dpl = _centerDrawParaLineX elif self.style.alignment == TA_RIGHT: dpl = _rightDrawParaLineX elif self.style.alignment == TA_JUSTIFY: dpl = _justifyDrawParaLineX else: raise ValueError("bad align %s" % repr(alignment)) #set up the font etc. tx = self.beginText(cur_x, cur_y) xs = tx.XtraState = ABag() xs.textColor = None # XXX Modified for XHTML2PDF xs.backColor = None xs.rise = 0 xs.underline = 0 xs.underlines = [] xs.underlineColor = None # XXX Modified for XHTML2PDF xs.background = 0 xs.backgrounds = [] xs.backgroundColor = None xs.backgroundFontSize = None xs.strike = 0 xs.strikes = [] xs.strikeColor = None # XXX Modified for XHTML2PDF xs.strikeFontSize = None xs.links = [] xs.link = None xs.leading = style.leading xs.leftIndent = leftIndent tx._leading = None tx._olb = None xs.cur_y = cur_y xs.f = f xs.style = style xs.autoLeading = autoLeading tx._fontname,tx._fontsize = None, None dpl( tx, offset, lines[0], noJustifyLast and nLines==1) _do_post_text(tx) #now the middle of the paragraph, aligned with the left margin which is our origin. for i in xrange(1, nLines): f = lines[i] dpl( tx, _offsets[i], f, noJustifyLast and i==lim) _do_post_text(tx) canvas.drawText(tx) canvas.restoreState() def getPlainText(self,identify=None): """Convenience function for templates which want access to the raw text, without XML tags. """ frags = getattr(self,'frags',None) if frags: plains = [] for frag in frags: if hasattr(frag, 'text'): plains.append(frag.text) return join(plains, '') elif identify: text = getattr(self,'text',None) if text is None: text = repr(self) return text else: return '' def getActualLineWidths0(self): """Convenience function; tells you how wide each line actually is. For justified styles, this will be the same as the wrap width; for others it might be useful for seeing if paragraphs will fit in spaces.""" assert hasattr(self, 'width'), "Cannot call this method before wrap()" if self.blPara.kind: func = lambda frag, w=self.width: w - frag.extraSpace else: func = lambda frag, w=self.width: w - frag[0] return map(func,self.blPara.lines) if __name__=='__main__': #NORUNTESTS def dumpParagraphLines(P): print 'dumpParagraphLines()' % id(P) lines = P.blPara.lines for l,line in enumerate(lines): line = lines[l] if hasattr(line,'words'): words = line.words else: words = line[1] nwords = len(words) print 'line%d: %d(%s)\n ' % (l,nwords,str(getattr(line,'wordCount','Unknown'))), for w in xrange(nwords): print "%d:'%s'"%(w,getattr(words[w],'text',words[w])), print def fragDump(w): R= ["'%s'" % w[1]] for a in ('fontName', 'fontSize', 'textColor', 'rise', 'underline', 'strike', 'link', 'cbDefn','lineBreak'): if hasattr(w[0],a): R.append('%s=%r' % (a,getattr(w[0],a))) return ', '.join(R) def dumpParagraphFrags(P): print 'dumpParagraphFrags() minWidth() = %.2f' % (id(P), P.minWidth()) frags = P.frags n =len(frags) for l in xrange(n): print "frag%d: '%s' %s" % (l, frags[l].text,' '.join(['%s=%s' % (k,getattr(frags[l],k)) for k in frags[l].__dict__ if k!=text])) l = 0 cum = 0 for W in _getFragWords(frags): cum += W[0] print "fragword%d: cum=%3d size=%d" % (l, cum, W[0]), for w in W[1:]: print '(%s)' % fragDump(w), print l += 1 from reportlab.lib.styles import getSampleStyleSheet, ParagraphStyle from reportlab.lib.units import cm import sys TESTS = sys.argv[1:] if TESTS==[]: TESTS=['4'] def flagged(i,TESTS=TESTS): return 'all' in TESTS or '*' in TESTS or str(i) in TESTS styleSheet = getSampleStyleSheet() B = styleSheet['BodyText'] style = ParagraphStyle("discussiontext", parent=B) style.fontName= 'Helvetica' if flagged(1): text='''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't 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. ''' P=Paragraph(text,style) dumpParagraphFrags(P) aW, aH = 456.0, 42.8 w,h = P.wrap(aW, aH) dumpParagraphLines(P) S = P.split(aW,aH) for s in S: s.wrap(aW,aH) dumpParagraphLines(s) aH = 500 if flagged(2): P=Paragraph("""Price*""", styleSheet['Normal']) dumpParagraphFrags(P) w,h = P.wrap(24, 200) dumpParagraphLines(P) if flagged(3): text = """Dieses Kapitel bietet eine schnelle Programme :: starten Eingabeaufforderung :: (>>>) >>> (Eingabeaufforderung) Einführung in Python Python :: Einführung . Das Ziel ist, die grundlegenden Eigenschaften von Python darzustellen, ohne sich zu sehr in speziellen Regeln oder Details zu verstricken. Dazu behandelt dieses Kapitel kurz die wesentlichen Konzepte wie Variablen, Ausdrücke, Kontrollfluss, Funktionen sowie Ein- und Ausgabe. Es erhebt nicht den Anspruch, umfassend zu sein.""" P=Paragraph(text, styleSheet['Code']) dumpParagraphFrags(P) w,h = P.wrap(6*72, 9.7*72) dumpParagraphLines(P) if flagged(4): text='''Die eingebaute Funktion range(i, j [, stride]) erzeugt eine Liste von Ganzzahlen und füllt sie mit Werten k, für die gilt: i <= k < j. Man kann auch eine optionale Schrittweite angeben. Die eingebaute Funktion xrange() erfüllt einen ähnlichen Zweck, gibt aber eine unveränderliche Sequenz vom Typ XRangeType zurück. Anstatt alle Werte in der Liste abzuspeichern, berechnet diese Liste ihre Werte, wann immer sie angefordert werden. Das ist sehr viel speicherschonender, wenn mit sehr langen Listen von Ganzzahlen gearbeitet wird. XRangeType kennt eine einzige Methode, s.tolist(), die seine Werte in eine Liste umwandelt.''' aW = 420 aH = 64.4 P=Paragraph(text, B) dumpParagraphFrags(P) w,h = P.wrap(aW,aH) print 'After initial wrap',w,h dumpParagraphLines(P) S = P.split(aW,aH) dumpParagraphFrags(S[0]) w0,h0 = S[0].wrap(aW,aH) print 'After split wrap',w0,h0 dumpParagraphLines(S[0]) if flagged(5): text = ' %s & %s < >]]>' % (chr(163),chr(163)) P=Paragraph(text, styleSheet['Code']) dumpParagraphFrags(P) w,h = P.wrap(6*72, 9.7*72) dumpParagraphLines(P) if flagged(6): for text in ['''Here comes Helvetica 14 with strong emphasis.''', '''Here comes Helvetica 14 with strong emphasis.''', '''Here comes Courier 3cm and normal again.''', ]: P=Paragraph(text, styleSheet['Normal'], caseSensitive=0) dumpParagraphFrags(P) w,h = P.wrap(6*72, 9.7*72) dumpParagraphLines(P) if flagged(7): text = """Generated by:Dilbert""" P=Paragraph(text, styleSheet['Code']) dumpParagraphFrags(P) w,h = P.wrap(6*72, 9.7*72) dumpParagraphLines(P) if flagged(8): text ="""- bullet 0
- bullet 1
- bullet 2
- bullet 3
- bullet 4
- bullet 5""" P=Paragraph(text, styleSheet['Normal']) dumpParagraphFrags(P) w,h = P.wrap(6*72, 9.7*72) dumpParagraphLines(P) S = P.split(6*72,h/2.0) print len(S) dumpParagraphLines(S[0]) dumpParagraphLines(S[1]) if flagged(9): text="""Furthermore, the fundamental error of regarding functional notions as categorial delimits a general convention regarding the forms of the
grammar. I suggested that these results would follow from the assumption that""" P=Paragraph(text,ParagraphStyle('aaa',parent=styleSheet['Normal'],align=TA_JUSTIFY)) dumpParagraphFrags(P) w,h = P.wrap(6*cm-12, 9.7*72) dumpParagraphLines(P) if flagged(10): text="""a b c\xc2\xa0d e f""" P=Paragraph(text,ParagraphStyle('aaa',parent=styleSheet['Normal'],align=TA_JUSTIFY)) dumpParagraphFrags(P) w,h = P.wrap(6*cm-12, 9.7*72) dumpParagraphLines(P) pisa-3.0.32/sx/pisa3/._pisa_tags.py0000644000175000017500000000035111200743065015076 0ustar wmbwmbMac OS X  2ATTR9>QQcom.apple.quarantineq/0000;49cba683;Safari.app;9AFF29BE-A1F8-4D2F-A543-8AC395074CD0|com.apple.Safaripisa-3.0.32/sx/pisa3/._pisa_turbogears.py0000644000175000017500000000035111072375237016326 0ustar wmbwmbMac OS X  2ATTR9?QQcom.apple.quarantineq/0000;49cba683;Safari.app;9AFF29BE-A1F8-4D2F-A543-8AC395074CD0|com.apple.Safaripisa-3.0.32/sx/pisa3/pisa_tables.py0000644000175000017500000003116211200743122015173 0ustar wmbwmb# -*- coding: ISO-8859-1 -*- ############################################# ## (C)opyright by Dirk Holtwick, 2002-2007 ## ## All rights reserved ## ############################################# __reversion__ = "$Revision: 20 $" __author__ = "$Author: holtwick $" __date__ = "$Date: 2007-10-09 12:58:24 +0200 (Di, 09 Okt 2007) $" from pisa_tags import pisaTag from pisa_util import * from pisa_reportlab import PmlTable, TableStyle, PmlKeepInFrame import copy import sys import logging log = logging.getLogger("ho.pisa") def _width(value=None): if value is None: return None value = str(value) if value.endswith("%"): return value return getSize(value) class TableData: def __init__(self): self.data = [] self.styles = [] self.span = [] self.mode = "" self.padding = 0 self.col = 0 # self.c = None def add_cell(self, data=None): self.col += 1 self.data[len(self.data) - 1].append(data) def add_style(self, data): # print self.mode, data # Do we have color and # width = data[3] #if data[0].startswith("LINE"): # color = data[4] # if color is None: # return self.styles.append(copy.copy(data)) def add_empty(self, x, y): self.span.append((x, y)) def get_data(self): data = self.data for x, y in self.span: try: data[y].insert(x, '') except: pass return data def add_cell_styles(self, c, begin, end, mode="td"): def getColor(a, b): return a self.mode = mode.upper() if c.frag.backColor and mode != "tr": # XXX Stimmt das so? self.add_style(('BACKGROUND', begin, end, c.frag.backColor)) # print 'BACKGROUND', begin, end, c.frag.backColor if 0: log.debug("%r", ( begin, end, c.frag.borderTopWidth, c.frag.borderTopStyle, c.frag.borderTopColor, c.frag.borderBottomWidth, c.frag.borderBottomStyle, c.frag.borderBottomColor, c.frag.borderLeftWidth, c.frag.borderLeftStyle, c.frag.borderLeftColor, c.frag.borderRightWidth, c.frag.borderRightStyle, c.frag.borderRightColor, )) if getBorderStyle(c.frag.borderTopStyle) and c.frag.borderTopWidth and c.frag.borderTopColor is not None: self.add_style(('LINEABOVE', begin, (end[0], begin[1]), c.frag.borderTopWidth, c.frag.borderTopColor, "squared")) if getBorderStyle(c.frag.borderLeftStyle) and c.frag.borderLeftWidth and c.frag.borderLeftColor is not None: self.add_style(('LINEBEFORE', begin, (begin[0], end[1]), c.frag.borderLeftWidth, c.frag.borderLeftColor, "squared")) if getBorderStyle(c.frag.borderRightStyle) and c.frag.borderRightWidth and c.frag.borderRightColor is not None: self.add_style(('LINEAFTER', (end[0], begin[1]), end, c.frag.borderRightWidth, c.frag.borderRightColor, "squared")) if getBorderStyle(c.frag.borderBottomStyle) and c.frag.borderBottomWidth and c.frag.borderBottomColor is not None: self.add_style(('LINEBELOW', (begin[0], end[1]), end, c.frag.borderBottomWidth, c.frag.borderBottomColor, "squared")) self.add_style(('LEFTPADDING', begin, end, c.frag.paddingLeft or self.padding)) self.add_style(('RIGHTPADDING', begin, end, c.frag.paddingRight or self.padding)) self.add_style(('TOPPADDING', begin, end, c.frag.paddingTop or self.padding)) self.add_style(('BOTTOMPADDING', begin, end, c.frag.paddingBottom or self.padding)) class pisaTagTABLE(pisaTag): def start(self, c): c.addPara() attrs = self.attr # Swap table data c.tableData, self.tableData = TableData(), c.tableData tdata = c.tableData # border #tdata.border = attrs.border #tdata.bordercolor = attrs.bordercolor begin = (0, 0) end = (-1, - 1) if attrs.border and attrs.bordercolor: frag = c.frag frag.borderLeftWidth = attrs.border frag.borderLeftColor = attrs.bordercolor frag.borderLeftStyle = "solid" frag.borderRightWidth = attrs.border frag.borderRightColor = attrs.bordercolor frag.borderRightStyle = "solid" frag.borderTopWidth = attrs.border frag.borderTopColor = attrs.bordercolor frag.borderTopStyle = "solid" frag.borderBottomWidth = attrs.border frag.borderBottomColor = attrs.bordercolor frag.borderBottomStyle = "solid" # tdata.add_style(("GRID", begin, end, attrs.border, attrs.bordercolor)) tdata.padding = attrs.cellpadding #if 0: #attrs.cellpadding: # tdata.add_style(('LEFTPADDING', begin, end, attrs.cellpadding)) # tdata.add_style(('RIGHTPADDING', begin, end, attrs.cellpadding)) # tdata.add_style(('TOPPADDING', begin, end, attrs.cellpadding)) # tdata.add_style(('BOTTOMPADDING', begin, end, attrs.cellpadding)) # alignment #~ tdata.add_style(('VALIGN', (0,0), (-1,-1), attrs.valign.upper())) # Set Border and padding styles tdata.add_cell_styles(c, (0, 0), (-1, - 1), "table") # bgcolor #if attrs.bgcolor is not None: # tdata.add_style(('BACKGROUND', (0, 0), (-1, -1), attrs.bgcolor)) tdata.align = attrs.align.upper() tdata.col = 0 tdata.row = 0 tdata.colw = [] tdata.rowh = [] tdata.repeat = attrs.repeat tdata.width = _width(attrs.width) # self.tabdata.append(tdata) def end(self, c): tdata = c.tableData data = tdata.get_data() # Add missing columns so that each row has the same count of columns # This prevents errors in Reportlab table maxcols = max([len(row) for row in data] or [0]) for i, row in enumerate(data): data[i] += [''] * (maxcols - len(row)) try: if tdata.data: # log.debug("Table sryles %r", tdata.styles) t = PmlTable( data, colWidths=tdata.colw, rowHeights=tdata.rowh, # totalWidth = tdata.width, splitByRow=1, # repeatCols = 1, repeatRows=tdata.repeat, hAlign=tdata.align, vAlign='TOP', style=TableStyle(tdata.styles)) t.totalWidth = _width(tdata.width) t.spaceBefore = c.frag.spaceBefore t.spaceAfter = c.frag.spaceAfter # XXX Maybe we need to copy some more properties? t.keepWithNext = c.frag.keepWithNext # t.hAlign = tdata.align c.addStory(t) else: log.warn(c.warning(" is empty")) except: log.warn(c.warning("
"), exc_info=1) # Cleanup and re-swap table data c.clearFrag() c.tableData, self.tableData = self.tableData, None class pisaTagTR(pisaTag): def start(self, c): tdata = c.tableData row = tdata.row begin = (0, row) end = (-1, row) tdata.add_cell_styles(c, begin, end, "tr") c.frag.vAlign = self.attr.valign or c.frag.vAlign tdata.col = 0 tdata.data.append([]) def end(self, c): c.tableData.row += 1 class pisaTagTD(pisaTag): def start(self, c): if self.attr.align is not None: #print self.attr.align, getAlign(self.attr.align) c.frag.alignment = getAlign(self.attr.align) c.clearFrag() self.story = c.swapStory() # print "#", len(c.story) attrs = self.attr tdata = c.tableData cspan = attrs.colspan rspan = attrs.rowspan row = tdata.row col = tdata.col while 1: for x, y in tdata.span: if x == col and y == row: col += 1 tdata.col += 1 break #cs = 0 #rs = 0 begin = (col, row) end = (col, row) if cspan: end = (end[0] + cspan - 1, end[1]) if rspan: end = (end[0], end[1] + rspan - 1) if begin != end: #~ print begin, end tdata.add_style(('SPAN', begin, end)) for x in range(begin[0], end[0] + 1): for y in range(begin[1], end[1] + 1): if x != begin[0] or y != begin[1]: tdata.add_empty(x, y) # Set Border and padding styles tdata.add_cell_styles(c, begin, end, "td") # Calculate widths # Add empty placeholders for new columns if (col + 1) > len(tdata.colw): tdata.colw = tdata.colw + ((col + 1 - len(tdata.colw)) * [_width()]) # Get value of with, if no spanning if not cspan: # print c.frag.width width = c.frag.width or self.attr.width #self._getStyle(None, attrs, "width", "width", mode) # If is value, the set it in the right place in the arry # print width, _width(width) if width is not None: tdata.colw[col] = _width(width) # Calculate heights if row + 1 > len(tdata.rowh): tdata.rowh = tdata.rowh + ((row + 1 - len(tdata.rowh)) * [_width()]) if not rspan: height = None #self._getStyle(None, attrs, "height", "height", mode) if height is not None: tdata.rowh[row] = _width(height) tdata.add_style(('FONTSIZE', begin, end, 1.0)) tdata.add_style(('LEADING', begin, end, 1.0)) # Vertical align valign = self.attr.valign or c.frag.vAlign if valign is not None: tdata.add_style(('VALIGN', begin, end, valign.upper())) # Reset border, otherwise the paragraph block will have borders too frag = c.frag frag.borderLeftWidth = 0 frag.borderLeftColor = None frag.borderLeftStyle = None frag.borderRightWidth = 0 frag.borderRightColor = None frag.borderRightStyle = None frag.borderTopWidth = 0 frag.borderTopColor = None frag.borderTopStyle = None frag.borderBottomWidth = 0 frag.borderBottomColor = None frag.borderBottomStyle = None def end(self, c): tdata = c.tableData c.addPara() cell = c.story # Handle empty cells, they otherwise collapse if not cell: cell = ' ' # Keep in frame if needed since Reportlab does no split inside of cells elif (not c.frag.insideStaticFrame) and (c.frag.keepInFrameMode is not None): # tdata.keepinframe["content"] = cell cell = PmlKeepInFrame( maxWidth=0, maxHeight=0, mode=c.frag.keepInFrameMode, content=cell) c.swapStory(self.story) tdata.add_cell(cell) class pisaTagTH(pisaTagTD): pass ''' end_th = end_td def start_keeptogether(self, attrs): self.story.append([]) self.next_para() def end_keeptogether(self): if not self.story[-1]: self.add_noop() self.next_para() s = self.story.pop() self.add_story(KeepTogether(s)) def start_keepinframe(self, attrs): self.story.append([]) self.keepinframe = { "maxWidth": attrs["maxwidth"], "maxHeight": attrs["maxheight"], "mode": attrs["mode"], "name": attrs["name"], "mergeSpace": attrs["mergespace"] } # print self.keepinframe self.next_para() def end_keepinframe(self): if not self.story[-1]: self.add_noop() self.next_para() self.keepinframe["content"] = self.story.pop() self.add_story(KeepInFrame(**self.keepinframe)) '''pisa-3.0.32/sx/pisa3/pisa_pdf.py0000644000175000017500000000320711165202562014501 0ustar wmbwmb# -*- coding: ISO-8859-1 -*- ############################################# ## (C)opyright by Dirk Holtwick, 2002-2007 ## ## All rights reserved ## ############################################# __reversion__ = "$Revision: 20 $" __author__ = "$Author: holtwick $" __date__ = "$Date: 2007-10-09 12:58:24 +0200 (Di, 09 Okt 2007) $" from pisa_util import pisaTempFile, getFile import logging log = logging.getLogger("ho.pisa") class pisaPDF: def __init__(self, capacity=-1): self.capacity = capacity self.files = [] def addFromURI(self, url, basepath=None): obj = getFile(url, basepath) if obj and (not obj.notFound()): self.files.append(obj.getFile()) addFromFileName = addFromURI def addFromFile(self, f): if hasattr(f, "read"): self.files.append(f) self.addFromURI(f) def addFromString(self, data): self.files.append(pisaTempFile(data, capacity=self.capacity)) def addDocument(self, doc): if hasattr(doc.dest, "read"): self.files.append(doc.dest) def join(self, file=None): import pyPdf if pyPdf: output = pyPdf.PdfFileWriter() for pdffile in self.files: input = pyPdf.PdfFileReader(pdffile) for pageNumber in range(0, input.getNumPages()): output.addPage(input.getPage(pageNumber)) if file is not None: output.write(file) return file out = pisaTempFile(capacity=self.capacity) output.write(out) return out.getvalue() getvalue = join __str__ = join pisa-3.0.32/sx/pisa3/pisa_parser.py0000644000175000017500000005614611200026233015223 0ustar wmbwmb# -*- coding: ISO-8859-1 -*- ############################################# ## (C)opyright by Dirk Holtwick, 2002-2007 ## ## All rights reserved ## ############################################# __reversion__ = "$Revision: 20 $" __author__ = "$Author: holtwick $" __date__ = "$Date: 2007-10-09 12:58:24 +0200 (Di, 09 Okt 2007) $" import pprint import copy import types import re import os import os.path import html5lib from html5lib import treebuilders, serializer, treewalkers, inputstream from xml.dom import Node import xml.dom.minidom from pisa_default import * from pisa_util import * from pisa_tags import * from pisa_tables import * import sx.w3c.css as css import sx.w3c.cssDOMElementInterface as cssDOMElementInterface import logging log = logging.getLogger("ho.pisa") rxhttpstrip = re.compile("https?://[^/]+(.*)", re.M | re.I) class AttrContainer(dict): def __getattr__(self, name): try: return dict.__getattr__(self, name) except: return self[name] def pisaGetAttributes(c, tag, attributes): global TAGS attrs = {} if attributes: for k, v in attributes.items(): try: attrs[str(k)] = str(v) # XXX no Unicode! Reportlab fails with template names except: attrs[k] = v nattrs = {} if TAGS.has_key(tag): block, adef = TAGS[tag] adef["id"] = STRING # print block, adef for k, v in adef.items(): nattrs[k] = None # print k, v # defaults, wenn vorhanden if type(v) == types.TupleType: if v[1] == MUST: if not attrs.has_key(k): log.warn(c.warning("Attribute '%s' must be set!", k)) nattrs[k] = None continue nv = attrs.get(k, v[1]) dfl = v[1] v = v[0] else: nv = attrs.get(k, None) dfl = None try: if nv is not None: if type(v) == types.ListType: nv = nv.strip().lower() if nv not in v: #~ raise PML_EXCEPTION, "attribute '%s' of wrong value, allowed is one of: %s" % (k, repr(v)) log.warn(c.warning("Attribute '%s' of wrong value, allowed is one of: %s", k, repr(v))) nv = dfl elif v == BOOL: nv = nv.strip().lower() nv = nv in ("1", "y", "yes", "true", str(k)) elif v == SIZE: try: nv = getSize(nv) except: log.warn(c.warning("Attribute '%s' expects a size value", k)) elif v == BOX: nv = getBox(nv, c.pageSize) elif v == POS: nv = getPos(nv, c.pageSize) elif v == INT: nv = int(nv) elif v == COLOR: nv = getColor(nv) elif v == FILE: nv = c.getFile(nv) elif v == FONT: nv = c.getFontName(nv) nattrs[k] = nv #for k in attrs.keys(): # if not nattrs.has_key(k): # c.warning("attribute '%s' for tag <%s> not supported" % (k, tag)) except Exception, e: log.exception(c.error("Tag handling")) #else: # c.warning("tag <%s> is not supported" % tag) return AttrContainer(nattrs) attrNames = ''' color font-family font-size font-weight font-style text-decoration line-height background-color display margin-left margin-right margin-top margin-bottom padding-left padding-right padding-top padding-bottom border-top-color border-top-style border-top-width border-bottom-color border-bottom-style border-bottom-width border-left-color border-left-style border-left-width border-right-color border-right-style border-right-width text-align vertical-align width height zoom page-break-after page-break-before list-style-type list-style-image white-space text-indent -pdf-page-break -pdf-frame-break -pdf-next-page -pdf-keep-with-next -pdf-outline -pdf-outline-level -pdf-outline-open -pdf-line-spacing -pdf-keep-in-frame-mode '''.strip().split() def getCSSAttr(self, cssCascade, attrName, default=NotImplemented): if attrName in self.cssAttrs: return self.cssAttrs[attrName] try: result = cssCascade.findStyleFor(self.cssElement, attrName, default) except LookupError: result = None # XXX Workaround for inline styles try: style = self.cssStyle except: style = self.cssStyle = cssCascade.parser.parseInline(self.cssElement.getStyleAttr() or '')[0] if style.has_key(attrName): result = style[attrName] if result == 'inherit': if hasattr(self.parentNode, 'getCSSAttr'): result = self.parentNode.getCSSAttr(cssCascade, attrName, default) elif default is not NotImplemented: return default else: raise LookupError("Could not find inherited CSS attribute value for '%s'" % (attrName,)) if result is not None: self.cssAttrs[attrName] = result return result xml.dom.minidom.Element.getCSSAttr = getCSSAttr def CSSCollect(node, c): #node.cssAttrs = {} #return node.cssAttrs if c.css: node.cssElement = cssDOMElementInterface.CSSDOMElementInterface(node) node.cssAttrs = {} # node.cssElement.onCSSParserVisit(c.cssCascade.parser) cssAttrMap = {} for cssAttrName in attrNames: try: cssAttrMap[cssAttrName] = node.getCSSAttr(c.cssCascade, cssAttrName) #except LookupError: # pass except Exception: log.debug("CSS error '%s'", cssAttrName, exc_info=1) return node.cssAttrs def CSS2Frag(c, kw, isBlock): # COLORS if c.cssAttr.has_key("color"): c.frag.textColor = getColor(c.cssAttr["color"]) if c.cssAttr.has_key("background-color"): c.frag.backColor = getColor(c.cssAttr["background-color"]) # FONT SIZE, STYLE, WEIGHT if c.cssAttr.has_key("font-family"): c.frag.fontName = c.getFontName(c.cssAttr["font-family"]) if c.cssAttr.has_key("font-size"): # XXX inherit c.frag.fontSize = max(getSize("".join(c.cssAttr["font-size"]), c.frag.fontSize, c.baseFontSize), 1.0) if c.cssAttr.has_key("line-height"): leading = "".join(c.cssAttr["line-height"]) c.frag.leading = getSize(leading, c.frag.fontSize) c.frag.leadingSource = leading else: c.frag.leading = getSize(c.frag.leadingSource, c.frag.fontSize) if c.cssAttr.has_key("-pdf-line-spacing"): c.frag.leadingSpace = getSize("".join(c.cssAttr["-pdf-line-spacing"])) # print "line-spacing", c.cssAttr["-pdf-line-spacing"], c.frag.leading if c.cssAttr.has_key("font-weight"): value = c.cssAttr["font-weight"].lower() if value in ("bold", "bolder", "500", "600", "700", "800", "900"): c.frag.bold = 1 else: c.frag.bold = 0 for value in toList(c.cssAttr.get("text-decoration", "")): if "underline" in value: c.frag.underline = 1 if "line-through" in value: c.frag.strike = 1 if "none" in value: c.frag.underline = 0 c.frag.strike = 0 if c.cssAttr.has_key("font-style"): value = c.cssAttr["font-style"].lower() if value in ("italic", "oblique"): c.frag.italic = 1 else: c.frag.italic = 0 if c.cssAttr.has_key("white-space"): # normal | pre | nowrap c.frag.whiteSpace = str(c.cssAttr["white-space"]).lower() # ALIGN & VALIGN if c.cssAttr.has_key("text-align"): c.frag.alignment = getAlign(c.cssAttr["text-align"]) if c.cssAttr.has_key("vertical-align"): c.frag.vAlign = c.cssAttr["vertical-align"] # HEIGHT & WIDTH if c.cssAttr.has_key("height"): c.frag.height = "".join(toList(c.cssAttr["height"])) # XXX Relative is not correct! if c.frag.height in ("auto",): c.frag.height = None if c.cssAttr.has_key("width"): # print c.cssAttr["width"] c.frag.width = "".join(toList(c.cssAttr["width"])) # XXX Relative is not correct! if c.frag.width in ("auto",): c.frag.width = None # ZOOM if c.cssAttr.has_key("zoom"): # print c.cssAttr["width"] zoom = "".join(toList(c.cssAttr["zoom"])) # XXX Relative is not correct! if zoom.endswith("%"): zoom = float(zoom[: - 1]) / 100.0 c.frag.zoom = float(zoom) # MARGINS & LIST INDENT, STYLE if isBlock: if c.cssAttr.has_key("margin-top"): c.frag.spaceBefore = getSize(c.cssAttr["margin-top"], c.frag.fontSize) if c.cssAttr.has_key("margin-bottom"): c.frag.spaceAfter = getSize(c.cssAttr["margin-bottom"], c.frag.fontSize) if c.cssAttr.has_key("margin-left"): c.frag.bulletIndent = kw["margin-left"] # For lists kw["margin-left"] += getSize(c.cssAttr["margin-left"], c.frag.fontSize) c.frag.leftIndent = kw["margin-left"] # print "MARGIN LEFT", kw["margin-left"], c.frag.bulletIndent if c.cssAttr.has_key("margin-right"): kw["margin-right"] += getSize(c.cssAttr["margin-right"], c.frag.fontSize) c.frag.rightIndent = kw["margin-right"] # print c.frag.rightIndent if c.cssAttr.has_key("text-indent"): c.frag.firstLineIndent = getSize(c.cssAttr["text-indent"], c.frag.fontSize) if c.cssAttr.has_key("list-style-type"): c.frag.listStyleType = str(c.cssAttr["list-style-type"]).lower() if c.cssAttr.has_key("list-style-image"): c.frag.listStyleImage = c.getFile(c.cssAttr["list-style-image"]) # PADDINGS if isBlock: if c.cssAttr.has_key("padding-top"): c.frag.paddingTop = getSize(c.cssAttr["padding-top"], c.frag.fontSize) if c.cssAttr.has_key("padding-bottom"): c.frag.paddingBottom = getSize(c.cssAttr["padding-bottom"], c.frag.fontSize) if c.cssAttr.has_key("padding-left"): c.frag.paddingLeft = getSize(c.cssAttr["padding-left"], c.frag.fontSize) if c.cssAttr.has_key("padding-right"): c.frag.paddingRight = getSize(c.cssAttr["padding-right"], c.frag.fontSize) # BORDERS if isBlock: if c.cssAttr.has_key("border-top-width"): # log.debug(c.cssAttr["border-top-width"]) c.frag.borderTopWidth = getSize(c.cssAttr["border-top-width"], c.frag.fontSize) if c.cssAttr.has_key("border-bottom-width"): c.frag.borderBottomWidth = getSize(c.cssAttr["border-bottom-width"], c.frag.fontSize) if c.cssAttr.has_key("border-left-width"): c.frag.borderLeftWidth = getSize(c.cssAttr["border-left-width"], c.frag.fontSize) if c.cssAttr.has_key("border-right-width"): c.frag.borderRightWidth = getSize(c.cssAttr["border-right-width"], c.frag.fontSize) if c.cssAttr.has_key("border-top-style"): c.frag.borderTopStyle = c.cssAttr["border-top-style"] if c.cssAttr.has_key("border-bottom-style"): c.frag.borderBottomStyle = c.cssAttr["border-bottom-style"] if c.cssAttr.has_key("border-left-style"): c.frag.borderLeftStyle = c.cssAttr["border-left-style"] if c.cssAttr.has_key("border-right-style"): c.frag.borderRightStyle = c.cssAttr["border-right-style"] if c.cssAttr.has_key("border-top-color"): c.frag.borderTopColor = getColor(c.cssAttr["border-top-color"]) if c.cssAttr.has_key("border-bottom-color"): c.frag.borderBottomColor = getColor(c.cssAttr["border-bottom-color"]) if c.cssAttr.has_key("border-left-color"): c.frag.borderLeftColor = getColor(c.cssAttr["border-left-color"]) if c.cssAttr.has_key("border-right-color"): c.frag.borderRightColor = getColor(c.cssAttr["border-right-color"]) def pisaPreLoop(node, c, collect=False): """ Collect all CSS definitions """ data = u"" if node.nodeType == Node.TEXT_NODE and collect: data = node.data elif node.nodeType == Node.ELEMENT_NODE: name = node.tagName.lower() # print name, node.attributes.items() if name in ("style", "link"): attr = pisaGetAttributes(c, name, node.attributes) # print " ", attr media = [x.strip() for x in attr.media.lower().split(",") if x.strip()] # print repr(media) if (attr.get("type", "").lower() in ("", "text/css") and ( not media or "all" in media or "print" in media or "pdf" in media)): if name == "style": for node in node.childNodes: data += pisaPreLoop(node, c, collect=True) c.addCSS(data) return u"" #collect = True if name == "link" and attr.href and attr.rel.lower() == "stylesheet": # print "CSS LINK", attr c.addCSS('\n@import "%s" %s;' % (attr.href, ",".join(media))) # c.addCSS(unicode(file(attr.href, "rb").read(), attr.charset)) #else: # print node.nodeType for node in node.childNodes: result = pisaPreLoop(node, c, collect=collect) if collect: data += result return data def pisaLoop(node, c, path=[], **kw): # Initialize KW if not kw: kw = { "margin-top": 0, "margin-bottom": 0, "margin-left": 0, "margin-right": 0, } else: kw = copy.copy(kw) indent = len(path) * " " # TEXT if node.nodeType == Node.TEXT_NODE: # print indent, "#", repr(node.data) #, c.frag c.addFrag(node.data) # c.text.append(node.value) # ELEMENT elif node.nodeType == Node.ELEMENT_NODE: node.tagName = node.tagName.replace(":", "").lower() if node.tagName in ("style", "script"): return path = copy.copy(path) + [node.tagName] # Prepare attributes attr = pisaGetAttributes(c, node.tagName, node.attributes) # log.debug(indent + "<%s %s>" % (node.tagName, attr) + repr(node.attributes.items())) #, path # Calculate styles c.cssAttr = CSSCollect(node, c) c.node = node # Block? PAGE_BREAK = 1 PAGE_BREAK_RIGHT = 2 PAGE_BREAK_LEFT = 3 pageBreakAfter = False frameBreakAfter = False display = c.cssAttr.get("display", "inline").lower() # print indent, node.tagName, display, c.cssAttr.get("background-color", None), attr isBlock = (display == "block") if isBlock: c.addPara() # Page break by CSS if c.cssAttr.has_key("-pdf-next-page"): c.addStory(NextPageTemplate(str(c.cssAttr["-pdf-next-page"]))) if c.cssAttr.has_key("-pdf-page-break"): if str(c.cssAttr["-pdf-page-break"]).lower() == "before": c.addStory(PageBreak()) if c.cssAttr.has_key("-pdf-frame-break"): if str(c.cssAttr["-pdf-frame-break"]).lower() == "before": c.addStory(FrameBreak()) if str(c.cssAttr["-pdf-frame-break"]).lower() == "after": frameBreakAfter = True if c.cssAttr.has_key("page-break-before"): if str(c.cssAttr["page-break-before"]).lower() == "always": c.addStory(PageBreak()) if str(c.cssAttr["page-break-before"]).lower() == "right": c.addStory(PageBreak()) c.addStory(PmlRightPageBreak()) if str(c.cssAttr["page-break-before"]).lower() == "left": c.addStory(PageBreak()) c.addStory(PmlLeftPageBreak()) if c.cssAttr.has_key("page-break-after"): if str(c.cssAttr["page-break-after"]).lower() == "always": pageBreakAfter = PAGE_BREAK if str(c.cssAttr["page-break-after"]).lower() == "right": pageBreakAfter = PAGE_BREAK_RIGHT if str(c.cssAttr["page-break-after"]).lower() == "left": pageBreakAfter = PAGE_BREAK_LEFT if display == "none": # print "none!" return # Translate CSS to frags # Save previous frag styles c.pushFrag() # Map styles to Reportlab fragment properties CSS2Frag(c, kw, isBlock) # EXTRAS if c.cssAttr.has_key("-pdf-keep-with-next"): c.frag.keepWithNext = getBool(c.cssAttr["-pdf-keep-with-next"]) if c.cssAttr.has_key("-pdf-outline"): c.frag.outline = getBool(c.cssAttr["-pdf-outline"]) if c.cssAttr.has_key("-pdf-outline-level"): c.frag.outlineLevel = int(c.cssAttr["-pdf-outline-level"]) if c.cssAttr.has_key("-pdf-outline-open"): c.frag.outlineOpen = getBool(c.cssAttr["-pdf-outline-open"]) #if c.cssAttr.has_key("-pdf-keep-in-frame-max-width"): # c.frag.keepInFrameMaxWidth = getSize("".join(c.cssAttr["-pdf-keep-in-frame-max-width"])) #if c.cssAttr.has_key("-pdf-keep-in-frame-max-height"): # c.frag.keepInFrameMaxHeight = getSize("".join(c.cssAttr["-pdf-keep-in-frame-max-height"])) if c.cssAttr.has_key("-pdf-keep-in-frame-mode"): value = str(c.cssAttr["-pdf-keep-in-frame-mode"]).strip().lower() if value not in ("shrink", "error", "overflow", "shrink", "truncate"): value = None c.frag.keepInFrameMode = value # BEGIN tag klass = globals().get("pisaTag%s" % node.tagName.replace(":", "").upper(), None) obj = None # Static block elementId = attr.get("id", None) staticFrame = c.frameStatic.get(elementId, None) if staticFrame: c.frag.insideStaticFrame += 1 oldStory = c.swapStory() # Tag specific operations if klass is not None: obj = klass(node, attr) obj.start(c) # Visit child nodes c.fragBlock = fragBlock = copy.copy(c.frag) for nnode in node.childNodes: pisaLoop(nnode, c, path, **kw) c.fragBlock = fragBlock # END tag if obj: obj.end(c) # Block? if isBlock: c.addPara() # XXX Buggy! # Page break by CSS if pageBreakAfter: c.addStory(PageBreak()) if pageBreakAfter == PAGE_BREAK_RIGHT: c.addStory(PmlRightPageBreak()) if pageBreakAfter == PAGE_BREAK_LEFT: c.addStory(PmlLeftPageBreak()) if frameBreakAfter: c.addStory(FrameBreak()) # Static block, END if staticFrame: c.addPara() for frame in staticFrame: frame.pisaStaticStory = c.story c.swapStory(oldStory) c.frag.insideStaticFrame -= 1 # c.debug(1, indent, "" % (node.tagName)) # Reset frag style c.pullFrag() # Unknown or not handled else: # c.debug(1, indent, "???", node, node.nodeType, repr(node)) # Loop over children for node in node.childNodes: pisaLoop(node, c, path, **kw) def pisaParser(src, c, default_css="", xhtml=False, encoding=None, xml_output=None): """ - Parse HTML and get miniDOM - Extract CSS informations, add default CSS, parse CSS - Handle the document DOM itself and build reportlab story - Return Context object """ if xhtml: parser = html5lib.XHTMLParser(tree=treebuilders.getTreeBuilder("dom")) else: parser = html5lib.HTMLParser(tree=treebuilders.getTreeBuilder("dom")) if type(src) in types.StringTypes: if type(src) is types.UnicodeType: encoding = "utf8" src = src.encode(encoding) src = pisaTempFile(src, capacity=c.capacity) # Test for the restrictions of html5lib if encoding: # Workaround for html5lib<0.11.1 if hasattr(inputstream, "isValidEncoding"): if encoding.strip().lower() == "utf8": encoding = "utf-8" if not inputstream.isValidEncoding(encoding): log.error("%r is not a valid encoding e.g. 'utf8' is not valid but 'utf-8' is!", encoding) else: if inputstream.codecName(encoding) is None: log.error("%r is not a valid encoding", encoding) document = parser.parse( src, encoding=encoding) if xml_output: xml_output.write(document.toprettyxml(encoding="utf8")) if default_css: c.addCSS(default_css) pisaPreLoop(document, c) #try: c.parseCSS() #except: # c.cssText = DEFAULT_CSS # c.parseCSS() # c.debug(9, pprint.pformat(c.css)) pisaLoop(document, c) return c # Shortcuts HTML2PDF = pisaParser def XHTML2PDF(*a, **kw): kw["xhtml"] = True return HTML2PDF(*a, **kw) XML2PDF = XHTML2PDF pisa-3.0.32/sx/pisa3/pisa_document.py0000644000175000017500000001574311200742440015550 0ustar wmbwmb# -*- coding: ISO-8859-1 -*- ############################################# ## (C)opyright by Dirk Holtwick, 2002-2007 ## ## All rights reserved ## ############################################# __reversion__ = "$Revision: 20 $" __author__ = "$Author: holtwick $" __date__ = "$Date: 2007-10-09 12:58:24 +0200 (Di, 09 Okt 2007) $" from pisa_context import pisaContext from pisa_parser import pisaParser from pisa_util import * from pisa_reportlab import * from pisa_default import DEFAULT_CSS from reportlab.platypus.flowables import Spacer #import os #import types #import cgi #import logging log = logging.getLogger("ho.pisa") def pisaErrorDocument(dest, c): out = pisaTempFile(capacity=c.capacity) out.write("

%d error(s) occured:

" % c.err) for mode, line, msg, code in c.log: if mode=="error": out.write("

%s in line %d: %s
" % (mode, line, cgi.escape(msg))) out.write("

%d warning(s) occured:

" % c.warn) for mode, line, msg, code in c.log: if mode=="warning": out.write("

%s in line %d: %s

" % (mode, line, cgi.escape(msg))) return pisaDocument(out.getvalue(), dest, raise_exception=False) def pisaStory( src, path = None, link_callback = None, debug = 0, default_css = None, xhtml = False, encoding = None, c = None, xml_output = None, **kw): # Prepare Context if not c: c = pisaContext(path, debug=debug) c.pathCallback = link_callback # Use a default set of CSS definitions to get an expected output if default_css is None: default_css = DEFAULT_CSS # Parse and fill the story pisaParser(src, c, default_css, xhtml, encoding, xml_output) #if 0: # import reportlab.pdfbase.pdfmetrics as pm # pm.dumpFontData() # Avoid empty documents if not c.story: c.story = [Spacer(1,1)] # c.addPara(force=True) # Remove anchors if they do not exist (because of a bug in Reportlab) for frag, anchor in c.anchorFrag: if anchor not in c.anchorName: frag.link = None return c def pisaDocument( src, dest = None, path = None, link_callback = None, debug = 0, show_error_as_pdf = False, default_css = None, xhtml = False, encoding = None, xml_output = None, raise_exception = True, capacity = 100 * 1024, # -1, **kw): c = None if show_error_as_pdf: raise_exception = False try: log.debug("pisaDocument options:\n src = %r\n dest = %r\n path = %r\n link_callback = %r\n xhtml = %r", src, dest, path, link_callback, xhtml) # Prepare simple context c = pisaContext(path, debug=debug, capacity=capacity) c.pathCallback = link_callback if dest is None: dest = pisaTempFile(capacity=c.capacity) c.dest = dest # Build story c = pisaStory(src, path, link_callback, debug, default_css, xhtml, encoding, c=c, xml_output=xml_output) # Buffer PDF into memory out = pisaTempFile(capacity=c.capacity) doc = PmlBaseDoc( out, pagesize = c.pageSize, author = c.meta["author"].strip(), subject = c.meta["subject"].strip(), keywords = [x.strip() for x in c.meta["keywords"].strip().split(",") if x], title = c.meta["title"].strip(), showBoundary = 0, allowSplitting = 1) # XXX It is not possible to access PDF info, because it is private in canvas # doc.info.producer = "pisa " # Prepare templates and their frames if c.templateList.has_key("body"): body = c.templateList["body"] del c.templateList["body"] else: x, y, w, h = getBox("1cm 1cm -1cm -1cm", c.pageSize) body = PmlPageTemplate( id="body", frames=[ Frame(x, y, w, h, id = "body", leftPadding = 0, rightPadding = 0, bottomPadding = 0, topPadding = 0)], pagesize = c.pageSize) # print body.frames # print [body] + c.templateList.values() doc.addPageTemplates([body] + c.templateList.values()) # Use multibuild e.g. if a TOC has to be created if c.multiBuild: doc.multiBuild(c.story) else: doc.build(c.story) # Add watermarks if pyPdf: for bgouter in c.pisaBackgroundList: # If we have at least one background, then lets do it if bgouter: istream = out try: output = pyPdf.PdfFileWriter() input1 = pyPdf.PdfFileReader(istream) ctr = 0 for bg in c.pisaBackgroundList: page = input1.getPage(ctr) if bg and not bg.notFound() and (bg.mimetype=="application/pdf"): bginput = pyPdf.PdfFileReader(bg.getFile()) pagebg = bginput.getPage(0) pagebg.mergePage(page) page = pagebg else: log.warn(c.warning("Background PDF %s doesn't exist.", bg)) output.addPage(page) ctr += 1 out = pisaTempFile(capacity=c.capacity) output.write(out) # data = sout.getvalue() except Exception: log.exception(c.error("pyPDF error")) if raise_exception: raise # Found a background? So leave loop after first occurence break else: log.warn(c.warning("pyPDF not installed!")) # In web frameworks for debugging purposes maybe an output of # errors in a PDF is preferred if show_error_as_pdf and c and c.err: return pisaErrorDocument(c.dest, c) # Get the resulting PDF and write it to the file object # passed from the caller data = out.getvalue() c.dest.write(data) except: # log.exception(c.error("Document error")) log.exception("Document error") c.err += 1 if raise_exception: raise if raise_exception and c.err: raise Exception("Errors occured, please see log files for more informations") return c pisa-3.0.32/sx/pisa3/._pisa_default.py0000644000175000017500000000035111163201333015557 0ustar wmbwmbMac OS X  2ATTR97QQcom.apple.quarantineq/0000;49cba683;Safari.app;9AFF29BE-A1F8-4D2F-A543-8AC395074CD0|com.apple.Safaripisa-3.0.32/sx/pisa3/pisa.py0000644000175000017500000003364611200744635013664 0ustar wmbwmb# -*- coding: ISO-8859-1 -*- ############################################# ## (C)opyright by Dirk Holtwick, 2002-2007 ## ## All rights reserved ## ############################################# __reversion__ = "$Revision: 20 $" __author__ = "$Author: holtwick $" __date__ = "$Date: 2007-10-09 12:58:24 +0200 (Di, 09 Okt 2007) $" import getopt import sys import os import os.path import glob import urllib2 import urlparse import tempfile from pisa_version import * from pisa_document import * from pisa_util import getFile from pisa_default import DEFAULT_CSS import logging log = logging.getLogger("ho.pisa") __version__ = VERSION # Backward compatibility CreatePDF = pisaDocument USAGE = (VERSION_STR + """ USAGE: pisa [options] SRC [DEST] SRC Name of a HTML file or a file pattern using * placeholder. If you want to read from stdin use "-" as file name. You may also load an URL over HTTP. Take care of putting the in quotes if it contains characters like "?". DEST Name of the generated PDF file or "-" if you like to send the result to stdout. Take care that the destination file is not already opened by an other application like the Adobe Reader. If the destination is not writeable a similar name will be calculated automatically. [options] --base, -b: Specify a base path if input come via STDIN --css, -c: Path to default CSS file --css-dump: Dumps the default CSS definitions to STDOUT --debug, -d: Show debugging informations --encoding: the character encoding of SRC. If left empty (default) this information will be extracted from the HTML header data --help, -h: Show this help text --quiet, -q: Show no messages --start-viewer, -s: Start PDF default viewer on Windows and MacOSX (e.g. AcrobatReader) --version: Show version information --warn, -w: Show warnings --xml, --xhtml, -x: Force parsing in XML Mode (automatically used if file ends with ".xml") --html: Force parsing in HTML Mode (default) """).strip() COPYRIGHT = VERSION_STR LOG_FORMAT = "%(levelname)s [%(name)s] %(message)s" LOG_FORMAT_DEBUG = "%(levelname)s [%(name)s] %(pathname)s line %(lineno)d: %(message)s" #def options(): # from optparse import OptionParser # usage = "usage: %prog [options] arg" # description = """ # Converts HTML/XHTML/XML/CSS to PDF using the Reportlab Toolkit. # """.strip() # version = VERSION_STR # parser = OptionParser( # usage, # description=description, # version=version, # ) # parser.add_option( # "-c", "--css", # help="Path to default CSS file", # dest="css", # ) # parser.add_option("-q", "--quiet", # action="store_false", dest="verbose", default=True, # help="don't print status messages to stdout") # parser.set_defaults( # css=None, # ) # (options, args) = parser.parse_args() # if len(args) != 1: # parser.error("incorrect number of arguments") # # print options, args def usage(): print USAGE class pisaLinkLoader: """ Helper to load page from an URL and load corresponding files to temporary files. If getFileName is called it returns the temporary filename and takes care to delete it when pisaLinkLoader is unloaded. """ def __init__(self, src, quiet=True): self.quiet = quiet self.src = src self.tfileList = [] def __del__(self): for path in self.tfileList: # print "DELETE", path os.remove(path) def getFileName(self, name, relative=None): try: url = urlparse.urljoin(relative or self.src, name) path = urlparse.urlsplit(url)[2] suffix = "" if "." in path: new_suffix = "." + path.split(".")[-1].lower() if new_suffix in (".css", ".gif", ".jpg", ".png"): suffix = new_suffix path = tempfile.mktemp(prefix="pisa-", suffix = suffix) ufile = urllib2.urlopen(url) tfile = file(path, "wb") while True: data = ufile.read(1024) if not data: break # print data tfile.write(data) ufile.close() tfile.close() self.tfileList.append(path) if not self.quiet: print " Loading", url, "to", path return path except Exception, e: if not self.quiet: print " ERROR:", e log.exception("pisaLinkLoader.getFileName") return None def command(): if "--profile" in sys.argv: print "*** PROFILING ENABLED" import cProfile as profile import pstats prof = profile.Profile() prof.runcall(execute) pstats.Stats(prof).strip_dirs().sort_stats('cumulative').print_stats() # cProfile.run("execute()") else: execute() def execute(): # from optparse import OptionParser # # parser = OptionParser() # parser.add_option("-f", "--file", dest="filename", # help="write report to FILE", metavar="FILE") # parser.add_option("-q", "--quiet", # action="store_false", dest="verbose", default=True, # help="don't print status messages to stdout") # (options, args) = parser.parse_args() try: opts, args = getopt.getopt(sys.argv[1:], "dhqstwcxb", [ "quiet", "help", "start-viewer", "start", "debug=", "copyright", "version", "warn", #"booklet=", #"multivalent=", #"multivalent-path=", "tempdir=", "format=", "css=", "base=", "css-dump", "xml-dump", "xhtml", "xml", "html", "encoding=", "system", "profile", ]) except getopt.GetoptError: usage() sys.exit(2) errors = 0 startviewer = 0 quiet = 0 debug = 0 #multivalent_path = "" #booklet = "" tempdir = None format = "pdf" css = None xhtml = None encoding = None xml_output = None base_dir = None log_level = logging.ERROR log_format = LOG_FORMAT for o, a in opts: if o in ("-h", "--help"): # Hilfe anzeigen usage() sys.exit() if o in ("-s", "--start-viewer", "--start"): # Anzeigeprogramm starten startviewer = 1 if o in ("-q", "--quiet"): # Output unterdrcken quiet = 1 if o in ("-w", "--warn"): # Warnings log_level = min(log_level, logging.WARN) # If also -d ignore -w if o in ("-d", "--debug"): # Debug log_level = logging.DEBUG log_format = LOG_FORMAT_DEBUG # debug = 10 if a: log_level = int(a) # if o in ("--multivalent", "--multivalent-path"): # # Multivalent.jar fr Booklet # multivalent_path = a # if o in ("--booklet",): # # Booklet # booklet = a if o in ("--copyright", "--version"): print COPYRIGHT sys.exit(0) if o in ("--system",): print COPYRIGHT print print "SYSTEM INFORMATIONS" print "--------------------------------------------" print "OS: ", sys.platform print "Python: ", sys.version import html5lib print "html5lib: ", "?" import reportlab print "Reportlab: ", reportlab.Version #try: # import pyPdf # print "pyPdf: ", pyPdf.__version__ #except: # print "pyPdf: ","-" sys.exit(0) # if o in ("--tempdir",): # # Tempdir # tempdir = a if o in ("-t", "--format"): # Format XXX ??? format = a if o in ("-b","--base"): base_dir = a if o in ("--encoding",) and a: # Encoding encoding = a if o in ("-c", "--css"): # CSS # css = "@import url('%s');" % a css = file(a, "r").read() if o in ("--css-dump",): # CSS dump print DEFAULT_CSS return if o in ("--xml-dump",): xml_output = sys.stdout if o in ("-x", "--xml", "--xhtml"): xhtml = True elif o in ("--html",): xhtml = False if not quiet: try: logging.basicConfig( level=log_level, format=log_format) except: # XXX Logging doesn't work for Python 2.3 logging.basicConfig() if len(args) not in (1, 2): usage() sys.exit(2) if len(args)==2: a_src, a_dest = args else: a_src = args[0] a_dest = None if "*" in a_src: a_src = glob.glob(a_src) # print a_src else: a_src = [a_src] for src in a_src: # If not forced to parse in a special way have a look # at the filename suffix if xhtml is None: xhtml = src.lower().endswith(".xml") lc = None wpath = None if src=="-" or base_dir!=None: # Output to console fsrc = sys.stdin wpath = os.getcwd() if base_dir: wpath = base_dir else: # fsrc = open(src, "r") if src.startswith("http:") or src.startswith("https:"): wpath = src fsrc = getFile(src).getFile() # fsrc = urllib2.urlopen(src) # lc = pisaLinkLoader(src, quiet=quiet).getFileName src = "".join(urlparse.urlsplit(src)[1:3]).replace("/", "-") else: fsrc = wpath = os.path.abspath(src) fsrc = open(fsrc, "rb") if a_dest is None: dest_part = src if dest_part.lower().endswith(".html") or dest_part.lower().endswith(".htm"): dest_part = ".".join(src.split(".")[:-1]) dest = dest_part + "." + format.lower() for i in range(10): try: open(dest, "wb").close() break except: pass dest = dest_part + "-%d.%s" % (i, format.lower()) else: dest = a_dest fdestclose = 0 if dest=="-" or base_dir: if sys.platform == "win32": import msvcrt msvcrt.setmode(sys.stdout.fileno(), os.O_BINARY) fdest = sys.stdout startviewer = 0 else: dest = os.path.abspath(dest) try: open(dest, "wb").close() except: print "File '%s' seems to be in use of another application." % dest sys.exit(2) fdest = open(dest, "wb") fdestclose = 1 if not quiet: print "Converting %s to %s..." % (src, dest) try: pdf = pisaDocument( fsrc, fdest, debug = debug, path = wpath, errout = sys.stdout, #multivalent_path = multivalent_path, #booklet = booklet, tempdir = tempdir, format = format, link_callback = lc, default_css = css, xhtml = xhtml, encoding = encoding, xml_output = xml_output, ) if xml_output: xml_output.getvalue() if fdestclose: fdest.close() if (not errors) and startviewer: if not quiet: print "Open viewer for file %s" % dest startViewer(dest) except: if not quiet: print "*** ERRORS OCCURED" sys.exit(1) def startViewer(filename): " Helper for opening a PDF file" if filename: try: os.startfile(filename) except: # try to opan a la apple os.system('open "%s"' % filename) def showLogging(debug=False): " Shortcut for enabling log dump " try: log_level = logging.WARN log_format = LOG_FORMAT_DEBUG if debug: log_level = logging.DEBUG logging.basicConfig( level=log_level, format=log_format) except: logging.basicConfig() # Background informations in data URI here: # http://en.wikipedia.org/wiki/Data_URI_scheme def makeDataURI(data=None, mimetype=None, filename=None): import base64 if not mimetype: if filename: import mimetypes mimetype = mimetypes.guess_type(filename)[0].split(";")[0] else: raise Exception("You need to provide a mimetype or a filename for makeDataURI") return "data:" + mimetype + ";base64," + "".join(base64.encodestring(data).split()) def makeDataURIFromFile(filename): data = open(filename, "rb").read() return makeDataURI(data, filename=filename) if __name__=="__main__": command() pisa-3.0.32/sx/pisa3/._pisa_parser.py0000644000175000017500000000035111200026233015423 0ustar wmbwmbMac OS X  2ATTR9:QQcom.apple.quarantineq/0000;49cba683;Safari.app;9AFF29BE-A1F8-4D2F-A543-8AC395074CD0|com.apple.Safaripisa-3.0.32/sx/pisa3/pisa_util.py0000644000175000017500000006151211200743032014700 0ustar wmbwmb# -*- coding: ISO-8859-1 -*- ############################################# ## (C)opyright by Dirk Holtwick, 2002-2007 ## ## All rights reserved ## ############################################# __reversion__ = "$Revision: 20 $" __author__ = "$Author: holtwick $" __date__ = "$Date: 2007-10-09 12:58:24 +0200 (Di, 09 Okt 2007) $" from reportlab.lib.units import inch, cm from reportlab.lib.styles import * from reportlab.lib.enums import * from reportlab.lib.colors import * from reportlab.lib.pagesizes import * from reportlab.pdfbase import pdfmetrics # from reportlab.platypus import * # from reportlab.platypus.flowables import Flowable # from reportlab.platypus.tableofcontents import TableOfContents # from reportlab.platypus.para import Para, PageNumberObject, UNDERLINE, HotLink import reportlab import copy import types import os import os.path import pprint import sys import string import re import base64 import urlparse import mimetypes import urllib2 import urllib import httplib import tempfile import shutil rgb_re = re.compile("^.*?rgb[(]([0-9]+).*?([0-9]+).*?([0-9]+)[)].*?[ ]*$") if not(reportlab.Version[0] == "2" and reportlab.Version[2] >= "1"): raise ImportError("Reportlab Version 2.1+ is needed!") REPORTLAB22 = (reportlab.Version[0] == "2" and reportlab.Version[2] >= "2") # print "***", reportlab.Version, REPORTLAB22, reportlab.__file__ import logging log = logging.getLogger("ho.pisa") try: import cStringIO as StringIO except: import StringIO try: import pyPdf except: pyPdf = None try: from reportlab.graphics import renderPM except: renderPM = None try: from reportlab.graphics import renderSVG except: renderSVG = None def ErrorMsg(): """ Helper to get a nice traceback as string """ import traceback, sys, cgi type = value = tb = limit = None type, value, tb = sys.exc_info() list = traceback.format_tb(tb, limit) + traceback.format_exception_only(type, value) return "Traceback (innermost last):\n" + "%-20s %s" % ( string.join(list[: - 1], ""), list[ - 1]) def toList(value): if type(value) not in (types.ListType, types.TupleType): return [value] return list(value) def flatten(x): """flatten(sequence) -> list copied from http://kogs-www.informatik.uni-hamburg.de/~meine/python_tricks Returns a single, flat list which contains all elements retrieved from the sequence and all recursively contained sub-sequences (iterables). Examples: >>> [1, 2, [3,4], (5,6)] [1, 2, [3, 4], (5, 6)] >>> flatten([[[1,2,3], (42,None)], [4,5], [6], 7, MyVector(8,9,10)]) [1, 2, 3, 42, None, 4, 5, 6, 7, 8, 9, 10]""" result = [] for el in x: #if isinstance(el, (list, tuple)): if hasattr(el, "__iter__") and not isinstance(el, basestring): result.extend(flatten(el)) else: result.append(el) return result def _toColor(arg, default=None): '''try to map an arbitrary arg to a color instance''' if isinstance(arg, Color): return arg tArg = type(arg) if tArg in (types.ListType, types.TupleType): 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 tArg == types.StringType: C = getAllNamedColors() s = arg.lower() if C.has_key(s): return C[s] try: return toColor(eval(arg)) except: pass try: return HexColor(arg) except: if default is None: raise ValueError('Invalid color value %r' % arg) return default def getColor(value, default=None): " Convert to color value " try: original = value if isinstance(value, Color): return value value = str(value).strip().lower() if value == "transparent" or value == "none": return default if value in COLOR_BY_NAME: return COLOR_BY_NAME[value] if value.startswith("#") and len(value) == 4: value = "#" + value[1] + value[1] + value[2] + value[2] + value[3] + value[3] elif rgb_re.search(value): # e.g., value = "", go figure: r, g, b = [int(x) for x in rgb_re.search(value).groups()] value = "#%02x%02x%02x" % (r, g, b) else: # Shrug pass # XXX Throws illegal in 2.1 e.g. toColor('none'), # therefore we have a workaround here return _toColor(value) except ValueError, e: log.warn("Unknown color %r", original) return default def getBorderStyle(value, default=None): # log.debug(value) if value and (str(value).lower() not in ("none", "hidden")): return value return default mm = cm / 10.0 dpi96 = (1.0 / 96.0 * inch) _absoluteSizeTable = { "1": 50.0 / 100.0, "xx-small": 50.0 / 100.0, "x-small": 50.0 / 100.0, "2": 75.0 / 100.0, "small": 75.0 / 100.0, "3": 100.0 / 100.0, "medium": 100.0 / 100.0, "4": 125.0 / 100.0, "large": 125.0 / 100.0, "5": 150.0 / 100.0, "x-large": 150.0 / 100.0, "6": 175.0 / 100.0, "xx-large": 175.0 / 100.0, "7": 200.0 / 100.0, "xxx-large": 200.0 / 100.0, #"xx-small" : 3./5., #"x-small": 3./4., #"small": 8./9., #"medium": 1./1., #"large": 6./5., #"x-large": 3./2., #"xx-large": 2./1., #"xxx-large": 3./1., } _relativeSizeTable = { "larger": 1.25, "smaller": 0.75, "+4": 200.0 / 100.0, "+3": 175.0 / 100.0, "+2": 150.0 / 100.0, "+1": 125.0 / 100.0, "-1": 75.0 / 100.0, "-2": 50.0 / 100.0, "-3": 25.0 / 100.0, } MIN_FONT_SIZE = 1.0 def getSize(value, relative=0, base=None, default=0.0): """ Converts strings to standard sizes """ try: original = value if value is None: return relative elif type(value) is types.FloatType: return value elif type(value) is types.IntType: return float(value) elif type(value) in (types.TupleType, types.ListType): value = "".join(value) value = str(value).strip().lower().replace(",", ".") if value[ - 2:] == 'cm': return float(value[: - 2].strip()) * cm elif value[ - 2:] == 'mm': return (float(value[: - 2].strip()) * mm) # 1mm = 0.1cm elif value[ - 2:] == 'in': return float(value[: - 2].strip()) * inch # 1pt == 1/72inch elif value[ - 2:] == 'inch': return float(value[: - 4].strip()) * inch # 1pt == 1/72inch elif value[ - 2:] == 'pt': return float(value[: - 2].strip()) elif value[ - 2:] == 'pc': return float(value[: - 2].strip()) * 12.0 # 1pc == 12pt elif value[ - 2:] == 'px': return float(value[: - 2].strip()) * dpi96 # XXX W3C says, use 96pdi http://www.w3.org/TR/CSS21/syndata.html#length-units elif value[ - 1:] == 'i': # 1pt == 1/72inch return float(value[: - 1].strip()) * inch elif value in ("none", "0", "auto"): return 0.0 elif relative: if value[ - 2:] == 'em': # XXX return (float(value[: - 2].strip()) * relative) # 1em = 1 * fontSize elif value[ - 2:] == 'ex': # XXX return (float(value[: - 2].strip()) * (relative / 2.0)) # 1ex = 1/2 fontSize elif value[ - 1:] == '%': # print "%", value, relative, (relative * float(value[:-1].strip())) / 100.0 return (relative * float(value[: - 1].strip())) / 100.0 # 1% = (fontSize * 1) / 100 elif value in ("normal", "inherit"): return relative elif _relativeSizeTable.has_key(value): if base: return max(MIN_FONT_SIZE, base * _relativeSizeTable[value]) return max(MIN_FONT_SIZE, relative * _relativeSizeTable[value]) elif _absoluteSizeTable.has_key(value): if base: return max(MIN_FONT_SIZE, base * _absoluteSizeTable[value]) return max(MIN_FONT_SIZE, relative * _absoluteSizeTable[value]) try: value = float(value) except: log.warn("getSize: Not a float %r", value) return default #value = 0 return max(0, value) except Exception: log.warn("getSize %r %r", original, relative, exc_info=1) # print "ERROR getSize", repr(value), repr(value), e return default def getCoords(x, y, w, h, pagesize): """ As a stupid programmer I like to use the upper left corner of the document as the 0,0 coords therefore we need to do some fancy calculations """ #~ print pagesize ax, ay = pagesize if x < 0: x = ax + x if y < 0: y = ay + y if w != None and h != None: if w <= 0: w = (ax - x + w) if h <= 0: h = (ay - y + h) return x, (ay - y - h), w, h return x, (ay - y) def getBox(box, pagesize): """ Parse sizes by corners in the form: The last to values with negative values are interpreted as offsets form the right and lower border. """ box = str(box).split() if len(box) != 4: raise Exception, "box not defined right way" x, y, w, h = map(getSize, box) return getCoords(x, y, w, h, pagesize) def getPos(position, pagesize): """ Pair of coordinates """ position = str(position).split() if len(position) != 2: raise Exception, "position not defined right way" x, y = map(getSize, position) return getCoords(x, y, None, None, pagesize) def getBool(s): " Is it a boolean? " return str(s).lower() in ("y", "yes", "1", "true") _uid = 0 def getUID(): " Unique ID " global _uid _uid += 1 return str(_uid) _alignments = { "left": TA_LEFT, "center": TA_CENTER, "middle": TA_CENTER, "right": TA_RIGHT, "justify": TA_JUSTIFY, } def getAlign(value, default=TA_LEFT): return _alignments.get(str(value).lower(), default) #def getVAlign(value): # # Unused # return str(value).upper() class pisaTempFile(object): """A temporary file implementation that uses memory unless either capacity is breached or fileno is requested, at which point a real temporary file will be created and the relevant details returned If capacity is -1 the second strategy will never be used. Inspired by: http://code.activestate.com/recipes/496744/ """ STRATEGIES = ( StringIO.StringIO, tempfile.NamedTemporaryFile) CAPACITY = 10 * 1024 def __init__(self, buffer="", capacity=CAPACITY): """Creates a TempFile object containing the specified buffer. If capacity is specified, we use a real temporary file once the file gets larger than that size. Otherwise, the data is stored in memory. """ #if hasattr(buffer, "read"): #shutil.copyfileobj( fsrc, fdst[, length]) self.capacity = capacity self.strategy = int(len(buffer) > self.capacity) self._delegate = self.STRATEGIES[self.strategy]() self.write(buffer) def makeTempFile(self): " Switch to next startegy. If an error occured stay with the first strategy " if self.strategy == 0: try: new_delegate = self.STRATEGIES[1]() new_delegate.write(self.getvalue()) self._delegate = new_delegate self.strategy = 1 log.warn("Created temporary file %s", self.name) except: self.capacity = - 1 def getFileName(self): " Get a named temporary file " self.makeTempFile() return self.name def fileno(self): """Forces this buffer to use a temporary file as the underlying. object and returns the fileno associated with it. """ self.makeTempFile() return self._delegate.fileno() def getvalue(self): " Get value of file. Work around for second strategy " if self.strategy == 0: return self._delegate.getvalue() self._delegate.flush() self._delegate.seek(0) return self._delegate.read() def write(self, value): " If capacity != -1 and length of file > capacity it is time to switch " if self.capacity > 0 and self.strategy == 0: len_value = len(value) if len_value >= self.capacity: needs_new_strategy = True else: self.seek(0, 2) # find end of file needs_new_strategy = \ (self.tell() + len_value) >= self.capacity if needs_new_strategy: self.makeTempFile() self._delegate.write(value) def __getattr__(self, name): try: return getattr(self._delegate, name) except AttributeError: # hide the delegation e = "object '%s' has no attribute '%s'" \ % (self.__class__.__name__, name) raise AttributeError(e) _rx_datauri = re.compile("^data:(?P[a-z]+/[a-z]+);base64,(?P.*)$", re.M | re.DOTALL) class pisaFileObject: """ XXX """ def __init__(self, uri, basepath=None): self.basepath = basepath self.mimetype = None self.file = None self.data = None self.uri = None self.local = None self.tmp_file = None uri = str(uri) log.debug("FileObject %r, Basepath: %r", uri, basepath) # Data URI if uri.startswith("data:"): m = _rx_datauri.match(uri) self.mimetype = m.group("mime") self.data = base64.decodestring(m.group("data")) else: # Check if we have an external scheme if basepath and not (uri.startswith("http://") or uri.startswith("https://")): urlParts = urlparse.urlparse(basepath) else: urlParts = urlparse.urlparse(uri) log.debug("URLParts: %r", urlParts) # Drive letters have len==1 but we are looking for things like http: if len(urlParts[0]) > 1 : # External data if basepath: uri = urlparse.urljoin(basepath, uri) #path = urlparse.urlsplit(url)[2] #mimetype = getMimeType(path) # Using HTTPLIB server, path = urllib.splithost(uri[uri.find("//"):]) if uri.startswith("https://"): conn = httplib.HTTPSConnection(server) else: conn = httplib.HTTPConnection(server) conn.request("GET", path) r1 = conn.getresponse() # log.debug("HTTP %r %r %r %r", server, path, uri, r1) if (r1.status, r1.reason) == (200, "OK"): # data = r1.read() self.mimetype = r1.getheader("Content-Type", None).split(";")[0] self.uri = uri if r1.getheader("content-encoding") == "gzip": # zbuf = cStringIO.StringIO(data) import gzip self.file = gzip.GzipFile(mode="rb", fileobj=r1) #data = zfile.read() #zfile.close() else: self.file = r1 # self.file = urlResponse else: urlResponse = urllib2.urlopen(uri) self.mimetype = urlResponse.info().get("Content-Type", None).split(";")[0] self.uri = urlResponse.geturl() self.file = urlResponse else: # Local data if basepath: uri = os.path.normpath(os.path.join(basepath, uri)) if os.path.isfile(uri): self.uri = uri self.local = uri self.setMimeTypeByName(uri) self.file = open(uri, "rb") def getFile(self): if self.file is not None: return self.file if self.data is not None: return pisaTempFile(self.data) return None def getNamedFile(self): if self.notFound(): return None if self.local: return str(self.local) if not self.tmp_file: self.tmp_file = tempfile.NamedTemporaryFile() if self.file: shutil.copyfileobj(self.file, self.tmp_file) else: self.tmp_file.write(self.getData()) self.tmp_file.flush() return self.tmp_file.name def getData(self): if self.data is not None: return self.data if self.file is not None: self.data = self.file.read() return self.data return None def notFound(self): return (self.file is None) and (self.data is None) def setMimeTypeByName(self, name): " Guess the mime type " mimetype = mimetypes.guess_type(name)[0] if mimetype is not None: self.mimetype = mimetypes.guess_type(name)[0].split(";")[0] def getFile(*a , **kw): file = pisaFileObject(*a, **kw) if file.notFound(): return None return file COLOR_BY_NAME = { 'activeborder': Color(212, 208, 200), 'activecaption': Color(10, 36, 106), 'aliceblue': Color(.941176, .972549, 1), 'antiquewhite': Color(.980392, .921569, .843137), 'appworkspace': Color(128, 128, 128), 'aqua': Color(0, 1, 1), 'aquamarine': Color(.498039, 1, .831373), 'azure': Color(.941176, 1, 1), 'background': Color(58, 110, 165), 'beige': Color(.960784, .960784, .862745), 'bisque': Color(1, .894118, .768627), 'black': Color(0, 0, 0), 'blanchedalmond': Color(1, .921569, .803922), 'blue': Color(0, 0, 1), 'blueviolet': Color(.541176, .168627, .886275), 'brown': Color(.647059, .164706, .164706), 'burlywood': Color(.870588, .721569, .529412), 'buttonface': Color(212, 208, 200), 'buttonhighlight': Color(255, 255, 255), 'buttonshadow': Color(128, 128, 128), 'buttontext': Color(0, 0, 0), 'cadetblue': Color(.372549, .619608, .627451), 'captiontext': Color(255, 255, 255), 'chartreuse': Color(.498039, 1, 0), 'chocolate': Color(.823529, .411765, .117647), 'coral': Color(1, .498039, .313725), 'cornflowerblue': Color(.392157, .584314, .929412), 'cornsilk': Color(1, .972549, .862745), 'crimson': Color(.862745, .078431, .235294), 'cyan': Color(0, 1, 1), 'darkblue': Color(0, 0, .545098), 'darkcyan': Color(0, .545098, .545098), 'darkgoldenrod': Color(.721569, .52549, .043137), 'darkgray': Color(.662745, .662745, .662745), 'darkgreen': Color(0, .392157, 0), 'darkgrey': Color(.662745, .662745, .662745), 'darkkhaki': Color(.741176, .717647, .419608), 'darkmagenta': Color(.545098, 0, .545098), 'darkolivegreen': Color(.333333, .419608, .184314), 'darkorange': Color(1, .54902, 0), 'darkorchid': Color(.6, .196078, .8), 'darkred': Color(.545098, 0, 0), 'darksalmon': Color(.913725, .588235, .478431), 'darkseagreen': Color(.560784, .737255, .560784), 'darkslateblue': Color(.282353, .239216, .545098), 'darkslategray': Color(.184314, .309804, .309804), 'darkslategrey': Color(.184314, .309804, .309804), 'darkturquoise': Color(0, .807843, .819608), 'darkviolet': Color(.580392, 0, .827451), 'deeppink': Color(1, .078431, .576471), 'deepskyblue': Color(0, .74902, 1), 'dimgray': Color(.411765, .411765, .411765), 'dimgrey': Color(.411765, .411765, .411765), 'dodgerblue': Color(.117647, .564706, 1), 'firebrick': Color(.698039, .133333, .133333), 'floralwhite': Color(1, .980392, .941176), 'forestgreen': Color(.133333, .545098, .133333), 'fuchsia': Color(1, 0, 1), 'gainsboro': Color(.862745, .862745, .862745), 'ghostwhite': Color(.972549, .972549, 1), 'gold': Color(1, .843137, 0), 'goldenrod': Color(.854902, .647059, .12549), 'gray': Color(.501961, .501961, .501961), 'graytext': Color(128, 128, 128), 'green': Color(0, .501961, 0), 'greenyellow': Color(.678431, 1, .184314), 'grey': Color(.501961, .501961, .501961), 'highlight': Color(10, 36, 106), 'highlighttext': Color(255, 255, 255), 'honeydew': Color(.941176, 1, .941176), 'hotpink': Color(1, .411765, .705882), 'inactiveborder': Color(212, 208, 200), 'inactivecaption': Color(128, 128, 128), 'inactivecaptiontext': Color(212, 208, 200), 'indianred': Color(.803922, .360784, .360784), 'indigo': Color(.294118, 0, .509804), 'infobackground': Color(255, 255, 225), 'infotext': Color(0, 0, 0), 'ivory': Color(1, 1, .941176), 'khaki': Color(.941176, .901961, .54902), 'lavender': Color(.901961, .901961, .980392), 'lavenderblush': Color(1, .941176, .960784), 'lawngreen': Color(.486275, .988235, 0), 'lemonchiffon': Color(1, .980392, .803922), 'lightblue': Color(.678431, .847059, .901961), 'lightcoral': Color(.941176, .501961, .501961), 'lightcyan': Color(.878431, 1, 1), 'lightgoldenrodyellow': Color(.980392, .980392, .823529), 'lightgray': Color(.827451, .827451, .827451), 'lightgreen': Color(.564706, .933333, .564706), 'lightgrey': Color(.827451, .827451, .827451), 'lightpink': Color(1, .713725, .756863), 'lightsalmon': Color(1, .627451, .478431), 'lightseagreen': Color(.12549, .698039, .666667), 'lightskyblue': Color(.529412, .807843, .980392), 'lightslategray': Color(.466667, .533333, .6), 'lightslategrey': Color(.466667, .533333, .6), 'lightsteelblue': Color(.690196, .768627, .870588), 'lightyellow': Color(1, 1, .878431), 'lime': Color(0, 1, 0), 'limegreen': Color(.196078, .803922, .196078), 'linen': Color(.980392, .941176, .901961), 'magenta': Color(1, 0, 1), 'maroon': Color(.501961, 0, 0), 'mediumaquamarine': Color(.4, .803922, .666667), 'mediumblue': Color(0, 0, .803922), 'mediumorchid': Color(.729412, .333333, .827451), 'mediumpurple': Color(.576471, .439216, .858824), 'mediumseagreen': Color(.235294, .701961, .443137), 'mediumslateblue': Color(.482353, .407843, .933333), 'mediumspringgreen': Color(0, .980392, .603922), 'mediumturquoise': Color(.282353, .819608, .8), 'mediumvioletred': Color(.780392, .082353, .521569), 'menu': Color(212, 208, 200), 'menutext': Color(0, 0, 0), 'midnightblue': Color(.098039, .098039, .439216), 'mintcream': Color(.960784, 1, .980392), 'mistyrose': Color(1, .894118, .882353), 'moccasin': Color(1, .894118, .709804), 'navajowhite': Color(1, .870588, .678431), 'navy': Color(0, 0, .501961), 'oldlace': Color(.992157, .960784, .901961), 'olive': Color(.501961, .501961, 0), 'olivedrab': Color(.419608, .556863, .137255), 'orange': Color(1, .647059, 0), 'orangered': Color(1, .270588, 0), 'orchid': Color(.854902, .439216, .839216), 'palegoldenrod': Color(.933333, .909804, .666667), 'palegreen': Color(.596078, .984314, .596078), 'paleturquoise': Color(.686275, .933333, .933333), 'palevioletred': Color(.858824, .439216, .576471), 'papayawhip': Color(1, .937255, .835294), 'peachpuff': Color(1, .854902, .72549), 'peru': Color(.803922, .521569, .247059), 'pink': Color(1, .752941, .796078), 'plum': Color(.866667, .627451, .866667), 'powderblue': Color(.690196, .878431, .901961), 'purple': Color(.501961, 0, .501961), 'red': Color(1, 0, 0), 'rosybrown': Color(.737255, .560784, .560784), 'royalblue': Color(.254902, .411765, .882353), 'saddlebrown': Color(.545098, .270588, .07451), 'salmon': Color(.980392, .501961, .447059), 'sandybrown': Color(.956863, .643137, .376471), 'scrollbar': Color(212, 208, 200), 'seagreen': Color(.180392, .545098, .341176), 'seashell': Color(1, .960784, .933333), 'sienna': Color(.627451, .321569, .176471), 'silver': Color(.752941, .752941, .752941), 'skyblue': Color(.529412, .807843, .921569), 'slateblue': Color(.415686, .352941, .803922), 'slategray': Color(.439216, .501961, .564706), 'slategrey': Color(.439216, .501961, .564706), 'snow': Color(1, .980392, .980392), 'springgreen': Color(0, 1, .498039), 'steelblue': Color(.27451, .509804, .705882), 'tan': Color(.823529, .705882, .54902), 'teal': Color(0, .501961, .501961), 'thistle': Color(.847059, .74902, .847059), 'threeddarkshadow': Color(64, 64, 64), 'threedface': Color(212, 208, 200), 'threedhighlight': Color(255, 255, 255), 'threedlightshadow': Color(212, 208, 200), 'threedshadow': Color(128, 128, 128), 'tomato': Color(1, .388235, .278431), 'turquoise': Color(.25098, .878431, .815686), 'violet': Color(.933333, .509804, .933333), 'wheat': Color(.960784, .870588, .701961), 'white': Color(1, 1, 1), 'whitesmoke': Color(.960784, .960784, .960784), 'window': Color(255, 255, 255), 'windowframe': Color(0, 0, 0), 'windowtext': Color(0, 0, 0), 'yellow': Color(1, 1, 0), 'yellowgreen': Color(.603922, .803922, .196078)} pisa-3.0.32/sx/pisa3/._pisa_wsgi.py0000644000175000017500000000035111103556730015114 0ustar wmbwmbMac OS X  2ATTR9BQQcom.apple.quarantineq/0000;49cba683;Safari.app;9AFF29BE-A1F8-4D2F-A543-8AC395074CD0|com.apple.Safaripisa-3.0.32/sx/pisa3/._reportlab_paragraph.py0000644000175000017500000000035111164071226017145 0ustar wmbwmbMac OS X  2ATTR9DQQcom.apple.quarantineq/0000;49cba683;Safari.app;9AFF29BE-A1F8-4D2F-A543-8AC395074CD0|com.apple.Safaripisa-3.0.32/sx/pisa3/._pisa_version.py0000644000175000017500000000035111177602650015634 0ustar wmbwmbMac OS X  2ATTR9AQQcom.apple.quarantineq/0000;49cba683;Safari.app;9AFF29BE-A1F8-4D2F-A543-8AC395074CD0|com.apple.Safaripisa-3.0.32/sx/pisa3/._pisa_context.py0000644000175000017500000000035111200742635015626 0ustar wmbwmbMac OS X  2ATTR96QQcom.apple.quarantineq/0000;49cba683;Safari.app;9AFF29BE-A1F8-4D2F-A543-8AC395074CD0|com.apple.Safaripisa-3.0.32/sx/pisa3/.___init__.py0000644000175000017500000000035111114712635014666 0ustar wmbwmbMac OS X  2ATTR95QQcom.apple.quarantineq/0000;49cba683;Safari.app;9AFF29BE-A1F8-4D2F-A543-8AC395074CD0|com.apple.Safaripisa-3.0.32/sx/pisa3/._pisa_paragraph2.py0000644000175000017500000000035111111257634016172 0ustar wmbwmbMac OS X  2ATTR94QQcom.apple.quarantineq/0000;49cba683;Safari.app;9AFF29BE-A1F8-4D2F-A543-8AC395074CD0|com.apple.Safaripisa-3.0.32/sx/pisa3/._pisa.py0000644000175000017500000000035111200744635014064 0ustar wmbwmbMac OS X  2ATTR9CQQcom.apple.quarantineq/0000;49cba683;Safari.app;9AFF29BE-A1F8-4D2F-A543-8AC395074CD0|com.apple.Safaripisa-3.0.32/sx/pisa3/pisa_version.py0000644000175000017500000000122011177602650015413 0ustar wmbwmb# -*- coding: ISO-8859-1 -*- ############################################# ## (C)opyright by Dirk Holtwick, 2002-2008 ## ## All rights reserved ## ############################################# __reversion__ = "$Revision: 247 $" __author__ = "$Author: holtwick $" __date__ = "$Date: 2008-08-15 13:37:57 +0200 (Fr, 15 Aug 2008) $" __version__ = VERSION = "VERSION{3.0.32}VERSION"[8:-8] __build__ = BUILD = "BUILD{2009-05-04}BUILD"[6:-6] VERSION_STR = "pisa %s (Build %s)\n(C) 2002-2009 Dirk Holtwick , Germany\nWebsite http://www.xhtml2pdf.com" % ( VERSION, BUILD, ) pisa-3.0.32/sx/pisa3/pisa_paragraph.py0000644000175000017500000005651611200743305015703 0ustar wmbwmb#!/bin/env/python # -*- coding: utf-8 -*- """ A paragraph class to be used with ReportLab Platypus. TODO ==== - Bullets - Weblinks and internal links - Borders and margins (Box) - Underline, Background, Strike - Images - Hyphenation + Alignment + Breakline, empty lines + TextIndent - Sub and super """ from reportlab.lib.enums import TA_CENTER, TA_JUSTIFY, TA_LEFT, TA_RIGHT from reportlab.pdfbase.pdfmetrics import stringWidth from reportlab.platypus.flowables import Flowable from reportlab.lib.colors import Color class Style(dict): """ Style. Single place for style definitions: Paragraphs and Fragments. The naming follows the convention of CSS written in camelCase letters. """ DEFAULT = { "textAlign": TA_LEFT, "textIndent": 0.0, "width": None, "height": None, "fontName": "Times-Roman", "fontSize": 10.0, "color": Color(0, 0, 0), "lineHeight": 1.5, "lineHeightAbsolute": None, "pdfLineSpacing": 0, "link": None, } def __init__(self, **kw): self.update(self.DEFAULT) self.update(kw) self.spaceBefore = 0 self.spaceAfter = 0 self.keepWithNext = False class Box(dict): """ Box. Handles the following styles: backgroundColor, backgroundImage paddingLeft, paddingRight, paddingTop, paddingBottom marginLeft, marginRight, marginTop, marginBottom borderLeftColor, borderLeftWidth, borderLeftStyle borderRightColor, borderRightWidth, borderRightStyle borderTopColor, borderTopWidth, borderTopStyle borderBottomColor, borderBottomWidth, borderBottomStyle Not used in inline Elements: paddingTop, paddingBottom marginTop, marginBottom """ name = "box" def drawBox(self, canvas, x, y, w, h): canvas.saveState() # Background bg = self.get("backgroundColor", None) if bg is not None: # draw a filled rectangle (with no stroke) using bg color canvas.setFillColor(bg) canvas.rect(x, y, w, h, fill=1, stroke=0) # Borders def _drawBorderLine(bstyle, width, color, x1, y1, x2, y2): # We need width and border style to be able to draw a border if width and bstyle: # If no color for border is given, the text color is used (like defined by W3C) if color is None: color = self.get("textColor", Color(0, 0, 0)) # print "Border", bstyle, width, color if color is not None: canvas.setStrokeColor(color) canvas.setLineWidth(width) canvas.line(x1, y1, x2, y2) _drawBorderLine(self.get("borderLeftStyle", None), self.get("borderLeftWidth", None), self.get("borderLeftColor", None), x, y, x, y + h) _drawBorderLine(self.get("borderRightStyle", None), self.get("borderRightWidth", None), self.get("borderRightColor", None), x + w, y, x + w, y + h) _drawBorderLine(self.get("borderTopStyle", None), self.get("borderTopWidth", None), self.get("borderTopColor", None), x, y + h, x + w, y + h) _drawBorderLine(self.get("borderBottomStyle", None), self.get("borderBottomWidth", None), self.get("borderBottomColor", None), x, y, x + w, y) canvas.restoreState() class Fragment(Box): """ Fragment. text: String containing text fontName: fontSize: width: Width of string height: Height of string """ name = "fragment" isSoft = False isText = False isLF = False def calc(self): self["width"] = 0 class Word(Fragment): " A single word. " name = "word" isText = True def calc(self): """ XXX Cache stringWith if not accelerated?! """ self["width"] = stringWidth(self["text"], self["fontName"], self["fontSize"]) class Space(Fragment): """ A space between fragments that is the usual place for line breaking. """ name = "space" isSoft = True def calc(self): self["width"] = stringWidth(" ", self["fontName"], self["fontSize"]) class LineBreak(Fragment): " Line break. " name = "br" isSoft = True isLF = True pass class BoxBegin(Fragment): name = "begin" def calc(self): self["width"] = self.get("marginLeft", 0) + self.get("paddingLeft", 0) # + border if border def draw(self, canvas, y): # if not self["length"]: x = self.get("marginLeft", 0) + self["x"] w = self["length"] + self.get("paddingRight", 0) h = self["fontSize"] self.drawBox(canvas, x, y, w, h) class BoxEnd(Fragment): name = "end" def calc(self): self["width"] = self.get("marginRight", 0) + self.get("paddingRight", 0) # + border class Image(Fragment): name = "image" pass class Line(list): """ Container for line fragments. """ LINEHEIGHT = 1.0 def __init__(self, style): self.width = 0 self.height = 0 self.isLast = False self.style = style self.boxStack = [] list.__init__(self) def doAlignment(self, width, alignment): # Apply alignment if alignment != TA_LEFT: lineWidth = self[ - 1]["x"] + self[ - 1]["width"] emptySpace = width - lineWidth if alignment == TA_RIGHT: for j, frag in enumerate(self): frag["x"] += emptySpace elif alignment == TA_CENTER: for j, frag in enumerate(self): frag["x"] += emptySpace / 2.0 elif alignment == TA_JUSTIFY and not self.isLast: # XXX last line before split delta = emptySpace / (len(self) - 1) for j, frag in enumerate(self): frag["x"] += j * delta # Boxes for frag in self: x = frag["x"] + frag["width"] # print "***", x, frag["x"] if isinstance(frag, BoxBegin): self.boxStack.append(frag) elif isinstance(frag, BoxEnd): if self.boxStack: frag = self.boxStack.pop() frag["length"] = x - frag["x"] # Handle the rest for frag in self.boxStack: print "***", x, frag["x"] frag["length"] = x - frag["x"] def doLayout(self, width): "Align words in previous line." # Calculate dimensions self.width = width self.height = self.lineHeight = max(frag.get("fontSize" , 0) * self.LINEHEIGHT for frag in self) # Apply line height self.fontSize = max(frag.get("fontSize" , 0) for frag in self) y = (self.lineHeight - self.fontSize) # / 2 for frag in self: frag["y"] = y return self.height def dumpFragments(self): print "Line", 40*"-" for frag in self: print "%s" % frag.get("text", frag.name.upper()), print class Group(list): pass class Text(list): """ Container for text fragments. Helper functions for splitting text into lines and calculating sizes and positions. """ def __init__(self, data=[], style=None): #self.groups = [] self.lines = [] self.width = 0 self.height = 0 self.maxWidth = 0 self.maxHeight = 0 self.style = style list.__init__(self, data) def calc(self): """ Calculate sizes of fragments. """ #pos = 0 #while #whi #group = Group() #gWidth = 0 #for frag in self: # width = frag.calc() # if frag.isSoft: # group.width = gWidth # self.groups.append(group) # self. # gWidth += width [word.calc() for word in self] def splitIntoLines(self, maxWidth, maxHeight, splitted=False): """ Split text into lines and calculate X positions. If we need more space in height than available we return the rest of the text """ self.lines = [] self.height = 0 self.maxWidth = self.width = maxWidth self.maxHeight = maxHeight boxStack = [] style = self.style x = 0 # Start with indent in first line of text if not splitted: x = style["textIndent"] lenText = len(self) pos = 0 while pos < lenText: # Reset values for new line posBegin = pos posSpace = pos line = Line(style) # Update boxes for next line for box in copy.copy(boxStack): box["x"] = 0 line.append(BoxBegin(box)) while pos < lenText: # Get fragment, its width and set X frag = self[pos] fragWidth = frag["width"] frag["x"] = x pos += 1 # Keep in mind boxes for next lines if isinstance(frag, BoxBegin): boxStack.append(frag) elif isinstance(frag, BoxEnd): boxStack.pop() # If space or linebreak handle special way if frag.isSoft: if frag.isLF: posSpace = pos line.append(frag) break # First element of line should not be a space if x == 0: continue # Keep in mind last possible line break posSpace = pos - 1 # The elements exceed the current line elif (fragWidth + x > maxWidth): break # Add fragment to line and update x x += fragWidth line.append(frag) # Remove until last soft item #if (posSpace < pos) and (posSpace > posBegin): # print "Remove", line[::-(posSpace - posBegin)] # del line[::-(posSpace - posBegin)] # pos = posSpace # Remove trailing white spaces while line and line[-1].name in ("space", "br"): # print "Pop", line.pop() # Add line to list line.dumpFragments() # if line: self.height += line.doLayout(self.width) self.lines.append(line) # If not enough space for current line force to split if self.height > maxHeight: return posBegin # Reset variables x = 0 # Apply alignment self.lines[ - 1].isLast = True [line.doAlignment(maxWidth, style["textAlign"]) for line in self.lines] return None def dumpLines(self): """ For debugging dump all line and their content """ i = 0 for line in self.lines: print "Line %d:" % i, line.dumpFragments() i += 1 class Paragraph(Flowable): """A simple Paragraph class respecting alignment. Does text without tags. Respects only the following global style attributes: fontName, fontSize, leading, firstLineIndent, leftIndent, rightIndent, textColor, alignment. (spaceBefore, spaceAfter are handled by the Platypus framework.) """ def __init__(self, text, style, debug=False, splitted=False, **kwDict): Flowable.__init__(self) # self._showBoundary = True self.text = text self.text.calc() self.style = style self.text.style = style self.debug = debug self.splitted = splitted # More attributes for k, v in kwDict.items(): setattr(self, k, v) # set later... self.splitIndex = None # overwritten methods from Flowable class def wrap(self, availWidth, availHeight): "Determine the rectangle this paragraph really needs." # memorize available space self.avWidth = availWidth self.avHeight = availHeight if self.debug: print "*** wrap (%f, %f)" % (availWidth, availHeight) if not self.text: if self.debug: print "*** wrap (%f, %f) needed" % (0, 0) return 0, 0 style = self.style # Split lines width = availWidth # - style.leftIndent - style.rightIndent self.splitIndex = self.text.splitIntoLines(width, availHeight) self.width, self.height = availWidth, self.text.height if self.debug: print "*** wrap (%f, %f) needed, splitIndex %r" % (self.width, self.height, self.splitIndex) return self.width, self.height #def visitFirstParagraph(self, para): # return para #def visitOtherParagraph(self, para): # return para def split(self, availWidth, availHeight): "Split ourself in two paragraphs." if self.debug: print "*** split (%f, %f)" % (availWidth, availHeight) splitted = [] if self.splitIndex: text1 = self.text[:self.splitIndex] text2 = self.text[self.splitIndex:] p1 = Paragraph(Text(text1), self.style, debug=self.debug) p2 = Paragraph(Text(text2), self.style, debug=self.debug, splitted=True) splitted = [p1, p2] if self.debug: print "*** text1 %s / text %s" % (len(text1), len(text2)) if self.debug: print '*** return %s' % self.splitted return splitted def draw(self): "Render the content of the paragraph." if self.debug: print "*** draw" if not self.text: return canvas = self.canv style = self.style canvas.saveState() # Draw box arround paragraph for debugging if self.debug: bw = 0.5 bc = Color(1, 1, 0) bg = Color(0.9, 0.9, 0.9) canvas.setStrokeColor(bc) canvas.setLineWidth(bw) canvas.setFillColor(bg) canvas.rect( style.leftIndent, 0, self.width, self.height, fill=1, stroke=1) y = 0 dy = self.height for line in self.text.lines: y += line.height for frag in line: # Box if hasattr(frag, "draw"): frag.draw(canvas, dy - y) # Text if frag.get("text", ""): canvas.setFont(frag["fontName"], frag["fontSize"]) canvas.setFillColor(frag.get("color", style["color"])) canvas.drawString(frag["x"], dy - y + frag["y"], frag["text"]) # XXX LINK link = frag.get("link", None) if link: _scheme_re = re.compile('^[a-zA-Z][-+a-zA-Z0-9]+$') x, y, w, h = frag["x"], dy - y, frag["width"], frag["fontSize"] rect = (x, y, w, h) if isinstance(link, unicode): link = link.encode('utf8') parts = link.split(':', 1) scheme = len(parts) == 2 and parts[0].lower() or '' if _scheme_re.match(scheme) and scheme != 'document': kind = scheme.lower() == 'pdf' and 'GoToR' or 'URI' if kind == 'GoToR': link = parts[1] # tx._canvas.linkURL(link, rect, relative=1, kind=kind) canvas.linkURL(link, rect, relative=1, kind=kind) else: if link[0] == '#': link = link[1:] scheme = '' canvas.linkRect("", scheme != 'document' and link or parts[1], rect, relative=1) canvas.restoreState() if __name__ == "__main__": from reportlab.platypus import SimpleDocTemplate from reportlab.lib.styles import * from reportlab.rl_config import * from reportlab.lib.units import * import os import copy import re import pprint styles = getSampleStyleSheet() ALIGNMENTS = (TA_LEFT, TA_RIGHT, TA_CENTER, TA_JUSTIFY) TEXT = """ Lörem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum. Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum. Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. """.strip() def textGenerator(data, fn, fs): i = 1 for word in re.split('\s+', data): if word: yield Word( text="[%d|%s]" % (i, word), fontName=fn, fontSize=fs ) yield Space( fontName=fn, fontSize=fs ) def createText(data, fn, fs): text = Text(list(textGenerator(data, fn, fs))) return text def makeBorder(width, style="solid", color=Color(1, 0, 0)): return dict( borderLeftColor=color, borderLeftWidth=width, borderLeftStyle=style, borderRightColor=color, borderRightWidth=width, borderRightStyle=style, borderTopColor=color, borderTopWidth=width, borderTopStyle=style, borderBottomColor=color, borderBottomWidth=width, borderBottomStyle=style ) def test(): doc = SimpleDocTemplate("test.pdf") story = [] style = Style(fontName="Helvetica", textIndent=24.0) fn = style["fontName"] fs = style["fontSize"] sampleText1 = createText(TEXT[:100], fn, fs) sampleText2 = createText(TEXT[100:], fn, fs) text = Text(sampleText1 + [ Space( fontName=fn, fontSize=fs), Word( text="TrennbarTrennbar", pairs=[("Trenn-", "barTrennbar")], fontName=fn, fontSize=fs), Space( fontName=fn, fontSize=fs), Word( text="Normal", color=Color(1, 0, 0), fontName=fn, fontSize=fs), Space( fontName=fn, fontSize=fs), Word( text="gGrößer", fontName=fn, fontSize=fs * 1.5), Space( fontName=fn, fontSize=fs), Word( text="Bold", fontName="Times-Bold", fontSize=fs), Space( fontName=fn, fontSize=fs), Word( text="jItalic", fontName="Times-Italic", fontSize=fs), Space( fontName=fn, fontSize=fs), # ipsum # Lorem ipsum Lorem BoxBegin( fontName=fn, fontSize=fs, **makeBorder(0.5, "solid", Color(0, 1, 0))), Word( text="Lorem", fontName="Times-Bold", fontSize=fs), Word( text="Lorem", fontName=fn, fontSize=fs), Word( text="Lorem", fontName=fn, fontSize=fs), Word( text="Lorem", fontName=fn, fontSize=fs), Word( text="Lorem", fontName=fn, fontSize=fs), Word( text="Lorem", fontName=fn, fontSize=fs), Word( text="Lorem", fontName=fn, fontSize=fs), Word( text="Lorem", fontName=fn, fontSize=fs), Word( text="Lorem", fontName=fn, fontSize=fs), Word( text="Lorem", fontName="Times-Bold", fontSize=fs), Space( fontName=fn, fontSize=fs), Word( text="Lorem", fontName=fn, fontSize=fs), Space( fontName=fn, fontSize=fs), Word( text="Lorem", fontName=fn, fontSize=fs), Space( fontName=fn, fontSize=fs), Word( text="Lorem", fontName=fn, fontSize=fs), Space( fontName=fn, fontSize=fs), BoxBegin( fontName=fn, fontSize=fs, backgroundColor=Color(1, 1, 0), **makeBorder(1, "solid", Color(1, 0, 0))), Word( text="Lorem", fontName=fn, fontSize=fs), BoxEnd(), Space( fontName=fn, fontSize=fs), Word( text="Lorem", fontName=fn, fontSize=fs), Space( fontName=fn, fontSize=fs), BoxEnd(), LineBreak( fontName=fn, fontSize=fs), LineBreak( fontName=fn, fontSize=fs), ] + sampleText2) story.append(Paragraph( copy.copy(text), style, debug=0)) for i in range(10): style = copy.deepcopy(style) style["textAlign"] = ALIGNMENTS[i % 4] text = createText(("(%d) " % i) + TEXT, fn, fs) story.append(Paragraph( copy.copy(text), style, debug=0)) doc.build(story) test() os.system("start test.pdf") # createText(TEXT, styles["Normal"].fontName, styles["Normal"].fontSize) pisa-3.0.32/sx/pisa3/._pisa_util.py0000644000175000017500000000035111200743032015107 0ustar wmbwmbMac OS X  2ATTR9@QQcom.apple.quarantineq/0000;49cba683;Safari.app;9AFF29BE-A1F8-4D2F-A543-8AC395074CD0|com.apple.Safaripisa-3.0.32/sx/pisa3/pisa_context.py0000644000175000017500000012011411200742635015411 0ustar wmbwmb# -*- coding: utf-8 -*- ############################################# ## (C)opyright by Dirk Holtwick, 2002-2007 ## ## All rights reserved ## ############################################# __reversion__ = "$Revision: 20 $" __author__ = "$Author: holtwick $" __date__ = "$Date: 2007-10-09 12:58:24 +0200 (Di, 09 Okt 2007) $" from pisa_util import * from pisa_reportlab import * import pisa_default import pisa_parser import re import urlparse import types from reportlab.platypus.paraparser import ParaParser, ParaFrag, ps2tt, tt2ps, ABag from reportlab.platypus.paragraph import cleanBlockQuotedText from reportlab.lib.styles import ParagraphStyle import reportlab.rl_config reportlab.rl_config.warnOnMissingFontGlyphs = 0 from reportlab.pdfbase import pdfmetrics from reportlab.pdfbase.ttfonts import TTFont from reportlab.lib.fonts import addMapping from sx.w3c import css, cssDOMElementInterface from html5lib.sanitizer import * import logging log = logging.getLogger("ho.pisa") sizeDelta = 2 # amount to reduce font size by for super and sub script subFraction = 0.4 # fraction of font size that a sub script should be lowered superFraction = 0.4 NBSP = u"\u00a0" def clone(self, **kwargs): n = ParaFrag(**self.__dict__) if kwargs: d = n.__dict__ d.update(kwargs) # This else could cause trouble in Paragraphs with images etc. if "cbDefn" in d: del d["cbDefn"] n.bulletText = None return n ParaFrag.clone = clone def getParaFrag(style): frag = ParaFrag() frag.sub = 0 frag.super = 0 frag.rise = 0 frag.underline = 0 # XXX Need to be able to set color to fit CSS tests frag.strike = 0 frag.greek = 0 frag.link = None frag.text = "" # frag.lineBreak = 0 #if bullet: # frag.fontName, frag.bold, frag.italic = ps2tt(style.bulletFontName) # frag.fontSize = style.bulletFontSize # frag.textColor = hasattr(style,'bulletColor') and style.bulletColor or style.textColor #else: frag.fontName = "Times-Roman" frag.fontName, frag.bold, frag.italic = ps2tt(style.fontName) frag.fontSize = style.fontSize frag.textColor = style.textColor # Extras frag.leading = 0 frag.leadingSource = "150%" frag.leadingSpace = 0 frag.backColor = None frag.spaceBefore = 0 frag.spaceAfter = 0 frag.leftIndent = 0 frag.rightIndent = 0 frag.firstLineIndent = 0 frag.keepWithNext = False frag.alignment = TA_LEFT frag.vAlign = None frag.borderWidth = 1 frag.borderStyle = None frag.borderPadding = 0 frag.borderColor = None frag.borderLeftWidth = frag.borderWidth frag.borderLeftColor = frag.borderColor frag.borderLeftStyle = frag.borderStyle frag.borderRightWidth = frag.borderWidth frag.borderRightColor = frag.borderColor frag.borderRightStyle = frag.borderStyle frag.borderTopWidth = frag.borderWidth frag.borderTopColor = frag.borderColor frag.borderTopStyle = frag.borderStyle frag.borderBottomWidth = frag.borderWidth frag.borderBottomColor = frag.borderColor frag.borderBottomStyle = frag.borderStyle frag.paddingLeft = 0 frag.paddingRight = 0 frag.paddingTop = 0 frag.paddingBottom = 0 frag.listStyleType = None frag.listStyleImage = None frag.whiteSpace = "normal" frag.pageNumber = False frag.height = None frag.width = None frag.bulletIndent = 0 frag.bulletText = None frag.bulletFontName = "Helvetica" frag.zoom = 1.0 frag.outline = False frag.outlineLevel = 0 frag.outlineOpen = False frag.keepInFrameMode = "shrink" #frag.keepInFrameMaxWidth = None #frag.keepInFrameMaxHeight = None frag.insideStaticFrame = 0 return frag def getDirName(path): if path and not (path.lower().startswith("http:") or path.lower().startswith("https:")): return os.path.dirname(os.path.abspath(path)) return path class pisaCSSBuilder(css.CSSBuilder): def atFontFace(self, declarations): " Embed fonts " result = self.ruleset([self.selector('*')], declarations) # print "@FONT-FACE", declarations, result try: data = result[0].values()[0] names = data["font-family"] # Font weight fweight = str(data.get("font-weight", "normal")).lower() bold = fweight in ("bold", "bolder", "500", "600", "700", "800", "900") if not bold and fweight <> "normal": log.warn(self.c.warning("@fontface, unknown value font-weight '%s'", fweight)) # Font style italic = str(data.get("font-style", "")).lower() in ("italic", "oblique") src = self.c.getFile(data["src"]) self.c.loadFont( names, src, bold=bold, italic=italic) except Exception, e: log.warn(self.c.warning("@fontface"), exc_info=1) return {}, {} def _pisaDimensions(self, data, width, height): " Calculate dimensions of a box " # print data, width, height box = data.get("-pdf-frame-box", []) # print 123, box if len(box) == 4: return [getSize(x) for x in box] top = getSize(data.get("top", 0), height) left = getSize(data.get("left", 0), width) bottom = - getSize(data.get("bottom", 0), height) right = - getSize(data.get("right", 0), width) w = getSize(data.get("width", 0), width, default=None) h = getSize(data.get("height", 0), height, default=None) #print width, height, top, left, bottom, right, w, h if "height" in data: if "bottom" in data: top = bottom - h else: bottom = top + h if "width" in data: if "right" in data: # print right, w left = right - w else: right = left + w top += getSize(data.get("margin-top", 0), height) left += getSize(data.get("margin-left", 0), width) bottom -= getSize(data.get("margin-bottom", 0), height) right -= getSize(data.get("margin-right", 0), width) # box = getCoords(left, top, width, height, self.c.pageSize) # print "BOX", box # print top, left, w, h return left, top, right, bottom def _pisaAddFrame(self, name, data, first=False, border=None, size=(0,0)): c = self.c if not name: name = "-pdf-frame-%d" % c.UID() x, y, w, h = self._pisaDimensions(data, size[0], size[1]) # print name, x, y, w, h #if not (w and h): # return None if first: return ( name, None, data.get("-pdf-frame-border", border), x, y, w, h) return ( name, data.get("-pdf-frame-content", None), data.get("-pdf-frame-border", border), x, y, w, h) def atPage(self, name, pseudopage, declarations): try: c = self.c data = {} name = name or "body" pageBorder = None if declarations: result = self.ruleset([self.selector('*')], declarations) # print "@PAGE", name, pseudopage, declarations, result if declarations: data = result[0].values()[0] pageBorder = data.get("-pdf-frame-border", None) if c.templateList.has_key(name): log.warn(self.c.warning("template '%s' has already been defined", name)) if data.has_key("-pdf-page-size"): c.pageSize = pisa_default.PML_PAGESIZES.get(str(data["-pdf-page-size"]).lower(), c.pageSize) if data.has_key("size"): size = data["size"] # print size, c.pageSize if type(size) is not types.ListType: size = [size] isLandscape = False sizeList = [] for value in size: valueStr = str(value).lower() if type(value) is types.TupleType: sizeList.append(getSize(value)) elif valueStr == "landscape": isLandscape = True elif pisa_default.PML_PAGESIZES.has_key(valueStr): c.pageSize = pisa_default.PML_PAGESIZES[valueStr] else: log.warn(c.warning("Unknown size value for @page")) if len(sizeList) == 2: c.pageSize = sizeList if isLandscape: c.pageSize = landscape(c.pageSize) for prop in [ "margin-top", "margin-left", "margin-right", "margin-bottom", "top", "left", "right", "bottom", "width", "height" ]: if data.has_key(prop): c.frameList.append(self._pisaAddFrame(name, data, first=True, border=pageBorder, size=c.pageSize)) break # self._drawing = PmlPageDrawing(self._pagesize) #if not c.frameList: # c.warning("missing frame definitions for template") # return {}, {} # Frames have to be calculated after we know the pagesize frameList = [] staticList = [] for fname, static, border, x, y, w, h in c.frameList: x, y, w, h = getCoords(x, y, w, h, c.pageSize) if w <= 0 or h <= 0: log.warn(self.c.warning("Negative width or height of frame. Check @frame definitions.")) frame = Frame( x, y, w, h, id=fname, leftPadding=0, rightPadding=0, bottomPadding=0, topPadding=0, showBoundary=border or pageBorder) if static: frame.pisaStaticStory = [] c.frameStatic[static] = [frame] + c.frameStatic.get(static, []) staticList.append(frame) else: frameList.append(frame) background = data.get("background-image", None) if background: background = self.c.getFile(background) # print background # print frameList if not frameList: # print 999 log.warn(c.warning("missing explicit frame definition for content or just static frames")) fname, static, border, x, y, w, h = self._pisaAddFrame(name, data, first=True, border=pageBorder, size=c.pageSize) x, y, w, h = getCoords(x, y, w, h, c.pageSize) if w <= 0 or h <= 0: log.warn(c.warning("Negative width or height of frame. Check @page definitions.")) frameList.append(Frame( x, y, w, h, id=fname, leftPadding=0, rightPadding=0, bottomPadding=0, topPadding=0, showBoundary=border or pageBorder)) pt = PmlPageTemplate( id=name, frames=frameList, pagesize=c.pageSize, ) pt.pisaStaticList = staticList pt.pisaBackground = background pt.pisaBackgroundList = c.pisaBackgroundList # self._pagesize) # pt.pml_statics = self._statics # pt.pml_draw = self._draw # pt.pml_drawing = self._drawing # pt.pml_background = attrs.background # pt.pml_bgstory = self._bgstory c.templateList[name] = pt c.template = None c.frameList = [] c.frameStaticList = [] except Exception, e: log.warn(self.c.warning("@page"), exc_info=1) return {}, {} def atFrame(self, name, declarations): if declarations: result = self.ruleset([self.selector('*')], declarations) # print "@BOX", name, declarations, result try: data = result[0] if data: data = data.values()[0] self.c.frameList.append( self._pisaAddFrame( name, data, size=self.c.pageSize)) except Exception, e: log.warn(self.c.warning("@frame"), exc_info=1) return {}, {} class pisaCSSParser(css.CSSParser): def parseExternal(self, cssResourceName): # print "@import", self.rootPath, cssResourceName oldRootPath = self.rootPath cssFile = self.c.getFile(cssResourceName, relative=self.rootPath) result = [] if not cssFile: return None if self.rootPath and (self.rootPath.startswith("http:") or self.rootPath.startswith("https:")): self.rootPath = urlparse.urljoin(self.rootPath, cssResourceName) else: self.rootPath = getDirName(cssFile.uri) # print "###", self.rootPath result = self.parse(cssFile.getData()) self.rootPath = oldRootPath return result class pisaContext: """ Helper class for creation of reportlab story and container for varoius data. """ def __init__(self, path, debug=0, capacity=-1): self.fontList = copy.copy(pisa_default.DEFAULT_FONT) self.path = [] self.capacity=capacity self.node = None self.toc = PmlTableOfContents() self.story = [] self.text = [] self.log = [] self.err = 0 self.warn = 0 self.text = u"" self.uidctr = 0 self.multiBuild = False self.pageSize = A4 self.template = None self.templateList = {} self.frameList = [] self.frameStatic = {} self.frameStaticList = [] self.pisaBackgroundList = [] self.baseFontSize = getSize("12pt") self.anchorFrag = [] self.anchorName = [] self.tableData = None self.frag = self.fragBlock = getParaFrag(ParagraphStyle('default%d' % self.UID())) self.fragList = [] self.fragAnchor = [] self.fragStack = [] self.fragStrip = True self.listCounter = 0 self.cssText = "" self.image = None self.imageData = {} self.force = False self.pathCallback = None # External callback function for path calculations # Store path to document self.pathDocument = path or "__dummy__" if not (self.pathDocument.lower().startswith("http:") or self.pathDocument.lower().startswith("https:")): self.pathDocument = os.path.abspath(self.pathDocument) self.pathDirectory = getDirName(self.pathDocument) self.meta = dict( author="", title="", subject="", keywords="", pagesize=A4, ) def UID(self): self.uidctr += 1 return self.uidctr # METHODS FOR CSS def addCSS(self, value): value = value.strip() if value.startswith("", "\n") #self.cssText = self.cssText.replace("", "\n") #self.debug(9, self.cssText) # print repr(self.cssText) # file("pisa.css", "wb").write(self.cssText.encode("utf8")) # self.cssText = re.compile(r"url\((.*?\))", re.M).sub('"\1"', self.cssText) # self.cssText = re.compile(r"\-moz\-.*?([\;\}]+)", re.M).sub(r"\1", self.cssText) # XXX Import has to be implemented! # self.cssText = re.compile(r"\@import.*;", re.M).sub("", self.cssText) # if 0: # try: # # Sanitize CSS # import cssutils # import logging # cssutils.log.setlog(logging.getLogger('csslog')) # cssutils.log.setloglevel(logging.DEBUG) # sheet = cssutils.parseString(self.cssText) # self.cssText = sheet.cssText # #err = csslog.getvalue() # except ImportError, e: # pass # except Exception, e: # log.exception(self.error("Error parsing CSS by cssutils")) # print self.cssText # file("pisa-sanitized.css", "w").write(self.cssText.encode("utf8")) # print self.cssText self.cssBuilder = pisaCSSBuilder(mediumSet=["all", "print", "pdf"]) self.cssBuilder.c = self self.cssParser = pisaCSSParser(self.cssBuilder) self.cssParser.rootPath = self.pathDirectory self.cssParser.c = self self.css = self.cssParser.parse(self.cssText) self.cssCascade = css.CSSCascadeStrategy(self.css) self.cssCascade.parser = self.cssParser # METHODS FOR STORY def addStory(self, data): self.story.append(data) def swapStory(self, story=[]): self.story, story = copy.copy(story), copy.copy(self.story) return story def toParagraphStyle(self, first): style = ParagraphStyle('default%d' % self.UID(), keepWithNext=first.keepWithNext) style.fontName = first.fontName style.fontSize = first.fontSize style.leading = max(first.leading + first.leadingSpace, first.fontSize * 1.25) style.backColor = first.backColor style.spaceBefore = first.spaceBefore style.spaceAfter = first.spaceAfter style.leftIndent = first.leftIndent style.rightIndent = first.rightIndent style.firstLineIndent = first.firstLineIndent style.textColor = first.textColor style.alignment = first.alignment style.bulletFontName = first.bulletFontName or first.fontName style.bulletFontSize = first.fontSize style.bulletIndent = first.bulletIndent # Border handling for Paragraph # Transfer the styles for each side of the border, *not* the whole # border values that reportlab supports. We'll draw them ourselves in # PmlParagraph. style.borderTopStyle = first.borderTopStyle style.borderTopWidth = first.borderTopWidth style.borderTopColor = first.borderTopColor style.borderBottomStyle = first.borderBottomStyle style.borderBottomWidth = first.borderBottomWidth style.borderBottomColor = first.borderBottomColor style.borderLeftStyle = first.borderLeftStyle style.borderLeftWidth = first.borderLeftWidth style.borderLeftColor = first.borderLeftColor style.borderRightStyle = first.borderRightStyle style.borderRightWidth = first.borderRightWidth style.borderRightColor = first.borderRightColor # If no border color is given, the text color is used (XXX Tables!) if (style.borderTopColor is None) and style.borderTopWidth: style.borderTopColor = first.textColor if (style.borderBottomColor is None) and style.borderBottomWidth: style.borderBottomColor = first.textColor if (style.borderLeftColor is None) and style.borderLeftWidth: style.borderLeftColor = first.textColor if (style.borderRightColor is None) and style.borderRightWidth: style.borderRightColor = first.textColor style.borderPadding = first.borderPadding style.paddingTop = first.paddingTop style.paddingBottom = first.paddingBottom style.paddingLeft = first.paddingLeft style.paddingRight = first.paddingRight # This is the old code replaced by the above, kept for reference #style.borderWidth = 0 #if getBorderStyle(first.borderTopStyle): # style.borderWidth = max(first.borderLeftWidth, first.borderRightWidth, first.borderTopWidth, first.borderBottomWidth) # style.borderPadding = first.borderPadding # + first.borderWidth # style.borderColor = first.borderTopColor # # If no border color is given, the text color is used (XXX Tables!) # if (style.borderColor is None) and style.borderWidth: # style.borderColor = first.textColor style.fontName = tt2ps(first.fontName, first.bold, first.italic) return style def addTOC(self): # style = copy.deepcopy(self.toParagraphStyle(self.fragBlock)) #cssAttrs = copy.deepcopy(self.node.cssAttrs) #frag = copy.deepcopy(self.frag) styles = [] for i in range(0, 20): self.node.attributes["class"] = "pdftoclevel%d" % i #self.node.cssAttrs = copy.deepcopy(cssAttrs) #self.frag = copy.deepcopy(frag) self.cssAttr = pisa_parser.CSSCollect(self.node, self) pisa_parser.CSS2Frag(self, { "margin-top": 0, "margin-bottom": 0, "margin-left": 0, "margin-right": 0, }, True) pstyle = self.toParagraphStyle(self.frag) #styles.append(copy.deepcopy(pstyle)) styles.append(pstyle) # log.warn("%r", self.fragBlock.textColor) self.toc.levelStyles = styles self.addStory(self.toc) def dumpPara(self, frags, style): return print "%s/%s %s *** PARA" % (style.fontSize, style.leading, style.fontName) for frag in frags: print "%s/%s %r %r" % ( frag.fontSize, frag.leading, getattr(frag, "cbDefn", None), frag.text) print def addPara(self, force=False): # print self.force, repr(self.text) force = (force or self.force) self.force = False # Cleanup the trail try: rfragList = reversed(self.fragList) except: # For Python 2.3 compatibility rfragList = copy.copy(self.fragList) rfragList.reverse() #for frag in rfragList: # frag.text = frag.text.rstrip() # if frag.text: # break # Find maximum lead maxLeading = 0 #fontSize = 0 for frag in self.fragList: leading = getSize(frag.leadingSource, frag.fontSize) + frag.leadingSpace maxLeading = max(leading, frag.fontSize + frag.leadingSpace, maxLeading) frag.leading = leading if force or (self.text.strip() and self.fragList): # Strip trailing whitespaces #for f in self.fragList: # f.text = f.text.lstrip() # if f.text: # break #self.fragList[-1].lineBreak = self.fragList[-1].text.rstrip() # Update paragraph style by style of first fragment first = self.fragBlock style = self.toParagraphStyle(first) # style.leading = first.leading + first.leadingSpace if first.leadingSpace: style.leading = maxLeading else: style.leading = getSize(first.leadingSource, first.fontSize) + first.leadingSpace # style.leading = maxLeading # + first.leadingSpace #style.fontSize = fontSize # borderRadius: None, # print repr(self.text.strip()), style.leading, "".join([repr(x.text) for x in self.fragList]) # print first.leftIndent, first.listStyleType,repr(self.text) bulletText = copy.copy(first.bulletText) first.bulletText = None # Add paragraph to story if force or len(self.fragAnchor + self.fragList) > 0: # We need this empty fragment to work around problems in # Reportlab paragraphs regarding backGround etc. if self.fragList: self.fragList.append(self.fragList[ - 1].clone(text='')) else: blank = self.frag.clone() blank.fontName = "Helvetica" blank.text = '' self.fragList.append(blank) self.dumpPara(self.fragAnchor + self.fragList, style) para = PmlParagraph( self.text, style, frags=self.fragAnchor + self.fragList, bulletText=bulletText) # Mirrored and BIDI #import unicodedata #for c in self.text: # print unicodedata.bidirectional(c), para.outline = first.outline para.outlineLevel = first.outlineLevel para.outlineOpen = first.outlineOpen para.keepWithNext = first.keepWithNext para.autoLeading = "max" if self.image: para = PmlParagraphAndImage( para, self.image, side=self.imageData.get("align", "left")) self.addStory(para) self.fragAnchor = [] first.bulletText = None # Reset data self.image = None self.imageData = {} self.clearFrag() # METHODS FOR FRAG def clearFrag(self): self.fragList = [] self.fragStrip = True self.text = u"" def copyFrag(self, **kw): return self.frag.clone(**kw) def newFrag(self, **kw): self.frag = self.frag.clone(**kw) return self.frag def _appendFrag(self, frag): if frag.link and frag.link.startswith("#"): self.anchorFrag.append((frag, frag.link[1:])) self.fragList.append(frag) # XXX Argument frag is useless! def addFrag(self, text="", frag=None): frag = baseFrag = self.frag.clone() # if sub and super are both on they will cancel each other out if frag.sub == 1 and frag.super == 1: frag.sub = 0 frag.super = 0 # XXX Has to be replaced by CSS styles like vertical-align and font-size if frag.sub: frag.rise = - frag.fontSize * subFraction frag.fontSize = max(frag.fontSize - sizeDelta, 3) elif frag.super: frag.rise = frag.fontSize * superFraction frag.fontSize = max(frag.fontSize - sizeDelta, 3) # XXX Unused? #if frag.greek: # frag.fontName = 'symbol' # text = _greekConvert(text) # bold, italic, and underline frag.fontName = frag.bulletFontName = tt2ps(frag.fontName, frag.bold, frag.italic) # print frag.bulletFontName # Modify text for optimal whitespace handling # XXX Support Unicode whitespaces? # XXX What about images? # XXX Doesn't work with Reportlab > 2.1 # NBSP = '\xc2\xa0' # u"_" #if REPORTLAB22: # NBSP = u" " # Replace ­ with empty and normalize NBSP text = (text .replace(u"\xad", u"") .replace(u"\xc2\xa0", NBSP) .replace(u"\xa0", NBSP)) # log.debug("> %r", text) if frag.whiteSpace == "pre": # Handle by lines for text in re.split(r'(\r\n|\n|\r)', text): # This is an exceptionally expensive piece of code self.text += text if ("\n" in text) or ("\r" in text): # If EOL insert a linebreak frag = baseFrag.clone() frag.text = "" frag.lineBreak = 1 self._appendFrag(frag) else: # Handle tabs in a simple way text = text.replace(u"\t", 8 * u" ") # Somehow for Reportlab NBSP have to be inserted # as single character fragments for text in re.split(r'(\ )', text): frag = baseFrag.clone() if text == " ": text = NBSP frag.text = text self._appendFrag(frag) else: for text in re.split(u'(' + NBSP + u')', text): frag = baseFrag.clone() if text == NBSP: self.force = True frag.text = NBSP self.text += text self._appendFrag(frag) else: frag.text = " ".join(("x" + text + "x").split())[1: - 1] if self.fragStrip: frag.text = frag.text.lstrip() if frag.text: self.fragStrip = False self.text += frag.text self._appendFrag(frag) # print frag.fontName, repr(frag.text), frag.bulletText def pushFrag(self): self.fragStack.append(self.frag) self.newFrag() def pullFrag(self): self.frag = self.fragStack.pop() # XXX def _getFragment(self, l=20): try: return repr(" ".join(self.node.toxml().split()[:l])) except: return "" def _getLineNumber(self): return 0 def context(self, msg): return "%s\n%s" % ( str(msg), self._getFragment(50)) # return "line %s: %s\n%s" % ( # self._getLineNumber(), # str(msg), # self._getFragment(50)) def warning(self, msg, *args): self.warn += 1 self.log.append((pisa_default.PML_WARNING, self._getLineNumber(), str(msg), self._getFragment(50))) try: return self.context(msg % args) except: return self.context(msg) def error(self, msg, *args): self.err += 1 self.log.append((pisa_default.PML_ERROR, self._getLineNumber(), str(msg), self._getFragment(50))) try: return self.context(msg % args) except: return self.context(msg) # UTILS def _getFileDeprecated(self, name, relative): try: if name.startswith("data:"): return name path = relative or self.pathDirectory if self.pathCallback is not None: nv = self.pathCallback(name, relative) else: if path is None: log.warn("Could not find main directory for getting filename. Use CWD") path = os.getcwd() nv = os.path.normpath(os.path.join(path, name)) if not(nv and os.path.isfile(nv)): nv = None if nv is None: log.warn(self.warning("File '%s' does not exist", name)) return nv except: log.warn(self.warning("getFile %r %r %r", name, relative, path), exc_info=1) def getFile(self, name, relative=None): """ Returns a file name or None """ if self.pathCallback is not None: return getFile(self._getFileDeprecated(name, relative)) return getFile(name, relative or self.pathDirectory) def getFontName(self, names, default="helvetica"): """ Name of a font """ # print names, self.fontList if type(names) is not types.ListType: names = str(names).strip().split(",") for name in names: font = self.fontList.get(str(name).strip().lower(), None) if font is not None: return font return self.fontList.get(default, None) def registerFont(self, fontname, alias=[]): self.fontList[str(fontname).lower()] = str(fontname) for a in alias: self.fontList[str(a)] = str(fontname) def loadFont(self, names, src, encoding="WinAnsiEncoding", bold=0, italic=0): # XXX Just works for local filenames! if names and src: # and src.local: file = src src = file.uri log.debug("Load font %r", src) if type(names) is types.ListType: fontAlias = names else: fontAlias = [x.lower().strip() for x in names.split(",") if x] # XXX Problems with unicode here fontAlias = [str(x) for x in fontAlias] fontName = fontAlias[0] parts = src.split(".") baseName, suffix = ".".join(parts[: - 1]), parts[ - 1] suffix = suffix.lower() try: if suffix == "ttf": # determine full font name according to weight and style fullFontName = "%s_%d%d" % (fontName, bold, italic) # check if font has already been registered if fullFontName in self.fontList: log.warn(self.warning("Repeated font embed for %s, skip new embed ", fullFontName)) else: # Register TTF font and special name filename = file.getNamedFile() pdfmetrics.registerFont(TTFont(fullFontName, filename)) # Add or replace missing styles for bold in (0, 1): for italic in (0, 1): if ("%s_%d%d" % (fontName, bold, italic)) not in self.fontList: addMapping(fontName, bold, italic, fullFontName) # Register "normal" name and the place holder for style self.registerFont(fontName, fontAlias + [fullFontName]) elif suffix in ("afm", "pfb"): if suffix == "afm": afm = file.getNamedFile() tfile = pisaFileObject(baseName + ".pfb") pfb = tfile.getNamedFile() else: pfb = file.getNamedFile() tfile = pisaFileObject(baseName + ".afm") afm = tfile.getNamedFile() #afm = baseName + ".afm" #pfb = baseName + ".pfb" # determine full font name according to weight and style fullFontName = "%s_%d%d" % (fontName, bold, italic) #fontNameOriginal = "" #for line in open(afm).readlines()[:-1]: # if line[:16] == 'StartCharMetrics': # self.error("Font name not found") # if line[:8] == 'FontName': # fontNameOriginal = line[9:].strip() # break # check if font has already been registered if fullFontName in self.fontList: log.warn(self.warning("Repeated font embed for %s, skip new embed", fontName)) else: # Include font face = pdfmetrics.EmbeddedType1Face(afm, pfb) fontNameOriginal = face.name pdfmetrics.registerTypeFace(face) # print fontName, fontNameOriginal, fullFontName justFont = pdfmetrics.Font(fullFontName, fontNameOriginal, encoding) pdfmetrics.registerFont(justFont) # Add or replace missing styles for bold in (0, 1): for italic in (0, 1): if ("%s_%d%d" % (fontName, bold, italic)) not in self.fontList: addMapping(fontName, bold, italic, fontNameOriginal) # Register "normal" name and the place holder for style self.registerFont(fontName, fontAlias + [fullFontName, fontNameOriginal]) #import pprint #pprint.pprint(self.fontList) else: log.warning(self.warning("wrong attributes for ")) except Exception: log.warn(self.warning("Loading font '%s'", fontName), exc_info=1) pisa-3.0.32/sx/pisa3/._pisa_document.py0000644000175000017500000000035111200742440015752 0ustar wmbwmbMac OS X  2ATTR98QQcom.apple.quarantineq/0000;49cba683;Safari.app;9AFF29BE-A1F8-4D2F-A543-8AC395074CD0|com.apple.Safaripisa-3.0.32/sx/pisa3/._pisa_reportlab.py0000644000175000017500000000035111200024632016122 0ustar wmbwmbMac OS X  2ATTR9<QQcom.apple.quarantineq/0000;49cba683;Safari.app;9AFF29BE-A1F8-4D2F-A543-8AC395074CD0|com.apple.Safaripisa-3.0.32/sx/pisa3/pisa_paragraph2.py0000644000175000017500000006341411111257634015766 0ustar wmbwmb#!/bin/env/python # -*- coding: utf-8 -*- """ A paragraph class to be used with ReportLab Platypus. TODO ==== - Bullets - Weblinks and internal links - Borders and margins (Box) - Underline, Background, Strike - Images - Hyphenation + Alignment + Breakline, empty lines + TextIndent - Sub and super """ from reportlab.lib.enums import TA_CENTER, TA_JUSTIFY, TA_LEFT, TA_RIGHT from reportlab.pdfbase.pdfmetrics import stringWidth from reportlab.platypus.flowables import Flowable from reportlab.lib.colors import Color WORD = 1 SPACE = 2 BR = 3 BEGIN = 4 END = 5 IMAGE = 6 class Style(dict): """ Style. Single place for style definitions: Paragraphs and Fragments. The naming follows the convention of CSS written in camelCase letters. """ DEFAULT = { "textAlign": TA_LEFT, "textIndent": 0.0, "width": None, "height": None, "fontName": "Times-Roman", "fontSize": 10.0, "color": Color(0, 0, 0), "lineHeight": 1.5, "lineHeightAbsolute": None, "pdfLineSpacing": 0, "link": None, } def __init__(self, **kw): self.update(self.DEFAULT) self.update(kw) self.spaceBefore = 0 self.spaceAfter = 0 self.keepWithNext = False class Box(dict): """ Box. Handles the following styles: # underline, underLineColor (?) # strike, strikeColor (?) backgroundColor, backgroundImage paddingLeft, paddingRight, paddingTop, paddingBottom marginLeft, marginRight, marginTop, marginBottom borderLeftColor, borderLeftWidth, borderLeftStyle borderRightColor, borderRightWidth, borderRightStyle borderTopColor, borderTopWidth, borderTopStyle borderBottomColor, borderBottomWidth, borderBottomStyle Not used in inline Elements: paddingTop, paddingBottom marginTop, marginBottom Needs also: fontName, fontSize, color """ name = "box" def _drawBefore(self, canvas, x, y, w, h): canvas.saveState() textColor = self.get("color", Color(0, 0, 0)) # Background bg = self.get("backgroundColor", None) if bg is not None: # draw a filled rectangle (with no stroke) using bg color canvas.setFillColor(bg) canvas.rect(x, y, w, h, fill=1, stroke=0) # Borders def _drawBorderLine(bstyle, width, color, x1, y1, x2, y2): # We need width and border style to be able to draw a border if width and bstyle: # If no color for border is given, the text color is used (like defined by W3C) if color is None: color = textColor # print "Border", bstyle, width, color if color is not None: canvas.setStrokeColor(color) canvas.setLineWidth(width) canvas.line(x1, y1, x2, y2) _drawBorderLine(self.get("borderLeftStyle", None), self.get("borderLeftWidth", None), self.get("borderLeftColor", None), x, y, x, y + h) _drawBorderLine(self.get("borderRightStyle", None), self.get("borderRightWidth", None), self.get("borderRightColor", None), x + w, y, x + w, y + h) _drawBorderLine(self.get("borderTopStyle", None), self.get("borderTopWidth", None), self.get("borderTopColor", None), x, y + h, x + w, y + h) _drawBorderLine(self.get("borderBottomStyle", None), self.get("borderBottomWidth", None), self.get("borderBottomColor", None), x, y, x + w, y) # Underline if self.get("underline", None): ff = 0.125 * self["fontSize"] yUnderline = y - 1.0 * ff canvas.setLineWidth(ff * 0.75) canvas.setStrokeColor(textColor) canvas.line(x, yUnderline, x+w, yUnderline) canvas.restoreState() def _drawAfter(self, canvas, x, y, w, h): # Strike if self.get("strike", None): ff = 0.125 * self["fontSize"] yStrike = y + 2.0 * ff textColor = self.get("color", Color(0, 0, 0)) canvas.saveState() canvas.setLineWidth(ff * 0.75) canvas.setStrokeColor(textColor) canvas.line(x, yStrike, x+w, yStrike) canvas.restoreState() class Fragment(Box): """ Fragment. text: String containing text fontName: fontSize: width: Width of string height: Height of string """ name = "fragment" type = None isSoft = False isText = False isLF = False def calc(self): self["width"] = 0 def __str__(self): if self.isText: return "'%s'" % self["text"] return "<%s>" % self.name.upper() class BoxBegin(Fragment): name = "begin" type = BEGIN def calc(self): self["width"] = self.get("marginLeft", 0) + self.get("paddingLeft", 0) # + border if border def drawBefore(self, canvas, y): print repr(self) x = self.get("marginLeft", 0) + self["x"] w = self["length"] + self.get("paddingRight", 0) h = self["fontSize"] self["box"] = (x, w, h) self._drawBefore(canvas, x, y, w, h) def drawAfter(self, canvas, y): x, w, h = self["box"] self._drawAfter(canvas, x, y, w, h) class BoxEnd(Fragment): name = "end" type = END def calc(self): self["width"] = self.get("marginRight", 0) + self.get("paddingRight", 0) # + border class Word(Fragment): " A single word. " name = "word" type = WORD isText = True def calc(self): """ XXX Cache stringWith if not accelerated?! """ self["width"] = stringWidth(self["text"], self["fontName"], self["fontSize"]) class Space(Fragment): """ A space between fragments that is the usual place for line breaking. """ name = "space" type = SPACE isSoft = True def calc(self): self["width"] = stringWidth(" ", self["fontName"], self["fontSize"]) #def makeSpace(fn, fs): # obj = Space() # obj.update({"fontName": fn, "fontSize": fs}) # obj.calc() # return obj class LineBreak(Fragment): " Line break. " name = "br" type = BR isSoft = True isLF = True pass class Image(Fragment): name = "image" type = IMAGE isText = True pass class Line(list): """ Container for line fragments. """ LINEHEIGHT = 1.0 def __init__(self, style): self.width = 0 self.height = 0 self.isLast = False self.br = False self.style = style self.boxStack = [] list.__init__(self) def doAlignment(self, width, alignment): # Apply alignment if alignment != TA_LEFT: lineWidth = self[ - 1]["x"] + self[ - 1]["width"] emptySpace = width - lineWidth if alignment == TA_RIGHT: for j, frag in enumerate(self): frag["x"] += emptySpace elif alignment == TA_CENTER: for j, frag in enumerate(self): frag["x"] += emptySpace / 2.0 elif alignment == TA_JUSTIFY and not self.br: # XXX Just spaces! Currently divides also sticky fragments delta = emptySpace / (len(self) - 1) for j, frag in enumerate(self): frag["x"] += j * delta # Boxes for frag in self: x = frag["x"] + frag["width"] if isinstance(frag, BoxBegin): self.boxStack.append(frag) elif isinstance(frag, BoxEnd): if self.boxStack: frag = self.boxStack.pop() frag["length"] = x - frag["x"] # Handle the rest for frag in self.boxStack: frag["length"] = x - frag["x"] def doLayout(self, width): "Align words in previous line." # Calculate dimensions self.width = width self.height = self.lineHeight = max(frag.get("fontSize" , 0) * self.LINEHEIGHT for frag in self) # Apply line height self.fontSize = max(frag.get("fontSize" , 0) for frag in self) y = (self.lineHeight - self.fontSize) # / 2 for frag in self: frag["y"] = y return self.height def dumpFragments(self): print "Line", 40*"-" for frag in self: print "%s" % frag.get("text", frag.name.upper()), print class Group(list): pass class Text(list): """ Container for text fragments. Helper functions for splitting text into lines and calculating sizes and positions. """ def __init__(self, data=[], style=None): #self.groups = [] self.lines = [] self.width = 0 self.height = 0 self.maxWidth = 0 self.maxHeight = 0 self.pos = 0 self.oldSpace = None self.newSpace = None self.style = style list.__init__(self, data) def calc(self): """ Calculate sizes of fragments. """ [word.calc() for word in self] def getGroup(self): self.oldSpace = self.newSpace # For Space recycing group = [] width = 0 br = False length = len(self) while self.pos < length: frag = self[self.pos] type_ = frag.type self.pos += 1 if type_ == SPACE: self.newSpace = frag # For Space recycing if group: break continue group.append(frag) width += frag.get("width", 0) if type_ == BR: br = True break return width, br, group def splitIntoLines(self, maxWidth, maxHeight, splitted=False): """ Split text into lines and calculate X positions. If we need more space in height than available we return the rest of the text """ self.lines = [] self.pos = 0 self.height = 0 self.maxWidth = self.width = maxWidth self.maxHeight = maxHeight boxStack = [] style = self.style x = 0 # Start with indent in first line of text if not splitted: x = style["textIndent"] # Loop for each line while 1: # Reset values for new line posBegin = self.pos line = Line(style) # Update boxes for next line for box in copy.deepcopy(boxStack): box["x"] = 0 line.append(BoxBegin(box)) # Loop for collecting line elements while 1: # Get next group of unbreakable elements self.groupPos = self.pos groupWidth, br, group = self.getGroup() # No more groups? Leave line if not group: break # print width, " ".join([str(x) for x in group]) # To we fit the line? Reset cursor and finish line if (groupWidth + x > maxWidth): self.pos = self.groupPos break # Space recycling if self.oldSpace: group.insert(0, self.oldSpace) # Add fragments to line and update x for frag in group: # Add fragment to line and update x frag["x"] = x x += frag["width"] line.append(frag) # Keep in mind boxes for next lines if isinstance(frag, BoxBegin): boxStack.append(frag) elif isinstance(frag, BoxEnd): boxStack.pop() # We got a new line forced if br: line.br = True break self.newSpace = None # Add line to list line.dumpFragments() if line: self.height += line.doLayout(self.width) self.lines.append(line) # If not enough space for current line force to split if self.height > maxHeight: return posBegin # Reached the end if not group: break # Reset variables x = 0 # Apply alignment self.lines[ - 1].br = True [line.doAlignment(maxWidth, style["textAlign"]) for line in self.lines] return None def dumpLines(self): """ For debugging dump all line and their content """ i = 0 for line in self.lines: print "Line %d:" % i, line.dumpFragments() i += 1 class Paragraph(Flowable): """A simple Paragraph class respecting alignment. Does text without tags. Respects only the following global style attributes: fontName, fontSize, leading, firstLineIndent, leftIndent, rightIndent, textColor, alignment. (spaceBefore, spaceAfter are handled by the Platypus framework.) """ def __init__(self, text, style, debug=False, splitted=False, **kwDict): Flowable.__init__(self) # self._showBoundary = True self.text = text self.text.calc() self.style = style self.text.style = style self.debug = debug self.splitted = splitted # More attributes for k, v in kwDict.items(): setattr(self, k, v) # set later... self.splitIndex = None # overwritten methods from Flowable class def wrap(self, availWidth, availHeight): "Determine the rectangle this paragraph really needs." # memorize available space self.avWidth = availWidth self.avHeight = availHeight if self.debug: print "*** wrap (%f, %f)" % (availWidth, availHeight) if not self.text: if self.debug: print "*** wrap (%f, %f) needed" % (0, 0) return 0, 0 style = self.style # Split lines width = availWidth # - style.leftIndent - style.rightIndent self.splitIndex = self.text.splitIntoLines(width, availHeight) self.width, self.height = availWidth, self.text.height if self.debug: print "*** wrap (%f, %f) needed, splitIndex %r" % (self.width, self.height, self.splitIndex) return self.width, self.height #def visitFirstParagraph(self, para): # return para #def visitOtherParagraph(self, para): # return para def split(self, availWidth, availHeight): "Split ourself in two paragraphs." if self.debug: print "*** split (%f, %f)" % (availWidth, availHeight) splitted = [] if self.splitIndex: text1 = self.text[:self.splitIndex] text2 = self.text[self.splitIndex:] p1 = Paragraph(Text(text1), self.style, debug=self.debug) p2 = Paragraph(Text(text2), self.style, debug=self.debug, splitted=True) splitted = [p1, p2] if self.debug: print "*** text1 %s / text %s" % (len(text1), len(text2)) if self.debug: print '*** return %s' % self.splitted return splitted def draw(self): "Render the content of the paragraph." if self.debug: print "*** draw" if not self.text: return canvas = self.canv style = self.style canvas.saveState() # Draw box arround paragraph for debugging if self.debug: bw = 0.5 bc = Color(1, 1, 0) bg = Color(0.9, 0.9, 0.9) canvas.setStrokeColor(bc) canvas.setLineWidth(bw) canvas.setFillColor(bg) canvas.rect( style.leftIndent, 0, self.width, self.height, fill=1, stroke=1) y = 0 dy = self.height for line in self.text.lines: y += line.height for frag in line: type_ = frag.type # Box if type_ == BEGIN: frag.drawBefore(canvas, dy - y) # Text if type_ == WORD: canvas.setFont(frag["fontName"], frag["fontSize"]) canvas.setFillColor(frag.get("color", style["color"])) canvas.drawString(frag["x"], dy - y + frag["y"], frag["text"]) # Box if type_ == BEGIN: frag.drawAfter(canvas, dy - y) # XXX LINK link = frag.get("link", None) if link: _scheme_re = re.compile('^[a-zA-Z][-+a-zA-Z0-9]+$') x, y, w, h = frag["x"], dy - y, frag["width"], frag["fontSize"] rect = (x, y, w, h) if isinstance(link, unicode): link = link.encode('utf8') parts = link.split(':', 1) scheme = len(parts) == 2 and parts[0].lower() or '' if _scheme_re.match(scheme) and scheme != 'document': kind = scheme.lower() == 'pdf' and 'GoToR' or 'URI' if kind == 'GoToR': link = parts[1] tx._canvas.linkURL(link, rect, relative=1, kind=kind) else: if link[0] == '#': link = link[1:] scheme = '' canvas.linkRect("", scheme != 'document' and link or parts[1], rect, relative=1) canvas.restoreState() if __name__ == "__main__": from reportlab.platypus import SimpleDocTemplate from reportlab.lib.styles import * from reportlab.rl_config import * from reportlab.lib.units import * import os import copy import re import pprint styles = getSampleStyleSheet() ALIGNMENTS = (TA_LEFT, TA_RIGHT, TA_CENTER, TA_JUSTIFY) TEXT = """ Lörem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum. Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum. Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. """.strip() def textGenerator(data, fn, fs): i = 1 for word in re.split('\s+', data): if word: yield Word( text="[%d|%s]" % (i, word), fontName=fn, fontSize=fs ) yield Space( fontName=fn, fontSize=fs ) i += 1 def createText(data, fn, fs): text = Text(list(textGenerator(data, fn, fs))) return text def makeBorder(width, style="solid", color=Color(1, 0, 0)): return dict( borderLeftColor=color, borderLeftWidth=width, borderLeftStyle=style, borderRightColor=color, borderRightWidth=width, borderRightStyle=style, borderTopColor=color, borderTopWidth=width, borderTopStyle=style, borderBottomColor=color, borderBottomWidth=width, borderBottomStyle=style ) def makeSpecial(fn="Times-Roman", fs=10): return [ Space( fontName=fn, fontSize=fs), Word( text="TrennbarTrennbar", pairs=[("Trenn-", "barTrennbar")], fontName=fn, fontSize=fs), Space( fontName=fn, fontSize=fs), Word( text="Normal", color=Color(1, 0, 0), fontName=fn, fontSize=fs), Space( fontName=fn, fontSize=fs), BoxBegin( fontName=fn, fontSize=fs, underline=True, strike=True), Word( text="gGrößer", fontName=fn, fontSize=fs * 1.5), Space( fontName=fn, fontSize=fs), Word( text="Bold", fontName="Times-Bold", fontSize=fs), BoxEnd(), Space( fontName=fn, fontSize=fs), Word( text="jItalic", fontName="Times-Italic", fontSize=fs), Space( fontName=fn, fontSize=fs), # ipsum # Lorem ipsum Lorem BoxBegin( fontName=fn, fontSize=fs, **makeBorder(0.5, "solid", Color(0, 1, 0))), Word( text="Lorem", fontName="Times-Bold", fontSize=fs), Word( text="Lorem", fontName=fn, fontSize=fs), Word( text="Lorem", fontName=fn, fontSize=fs), Word( text="Lorem", fontName=fn, fontSize=fs), Word( text="Lorem", fontName=fn, fontSize=fs), Word( text="Lorem", fontName=fn, fontSize=fs), Word( text="Lorem", fontName=fn, fontSize=fs), Word( text="Lorem", fontName=fn, fontSize=fs), Word( text="Lorem", fontName=fn, fontSize=fs), Word( text="Lorem", fontName="Times-Bold", fontSize=fs), Space( fontName=fn, fontSize=fs), Word( text="Lorem", fontName=fn, fontSize=fs), Space( fontName=fn, fontSize=fs), Word( text="Lorem", fontName=fn, fontSize=fs), Space( fontName=fn, fontSize=fs), Word( text="Lorem", fontName=fn, fontSize=fs), Space( fontName=fn, fontSize=fs), BoxBegin( fontName=fn, fontSize=fs, backgroundColor=Color(1, 1, 0), **makeBorder(1, "solid", Color(1, 0, 0))), Word( text="Lorem", fontName=fn, fontSize=fs), BoxEnd(), Space( fontName=fn, fontSize=fs), Word( text="Lorem", fontName=fn, fontSize=fs), Space( fontName=fn, fontSize=fs), BoxEnd(), LineBreak( fontName=fn, fontSize=fs), LineBreak( fontName=fn, fontSize=fs), ] def test(): doc = SimpleDocTemplate("test.pdf") story = [] style = Style(fontName="Helvetica", textIndent=24.0) fn = style["fontName"] fs = style["fontSize"] sampleText1 = createText(TEXT[:100], fn, fs) sampleText2 = createText(TEXT[100:], fn, fs) text = Text(sampleText1 + makeSpecial(fn, fs) + sampleText2) story.append(Paragraph( copy.copy(text), style, debug=0)) if 0: for i in range(10): style = copy.deepcopy(style) style["textAlign"] = ALIGNMENTS[i % 4] text = createText(("(%d) " % i) + TEXT, fn, fs) story.append(Paragraph( copy.copy(text), style, debug=0)) doc.build(story) def test2(): # text = Text(list(textGenerator(TEXT, "Times-Roman", 10))) text = Text(makeSpecial()) text.calc() print text[1].type while 1: width, br, group = text.getGroup() if not group: print "ENDE", repr(group) break print width, br, " ".join([str(x) for x in group]) # test2() if 1: test() os.system("start test.pdf") # createText(TEXT, styles["Normal"].fontName, styles["Normal"].fontSize) pisa-3.0.32/sx/pisa3/pisa_tags.py0000644000175000017500000004403011200743065014663 0ustar wmbwmb# -*- coding: utf-8 -*- ############################################# ## (C)opyright by Dirk Holtwick, 2002-2007 ## ## All rights reserved ## ############################################# __reversion__ = "$Revision: 20 $" __author__ = "$Author: holtwick $" __date__ = "$Date: 2007-10-09 12:58:24 +0200 (Di, 09 Okt 2007) $" from pisa_default import DEFAULT_CSS from pisa_reportlab import * from pisa_util import * from reportlab.graphics.barcode.code39 import Standard39 from reportlab.lib.styles import ParagraphStyle from reportlab.platypus.flowables import * from reportlab.platypus.paraparser import tt2ps, ABag from reportlab_paragraph import cleanBlockQuotedText import reportlab.lib.utils import os import pprint import re import warnings import logging log = logging.getLogger("ho.pisa") def deprecation(message): warnings.warn("<" + message + "> is deprecated!", DeprecationWarning, stacklevel=2) class pisaTag: """ The default class for a tag definition """ def __init__(self, node, attr): self.node = node self.tag = node.tagName self.attr = attr def start(self, c): pass def end(self, c): pass class pisaTagBODY(pisaTag): """ We can also asume that there is a BODY tag because html5lib adds it for us. Here we take the base font size for later calculations in the FONT tag. """ def start(self, c): c.baseFontSize = c.frag.fontSize # print "base font size", c.baseFontSize class pisaTagTITLE(pisaTag): def end(self, c): c.meta["title"] = c.text c.clearFrag() class pisaTagSTYLE(pisaTag): def start(self, c): c.addPara() def end(self, c): c.clearFrag() class pisaTagMETA(pisaTag): def start(self, c): name = self.attr.name.lower() if name in ("author" , "subject", "keywords"): c.meta[name] = self.attr.content class pisaTagSUP(pisaTag): def start(self, c): c.frag.super = 1 class pisaTagSUB(pisaTag): def start(self, c): c.frag.sub = 1 class pisaTagA(pisaTag): rxLink = re.compile("^(#|[a-z]+\:).*") def start(self, c): attr = self.attr # XXX Also support attr.id ? if attr.name: # Important! Make sure that cbDefn is not inherited by other # fragments because of a bug in Reportlab! afrag = c.frag.clone() # These 3 lines are needed to fix an error with non internal fonts afrag.fontName = "Helvetica" afrag.bold = 0 afrag.italic = 0 afrag.cbDefn = ABag( kind="anchor", name=attr.name, label="anchor") c.fragAnchor.append(afrag) c.anchorName.append(attr.name) if attr.href and self.rxLink.match(attr.href): c.frag.link = attr.href def end(self, c): pass class pisaTagFONT(pisaTag): # Source: http://www.w3.org/TR/CSS21/fonts.html#propdef-font-size def start(self, c): if self.attr["color"] is not None: c.frag.textColor = getColor(self.attr["color"]) if self.attr["face"] is not None: c.frag.fontName = c.getFontName(self.attr["face"]) if self.attr["size"] is not None: size = getSize(self.attr["size"], c.frag.fontSize, c.baseFontSize) c.frag.fontSize = max(size, 1.0) def end(self, c): pass class pisaTagP(pisaTag): def start(self, c): # save the type of tag; it's used in PmlBaseDoc.afterFlowable() # to check if we need to add an outline-entry # c.frag.tag = self.tag if self.attr.align is not None: #print self.attr.align, getAlign(self.attr.align) c.frag.alignment = getAlign(self.attr.align) class pisaTagDIV(pisaTagP): pass class pisaTagH1(pisaTagP): pass class pisaTagH2(pisaTagP): pass class pisaTagH3(pisaTagP): pass class pisaTagH4(pisaTagP): pass class pisaTagH5(pisaTagP): pass class pisaTagH6(pisaTagP): pass def listDecimal(c): c.listCounter += 1 return unicode("%d." % c.listCounter) _bullet = u"\u2022" _list_style_type = { "none": u"", "disc": _bullet, "circle": _bullet, # XXX PDF has no equivalent "square": _bullet, # XXX PDF has no equivalent "decimal": listDecimal, "decimal-leading-zero": listDecimal, "lower-roman": listDecimal, "upper-roman": listDecimal, "hebrew": listDecimal, "georgian": listDecimal, "armenian": listDecimal, "cjk-ideographic": listDecimal, "hiragana": listDecimal, "katakana": listDecimal, "hiragana-iroha": listDecimal, "katakana-iroha": listDecimal, "lower-latin": listDecimal, "lower-alpha": listDecimal, "upper-latin": listDecimal, "upper-alpha": listDecimal, "lower-greek": listDecimal, } class pisaTagUL(pisaTagP): def start(self, c): self.counter, c.listCounter = c.listCounter, 0 def end(self, c): c.addPara() # XXX Simulate margin for the moment c.addStory(Spacer(width=1, height=c.fragBlock.spaceAfter)) c.listCounter = self.counter class pisaTagOL(pisaTagUL): pass class pisaTagLI(pisaTag): def start(self, c): lst = _list_style_type.get(c.frag.listStyleType or "disc", _bullet) #log.debug("frag %r", c.copyFrag( # text=lst, # bulletFontName=c.getFontName("helvetica"), # fontName=c.getFontName("helvetica"))) # c.addFrag("") #frag = ParaFrag() #frag.fontName = frag.bulletFontName = c.getFontName("helvetica") #frag.fontSize = c.frag.fontSize #c.frag.fontName = c.getFontName("helvetica") frag = copy.copy(c.frag) #print "###", c.frag.fontName #frag.fontName = "au_00" # c.getFontName("helvetica") #frag.bulletFontName = "au_00" # c.getFontName("helvetica") self.offset = 0 if frag.listStyleImage is not None: frag.text = u"" f = frag.listStyleImage if f and (not f.notFound()): img = PmlImage( f.getData(), width=None, height=None) img.drawHeight *= dpi96 img.drawWidth *= dpi96 img.pisaZoom = frag.zoom img.drawWidth *= img.pisaZoom img.drawHeight *= img.pisaZoom frag.image = img self.offset = max(0, img.drawHeight - c.frag.fontSize) else: if type(lst) == type(u""): frag.text = lst else: # XXX This should be the recent font, but it throws errors in Reportlab! frag.text = lst(c) # XXX This should usually be done in the context!!! frag.fontName = frag.bulletFontName = tt2ps(frag.fontName, frag.bold, frag.italic) c.frag.bulletText = [frag] def end(self, c): c.fragBlock.spaceBefore += self.offset #c.fragBlock.bulletText = self.bulletText #print 999, self.bulletText # c.addPara() class pisaTagBR(pisaTag): def start(self, c): # print "BR", c.text[-40:] c.frag.lineBreak = 1 c.addFrag() c.fragStrip = True del c.frag.lineBreak c.force = True class pisaTagIMG(pisaTag): def start(self, c): attr = self.attr if attr.src and (not attr.src.notFound()): try: align = attr.align or c.frag.vAlign or "baseline" # print "align", align, attr.align, c.frag.vAlign width = c.frag.width height = c.frag.height if attr.width: width = attr.width * dpi96 if attr.height: height = attr.height * dpi96 img = PmlImage( attr.src.getData(), width=None, height=None) img.pisaZoom = c.frag.zoom img.drawHeight *= dpi96 img.drawWidth *= dpi96 if (width is None) and (height is not None): factor = float(height) / img.drawHeight img.drawWidth *= factor img.drawHeight = height elif (height is None) and (width is not None): factor = float(width) / img.drawWidth img.drawHeight *= factor img.drawWidth = width elif (width is not None) and (height is not None): img.drawWidth = width img.drawHeight = height img.drawWidth *= img.pisaZoom img.drawHeight *= img.pisaZoom img.spaceBefore = c.frag.spaceBefore img.spaceAfter = c.frag.spaceAfter # print "image", id(img), img.drawWidth, img.drawHeight ''' TODO: - Apply styles - vspace etc. - Borders - Test inside tables ''' c.force = True if align in ["left", "right"]: c.image = img c.imageData = dict( align=align ) else: # Important! Make sure that cbDefn is not inherited by other # fragments because of a bug in Reportlab! # afrag = c.frag.clone() valign = align if valign in ["texttop"]: valign = "top" elif valign in ["absmiddle"]: valign = "middle" elif valign in ["absbottom", "baseline"]: valign = "bottom" afrag = c.frag.clone() afrag.text = "" afrag.fontName="Helvetica" # Fix for a nasty bug!!! afrag.cbDefn = ABag( kind="img", image=img, #.getImage(), # XXX Inline? valign=valign, fontName="Helvetica", fontSize=img.drawHeight, width=img.drawWidth, height=img.drawHeight) # print "add frag", id(afrag), img.drawWidth, img.drawHeight c.fragList.append(afrag) c.fontSize = img.drawHeight except Exception: log.warn(c.warning("Error in handling image"), exc_info=1) else: log.warn(c.warning("Need a valid file name!")) class pisaTagHR(pisaTag): def start(self, c): c.addPara() c.addStory(HRFlowable( color=self.attr.color, thickness=self.attr.size, width="100%", spaceBefore=c.frag.spaceBefore, spaceAfter=c.frag.spaceAfter )) # --- Forms import pisa_reportlab if 0: class pisaTagINPUT(pisaTag): def _render(self, c, attr): width = 10 height = 10 if attr.type == "text": width = 100 height = 12 c.addStory(pisa_reportlab.PmlInput(attr.name, type=attr.type, default=attr.value, width=width, height=height, )) def end(self, c): c.addPara() attr = self.attr if attr.name: self._render(c, attr) c.addPara() class pisaTagTEXTAREA(pisaTagINPUT): def _render(self, c, attr): c.addStory(pisa_reportlab.PmlInput(attr.name, default="", width=100, height=100)) class pisaTagSELECT(pisaTagINPUT): def start(self, c): c.select_options = ["One", "Two", "Three"] def _render(self, c, attr): c.addStory(pisa_reportlab.PmlInput(attr.name, type="select", default=c.select_options[0], options=c.select_options, width=100, height=40)) c.select_options = None class pisaTagOPTION(pisaTag): pass # ============================================ class pisaTagPDFNEXTPAGE(pisaTag): """ """ def start(self, c): # deprecation("pdf:nextpage") c.addPara() if self.attr.name: c.addStory(NextPageTemplate(self.attr.name)) c.addStory(PageBreak()) class pisaTagPDFNEXTTEMPLATE(pisaTag): """ """ def start(self, c): # deprecation("pdf:frame") c.addStory(NextPageTemplate(self.attr["name"])) class pisaTagPDFNEXTFRAME(pisaTag): """ """ def start(self, c): c.addPara() c.addStory(FrameBreak()) class pisaTagPDFSPACER(pisaTag): """ """ def start(self, c): c.addPara() c.addStory(Spacer(1, self.attr.height)) class pisaTagPDFPAGENUMBER(pisaTag): """ """ def start(self, c): c.frag.pageNumber = True c.addFrag(self.attr.example) c.frag.pageNumber = False class pisaTagPDFTOC(pisaTag): """ """ def end(self, c): c.multiBuild = True c.addTOC() class pisaTagPDFFRAME(pisaTag): """ """ def start(self, c): deprecation("pdf:frame") attrs = self.attr name = attrs["name"] if name is None: name = "frame%d" % c.UID() x, y, w, h = attrs.box self.frame = Frame( x, y, w, h, id=name, leftPadding=0, rightPadding=0, bottomPadding=0, topPadding=0, showBoundary=attrs.border) self.static = False if self.attr.static: self.static = True c.addPara() self.story = c.swapStory() else: c.frameList.append(self.frame) def end(self, c): if self.static: c.addPara() self.frame.pisaStaticStory = c.story c.frameStaticList.append(self.frame) c.swapStory(self.story) class pisaTagPDFTEMPLATE(pisaTag): """ """ def start(self, c): deprecation("pdf:template") attrs = self.attr #print attrs name = attrs["name"] c.frameList = [] c.frameStaticList = [] if c.templateList.has_key(name): log.warn(c.warning("template '%s' has already been defined", name)) ''' self.oldpagesize = A4 # self._pagesize self._pagesize = PML_PAGESIZES[attrs.format] if attrs.orientation is not None: if attrs.orientation == "landscape": self._pagesize = landscape(self._pagesize) elif attrs.orientation == "portrait": self._pagesize = portrait(self._pagesize) ''' # self._drawing = PmlPageDrawing(self._pagesize) def end(self, c): attrs = self.attr name = attrs["name"] if len(c.frameList) <= 0: log.warn(c.warning("missing frame definitions for template")) pt = PmlPageTemplate( id=name, frames=c.frameList, pagesize=A4, ) pt.pisaStaticList = c.frameStaticList pt.pisaBackgroundList = c.pisaBackgroundList pt.pisaBackground = self.attr.background # self._pagesize) # pt.pml_statics = self._statics # pt.pml_draw = self._draw # pt.pml_drawing = self._drawing # pt.pml_background = attrs.background # pt.pml_bgstory = self._bgstory c.templateList[name] = pt c.template = None c.frameList = [] c.frameStaticList = [] class pisaTagPDFFONT(pisaTag): """ """ def start(self, c): deprecation("pdf:font") c.loadFont(self.attr.name, self.attr.src, self.attr.encoding) class pisaTagPDFBARCODE(pisaTag): """ """ def start(self, c): c.addPara() attr = self.attr bc = Standard39() bc.value = attr.value bc.barHeight = 0.5 * inch bc.lquiet = 0 # left padding bc.rquiet = 0 # left padding bc.hAlign = attr.align.upper() c.addStory(bc) c.addPara() pisa-3.0.32/sx/pisa3/._pisa_paragraph.py0000644000175000017500000000035111200743305016102 0ustar wmbwmbMac OS X  2ATTR99QQcom.apple.quarantineq/0000;49cba683;Safari.app;9AFF29BE-A1F8-4D2F-A543-8AC395074CD0|com.apple.Safaripisa-3.0.32/sx/pisa3/._pisa_pdf.py0000644000175000017500000000035111165202562014713 0ustar wmbwmbMac OS X  2ATTR9;QQcom.apple.quarantineq/0000;49cba683;Safari.app;9AFF29BE-A1F8-4D2F-A543-8AC395074CD0|com.apple.Safaripisa-3.0.32/sx/pisa3/pisa_default.py0000644000175000017500000003511211163201333015345 0ustar wmbwmb# -*- coding: ISO-8859-1 -*- ############################################# ## (C)opyright by Dirk Holtwick, 2002-2007 ## ## All rights reserved ## ############################################# __reversion__ = "$Revision: 20 $" __author__ = "$Author: holtwick $" __date__ = "$Date: 2007-10-09 12:58:24 +0200 (Di, 09 Okt 2007) $" from reportlab.lib.pagesizes import * PML_WARNING = "warning" PML_ERROR = "error" PML_EXCEPTION = "PML Exception" PML_PREFIX = "pdf:" #CLASS = 1 BOOL = 2 FONT = 3 COLOR = 4 FILE = 5 SIZE = 6 INT = 7 STRING = 8 BOX = 9 POS = 10 #STYLE = 11 MUST = 23 """ Definition of all known tags. Also used for building the reference """ TAGS = { # FORMAT #"document": (1, { # "format": (["a0", "a1", "a2", "a3", "a4", "a5", "a6", # "b0", "b1", "b2", "b3", "b4", "b5", "b6", # "letter", "legal", "elevenseventeen"], "a4"), # "orientation": ["portrait", "landscape"], # "fullscreen": (BOOL, "0"), # "author": (STRING, ""), # "subject": (STRING, ""), # "title": (STRING, ""), # "duration": INT, # "showoutline": (BOOL, "0"), # "outline": INT, # }), "pdftemplate": (1, { "name": (STRING, "body"), "format": (["a0", "a1", "a2", "a3", "a4", "a5", "a6", "b0", "b1", "b2", "b3", "b4", "b5", "b6", "letter", "legal", "elevenseventeen"], "a4"), "orientation": ["portrait", "landscape"], "background": FILE, }), "pdfframe": (0, { "name": (STRING, ""), "box": (BOX, MUST), "border": (BOOL, "0"), "static": (BOOL, "0"), }), #"static": (1, { # "name": STRING, # "box": (BOX, MUST), # "border": (BOOL, "0"), # }), "pdfnexttemplate": (0, { "name": (STRING, "body"), }), "pdfnextpage": (0, { "name": (STRING, ""), # "background": FILE, }), "pdfnextframe": (0, {}), "pdffont": (0, { "src": (FILE, MUST), "name": (STRING, MUST), # "print": (BOOL, "0"), "encoding": (STRING, "WinAnsiEncoding"), }), "pdfdrawline": (0, { "from": (POS, MUST), "to": (POS, MUST), "color": (COLOR, "#000000"), "width": (SIZE, 1), }), "drawpoint": (0, { "pos": (POS, MUST), "color": (COLOR, "#000000"), "width": (SIZE, 1), }), "pdfdrawlines": (0, { "coords": (STRING, MUST), "color": (COLOR, "#000000"), "width": (SIZE, 1), }), "pdfdrawstring": (0, { "pos": (POS, MUST), "text": (STRING, MUST), "color": (COLOR, "#000000"), "align": (["left", "center", "right"], "right"), "valign": (["top", "middle", "bottom"], "bottom"), # "class": CLASS, "rotate": (INT, "0"), }), "pdfdrawimg": (0, { "pos": (POS, MUST), "src": (FILE, MUST), "width": SIZE, "height": SIZE, "align": (["left", "center", "right"], "right"), "valign": (["top", "middle", "bottom"], "bottom"), }), "pdfspacer" : (0, { "height": (SIZE, MUST), }), "pdfpagenumber": (0, { "example": (STRING, "0"), }), "pdftoc": (0, { }), "pdfversion": (0, { }), "pdfkeeptogether": (1, { }), "pdfkeepinframe": (1, { "maxwidth": SIZE, "maxheight": SIZE, "mergespace": (INT, 1), "mode": (["error", "overflow", "shrink", "truncate"], "shrink"), "name": (STRING, "") }), # The chart example, see pml_charts "pdfchart": (1, { "type": (["spider","bar"], "bar"), "strokecolor": (COLOR, "#000000"), "width": (SIZE, MUST), "height": (SIZE, MUST), }), "pdfchartdata": (0, { "set": (STRING, MUST), "value": (STRING), # "label": (STRING), "strokecolor": (COLOR), "fillcolor": (COLOR), "strokewidth": (SIZE), }), "pdfchartlabel": (0, { "value": (STRING, MUST), }), "pdfbarcode": (0, { "value": (STRING, MUST), "align": (["left", "center", "right"], "left"), }), # ======================================================== "link": (0, { "href": (STRING, MUST), "rel": (STRING, ""), "type": (STRING, ""), "media": (STRING, "all"), "charset": (STRING, "latin1"), # XXX Must be something else... }), "meta": (0, { "name": (STRING, ""), "content": (STRING, ""), }), "style": (0, { "type": (STRING, ""), "media": (STRING, "all"), }), "img": (0, { "src": (FILE, MUST), "width": SIZE, "height": SIZE, "align": ["top", "middle", "bottom", "left", "right", "texttop", "absmiddle", "absbottom", "baseline"], }), "table": (1, { "align": (["left", "center", "right"], "left"), "valign": (["top", "bottom", "middle"], "middle"), "border": (SIZE, "0"), "bordercolor": (COLOR, "#000000"), "bgcolor": COLOR, "cellpadding": (SIZE, "0"), "cellspacing": (SIZE, "0"), "repeat": (INT, "0"), # XXX Remove this! Set to 0 "width": STRING, #"keepmaxwidth": SIZE, #"keepmaxheight": SIZE, #"keepmergespace": (INT, 1), #"keepmode": (["error", "overflow", "shrink", "truncate"], "shrink"), }), "tr": (1, { "bgcolor": COLOR, "valign": ["top", "bottom", "middle"], "border": SIZE, "bordercolor": (COLOR, "#000000"), }), "td": (1, { "align": ["left", "center", "right", "justify"], "valign": ["top", "bottom", "middle"], "width": STRING, "bgcolor": COLOR, "border": SIZE, "bordercolor": (COLOR, "#000000"), "colspan": INT, "rowspan": INT, }), "th": (1, { "align": ["left", "center", "right", "justify"], "valign": ["top", "bottom", "middle"], "width": STRING, "bgcolor": COLOR, "border": SIZE, "bordercolor": (COLOR, "#000000"), "colspan": INT, "rowspan": INT, }), "dl": (1, { }), "dd": (1, { }), "dt": (1, { }), "ol": (1, { "type": (["1", "a", "A", "i", "I"], "1"), }), "ul": (1, { "type": (["circle", "disk", "square"], "disk"), }), "li": (1, { }), "hr": (0, { "color": (COLOR, "#000000"), "size": (SIZE, "1"), "align": ["left", "center", "right", "justify"], }), "div": (1, { "align": ["left", "center", "right", "justify"], }), "p": (1, { "align": ["left", "center", "right", "justify"], }), "br": (0, { }), "h1": (1, { "outline": STRING, "closed": (INT, 0), "align": ["left", "center", "right", "justify"], }), "h2": (1, { "outline": STRING, "closed": (INT, 0), "align": ["left", "center", "right", "justify"], }), "h3": (1, { "outline": STRING, "closed": (INT, 0), "align": ["left", "center", "right", "justify"], }), "h4": (1, { "outline": STRING, "closed": (INT, 0), "align": ["left", "center", "right", "justify"], }), "h5": (1, { "outline": STRING, "closed": (INT, 0), "align": ["left", "center", "right", "justify"], }), "h6": (1, { "outline": STRING, "closed": (INT, 0), "align": ["left", "center", "right", "justify"], }), "font": (1, { "face": FONT, "color": COLOR, "size": STRING, }), "a": (1, { "href": STRING, "name": STRING, }), "input": (0, { "name": STRING, "value": STRING, "type": (["text", "hidden", "checkbox"], "text"), }), "textarea": (1, { "name": STRING, }), "select": (1, { "name": STRING, "value": STRING, }), "option": (0, { "value": STRING, }), } # XXX use "html" not "*" as default! DEFAULT_CSS = """ html { font-family: Helvetica; font-size: 10px; font-weight: normal; color: #000000; background-color: transparent; margin: 0; padding: 0; line-height: 150%; border: 1px none; display: inline; width: auto; height: auto; white-space: normal; } b, strong { font-weight: bold; } i, em { font-style: italic; } u { text-decoration: underline; } s, strike { text-decoration: line-through; } a { text-decoration: underline; color: blue; } ins { color: green; text-decoration: underline; } del { color: red; text-decoration: line-through; } pre, code, kbd, samp, tt { font-family: "Courier New"; } h1, h2, h3, h4, h5, h6 { font-weight:bold; -pdf-outline: true; -pdf-outline-open: false; } h1 { /*18px via YUI Fonts CSS foundation*/ font-size:138.5%; -pdf-outline-level: 0; } h2 { /*16px via YUI Fonts CSS foundation*/ font-size:123.1%; -pdf-outline-level: 1; } h3 { /*14px via YUI Fonts CSS foundation*/ font-size:108%; -pdf-outline-level: 2; } h4 { -pdf-outline-level: 3; } h5 { -pdf-outline-level: 4; } h6 { -pdf-outline-level: 5; } h1, h2, h3, h4, h5, h6, p, pre, hr { margin:1em 0; } address, blockquote, body, center, dl, dir, div, fieldset, form, h1, h2, h3, h4, h5, h6, hr, isindex, menu, noframes, noscript, ol, p, pre, table, th, tr, td, ul, li, dd, dt, pdftoc { display: block; } table { -pdf-keep-in-frame-mode: shrink; } tr, th, td { vertical-align: middle; width: auto; } th { text-align: center; font-weight: bold; } center { text-align: center; } big { font-size: 125%; } small { font-size: 75%; } ul { margin-left: 1.5em; list-style-type: disc; } ul ul { list-style-type: circle; } ul ul ul { list-style-type: square; } ol { list-style-type: decimal; margin-left: 1.5em; } pre { white-space: pre; } blockquote { margin-left: 1.5em; margin-right: 1.5em; } noscript { display: none; } """ DEFAULT_FONT = { "courier": "Courier", "courier-bold": "Courier-Bold", "courier-boldoblique": "Courier-BoldOblique", "courier-oblique": "Courier-Oblique", "helvetica": "Helvetica", "helvetica-bold": "Helvetica-Bold", "helvetica-boldoblique": "Helvetica-BoldOblique", "helvetica-oblique": "Helvetica-Oblique", "times": "Times-Roman", "times-roman": "Times-Roman", "times-bold": "Times-Bold", "times-boldoblique": "Times-BoldOblique", "times-oblique": "Times-Oblique", "symbol": "Symbol", "zapfdingbats": "ZapfDingbats", "zapf-dingbats": "ZapfDingbats", # Alias "arial": "Helvetica", "times new roman": "Times-Roman", "georgia": "Times-Roman", 'serif':'Times-Roman', 'sansserif':'Helvetica', 'sans':'Helvetica', 'monospaced':'Courier', 'monospace':'Courier', 'mono':'Courier', 'courier new':'Courier', 'verdana':'Helvetica', 'geneva':'Helvetica', } PML_PAGESIZES = { "a0": A0, "a1": A1, "a2": A2, "a3": A3, "a4": A4, "a5": A5, "a6": A6, "b0": B0, "b1": B1, "b2": B2, "b3": B3, "b4": B4, "b5": B5, "b6": B6, "letter": LETTER, "legal": LEGAL, "ledger": ELEVENSEVENTEEN, "elevenseventeen": ELEVENSEVENTEEN, }pisa-3.0.32/sx/w3c/0000755000175000017500000000000011201057433012011 5ustar wmbwmbpisa-3.0.32/sx/w3c/css.py0000644000175000017500000006351711160170354013171 0ustar wmbwmb#!/usr/bin/env python ##~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ##~ Copyright (C) 2002-2004 TechGame Networks, LLC. ##~ ##~ This library is free software; you can redistribute it and/or ##~ modify it under the terms of the BSD style License as found in the ##~ LICENSE file included with this distribution. ## ## Modified by Dirk Holtwick , 2007-2008 ##~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ """CSS-2.1 engine Primary classes: * CSSElementInterfaceAbstract Provide a concrete implementation for the XML element model used. * CSSCascadeStrategy Implements the CSS-2.1 engine's attribute lookup rules. * CSSParser Parses CSS source forms into usable results using CSSBuilder and CSSMutableSelector. You may want to override parseExternal() * CSSBuilder (and CSSMutableSelector) A concrete implementation for cssParser.CSSBuilderAbstract (and cssParser.CSSSelectorAbstract) to provide usable results to CSSParser requests. Dependencies: python 2.3 (or greater) sets, cssParser, re (via cssParser) """ #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ #~ Imports #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ import copy import sets import cssParser import cssSpecial #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ #~ Constants / Variables / Etc. #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ CSSParseError = cssParser.CSSParseError #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ #~ Definitions #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ class CSSElementInterfaceAbstract(object): def getAttr(self, name, default=NotImplemented): raise NotImplementedError('Subclass responsibility') def getIdAttr(self): return self.getAttr('id', '') def getClassAttr(self): return self.getAttr('class', '') def getInlineStyle(self): raise NotImplementedError('Subclass responsibility') def matchesNode(self): raise NotImplementedError('Subclass responsibility') def inPseudoState(self, name, params=()): raise NotImplementedError('Subclass responsibility') def iterXMLParents(self): """Results must be compatible with CSSElementInterfaceAbstract""" raise NotImplementedError('Subclass responsibility') def getPreviousSibling(self): raise NotImplementedError('Subclass responsibility') #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ class CSSCascadeStrategy(object): author = None user = None userAgenr = None def __init__(self, author=None, user=None, userAgent=None): if author is not None: self.author = author if user is not None: self.user = user if userAgent is not None: self.userAgenr = userAgent def copyWithUpdate(self, author=None, user=None, userAgent=None): if author is None: author = self.author if user is None: user = self.user if userAgent is None: userAgent = self.userAgenr return self.__class__(author, user, userAgent) #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ def iterCSSRulesets(self, inline=None): if self.userAgenr is not None: yield self.userAgenr[0] yield self.userAgenr[1] if self.user is not None: yield self.user[0] if self.author is not None: yield self.author[0] yield self.author[1] if inline: yield inline[0] yield inline[1] if self.user is not None: yield self.user[1] #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ def findStyleFor(self, element, attrName, default=NotImplemented): """Attempts to find the style setting for attrName in the CSSRulesets. Note: This method does not attempt to resolve rules that return "inherited", "default", or values that have units (including "%"). This is left up to the client app to re-query the CSS in order to implement these semantics. """ rule = self.findCSSRulesFor(element, attrName) return self._extractStyleForRule(rule, attrName, default) def findStylesForEach(self, element, attrNames, default=NotImplemented): """Attempts to find the style setting for attrName in the CSSRulesets. Note: This method does not attempt to resolve rules that return "inherited", "default", or values that have units (including "%"). This is left up to the client app to re-query the CSS in order to implement these semantics. """ rules = self.findCSSRulesForEach(element, attrNames) return [(attrName, self._extractStyleForRule(rule, attrName, default)) for attrName, rule in rules.iteritems()] def findCSSRulesFor(self, element, attrName): rules = [] inline = element.getInlineStyle() for ruleset in self.iterCSSRulesets(inline): rules += ruleset.findCSSRuleFor(element, attrName) rules.sort() return rules def findCSSRulesForEach(self, element, attrNames): rules = dict([(name, []) for name in attrNames]) inline = element.getInlineStyle() for ruleset in self.iterCSSRulesets(inline): for attrName, attrRules in rules.iteritems(): attrRules += ruleset.findCSSRuleFor(element, attrName) for attrRules in rules.itervalues(): attrRules.sort() return rules #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ def _extractStyleForRule(self, rule, attrName, default=NotImplemented): if rule: # rule is packed in a list to differentiate from "no rule" vs "rule # whose value evalutates as False" style = rule[-1][1] return style[attrName] elif default is not NotImplemented: return default else: raise LookupError("Could not find style for '%s' in %r" % (attrName, rule)) #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ #~ CSS Selectors #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ class CSSSelectorBase(object): inline = False _hash = None _specificity = None def __init__(self, completeName='*'): if not isinstance(completeName, tuple): completeName = (None, '*', completeName) self.completeName = completeName def _updateHash(self): self._hash = hash((self.fullName, self.specificity(), self.qualifiers)) def __hash__(self): if self._hash is None: return object.__hash__(self) else: return self._hash def getNSPrefix(self): return self.completeName[0] nsPrefix = property(getNSPrefix) def getName(self): return self.completeName[2] name = property(getName) def getNamespace(self): return self.completeName[1] namespace = property(getNamespace) def getFullName(self): return self.completeName[1:3] fullName = property(getFullName) def __repr__(self): strArgs = (self.__class__.__name__,)+self.specificity()+(self.asString(),) return '<%s %d:%d:%d:%d %s >' % strArgs def __str__(self): return self.asString() def __cmp__(self, other): result = cmp(self.specificity(), other.specificity()) if result != 0: return result result = cmp(self.fullName, other.fullName) if result != 0: return result result = cmp(self.qualifiers, other.qualifiers) return result def specificity(self): if self._specificity is None: self._specificity = self._calcSpecificity() return self._specificity def _calcSpecificity(self): """from http://www.w3.org/TR/CSS21/cascade.html#specificity""" hashCount = 0 qualifierCount = 0 elementCount = int(self.name != '*') for q in self.qualifiers: if q.isHash(): hashCount += 1 elif q.isClass(): qualifierCount += 1 elif q.isAttr(): qualifierCount += 1 elif q.isPseudo(): elementCount += 1 elif q.isCombiner(): i,h,q,e = q.selector.specificity() hashCount += h qualifierCount += q elementCount += e return self.inline, hashCount, qualifierCount, elementCount def matches(self, element=None): if element is None: return False if not element.matchesNode(self.fullName): return False for qualifier in self.qualifiers: if not qualifier.matches(element): return False else: return True def asString(self): result = [] if self.nsPrefix is not None: result.append('%s|%s' % (self.nsPrefix, self.name)) else: result.append(self.name) for q in self.qualifiers: if q.isCombiner(): result.insert(0, q.asString()) else: result.append(q.asString()) return ''.join(result) #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ class CSSInlineSelector(CSSSelectorBase): inline = True #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ class CSSMutableSelector(CSSSelectorBase, cssParser.CSSSelectorAbstract): qualifiers = [] def asImmutable(self): return CSSImmutableSelector(self.completeName, [q.asImmutable() for q in self.qualifiers]) def combineSelectors(klass, selectorA, op, selectorB): selectorB.addCombination(op, selectorA) return selectorB combineSelectors = classmethod(combineSelectors) def addCombination(self, op, other): self._addQualifier(CSSSelectorCombinationQualifier(op, other)) def addHashId(self, hashId): self._addQualifier(CSSSelectorHashQualifier(hashId)) def addClass(self, class_): self._addQualifier(CSSSelectorClassQualifier(class_)) def addAttribute(self, attrName): self._addQualifier(CSSSelectorAttributeQualifier(attrName)) def addAttributeOperation(self, attrName, op, attrValue): self._addQualifier(CSSSelectorAttributeQualifier(attrName, op, attrValue)) def addPseudo(self, name): self._addQualifier(CSSSelectorPseudoQualifier(name)) def addPseudoFunction(self, name, params): self._addQualifier(CSSSelectorPseudoQualifier(name, params)) #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ def _addQualifier(self, qualifier): if self.qualifiers: self.qualifiers.append(qualifier) else: self.qualifiers = [qualifier] #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ class CSSImmutableSelector(CSSSelectorBase): def __init__(self, completeName='*', qualifiers=()): # print completeName, qualifiers self.qualifiers = tuple(qualifiers) CSSSelectorBase.__init__(self, completeName) self._updateHash() def fromSelector(klass, selector): return klass(selector.completeName, selector.qualifiers) fromSelector = classmethod(fromSelector) #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ #~ CSS Selector Qualifiers -- see CSSImmutableSelector #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ class CSSSelectorQualifierBase(object): def isHash(self): return False def isClass(self): return False def isAttr(self): return False def isPseudo(self): return False def isCombiner(self): return False def asImmutable(self): return self def __str__(self): return self.asString() class CSSSelectorHashQualifier(CSSSelectorQualifierBase): def __init__(self, hashId): self.hashId = hashId def isHash(self): return True def __hash__(self): return hash((self.hashId,)) def asString(self): return '#'+self.hashId def matches(self, element): return element.getIdAttr() == self.hashId class CSSSelectorClassQualifier(CSSSelectorQualifierBase): def __init__(self, classId): self.classId = classId def isClass(self): return True def __hash__(self): return hash((self.classId,)) def asString(self): return '.'+self.classId def matches(self, element): return self.classId in element.getClassAttr().split() class CSSSelectorAttributeQualifier(CSSSelectorQualifierBase): name, op, value = None, None, NotImplemented def __init__(self, attrName, op=None, attrValue=NotImplemented): self.name = attrName if op is not self.op: self.op = op if attrValue is not self.value: self.value = attrValue def isAttr(self): return True def __hash__(self): return hash((self.name, self.op, self.value)) def asString(self): if self.value is NotImplemented: return '[%s]' % (self.name,) else: return '[%s%s%s]' % (self.name, self.op, self.value) def matches(self, element): op = self.op if op is None: return element.getAttr(self.name, NotImplemented) != NotImplemented elif op == '=': return self.value == element.getAttr(self.name, NotImplemented) elif op == '~=': return self.value in element.getAttr(self.name, '').split() elif op == '|=': return self.value in element.getAttr(self.name, '').split('-') else: raise RuntimeError("Unknown operator %r for %r" % (self.op, self)) class CSSSelectorPseudoQualifier(CSSSelectorQualifierBase): def __init__(self, attrName, params=()): self.name = attrName self.params = tuple(params) def isPseudo(self): return True def __hash__(self): return hash((self.name, self.params)) def asString(self): if self.params: return ':'+self.name else: return ':%s(%s)' % (self.name, self.params) def matches(self, element): return element.inPseudoState(self.name, self.params) class CSSSelectorCombinationQualifier(CSSSelectorQualifierBase): def __init__(self, op, selector): self.op = op self.selector = selector def isCombiner(self): return True def __hash__(self): return hash((self.op, self.selector)) def asImmutable(self): return self.__class__(self.op, self.selector.asImmutable()) def asString(self): return '%s%s' % (self.selector.asString(), self.op) def matches(self, element): op, selector = self.op, self.selector if op == ' ': for parent in element.iterXMLParents(): if selector.matches(parent): return True else: return False elif op == '>': for parent in element.iterXMLParents(): if selector.matches(parent): return True else: return False elif op == '+': return selector.matches(element.getPreviousSibling()) #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ #~ CSS Misc #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ class CSSTerminalFunction(object): def __init__(self, name, params): self.name = name self.params = params def __repr__(self): return '' % (self.name, ', '.join(self.params)) class CSSTerminalOperator(tuple): def __new__(klass, *args): return tuple.__new__(klass, args) def __repr__(self): return 'op' + tuple.__repr__(self) #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ #~ CSS Objects #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ class CSSDeclarations(dict): pass class CSSRuleset(dict): def findCSSRulesFor(self, element, attrName): ruleResults = [] append = ruleResults.append for nodeFilter, declarations in self.iteritems(): if (attrName in declarations) and (nodeFilter.matches(element)): append((nodeFilter, declarations)) ruleResults.sort() return ruleResults def findCSSRuleFor(self, *args, **kw): # rule is packed in a list to differentiate from "no rule" vs "rule # whose value evalutates as False" return self.findCSSRulesFor(*args, **kw)[-1:] def mergeStyles(self, styles): " XXX Bugfix for use in PISA " for k, v in styles.items(): if self.has_key(k) and self[k]: self[k] = copy.copy(self[k]) self[k].update(v) else: self[k] = v class CSSInlineRuleset(CSSRuleset, CSSDeclarations): def findCSSRulesFor(self, element, attrName): if attrName in self: return [(CSSInlineSelector(), self)] else: return [] def findCSSRuleFor(self, *args, **kw): # rule is packed in a list to differentiate from "no rule" vs "rule # whose value evalutates as False" return self.findCSSRulesFor(*args, **kw)[-1:] #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ #~ CSS Builder #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ class CSSBuilder(cssParser.CSSBuilderAbstract): RulesetFactory = CSSRuleset SelectorFactory = CSSMutableSelector MediumSetFactory = sets.Set DeclarationsFactory = CSSDeclarations TermFunctionFactory = CSSTerminalFunction TermOperatorFactory = CSSTerminalOperator xmlnsSynonyms = {} mediumSet = None trackImportance = True charset = None def __init__(self, mediumSet=mediumSet, trackImportance=trackImportance): self.setMediumSet(mediumSet) self.setTrackImportance(trackImportance) def isValidMedium(self, mediums): if not mediums: return False if 'all' in mediums: return True mediums = self.MediumSetFactory(mediums) return bool(self.getMediumSet().intersection(mediums)) def getMediumSet(self): return self.mediumSet def setMediumSet(self, mediumSet): self.mediumSet = self.MediumSetFactory(mediumSet) def updateMediumSet(self, mediumSet): self.getMediumSet().update(mediumSet) def getTrackImportance(self): return self.trackImportance def setTrackImportance(self, trackImportance=True): self.trackImportance = trackImportance #~ helpers ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ def _pushState(self): _restoreState = self.__dict__ self.__dict__ = self.__dict__.copy() self._restoreState = _restoreState self.namespaces = {} def _popState(self): self.__dict__ = self._restoreState def _declarations(self, declarations, DeclarationsFactory=None): DeclarationsFactory = DeclarationsFactory or self.DeclarationsFactory if self.trackImportance: normal, important = [], [] for d in declarations: if d[-1]: important.append(d[:-1]) else: normal.append(d[:-1]) return DeclarationsFactory(normal), DeclarationsFactory(important) else: return DeclarationsFactory(declarations) def _xmlnsGetSynonym(self, uri): # Don't forget to substitute our namespace synonyms! return self.xmlnsSynonyms.get(uri or None, uri) or None #~ css results ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ def beginStylesheet(self): self._pushState() def endStylesheet(self): self._popState() def stylesheet(self, stylesheetElements, stylesheetImports): # XXX Updated for PISA if self.trackImportance: normal, important = self.RulesetFactory(), self.RulesetFactory() for normalStylesheet, importantStylesheet in stylesheetImports: normal.mergeStyles(normalStylesheet) important.mergeStyles(importantStylesheet) for normalStyleElement, importantStyleElement in stylesheetElements: normal.mergeStyles(normalStyleElement) important.mergeStyles(importantStyleElement) return normal, important else: result = self.RulesetFactory() for stylesheet in stylesheetImports: result.mergeStyles(stylesheet) for styleElement in stylesheetElements: result.mergeStyles(styleElement) return result def beginInline(self): self._pushState() def endInline(self): self._popState() def specialRules(self, declarations): return cssSpecial.parseSpecialRules(declarations) def inline(self, declarations): declarations = self.specialRules(declarations) return self._declarations(declarations, CSSInlineRuleset) def ruleset(self, selectors, declarations): # XXX Modified for pisa! declarations = self.specialRules(declarations) # XXX Modified for pisa! if self.trackImportance: normalDecl, importantDecl = self._declarations(declarations) normal, important = self.RulesetFactory(), self.RulesetFactory() for s in selectors: s = s.asImmutable() if normalDecl: normal[s] = normalDecl if importantDecl: important[s] = importantDecl return normal, important else: declarations = self._declarations(declarations) result = [(s.asImmutable(), declarations) for s in selectors] return self.RulesetFactory(result) #~ css namespaces ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ def resolveNamespacePrefix(self, nsPrefix, name): if nsPrefix == '*': return (nsPrefix, '*', name) xmlns = self.namespaces.get(nsPrefix, None) xmlns = self._xmlnsGetSynonym(xmlns) return (nsPrefix, xmlns, name) #~ css @ directives ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ def atCharset(self, charset): self.charset = charset def atImport(self, import_, mediums, cssParser): if self.isValidMedium(mediums): return cssParser.parseExternal(import_) return None def atNamespace(self, nsprefix, uri): self.namespaces[nsprefix] = uri def atMedia(self, mediums, ruleset): if self.isValidMedium(mediums): return ruleset return None def atPage(self, page, pseudopage, declarations): return self.ruleset([self.selector('*')], declarations) def atFontFace(self, declarations): return self.ruleset([self.selector('*')], declarations) def atIdent(self, atIdent, cssParser, src): return src, NotImplemented #~ css selectors ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ def selector(self, name): return self.SelectorFactory(name) def combineSelectors(self, selectorA, op, selectorB): return self.SelectorFactory.combineSelectors(selectorA, op, selectorB) #~ css declarations ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ def property(self, name, value, important=False): if self.trackImportance: return (name, value, important) else: return (name, value) def combineTerms(self, termA, op, termB): if op in (',', ' '): if isinstance(termA, list): termA.append(termB) return termA else: return [termA, termB] elif op is None and termB is None: return [termA] else: if isinstance(termA, list): # Bind these "closer" than the list operators -- i.e. work on # the (recursively) last element of the list termA[-1] = self.combineTerms(termA[-1], op, termB) return termA else: return self.TermOperatorFactory(termA, op, termB) def termIdent(self, value): return value def termNumber(self, value, units=None): if units: return value, units else: return value def termRGB(self, value): return value def termURI(self, value): return value def termString(self, value): return value def termUnicodeRange(self, value): return value def termFunction(self, name, value): return self.TermFunctionFactory(name, value) def termUnknown(self, src): return src, NotImplemented #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ #~ CSS Parser -- finally! #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ class CSSParser(cssParser.CSSParser): CSSBuilderFactory = CSSBuilder def __init__(self, cssBuilder=None, create=True, **kw): if not cssBuilder and create: assert cssBuilder is None cssBuilder = self.createCSSBuilder(**kw) cssParser.CSSParser.__init__(self, cssBuilder) def createCSSBuilder(self, **kw): return self.CSSBuilderFactory(**kw) def parseExternal(self, cssResourceName): if os.path.isfile(cssResourceName): cssFile = file(cssResourceName, 'r') return self.parseFile(cssFile, True) else: raise RuntimeError("Cannot resolve external CSS file: \"%s\"" % cssResourceName) pisa-3.0.32/sx/w3c/__init__.py0000644000175000017500000000067711160170354014136 0ustar wmbwmb#!/usr/bin/env python ##~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ##~ Copyright (C) 2002-2004 TechGame Networks, LLC. ##~ ##~ This library is free software; you can redistribute it and/or ##~ modify it under the terms of the BSD style License as found in the ##~ LICENSE file included with this distribution. ## ## Modified by Dirk Holtwick , 2007 ##~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ pisa-3.0.32/sx/w3c/cssDOMElementInterface.py0000644000175000017500000001033211160170354016647 0ustar wmbwmb#!/usr/bin/env python ##~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ##~ Copyright (C) 2002-2004 TechGame Networks, LLC. ##~ ##~ This library is free software; you can redistribute it and/or ##~ modify it under the terms of the BSD style License as found in the ##~ LICENSE file included with this distribution. ## ## Modified by Dirk Holtwick , 2007-2008 ##~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ #~ Imports #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ import css #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ #~ Definitions #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ class CSSDOMElementInterface(css.CSSElementInterfaceAbstract): """An implementation of css.CSSElementInterfaceAbstract for xml.dom Element Nodes""" #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ #~ Constants / Variables / Etc. #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ style = None _pseudoStateHandlerLookup = { 'first-child': lambda self: not bool(self.getPreviousSibling()), 'not-first-child': lambda self: bool(self.getPreviousSibling()), 'last-child': lambda self: not bool(self.getNextSibling()), 'not-last-child': lambda self: bool(self.getNextSibling()), 'middle-child': lambda self: not bool(self.getPreviousSibling()) and not bool(self.getNextSibling()), 'not-middle-child': lambda self: bool(self.getPreviousSibling()) or bool(self.getNextSibling()), # XXX 'first-line': } #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ #~ Definitions #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ def __init__(self, domElement, cssParser=None): self.domElement = domElement # print self.domElement.attributes if cssParser is not None: self.onCSSParserVisit(cssParser) def onCSSParserVisit(self, cssParser): styleSrc = self.getStyleAttr() if styleSrc: style = cssParser.parseInline(styleSrc) self.setInlineStyle(style) #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ def matchesNode(self, (namespace, tagName)): if tagName not in ('*', self.domElement.tagName): return False if namespace in (None, '', '*'): # matches any namespace return True else: # full compare return namespace == self.domElement.namespaceURI def getAttr(self, name, default=NotImplemented): attrValue = self.domElement.attributes.get(name) if attrValue is not None: return attrValue.value else: return default def getIdAttr(self): return self.getAttr('id', '') def getClassAttr(self): return self.getAttr('class', '') def getStyleAttr(self): return self.getAttr('style', None) def inPseudoState(self, name, params=()): handler = self._pseudoStateHandlerLookup.get(name, lambda self: False) return handler(self) def iterXMLParents(self, includeSelf=False): klass = self.__class__ current = self.domElement if not includeSelf: current = current.parentNode while (current is not None) and (current.nodeType == current.ELEMENT_NODE): yield klass(current) current = current.parentNode def getPreviousSibling(self): sibling = self.domElement.previousSibling while sibling: if sibling.nodeType == sibling.ELEMENT_NODE: return sibling else: sibling = sibling.previousSibling return None def getNextSibling(self): sibling = self.domElement.nextSibling while sibling: if sibling.nodeType == sibling.ELEMENT_NODE: return sibling else: sibling = sibling.nextSibling return None def getInlineStyle(self): return self.style def setInlineStyle(self, style): self.style = style pisa-3.0.32/sx/w3c/cssSpecial.py0000644000175000017500000003262711160170354014470 0ustar wmbwmb# -*- coding: ISO-8859-1 -*- ############################################# ## (C)opyright by Dirk Holtwick, 2002-2007 ## ## All rights reserved ## ############################################# __reversion__ = "$Revision: 20 $" __author__ = "$Author: holtwick $" __date__ = "$Date: 2007-10-09 12:58:24 +0200 (Di, 09 Okt 2007) $" """ Helper for complex CSS definitons like font, margin, padding and border Optimized for use with PISA """ import types import logging log = logging.getLogger("ho.css") def toList(value): if type(value)!=types.ListType: return [value] return value _styleTable = { "normal": "", "italic": "", "oblique": "", } _variantTable = { "normal": None, "small-caps": None, } _weightTable = { "light": 300, "lighter": 300, # fake relativness for now "normal": 400, "bold": 700, "bolder": 700, # fake relativness for now "100": 100, "200": 200, "300": 300, "400": 400, "500": 500, "600": 600, "700": 700, "800": 800, "900": 900, #wx.LIGHT: 300, #wx.NORMAL: 400, #wx.BOLD: 700, } #_absSizeTable = { # "xx-small" : 3./5., # "x-small": 3./4., # "small": 8./9., # "medium": 1./1., # "large": 6./5., # "x-large": 3./2., # "xx-large": 2./1., # "xxx-large": 3./1., # "larger": 1.25, # XXX Not totaly CSS conform: # "smaller": 0.75, # http://www.w3.org/TR/CSS21/fonts.html#propdef-font-size # } _borderStyleTable = { "none": 0, "hidden": 0, "dotted": 1, "dashed": 1, "solid": 1, "double": 1, "groove": 1, "ridge": 1, "inset": 1, "outset": 1, } ''' _relSizeTable = { 'pt': # pt: absolute point size # Note: this is 1/72th of an inch (lambda value, pt: value), 'px': # px: pixels, relative to the viewing device # Note: approximate at the size of a pt (lambda value, pt: value), 'ex': # ex: proportional to the 'x-height' of the parent font # Note: can't seem to dervie this value from wx.Font methods, # so we'll approximate by calling it 1/2 a pt (lambda value, pt: 2 * value), 'pc': # pc: 12:1 pica:point size # Note: this is 1/6th of an inch (lambda value, pt: 12*value), 'in': # in: 72 inches per point (lambda value, pt: 72*value), 'cm': # in: 72 inches per point, 2.54 cm per inch (lambda value, pt,_r=72./2.54: _r*value), 'mm': # in: 72 inches per point, 25.4 mm per inch (lambda value, pt,_r=72./25.4: _r*value), '%': # %: percentage of the parent's pointSize (lambda value, pt: 0.01 * pt * value), 'em': # em: proportional to the 'font-size' of the parent font (lambda value, pt: pt * value), } ''' def getNextPart(parts): if parts: part = parts.pop(0) else: part = None return part def isSize(value): return value and ((type(value) is types.TupleType) or value=="0") def splitBorder(parts): """ The order of the elements seems to be of no importance: http://www.w3.org/TR/CSS21/box.html#border-shorthand-properties """ width = style = color = None copy_parts = parts[:] # part = getNextPart(parts) if len(parts)>3: log.warn("To many elements for border style %r", parts) for part in parts: # Width if isSize(part): width = part # part = getNextPart(parts) # Style elif _borderStyleTable.has_key(part.lower()): style = part # part = getNextPart(parts) # Color else: color = part # log.debug("Border styles: %r -> %r ", copy_parts, (width, style, color)) return (width, style, color) def parseSpecialRules(declarations, debug=0): # print selectors, declarations # CSS MODIFY! dd = [] for d in declarations: if debug: log.debug("CSS special IN: %r", d) name, parts, last = d oparts = parts parts = toList(parts) # FONT if name == "font": # [ [ <'font-style'> || <'font-variant'> || <'font-weight'> ]? <'font-size'> [ / <'line-height'> ]? <'font-family'> ] | inherit ddlen = len(dd) part = getNextPart(parts) # Style if part and _styleTable.has_key(part): dd.append(("font-style", part, last)) part = getNextPart(parts) # Variant if part and _variantTable.has_key(part): dd.append(("font-variant", part, last)) part = getNextPart(parts) # Weight if part and _weightTable.has_key(part): dd.append(("font-weight", part, last)) part = getNextPart(parts) # Size and Line Height if isinstance(part, tuple) and len(part) == 3: fontSize, slash, lineHeight = part assert slash == '/' dd.append(("font-size", fontSize, last)) dd.append(("line-height", lineHeight, last)) else: dd.append(("font-size", part, last)) # Face/ Family dd.append(("font-face", parts, last)) # BACKGROUND elif name == "background": # [<'background-color'> || <'background-image'> || <'background-repeat'> || <'background-attachment'> || <'background-position'>] | inherit # XXX We do not receive url() and parts list, so we go for a dirty work arround part = getNextPart(parts) or oparts if part: if ("." in part) or ("data:" in part): dd.append(("background-image", part, last)) else: dd.append(("background-color", part, last)) if 0: part = getNextPart(parts) or oparts print "~", part, parts, oparts, declarations # Color if part and (not part.startswith("url")): dd.append(("background-color", part, last)) part = getNextPart(parts) # Background if part: dd.append(("background-image", part, last)) # XXX Incomplete! Error in url()! # MARGIN elif name == "margin": if len(parts)==1: top = bottom = left = right = parts[0] elif len(parts)==2: top = bottom = parts[0] left = right = parts[1] elif len(parts)==3: top = parts[0] left = right = parts[1] bottom = parts[2] elif len(parts)==4: top = parts[0] right = parts[1] bottom = parts[2] left = parts[3] else: continue dd.append(("margin-left", left, last)) dd.append(("margin-right", right, last)) dd.append(("margin-top", top, last)) dd.append(("margin-bottom", bottom, last)) # PADDING elif name == "padding": if len(parts)==1: top = bottom = left = right = parts[0] elif len(parts)==2: top = bottom = parts[0] left = right = parts[1] elif len(parts)==3: top = parts[0] left = right = parts[1] bottom = parts[2] elif len(parts)==4: top = parts[0] right = parts[1] bottom = parts[2] left = parts[3] else: continue dd.append(("padding-left", left, last)) dd.append(("padding-right", right, last)) dd.append(("padding-top", top, last)) dd.append(("padding-bottom", bottom, last)) # BORDER WIDTH elif name == "border-width": if len(parts)==1: top = bottom = left = right = parts[0] elif len(parts)==2: top = bottom = parts[0] left = right = parts[1] elif len(parts)==3: top = parts[0] left = right = parts[1] bottom = parts[2] elif len(parts)==4: top = parts[0] right = parts[1] bottom = parts[2] left = parts[3] else: continue dd.append(("border-left-width", left, last)) dd.append(("border-right-width", right, last)) dd.append(("border-top-width", top, last)) dd.append(("border-bottom-width", bottom, last)) # BORDER COLOR elif name == "border-color": if len(parts)==1: top = bottom = left = right = parts[0] elif len(parts)==2: top = bottom = parts[0] left = right = parts[1] elif len(parts)==3: top = parts[0] left = right = parts[1] bottom = parts[2] elif len(parts)==4: top = parts[0] right = parts[1] bottom = parts[2] left = parts[3] else: continue dd.append(("border-left-color", left, last)) dd.append(("border-right-color", right, last)) dd.append(("border-top-color", top, last)) dd.append(("border-bottom-color", bottom, last)) # BORDER STYLE elif name == "border-style": if len(parts)==1: top = bottom = left = right = parts[0] elif len(parts)==2: top = bottom = parts[0] left = right = parts[1] elif len(parts)==3: top = parts[0] left = right = parts[1] bottom = parts[2] elif len(parts)==4: top = parts[0] right = parts[1] bottom = parts[2] left = parts[3] else: continue dd.append(("border-left-style", left, last)) dd.append(("border-right-style", right, last)) dd.append(("border-top-style", top, last)) dd.append(("border-bottom-style", bottom, last)) # BORDER elif name == "border": width, style, color = splitBorder(parts) if width is not None: dd.append(("border-left-width", width, last)) dd.append(("border-right-width", width, last)) dd.append(("border-top-width", width, last)) dd.append(("border-bottom-width", width, last)) if style is not None: dd.append(("border-left-style", style, last)) dd.append(("border-right-style", style, last)) dd.append(("border-top-style", style, last)) dd.append(("border-bottom-style", style, last)) if color is not None: dd.append(("border-left-color", color, last)) dd.append(("border-right-color", color, last)) dd.append(("border-top-color", color, last)) dd.append(("border-bottom-color", color, last)) # BORDER TOP, BOTTOM, LEFT, RIGHT elif name in ("border-top", "border-bottom", "border-left", "border-right"): direction = name[7:] width, style, color = splitBorder(parts) # print direction, width if width is not None: dd.append(("border-" + direction + "-width", width, last)) if style is not None: dd.append(("border-" + direction + "-style", style, last)) if color is not None: dd.append(("border-" + direction + "-color", color, last)) # REST else: dd.append(d) if debug and dd: log.debug("CSS special OUT:\n%s", "\n".join([repr(d) for d in dd])) if 0: #declarations!=dd: print "###", declarations print "#->", dd # CSS MODIFY! END return dd #import re #_rxhttp = re.compile(r"url\([\'\"]?http\:\/\/[^\/]", re.IGNORECASE|re.DOTALL) def cleanupCSS(src): # src = _rxhttp.sub('url(', src) return srcpisa-3.0.32/sx/w3c/cssParser.py0000644000175000017500000011637511160170354014347 0ustar wmbwmb#!/usr/bin/env python ##~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ##~ Copyright (C) 2002-2004 TechGame Networks, LLC. ##~ ##~ This library is free software; you can redistribute it and/or ##~ modify it under the terms of the BSD style License as found in the ##~ LICENSE file included with this distribution. ## ## Modified by Dirk Holtwick , 2007-2008 ##~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ """CSS-2.1 parser. The CSS 2.1 Specification this parser was derived from can be found at http://www.w3.org/TR/CSS21/ Primary Classes: * CSSParser Parses CSS source forms into results using a Builder Pattern. Must provide concrete implemenation of CSSBuilderAbstract. * CSSBuilderAbstract Outlines the interface between CSSParser and it's rule-builder. Compose CSSParser with a concrete implementation of the builder to get usable results from the CSS parser. Dependencies: python 2.3 (or greater) re """ #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ #~ Imports #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ import re import cssSpecial #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ #~ Definitions #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ def isAtRuleIdent(src, ident): return re.match(r'^@' + ident + r'\s*', src) def stripAtRuleIdent(src): return re.sub(r'^@[a-z\-]+\s*', '', src) class CSSSelectorAbstract(object): """Outlines the interface between CSSParser and it's rule-builder for selectors. CSSBuilderAbstract.selector and CSSBuilderAbstract.combineSelectors must return concrete implementations of this abstract. See css.CSSMutableSelector for an example implementation. """ def addHashId(self, hashId): raise NotImplementedError('Subclass responsibility') def addClass(self, class_): raise NotImplementedError('Subclass responsibility') def addAttribute(self, attrName): raise NotImplementedError('Subclass responsibility') def addAttributeOperation(self, attrName, op, attrValue): raise NotImplementedError('Subclass responsibility') def addPseudo(self, name): raise NotImplementedError('Subclass responsibility') def addPseudoFunction(self, name, value): raise NotImplementedError('Subclass responsibility') class CSSBuilderAbstract(object): """Outlines the interface between CSSParser and it's rule-builder. Compose CSSParser with a concrete implementation of the builder to get usable results from the CSS parser. See css.CSSBuilder for an example implementation """ def setCharset(self, charset): raise NotImplementedError('Subclass responsibility') #~ css results ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ def beginStylesheet(self): raise NotImplementedError('Subclass responsibility') def stylesheet(self, elements): raise NotImplementedError('Subclass responsibility') def endStylesheet(self): raise NotImplementedError('Subclass responsibility') def beginInline(self): raise NotImplementedError('Subclass responsibility') def inline(self, declarations): raise NotImplementedError('Subclass responsibility') def endInline(self): raise NotImplementedError('Subclass responsibility') def ruleset(self, selectors, declarations): raise NotImplementedError('Subclass responsibility') #~ css namespaces ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ def resolveNamespacePrefix(self, nsPrefix, name): raise NotImplementedError('Subclass responsibility') #~ css @ directives ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ def atCharset(self, charset): raise NotImplementedError('Subclass responsibility') def atImport(self, import_, mediums, cssParser): raise NotImplementedError('Subclass responsibility') def atNamespace(self, nsPrefix, uri): raise NotImplementedError('Subclass responsibility') def atMedia(self, mediums, ruleset): raise NotImplementedError('Subclass responsibility') def atPage(self, page, pseudopage, declarations): raise NotImplementedError('Subclass responsibility') def atFontFace(self, declarations): raise NotImplementedError('Subclass responsibility') def atIdent(self, atIdent, cssParser, src): return src, NotImplemented #~ css selectors ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ def combineSelectors(self, selectorA, combiner, selectorB): """Return value must implement CSSSelectorAbstract""" raise NotImplementedError('Subclass responsibility') def selector(self, name): """Return value must implement CSSSelectorAbstract""" raise NotImplementedError('Subclass responsibility') #~ css declarations ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ def property(self, name, value, important=False): raise NotImplementedError('Subclass responsibility') def combineTerms(self, termA, combiner, termB): raise NotImplementedError('Subclass responsibility') def termIdent(self, value): raise NotImplementedError('Subclass responsibility') def termNumber(self, value, units=None): raise NotImplementedError('Subclass responsibility') def termRGB(self, value): raise NotImplementedError('Subclass responsibility') def termURI(self, value): raise NotImplementedError('Subclass responsibility') def termString(self, value): raise NotImplementedError('Subclass responsibility') def termUnicodeRange(self, value): raise NotImplementedError('Subclass responsibility') def termFunction(self, name, value): raise NotImplementedError('Subclass responsibility') def termUnknown(self, src): raise NotImplementedError('Subclass responsibility') #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ #~ CSS Parser #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ class CSSParseError(Exception): src = None ctxsrc = None fullsrc = None inline = False srcCtxIdx = None srcFullIdx = None ctxsrcFullIdx = None def __init__(self, msg, src, ctxsrc=None): Exception.__init__(self, msg) self.src = src self.ctxsrc = ctxsrc or src if self.ctxsrc: self.srcCtxIdx = self.ctxsrc.find(self.src) if self.srcCtxIdx < 0: del self.srcCtxIdx def __str__(self): if self.ctxsrc: return Exception.__str__(self) + ':: (' + repr(self.ctxsrc[:self.srcCtxIdx]) + ', ' + repr(self.ctxsrc[self.srcCtxIdx:self.srcCtxIdx+20]) + ')' else: return Exception.__str__(self) + ':: ' + repr(self.src[:40]) def setFullCSSSource(self, fullsrc, inline=False): self.fullsrc = fullsrc if inline: self.inline = inline if self.fullsrc: self.srcFullIdx = self.fullsrc.find(self.src) if self.srcFullIdx < 0: del self.srcFullIdx self.ctxsrcFullIdx = self.fullsrc.find(self.ctxsrc) if self.ctxsrcFullIdx < 0: del self.ctxsrcFullIdx #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ class CSSParser(object): """CSS-2.1 parser dependent only upon the re module. Implemented directly from http://www.w3.org/TR/CSS21/grammar.html Tested with some existing CSS stylesheets for portability. CSS Parsing API: * setCSSBuilder() To set your concrete implementation of CSSBuilderAbstract * parseFile() Use to parse external stylesheets using a file-like object >>> cssFile = open('test.css', 'r') >>> stylesheets = myCSSParser.parseFile(cssFile) * parse() Use to parse embedded stylesheets using source string >>> cssSrc = ''' body,body.body { font: 110%, "Times New Roman", Arial, Verdana, Helvetica, serif; background: White; color: Black; } a {text-decoration: underline;} ''' >>> stylesheets = myCSSParser.parse(cssSrc) * parseInline() Use to parse inline stylesheets using attribute source string >>> style = 'font: 110%, "Times New Roman", Arial, Verdana, Helvetica, serif; background: White; color: Black' >>> stylesheets = myCSSParser.parseInline(style) * parseAttributes() Use to parse attribute string values into inline stylesheets >>> stylesheets = myCSSParser.parseAttributes( font='110%, "Times New Roman", Arial, Verdana, Helvetica, serif', background='White', color='Black') * parseSingleAttr() Use to parse a single string value into a CSS expression >>> fontValue = myCSSParser.parseSingleAttr('110%, "Times New Roman", Arial, Verdana, Helvetica, serif') """ #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ #~ Constants / Variables / Etc. #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ParseError = CSSParseError AttributeOperators = ['=', '~=', '|=', '&=', '^=', '!=', '<>'] SelectorQualifiers = ('#', '.', '[', ':') SelectorCombiners = ['+', '>'] ExpressionOperators = ('/', '+', ',') #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ #~ Regular expressions #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ if True: # makes the following code foldable _orRule = lambda *args: '|'.join(args) _reflags = re.I | re.M | re.U i_hex = '[0-9a-fA-F]' i_nonascii = u'[\200-\377]' i_unicode = '\\\\(?:%s){1,6}\s?' % i_hex i_escape = _orRule(i_unicode, u'\\\\[ -~\200-\377]') # i_nmstart = _orRule('[A-Za-z_]', i_nonascii, i_escape) i_nmstart = _orRule('\-[^0-9]|[A-Za-z_]', i_nonascii, i_escape) # XXX Added hyphen, http://www.w3.org/TR/CSS21/syndata.html#value-def-identifier i_nmchar = _orRule('[-0-9A-Za-z_]', i_nonascii, i_escape) i_ident = '((?:%s)(?:%s)*)' % (i_nmstart,i_nmchar) re_ident = re.compile(i_ident, _reflags) i_element_name = '((?:%s)|\*)' % (i_ident[1:-1],) re_element_name = re.compile(i_element_name, _reflags) i_namespace_selector = '((?:%s)|\*|)\|(?!=)' % (i_ident[1:-1],) re_namespace_selector = re.compile(i_namespace_selector, _reflags) i_class = '\\.' + i_ident re_class = re.compile(i_class, _reflags) i_hash = '#((?:%s)+)' % i_nmchar re_hash = re.compile(i_hash, _reflags) i_rgbcolor = '(#%s{6}|#%s{3})' % (i_hex, i_hex) re_rgbcolor = re.compile(i_rgbcolor, _reflags) i_nl = u'\n|\r\n|\r|\f' i_escape_nl = u'\\\\(?:%s)' % i_nl i_string_content = _orRule(u'[\t !#$%&(-~]', i_escape_nl, i_nonascii, i_escape) i_string1 = u'\"((?:%s|\')*)\"' % i_string_content i_string2 = u'\'((?:%s|\")*)\'' % i_string_content i_string = _orRule(i_string1, i_string2) re_string = re.compile(i_string, _reflags) i_uri = (u'url\\(\s*(?:(?:%s)|((?:%s)+))\s*\\)' % (i_string, _orRule('[!#$%&*-~]', i_nonascii, i_escape))) # XXX For now # i_uri = u'(url\\(.*?\\))' re_uri = re.compile(i_uri, _reflags) i_num = u'(([-+]?[0-9]+(?:\\.[0-9]+)?)|([-+]?\\.[0-9]+))' # XXX Added out paranthesis, because e.g. .5em was not parsed correctly re_num = re.compile(i_num, _reflags) i_unit = '(%%|%s)?' % i_ident re_unit = re.compile(i_unit, _reflags) i_function = i_ident + '\\(' re_function = re.compile(i_function, _reflags) i_functionterm = u'[-+]?' + i_function re_functionterm = re.compile(i_functionterm, _reflags) i_unicoderange1 = "(?:U\\+%s{1,6}-%s{1,6})" % (i_hex, i_hex) i_unicoderange2 = "(?:U\\+\?{1,6}|{h}(\?{0,5}|{h}(\?{0,4}|{h}(\?{0,3}|{h}(\?{0,2}|{h}(\??|{h}))))))" i_unicoderange = i_unicoderange1 # u'(%s|%s)' % (i_unicoderange1, i_unicoderange2) re_unicoderange = re.compile(i_unicoderange, _reflags) # i_comment = u'(?:\/\*[^*]*\*+([^/*][^*]*\*+)*\/)|(?://.*)' # gabriel: only C convention for comments is allowed in CSS i_comment = u'(?:\/\*[^*]*\*+([^/*][^*]*\*+)*\/)' re_comment = re.compile(i_comment, _reflags) i_important = u'!\s*(important)' re_important = re.compile(i_important, _reflags) del _orRule #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ #~ Public #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ def __init__(self, cssBuilder=None): self.setCSSBuilder(cssBuilder) #~ CSS Builder to delegate to ~~~~~~~~~~~~~~~~~~~~~~~~ def getCSSBuilder(self): """A concrete instance implementing CSSBuilderAbstract""" return self._cssBuilder def setCSSBuilder(self, cssBuilder): """A concrete instance implementing CSSBuilderAbstract""" self._cssBuilder = cssBuilder cssBuilder = property(getCSSBuilder, setCSSBuilder) #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ #~ Public CSS Parsing API #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ def parseFile(self, srcFile, closeFile=False): """Parses CSS file-like objects using the current cssBuilder. Use for external stylesheets.""" try: result = self.parse(srcFile.read()) finally: if closeFile: srcFile.close() return result def parse(self, src): """Parses CSS string source using the current cssBuilder. Use for embedded stylesheets.""" self.cssBuilder.beginStylesheet() try: # XXX Some simple preprocessing src = cssSpecial.cleanupCSS(src) try: src, stylesheet = self._parseStylesheet(src) except self.ParseError, err: err.setFullCSSSource(src) raise finally: self.cssBuilder.endStylesheet() return stylesheet def parseInline(self, src): """Parses CSS inline source string using the current cssBuilder. Use to parse a tag's 'sytle'-like attribute.""" self.cssBuilder.beginInline() try: try: src, properties = self._parseDeclarationGroup(src.strip(), braces=False) except self.ParseError, err: err.setFullCSSSource(src, inline=True) raise result = self.cssBuilder.inline(properties) finally: self.cssBuilder.endInline() return result def parseAttributes(self, attributes={}, **kwAttributes): """Parses CSS attribute source strings, and return as an inline stylesheet. Use to parse a tag's highly CSS-based attributes like 'font'. See also: parseSingleAttr """ if attributes: kwAttributes.update(attributes) self.cssBuilder.beginInline() try: properties = [] try: for propertyName, src in kwAttributes.iteritems(): src, property = self._parseDeclarationProperty(src.strip(), propertyName) properties.append(property) except self.ParseError, err: err.setFullCSSSource(src, inline=True) raise result = self.cssBuilder.inline(properties) finally: self.cssBuilder.endInline() return result def parseSingleAttr(self, attrValue): """Parse a single CSS attribute source string, and returns the built CSS expression. Use to parse a tag's highly CSS-based attributes like 'font'. See also: parseAttributes """ results = self.parseAttributes(temp=attrValue) if 'temp' in results[1]: return results[1]['temp'] else: return results[0]['temp'] #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ #~ Internal _parse methods #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ def _parseStylesheet(self, src): """stylesheet : [ CHARSET_SYM S* STRING S* ';' ]? [S|CDO|CDC]* [ import [S|CDO|CDC]* ]* [ [ ruleset | media | page | font_face ] [S|CDO|CDC]* ]* ; """ # Get rid of the comments src = self.re_comment.sub(u'', src) # [ CHARSET_SYM S* STRING S* ';' ]? src = self._parseAtCharset(src) # [S|CDO|CDC]* src = self._parseSCDOCDC(src) # [ import [S|CDO|CDC]* ]* src, stylesheetImports = self._parseAtImports(src) # [ namespace [S|CDO|CDC]* ]* src = self._parseAtNamespace(src) stylesheetElements = [] # [ [ ruleset | atkeywords ] [S|CDO|CDC]* ]* while src: # due to ending with ]* if src.startswith('@'): # @media, @page, @font-face src, atResults = self._parseAtKeyword(src) if atResults is not None: stylesheetElements.extend(atResults) else: # ruleset src, ruleset = self._parseRuleset(src) stylesheetElements.append(ruleset) # [S|CDO|CDC]* src = self._parseSCDOCDC(src) stylesheet = self.cssBuilder.stylesheet(stylesheetElements, stylesheetImports) return src, stylesheet def _parseSCDOCDC(self, src): """[S|CDO|CDC]*""" while 1: src = src.lstrip() if src.startswith(''): src = src[3:] else: break return src #~ CSS @ directives ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ def _parseAtCharset(self, src): """[ CHARSET_SYM S* STRING S* ';' ]?""" if isAtRuleIdent(src, 'charset'): src = stripAtRuleIdent(src) charset, src = self._getString(src) src = src.lstrip() if src[:1] != ';': raise self.ParseError('@charset expected a terminating \';\'', src, ctxsrc) src = src[1:].lstrip() self.cssBuilder.atCharset(charset) return src def _parseAtImports(self, src): """[ import [S|CDO|CDC]* ]*""" result = [] while isAtRuleIdent(src, 'import'): ctxsrc = src src = stripAtRuleIdent(src) import_, src = self._getStringOrURI(src) if import_ is None: raise self.ParseError('Import expecting string or url', src, ctxsrc) mediums = [] medium, src = self._getIdent(src.lstrip()) while medium is not None: mediums.append(medium) if src[:1] == ',': src = src[1:].lstrip() medium, src = self._getIdent(src) else: break # XXX No medium inherits and then "all" is appropriate if not mediums: mediums = ["all"] if src[:1] != ';': raise self.ParseError('@import expected a terminating \';\'', src, ctxsrc) src = src[1:].lstrip() stylesheet = self.cssBuilder.atImport(import_, mediums, self) if stylesheet is not None: result.append(stylesheet) src = self._parseSCDOCDC(src) return src, result def _parseAtNamespace(self, src): """namespace : @namespace S* [IDENT S*]? [STRING|URI] S* ';' S* """ src = self._parseSCDOCDC(src) while isAtRuleIdent(src, 'namespace'): ctxsrc = src src = stripAtRuleIdent(src) namespace, src = self._getStringOrURI(src) if namespace is None: nsPrefix, src = self._getIdent(src) if nsPrefix is None: raise self.ParseError('@namespace expected an identifier or a URI', src, ctxsrc) namespace, src = self._getStringOrURI(src.lstrip()) if namespace is None: raise self.ParseError('@namespace expected a URI', src, ctxsrc) else: nsPrefix = None src = src.lstrip() if src[:1] != ';': raise self.ParseError('@namespace expected a terminating \';\'', src, ctxsrc) src = src[1:].lstrip() self.cssBuilder.atNamespace(nsPrefix, namespace) src = self._parseSCDOCDC(src) return src def _parseAtKeyword(self, src): """[media | page | font_face | unknown_keyword]""" ctxsrc = src if isAtRuleIdent(src, 'media'): src, result = self._parseAtMedia(src) elif isAtRuleIdent(src, 'page'): src, result = self._parseAtPage(src) elif isAtRuleIdent(src, 'font-face'): src, result = self._parseAtFontFace(src) # XXX added @import, was missing! elif isAtRuleIdent(src, 'import'): src, result = self._parseAtImports(src) elif isAtRuleIdent(src, 'frame'): src, result = self._parseAtFrame(src) elif src.startswith('@'): src, result = self._parseAtIdent(src) else: raise self.ParseError('Unknown state in atKeyword', src, ctxsrc) return src, result def _parseAtMedia(self, src): """media : MEDIA_SYM S* medium [ ',' S* medium ]* '{' S* ruleset* '}' S* ; """ ctxsrc = src src = src[len('@media '):].lstrip() mediums = [] while src and src[0] != '{': medium, src = self._getIdent(src) if medium is None: raise self.ParseError('@media rule expected media identifier', src, ctxsrc) mediums.append(medium) if src[0] == ',': src = src[1:].lstrip() else: src = src.lstrip() if not src.startswith('{'): raise self.ParseError('Ruleset opening \'{\' not found', src, ctxsrc) src = src[1:].lstrip() stylesheetElements = [] #while src and not src.startswith('}'): # src, ruleset = self._parseRuleset(src) # stylesheetElements.append(ruleset) # src = src.lstrip() # Containing @ where not found and parsed while src and not src.startswith('}'): if src.startswith('@'): # @media, @page, @font-face src, atResults = self._parseAtKeyword(src) if atResults is not None: stylesheetElements.extend(atResults) else: # ruleset src, ruleset = self._parseRuleset(src) stylesheetElements.append(ruleset) src = src.lstrip() if not src.startswith('}'): raise self.ParseError('Ruleset closing \'}\' not found', src, ctxsrc) else: src = src[1:].lstrip() result = self.cssBuilder.atMedia(mediums, stylesheetElements) return src, result def _parseAtPage(self, src): """page : PAGE_SYM S* IDENT? pseudo_page? S* '{' S* declaration [ ';' S* declaration ]* '}' S* ; """ ctxsrc = src src = src[len('@page '):].lstrip() page, src = self._getIdent(src) if src[:1] == ':': pseudopage, src = self._getIdent(src[1:]) else: pseudopage = None #src, properties = self._parseDeclarationGroup(src.lstrip()) # Containing @ where not found and parsed stylesheetElements = [] src = src.lstrip() properties = [] # XXX Extended for PDF use if not src.startswith('{'): raise self.ParseError('Ruleset opening \'{\' not found', src, ctxsrc) else: src = src[1:].lstrip() while src and not src.startswith('}'): if src.startswith('@'): # @media, @page, @font-face src, atResults = self._parseAtKeyword(src) if atResults is not None: stylesheetElements.extend(atResults) else: src, nproperties = self._parseDeclarationGroup(src.lstrip(), braces=False) properties += nproperties src = src.lstrip() result = [self.cssBuilder.atPage(page, pseudopage, properties)] return src[1:].lstrip(), result def _parseAtFrame(self, src): """ XXX Proprietary for PDF """ ctxsrc = src src = src[len('@frame '):].lstrip() box, src = self._getIdent(src) src, properties = self._parseDeclarationGroup(src.lstrip()) result = [self.cssBuilder.atFrame(box, properties)] return src.lstrip(), result def _parseAtFontFace(self, src): ctxsrc = src src = src[len('@font-face '):].lstrip() src, properties = self._parseDeclarationGroup(src) result = [self.cssBuilder.atFontFace(properties)] return src, result def _parseAtIdent(self, src): ctxsrc = src atIdent, src = self._getIdent(src[1:]) if atIdent is None: raise self.ParseError('At-rule expected an identifier for the rule', src, ctxsrc) src, result = self.cssBuilder.atIdent(atIdent, self, src) if result is NotImplemented: # An at-rule consists of everything up to and including the next semicolon (;) or the next block, whichever comes first semiIdx = src.find(';') if semiIdx < 0: semiIdx = None blockIdx = src[:semiIdx].find('{') if blockIdx < 0: blockIdx = None if semiIdx is not None and semiIdx < blockIdx: src = src[semiIdx+1:].lstrip() elif blockIdx is None: # consume the rest of the content since we didn't find a block or a semicolon src = src[-1:-1] elif blockIdx is not None: # expecing a block... src = src[blockIdx:] try: # try to parse it as a declarations block src, declarations = self._parseDeclarationGroup(src) except self.ParseError: # try to parse it as a stylesheet block src, stylesheet = self._parseStylesheet(src) else: raise self.ParserError('Unable to ignore @-rule block', src, ctxsrc) return src.lstrip(), result #~ ruleset - see selector and declaration groups ~~~~ def _parseRuleset(self, src): """ruleset : selector [ ',' S* selector ]* '{' S* declaration [ ';' S* declaration ]* '}' S* ; """ src, selectors = self._parseSelectorGroup(src) src, properties = self._parseDeclarationGroup(src.lstrip()) result = self.cssBuilder.ruleset(selectors, properties) return src, result #~ selector parsing ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ def _parseSelectorGroup(self, src): selectors = [] while src[:1] not in ('{','}', ']','(',')', ';', ''): src, selector = self._parseSelector(src) if selector is None: break selectors.append(selector) if src.startswith(','): src = src[1:].lstrip() return src, selectors def _parseSelector(self, src): """selector : simple_selector [ combinator simple_selector ]* ; """ src, selector = self._parseSimpleSelector(src) srcLen = len(src) # XXX while src[:1] not in ('', ',', ';', '{','}', '[',']','(',')'): for combiner in self.SelectorCombiners: if src.startswith(combiner): src = src[len(combiner):].lstrip() break else: combiner = ' ' src, selectorB = self._parseSimpleSelector(src) # XXX Fix a bug that occured here e.g. : .1 {...} if len(src) >= srcLen: src = src[1:] while src and (src[:1] not in ('', ',', ';', '{','}', '[',']','(',')')): src = src[1:] return src.lstrip(), None selector = self.cssBuilder.combineSelectors(selector, combiner, selectorB) return src.lstrip(), selector def _parseSimpleSelector(self, src): """simple_selector : [ namespace_selector ]? element_name? [ HASH | class | attrib | pseudo ]* S* ; """ ctxsrc = src.lstrip() nsPrefix, src = self._getMatchResult(self.re_namespace_selector, src) name, src = self._getMatchResult(self.re_element_name, src) if name: pass # already *successfully* assigned elif src[:1] in self.SelectorQualifiers: name = '*' else: raise self.ParseError('Selector name or qualifier expected', src, ctxsrc) name = self.cssBuilder.resolveNamespacePrefix(nsPrefix, name) selector = self.cssBuilder.selector(name) while src and src[:1] in self.SelectorQualifiers: hash_, src = self._getMatchResult(self.re_hash, src) if hash_ is not None: selector.addHashId(hash_) continue class_, src = self._getMatchResult(self.re_class, src) if class_ is not None: selector.addClass(class_) continue if src.startswith('['): src, selector = self._parseSelectorAttribute(src, selector) elif src.startswith(':'): src, selector = self._parseSelectorPseudo(src, selector) else: break return src.lstrip(), selector def _parseSelectorAttribute(self, src, selector): """attrib : '[' S* [ namespace_selector ]? IDENT S* [ [ '=' | INCLUDES | DASHMATCH ] S* [ IDENT | STRING ] S* ]? ']' ; """ ctxsrc = src if not src.startswith('['): raise self.ParseError('Selector Attribute opening \'[\' not found', src, ctxsrc) src = src[1:].lstrip() nsPrefix, src = self._getMatchResult(self.re_namespace_selector, src) attrName, src = self._getIdent(src) src=src.lstrip() if attrName is None: raise self.ParseError('Expected a selector attribute name', src, ctxsrc) if nsPrefix is not None: attrName = self.cssBuilder.resolveNamespacePrefix(nsPrefix, attrName) for op in self.AttributeOperators: if src.startswith(op): break else: op = '' src = src[len(op):].lstrip() if op: attrValue, src = self._getIdent(src) if attrValue is None: attrValue, src = self._getString(src) if attrValue is None: raise self.ParseError('Expected a selector attribute value', src, ctxsrc) else: attrValue = None if not src.startswith(']'): raise self.ParseError('Selector Attribute closing \']\' not found', src, ctxsrc) else: src = src[1:] if op: selector.addAttributeOperation(attrName, op, attrValue) else: selector.addAttribute(attrName) return src, selector def _parseSelectorPseudo(self, src, selector): """pseudo : ':' [ IDENT | function ] ; """ ctxsrc = src if not src.startswith(':'): raise self.ParseError('Selector Pseudo \':\' not found', src, ctxsrc) src = src[1:] name, src = self._getIdent(src) if not name: raise self.ParseError('Selector Pseudo identifier not found', src, ctxsrc) if src.startswith('('): # function src = src[1:].lstrip() src, term = self._parseExpression(src, True) if not src.startswith(')'): raise self.ParseError('Selector Pseudo Function closing \')\' not found', src, ctxsrc) src = src[1:] selector.addPseudoFunction(name, term) else: selector.addPseudo(name) return src, selector #~ declaration and expression parsing ~~~~~~~~~~~~~~~ def _parseDeclarationGroup(self, src, braces=True): ctxsrc = src if src.startswith('{'): src, braces = src[1:], True elif braces: raise self.ParseError('Declaration group opening \'{\' not found', src, ctxsrc) properties = [] src = src.lstrip() while src[:1] not in ('', ',', '{','}', '[',']','(',')','@'): # XXX @? src, property = self._parseDeclaration(src) # XXX Workaround for styles like "*font: smaller" if src.startswith("*"): src = "-nothing-" + src[1:] continue if property is None: break properties.append(property) if src.startswith(';'): src = src[1:].lstrip() else: break if braces: if not src.startswith('}'): raise self.ParseError('Declaration group closing \'}\' not found', src, ctxsrc) src = src[1:] return src.lstrip(), properties def _parseDeclaration(self, src): """declaration : ident S* ':' S* expr prio? | /* empty */ ; """ # property propertyName, src = self._getIdent(src) if propertyName is not None: src = src.lstrip() # S* : S* if src[:1] in (':', '='): # Note: we are being fairly flexable here... technically, the # ":" is *required*, but in the name of flexibility we # suppor a null transition, as well as an "=" transition src = src[1:].lstrip() src, property = self._parseDeclarationProperty(src, propertyName) else: property = None return src, property def _parseDeclarationProperty(self, src, propertyName): # expr src, expr = self._parseExpression(src) # prio? important, src = self._getMatchResult(self.re_important, src) src = src.lstrip() property = self.cssBuilder.property(propertyName, expr, important) return src, property def _parseExpression(self, src, returnList=False): """ expr : term [ operator term ]* ; """ src, term = self._parseExpressionTerm(src) operator = None while src[:1] not in ('', ';', '{','}', '[',']', ')'): for operator in self.ExpressionOperators: if src.startswith(operator): src = src[len(operator):] break else: operator = ' ' src, term2 = self._parseExpressionTerm(src.lstrip()) if term2 is NotImplemented: break else: term = self.cssBuilder.combineTerms(term, operator, term2) if operator is None and returnList: term = self.cssBuilder.combineTerms(term, None, None) return src, term else: return src, term def _parseExpressionTerm(self, src): """term : unary_operator? [ NUMBER S* | PERCENTAGE S* | LENGTH S* | EMS S* | EXS S* | ANGLE S* | TIME S* | FREQ S* | function ] | STRING S* | IDENT S* | URI S* | RGB S* | UNICODERANGE S* | hexcolor ; """ ctxsrc = src result, src = self._getMatchResult(self.re_num, src) if result is not None: units, src = self._getMatchResult(self.re_unit, src) term = self.cssBuilder.termNumber(result, units) return src.lstrip(), term result, src = self._getString(src, self.re_uri) if result is not None: # XXX URL!!!! term = self.cssBuilder.termURI(result) return src.lstrip(), term result, src = self._getString(src) if result is not None: term = self.cssBuilder.termString(result) return src.lstrip(), term result, src = self._getMatchResult(self.re_functionterm, src) if result is not None: src, params = self._parseExpression(src, True) if src[0] != ')': raise self.ParseError('Terminal function expression expected closing \')\'', src, ctxsrc) src = src[1:].lstrip() term = self.cssBuilder.termFunction(result, params) return src, term result, src = self._getMatchResult(self.re_rgbcolor, src) if result is not None: term = self.cssBuilder.termRGB(result) return src.lstrip(), term result, src = self._getMatchResult(self.re_unicoderange, src) if result is not None: term = self.cssBuilder.termUnicodeRange(result) return src.lstrip(), term nsPrefix, src = self._getMatchResult(self.re_namespace_selector, src) result, src = self._getIdent(src) if result is not None: if nsPrefix is not None: result = self.cssBuilder.resolveNamespacePrefix(nsPrefix, result) term = self.cssBuilder.termIdent(result) return src.lstrip(), term return self.cssBuilder.termUnknown(src) #~ utility methods ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ def _getIdent(self, src, default=None): return self._getMatchResult(self.re_ident, src, default) def _getString(self, src, rexpression=None, default=None): if rexpression is None: rexpression = self.re_string result = rexpression.match(src) if result: strres = filter(None, result.groups()) if strres: strres = strres[0] else: strres = '' return strres, src[result.end():] else: return default, src def _getStringOrURI(self, src): result, src = self._getString(src, self.re_uri) if result is None: result, src = self._getString(src) return result, src def _getMatchResult(self, rexpression, src, default=None, group=1): result = rexpression.match(src) if result: return result.group(group), src[result.end():] else: return default, src pisa-3.0.32/pisa.egg-info/0000755000175000017500000000000011201057433013311 5ustar wmbwmbpisa-3.0.32/pisa.egg-info/top_level.txt0000644000175000017500000000000611201057431016035 0ustar wmbwmbsx ho pisa-3.0.32/pisa.egg-info/PKG-INFO0000644000175000017500000000647411201057431014417 0ustar wmbwmbMetadata-Version: 1.1 Name: pisa Version: 3.0.32 Summary: PDF generator using HTML and CSS Home-page: http://www.xhtml2pdf.com Author: Dirk Holtwick Author-email: dirk.holtwick@gmail.com License: GNU General Public License (GPL) Download-URL: http://pypi.python.org/pypi/pisa/ Description: pisa is a html2pdf converter using the ReportLab Toolkit, the HTML5lib and pyPdf. It supports HTML 5 and CSS 2.1 (and some of CSS 3). It is completely written in pure Python so it is platform independent. The main benefit of this tool that a user with Web skills like HTML and CSS is able to generate PDF templates very quickly without learning new technologies. Easy integration into Python frameworks like CherryPy, KID Templating, TurboGears, Django, Zope, Plone, Google AppEngine (GAE) etc. (see 'demo' folder for examples) Keywords: PDF,HTML,XHTML,XML,CSS Platform: UNKNOWN Classifier: Development Status :: 5 - Production/Stable Classifier: Development Status :: 6 - Mature Classifier: Environment :: Console Classifier: Environment :: MacOS X Classifier: Environment :: Other Environment Classifier: Environment :: Web Environment Classifier: Environment :: Win32 (MS Windows) Classifier: Framework :: Django Classifier: Framework :: Plone Classifier: Framework :: Pylons Classifier: Framework :: TurboGears Classifier: Framework :: Zope2 Classifier: Framework :: Zope3 Classifier: Intended Audience :: Customer Service Classifier: Intended Audience :: Developers Classifier: Intended Audience :: Education Classifier: Intended Audience :: Financial and Insurance Industry Classifier: Intended Audience :: Healthcare Industry Classifier: Intended Audience :: Information Technology Classifier: Intended Audience :: Legal Industry Classifier: Intended Audience :: Manufacturing Classifier: Intended Audience :: Science/Research Classifier: Intended Audience :: System Administrators Classifier: Intended Audience :: Telecommunications Industry Classifier: License :: Free for non-commercial use Classifier: License :: OSI Approved :: GNU General Public License (GPL) Classifier: Natural Language :: English Classifier: Natural Language :: German Classifier: Operating System :: MacOS Classifier: Operating System :: MacOS :: MacOS X Classifier: Operating System :: Microsoft Classifier: Operating System :: Microsoft :: MS-DOS Classifier: Operating System :: Microsoft :: Windows Classifier: Operating System :: Other OS Classifier: Operating System :: POSIX Classifier: Operating System :: POSIX :: Linux Classifier: Operating System :: Unix Classifier: Topic :: Documentation Classifier: Topic :: Internet Classifier: Topic :: Multimedia Classifier: Topic :: Office/Business Classifier: Topic :: Office/Business :: Financial Classifier: Topic :: Office/Business :: Financial :: Accounting Classifier: Topic :: Printing Classifier: Topic :: Text Processing Classifier: Topic :: Text Processing :: Filters Classifier: Topic :: Text Processing :: Fonts Classifier: Topic :: Text Processing :: General Classifier: Topic :: Text Processing :: Indexing Classifier: Topic :: Text Processing :: Linguistic Classifier: Topic :: Text Processing :: Markup Classifier: Topic :: Text Processing :: Markup :: HTML Classifier: Topic :: Text Processing :: Markup :: XML Classifier: Topic :: Utilities Requires: html5lib Requires: pypdf Requires: pil pisa-3.0.32/pisa.egg-info/entry_points.txt0000644000175000017500000000011011201057431016575 0ustar wmbwmb[console_scripts] pisa = sx.pisa3:command xhtml2pdf = sx.pisa3:command pisa-3.0.32/pisa.egg-info/SOURCES.txt0000644000175000017500000001046711201057433015205 0ustar wmbwmbCHANGELOG.txt LICENSE.txt PKG-INFO README.txt VERSION.txt ez_setup.py pisa.py setup.cfg setup.py demo/cherrypy/demo-cherrypy.conf demo/cherrypy/demo-cherrypy.html demo/cherrypy/demo-cherrypy.py demo/djangoproject/__init__.py demo/djangoproject/django-admin.py demo/djangoproject/ezpdf.py demo/djangoproject/manage.py demo/djangoproject/settings.py demo/djangoproject/urls.py demo/djangoproject/views.py demo/djangoproject/templates/base.html demo/djangoproject/templates/entries.html demo/tgpisa/dev.cfg demo/tgpisa/sample-prod.cfg demo/tgpisa/setup.py demo/tgpisa/start-tgpisa.py demo/tgpisa/test.cfg demo/tgpisa/tgpisa/__init__.py demo/tgpisa/tgpisa/commands.py demo/tgpisa/tgpisa/controllers.py demo/tgpisa/tgpisa/json.py demo/tgpisa/tgpisa/model.py demo/tgpisa/tgpisa/release.py demo/tgpisa/tgpisa/config/__init__.py demo/tgpisa/tgpisa/config/app.cfg demo/tgpisa/tgpisa/config/log.cfg demo/tgpisa/tgpisa/static/css/style.css demo/tgpisa/tgpisa/static/images/favicon.ico demo/tgpisa/tgpisa/static/images/header_inner.png demo/tgpisa/tgpisa/static/images/info.png demo/tgpisa/tgpisa/static/images/ok.png demo/tgpisa/tgpisa/static/images/tg_under_the_hood.png demo/tgpisa/tgpisa/static/images/under_the_hood_blue.png demo/tgpisa/tgpisa/templates/__init__.py demo/tgpisa/tgpisa/templates/login.kid demo/tgpisa/tgpisa/templates/master.kid demo/tgpisa/tgpisa/templates/welcome.kid demo/wsgi/pisawsgidemo.py doc/pisa-en.html doc/pisa-en.pdf doc/pisa.css doc/screen.css ho/__init__.py ho/pisa/__init__.py pisa.egg-info/PKG-INFO pisa.egg-info/SOURCES.txt pisa.egg-info/dependency_links.txt pisa.egg-info/entry_points.txt pisa.egg-info/top_level.txt sx/__init__.py sx/pisa3/__init__.py sx/pisa3/pisa.py sx/pisa3/pisa_context.py sx/pisa3/pisa_default.py sx/pisa3/pisa_document.py sx/pisa3/pisa_paragraph.py sx/pisa3/pisa_paragraph2.py sx/pisa3/pisa_parser.py sx/pisa3/pisa_pdf.py sx/pisa3/pisa_reportlab.py sx/pisa3/pisa_tables.py sx/pisa3/pisa_tags.py sx/pisa3/pisa_turbogears.py sx/pisa3/pisa_util.py sx/pisa3/pisa_version.py sx/pisa3/pisa_wsgi.py sx/pisa3/reportlab_paragraph.py sx/w3c/__init__.py sx/w3c/css.py sx/w3c/cssDOMElementInterface.py sx/w3c/cssParser.py sx/w3c/cssSpecial.py test/cookbook.html test/cookbook.py test/datauri.py test/default.css test/helloworld.py test/linkloading.py test/pdf.css test/pdfform.html test/pdfjoiner.py test/simple-css.html test/simple-test.html test/simple.py test/story2canvas.py test/test-align.html test/test-all.html test/test-background-img.html test/test-background.html test/test-barcode.html test/test-bidirectional-text.html test/test-blocks.html test/test-cdata.html test/test-cdata.xml test/test-collapse.html test/test-css-body.html test/test-css-border.html test/test-css-fontface.html test/test-css-id.html test/test-css-media-1.css test/test-css-media-2.css test/test-css-media-4.css test/test-css-media.html test/test-css.html test/test-entities.html test/test-error.html test/test-font-img-error.html test/test-font.html test/test-helloworld.html test/test-image-align.html test/test-image.html test/test-invoice.html test/test-keep-with-next.html test/test-linespacing.html test/test-link.html test/test-list.html test/test-loremipsum.html test/test-margins.html test/test-page-box.html test/test-para-border.html test/test-pisa-linkfont.html test/test-pisa-toc-entities.html test/test-pisa-toc.html test/test-pre.html test/test-syntax.html test/test-tables.html test/test-template.html test/test-unicode-all.html test/test-unicode-greek.html test/test-unicode-japanese.html test/test-unicode-thaana.html test/test-w3c-css.html test/unicode.css test/visualdiff.py test/witherror.py test/x.txt test/css/content.css test/css/reset.css test/css/test-css-media-3.css test/font/README.txt test/img/beach.jpg test/img/denker.png test/img/test.jpg test/pdf/background-sample.pdf test/pdf/test-invoice-bg.pdf test/test-all/01.jpg test/test-all/02.jpg tests/__init__.py tests/runtests.py tests/test_parser.py tests/test_samples.py tests/test_uri.py tests/samples/borders.html tests/samples/borders.pdf tests/samples/font-and-styles.html tests/samples/font-and-styles.pdf tests/samples/images.html tests/samples/images.pdf tests/samples/tables.html tests/samples/tables.pdf tests/samples/unicode.css tests/samples/utf8.html tests/samples/utf8.pdf tests/samples/font/CODE2000.TTF tests/samples/img/denker.png tests/samples/img/tree.jpg tests/tmp/right/borders.pdfpisa-3.0.32/pisa.egg-info/dependency_links.txt0000644000175000017500000000000111201057431017355 0ustar wmbwmb pisa-3.0.32/CHANGELOG.txt0000644000175000017500000003651011201057400012712 0ustar wmbwmbCHANGELOG ========= ******************************************************************************** "I would like to thank the people mentioned in brackets in this change log very much for their help and support!" - Dirk ******************************************************************************** Version 3.0.32, 2009-05-08 - NEW: New command line option '--base' to specify base path if input comes via STDIN - FIX: The 'keep in frame' feature for tables did not work inside of static frames (Arun Shanker Prasad) - FIX: Small typos Version 3.0.31, 2009-05-04 - NEW: Support for Style "list-style-image", also supports "zoom" - NEW: Temporary files internally are written to disk if they exceed a certain size - NEW: Font names can now also read from external URL - UPD: Modified pdfjoiner.py demo - FIX: Custom font image problem still appeared - FIX: Single image in a block issue - FIX: Randomly used wrong images is fixed using a workaround for the bug in Reportlab _digester routine - FIX: Empty tables error (Davide Moro) - FIX: Fallback to urllib2 if httpdlib fails Version 3.0.30, 2009-03-27 - NEW: Default CSS now hides content of
and - Fixed that more than one static frame can use the same named element - Added -pdf-next-page to specify next page template - Added -pdf-frame-break: after, before - Fixed bug for @page without declarations - Added option for output of errors as PDF (e.g. useful in web applications) - Set "producer" to "pisa" - Set author, subject and keywords with Version 3.0.10, 2007-11-02 - Fixed some problems with wrong @page and @frame definitions - New property -pdf-frame-box - Implemented a pre parser for CSS that cleans up the code with some regular expression, like stripping illegal url(http://...) - Improved online demo - First release of binary Windows command line version or pisa - Fixed some issues with named anchors - Empty documents are now delivered correctly - Fixed error on list types - Fixed problem with debugging infos Version 3.0.9, 2007-10-31 - Modified setup.py for Chesse Shop - Added bdist_wininst to setup - Moved w3c into sx package and added license text - Modified simple.py demo script - Clean up for first public release Version 3.0.8, 2007-10-31 - Added and a bugfix for ReportLab anchors - Added - More documentation about fonts and new font aliases - Fixed some bugs in tables -
now uses ReportLabs implementation - Margin collapse by using spaceBefore and spaceAfter - Renamed -pdf-page-size to size (CSS3) Version 3.0.7, 2007-10-30 - Static frames in @frame - Wrote layout section in documentation - Updated the documentation CSS - Renamed @box to @frame - Added -pdf-page-size and -pdf-page-orientation - Added @page and @box - Fixed some problems with font definitions and Unicode - Font "Times" does not exist, changed default to "Times-Roman" - Margins, paddings and borders are only applied in display:block elements Version 3.0.6, 2007-10-29 - Implemented @font-face - "font-family" can now handle comma separated font names - Implemented for embedding TTF and PS fonts - looks for rel="stylesheet" - Style "white-space" and support for PRE - Nested lists and ordered lists, Style "list-style-type" - Prepared parser for @page and @box Version 3.0.5, 2007-10-25 - Initial implementation of @font-face - Warnings are only shown if flag -w is set - Relative @import implementations - Workaround for styles beginning with asterics like "*font: small" - Support for color=transparent (threw Exceptions before) - For @import with now media, is now set media=all - Fixed the .1 CSS parser problem - Removed cssutils again because of problems with @import - Ignore CDATA in style definitions - New method c.debug and command line option --debug - Better URL support - CSS attributes may now start with hyphen for vendor specific styles e.g. "-pdf-page-break" - Implemented @import - Implemented @media - Images are now recalculated to 96DPI too - 1px = 1/96inch (96dpi) instead of 1px = 1pt = 1/72inch - Added some new tests like test-css-media.html Version 3.0.0 - Initial versions of pisa rewrite pisa-3.0.32/setup.py0000644000175000017500000001035711177602650012414 0ustar wmbwmb#!/usr/bin/env python # -*- coding: ISO-8859-1 -*- ############################################# ## (C)opyright by Dirk Holtwick, 2002-2008 ## ## All rights reserved ## ############################################# __version__ = "$Revision: 247 $" __author__ = "$Author: holtwick $" __date__ = "$Date: 2008-08-15 13:37:57 +0200 (Fr, 15 Aug 2008) $" __svnid__ = "$Id: setup.py 247 2008-08-15 11:37:57Z holtwick $" try: from setuptools import setup, find_packages except ImportError: from ez_setup import use_setuptools use_setuptools() from setuptools import setup, find_packages setup( name = "pisa", version = "VERSION{3.0.32}VERSION"[8:-8], description = "PDF generator using HTML and CSS", license = "GNU General Public License (GPL)", author = "Dirk Holtwick", author_email = "dirk.holtwick@gmail.com", url = "http://www.xhtml2pdf.com", download_url = "http://pypi.python.org/pypi/pisa/", keywords = "PDF, HTML, XHTML, XML, CSS", requires = ["html5lib", "pypdf", "pil"], #, "reportlab"], include_package_data = False, packages = [ 'ho', 'ho.pisa', 'sx', 'sx.pisa3', 'sx.w3c', ], test_suite = "tests", entry_points = { 'console_scripts': [ 'pisa = sx.pisa3:command', 'xhtml2pdf = sx.pisa3:command', ] }, long_description = """ pisa is a html2pdf converter using the ReportLab Toolkit, the HTML5lib and pyPdf. It supports HTML 5 and CSS 2.1 (and some of CSS 3). It is completely written in pure Python so it is platform independent. The main benefit of this tool that a user with Web skills like HTML and CSS is able to generate PDF templates very quickly without learning new technologies. Easy integration into Python frameworks like CherryPy, KID Templating, TurboGears, Django, Zope, Plone, Google AppEngine (GAE) etc. (see 'demo' folder for examples) """.strip(), classifiers = [x.strip() for x in """ Development Status :: 5 - Production/Stable Development Status :: 6 - Mature Environment :: Console Environment :: MacOS X Environment :: Other Environment Environment :: Web Environment Environment :: Win32 (MS Windows) Framework :: Django Framework :: Plone Framework :: Pylons Framework :: TurboGears Framework :: Zope2 Framework :: Zope3 Intended Audience :: Customer Service Intended Audience :: Developers Intended Audience :: Education Intended Audience :: Financial and Insurance Industry Intended Audience :: Healthcare Industry Intended Audience :: Information Technology Intended Audience :: Legal Industry Intended Audience :: Manufacturing Intended Audience :: Science/Research Intended Audience :: System Administrators Intended Audience :: Telecommunications Industry License :: Free for non-commercial use License :: OSI Approved :: GNU General Public License (GPL) Natural Language :: English Natural Language :: German Operating System :: MacOS Operating System :: MacOS :: MacOS X Operating System :: Microsoft Operating System :: Microsoft :: MS-DOS Operating System :: Microsoft :: Windows Operating System :: Other OS Operating System :: POSIX Operating System :: POSIX :: Linux Operating System :: Unix Topic :: Documentation Topic :: Internet Topic :: Multimedia Topic :: Office/Business Topic :: Office/Business :: Financial Topic :: Office/Business :: Financial :: Accounting Topic :: Printing Topic :: Text Processing Topic :: Text Processing :: Filters Topic :: Text Processing :: Fonts Topic :: Text Processing :: General Topic :: Text Processing :: Indexing Topic :: Text Processing :: Linguistic Topic :: Text Processing :: Markup Topic :: Text Processing :: Markup :: HTML Topic :: Text Processing :: Markup :: XML Topic :: Utilities """.strip().splitlines()], ) pisa-3.0.32/ez_setup.py0000644000175000017500000002233411160170402013073 0ustar wmbwmb#!python """Bootstrap setuptools installation If you want to use setuptools in your package's setup.py, just include this file in the same directory with it, and add this to the top of your setup.py:: from ez_setup import use_setuptools use_setuptools() If you want to require a specific version of setuptools, set a download mirror, or use an alternate download directory, you can do so by supplying the appropriate options to ``use_setuptools()``. This file can also be run as a script to install or upgrade setuptools. """ import sys DEFAULT_VERSION = "0.6c9" DEFAULT_URL = "http://pypi.python.org/packages/%s/s/setuptools/" % sys.version[:3] md5_data = { 'setuptools-0.6b1-py2.3.egg': '8822caf901250d848b996b7f25c6e6ca', 'setuptools-0.6b1-py2.4.egg': 'b79a8a403e4502fbb85ee3f1941735cb', 'setuptools-0.6b2-py2.3.egg': '5657759d8a6d8fc44070a9d07272d99b', 'setuptools-0.6b2-py2.4.egg': '4996a8d169d2be661fa32a6e52e4f82a', 'setuptools-0.6b3-py2.3.egg': 'bb31c0fc7399a63579975cad9f5a0618', 'setuptools-0.6b3-py2.4.egg': '38a8c6b3d6ecd22247f179f7da669fac', 'setuptools-0.6b4-py2.3.egg': '62045a24ed4e1ebc77fe039aa4e6f7e5', 'setuptools-0.6b4-py2.4.egg': '4cb2a185d228dacffb2d17f103b3b1c4', 'setuptools-0.6c1-py2.3.egg': 'b3f2b5539d65cb7f74ad79127f1a908c', 'setuptools-0.6c1-py2.4.egg': 'b45adeda0667d2d2ffe14009364f2a4b', 'setuptools-0.6c2-py2.3.egg': 'f0064bf6aa2b7d0f3ba0b43f20817c27', 'setuptools-0.6c2-py2.4.egg': '616192eec35f47e8ea16cd6a122b7277', 'setuptools-0.6c3-py2.3.egg': 'f181fa125dfe85a259c9cd6f1d7b78fa', 'setuptools-0.6c3-py2.4.egg': 'e0ed74682c998bfb73bf803a50e7b71e', 'setuptools-0.6c3-py2.5.egg': 'abef16fdd61955514841c7c6bd98965e', 'setuptools-0.6c4-py2.3.egg': 'b0b9131acab32022bfac7f44c5d7971f', 'setuptools-0.6c4-py2.4.egg': '2a1f9656d4fbf3c97bf946c0a124e6e2', 'setuptools-0.6c4-py2.5.egg': '8f5a052e32cdb9c72bcf4b5526f28afc', 'setuptools-0.6c5-py2.3.egg': 'ee9fd80965da04f2f3e6b3576e9d8167', 'setuptools-0.6c5-py2.4.egg': 'afe2adf1c01701ee841761f5bcd8aa64', 'setuptools-0.6c5-py2.5.egg': 'a8d3f61494ccaa8714dfed37bccd3d5d', 'setuptools-0.6c6-py2.3.egg': '35686b78116a668847237b69d549ec20', 'setuptools-0.6c6-py2.4.egg': '3c56af57be3225019260a644430065ab', 'setuptools-0.6c6-py2.5.egg': 'b2f8a7520709a5b34f80946de5f02f53', 'setuptools-0.6c7-py2.3.egg': '209fdf9adc3a615e5115b725658e13e2', 'setuptools-0.6c7-py2.4.egg': '5a8f954807d46a0fb67cf1f26c55a82e', 'setuptools-0.6c7-py2.5.egg': '45d2ad28f9750e7434111fde831e8372', 'setuptools-0.6c8-py2.3.egg': '50759d29b349db8cfd807ba8303f1902', 'setuptools-0.6c8-py2.4.egg': 'cba38d74f7d483c06e9daa6070cce6de', 'setuptools-0.6c8-py2.5.egg': '1721747ee329dc150590a58b3e1ac95b', } import sys, os try: from hashlib import md5 except ImportError: from md5 import md5 def _validate_md5(egg_name, data): if egg_name in md5_data: digest = md5(data).hexdigest() if digest != md5_data[egg_name]: print >>sys.stderr, ( "md5 validation of %s failed! (Possible download problem?)" % egg_name ) sys.exit(2) return data def use_setuptools( version=DEFAULT_VERSION, download_base=DEFAULT_URL, to_dir=os.curdir, download_delay=15 ): """Automatically find/download setuptools and make it available on sys.path `version` should be a valid setuptools version number that is available as an egg for download under the `download_base` URL (which should end with a '/'). `to_dir` is the directory where setuptools will be downloaded, if it is not already available. If `download_delay` is specified, it should be the number of seconds that will be paused before initiating a download, should one be required. If an older version of setuptools is installed, this routine will print a message to ``sys.stderr`` and raise SystemExit in an attempt to abort the calling script. """ was_imported = 'pkg_resources' in sys.modules or 'setuptools' in sys.modules def do_download(): egg = download_setuptools(version, download_base, to_dir, download_delay) sys.path.insert(0, egg) import setuptools; setuptools.bootstrap_install_from = egg try: import pkg_resources except ImportError: return do_download() try: pkg_resources.require("setuptools>="+version); return except pkg_resources.VersionConflict, e: if was_imported: print >>sys.stderr, ( "The required version of setuptools (>=%s) is not available, and\n" "can't be installed while this script is running. Please install\n" " a more recent version first, using 'easy_install -U setuptools'." "\n\n(Currently using %r)" ) % (version, e.args[0]) sys.exit(2) else: del pkg_resources, sys.modules['pkg_resources'] # reload ok return do_download() except pkg_resources.DistributionNotFound: return do_download() def download_setuptools( version=DEFAULT_VERSION, download_base=DEFAULT_URL, to_dir=os.curdir, delay = 15 ): """Download setuptools from a specified location and return its filename `version` should be a valid setuptools version number that is available as an egg for download under the `download_base` URL (which should end with a '/'). `to_dir` is the directory where the egg will be downloaded. `delay` is the number of seconds to pause before an actual download attempt. """ import urllib2, shutil egg_name = "setuptools-%s-py%s.egg" % (version,sys.version[:3]) url = download_base + egg_name saveto = os.path.join(to_dir, egg_name) src = dst = None if not os.path.exists(saveto): # Avoid repeated downloads try: from distutils import log if delay: log.warn(""" --------------------------------------------------------------------------- This script requires setuptools version %s to run (even to display help). I will attempt to download it for you (from %s), but you may need to enable firewall access for this script first. I will start the download in %d seconds. (Note: if this machine does not have network access, please obtain the file %s and place it in this directory before rerunning this script.) ---------------------------------------------------------------------------""", version, download_base, delay, url ); from time import sleep; sleep(delay) log.warn("Downloading %s", url) src = urllib2.urlopen(url) # Read/write all in one block, so we don't create a corrupt file # if the download is interrupted. data = _validate_md5(egg_name, src.read()) dst = open(saveto,"wb"); dst.write(data) finally: if src: src.close() if dst: dst.close() return os.path.realpath(saveto) def main(argv, version=DEFAULT_VERSION): """Install or upgrade setuptools and EasyInstall""" try: import setuptools except ImportError: egg = None try: egg = download_setuptools(version, delay=0) sys.path.insert(0,egg) from setuptools.command.easy_install import main return main(list(argv)+[egg]) # we're done here finally: if egg and os.path.exists(egg): os.unlink(egg) else: if setuptools.__version__ == '0.0.1': print >>sys.stderr, ( "You have an obsolete version of setuptools installed. Please\n" "remove it from your system entirely before rerunning this script." ) sys.exit(2) req = "setuptools>="+version import pkg_resources try: pkg_resources.require(req) except pkg_resources.VersionConflict: try: from setuptools.command.easy_install import main except ImportError: from easy_install import main main(list(argv)+[download_setuptools(delay=0)]) sys.exit(0) # try to force an exit else: if argv: from setuptools.command.easy_install import main main(argv) else: print "Setuptools version",version,"or greater has been installed." print '(Run "ez_setup.py -U setuptools" to reinstall or upgrade.)' def update_md5(filenames): """Update our built-in md5 registry""" import re for name in filenames: base = os.path.basename(name) f = open(name,'rb') md5_data[base] = md5(f.read()).hexdigest() f.close() data = [" %r: %r,\n" % it for it in md5_data.items()] data.sort() repl = "".join(data) import inspect srcfile = inspect.getsourcefile(sys.modules[__name__]) f = open(srcfile, 'rb'); src = f.read(); f.close() match = re.search("\nmd5_data = {\n([^}]+)}", src) if not match: print >>sys.stderr, "Internal error!" sys.exit(2) src = src[:match.start(1)] + repl + src[match.end(1):] f = open(srcfile,'w') f.write(src) f.close() if __name__=='__main__': if len(sys.argv)>2 and sys.argv[1]=='--md5update': update_md5(sys.argv[2:]) else: main(sys.argv[1:]) pisa-3.0.32/tests/0000755000175000017500000000000011201057433012025 5ustar wmbwmbpisa-3.0.32/tests/__init__.py0000644000175000017500000000004411160170401014127 0ustar wmbwmbfrom runtests import buildTestSuite pisa-3.0.32/tests/samples/0000755000175000017500000000000011201057433013471 5ustar wmbwmbpisa-3.0.32/tests/samples/borders.pdf0000644000175000017500000003137211162761635015646 0ustar wmbwmb%PDF-1.3 % ReportLab Generated PDF document http://www.reportlab.com % 'BasicFonts': class PDFDictionary 1 0 obj % The standard fonts dictionary << /F1 2 0 R /F2 3 0 R /F3 5 0 R >> endobj % 'F1': class PDFType1Font 2 0 obj % Font Helvetica << /BaseFont /Helvetica /Encoding /WinAnsiEncoding /Name /F1 /Subtype /Type1 /Type /Font >> endobj % 'F2': class PDFType1Font 3 0 obj % Font Helvetica-Bold << /BaseFont /Helvetica-Bold /Encoding /WinAnsiEncoding /Name /F2 /Subtype /Type1 /Type /Font >> endobj % 'FormXob.8b4ac10e5b9ed4a3611ffb37fb197336': class PDFImageXObject 4 0 obj << /BitsPerComponent 8 /ColorSpace /DeviceRGB /Filter [ /ASCII85Decode /FlateDecode ] /Height 137 /Length 6081 /Subtype /Image /Type /XObject /Width 70 >> stream Gb!$LYEC/6'uilXLb]gc-mYrH%mU7M++dQZV8*YT5WTS`M'L$(P.$jc?N>^\JQO*s1jA9OoBS'U\MpRhB6JGJDH,[r=(U7WSo_[<2fi;3^4Ou2h_G-)hf$:.cbH*eq,\O&TT'Jsr5IdL^M;fn++J!SeaT4/0Q`J]!CHYG(")TM5>8ij9nUe&f"_0gNJ;$AkMP%+7QYKYp&GWL%2p38;EJQ.JF7Ol!UA]Ps4fNg:T8I?<#^G<:c(0!*B4+VRWTq,&2c2Mj"H),cTg8M9b=5O8LVMtD4V2044(E.dRdn_5A=JO'Dddg\j^L25]'-VTDu"+2^$iC_Bm%+:C[rD+meUS7n5D?3(`;fjI:ZVIj't@!GU]E*$Aq<@poQ+JFUQ-?Xa]9AX),[.5_C/lUr^o>Ql-="=%qXLgCPY(VmEp;k&X+hZVHe[*?J-dAE"NPodB-ceCak[K7j=qh;D[#D[0Eh?B\a;3jB[f.g&MUi\?u$haePB4H[2i-KaJXfCSX=I;"Ree#54B3WD;n5$hJAS[q(YO@fTSb<&PJ2G6rKQZs2>re`VWD5*_l8/?g;NjNcao0?PpBEohXF#^@0:j7U8LP'*fhK>qYJ[X7jAZT\o!gmFp,"jY?',#1d4g#R`WNi.,1L7I?Bkr^NQqg"i,.c@\1'-4?j&d086FMm\SE&-1m6/g/bQ][EB:Js3[j^CtS^,ieuN6E\.![B*P+D#JER_A0QndX\]$/WR4i9Kd,\7/@jWT9>LniG-QeMgNhP^S3)*E8kK#3$l6g9)WoHOli;-44MC:W).((CR`AR'"qH3Lh!OUJ(HP7,X$eXGD)#FjkVX/3W>ret\%-?BT6!QIgbpRUMC:Q,UTP@^BjMUu5WsrNj>l8OO.o4l>1#?M>UX^V]%XD:&CMmm*g/@(ZWbV;S6"K-O&/Lp0BIK79BN-DKgWdSRZ9:Z\E`<6\AEc1BKQ=Hk++7`78$)VV;9E_s\BO(F1.Rp'#aj-7`q+')jfX,1Q(.San\9Z&3'i]O;Xh%=d?'"/Z?5m#5"&4Pnm4eA!*-LnLO51]*R9,\.F*+"FTusn+pj'ZlDe+[d#r=%4-WG+#Z9#\51)2l#:.QL2GmCPr'Tl#aq&2)mcca1jFgT&N^A&ZW0KSm.8u_F%k@BnJV\Q7;@&pF3H/]t5nt(?`WJ`p'\*PX0EpUe#P#fNlnIZ;3G3mKI_:PdWj-^_A>!0k"9VM"k6=LW0ChR5^L^7*&dJ]^f9p(ZZ#662tomo-$.uHdgVqcGNg.-l'\gGScdbI&,]a=QQpVZW6TcP)ts\+1m=geL=+ARXd6XL5^!n@RDFLHZKEP"Bp,OQr8L`;mcplFAKXFCDCZ=a?PUp%n-1$pIiYKOTE@P:!WQ\m>>m$M&ls9nX?9"[q1g'e3i;5",@uaSjUuD0%&(2@L[SpKH"q98/f[gl>5hT=%!O,%&XOIg*g1"L#e-K")C)$c@pG&LkLEI/BONP`*$;qW[0bmI!MQKni9cN@p>l97?>G,@1aMCfYm\O]+;u?(.dT^11:Y.63M0g9GbD8YfUOZhg$'DEGQdM!g674q"1@=rqW:.C,d-M>NPa;o&#&"6#i#Y_ZoD1Kl7Z*Qd?Jn&K8liniN"gs/FES#*`;ha1Pq`[?VAp+X5qRa\hshBR!d"'\Jn?eW[`CLYcJ!!(H#q;*dUIc3lZD+jr]>fH`CH`f-3VcO/qX:A3Y3+B_h@F'N\4"9Lr'M)?28;khLDDH8Dbd5kP]jnaeMaP-Gn/^_Ao,[Z>R3?fGZL3j<"Am(kU1&]nHFAWE`:I[D:-u1E*&VP".@tiYTFk9TgkmOY:aVrSnj9*ID6n^47#Qs%nP0K/a&>Hb>/(WZQD'Uo_b'#?:HaF(F.!3/\`h3tGM9$*qSP%Wn*X!fg%BN@g:[XI,ERbBAEo!nuVik9GS#fi\lm-K`MXo_4pVmK1RlscuX@KX']AHYV!#dKSo8OT+M'ucgk=qNnfCMru#]=t^0M.sLW[H!MNm:$\#Gtt5Ko9*R-"_ZT!)+a91U,dP@l`tb!o=WE-Z&;OZT:i^l8LgHP8a]GPrZS+nandp-C,T58,@lCQ+JkfrMBl)oilV]&MU^ZUT]updbFYFA#%D[HSG2]a,Tp6;I4)-3/@8`?Y-Rd9S^h#bke_=fY2;p%qsgUS=W'aZ)nY>`RRhEp2.6M]$*G^pDXuVj#01m-Sur9X^+ert?56>C`O"CT69%6uM\p=(qiCH'H;2i$flHkGFXXdZ;Df"?\X-NY2-mtk7eB$pc@bSfcTg,h0K$BJ,2^8InIE\bj&C!4`^it!H>VX(?K>E5-i@UNr&Hg:06Xgb#C8!II._Vhq8MfFT&1_nUJ8=f)cesEZ'fsp'pO'+F(G8=k"F2*UeqrC>K;J9ZqoXPg:#*X6S7+Q=Ns]WkEKH>S$aMI]tPsX/k60l8Q!7dQX-cAKXPOL[OF(8&Z%hTZ@UV0JfM()8f0l/ZHB+MAr;%m$[oT+/%m?Q>qh-j=*-A7QNf#gYI]3d$,+-<5.:G!(E)X(RJ2i#mr"pR;d)4S=@5Tl5jK]ahCj:Rn0Zpf`P%\t,>2Td\-QbaV+Z\h_?&[-o^87ngkF(,iH/63EXjp#V?S?(5C(0uBJ];3h2Qlh);+mQpaSY+p@URdEf?Z@mICe7'$-0ZABb%?L6C#?5+?B[275?-PM>&.Y+a`2I@V6kqhmn,`n'.b<7:Pb2,,hPD"gd:h$/p<9U<8]-Z*Z\!J@/@^(H8lE=7(),Y7ZJn)01$ckLT"a?Y&uu#3?%?"SA_JkBQh7H]6uKY!0L>q.\`.6:Lgh^/^:g1]Iq6n0Me@5FYcZ7Zt$4rZLVJTZm6t0c-_I5>ibIEpO+eSK_MEj.]IGQB7""FAsRdTo^Z$Idc)>sT%6h&h4`H6#+[RTe%*:Gb=hr`?"5P,D&.U1Rro=f$BI0Q*7ChlI-1,Dd4Z>LJ*8BY7!7Jkbjq[nMuF=F=[&l8IPRYc/l&;&6TiN8D7\%`e?-'&DO-p@;5q4\XX/Gcr/Ou1H\f8IG>`I\`$K^ASJFtd8s0bUE)O2,=YG(ne-P;[I@(tf1ok>Ab=?MaJd,".=!=:eiGnQH,>[20,.<2LD$!G4K4K(DZ=YHq336NlKO#hUP)1-_DdAi*rB%OFX)4F\Ae:E5su_]QQ$./GKYf6'>biH[b([p1d.jEa+tA#&Dt;1GY1"9Ad`X(cbh(&>Xp:#G>g*`d+<@QOo@acMnSBSq%dNgGPplO9(,$0#eXs%q9qK_fN&-cRWBs;H;K*J#5(cS;)5?3dG^rmn+S'D+t#cOFMN&3c)K4co$TOI&a?PM>mk,g'"j%?cVn;<,LaWpDir4&JHH1h0k+*W(7-T'n+80p,,n@u$\8eL9U9fQM(OMb+)SNt7:&dnCaAijsbl2ju$L/D$H-ci^LsG^MQ'=B3/9X5q2$tGZ=WlEB?!1[*q4=(R#)K;%GmM3f-*q_n0'1YZ`2$Ak((F=t.2ir`GZZd\#fiF897]16)Ef8hB5b7"?kErE$kGI3\'EUnDXUs*!)R$,UWeCMc@_Y&>:T:m,!3M@H\S0>bMQJXmeo/2#_MaV&>^!V-QF;0rr5;pm@ETlr=b*tQL#',En\Q^6?J*?"&qLh>6SLr,-EmqLImct7$lq.:k<:/Xd**>/Gd-p,rkfpV#=O>S\aC?AP;[-'(T*l''g"GZd5Th,XfiTcCJZV:-(frV62_%Hd_[QJFI*1%,0_2QqR)L-b7S&W4,ue[VK1W:Qh"8<'WK/&X-9BHoRj2$^gN$-*u8cZCmk4`?d\"j:8?aNTnHfl@@00M?M`]3iQAlQKVt#:hqm;GZ2:4b-OH5f+^j#.,9!e_l;+JH:k!-/tj(R`N=OhgMU_Al'.p)pR(RT4Fb"jFrbTh/9Q%P=@u/Wkm.M9=0_'(K3E`84Ir[G>"0rljBui>Yg`YfSBRUPg5]?Gl7U9#Gi0W,agAg&ZFWiR8^QV2kFmK"/<$CkdmHTkGj&h@bE.opm=-cmc"k;)V&!#&+X*;KRs2J.QZ[L*r4lN5'(l5:TWl2&FELFJ`m@?Ce:"TkmON4s\oCUG7/udX5BIpe8BIf?7'N;l:Fb*RT&XekKMIkI-CNjgX!RVLSQgViM<6X,le8a&WFHfkeRl@7Iur77WN=*$PI3R3Fugg"pD!AXn4>k.[O2^K!4Mc^m/=Ke<-/A%Np^6.i_Bs'Fgf"Gar-eImm?4L>)gSC?I6#ANl/1F.GK$,Ag/cGh5BhZfN]0VcLWBWOm\M'VmHGF3#Eo6)$E@F=hT1;HMnp!$endstream endobj % 'F3': class PDFType1Font 5 0 obj % Font Courier << /BaseFont /Courier /Encoding /WinAnsiEncoding /Name /F3 /Subtype /Type1 /Type /Font >> endobj % 'Page1': class PDFPage 6 0 obj % Page dictionary << /Contents 18 0 R /MediaBox [ 0 0 595.2756 841.8898 ] /Parent 17 0 R /Resources << /Font 1 0 R /ProcSet [ /PDF /Text /ImageB /ImageC /ImageI ] /XObject << /FormXob.8b4ac10e5b9ed4a3611ffb37fb197336 4 0 R >> >> /Rotate 0 /Trans << >> /Type /Page >> endobj % 'Page2': class PDFPage 7 0 obj % Page dictionary << /Contents 19 0 R /MediaBox [ 0 0 595.2756 841.8898 ] /Parent 17 0 R /Resources << /Font 1 0 R /ProcSet [ /PDF /Text /ImageB /ImageC /ImageI ] >> /Rotate 0 /Trans << >> /Type /Page >> endobj % 'R8': class PDFCatalog 8 0 obj % Document Root << /Outlines 10 0 R /PageMode /UseNone /Pages 17 0 R /Type /Catalog >> endobj % 'R9': class PDFInfo 9 0 obj << /Author () /CreationDate (D:20090326212045-01'00') /Keywords () /Producer (pisa HTML to PDF ) /Subject () /Title () >> endobj % 'R10': class PDFOutlines 10 0 obj << /Count 6 /First 11 0 R /Last 16 0 R /Type /Outlines >> endobj % 'Outline.0': class OutlineEntryObject 11 0 obj << /Dest [ 6 0 R /Fit ] /Next 12 0 R /Parent 10 0 R /Title (Hello World: class=c1) >> endobj % 'Outline.1': class OutlineEntryObject 12 0 obj << /Dest [ 6 0 R /Fit ] /Next 13 0 R /Parent 10 0 R /Prev 11 0 R /Title (Goodbye: class=c2 ) >> endobj % 'Outline.2': class OutlineEntryObject 13 0 obj << /Dest [ 6 0 R /Fit ] /Next 14 0 R /Parent 10 0 R /Prev 12 0 R /Title (Goodbye: class=c2 padding: 16px;) >> endobj % 'Outline.3': class OutlineEntryObject 14 0 obj << /Dest [ 6 0 R /Fit ] /Next 15 0 R /Parent 10 0 R /Prev 13 0 R /Title (Goodbye: class=c2 padding: 16px;) >> endobj % 'Outline.4': class OutlineEntryObject 15 0 obj << /Dest [ 6 0 R /Fit ] /Next 16 0 R /Parent 10 0 R /Prev 14 0 R /Title (Goodbye: class=c2Next line ) >> endobj % 'Outline.5': class OutlineEntryObject 16 0 obj << /Dest [ 6 0 R /Fit ] /Parent 10 0 R /Prev 15 0 R /Title (Mixed colors: class=c3) >> endobj % 'R17': class PDFPages 17 0 obj % page tree << /Count 2 /Kids [ 6 0 R 7 0 R ] /Type /Pages >> endobj % 'R18': class PDFStream 18 0 obj % page stream << /Filter [ /ASCII85Decode /FlateDecode ] /Length 2146 >> stream Gb"/)gMYb8&:HLqJ!cQ(DNJ].^1<*b1ruL(Bnc0m??QOA';L&p>==94UR_VuTK?C[X93'VcIr+6lMmL^VMe6kC1"NQESh$bDqEF6;l^8Ao&iq!!uCWr%4M"8%VmM!l.US+iqH?.cL-Hm9No9gb"\r0G;bTi_KW<>["d9>Q6,GI*tnW!%J#M8-O\45&ORPSD0<<n$nb2m>'6JQV7bXt,*C(j#5C3kMTiRV,8pNK\g&]-#7EH#fi^*HVn^3d2XdP6c)TicR-O%ms)_hdKVSFRJ$gOsaLst*@O-ZF)$YZcTfHA/&G6^sL%P"rD"t?(+Jt!.8+gdZ?6"aS=LEl2=3bm5i4k":e,!&2_p-#.(@CKr\]HN=2A4PE0r$>fgOF[0%Dioft&4LS^q#Zpihu#=@AP_k>%;K]C&,Tu+Jt/5P],A178*q@N#E9%LH"'T6Ac`942^D'm((X1B(O%'3he\[5DTktiLEJkh8Jp(>3=K8P'@ks:NE!JOL)OVqphe9$r[';HJ+=oUQ8/^`[;+s\8-VC:[TY8:=Y1LH.Q"f\S$75:*iBoTZ="NQURDP,[4c1R4(mPec10p?JdXP/J'[gYoQO4e$I$qUEn72gicf`J5n[gRriT\>**4.nB$_-jT&Y)s1Ns8X#_U0X'XtciU.a?qIDo-&RO?YuSP9B0D^e#AU%&oQpWhN8>T.iWd^pd0Fs_5mjT7$u>:8$8O[ZF`g`Y+'bWDAh+?/&5`B_re1?GW'tGgF2K!I3.-22T5"\Uc&AL=@PAD&05?S^57gF[h@@`*a%X8T2?_g11.?l`-)o4rMe5$2"s*V%6p/=L2>Q:^;Mpd:!-t)B\(Og]f"X:b7=>R>fA#IbB4cn$XCa&eZSMRGZLu"Y\dhurS]2):L(FUI]io:RXdA+ZoP_.5(:1prdp3Nau!LF8p4Lh!$(Iu_PRmJb;t?uV&LiC$A-c.:YUQ_X>k.C0Hk#(%4bZ57<`h5ncFCk?H6XDhufIekb,k+/BYfKFd_A(<&S%B"E>3s;&n+h"Z?#1_%K*8>IDpa8;#):J09\5e,b-8.^3'GU@TtJ*PFW(-./3QT#P[?8$iTNVspBLEjE?ZME1fc@uE%DJh#&%W08Jt_n;Ps%Dp1l36f,+)@(m(Y`ha8n/Rm>@ltKW=3bARdb\L1+nVPU7j]'QEc98W'Kl)G,*871lZ7'qU3!QCkVCaGW-fm'#NI&;F5:G\s[3e_nfka7Ym_a`ED;DE=KiDr5TlGACD/O\%qq*S2r;cVT,2U3+G8%K^0T;)m26\`m@8(9V4[IZK'BV(/#lIGJ:ANX>W)NSiL1E=J?0aOKUD#AtNj/n^-8V]h,5P,%sTWJ8,h[lC%SDXPhLLIO,Mc2L9!cpS=7/Tr&thFuGGjRITB-[YsSb"uG4W#n1ponW%YO`*J\LUst]nQDSLcW*XPcQ"s0]k,+b9!'f\P]/hJ,hMuJ_a^Pq"62-#FBY:BhdiKAE,6!HBE&"DUb*b~>endstream endobj % 'R19': class PDFStream 19 0 obj % page stream << /Filter [ /ASCII85Decode /FlateDecode ] /Length 665 >> stream Gb!#WbAQ&g&A/tO5Kkhk;HD<%f:qLY(B`q-YghB<+d*0SBg09^fl#7A!IQF$&<_3LGBRRI;=Gg^;d4VjnEI!,/28+eCJeSd_#:Ln4Dm+Toos)Sfo)kJlPA*8?2laB/?R+DpCGg_4-Ql\jO]3AK8ag=lD(Spqsp]UG,TAYXGUc-Bk*mYqRCN-;<^:&(ugN(k,r(?)?7^L>0JH=kel*3mDDZKk.CVZ4f[SZkXLfYj38#IuB,cW+=T>f,N47Pc%>V'r!7_"%c?+7E_C9W5PibYLUB_mY$h*PF^oqEqSmTV\fAQoAB_Ue8rhLUS%JD-0oK+rR0OkdYZUmW6rg9ZC.R$GIr"Bqr0-.bC3X^:MigZA&\n9[@`jI)5ML.bCoh.4Q_b/^2Q<8S-UHPVKl'k=#J>EkQeY\Jm!endstream endobj xref 0 20 0000000000 65535 f 0000000113 00000 n 0000000233 00000 n 0000000398 00000 n 0000000614 00000 n 0000006934 00000 n 0000007093 00000 n 0000007437 00000 n 0000007716 00000 n 0000007852 00000 n 0000008057 00000 n 0000008182 00000 n 0000008337 00000 n 0000008504 00000 n 0000008685 00000 n 0000008866 00000 n 0000009043 00000 n 0000009183 00000 n 0000009298 00000 n 0000011589 00000 n trailer << /ID % ReportLab generated PDF document -- digest (http://www.reportlab.com) [(\372\310B-\361\\\366K;\313\363\363\336\360\272e) (\372\310B-\361\\\366K;\313\363\363\336\360\272e)] /Info 9 0 R /Root 8 0 R /Size 20 >> startxref 12371 %%EOF pisa-3.0.32/tests/samples/images.pdf0000644000175000017500000007066411162761636015463 0ustar wmbwmb%PDF-1.3 % ReportLab Generated PDF document http://www.reportlab.com % 'BasicFonts': class PDFDictionary 1 0 obj % The standard fonts dictionary << /F1 2 0 R /F2 3 0 R >> endobj % 'F1': class PDFType1Font 2 0 obj % Font Helvetica << /BaseFont /Helvetica /Encoding /WinAnsiEncoding /Name /F1 /Subtype /Type1 /Type /Font >> endobj % 'F2': class PDFType1Font 3 0 obj % Font Helvetica-Bold << /BaseFont /Helvetica-Bold /Encoding /WinAnsiEncoding /Name /F2 /Subtype /Type1 /Type /Font >> endobj % 'FormXob.3ba39c9a6e36b0773a0b2a5555c49cc2': class PDFImageXObject 4 0 obj << /BitsPerComponent 8 /ColorSpace /DeviceRGB /Filter [ /ASCII85Decode /FlateDecode ] /Height 137 /Length 6081 /Subtype /Image /Type /XObject /Width 70 >> stream Gb!$LYEC/6'uilXLb]gc-mYrH%mU7M++dQZV8*YT5WTS`M'L$(P.$jc?N>^\JQO*s1jA9OoBS'U\MpRhB6JGJDH,[r=(U7WSo_[<2fi;3^4Ou2h_G-)hf$:.cbH*eq,\O&TT'Jsr5IdL^M;fn++J!SeaT4/0Q`J]!CHYG(")TM5>8ij9nUe&f"_0gNJ;$AkMP%+7QYKYp&GWL%2p38;EJQ.JF7Ol!UA]Ps4fNg:T8I?<#^G<:c(0!*B4+VRWTq,&2c2Mj"H),cTg8M9b=5O8LVMtD4V2044(E.dRdn_5A=JO'Dddg\j^L25]'-VTDu"+2^$iC_Bm%+:C[rD+meUS7n5D?3(`;fjI:ZVIj't@!GU]E*$Aq<@poQ+JFUQ-?Xa]9AX),[.5_C/lUr^o>Ql-="=%qXLgCPY(VmEp;k&X+hZVHe[*?J-dAE"NPodB-ceCak[K7j=qh;D[#D[0Eh?B\a;3jB[f.g&MUi\?u$haePB4H[2i-KaJXfCSX=I;"Ree#54B3WD;n5$hJAS[q(YO@fTSb<&PJ2G6rKQZs2>re`VWD5*_l8/?g;NjNcao0?PpBEohXF#^@0:j7U8LP'*fhK>qYJ[X7jAZT\o!gmFp,"jY?',#1d4g#R`WNi.,1L7I?Bkr^NQqg"i,.c@\1'-4?j&d086FMm\SE&-1m6/g/bQ][EB:Js3[j^CtS^,ieuN6E\.![B*P+D#JER_A0QndX\]$/WR4i9Kd,\7/@jWT9>LniG-QeMgNhP^S3)*E8kK#3$l6g9)WoHOli;-44MC:W).((CR`AR'"qH3Lh!OUJ(HP7,X$eXGD)#FjkVX/3W>ret\%-?BT6!QIgbpRUMC:Q,UTP@^BjMUu5WsrNj>l8OO.o4l>1#?M>UX^V]%XD:&CMmm*g/@(ZWbV;S6"K-O&/Lp0BIK79BN-DKgWdSRZ9:Z\E`<6\AEc1BKQ=Hk++7`78$)VV;9E_s\BO(F1.Rp'#aj-7`q+')jfX,1Q(.San\9Z&3'i]O;Xh%=d?'"/Z?5m#5"&4Pnm4eA!*-LnLO51]*R9,\.F*+"FTusn+pj'ZlDe+[d#r=%4-WG+#Z9#\51)2l#:.QL2GmCPr'Tl#aq&2)mcca1jFgT&N^A&ZW0KSm.8u_F%k@BnJV\Q7;@&pF3H/]t5nt(?`WJ`p'\*PX0EpUe#P#fNlnIZ;3G3mKI_:PdWj-^_A>!0k"9VM"k6=LW0ChR5^L^7*&dJ]^f9p(ZZ#662tomo-$.uHdgVqcGNg.-l'\gGScdbI&,]a=QQpVZW6TcP)ts\+1m=geL=+ARXd6XL5^!n@RDFLHZKEP"Bp,OQr8L`;mcplFAKXFCDCZ=a?PUp%n-1$pIiYKOTE@P:!WQ\m>>m$M&ls9nX?9"[q1g'e3i;5",@uaSjUuD0%&(2@L[SpKH"q98/f[gl>5hT=%!O,%&XOIg*g1"L#e-K")C)$c@pG&LkLEI/BONP`*$;qW[0bmI!MQKni9cN@p>l97?>G,@1aMCfYm\O]+;u?(.dT^11:Y.63M0g9GbD8YfUOZhg$'DEGQdM!g674q"1@=rqW:.C,d-M>NPa;o&#&"6#i#Y_ZoD1Kl7Z*Qd?Jn&K8liniN"gs/FES#*`;ha1Pq`[?VAp+X5qRa\hshBR!d"'\Jn?eW[`CLYcJ!!(H#q;*dUIc3lZD+jr]>fH`CH`f-3VcO/qX:A3Y3+B_h@F'N\4"9Lr'M)?28;khLDDH8Dbd5kP]jnaeMaP-Gn/^_Ao,[Z>R3?fGZL3j<"Am(kU1&]nHFAWE`:I[D:-u1E*&VP".@tiYTFk9TgkmOY:aVrSnj9*ID6n^47#Qs%nP0K/a&>Hb>/(WZQD'Uo_b'#?:HaF(F.!3/\`h3tGM9$*qSP%Wn*X!fg%BN@g:[XI,ERbBAEo!nuVik9GS#fi\lm-K`MXo_4pVmK1RlscuX@KX']AHYV!#dKSo8OT+M'ucgk=qNnfCMru#]=t^0M.sLW[H!MNm:$\#Gtt5Ko9*R-"_ZT!)+a91U,dP@l`tb!o=WE-Z&;OZT:i^l8LgHP8a]GPrZS+nandp-C,T58,@lCQ+JkfrMBl)oilV]&MU^ZUT]updbFYFA#%D[HSG2]a,Tp6;I4)-3/@8`?Y-Rd9S^h#bke_=fY2;p%qsgUS=W'aZ)nY>`RRhEp2.6M]$*G^pDXuVj#01m-Sur9X^+ert?56>C`O"CT69%6uM\p=(qiCH'H;2i$flHkGFXXdZ;Df"?\X-NY2-mtk7eB$pc@bSfcTg,h0K$BJ,2^8InIE\bj&C!4`^it!H>VX(?K>E5-i@UNr&Hg:06Xgb#C8!II._Vhq8MfFT&1_nUJ8=f)cesEZ'fsp'pO'+F(G8=k"F2*UeqrC>K;J9ZqoXPg:#*X6S7+Q=Ns]WkEKH>S$aMI]tPsX/k60l8Q!7dQX-cAKXPOL[OF(8&Z%hTZ@UV0JfM()8f0l/ZHB+MAr;%m$[oT+/%m?Q>qh-j=*-A7QNf#gYI]3d$,+-<5.:G!(E)X(RJ2i#mr"pR;d)4S=@5Tl5jK]ahCj:Rn0Zpf`P%\t,>2Td\-QbaV+Z\h_?&[-o^87ngkF(,iH/63EXjp#V?S?(5C(0uBJ];3h2Qlh);+mQpaSY+p@URdEf?Z@mICe7'$-0ZABb%?L6C#?5+?B[275?-PM>&.Y+a`2I@V6kqhmn,`n'.b<7:Pb2,,hPD"gd:h$/p<9U<8]-Z*Z\!J@/@^(H8lE=7(),Y7ZJn)01$ckLT"a?Y&uu#3?%?"SA_JkBQh7H]6uKY!0L>q.\`.6:Lgh^/^:g1]Iq6n0Me@5FYcZ7Zt$4rZLVJTZm6t0c-_I5>ibIEpO+eSK_MEj.]IGQB7""FAsRdTo^Z$Idc)>sT%6h&h4`H6#+[RTe%*:Gb=hr`?"5P,D&.U1Rro=f$BI0Q*7ChlI-1,Dd4Z>LJ*8BY7!7Jkbjq[nMuF=F=[&l8IPRYc/l&;&6TiN8D7\%`e?-'&DO-p@;5q4\XX/Gcr/Ou1H\f8IG>`I\`$K^ASJFtd8s0bUE)O2,=YG(ne-P;[I@(tf1ok>Ab=?MaJd,".=!=:eiGnQH,>[20,.<2LD$!G4K4K(DZ=YHq336NlKO#hUP)1-_DdAi*rB%OFX)4F\Ae:E5su_]QQ$./GKYf6'>biH[b([p1d.jEa+tA#&Dt;1GY1"9Ad`X(cbh(&>Xp:#G>g*`d+<@QOo@acMnSBSq%dNgGPplO9(,$0#eXs%q9qK_fN&-cRWBs;H;K*J#5(cS;)5?3dG^rmn+S'D+t#cOFMN&3c)K4co$TOI&a?PM>mk,g'"j%?cVn;<,LaWpDir4&JHH1h0k+*W(7-T'n+80p,,n@u$\8eL9U9fQM(OMb+)SNt7:&dnCaAijsbl2ju$L/D$H-ci^LsG^MQ'=B3/9X5q2$tGZ=WlEB?!1[*q4=(R#)K;%GmM3f-*q_n0'1YZ`2$Ak((F=t.2ir`GZZd\#fiF897]16)Ef8hB5b7"?kErE$kGI3\'EUnDXUs*!)R$,UWeCMc@_Y&>:T:m,!3M@H\S0>bMQJXmeo/2#_MaV&>^!V-QF;0rr5;pm@ETlr=b*tQL#',En\Q^6?J*?"&qLh>6SLr,-EmqLImct7$lq.:k<:/Xd**>/Gd-p,rkfpV#=O>S\aC?AP;[-'(T*l''g"GZd5Th,XfiTcCJZV:-(frV62_%Hd_[QJFI*1%,0_2QqR)L-b7S&W4,ue[VK1W:Qh"8<'WK/&X-9BHoRj2$^gN$-*u8cZCmk4`?d\"j:8?aNTnHfl@@00M?M`]3iQAlQKVt#:hqm;GZ2:4b-OH5f+^j#.,9!e_l;+JH:k!-/tj(R`N=OhgMU_Al'.p)pR(RT4Fb"jFrbTh/9Q%P=@u/Wkm.M9=0_'(K3E`84Ir[G>"0rljBui>Yg`YfSBRUPg5]?Gl7U9#Gi0W,agAg&ZFWiR8^QV2kFmK"/<$CkdmHTkGj&h@bE.opm=-cmc"k;)V&!#&+X*;KRs2J.QZ[L*r4lN5'(l5:TWl2&FELFJ`m@?Ce:"TkmON4s\oCUG7/udX5BIpe8BIf?7'N;l:Fb*RT&XekKMIkI-CNjgX!RVLSQgViM<6X,le8a&WFHfkeRl@7Iur77WN=*$PI3R3Fugg"pD!AXn4>k.[O2^K!4Mc^m/=Ke<-/A%Np^6.i_Bs'Fgf"Gar-eImm?4L>)gSC?I6#ANl/1F.GK$,Ag/cGh5BhZfN]0VcLWBWOm\M'VmHGF3#Eo6)$E@F=hT1;HMnp!$endstream endobj % 'FormXob.77e7cc02a2ba171dbd87c00d37df4193': class PDFImageXObject 5 0 obj << /BitsPerComponent 8 /ColorSpace /DeviceRGB /Filter [ /ASCII85Decode /FlateDecode ] /Height 137 /Length 6081 /Subtype /Image /Type /XObject /Width 70 >> stream Gb!$LYEC/6'uilXLb]gc-mYrH%mU7M++dQZV8*YT5WTS`M'L$(P.$jc?N>^\JQO*s1jA9OoBS'U\MpRhB6JGJDH,[r=(U7WSo_[<2fi;3^4Ou2h_G-)hf$:.cbH*eq,\O&TT'Jsr5IdL^M;fn++J!SeaT4/0Q`J]!CHYG(")TM5>8ij9nUe&f"_0gNJ;$AkMP%+7QYKYp&GWL%2p38;EJQ.JF7Ol!UA]Ps4fNg:T8I?<#^G<:c(0!*B4+VRWTq,&2c2Mj"H),cTg8M9b=5O8LVMtD4V2044(E.dRdn_5A=JO'Dddg\j^L25]'-VTDu"+2^$iC_Bm%+:C[rD+meUS7n5D?3(`;fjI:ZVIj't@!GU]E*$Aq<@poQ+JFUQ-?Xa]9AX),[.5_C/lUr^o>Ql-="=%qXLgCPY(VmEp;k&X+hZVHe[*?J-dAE"NPodB-ceCak[K7j=qh;D[#D[0Eh?B\a;3jB[f.g&MUi\?u$haePB4H[2i-KaJXfCSX=I;"Ree#54B3WD;n5$hJAS[q(YO@fTSb<&PJ2G6rKQZs2>re`VWD5*_l8/?g;NjNcao0?PpBEohXF#^@0:j7U8LP'*fhK>qYJ[X7jAZT\o!gmFp,"jY?',#1d4g#R`WNi.,1L7I?Bkr^NQqg"i,.c@\1'-4?j&d086FMm\SE&-1m6/g/bQ][EB:Js3[j^CtS^,ieuN6E\.![B*P+D#JER_A0QndX\]$/WR4i9Kd,\7/@jWT9>LniG-QeMgNhP^S3)*E8kK#3$l6g9)WoHOli;-44MC:W).((CR`AR'"qH3Lh!OUJ(HP7,X$eXGD)#FjkVX/3W>ret\%-?BT6!QIgbpRUMC:Q,UTP@^BjMUu5WsrNj>l8OO.o4l>1#?M>UX^V]%XD:&CMmm*g/@(ZWbV;S6"K-O&/Lp0BIK79BN-DKgWdSRZ9:Z\E`<6\AEc1BKQ=Hk++7`78$)VV;9E_s\BO(F1.Rp'#aj-7`q+')jfX,1Q(.San\9Z&3'i]O;Xh%=d?'"/Z?5m#5"&4Pnm4eA!*-LnLO51]*R9,\.F*+"FTusn+pj'ZlDe+[d#r=%4-WG+#Z9#\51)2l#:.QL2GmCPr'Tl#aq&2)mcca1jFgT&N^A&ZW0KSm.8u_F%k@BnJV\Q7;@&pF3H/]t5nt(?`WJ`p'\*PX0EpUe#P#fNlnIZ;3G3mKI_:PdWj-^_A>!0k"9VM"k6=LW0ChR5^L^7*&dJ]^f9p(ZZ#662tomo-$.uHdgVqcGNg.-l'\gGScdbI&,]a=QQpVZW6TcP)ts\+1m=geL=+ARXd6XL5^!n@RDFLHZKEP"Bp,OQr8L`;mcplFAKXFCDCZ=a?PUp%n-1$pIiYKOTE@P:!WQ\m>>m$M&ls9nX?9"[q1g'e3i;5",@uaSjUuD0%&(2@L[SpKH"q98/f[gl>5hT=%!O,%&XOIg*g1"L#e-K")C)$c@pG&LkLEI/BONP`*$;qW[0bmI!MQKni9cN@p>l97?>G,@1aMCfYm\O]+;u?(.dT^11:Y.63M0g9GbD8YfUOZhg$'DEGQdM!g674q"1@=rqW:.C,d-M>NPa;o&#&"6#i#Y_ZoD1Kl7Z*Qd?Jn&K8liniN"gs/FES#*`;ha1Pq`[?VAp+X5qRa\hshBR!d"'\Jn?eW[`CLYcJ!!(H#q;*dUIc3lZD+jr]>fH`CH`f-3VcO/qX:A3Y3+B_h@F'N\4"9Lr'M)?28;khLDDH8Dbd5kP]jnaeMaP-Gn/^_Ao,[Z>R3?fGZL3j<"Am(kU1&]nHFAWE`:I[D:-u1E*&VP".@tiYTFk9TgkmOY:aVrSnj9*ID6n^47#Qs%nP0K/a&>Hb>/(WZQD'Uo_b'#?:HaF(F.!3/\`h3tGM9$*qSP%Wn*X!fg%BN@g:[XI,ERbBAEo!nuVik9GS#fi\lm-K`MXo_4pVmK1RlscuX@KX']AHYV!#dKSo8OT+M'ucgk=qNnfCMru#]=t^0M.sLW[H!MNm:$\#Gtt5Ko9*R-"_ZT!)+a91U,dP@l`tb!o=WE-Z&;OZT:i^l8LgHP8a]GPrZS+nandp-C,T58,@lCQ+JkfrMBl)oilV]&MU^ZUT]updbFYFA#%D[HSG2]a,Tp6;I4)-3/@8`?Y-Rd9S^h#bke_=fY2;p%qsgUS=W'aZ)nY>`RRhEp2.6M]$*G^pDXuVj#01m-Sur9X^+ert?56>C`O"CT69%6uM\p=(qiCH'H;2i$flHkGFXXdZ;Df"?\X-NY2-mtk7eB$pc@bSfcTg,h0K$BJ,2^8InIE\bj&C!4`^it!H>VX(?K>E5-i@UNr&Hg:06Xgb#C8!II._Vhq8MfFT&1_nUJ8=f)cesEZ'fsp'pO'+F(G8=k"F2*UeqrC>K;J9ZqoXPg:#*X6S7+Q=Ns]WkEKH>S$aMI]tPsX/k60l8Q!7dQX-cAKXPOL[OF(8&Z%hTZ@UV0JfM()8f0l/ZHB+MAr;%m$[oT+/%m?Q>qh-j=*-A7QNf#gYI]3d$,+-<5.:G!(E)X(RJ2i#mr"pR;d)4S=@5Tl5jK]ahCj:Rn0Zpf`P%\t,>2Td\-QbaV+Z\h_?&[-o^87ngkF(,iH/63EXjp#V?S?(5C(0uBJ];3h2Qlh);+mQpaSY+p@URdEf?Z@mICe7'$-0ZABb%?L6C#?5+?B[275?-PM>&.Y+a`2I@V6kqhmn,`n'.b<7:Pb2,,hPD"gd:h$/p<9U<8]-Z*Z\!J@/@^(H8lE=7(),Y7ZJn)01$ckLT"a?Y&uu#3?%?"SA_JkBQh7H]6uKY!0L>q.\`.6:Lgh^/^:g1]Iq6n0Me@5FYcZ7Zt$4rZLVJTZm6t0c-_I5>ibIEpO+eSK_MEj.]IGQB7""FAsRdTo^Z$Idc)>sT%6h&h4`H6#+[RTe%*:Gb=hr`?"5P,D&.U1Rro=f$BI0Q*7ChlI-1,Dd4Z>LJ*8BY7!7Jkbjq[nMuF=F=[&l8IPRYc/l&;&6TiN8D7\%`e?-'&DO-p@;5q4\XX/Gcr/Ou1H\f8IG>`I\`$K^ASJFtd8s0bUE)O2,=YG(ne-P;[I@(tf1ok>Ab=?MaJd,".=!=:eiGnQH,>[20,.<2LD$!G4K4K(DZ=YHq336NlKO#hUP)1-_DdAi*rB%OFX)4F\Ae:E5su_]QQ$./GKYf6'>biH[b([p1d.jEa+tA#&Dt;1GY1"9Ad`X(cbh(&>Xp:#G>g*`d+<@QOo@acMnSBSq%dNgGPplO9(,$0#eXs%q9qK_fN&-cRWBs;H;K*J#5(cS;)5?3dG^rmn+S'D+t#cOFMN&3c)K4co$TOI&a?PM>mk,g'"j%?cVn;<,LaWpDir4&JHH1h0k+*W(7-T'n+80p,,n@u$\8eL9U9fQM(OMb+)SNt7:&dnCaAijsbl2ju$L/D$H-ci^LsG^MQ'=B3/9X5q2$tGZ=WlEB?!1[*q4=(R#)K;%GmM3f-*q_n0'1YZ`2$Ak((F=t.2ir`GZZd\#fiF897]16)Ef8hB5b7"?kErE$kGI3\'EUnDXUs*!)R$,UWeCMc@_Y&>:T:m,!3M@H\S0>bMQJXmeo/2#_MaV&>^!V-QF;0rr5;pm@ETlr=b*tQL#',En\Q^6?J*?"&qLh>6SLr,-EmqLImct7$lq.:k<:/Xd**>/Gd-p,rkfpV#=O>S\aC?AP;[-'(T*l''g"GZd5Th,XfiTcCJZV:-(frV62_%Hd_[QJFI*1%,0_2QqR)L-b7S&W4,ue[VK1W:Qh"8<'WK/&X-9BHoRj2$^gN$-*u8cZCmk4`?d\"j:8?aNTnHfl@@00M?M`]3iQAlQKVt#:hqm;GZ2:4b-OH5f+^j#.,9!e_l;+JH:k!-/tj(R`N=OhgMU_Al'.p)pR(RT4Fb"jFrbTh/9Q%P=@u/Wkm.M9=0_'(K3E`84Ir[G>"0rljBui>Yg`YfSBRUPg5]?Gl7U9#Gi0W,agAg&ZFWiR8^QV2kFmK"/<$CkdmHTkGj&h@bE.opm=-cmc"k;)V&!#&+X*;KRs2J.QZ[L*r4lN5'(l5:TWl2&FELFJ`m@?Ce:"TkmON4s\oCUG7/udX5BIpe8BIf?7'N;l:Fb*RT&XekKMIkI-CNjgX!RVLSQgViM<6X,le8a&WFHfkeRl@7Iur77WN=*$PI3R3Fugg"pD!AXn4>k.[O2^K!4Mc^m/=Ke<-/A%Np^6.i_Bs'Fgf"Gar-eImm?4L>)gSC?I6#ANl/1F.GK$,Ag/cGh5BhZfN]0VcLWBWOm\M'VmHGF3#Eo6)$E@F=hT1;HMnp!$endstream endobj % 'FormXob.10c72419a5ee41fec40f7cf4446074b6': class PDFImageXObject 6 0 obj << /BitsPerComponent 8 /ColorSpace /DeviceRGB /Filter [ /ASCII85Decode /FlateDecode ] /Height 137 /Length 6081 /Subtype /Image /Type /XObject /Width 70 >> stream Gb!$LYEC/6'uilXLb]gc-mYrH%mU7M++dQZV8*YT5WTS`M'L$(P.$jc?N>^\JQO*s1jA9OoBS'U\MpRhB6JGJDH,[r=(U7WSo_[<2fi;3^4Ou2h_G-)hf$:.cbH*eq,\O&TT'Jsr5IdL^M;fn++J!SeaT4/0Q`J]!CHYG(")TM5>8ij9nUe&f"_0gNJ;$AkMP%+7QYKYp&GWL%2p38;EJQ.JF7Ol!UA]Ps4fNg:T8I?<#^G<:c(0!*B4+VRWTq,&2c2Mj"H),cTg8M9b=5O8LVMtD4V2044(E.dRdn_5A=JO'Dddg\j^L25]'-VTDu"+2^$iC_Bm%+:C[rD+meUS7n5D?3(`;fjI:ZVIj't@!GU]E*$Aq<@poQ+JFUQ-?Xa]9AX),[.5_C/lUr^o>Ql-="=%qXLgCPY(VmEp;k&X+hZVHe[*?J-dAE"NPodB-ceCak[K7j=qh;D[#D[0Eh?B\a;3jB[f.g&MUi\?u$haePB4H[2i-KaJXfCSX=I;"Ree#54B3WD;n5$hJAS[q(YO@fTSb<&PJ2G6rKQZs2>re`VWD5*_l8/?g;NjNcao0?PpBEohXF#^@0:j7U8LP'*fhK>qYJ[X7jAZT\o!gmFp,"jY?',#1d4g#R`WNi.,1L7I?Bkr^NQqg"i,.c@\1'-4?j&d086FMm\SE&-1m6/g/bQ][EB:Js3[j^CtS^,ieuN6E\.![B*P+D#JER_A0QndX\]$/WR4i9Kd,\7/@jWT9>LniG-QeMgNhP^S3)*E8kK#3$l6g9)WoHOli;-44MC:W).((CR`AR'"qH3Lh!OUJ(HP7,X$eXGD)#FjkVX/3W>ret\%-?BT6!QIgbpRUMC:Q,UTP@^BjMUu5WsrNj>l8OO.o4l>1#?M>UX^V]%XD:&CMmm*g/@(ZWbV;S6"K-O&/Lp0BIK79BN-DKgWdSRZ9:Z\E`<6\AEc1BKQ=Hk++7`78$)VV;9E_s\BO(F1.Rp'#aj-7`q+')jfX,1Q(.San\9Z&3'i]O;Xh%=d?'"/Z?5m#5"&4Pnm4eA!*-LnLO51]*R9,\.F*+"FTusn+pj'ZlDe+[d#r=%4-WG+#Z9#\51)2l#:.QL2GmCPr'Tl#aq&2)mcca1jFgT&N^A&ZW0KSm.8u_F%k@BnJV\Q7;@&pF3H/]t5nt(?`WJ`p'\*PX0EpUe#P#fNlnIZ;3G3mKI_:PdWj-^_A>!0k"9VM"k6=LW0ChR5^L^7*&dJ]^f9p(ZZ#662tomo-$.uHdgVqcGNg.-l'\gGScdbI&,]a=QQpVZW6TcP)ts\+1m=geL=+ARXd6XL5^!n@RDFLHZKEP"Bp,OQr8L`;mcplFAKXFCDCZ=a?PUp%n-1$pIiYKOTE@P:!WQ\m>>m$M&ls9nX?9"[q1g'e3i;5",@uaSjUuD0%&(2@L[SpKH"q98/f[gl>5hT=%!O,%&XOIg*g1"L#e-K")C)$c@pG&LkLEI/BONP`*$;qW[0bmI!MQKni9cN@p>l97?>G,@1aMCfYm\O]+;u?(.dT^11:Y.63M0g9GbD8YfUOZhg$'DEGQdM!g674q"1@=rqW:.C,d-M>NPa;o&#&"6#i#Y_ZoD1Kl7Z*Qd?Jn&K8liniN"gs/FES#*`;ha1Pq`[?VAp+X5qRa\hshBR!d"'\Jn?eW[`CLYcJ!!(H#q;*dUIc3lZD+jr]>fH`CH`f-3VcO/qX:A3Y3+B_h@F'N\4"9Lr'M)?28;khLDDH8Dbd5kP]jnaeMaP-Gn/^_Ao,[Z>R3?fGZL3j<"Am(kU1&]nHFAWE`:I[D:-u1E*&VP".@tiYTFk9TgkmOY:aVrSnj9*ID6n^47#Qs%nP0K/a&>Hb>/(WZQD'Uo_b'#?:HaF(F.!3/\`h3tGM9$*qSP%Wn*X!fg%BN@g:[XI,ERbBAEo!nuVik9GS#fi\lm-K`MXo_4pVmK1RlscuX@KX']AHYV!#dKSo8OT+M'ucgk=qNnfCMru#]=t^0M.sLW[H!MNm:$\#Gtt5Ko9*R-"_ZT!)+a91U,dP@l`tb!o=WE-Z&;OZT:i^l8LgHP8a]GPrZS+nandp-C,T58,@lCQ+JkfrMBl)oilV]&MU^ZUT]updbFYFA#%D[HSG2]a,Tp6;I4)-3/@8`?Y-Rd9S^h#bke_=fY2;p%qsgUS=W'aZ)nY>`RRhEp2.6M]$*G^pDXuVj#01m-Sur9X^+ert?56>C`O"CT69%6uM\p=(qiCH'H;2i$flHkGFXXdZ;Df"?\X-NY2-mtk7eB$pc@bSfcTg,h0K$BJ,2^8InIE\bj&C!4`^it!H>VX(?K>E5-i@UNr&Hg:06Xgb#C8!II._Vhq8MfFT&1_nUJ8=f)cesEZ'fsp'pO'+F(G8=k"F2*UeqrC>K;J9ZqoXPg:#*X6S7+Q=Ns]WkEKH>S$aMI]tPsX/k60l8Q!7dQX-cAKXPOL[OF(8&Z%hTZ@UV0JfM()8f0l/ZHB+MAr;%m$[oT+/%m?Q>qh-j=*-A7QNf#gYI]3d$,+-<5.:G!(E)X(RJ2i#mr"pR;d)4S=@5Tl5jK]ahCj:Rn0Zpf`P%\t,>2Td\-QbaV+Z\h_?&[-o^87ngkF(,iH/63EXjp#V?S?(5C(0uBJ];3h2Qlh);+mQpaSY+p@URdEf?Z@mICe7'$-0ZABb%?L6C#?5+?B[275?-PM>&.Y+a`2I@V6kqhmn,`n'.b<7:Pb2,,hPD"gd:h$/p<9U<8]-Z*Z\!J@/@^(H8lE=7(),Y7ZJn)01$ckLT"a?Y&uu#3?%?"SA_JkBQh7H]6uKY!0L>q.\`.6:Lgh^/^:g1]Iq6n0Me@5FYcZ7Zt$4rZLVJTZm6t0c-_I5>ibIEpO+eSK_MEj.]IGQB7""FAsRdTo^Z$Idc)>sT%6h&h4`H6#+[RTe%*:Gb=hr`?"5P,D&.U1Rro=f$BI0Q*7ChlI-1,Dd4Z>LJ*8BY7!7Jkbjq[nMuF=F=[&l8IPRYc/l&;&6TiN8D7\%`e?-'&DO-p@;5q4\XX/Gcr/Ou1H\f8IG>`I\`$K^ASJFtd8s0bUE)O2,=YG(ne-P;[I@(tf1ok>Ab=?MaJd,".=!=:eiGnQH,>[20,.<2LD$!G4K4K(DZ=YHq336NlKO#hUP)1-_DdAi*rB%OFX)4F\Ae:E5su_]QQ$./GKYf6'>biH[b([p1d.jEa+tA#&Dt;1GY1"9Ad`X(cbh(&>Xp:#G>g*`d+<@QOo@acMnSBSq%dNgGPplO9(,$0#eXs%q9qK_fN&-cRWBs;H;K*J#5(cS;)5?3dG^rmn+S'D+t#cOFMN&3c)K4co$TOI&a?PM>mk,g'"j%?cVn;<,LaWpDir4&JHH1h0k+*W(7-T'n+80p,,n@u$\8eL9U9fQM(OMb+)SNt7:&dnCaAijsbl2ju$L/D$H-ci^LsG^MQ'=B3/9X5q2$tGZ=WlEB?!1[*q4=(R#)K;%GmM3f-*q_n0'1YZ`2$Ak((F=t.2ir`GZZd\#fiF897]16)Ef8hB5b7"?kErE$kGI3\'EUnDXUs*!)R$,UWeCMc@_Y&>:T:m,!3M@H\S0>bMQJXmeo/2#_MaV&>^!V-QF;0rr5;pm@ETlr=b*tQL#',En\Q^6?J*?"&qLh>6SLr,-EmqLImct7$lq.:k<:/Xd**>/Gd-p,rkfpV#=O>S\aC?AP;[-'(T*l''g"GZd5Th,XfiTcCJZV:-(frV62_%Hd_[QJFI*1%,0_2QqR)L-b7S&W4,ue[VK1W:Qh"8<'WK/&X-9BHoRj2$^gN$-*u8cZCmk4`?d\"j:8?aNTnHfl@@00M?M`]3iQAlQKVt#:hqm;GZ2:4b-OH5f+^j#.,9!e_l;+JH:k!-/tj(R`N=OhgMU_Al'.p)pR(RT4Fb"jFrbTh/9Q%P=@u/Wkm.M9=0_'(K3E`84Ir[G>"0rljBui>Yg`YfSBRUPg5]?Gl7U9#Gi0W,agAg&ZFWiR8^QV2kFmK"/<$CkdmHTkGj&h@bE.opm=-cmc"k;)V&!#&+X*;KRs2J.QZ[L*r4lN5'(l5:TWl2&FELFJ`m@?Ce:"TkmON4s\oCUG7/udX5BIpe8BIf?7'N;l:Fb*RT&XekKMIkI-CNjgX!RVLSQgViM<6X,le8a&WFHfkeRl@7Iur77WN=*$PI3R3Fugg"pD!AXn4>k.[O2^K!4Mc^m/=Ke<-/A%Np^6.i_Bs'Fgf"Gar-eImm?4L>)gSC?I6#ANl/1F.GK$,Ag/cGh5BhZfN]0VcLWBWOm\M'VmHGF3#Eo6)$E@F=hT1;HMnp!$endstream endobj % 'FormXob.d593f1e7fe7f63f3a253c6e22621021b': class PDFImageXObject 7 0 obj << /BitsPerComponent 8 /ColorSpace /DeviceRGB /Filter [ /ASCII85Decode /FlateDecode ] /Height 137 /Length 6081 /Subtype /Image /Type /XObject /Width 70 >> stream Gb!$LYEC/6'uilXLb]gc-mYrH%mU7M++dQZV8*YT5WTS`M'L$(P.$jc?N>^\JQO*s1jA9OoBS'U\MpRhB6JGJDH,[r=(U7WSo_[<2fi;3^4Ou2h_G-)hf$:.cbH*eq,\O&TT'Jsr5IdL^M;fn++J!SeaT4/0Q`J]!CHYG(")TM5>8ij9nUe&f"_0gNJ;$AkMP%+7QYKYp&GWL%2p38;EJQ.JF7Ol!UA]Ps4fNg:T8I?<#^G<:c(0!*B4+VRWTq,&2c2Mj"H),cTg8M9b=5O8LVMtD4V2044(E.dRdn_5A=JO'Dddg\j^L25]'-VTDu"+2^$iC_Bm%+:C[rD+meUS7n5D?3(`;fjI:ZVIj't@!GU]E*$Aq<@poQ+JFUQ-?Xa]9AX),[.5_C/lUr^o>Ql-="=%qXLgCPY(VmEp;k&X+hZVHe[*?J-dAE"NPodB-ceCak[K7j=qh;D[#D[0Eh?B\a;3jB[f.g&MUi\?u$haePB4H[2i-KaJXfCSX=I;"Ree#54B3WD;n5$hJAS[q(YO@fTSb<&PJ2G6rKQZs2>re`VWD5*_l8/?g;NjNcao0?PpBEohXF#^@0:j7U8LP'*fhK>qYJ[X7jAZT\o!gmFp,"jY?',#1d4g#R`WNi.,1L7I?Bkr^NQqg"i,.c@\1'-4?j&d086FMm\SE&-1m6/g/bQ][EB:Js3[j^CtS^,ieuN6E\.![B*P+D#JER_A0QndX\]$/WR4i9Kd,\7/@jWT9>LniG-QeMgNhP^S3)*E8kK#3$l6g9)WoHOli;-44MC:W).((CR`AR'"qH3Lh!OUJ(HP7,X$eXGD)#FjkVX/3W>ret\%-?BT6!QIgbpRUMC:Q,UTP@^BjMUu5WsrNj>l8OO.o4l>1#?M>UX^V]%XD:&CMmm*g/@(ZWbV;S6"K-O&/Lp0BIK79BN-DKgWdSRZ9:Z\E`<6\AEc1BKQ=Hk++7`78$)VV;9E_s\BO(F1.Rp'#aj-7`q+')jfX,1Q(.San\9Z&3'i]O;Xh%=d?'"/Z?5m#5"&4Pnm4eA!*-LnLO51]*R9,\.F*+"FTusn+pj'ZlDe+[d#r=%4-WG+#Z9#\51)2l#:.QL2GmCPr'Tl#aq&2)mcca1jFgT&N^A&ZW0KSm.8u_F%k@BnJV\Q7;@&pF3H/]t5nt(?`WJ`p'\*PX0EpUe#P#fNlnIZ;3G3mKI_:PdWj-^_A>!0k"9VM"k6=LW0ChR5^L^7*&dJ]^f9p(ZZ#662tomo-$.uHdgVqcGNg.-l'\gGScdbI&,]a=QQpVZW6TcP)ts\+1m=geL=+ARXd6XL5^!n@RDFLHZKEP"Bp,OQr8L`;mcplFAKXFCDCZ=a?PUp%n-1$pIiYKOTE@P:!WQ\m>>m$M&ls9nX?9"[q1g'e3i;5",@uaSjUuD0%&(2@L[SpKH"q98/f[gl>5hT=%!O,%&XOIg*g1"L#e-K")C)$c@pG&LkLEI/BONP`*$;qW[0bmI!MQKni9cN@p>l97?>G,@1aMCfYm\O]+;u?(.dT^11:Y.63M0g9GbD8YfUOZhg$'DEGQdM!g674q"1@=rqW:.C,d-M>NPa;o&#&"6#i#Y_ZoD1Kl7Z*Qd?Jn&K8liniN"gs/FES#*`;ha1Pq`[?VAp+X5qRa\hshBR!d"'\Jn?eW[`CLYcJ!!(H#q;*dUIc3lZD+jr]>fH`CH`f-3VcO/qX:A3Y3+B_h@F'N\4"9Lr'M)?28;khLDDH8Dbd5kP]jnaeMaP-Gn/^_Ao,[Z>R3?fGZL3j<"Am(kU1&]nHFAWE`:I[D:-u1E*&VP".@tiYTFk9TgkmOY:aVrSnj9*ID6n^47#Qs%nP0K/a&>Hb>/(WZQD'Uo_b'#?:HaF(F.!3/\`h3tGM9$*qSP%Wn*X!fg%BN@g:[XI,ERbBAEo!nuVik9GS#fi\lm-K`MXo_4pVmK1RlscuX@KX']AHYV!#dKSo8OT+M'ucgk=qNnfCMru#]=t^0M.sLW[H!MNm:$\#Gtt5Ko9*R-"_ZT!)+a91U,dP@l`tb!o=WE-Z&;OZT:i^l8LgHP8a]GPrZS+nandp-C,T58,@lCQ+JkfrMBl)oilV]&MU^ZUT]updbFYFA#%D[HSG2]a,Tp6;I4)-3/@8`?Y-Rd9S^h#bke_=fY2;p%qsgUS=W'aZ)nY>`RRhEp2.6M]$*G^pDXuVj#01m-Sur9X^+ert?56>C`O"CT69%6uM\p=(qiCH'H;2i$flHkGFXXdZ;Df"?\X-NY2-mtk7eB$pc@bSfcTg,h0K$BJ,2^8InIE\bj&C!4`^it!H>VX(?K>E5-i@UNr&Hg:06Xgb#C8!II._Vhq8MfFT&1_nUJ8=f)cesEZ'fsp'pO'+F(G8=k"F2*UeqrC>K;J9ZqoXPg:#*X6S7+Q=Ns]WkEKH>S$aMI]tPsX/k60l8Q!7dQX-cAKXPOL[OF(8&Z%hTZ@UV0JfM()8f0l/ZHB+MAr;%m$[oT+/%m?Q>qh-j=*-A7QNf#gYI]3d$,+-<5.:G!(E)X(RJ2i#mr"pR;d)4S=@5Tl5jK]ahCj:Rn0Zpf`P%\t,>2Td\-QbaV+Z\h_?&[-o^87ngkF(,iH/63EXjp#V?S?(5C(0uBJ];3h2Qlh);+mQpaSY+p@URdEf?Z@mICe7'$-0ZABb%?L6C#?5+?B[275?-PM>&.Y+a`2I@V6kqhmn,`n'.b<7:Pb2,,hPD"gd:h$/p<9U<8]-Z*Z\!J@/@^(H8lE=7(),Y7ZJn)01$ckLT"a?Y&uu#3?%?"SA_JkBQh7H]6uKY!0L>q.\`.6:Lgh^/^:g1]Iq6n0Me@5FYcZ7Zt$4rZLVJTZm6t0c-_I5>ibIEpO+eSK_MEj.]IGQB7""FAsRdTo^Z$Idc)>sT%6h&h4`H6#+[RTe%*:Gb=hr`?"5P,D&.U1Rro=f$BI0Q*7ChlI-1,Dd4Z>LJ*8BY7!7Jkbjq[nMuF=F=[&l8IPRYc/l&;&6TiN8D7\%`e?-'&DO-p@;5q4\XX/Gcr/Ou1H\f8IG>`I\`$K^ASJFtd8s0bUE)O2,=YG(ne-P;[I@(tf1ok>Ab=?MaJd,".=!=:eiGnQH,>[20,.<2LD$!G4K4K(DZ=YHq336NlKO#hUP)1-_DdAi*rB%OFX)4F\Ae:E5su_]QQ$./GKYf6'>biH[b([p1d.jEa+tA#&Dt;1GY1"9Ad`X(cbh(&>Xp:#G>g*`d+<@QOo@acMnSBSq%dNgGPplO9(,$0#eXs%q9qK_fN&-cRWBs;H;K*J#5(cS;)5?3dG^rmn+S'D+t#cOFMN&3c)K4co$TOI&a?PM>mk,g'"j%?cVn;<,LaWpDir4&JHH1h0k+*W(7-T'n+80p,,n@u$\8eL9U9fQM(OMb+)SNt7:&dnCaAijsbl2ju$L/D$H-ci^LsG^MQ'=B3/9X5q2$tGZ=WlEB?!1[*q4=(R#)K;%GmM3f-*q_n0'1YZ`2$Ak((F=t.2ir`GZZd\#fiF897]16)Ef8hB5b7"?kErE$kGI3\'EUnDXUs*!)R$,UWeCMc@_Y&>:T:m,!3M@H\S0>bMQJXmeo/2#_MaV&>^!V-QF;0rr5;pm@ETlr=b*tQL#',En\Q^6?J*?"&qLh>6SLr,-EmqLImct7$lq.:k<:/Xd**>/Gd-p,rkfpV#=O>S\aC?AP;[-'(T*l''g"GZd5Th,XfiTcCJZV:-(frV62_%Hd_[QJFI*1%,0_2QqR)L-b7S&W4,ue[VK1W:Qh"8<'WK/&X-9BHoRj2$^gN$-*u8cZCmk4`?d\"j:8?aNTnHfl@@00M?M`]3iQAlQKVt#:hqm;GZ2:4b-OH5f+^j#.,9!e_l;+JH:k!-/tj(R`N=OhgMU_Al'.p)pR(RT4Fb"jFrbTh/9Q%P=@u/Wkm.M9=0_'(K3E`84Ir[G>"0rljBui>Yg`YfSBRUPg5]?Gl7U9#Gi0W,agAg&ZFWiR8^QV2kFmK"/<$CkdmHTkGj&h@bE.opm=-cmc"k;)V&!#&+X*;KRs2J.QZ[L*r4lN5'(l5:TWl2&FELFJ`m@?Ce:"TkmON4s\oCUG7/udX5BIpe8BIf?7'N;l:Fb*RT&XekKMIkI-CNjgX!RVLSQgViM<6X,le8a&WFHfkeRl@7Iur77WN=*$PI3R3Fugg"pD!AXn4>k.[O2^K!4Mc^m/=Ke<-/A%Np^6.i_Bs'Fgf"Gar-eImm?4L>)gSC?I6#ANl/1F.GK$,Ag/cGh5BhZfN]0VcLWBWOm\M'VmHGF3#Eo6)$E@F=hT1;HMnp!$endstream endobj % 'Page1': class PDFPage 8 0 obj % Page dictionary << /Contents 14 0 R /MediaBox [ 0 0 595.2756 841.8898 ] /Parent 13 0 R /Resources << /Font 1 0 R /ProcSet [ /PDF /Text /ImageB /ImageC /ImageI ] /XObject << /FormXob.10c72419a5ee41fec40f7cf4446074b6 6 0 R /FormXob.3ba39c9a6e36b0773a0b2a5555c49cc2 4 0 R /FormXob.77e7cc02a2ba171dbd87c00d37df4193 5 0 R /FormXob.d593f1e7fe7f63f3a253c6e22621021b 7 0 R >> >> /Rotate 0 /Trans << >> /Type /Page >> endobj % 'R9': class PDFCatalog 9 0 obj % Document Root << /Outlines 11 0 R /PageMode /UseNone /Pages 13 0 R /Type /Catalog >> endobj % 'R10': class PDFInfo 10 0 obj << /Author () /CreationDate (D:20090326212045-01'00') /Keywords () /Producer (pisa HTML to PDF ) /Subject () /Title () >> endobj % 'R11': class PDFOutlines 11 0 obj << /Count 1 /First 12 0 R /Last 12 0 R /Type /Outlines >> endobj % 'Outline.0': class OutlineEntryObject 12 0 obj << /Dest [ 8 0 R /Fit ] /Parent 11 0 R /Title (Images) >> endobj % 'R13': class PDFPages 13 0 obj % page tree << /Count 1 /Kids [ 8 0 R ] /Type /Pages >> endobj % 'R14': class PDFStream 14 0 obj % page stream << /Filter [ /ASCII85Decode /FlateDecode ] /Length 1229 >> stream Gb"/&gQ(#H&:HLqJ!e9`8@ZRMbb/SF.'u$DVB`"Jlp<;1K=>=Za`hn%(P`c6FP_CZ+LLhI"#ZJ*OBsbd:q?t_q+XT8u\t$-jj1iHK-/B,&kBYB\GC%):27a-"3i5Oc[bX_8fs3%R$(_9@^H[g/lX1e)D1F12JBAo\aLj$k9a7Jjg7RFrc2+75:#?^hm155X*tMgHu^+6"=+@MOD;YD[r6XLQGT[8aW$:8+YN_prrG?"\$nI[El&a=UgcDkAD[d$PWq*9hoE3OCr*c80%;4;+W>AKiMN9u*gr2V@_&^Z9EIC[l590=LRkDG>iZ*%pief%]\UFU0LL*V:u:=;`9tcJc4j2s"Bl-]>-_kcU0!3coL(_#qC3q+r+D*oVt6L5<)9Tor6YV3`W^UPLCm[\[#*`(Sd5"'O6Og:@6,s;J^^ZN+9/h["44#+1)slYmY.iD&j2f(sYcHX-hJ-SgElg9F-#ZC:Wk/NIIP3Bc,Rj"oIgGjM5g+0Dn&0HN~>endstream endobj xref 0 15 0000000000 65535 f 0000000113 00000 n 0000000221 00000 n 0000000386 00000 n 0000000602 00000 n 0000006963 00000 n 0000013324 00000 n 0000019685 00000 n 0000026003 00000 n 0000026497 00000 n 0000026634 00000 n 0000026840 00000 n 0000026965 00000 n 0000027074 00000 n 0000027181 00000 n trailer << /ID % ReportLab generated PDF document -- digest (http://www.reportlab.com) [(\372\310B-\361\\\366K;\313\363\363\336\360\272e) (\372\310B-\361\\\366K;\313\363\363\336\360\272e)] /Info 10 0 R /Root 9 0 R /Size 15 >> startxref 28528 %%EOF pisa-3.0.32/tests/samples/utf8.pdf0000644000175000017500000040613011162761640015066 0ustar wmbwmb%PDF-1.3 % ReportLab Generated PDF document http://www.reportlab.com % 'BasicFonts': class PDFDictionary 1 0 obj % The standard fonts dictionary << /F1 2 0 R /F2+0 11 0 R /F2+1 15 0 R /F2+2 19 0 R /F2+3 23 0 R >> endobj % 'F1': class PDFType1Font 2 0 obj % Font Helvetica << /BaseFont /Helvetica /Encoding /WinAnsiEncoding /Name /F1 /Subtype /Type1 /Type /Font >> endobj % 'Annot.NUMBER1': class PDFDictionary 3 0 obj << /A << /S /URI /Type /Action /URI (http://www.columbia.edu/kermit/utf8.html) >> /Border [ 0 0 0 ] /Rect [ 57.85232 804.2816 224.1414 815.5316 ] /Subtype /Link /Type /Annot >> endobj % 'Page1': class PDFPage 4 0 obj % Page dictionary << /Annots [ 3 0 R ] /Contents 27 0 R /MediaBox [ 0 0 595.2756 841.8898 ] /Parent 26 0 R /Resources << /Font 1 0 R /ProcSet [ /PDF /Text /ImageB /ImageC /ImageI ] >> /Rotate 0 /Trans << >> /Type /Page >> endobj % 'Page2': class PDFPage 5 0 obj % Page dictionary << /Contents 28 0 R /MediaBox [ 0 0 595.2756 841.8898 ] /Parent 26 0 R /Resources << /Font 1 0 R /ProcSet [ /PDF /Text /ImageB /ImageC /ImageI ] >> /Rotate 0 /Trans << >> /Type /Page >> endobj % 'Page3': class PDFPage 6 0 obj % Page dictionary << /Contents 29 0 R /MediaBox [ 0 0 595.2756 841.8898 ] /Parent 26 0 R /Resources << /Font 1 0 R /ProcSet [ /PDF /Text /ImageB /ImageC /ImageI ] >> /Rotate 0 /Trans << >> /Type /Page >> endobj % 'Page4': class PDFPage 7 0 obj % Page dictionary << /Contents 30 0 R /MediaBox [ 0 0 595.2756 841.8898 ] /Parent 26 0 R /Resources << /Font 1 0 R /ProcSet [ /PDF /Text /ImageB /ImageC /ImageI ] >> /Rotate 0 /Trans << >> /Type /Page >> endobj % 'toUnicodeCMap:AAAAAA+Code2000': class PDFStream 8 0 obj << /Filter [ /FlateDecode ] /Length 1277 >> stream xmN+GṟDwKKbB^4)(HE ic{~l^|XOme_iz;\漟?>n{f=>O5ߞ׹wwNٓr Hʉ39+rQȃH+*OILɗ o~'ww;N~;~'ww;N~;=~/{^~{=~/{^~{ ?A? ?A?#(?GQ?G#(?GQ?G$ŸO ?O'I?ɟ'$ŸO ?O'I?ɟ'3,Ɵ?gY?˟g3,Ɵ?gY?˟g "_//E_ "_//E_UU-IW8dUP6>mHVC%u'jٮ;UUɪ}ܑUȪwd;wjkdˋZƑq9>'֪1.8mµlNg\c q-Y=ڧm>IY϶T{T{?o/zOϬJtUJt3?egQӵDtX s Y5NͮU6gbvjd2d>-WMƶc 1Gg<6'E?}if{o:Æ]:φo7MҌm?_G2oqiZt{gnNs%abNF-q2[w\,/v Kdܲb>d)ds ?gRW,:efY/;Vk~dd[j3_:~L:~Wz3~> stream xͽ}@[ם zνW`%>e,cII UJWuTԕPu eWue]fY.aR&e\z'Y&^z3zgQ 'Ayԉ/R=@$ FK(A=/YԋNz=~E'ѿ=t h} F% 4~ER9M4:D ("6C.?CiϠEA{2>DM@iUC4z  ͢G_7ߠ7@ߢO<)zO~9ܩr FcԬ7+[ɌIrĕL9muȷ !7c-znX]-yӝ;l =8N*yGQ!a -^^s! 9\jnF3;jJ|)73o^zo&gp =ȑo!oKp&$Ãrbj9wC5c]Hd}cE%jsMbsKsKSc9-ii42FQkʁ1X.jM1Cevs=cDєd 벌QNS<ʮ͏`HsmCeEzګTT65v8ԚVEÃ.""!q-V:I p3- $FW7M7sw>"Ĥ'K; TX/6޺ yf,*}o% K;DVf:Ih hz]#TjAT=l6VHvqQr[W83 Mf}\n _H = ]P?uׂ/YlM"fq t%mE;M^kݽU{-[u j4Ԯi r"&sy[DB7~‟Pnvݠ[8GЄzW%T /1i1)<&{CsIj,js yh}z>OgK4>p4=M.].b3z"Y8s,\xjp 7+qu:GҢȧC"NYE P2Է \" @fT*i+ӡp@*syV煃.{q]Йk>r%˱wQbY{mhrJUAMJ6ƞ!Fvk"!U WOԟ-E{_;~ [3Cd(9NGK \9l\^L,JdA@Z e(hqeSMgp( >цIP~[2@ktPi|s-sƷ=p-&;_|(Gb|oϏ:z),IDz/݉R mUC4QgSaj8ū7FO3yўdi2|e4wЉvߙ}joL,ܟ8|k]Rd8v:>қ{p)b+i)5Sr+5鋌CuN K[ Q)2Ӂsd +v}>htvpl988%Q _[$7!9?MXIXdfPhnCs12|>8,rX,L݉s]7]NHmGCoJқ#mm!!UZ=sWhBЉ str(C'&tf(χW9{5]XCc{ zXdH Xt:Y1H+1ޯ]ެ5zːj0(kT3LYL0 iΔYr09ʟ-9 .B~j 07=PCwyS+; QQpA䰸|Gi=K mvu|Z[lfj`kr| >#fsg&S,v AxGӏm(ZFT2aM41) k^tf%M :bPPpB<;+*z.W9 xK0&YI +*~#gùvcܞST)2');3 ";$ 2ȕ fU5+bW\OPSuQVG}/S?LC@598Ă7n#|R+ؠBH}'zOw JU݋â92/{/DzGY\Y%ӟˡFͅ'[.ԅRU# ~7+8eF^iX|& khŖ4J0&I01351F.6=; qeZITD=Ř/2ti.fKW̭p<pƯ>Ϧ"/ɓJfe:kfE֙8Rt:k69bky(0Op!qp!3Lel?Ig%begI47U=Kbhzƭ? ^p!vnw3$RG~zqJg>",.@Aɿ_,$5x>ln1c6 X;l*}if ] 3wCܐJJ6b.M\6 i\ b<~nuhe'30r UtM|}\R#W.SEh<^j/ZI8%Ikip"iյn.H5O4p6U0رWBH鴅db`+`6&Ij8#ߘ|ZEe$9@WQa,w.}^҉ ^!x->k|bJуͧt ]pxvIRPbW8@zeg w[A,JM1bq%訮xNnK=Ҥ > Bc4[ yT Ɋ}`zE&82 R54Va݇oE6p%2J|vIz K'=QJ-{m{:wWO C,\p_L&]@o,e Ec7p\ xSgdL}?U?!F;,S۟zqlR.+z+e~̴:ГFdCv֒YVPzEe*;K0 B`/V lb4["svb՘ y~ Xoh}zPoȣ_{nNEɱp]۞o=b Ϲ?cMVzGM@f:4 t ~{ lot(7V5kuZ%80r2QBݢ>rN9$3vkyrXxvQ˹w>O~!{?3غ=!+XkO&w_XddwN'+Ig1oAa]JX&B3n|E2OD^=KQoa.)\W1Ha\RPiIeWG%ЛƵa%]ȜmSnƩ`p!δ7?Az&~Im&:)n7&,f'Nd}| ;,ɮO>m6 NX\Z-~׵;t<ܘ'F9v%t-l)`"i9~"irg=u^7+;]|Zm=b#lDMӁņfgG̓FZE/s&m7EI3 M e,,(AP$v8=Ș?]Vg:qD<ˆ? xD#v‹ wtl:kqCZ|Q#7 7&يl2Y]քA$uWp'&He[1,gZV2ەY[t%`QlNPih rK.|pɼ^W Ҟ<].6Y]k R@.bd\@7lɃ"8 [ u#8?t!r*vB;H$_^§Dl=E `+emJh?$~8{fG!h%aera Ā#d;1A*+/6mf[SImcyEP/xsֻ:uIX1ꏥ˄" YY,wacxor:Mx6gy]&^c)UNnfR֢@E^۷zqSPZ5WΩEC.ؾ,cH\`V踡Q؀A\p81*W 8=ݚZLl|ƛ[v8 s%BϤ91L+⢄_IRzݔ+1t`8;"( s;b )Ģ79=|}aZmM5MyZ d{.*6mvrvA[]{}"^l0wVW 9׹)(Q[,t% :k`r:sV)M͢I"q!5ϯy|Ac2*b j pR NA7˿!.*H׆8uzD=Cx> ;ɭ4/ -$zCVwxs~g0SbrW@)-46k] mv"7 ~?]h %]xe=鱅ɮo<&jHcŷ9Ѹ%ߝx˜ȋ}}Qe’:v K.#NqvmpԔVte:=TEy9C{UdH'䥪k?o϶ XKzkYB/mc"[Kvȟwm{~ċ~a,FP٨ky Zʱ% ~]guCU4^<,symajr+̏hqۡti]Ux񞵑FMM9wV K$D'%~0oJ+{a?p{J\u3w.Gp$Q8$J5/P{k$O5Ԝ?No?jKp߾Eqڃ[G;C dQ !D'ǩv&ǦM/Mu]iXS5fm9 o*L8X-CT~Au>ElR %,3Թ9oxuYo^4y .5+R xdԨZjjK͸^ ?KD^ye?xM6ug~o <;[,:bpF3 j&$,=::*iQl`n\SkQ)&=rQFee`zʕx, J"yB!NPC]jwc{۵!Ogkw1aoOWfhd,GW6?:ۃ#V3JZY6JkkX"Hߌ[=X2V/jq#:ЊC>oȧD<2OLWT;MeNLgئB(U93'R" 0;OIA+i,p($KĘ{f @'j[TFVqzKd/O&{>4Q;I({d[GHDRiΗ$V&L&9#wk&v6MdgΘMѳiB)(TFk$`X;.YY)Q2\ %r{B0 /REڔوWiI-&p>ã)=DnrygBxf951D9 w?4};XhMw4iEt=>4[ Kf7^rs+l_}ͮؽRSQRRuݎ|gwc͙>=|߁>o_хXs*9Xg\=kinOy}Wim~fԋleMslWjxC3TqOky_9]%疒ٙhkuŅ۴[u_dPhkud$$1ǖmOGI/Wߖ {֧hoVV6xK8el&*sVٲ } g3#E۶hSXDwP H=İ=PRXRPP5u:bu#qIj;Bg:xd@n/_\G`wnb;F>[wr);&)g×:n0prC+Kӓ!qkoy__` ̝U/a?$D6s}a"[Vmtۓ۵e?OR|aut:2WIoʊWc;6M {Vڥk Y^l<]6,-oDamg%W!&pŦс}XUݎ\QSGWgzeMӗ=+0̺a\X#ىicI~Ĉ3ԾW.H>|:;3ֵ.v_oh鸉Al; j,0Uf]N{jr/@\h>Ш tˮf^ntė䖵!1/E1'b 6A0)~(1?]Cw#bllLXgxbAW9FWԧs{|B89<(.e%>t@@{3Bj_}dٕIvHJqӦ. NyGDCxvSOIf!S4G8|}Cq+j{^ x+pum(Xu.KngQౕsWX{r9^j~_ra#5)/MH1p"'[,Dd :ULUסUJ170~rygs^w_K;s|xz; p+|^ *\̕@+^?e/ +~ ʧV!Ӈ&W7X}R_7^ޠW`pvm?em(q{s+܆SreZ~67^iƸESf%1۵ș="]bS*b;BeC%nnoV89:$ps)1o\l 'Ãa! ,". ;$_c>a=Xwᬃo hن!2K)lM!pDIOߨV8 T;LŶ} ܒw8vJm[K+j ]Q|Æ]Ygc6N ~NILJg>3Tz붃| }g˾)Iܢ x}hۥߥ$DIT-Z} _/ L]e=})]my~n!C?X<7tȘ/<kYo`ۍCnLN`Wo/Nn{A,d~\nUs߿sRnr;},W\R6To&%,U wMN.bA"I` vV0JFE?_?gQ `ƫ9]̡ZF /u;9r[f0d3u>5;Z(~ޞ撖cÉ5 $ 8>LK8&E/045# {î` Lg.0ųAnwΐќl|/+gZw]h_frXOs7{Cξk:s+[j,ss ny}667G윽d(E}VZ$V:zH>( EV#緛ɄÅ'ɤ۵t=oٮΖ[u{1ѭx&fNEq$k2Gk(6Q&Q;4]Gk~I/䗓YWY(k3*or۽?`pGw.QL^ [}x<˽g߉pѷ.{E*߉a }kݾ:|xz,Ww8<mr]b\ <feh\ō5Sr 8_<<_\++A<;a=W'eO Ի k :wWih8d~h&dTK2\eҬ$JK!s ~%7r~%p?\p` HC=uˏ<!]K54be@yA \)(zU3mhW r^ i>KAVF.lLKZL^;J[KKӼZǞy?65BՈ,SIIJy-P9RX<{xN)tD^|Ez!d_ӫ4ye蕏/b@~BǝrSUn[q2P$N*N%zUID+I EӮk&4ok~uhj{/j_/@s}³lk˾-D$2FŢwVlMoߺuXP_]TҽG*}XտUGD(9]ziuҷʄse7}*td;eW+P73\6\3.lmwnl~r{jkN UU᪮KUwvqe܎;V8khgᝣ;oU]zwuS)b&js9f5i%h [ϒ YF-)˜elUjj 5m5jޭauXY/Z_^Ek_^`+ym1۰mζji :~ye{׬?D ~Z>bʕ*OгrrDIP]I 6+i*B)i57)i <0XNhZ`K Ca%] (ՙbi s,} 11ᤒP1V<_T_V*dWQVG>xִeX%]l[/iZxUxeAEr\ѧ;|<^;c=={rUE1t=غ1t=_Pr= wMP, P' EO(6q@ϣ(Ly=ym=(( ~s~'0@= Ov=02G!,KA¯ݏ ~Y>˰>1/@J{/{=}=gJǁ-wYp(hxwcz8||O=*!_ʅk.Y|}U:+ ִ\jb/ÝY*J% 0^ gAVVxJ[MyI[jNP >@a}A> % tD#/Q1~:9ONP=a$2> X>}^Y̿^Qh1 ORW9Ac`bU ZqH?@7>:IMYGI0i\~06n db|LLǙR =Q=?fNъ8;?5)wMT{Zb-E ƟIE'{}?XXrO1e>VRlB1Keq6Ac-ᷞO&V_'t^wG[!^ b6PLgٓ?8wAی*Q,T|QE*TLb|rcs~_XeI).<~l1ǽ ]ٟ`<=qƵ^~s)K\Țtaì?a^.X _aTeYÞfhm,+zr:Zǀ|-ys&B<,5i @if;_a\BPƬ;Vsg SNn<n_ODebtT~6u&endstream endobj % 'fontDescriptor:AAAAAA+Code2000': class PDFDictionary 10 0 obj << /Ascent 976.5625 /CapHeight 683.5938 /Descent -292.9688 /Flags 4 /FontBBox [ -1111.328 -294.9219 2107.422 976.5625 ] /FontFile2 9 0 R /FontName /AAAAAA+Code2000 /ItalicAngle 0 /StemV 109 /Type /FontDescriptor >> endobj % 'F2+0': class PDFTrueTypeFont 11 0 obj % Font code2000_00 subset 0 << /BaseFont /AAAAAA+Code2000 /FirstChar 0 /FontDescriptor 10 0 R /LastChar 255 /Name /F2+0 /Subtype /TrueType /ToUnicode 8 0 R /Type /Font /Widths [ 1000 1000 1000 1000 1000 1000 1000 1000 1000 1000 1000 1000 1000 1000 1000 1000 1000 1000 1000 1000 1000 1000 1000 1000 1000 1000 1000 1000 1000 1000 1000 1000 390.625 304.6875 449.2188 903.3203 513.6719 812.5 671.875 214.8438 300.7812 300.7812 535.1562 537.1094 357.4219 445.3125 277.3438 603.5156 537.1094 537.1094 537.1094 537.1094 537.1094 537.1094 537.1094 537.1094 537.1094 537.1094 277.3438 277.3438 468.75 537.1094 468.75 482.4219 677.7344 759.7656 650.3906 650.3906 648.4375 585.9375 585.9375 763.6719 742.1875 335.9375 707.0312 715.8203 585.9375 914.0625 777.3438 695.3125 591.7969 695.3125 718.75 513.6719 632.8125 730.4688 730.4688 1025.391 753.9062 656.25 593.75 341.7969 603.5156 341.7969 423.8281 718.75 367.1875 449.2188 593.75 484.375 593.75 476.5625 562.5 597.6562 650.3906 335.9375 298.8281 648.4375 335.9375 964.8438 650.3906 523.4375 593.75 511.7188 546.875 437.5 478.5156 587.8906 593.75 822.2656 589.8438 675.7812 455.0781 330.0781 230.4688 330.0781 441.4062 1000 603.5156 390.625 332.0312 693.3594 746.0938 474.6094 650.3906 669.9219 585.9375 693.3594 966.7969 894.5312 763.6719 960.9375 1025.391 736.3281 675.7812 964.8438 632.8125 1048.828 566.4062 509.7656 541.0156 332.0312 469.7266 570.3125 443.3594 477.5391 416.0156 492.1875 187.5 406.25 505.8594 625 469.7266 348.6328 451.1719 625 455.0781 495.1172 496.0938 631.8359 395.5078 332.0312 451.1719 531.25 724.6094 593.75 335.9375 449.2188 591.7969 523.4375 449.2188 632.8125 595.7031 630.8594 673.8281 718.75 593.75 667.9688 636.7188 523.4375 595.7031 505.8594 523.4375 718.75 626.9531 505.8594 464.8438 582.0312 595.7031 494.1406 671.875 464.8438 523.4375 687.5 523.4375 552.7344 695.3125 523.4375 914.0625 669.9219 759.7656 552.7344 585.9375 595.7031 595.7031 718.75 595.7031 505.8594 505.8594 523.4375 464.8438 669.9219 505.8594 845.7031 595.7031 759.7656 505.8594 785.1562 781.25 789.0625 451.1719 511.7188 476.5625 566.4062 437.5 675.7812 550.7812 468.75 488.2812 699.2188 578.125 535.1562 507.8125 523.4375 543.9453 650.3906 537.1094 535.1562 617.1875 578.125 548.8281 789.0625 507.8125 750 777.3438 687.5 ] >> endobj % 'toUnicodeCMap:AAAAAB+Code2000': class PDFStream 12 0 obj << /Filter [ /FlateDecode ] /Length 1342 >> stream xmKk\GLB  ^A? A4F>SUL 6ӧ>tz8qy;~>O/r_ӍǗ?{|}8^~:=nqvO=nvYonq{v?,owƼ-no6Dt.ޕ6>A[`OBG@@Wh0O}w\YF^=Ff^ m#q1^x(=tΊg"m|m7]1Ab cvGN͊Wѯe[a[ֿuIJo1v۩sŠv&TuݹE>xg9y  .*I̘w'~щc.Ώ:g;?jߘS^1^Z^/Q+OЉkx2Š_Oo{]1c^<%ϔE>r#~F=S<_"0~4ߡ 9W9 7l\30{9pO;#.Zg$Gx|(sɯ=ɿL-ٶJcIK3i_*'$_dTjO7RsƂ'G3T&g& ԥHciU[)gH^9iVB'rf/fF-sX;r_4 tii$9YϲH/F{Xiԧ8sҌ AQ璤Q-"yCc: i4^4"9Z`Z _b僳&ؿ5K3gFjUisQu(l|QH#~;ji;gi`~ souS|#Mp_/|+ r8g?> stream xŽ|y :;D$@L$2LeFAhTEDAdT0ʰʺ)x:R^e]^x.XR"q_oj4xdϞj+f3]J=ǧ?"rH/%7W.WG( 8:\ښx.u !̥ hKe B0[/=wewW:N]{>F}FG7=gg|-iyv?W>Yvk y4K\dIw *ZvF5Ej u|F$*!0AGբ:TQt GfjD'&ԌZ"#zD 'zSȅCQi򢏡n$@qt}'Q O^ AgϢ :>s<.k}MpT"f*ڦZcGW- T >nXrex *">&$  6j쪭-mc٤i:]Md~./=bю/$V?v+b{J,~łOBr ـ~{/PW9?Am~5m\g-V߈ _㥄#x)ENuńIdě, Q 9`lqG{#nЫ5 ލ;E[KgSl-#XyShgf'EMlt6Kykhx(Y킧 ^ ۱q@]\+]n]Rz$p$B,&59Rc*x\E[A~ȑAR,@VAGJHv. MPxTk;S4WķqΎvbe,i`k yab`TNFh١BmtXyi?}/^I7Ѐ65c|ѐT < 36E 8ӹwyD+ѕeA+moE1iFZ*Óx .eE o-Ӓ%޺U!/1}0&+ lmz]E}  L1@ҸGH|YJK]" DW.,OV-I [M`ǣ\!Td,iK(DrqPuvnZ m$\k4rҸI @%?`^ جsI.l6뤕xL!G"RȸA4AIi hB|{67P=kZX9%=سAFJEZhႱ@[3ТUᳵ|1],We{4Gf&./ ¢{N2CAik;$J9SG*V#UCj[VklS$F7%$ kdAlltTKDk~ tE]eZ~ >"u\kv7؞4ыVk0S=Q)l2Z VG c/囓DlZ DB^3/&xJ? sˤi3J%L!< r5>NuҠd)3Z*255jFS LanXB'+kuܫ ogP!JvkyKMecʶKѸMMYqGe*׈V; t;hZ~WC#=vSraFa" &ARыcfFivy-)QcƜqӕ#eRps5ie?a ƿ䒮|8H[6.i^A_fy!LbJ+?_FSO=~}/D%Q~wUCAᶋѠx)RM#S녰׬L{1,-O.UEǨA*[h~LN50bQZM餘%iͦ ȝQHVʥ;G#Cwq6պ>g~4!Ӫ[u:zFw8`2'6')ih+@C5`-j0X͚ʆ;,HpNM90")ʉumMe.̃;:;ӎ"_2OZ':꿵R5H}:^?0d-B$ -,؅}:`h-%xF&`H0/fAm20.,׷bePHy0^ޯ1k V2jP165ĩfuPTĭKb0=na)m;Ji 퍖uKl'9KNJ ʭ\HC8F/wzc`nLQX LsdfL_#:\p%z6\ y}%/F:$ exb5>WQk'G J»:m56|LJj! gک*05蹖&:Q Lr9iѕdOŅLvPn|~'RmWKY4&hx; שCMVA9CjZ]mU05Ux:&/>6ss}ӣ}WǓJ9*3gܛ==Pa_'ikz$#f>v><_q%zzMla +z1 4xZ#8VgB 8we8eu}HWA,a.JLI0vw)ԩn^Hgv4L98"96&?䪊>K Dv ќrCo]@aU= :QzrȎ&Kǰh{0x&us_Îw X̅IiH- ǸڭLP `Ӳ*hhY_gX[\mEªpWY+2W6 ih-(6>{6<>y:{Dw(ZCo{絅gaMBE \)kzx/-Adv捻y SCsR2~ljhx%=0c";;h`y8^xZ|nBG(䙭8Egq :JI ڴۄ4oԚ5/.5i{scP]Ѹ4\45t:Xn#.9m}b*s%+$T>-yx !MM=Sidmv1ƉѼY&CUfA#&2B*lٵj⸌bFnLFj+ǣLis5YɎ$!ML#7x6j):E;d$px(gm˛ϦEOaqCgnmq|ċ I8xIƺ42[#xʩؼ]XR"\+L3n4N'>K:}ra8 "I |arҔɌùX,$MҔ˘W)~JjM [C_3TniMRQݪZ 815b~ 1?e}lZd .ia˴"{T*'x32|Ҋwqnn}*b{zJ co z)7c:|]1kPE|RpTR0+ogJĒ> #"c:m^A<6Nd'Kd sKE]YX3tu=gQO9>-i;o{=s/ Al/ QB)VжةNmt . Oݺue0Td@M0EI~wFŹ*!IO>v:7 L2 ` 증n<3,hT;I݃br^eL7&am10pwv^&Ҍ)D]LP[d$ߑ#5:0PW5:ZJkOh 3~Hk'Lo`VFC>:R%Wq͜~6ĠQ6hUEylAY,yYv) FQ(ƲC.GQ5̐%Y`qd ޾px4=<%i"S(qk1Y^WmvE3]T4~LM ͻV\/w%͋R4ZB:-3&X [w'd}cPQ7ʲjP&BR _ Zpu[;`_DUSS]W]3' I;˔7L鄌2V'(Qfd|uꙥs2:u29%iFrY&5$hh~ǃ\ÀŦl_H?V-Ќ-k+(Y[OJDto (Yёeh3HW?!v hԠ5clh0hhIPݢj[R49𯽸^,ҝzZW%}ei\?tP[W>Z# 5*uM?^~|gr4zt5\2vگ3xR[jFc|7RV [L~K3x>@f2#3ZLmV{3ͽ2j;"XC50q$ d \\7tVfI<ϊL`d=K]302lv6ڡZ9}|$qmACޜ٪A ZUs4SM/I7 CԮX3=R}cU5UUU_6ߔzXdPQښ2Ų)7V0>Q&~x[ܜVwP_`)鑴z wh=FX/H&~ g\+]r\-_+ 8;yw^cP#"8txQq 7oO:}NC͘rWߒ4GtXgY :Me<#p7t"PLB,)!uR{2xOm.Ɔ$jzd2uBB\~ vՙ 8+pS8J#w1cb#GZ<:SB&Coq:빓0NNbyfg7ސޘx#q%psG~x8JG@>챽Pyc(3R1*'2y<;[͘]Ѕni #d4:+SNsRW^'@O'\==&Wtx-Vzp5+-Sy9wst(*笮Q;(Tqe+c_E}\uWW_n8_,pbrE[JkwOJwx&&Y,PV_bR}t [SͪVKS;0 VX-k3 ' 2xK+\Z6[>/?9n=~R3H/^s\#WrZlsrܝD}zp޾~8!b'h [cE]tMy'88<b2)cǬ&gN˴ HPJ|$%S{44=ܩkW0wIowy }>Vh:&{ 4@/fwĩø u쳞ze,-5|=Əp#s}v~h;2^?c=s݇S1~+p? 2ٰIHƊulަra8D)Nl6K&u㡏JQ^rT} NZ ӞF.$섍eH7zr/^ M1^pSG+4r 7~?].|r<{<FˇN_/i4 F_"#A?H* 3vse~<2뿢^z!be*<^, ` H`tϗ Ev;_ʾwz\698s1fK,PR=|)V C[ԱZ:QZr#pbklzzlk g;vQZP R-U:}}zodh9]NT;hWwTz$޿+?OeT% j=ux*8ГIg sA=?*&0ˍfHx8,=HlhI:Xt<7Fa/Pc鮴ď'FuqEvR&?q9TiBD\˻$O4 7opiެ g'v ygٚ(D&W{:!$ zYIlg<&ZxHQwiީ^-]hylŝ%b:4|'YXtl#Ob@\;WOޙHbk |`d2 tqKNOV 8-Ҥ1b}> n &4WV~/A㖏@"U$QyCHDe(aDET.W[~(wHc}nwۯgM=@gzMTiCd^u$z%p΅,A71P9(|v^G%8E`Z \.nA" a*]E5jlM+yAÈ Hӿ xd+Nס<&|2d>v0:l°0HٝP; PFe K CcF42ѝW ĸ0k>^ĮqhoM & ¶4uv4p`MUVȦv}oP[uhݖiakRy~Ũ#C9X^xU~ْMx(uOҷPt F "SYku}|E7.adu̙ YM?㻬ߓ(]˾#aA~k7w{tfsH[9XwX̦ik{ÆXy G׿z)O6٧=I M D8A G>]t< g#B txO9c֩\a\~N.;bZiQgxO5-#t@f&MW{:N;W: Gt7tu7uXcBLDM|toM/M,EQ:%˃`⇡M~"4ժ䳻W n^@r:TӽtVEE`$Pjc!IΎEh|^kZZ-m`h6Mj@99#%؇ ,]^k]ŝDE²JPla@9KU#d!׍zf ' ݝ#4!N`@Sb=arfw)z<r]ZQ/˕t@6K Ņ}oo7k;苕ЍmB)6i=qovv%Z} []ҐOm̱pdɣ qG''zu*SLHg=ΐw[Ylgp9ܑs,>cH4R\soiH('s4)c1o xΜt^>i ىA,,K9:P H\!f~fcu_PK )_b7ץW|(tP0>F_h77_^󩣅9}6Vth@[Rm2ܺ5̰7 8#nec]F}]u%w rCQ2 >,/"e(n/VwIdBv& rV{C gߛv7:j2wRSfɀ8iIΕss2] "N۶qZ6|k84-XCZNP,3d`5MF5YnҼڮjqMfOLM~Xwڔ '9gbXOriO2ˬ !Sr`n?vnDaYL*0&w.1ks}#EK~ql iﶜ6q[xߐ$f>q*8=S{=gMVڴcB85Y !ؘ4tlǑt*r͉tc6 Ʈl֚vMߘ}W"q"nVi.@=Z/! df21Hkj,m/͗8N_S$6uKZ6zv:j Fj9Py;85GúT|p[Dk:k |WOJc%_8tX}DC,|<׀,X$LJ~ϕר?|[5]_z@ݮ\53G|m*N=SOX fonHL/xp r9}:٘Cc'tky/KjW)-\:gwٳ#WԦQzϙ} _wpnw+6jѐM+s3=6%>sK믺R[7HһH)W{o"X>Y%a ` R[݆[Xӗ5զaW9SEIyfdɽ/h t& Xaxmm3ՓAtRZ=۫5!7 APq%X%Z.hx@d_g~̾ s[ia+ J)   vD۰v6ԡƳҢg<5eAI )iw*L3] 7[WeH#5:{<\%W6B^sr<{Ϡgٚl`8Av`k;S<화myfX#{ԩQo]£n=$>xݟ8S+L$=kOm6˭@&X%ىɞn~%}\|hu[-Cx?5:1t)͟}*`FÙ n3s :ʜ}/rEHUr u] 3a';~u*Ob*oi0]xWL nOЧKJ<~%S`(TJ8am^0 ^> %,GǩWkUh (ܭԟJy.<:qGg?Ju?8YLQyǧPOF1N]qGw4MaWNa%@tbd(avG`Ld:QMΏos~BQ=#&)d}TS`kЙdblV7% JĮgܛO[oW7dp.o>eMqNʢzWՕ"Qr"?|#ߦ=ד0q0Y3^ؓvC^em,ϏlSUb€7p 6dKN2)qdltd+{p͕L>Y' 1w|ުBΦNOnگ}=K_R{9k߆OJ }}q51$M<# =իEB:^oL2j6_|Qe3?uVF&[2;4KZQs~GZs4JN[i*:~'x"Kw9\LdD 1LCΠMcPkϖNypl-O['T\{?r w"}3=KNuR!8n,E0 G>"d~iQ]`{Mk_7ϲn3:h~{ ABS`Ts´'j 4 M:Ii,c $DSH^k,1bVQ!;ˬW;S|D-vqQ?2u+Jc޵E9"3XFѫhˈL(IPaY ш'x&t |Y9@"s)B`9&g&37%S~crց ³R7)EHӂ,;d,Kv}P @^&FkfM T|]+'q5g8`;`,a ׸ |ShHnjqZ~_+{e1T|ט]g)2jz h*,i9S{h](Z Ϥ@uЀ8u(8~\ ubgL&~H=L;3E3Lh3Y.|eaae7'γpހ8n|eq΀9Ken\քL&XV1rwfP2dcN3Zh@.=:W:`߯)dP}p~qh7 ?7mS t^b* 2eFM3ӂ dhz8T~p& e|70lE QtS(r54w0ZEm)*oGv:>ZfDK|ZeexU+ڏ+E~3 7 >Y\'NGi@eJKJ?ZÎ(}9P[aC#=a#x"mnW%H rnu\=  k4ۂTjVŪսՉ[=d;wơwm\;Xzx&Yy#wu]7}U7ۨU^}vƺu/M}>Zjzz^'54p o4v÷mxPc8f ݆^eÐ!oX2ی 6i9SƔ3M6zͣG=y;?f;9{,zWMƱc=>~ǿq?0uFI|km~|}z{1x;>q'޳,)[756m57}iY|o6oZ-}--ٖі-[V5lX9[Vku[-m-ۉ5{nG#u</=''<#x=2ugyǹՏzM>}t?iS'OeO^s-?f~,ch{]GwGvlǖ{Ĕf'|M^M:9*C^;j )\ hS<UMJYe5w*e <180-2a +C\yVְ{YY`eV&кRH\P U ek=2:{+ײהr=:V+C}]+=2^ XGi8V>F9S}MV>/#0͠q89Vt{=}O>g]/ >ztw/iFǽwX[ + r}<|%VSNBrYki WVxmJ_iI{jJP>{Zg}|j(3}u@A~]I$B%K TtIy p<e%x4"*pV$@DaMÓTnY9Eg`aJ+|HRP> hSb{Sq÷I|ǣ%mJ0`dat,יR}+L_b")EO+(P<$sBٷCנ-yF/2v؂~iZVBclpn:Y2a4y$2v=֧ ӊ%+tJ_8Yϳ')]+aQk]3FxFW|Z8F1QEjL_`n,,%NkF^?|D$㴂gbß /1BFϰZO/?bʜOa3)%(SpIPm%Вz͡?5w`i+?EyQ?lr_֟^~ }\vs}A/Lƹ rWM8a>h~y7 ֖WȶE:dV4G)ϰ/Gkeo2*{cxpH_/ 5LgRmTȢZ[%vTˬguZb}FǏRyz+ǰ+rr%\W]v |gR_qMc))1||ם *1 s+q*2{.άיݍan/1>5)]ݣ#ZrO:jTchÍb=)$K>l4g{0iTt_'n:endstream endobj % 'fontDescriptor:AAAAAB+Code2000': class PDFDictionary 14 0 obj << /Ascent 976.5625 /CapHeight 683.5938 /Descent -292.9688 /Flags 4 /FontBBox [ -1111.328 -294.9219 2107.422 976.5625 ] /FontFile2 13 0 R /FontName /AAAAAB+Code2000 /ItalicAngle 0 /StemV 109 /Type /FontDescriptor >> endobj % 'F2+1': class PDFTrueTypeFont 15 0 obj % Font code2000_00 subset 1 << /BaseFont /AAAAAB+Code2000 /FirstChar 0 /FontDescriptor 14 0 R /LastChar 255 /Name /F2+1 /Subtype /TrueType /ToUnicode 12 0 R /Type /Font /Widths [ 589.8438 527.3438 476.5625 720.7031 476.5625 748.0469 562.5 650.3906 726.5625 511.7188 0 0 0 441.4062 472.6562 550.7812 609.375 460.9375 531.25 812.5 472.6562 484.375 746.0938 507.8125 632.8125 738.2812 746.0938 681.6406 960.9375 746.0938 507.8125 738.2812 390.625 441.4062 738.2812 609.375 695.3125 531.25 462.8906 636.7188 828.125 0 898.4375 0 683.5938 841.7969 1601.562 273.4375 912.1094 683.5938 894.5312 718.75 746.0938 1712.891 841.7969 894.5312 1199.219 970.7031 755.8594 1556.641 1289.062 1218.75 1082.031 947.2656 935.5469 1054.688 1236.328 876.9531 898.4375 0 304.6875 0 800.7812 265.625 708.9844 0 660.1562 0 636.7188 265.625 636.7188 570.3125 570.3125 0 265.625 570.3125 593.75 265.625 667.9688 445.3125 449.2188 964.8438 437.5 595.7031 523.4375 464.8438 595.7031 277.3438 595.7031 558.5938 669.9219 562.5 669.9219 484.375 523.4375 449.2188 476.5625 476.5625 449.2188 476.5625 449.2188 650.3906 449.2188 449.2188 437.5 597.6562 675.7812 707.0312 902.3438 550.7812 1078.125 1078.125 476.5625 726.5625 828.125 550.7812 375 652.3438 902.3438 707.0312 335.9375 348.6328 443.3594 335.9375 269.5312 593.75 449.2188 593.75 466.7969 613.2812 613.2812 613.2812 613.2812 613.2812 613.2812 613.2812 613.2812 613.2812 613.2812 613.2812 613.2812 613.2812 613.2812 613.2812 613.2812 1000 1000 1000 1000 1000 1000 1000 1000 0 1000 1000 1000 1000 1000 1000 1000 1000 457.0312 570.3125 566.4062 523.4375 335.9375 585.9375 933.5938 548.8281 523.4375 476.5625 591.7969 523.4375 476.5625 914.0625 501.9531 523.4375 476.5625 437.5 449.2188 476.5625 455.0781 478.5156 476.5625 513.6719 507.8125 298.8281 695.3125 734.375 335.9375 335.9375 607.4219 671.875 550.7812 587.8906 558.5938 902.3438 751.9531 902.3438 587.8906 587.8906 587.8906 480.4688 902.3438 546.875 300.7812 744.1406 566.4062 587.8906 609.375 587.8906 433.5938 587.8906 406.25 335.9375 507.8125 175.7812 333.9844 697.2656 326.1719 769.5312 503.9062 500 371.0938 636.7188 1050.781 697.2656 648.4375 609.375 609.375 371.0938 1000 554.6875 265.625 751.9531 265.625 0 640.625 603.5156 505.8594 755.8594 707.0312 554.6875 931.6406 636.7188 ] >> endobj % 'toUnicodeCMap:AAAAAC+Code2000': class PDFStream 16 0 obj << /Filter [ /FlateDecode ] /Length 1357 >> stream xmj$GEBY!'<M$ VӒ{`UTD䉨|T޴/}u{?>mOǝ?=ܟv7௟o˗vsSO>lvYw7}8^~K_Oݿl{i[ownn;n;>oW%~wцFh+W>[= Ёz)БzI̙- *@7ەASv0/4_ӈ߀ِ&Mߐ?MPo s?$0,MM9Q!>eG]E]('V91%:_ W0Xg0[[3V=W~ڭg-8WiԸߓs%Nv_txGkF]kF-kVԸPѫɇ<]v.);zq⯘KNZZ8O?ώ.Gu;ߡw?9ɿZ5 fO~C~s,-5ߣ_ 4xe3OR-} c*ĀZ|W,zbQ`oP{? ~ٟp=h,ps?{=!߀3t zcE 'ߍ 3!иD铙qFѫ~_+8cgXDGȎ̉ N>{Ţ)HcΤXacF-)K-9Uӧɇ<]>Ws)`,<\`eѐ3;ѓ;*2 CNOVN\d?u ]vGj)r"?*W~07^_9? _ğ8yVs]sss(YP3{KC*~U\U9Ro*~U<-I?=V;'nFq'Vٱf6/;ٱ.Z:Ɏ>,;si8qciS >\Пd[g'zP,wzۓ4iVR75CvO`>w1Ių`'?WQ%X_#ʟy&9.Fu ?.υCr?f sal@.`s>5{>Cf='RsOI9|ГYyL{&0.;94jS +oכ |> ^noJ/(݃endstream endobj % 'fontFile:/Users/dirk/work/xhtml2pdf-30/tests/samples/font/CODE2000.TTF(AAAAAC+Code2000)': class PDFStream 17 0 obj << /Filter [ /FlateDecode ] /Length 24653 /Length1 44000 >> stream x`y'0F#zD !Sc&)DFTFDFTFUDUDyQբ^xed,e&rl&<ܔU6Ux-7ޛHdc< f޿J҇yǟ;[f+? _ -{cO>? |,/:H{iЧ>L~T(ޙ?VLN{~O}ж vz SU64??G"/]$ mg[`[R׏m|_qX&`4),`,C ZZ 6v2^~0ǀ=Q^T 48O0x )'@ 8qAp|$ H ~ς4p*Ȁ Ò5'x\yx|'"u2 -7+Y*`| >qEm&0   % ~̀obK:_7߀w 7"CmW.2#] {*߿'p`??'K_6(j -$b;8 pN%FFXPcz`tW'}`Zy&2):a8fuU\;^hjsޞǾ2mҍ@GaOBuN_GkvlvwPL[gߞx/Lg+%5VVS1N(-(Q A)>'\y /_<=v{=3i7-)L!wa_ W{`fLJ!u`:v۩Nr~%53dEbbtȯE,ӕ3+xN,MمMɫ.W"(pQD£+W0_zݸ.314 U+O$A>k3$z}=TzaBME`7{ys\-6$砸K+s,u%&͇dZK,W6(MY'0--C}|`a讫7o>ۡ"{Dvhk2Z+7ޑ[G_է"k[+S4ϾUs=/}4pK^!]o<+h<[|~zhʷ!'IGseS:;FtQNz^_06O6{fYʃNnI-gnN$LNŕ| W O凇D.WʹKg~G{LjMF]gQS& \B=gZISK~hx\M~I}/_ O+oﱓcňiǘeßxjbxlVa}..$f`N^aԍ[0)b)c{>>t{Y*-Ptszv͌ `%eIlGm8J_Š Cn݋tft$Dr":<[DD80OI5e!V*XW}DWB|ЯO~C-:}Vd2e>92߀RF,1]mivc*\=~*0 u?dnܬ|ʕt]^Dwim8w]7=s>i`pwuƶ/L A*cC!j믌JLZD"sl1 -ýeyw([V1 DÚ*'ա!m|_ߪXU ;=vHDoa#w#BznMXe'OM=&R(v],g$),`yJn1J`|P szC;o!Lܱ}J0;5Td?H S/of@ia?76SDjZ~ilZ_"ݧ,~}YboG?m|>;E ^y czks$.ɔP h l*CV;՜l؏I霾ja[&ڴl Y=+5vvV~FHxqxh߄x"X bzG)BEA|ҍ-`<(hjtrqG[D|WWshrGy"d2ѿwzy)o7iRL##o /_1D~S.Я9 [d_۩vK^lODžȈ1bpƛT)ۿ'Ӄ=S#X#V̋}G!AȑÀ3`cb'f,Iģp~qk#B't<hR pIW#,34%hU?N n /Q}cg?s*~Cu>)n\WƳԐ:-H>_>uʡN3vXcL;j&y;]6850W>003-7\y^,ɕF1ƔΑq%:<3a(Yep`hqtP]rvA1Xr.n;7,f͊Y8cPXZGu*sb1ņ>OxPC&A*G&K{ l4LuJ pu6iPmuLS]؆]* C1VN@G/j,ؘ6iq!a71f!"FHf%=Wno跘ޞ2on_TfL\pZN =wĘvuNKq8 U:dE 뷖Ffav "\'k~niԨTyd.{2Z곖(u K1Cj\`:p[d!FWN1QWa1.r!&q1fsn".\czˮmMuY[]j*qG` N-$bU b;lPA/#]%&$6y0LkꌫD4Z) '^Ѹkshb0kEn!(*+:WH8\4Vo2~eR%mm&*~ T0.i ̜VuNu)!nLy$q:Юfz{gWmoWƱ:D qdygU;Q?c?~ N8 VA,#ql/3̘cVOron(v|ɠ@'8nf;s&6P,#%Ƕ^G ;#' (9%XEaWu^W ?}_2嵙] F#MT  8kDnq^Y]sz 7`v2<  H6Lh έ=϶,s5ztN7]pywȽг]qkXٯm)~}GNBHQ-{! f𰁾A7^8t;(sz l!>3xj81y6|6BխY%"o":N;\Bdj'訒*4L3(GC2( XFlD3H);JMA709:}F9řB?Ls7vFP*,sJʪz+o ֦2:9\t,"xϠSH"tl-_$ I"gWPOB5x%2:˶fI~(4"]Վ3)EMxK' n|bvߏ i~$뢹p[SzBܜs^eqvtߣӠ9u9[yjKdiGsKq=p/PU e",잻M9}y)GVIJ&&/J΀m CgK?A؆lV|puZZ#45({.!JXVT }5U(Cih0ٽhL3KSS$Iʬ8>o{>毃v~\3ti+|}F9E^HD/= FłOC"{y-'-F 76\թ,AKoal݄A[;Ȼͥ/QWn]^B1&Ømt#<;B G;/Rz:;p;)L#3?nV,͹%ˁ{ɢG6aAae,`-hc!_ B0]*-2)bzh Z3 :c§jC{hkoC/# ]P]oô8S|' pD;H8d[wvBٰ)RQ6@,K2WR HX1)5aXm[,(|m[zԑ!O¿O_D\R5\bb)܁[I`aބħ̵;k}W:>ku| 7thUƠ"emQ.8C|%mg(dtdF7R46ߢ$VժK" S *ZO} Tܺ 4~gܜRSSZ]3&$ l cB4@T/pĚowY5ECze\Ϛ{Awvw@#V)HQuQ0# ~ۆPl>RۗԾ&\zuX"~Y+s}2DMT2eRݷ]ƾ%#wQBriR"pmhj˿PBK}J~s7^R?qT껯񩸌7~쓣_x,gDqt:KBlFΠRv2x鳩K,lEm'KgO$@3Ưћcˈ :[Dc!c?Tco_EW^ִ_!*J^=Nr>fƑ D'GZ>ɯz|,|̏LFQJ#!U4DgPlhcvj ,ݼ3W'^gى\v2EU.l؟ (*NR1EDߟI((6y>MfNNeۺXh„HD~uYdk0D#n"4Mق4u4uFs46;tNN qE&fȵNn 2m 7 V2JfAS,/,$UD{"y-9E%6_I/YZCHuF^ȉP|YGsh2Q "~uEAo~_ !Q܎ ?B]ya){9]|/MzFx 9ތkBow)rl\"/|~<cj׳uZY6m|D?ln'tvFbȘ-^r! i |X'P0PV~ѠFOwzNl (c6Xӯt}%}=H<{v'po?ndh6בcǎ}ϻ>m:ݫmu=A1uNF;Tsc^l` } BY,d t=2[U:m"'!QL>Oת3TBC6`bV#דF/sg̞3`0?`Qbfrv2T0}-&$)3&#Dv* q[!HPOW<@G $++F;s6f N"x 6Db cmbF{Atwɔ0Øy.d3#8y wIFOݣty=|^7n_j4;T%_Q%}+ըPopw?ô$gU~J5)'k#{ߴ=O 66jE#CѮJsiU<@Uex%(dq4*9*ׄdʈe7BYn*8>d*BsIpj whKIg^xp=sl6l1Rj &e;iNbnΩጤ$ÃLey!Xj4*kRj.ol$ cZ" )ǿ 䣑|49JB J6.s6YUx7y|d. )ɴV(3cc!^ŅpV x.2 |O3DpϊvaЫ\iY ˬ9iṈll G٘0iQyA%q"lrF<pUYYIlHpڌ2-WqU9jSXFv; OaUd--GxKqӧ\M G pG9>G~Ṓ(3F? Kv:cy,OhIcXVA#1TkXǿ >A.BN@?ڨ`X3q#S,;V^xByaeZ۽> JӚ}oմZ,2, U894|/ݫ$>%7z TaFfl]n60v,.э*OnNmk H C3 s`hYy?oDK/]z^+lA˖.m*;>_HPb$]`$׹xJ\`pcMe)6\FV_8z}V/H%g+ޗ9dnۭYo׿$x84lēnwzvHɘŻݿϖ Ûp &v'軯L]M A w2x'Znc"JQMF1]YI2AN$+c__ nOR<:j<^[m'K0z4?]px.foh$<{-2lv[w=>=;9ENx, jy"9:$NU|dҫy@4{졞J`QY0j8n!0ۨnb; EaɕMűFz#d/ 6v~I4$[pD5dY]J1iL VdG0->uZM2(AP9mw܄/S#jn].wkcMU|ևm7p$n(0&:²Gm!+{ HRFɳl^QJzz8) lVJMHjX^ȥґ]ȼ'Q+ӠZcrmC'a}zq2S|^ILAXa*%}2o.=`Ӝ~lFTBv[BKneL؞Љ=Ӟ0wsvao #QAv.pJ$@Rjj|"|߉.#o[L1=&O6rGS'\f'k.\cóklV9; $G3$<9d#}.g=>ŵ).}2y%ںq9+$.͇,(~Q;ӄ^Oc>}ࡃjj gېw\_rN/mDUQ$KHȣއ2l%NQeD$2/LCP1ǮSZ:4A3ȿz-&ϵ~`|7 o| F?xd-9/WaD_j1tm߽!;&_[m]ƌZ[+,a&Wh2p%05p le=0?vxP?5g؉@v*UotFk[~8g*1Ie-Inc0yR\8qtZfמIyku]~j:B%\[c'xQT Bzf.Cyx<%A Ss~9JʷhRY:ìfi!3Ր/؁vymn ax ~]B>#{ \:jF\dYcRZ-3z5u SZM0D*N=`LYVyNT8үpW$93ƞFGm|k %;+'vGf5Z9Gp]y^ t֭MÍ=v[BI vJRNN^6_9ȇ^X[-OnrICLKu~)5bvWhQtKJDX)F/e&t ;{-Vw-8 8=4& 2KNW%Pߞ|rd*'h!qu1WVs,K|e}r"Q)s`$4][)n*2e3l@$y;uOu;sͯ(0ÕBMoK Yb+^\6nJbCEi wgɴ?m梵5[(ޢ~ =MCvt%(") P^mtf40BZ BX7k9BZD9dt.6ᛴ!iv*KnȫG0edrOb4TquLcpj i?߯\ `T `!f΀\6ƻ ;LM]]zaD˿P_c cz^c9֕m_7 Cp#:93d%KjyxaBl:ppQ3rd?-(S@2N1J=wXtqD&nQ밅/L }Dy㊫if;s/?lX)!G_`+' K L3'Qn}v!qLINg:#{.^HX4@y=HmHcT:M&VAJs<'3eEwv'#w!\/8Cn館zO!D/K_S»].È::N=I,>a%{@@pҗi0< {$e.L{WԅWc',%?$DZB2TO`;Fs44'~)Pc̰fa㠁s؇-XV#Xu/vYksuj^ kdL=eF=Go 'ZX2] PRBԀS75eP'W!kH'o%eXl|.85^F-x[Ss#%vuLCa_πYuk t׃ CBl!3&>r{Jdi(XYK*3óf2' K}ZiS*:挝kr/MH(3둎VʺN4Uu5>ty٬x70y.L5Ć}ؾ!<E'8?3v0O^8I%5a^V7J5tW5v%ZhŽ[Ǖhv!\ԯ<{VۍT柢pl_g=vlͷ?@fd#f}vgM߆a6Y"1?h]DL~_a~!^Ѿ۠\ c- 7_!B6 u9u2vo֖1.'lM ai%Xg$d(_ BQ8"Hb*Re&,Lku(dB-n(Na!5[$)?bB+|Nj\;P_>s*4>M:b&z눏eMp.?kuY| \P׳e6XJ iM[OX=CIM֓O}q*z2Fˍh@Oj1sl;&Fmwq;gSi`d\ Ѿ/fu:Ȣ< Cq!,].k3r,f.Lݤ}+:|~~磇Oߊ"eas}T7^Ou&\ Bq :O꟞`p}Tuax4y:91?罇| _K8ItlbQy/1?Np6JeY.}PY.܀loͦt50{ek4۰5"]1MM~"v5kXUpcEYAFWXIiז%k,ҁ&X{WFC+*h<c[cqXE-30 >/.ɪ/z6yrPlk$ZP)jX,#Q$JlYE} sP3u:KGjd&E ),me2o3d Z bƎ֩!#'V`ЮZȼ]]yZ gnX_jßPmPx445$'y__uꔜ@ .P1ڳx &镘(|Q_ KcDm\[U]Mbљ?P:͛X yb s ̙k-wYK WNܾڐ9G&NxZ2Zxrڬ8 x IUI2߂o O?vݍ&AwÈ.nq|m5]+YMEtaj Y1d#p}qy8֝_Mw{Þ{}0bmcni=pk@twzʡz-TYz ӨvGG䩀!'ިGخ~/|g>Lv{G=rV+>09 ڬOlN[t {ΟW肦Ռ.p)¸IKY?Qpgߦ$!-/gT^LK5QP%A-D~-]aJ?ޞE}k*J>G%`DVV#:QIo&${lza=칯Y '(]dNUd?jvaZv>hgKB|FYj]~o.Zѯ!Ji}qcs\&RZE(mPELQYHdr:Y&F ؒejg!7-^)_Ք٬ `kH,_kvS_Oм6hVctk=4kmk+>xC&7v"VDh^oT zaEADk i(^X Q`ūY&-կDPr%/E[~S0,e=5}v[X?npeJ<`KfH/=ݭFFܪӟ]}reCTQg9P201HQ.h07Ī~uBԓ'֘I^#*Ie)q]H2?E)(||nr%㹵 TƢQù~}d}d{K ,Vüzt؇[mXnfz JTbw9puE,S(E6 S/vch 0\UU2+(ի Gg1t ) R$q~V$/8ϤkQ6;Mۄ;92vw AG.A̝Lyӓ1I TRNSL&)+A &VMĊTVi:>lI |6)e 2ϡue՗C 9;`^YȰDu&Ե8+Dž$W.dC1}va1^dPr~uTob9cR&ihKYa66ex4:"%H De4+"9I3<7abB&S06lHp)D-TV jC14J!5S%LLTqf#ج{o`AG7U{Wm{ VfhD.z4 s:M+VhRy &,sm$ 8:PE8@~zTn:C : *pgn/g.Q3J ـ9 -d_a+QUCG^Db;}>9djLdtBkj:7/v $ Q(0q}]pfR *y=G B#Xd NO]l[eȠ!fTEՙ(9'lEk+1)IcyF]X2{ɱƓ,n|hZ;;b;-dNm\G(ثj(;]HOpBoӟ=z+b=:>˟^kڇ}X3(+z#T<:j!z<d1NyM=b[(ʅH.%Uz*ɀv\+SI!?U>wu4DA6;MU9TW/ *qXRVs}ۨ_#&ݶP64tdO_ 6;mKNrI3d3kg$_&;kj3Z!cP ?˲.J+Au792Fs_hr;ݾkjw۶pj5blWٷM4f9uw~:Ȫ_+p3ߌĹH_=s5]8xs[/_Gֳ_BT2^_jrz"P&ςz2&9^>rj8===@@d,,!cVJS!-0uc2p.G}θ.C{:\f͐zheԓ!_Z׆}3ٷݷۿgΑQyfZll^QtgbStDVk[{2ӁUhu6.m rD&9!ɧ^ke2l2Wچ^9W;fNgxy!x菏6BNo@F0Y7m٢( 9(Ϩ-?tnUf2;N0eWHCzd7m}<'t96l+'BV69,;9'M?g`!첖7_m_zbߎeHwbݬc-9~ GS3zcM\"nR|+W *=Z4+X3Qaja']~^Zw=}<70wc<&KdS[Z0Dގ}Nf~ϟҐ'oga&EvYq36nބj -X69Af2WʟɫQ$Ǭg%!A"frVHV,r'e-ۣLǨ 0,hKRt;hi{)Rspw Fgv 4W&v^M2YRFxtf١!0 yLOjc\ };q>VՔ}1OD[}[8g7IsRJ~/R&W թߔ^an(=1^Ɩ_:EXvwwJ'V4Z,7k4XM=.w}qzkm..>a>ϱEYqʳ~|^d84 z##NYKW/%I٥d&A@`1z14Vn)l >o;9J'Cd$d>1{]/tgtWݸ7qHŽg%l$ ߭ `s4 *GwR/ \.+]WL7ɞ+c34x@ W N6h:[xcL =iR)Hf0Vfq6N-zsQծA`h ɑxA߶"IO'-0{yT9pzY,W vB6yAveuyv&Ue斖rt D0HQӺPrgrko·۩ZvjTƪʫ|SaI.MU''yVXXZ^"V{o{f} :k3UYfFxN=X_.Wqy8H}3S߭tfuK0uWm\xuw޼DWUg~E#kLs5zĈV+56^/\ .+: oAn=DL Sl)UjȮ2O8)lNb㙬BlSXϲ^3e:#9O-LQCx1%'G9kT:|Ծ/7^Wy= r .Ki+Z:80Yb]=$- lDGxw;8375 ^kPz֮eJ蕒@@6z-ـnrzMry~g#hw0I_ԓ3O-~Mjz|"RMv:R草S 6x$4&idHúR2T+㾅)'9 W.H`\CRЧi7JyWo,& AVxXL+#p]tqFk xE∑ tssa~mVC0'j=?ipZZi/<qD~ En #eظu%Tn_Ը7}97nj'+>_Q?.̊fA挻ak߱MI=[Wg(Vhg~_ZCSOhM0&O?%a)'WX靰lIh&:H0q@WߩX<_ a#'KSZ&ghbLZ3bz.CUq6cO!_ dOEfřE,h&ӪifFpdďaUtq3-ndI_[Ĩؒ4 ;p*yGˍ!1 `/ Iﻷ|O[Ԙ!3\k_S kH䋜>xj|`/+~C@;?Q{z(s ?z4M06 H\pm\UFmF\5}k4Yyኗ[m0ZVe5kkͯ*q!AaAzTGpZ0QO#oFxrQH#@1 FAa?yGUS(LH%W~+'^ܐ5AK!zxJKqj߯Bk ~V9zW[E3Ѓl5& @3 c@fr!4:ۏ^k_[-89 )jF١%v Tۣ#M=`7lmVgy7 R/1510j?mh飐V#c͓~a0f -@݌I?!}qU-fEڠ_%ndc v#g(H &5;/~0GZv1p)a1a1ё؟v✮@׫{Mw]7O_JBIIR+5y6EL ̤ c K]]Wvzj};v_cؗƧ&ץN}CUg|iȼjͺuהih0GӞs5gA|ټ[(ߒ28.qo^K{\Wo ł k />mI뽢3EJ|%%JFmۋSljKE{~,HGUG++>i837H>`:`=P}Jkʶ7*g*PUqUwkUTwV޴P'- igij!P $^yGZVT0N;DSnBC<-irTiԂu?Gp_B8xQ;&%f1ѲRsLz b*(GJ~N)w5ЊFNHYC eȉB{H[+C .BR]!BT#w{Vk7SΐC26&mZ]I"[;II,iLy@iqegVTފ 94nJvZR Ovmv ?d.J㳔z|I 5їhO Ѷk!hJ')xҤkڅI IWD$fI1 ]74\M]ӯFJqZJ|RI[K#ؙo Y>C$3i|ٵN6!gHBY Z/_,_.1>dE6[&%NO۩kSzEh"a-"i>iӭHuZN{;;Is$2q2UHu -)w.P*anuwr<| ]7hȴK`HfT"y3݈[imei;dRz,SNԛ`FP͹ۜ4fZGE|i1xZcՒjND<{J5GWSkh_>Q-m*o#7MoYX`Ak5`m2gLہ7t{;g$ZI+:L[]sPq;J T*tIo6DCt|.E"o||޽GKow?%-'@A藍y;سK3V"V=m3+endstream endobj % 'fontDescriptor:AAAAAC+Code2000': class PDFDictionary 18 0 obj << /Ascent 976.5625 /CapHeight 683.5938 /Descent -292.9688 /Flags 4 /FontBBox [ -1111.328 -294.9219 2107.422 976.5625 ] /FontFile2 17 0 R /FontName /AAAAAC+Code2000 /ItalicAngle 0 /StemV 109 /Type /FontDescriptor >> endobj % 'F2+2': class PDFTrueTypeFont 19 0 obj % Font code2000_00 subset 2 << /BaseFont /AAAAAC+Code2000 /FirstChar 0 /FontDescriptor 18 0 R /LastChar 255 /Name /F2+2 /Subtype /TrueType /ToUnicode 16 0 R /Type /Font /Widths [ 0 554.6875 662.1094 554.6875 265.625 814.4531 845.7031 648.4375 0 613.2812 0 0 0 955.0781 380.8594 783.2031 632.8125 662.1094 613.2812 1005.859 1007.812 697.2656 609.375 726.5625 507.8125 511.7188 970.7031 769.5312 301.7578 789.0625 769.5312 345.7031 390.625 970.7031 507.8125 521.4844 697.2656 292.9688 484.375 488.2812 294.9219 0 507.8125 195.3125 484.375 636.7188 294.9219 500 650.3906 597.6562 740.2344 390.625 398.4375 650.3906 390.625 664.0625 390.625 679.6875 734.375 703.125 628.9062 734.375 687.5 390.625 650.3906 515.625 0 703.125 650.3906 839.8438 714.8438 742.1875 476.5625 289.0625 0 212.8906 0 0 0 0 466.7969 968.75 0 968.75 558.5938 539.0625 0 968.75 558.5938 558.5938 367.1875 562.5 558.5938 312.5 0 0 560.5469 968.75 968.75 464.8438 1318.359 558.5938 0 968.75 558.5938 968.75 558.5938 523.4375 591.7969 523.4375 476.5625 591.7969 449.2188 335.9375 1000 1000 1000 1000 1000 1000 1000 1000 1000 1000 1000 1000 423.8281 0 638.6719 0 0 482.4219 238.2812 449.2188 425.7812 0 480.4688 425.7812 423.8281 953.125 664.0625 425.7812 480.4688 718.75 261.7188 480.4688 480.4688 0 480.4688 488.2812 0 488.2812 503.9062 480.4688 279.2969 480.4688 279.2969 574.2188 0 0 488.2812 0 480.4688 0 279.2969 480.4688 279.2969 632.8125 480.4688 724.6094 0 667.9688 537.1094 0 654.2969 509.7656 601.5625 582.0312 601.5625 0 535.1562 601.5625 0 554.6875 699.2188 599.6094 406.25 666.0156 269.5312 0 628.9062 687.5 341.7969 621.0938 335.9375 294.9219 236.3281 548.8281 164.0625 701.1719 298.8281 771.4844 289.0625 335.9375 544.9219 162.1094 449.2188 492.1875 1000 1000 1000 1000 1000 1000 1000 1000 1000 1000 1000 1000 1000 1000 1000 1000 1000 1000 1000 1000 1000 1000 1000 1000 1000 1000 1000 1000 1000 1000 0 1000 841.7969 794.9219 773.4375 740.2344 785.1562 1000 982.4219 746.0938 984.375 710.9375 695.3125 894.5312 923.8281 808.5938 923.8281 953.125 ] >> endobj % 'toUnicodeCMap:AAAAAD+Code2000': class PDFStream 20 0 obj << /Filter [ /FlateDecode ] /Length 958 >> stream xmj+GE&dz? AЕڎ D[{.1,:TU|<2?47ug]s{z?wuc~vOOÏgggy}9|јМ׵o0࿏ύV~5~<694O;lqr;Sae v5}vmLWpb~ v5 \cN N01G,{C4` V9-uƆp9=v,d,ƴ20X:l'H3#8Ú쳳'8'FG3a]f G1MϱYq+b88LnŬ#+ zFrI9#Ok46|`.{֤1|<%bB?-&8ϠO+9l83A9?st~sGE/3TZű)α?(o؇0 GC9N~F FU81+:E^*洊~G8&=83П$ʸ$^'̕6$?oII FjfMbXǾR8/[U}zp귆{Qe's-}[o!N˲@U/x-\o3/wendstream endobj % 'fontFile:/Users/dirk/work/xhtml2pdf-30/tests/samples/font/CODE2000.TTF(AAAAAD+Code2000)': class PDFStream 21 0 obj << /Filter [ /FlateDecode ] /Length 19829 /Length1 33048 >> stream x|u <;X$Z)\`rIeXDAdDATAځXEFESESA}8ux.eResh>6erl>6Kx9\/j)/eSx)#.?bg;o޼F5<;}O=)8R~EKp /]}Z2e3O=^}/vpk-P\">/'z |\?/,gx橹wzBwKkˀQ>>tH<d/Ǯ~#os };Cx@+tx.[Vu|/ '!ajDGP3jA r!7 ݅ȋF<׏P;PD](NS{it} >ԏLt?:@! :F;P]@BQnt=b=z/AYt%A4Cz=>)ϡ y4DϠgs(~=> Q8e4~~8'Я%IT@^FѿDB%U)4z C~OϠC "-Gx&K[RՉxa@0WB/`s*Bsl:v&?g8l6-u|ʂm/X? >тi|܂[ >sb|೷Ԃw΂_omx|-X[r(y0p[gv)FMyZjp8LY?wyً@;/U¡sWlį9?XZ[<_q+p}H 4§^n.;9>ܮFVqzJ+;uzK\/w r)﹋K/B/^>i@0 u~3_%Dí>5[xb2L؟|@ QFnza @ԈnOsͩvٯG]}Ͼ;+q3=qa Zg3`3ExNĴ 3zW2k݁g"27>1,DW_-p~;v\n7m|4r2~Wߢ˄lu8%Aw՗?[if$Z C' @cktv6wvչij((؜ljkOՊ=g7BOݫ}Ӏ/Ew{N>l%_=3'8{3Ou$iEמ<͝~ݣyWg|::.r{1{jxΞK9kCk.3^$5ӆ:vsbÝ9 J[v Z?=rYZi͋xΣoxT+5x؂E vz n ָ%Uu8,B=M5=aLyRBs8; q'^~JW^ɋN] %7.1 >>/>\v$ >9}I,;NL)8l(=؞X:m𼻆'ȳ_?CEL\[NUou}H|q6ǯnc 9έsHVkƤ~?)/Yvv|wnsR.,9np^Pln~sW-^X+xag.;0lױ >XtaY>O+gi|X%P'}WݞY[sY*\(j#aD|ɌLx2wKyc/\Li隮SԵU;/ƚ\CN}O FXآ DŽ`@3T13tjj|)}鵁ܘ+Tu]z'\48x8-<;{kLGSOhɖs )0-XGzN8+nA$ᣠrq]8Ebz8;\GVsjv.j7>tjh)Mym{1Si=^;䕵VӜ@W=r.g3Lɱ!7shh& 8ި9:"йr09->\~6a!9#jLX >w:' fu[eۺ9ޢcǍM ےh޾2C;~XҊ#8@ZzPK ع.lœثLqb)(o+\tg YMs8C*4:2+N>w g0r7{\~lnq|cn$+ivBKqhJ0ύm2H$FRP8)& Jb$mD!QbM@4Vٗ\ŗ!?H &N~OS௉ImGޠ t ?$; /tBD`%w-71]Т)<}<ϯ֥(a|}M<7.^F)5biie`cڱ'cO:ti)Z*=Id[m343(.ƒW?H|j]I=hƮ,8-Z$V mƂ$|(CmdTxp[sV3|95}>[߰ic7bٓhe>7૖^hcH}s^ً'F-7mxĂR[rd}^KvTӟYǫvgoS`Ӟ@O;(1#3Nf\~GqKg܋B2MS$ÃS:DZ:А>P<9ƀ} Ch7Bɱ:$ml-}At{N=֠ƃ\~[/8;=}@p4!b\f2ӌ%M1Ι &㦈E.ߍUG#vṊ@W88x )Btyi WxK1 MƽD SˠE E4 ^s~Q]7D\ǝxvuLD*NkN^:7%& ѲB0҇&vP~S9s;;y =`+EmhH*d}S8Q QHJฬE0+*)}*MvG@kFBdFW2iK>6p"%rjTB ?+FHm]q>O' ǣ8R$[z(N(yPT0/:'R YQK@@F70U9TEybgfcnѕl1IHd <.]p5@A8.b8O䉥IE/Ao[*V`16" UR"E͉c:NIZj18,G-MT VO`# S)N"8J+~]\WwK'/8p#nۛ3?"Z߼ȡ=~~/uBR_@_O?KߞyB;>ןT=|"ݠ7x,_"uE>T/>?GqmOSt@^,}4O$T8@pt6ZޤLI M#Z! ,U/h%fQnQSK x[toGRL?XeI:0 K4 CH,`a_0d&"s)F㩝m۾8%nO B%کXos;~ | '\~C%s#Շ)0x+J _qAAyOzSOR}W<@>]1(xowIq;p#lѵk!.7>qcs遳HgA&raUQ0BtηPHnѵx|߄g]Z01F!Gq>)Wr&rY2bZNd;95g4̊I/(wn .JΚa, t59W&(krrb\ɽs<16fK4OVuE\K/F[ʆ e9mN"`Oֶɰ(bDthT"(̈"Ld/<ĖT'd 8RqXcfXq|ȴ ٬*ർH<]uC p/tʎhu4UbJ<,[d$Q8+hk~Ul{ L"7H3@4$I./[MF@\Ε fl9Nri7¬9W]\uQ|(i<8L3$qtlW͞`x5!|>]gƫԧ'+ߦ/?28GOW4^z~VGݏ}8/|n:Qjz1+:oOW19M}~Dp/M\ 7u[iQ$1MhOM0FBv[d(O;A`t( LU28װ| Z ;z-aP=Ly-fcݣn&mƈHF Uddʷ&8EJL540c<\dP TQ^CZ. Ʉo!$ zfON$]YLl_+BtTڎϘ^6&*TAg$݋Yig,h8`cT;;d NnZH RY(F;H1 S@,@Sbsʕx.LM.4IؘQH96F 3-G^5;&M4;4+tZ!$)wUI1P 5~ NLʁlBlZ0 )r0V55ID1:QD3Zzc@πDu^feZC迣c+C$0MgiJupRM^6XY-d]P'l6gsz4MsʔrBWST驐:7x.* v&c t@.nG**T q1\JNdԭp 4[>~-𭯠Ghq]h%Qi% l~EdZ{Xbx {JnȹZ9X~p݊IF ǿs#ϟikRa lB$脙V6פdTm)^c="Jѝz)wX]K h'+''Y-GVԴ/b`P@*:ʹgeq8qoit4N?ӈ6^IO_<זdOަHd%]B=M?͝3f3-}vG3pr;ceD.ct$fp&Mp<ѹ19/2Vn8y`'3r3t,NR9^D7DWvc8ֳ[C, OhNO2 &CVLf*܊c$&V1M٤8͘t-K%RN'oC[|/nZlu5,.nyb͖-i3ۤ8\RѪa_L-x OK?@xmEQg+D_ǩ֐,~ Ne)lU|MD! P>;UǶe jA|nu|;'0.bT?]sļ5|ZHv$/rnh;7n Z>3t*M~JϢf1+e䉇:`4 RpkB $gT&8#x&m[AY4pbg8Pt+7o DWEs2.b-E1Vbzi8Pk1}8G7W䰨nj1Zqӡ |ч̃oS0Q>x +itZk0 wu-ÓX['f'ST 7^+(U99{ dž"j* J1NWqESH|}AMFKOJ!nÎN|D)b!mDкL>2)Kh..ʏfDIw/س #hB4c8ḭءޜ隊X*M4=SSJqqA9:^ݮëx? ;3>M`!fL^n0'*2Aj.f] x#$/zGs!%ixIB)lY"F䕿|p47m}•ͬ!;by>y?_N)ogo_ѩ}dhPu%@O7E7Sh/7Uѭ=}ԋ֜]anہGL su7}?6_!xt%clì|3~p8O{Xl5y.?{m, f:. ՟{"O==GÁCsS|~7? >] C)#\IO A7f\ s#_~|\}\(@|~Cw|_?sD=&{ ~~ G]?A/^?;i@[HO߃@g ^hYISO &9 n&McuƊ$c܌ \'\(̵\J7S$js2xs)zm 7ɨ%^5Z$}&iAɔaE=vYll,F09"0}s+*Mz0pfYϾҰh M_c,a%5b,wSH J kg`+Į`.R# HBAoXQ"}D h7"M6pP Ƀq1E-dSJ0BU^lqS25U4cZܾ8蹈.OQEq-$kN5 627]HM<Wڢ;>u|b~J_?S^PCiS%$k%w6X\51Kq;7WAOAs(~_95YfK9Y,w.4jp(xwn'MrI&Fppc:OCfuzr:8-Ýu#x^BG>b}XIJJ_GgQR_:tv!9Yz ~t^LY ^E|l>dKpx\ܑFt`sn;Z9_ٳf2WMvl:}a]G V{g$4;k 6w7ާv\=.EVM:pSov8Hm? 8V۳,Z`?UM`dy0앓hM´;{;7Zp]2>Mn'а--7[rlVv:yA6(mqGWRw rOu=Qq{Ojm!7K.'\459xd&f%ӕڙڠ>Fvᗏ}tHH剉CG#_{Еy$8z=CK s{kUP8F5oZA_߬`~FqG?}1@_Tyt.2N`=sޤ`"Hj_hs&M)2fY=INV G'|]ȍ>Ƕ3cSUӓu2ځB漢;05*s[kˆ(S󛎃ETD,/&gG}=uN玢d+h-퀇oj|ޞ[Q9D%=tt7f91<D t:4ȍƦ㮫o6hkPڟܠ67 .#Q)ÛT›oǯvn?յG&<hR?]D&-dJ lҌQ:wnMIкu}}u}뛻9 ;/im.3-_cv p) --u{c<>[I|/]>:'/M}DBFʧ 兤a\KuJs5]ȩn[\B-+C_fItx{fOa G$Y'e+K۰EͭSZ۟5xapC 0^ǥPN)g M\25}":% b62L5b/2fBkyӺc!*#wt+ XdaIp5ibevW#S.KT o&gXExqf-j\2ˋǹ2#&{3+٩n=}[*oWѤ4baBl9$V3~PyH 4 vPXAic˴6l燶ŭ!d<>y[ ·.e"l- Yjz)s-9nWEՆ|k4~aXwl <;96٬Rf{GT7~4>b uwL5ў%Zՙx4#5g}ͽR{_Vt~w\XI+E>1:JopT VE>3C׋`2J|adܷ.׮ٳ+צ95ڗ*W6f&K]R/h+bvk0hXۢ @Ty5 Kj%\MI²l\8,nP+anpo#~0+W28nSic#A^5'RxJeV)W>k DW<9jT/Fܥʳ »k=̧k<0zF .>cࢵ6Yuv,#4Yi.\P5$i*7hpczFGV{dTirKX[=_ڞGv:'{Clq18 q[c=zVf;WJ(ĂZYe!m{SKneI\R`c$iXxYE\!:T67%8=v6.d ~XDJW脣D+%P*RthzTrti$SXvNE2ǨY@V>YYZMzm?oW0K@׭}4e{MUXؒ2]pr6Fl`Rt2xȨ/f&3"1C8dq<`ne+6E"#ޢ^C=ޠAٸl?A-=fܮu <77L^elR 4Bem5o旟j•|'9\gA3^*j[-׸439\VV4]X^?Mۿ,o6hBe2|n YxW$i{}{}Tr\Nj69e1 %Rg8c)KҝjpI'‘!g8)ƎzXX`t!mC}ۃ3st($ʋd} LE%\nׯe'-_G'w^Y} ~slLrG 꾁LwOwcC!¿cg:z؇1 jޏBi:w8C}PqT=w1'\Bn7dSwӵ bN>Fׄ}uFZltX{t9͋MH., JzcOמ4vdrdE Yȣ 5goMS^YOkNb܍ʬ1Xx2_}]2޸Z [A]:qBSS ⱴg:^/N G2 f,W,34U_VU?Xl w#Jk{',8AsM[OϨ>>aI{J0Ako+;W{ow{Oa=.IY_=?vBH( a?<|#3 ug/L6ށPζ>حt*-|>oo6[ kO&={>B7T`l'@\0㴫kaCH2|zw?ݵ4o"{Xkׇ;EwnVr^=z̹LEij={Qwtx,-lDpR,Ek :mO7iթI](|`y[>ieqp47ZӸⵍ,rl}ag mA&BcQ˗8q7zjw[_Vףb/^hmZMt>n5",65yP SնVGο{{Kp;3k:'4A~c`k㽻&ŻGqm#F@ ȮvyOYڱRn5`Nx&qB7y&) UeSk &a \Lp 3AyjUItKSp]G4v-on'It.͊D ]c@u^w*AZHػ]?9c[,]wC"1w)sPwT mBW2X؈^,zp+j0w<\+c4ˉ{B%H&u&U5 ߟltc:5iwԾ<;7q(.AI{G|оJe}}hsӑ w}s9Bh>u ‘939> ُwswyI4/* 9,5?yU1~a4)|@[̰Hdއr`霔 (jNM)S:'k?~o"r\}LmfȦ3717y{FP'@/])de$skA'0bv$y+oh }V[d3t$WIv]6vqAӐ=S Nf,wq߼Hb5LS^_ #b2##>q㣺no!.njn>[͚f}?3@u߉_ gsǟ:G?ܯujo;/ 8_sid4+ײlbHwshe2^`L K;~L*˙ rC9߱fn=[d0eeG>ays]L.Ap ._WyNfwzyΥQz&Y/-mcy5Œ} Mg1*+V~Xûwquu, 1>--"ތI%+B*{ky\Hr|ʅ"Z߽/ ۥYP.nt]y m[ "WH|~]NL[{GT=Iaɪ,I ,,+8yˬVVK .Xu,ar l9@ ^X{Kms38ct@ {(U^$3d?InV7GTYU%jR- c A6[Yńn{hDLq?|h#NRB~G?ٹK}p1vڙԾw.{F[nݤOo 4x3,};i )4O,J.[knE(xp=9΀|\CpPqZ>wycsFf+5rЩWO}=SX/ޫ{<}ʙg>S9^ |#s}_t{##݋=z|=38C7l0:#$j֏}pe9͵6jmmd-v/#&V;fЖQn-cYڢվnY6$HƅZCxZ@˵𿪵x YkHK((twKFATJ"=Aa؝m֝%x`Hѣ#<M@OF}nm"i7޿ͷޘӉޘ'#R,>0nV9/sjbO\1-YIZljo%}P}OG,9L?D\'GH1ՙIoW̠98;H_ ~Be3$~x'!d>$C#M*˘lmg Qb*J~rȸNLU>?Wxx\ h:=}B^dIGme4+#FZRWG$]yMכfc2)d8샎/r|UWa92Ƶ#QYhWS+ w6++j1cI928c{o=4ǪvƸ5f+Y=<' R3tˌ&4>يHkyge<>Ov= Vp^Saezv=t}֎=ܬjUUR}s~|o~Z6M.Z=}sUk,/"e~{(qw'.o F#Kyg{NTct~n[?Ev瘞Rv'akj&z_NRO_y+y7sz[q7p_ef:N Qn&/w:Α~Kn׻{ѝwwĺ3 OLT}۸o/wžg=S[U3g͙#q҂%[k= Ձ=/=CTSc]]}OX糡w ] ns}lȾ~O؊XU}R.endstream endobj % 'fontDescriptor:AAAAAD+Code2000': class PDFDictionary 22 0 obj << /Ascent 976.5625 /CapHeight 683.5938 /Descent -292.9688 /Flags 4 /FontBBox [ -1111.328 -294.9219 2107.422 976.5625 ] /FontFile2 21 0 R /FontName /AAAAAD+Code2000 /ItalicAngle 0 /StemV 109 /Type /FontDescriptor >> endobj % 'F2+3': class PDFTrueTypeFont 23 0 obj % Font code2000_00 subset 3 << /BaseFont /AAAAAD+Code2000 /FirstChar 0 /FontDescriptor 22 0 R /LastChar 162 /Name /F2+3 /Subtype /TrueType /ToUnicode 20 0 R /Type /Font /Widths [ 1000 1000 1000 1000 1000 1000 1000 1000 1000 1000 1000 1000 1000 1000 1000 1000 1000 1000 289.0625 523.4375 476.5625 523.4375 828.125 822.2656 681.6406 470.7031 593.75 476.5625 593.75 562.5 964.8438 593.75 390.625 437.5 478.5156 591.7969 730.4688 695.3125 759.7656 730.4688 578.125 410.1562 455.0781 455.0781 650.3906 546.875 591.7969 650.3906 476.5625 593.75 546.875 335.9375 335.9375 552.7344 775.3906 777.3438 617.1875 714.8438 937.5 478.5156 593.75 587.8906 591.7969 335.9375 591.7969 652.3438 437.5 476.5625 298.8281 591.7969 734.375 650.3906 662.1094 734.375 650.3906 734.375 662.1094 707.0312 705.0781 728.5156 859.375 841.7969 982.4219 685.5469 742.1875 568.3594 951.1719 728.5156 867.1875 960.9375 710.9375 789.0625 1017.578 917.9688 808.5938 921.875 617.1875 892.5781 851.5625 753.9062 531.25 953.125 814.4531 742.1875 750 839.8438 910.1562 707.0312 707.0312 853.5156 925.7812 923.8281 550.7812 873.0469 953.125 664.0625 777.3438 491.2109 491.2109 491.2109 1000 1000 1000 1000 1000 1000 1000 1000 1000 1000 1000 1000 1000 1000 1000 1000 632.8125 687.5 759.7656 585.9375 585.9375 580.0781 789.0625 718.75 695.3125 675.7812 738.2812 750 890.625 890.625 849.6094 902.3438 687.5 658.2031 976.5625 484.375 664.0625 523.4375 591.7969 523.4375 1000 1000 1000 ] >> endobj % 'R24': class PDFCatalog 24 0 obj % Document Root << /Outlines 31 0 R /PageMode /UseNone /Pages 26 0 R /Type /Catalog >> endobj % 'R25': class PDFInfo 25 0 obj << /Author () /CreationDate (D:20090326212045-01'00') /Keywords () /Producer (pisa HTML to PDF ) /Subject () /Title (UTF-8 Sampler) >> endobj % 'R26': class PDFPages 26 0 obj % page tree << /Count 4 /Kids [ 4 0 R 5 0 R 6 0 R 7 0 R ] /Type /Pages >> endobj % 'R27': class PDFStream 27 0 obj % page stream << /Filter [ /ASCII85Decode /FlateDecode ] /Length 9536 >> stream Gb".aBli#uQJYW+s3R0DV8O($)l10hN%E/4*6D54-([K1]1o"g[#'FO+c>"0q?b<1#u)'!IeVAXpQNL2ps5X`-Q.8W`=AM%b]2=d%VHnU;,5JJYac@O/N>Ga+ms.Z(g&1I%5j+ob=^\9?8fiVu3'VnoK-"cgTrBQfjiqh46AObiAGtEnuCt0!sS=,,:>;@Zn)tQHX>M#R.^F.q,s'*gq[rc=T!]jSdSj`V0DVCZ-+ak6(RL-ed;!g'in2:X8n/,D@#m/.++CB,jMKE--+C:felKb70#(R#&W8e[)ZB"8Hu*hG#f?%N5Z,bbWpT-X3L"-P-E&`gV:@l=Q9;"fduR)Q?6a%D]>d"ZitG#Y^r6*'k]jNYeSm<9Y8)NJVa#^tfNCUXG?C%!&GXN"$r-qIlCb%k/@X=A,Q"YW/h?jEs%Ba!#r/iE59bMW)m%&p80$*j_Fe&\)4J^&'uKtnqGNF(J\-pS>)lEO,m_FE(19I<$o!<_lX(kNS1Z.``-_]B"i0c=-;?>ZD6!)6;kNeAot1HA1F22\u16O0=!Dn/a'';8EIF!E%F\-MV4CQ>n0[ps!7fSC^`TKiO&:j_o,I\I7k[o7*YLS/pN3gdm9hr5a9^eFIX+Vd.9TjJRoQT2om4VdfSNQ"o4hjMQ'hdBc\OQ2KArZZdAQ^jEG!DDjjqhYRH1[T.--Aq=W@#U#'p?GQmRDi>#Y1Sdd=X?EX-b^O%$7I/Q'%hcIRHqY*Ndo3oB%.!WJ,@/9<(YNJ5GlepG;=TL/1.>PE^W5^&%K^3E$85jl;V:Q7M)#`_ea(eq=a4%E[\Msi7#IaIMi+H,P,X83:GoT0[<`4]d<5p&E)X@U,@Qn]Qb*J]k*90&4mQVN:DTPC4j8`hkP,kZ4$`dBcTgd#WJ#<&R:;]p\MUi%29Q@*0Hk73-_rM!1#[8fKSlh0fL`ZU_(;ea?U/Td6PX%W<+G^=PS$7C#t+Uj@4-X<'L?u$>lF6OLBum?"J[.\'h-`GD8WCpjhYSr_*=N_DBh9V#VR9+!PC`=JFEY1dl[k#3"B5I;-ib.gV8IY<,/oV3$LaeH>J7Q,'<,42itLN_&`$7W7'^/7%Uh*Zje;1'tZecM)@G$4[gKlYXX'7Jr/Z27#W`*CfE&MpB:0i57<23FZQWh_N)E0ic,#A2AWo$Q3S$dtTXq;00/brF(YS2LG:+bjTkP=qraj0p3OCrCj(f[="n]CL3+d+a7ZH@%p,_o]eSB^<0$JnVjTfDZAbNN(/H)nOVZ?kq%4UT&g46,t6o*B?%%F-R\JVV?K-7V5Ol;0)qU]&pK+C5!r4Z^@55RUZ18XGX1)?qdinQgH6\7E'?$=U.>QXC`Ka+8]b%iFN@.=33]j1X,+_XM07*-)Uh5?X,pGKW@KA93GO1R5kZ5'uDK4[\8ejTn'OV'=VSX:a"JrY-=UuZeZ0YlHb:+A1M9]SuoeS8?F<^pAbHJH(La.JQrT&o63PVJFc):Z:3gA9Gdmjgn6]+BH0r)kn-H_B.+cGfe`Ge$/AU>7[!$H'Gi30+mW[PXuL7`5#Wg;=Z@*GT\C0ITraGJ@Ik*s_Xh*>^USGR&m_)hDufI".Gn4m=CoK)8b@Y7p?>bC6c5-c+P7K%Q&Bag`c;BJM"B6jioG@]Qe57.>QbRhQk>!:L5@(P2'_f(ilI?J^S/Es&(,or,2s]Z.>OJ&\4=Z='g0*Dj2Q*M)sGc2FiMUPB`+LOjn616nqI\@9qofTo`:/#-C'fWR3Moqo.i[5a(MnP#frXrcpG2se&BbE?L7mk6]5i4S,n!Zt(AD=1b\rQV+RJT\Ki4g8jpJU;&lK1Ep=m(P7qlCE_9c3TYG?52&;JTpM?OA7Uq"!Q;a%Hg!NJ\^t2,$0MhKHk]k9IBY:`O^gO/!\p/02pT6Ii7QcsoA/A]\;H#Q=@Sa>7a\\@h+-lCK_2HFpum#Gr]e'P%n>Gm$gntsgIDKE[oM5RZU`?#9e:-7hG5$JK/n"B]+C;aEqBHnHX-@#Y'kE-cQ_tPu1bH;<7n(>HUfg:TjH$20&-DKB&*#[JPD/p^VqlGL>?Q?XDpc#4=PP%%#dD0EK'e'iW#o-b*r$9j1_=4J*g`han'7Jb1]ro]_MKujU[t,?JDaS*8ma6HhRF6X4J0N5JB.-F*Vc>V(Gqh3WIXqT727dl;-S]hJNY`icJsBrbS%\l45iRei]"=)7-o-MmRV6mmrueYl)IjA\nlVrjo6/?5in6=^GW3?IqpFK]U1C-Sjjb/QoM.CRN/%d8+a\1o%0U7SifK!MnR9[+\>cK(j2si6`S[e&/SC2hBDH`(U]GrhB^gNEoGhOi.6_s8(C,%7aGY$j-B$HG(8/Eu/%g^cOHWY11H/ire+o=\U6J`^[3o[b_!Q,.3Y(Jo>;h?9tt^`jKM/M1`86cu'l;pPs=:C9)b`8m/;t=L9-O[P3CcUSU+E0#F@m=:QLI?!:uAdL$_b1+6d'I3:[b4]%(YeV^^ZR12O!N]oD\u2T%%=M9m@-tgjaHeo'?Jd.X&gI$!2SAn70I+N)e6;W%*btR7nk/q]&oU;-WC0)RJUO+s_HX?G`p9dWqN8SmR@Dg82,0Zi[p*rO.f!.4k0b0W;eX7b6,mBVN$^BF(]Uc,6A3Y%4H-[)I(&G/GIjcZo\)!fkdIK;,h!h\LO\%b^0i7+Nd9$NmcS!%jMXr]?.G"SO.IO+Q@M,ql(q\29Tj0].##a:!B2'FrZ2r#Zj[Q?NNaj"9Fi$4/$KbIn.hYa9BR$g+u-CWQ3e38"hp<[bm_[:5]>&G82;`'"J4`1;Rj9B<_JF1X5ekGF-2ZT2M4OtQ5me5LOo8mjc)T46`d1j5f$OANrc!+[Y-WGiV8UiZrLqa1r'82g<2J&?BeQ'4q)oo%Ic0;Q:o?W'?1QZ=Deu`;KfF3ePZCLkBOXL`oe$TK[D8DoF=t1VVZIVdIS>nkk_GGU*hFq#IXA+?N&<.a2!pmjUIU;4$80HmeI8e0T18n90@ojb8Cs2V^"pV*!bU;)X3H:i7pRO`78H$EKC7^Xc1XcJ0INUJ.U_Oo&RtScXiC"?idu'.5ISdb@5uh44n[m=;U9J^4IYU^c+/'ZO2o6>3r3Kdiuht]cmVjK4h:==9Wf>,nkX9-CdAY`D\dZBU'qS`#tFea73+kRukSY"?*+78Q!?)4=,@&Pf6mXJ1ohY1MoBUJ.,>!-_'hV$DUIo:5H$jJl4>m3]HT/o'3nd^seJ(b>^Zu$CkR]"f%f/pW,-S8X]s32B>sQ@mFB@rkQR6rmH>om%I7b%-;\h!=R0ujG8+2?*N@N-2-S#,_38.]ErR9:K6i6t--+b1^sc/8frAR=4QnUrnVD?p(M"m%Agb6S0ObjM**,f9Wl%/-ir+9eXk:NoX%@Z=:t?d9.,IIfWt%F#6F>*#Bo9K:>,=d@:mD/A7K?YX8;mEtE`(;MF1Fk(-rQimnThCKigBo5It:1SI/!m+qchDq\al&CD.Q.LhQ/58\Y0E(JuqdBhhjB?.k=TWA2i6]8;;r./h8usq#]P,`"BRVpQ@J:ij+gu]B,4"Tb;U!As*Ej4e*c:(HM3LaLKa8QB:R<.QI[mIo$U$O4oB#)ND7XD%3&0mPJ6;V*f?#DAWo_0`\W+NEk*LhuOpP7)2-][jb&)iAH3Rd:UrKKAbsdJ/>'o3[/OE,3Y;46+ID3d^9+<\M*:'6@PVc'QO=LW++I)UX'kA8dn?`mPnZ_qGRU"B[k6AT,8]dJS]5BmDhT0a9:u-\YQfE,.VMjgt"=2["8`V3P2[k;XU?&CX5Q[R7HjQXn>EPX>Sh6=_.WGe'e:rr!91\Bt`A30EZkkA3&.ml(Ao%bu(:e*f#Y/T-1'h+rNm;p!#A'`&nRUnU,*&"7T"?fW\e,X3Sm)%f;[@)HanR]d`Rd1&0h&sV=EmTGbss+6\d*=\io0e#rRXtM%eeN_dknOl]B/GInp\cDZ2Dr0Q4X&]^]/blfFl3[o)@@ZPF&_+p\.\BW_^FbPSr:q6^\r23VGCqP6kn8q`?Ot?;YfF!)M=!*k"8lAAuCnK1Rk&Z=I-0L/\kE9!]pO87tXdFLt\G-(+3=La)_^shisa[O]'PP&=8(&[N[>3Q$kYAC(-FZ\%Q;]h,/a73@V7E,nlNa'6;E5;TQ/`((%:i?u4^-gl\M(Cfh\uFB%.f8i=h,S&VBR11i.u#9Tq/bc566nP!+>Li%2Qh*Ye\:CK,/nTE.pB;=E[\8HPtfnZHlCP25`?VT97a"ndTF3S>Dh6n%/@L0VAfrr9.klbeM+In%DnK$3X"Y:KmOiK#8fYNOn!Z(cuqT?%$Q<9VN:qCPU3@!,o"_uG7$77OeBKWY$'\FgdCZ#Mf&9`An)pLg(]k;(q%Jc7bAI2\l>h)=JVT"7fYiA[1PVl=fp1(Yi5J9$CY5W19,?AYG5N+%IPXj"m\%Yq75sJ4s!W?UY;%H24[H5M?iraE[Iiq6+&EE;uHfM5m<L?9j4<@Z:o^Rcfs$p4iI*XeA7j!''DR=Tr0XgdW2V-1:eNd"Ff4Z7Es?b6qDRK0$5TqnMA!8B;6o0\U8eFYr3FJU:qkgd(@AD2LoGdj`qkSp8t$&knU"uCmDe:6lY^Oqeu(H-]u\o>DA;DRrP%ru!0am0SCa1m2?HEXRd2>Yo?R9CS#\u,-:n'GZqa%36cPQs%7#""5igV$f$NS=P6RHn9SIl?.>V5'mE0P@0gAA>RINhG?d>;q=rkGqrm^:/4WN(LRq19enKk,fiu$5cb.rk,g'%SJrA8-GZHHgs$uA^q32fQr0/0?6sKdfFJJ%i@<54==>,mR\"6"C;s`n$m#45`'M8fS1K&oXJpngrs`^s-^hd`V/Z<`C-4c58GU0s3r>&!JNB_hBS[Mb-gqiZ6BIJn#5.4abc$((I";EI/]Mk5"iX!1nA,AUJ?B\q3^r9bNq)\*r"%o=38jD;4WUTmD+^K.JC,l%'83]BOcL>eN4HMSr4%C8jBmGn#]>lkq:/e[?(_a73];h(f^^_(41[l5,.#&cOlY=?Din#NItY.HQM@qbaM%$Q40/A/t@7WV[u%bEfA#'072PV_1gULXsf^6PU-WbYg4Q@^m677[-hfjGHh3XLT"t\1+19k:'X/)s%0NQP>Xq#/_LW)WYS^(S?SNa@.Tp8:ht%&uO5NkJFgpj!lKt[P3'P*,E)GFQ"KDgJCf+THr[MO\!t5[K\i+PeedGZGC`u(LY(f"6\01/_i]CUXef0or^^m849j$BaajZoVZ@!A,D\QU.]N&9[m2%A]kX[KK(Qh/:0#]Fk^"AR)M@:n%2"&maf\gQeKM,c'(&1`s,^dK[/q^RInsc#Td-goLrDSucr@N=88)H[$&N?N;S1js'tfO(G`:mI9_&CW2Z$Ln#BZ#nrf.8^.#s1rqhdPub>KR7b&;RY@PSV`Q(JnU@VCe`pKSO%SfW=/D"bm?*DXlN6[#d04N+t>FkC=RRBgmjfg/[J1/Z\*R,Th(F5/n&R2)>tN-:$d/&@7ekHH$^dY."!F=9O&f0[o`>'0=Un[C3KLWA^b-G#I1\[@8>.RmF(:QqTGQeEp79UW0a#U\Cu%Y914O/ZJ@'m^eKX@pt)EbaI4\CM)0LGb#JUD^6s$6f)jsM9[4s_q4'o?ps>074=c:/?g%&U$ou.PLo%-GMHSYPn-hlc+;JZk@mp!rQri`@&,<]6hnO7[Di=PlM^S;o-PU`AgrkQ;RLI%9b%I)OA<2N??s2W"cF`Mt+#nfTok:/l7jU\M28!K0,[?F/bbl(H^%tdsonLnZQV@u82YdK`pQhJ5!@XPJPX1n/EG<]Q7aOE(XHQ+l?T^(G1u<_Snl.N_Grf6^;UK?9C4$?kV8>=IB/^hP&2Z#ANP#-1*8g.<,,DJA1'endstream endobj % 'R28': class PDFStream 28 0 obj % page stream << /Filter [ /ASCII85Decode /FlateDecode ] /Length 9669 >> stream Gb".aBm8<$P2Glfr.iSAmT<%o(cOusP?D7LQ.V*AbFW6644tt-,$Mq$i"/WMn_:OQ)rRE?.Tg)%Z9*Ml/;OG/lgCe31"#If%Rii^bdCH2eH\OZRj!%CcaoJ1=^ln$k1J]$uRj`AU@X**1\1bI/7t2:W,g5u\P@M&orSqZ*`lIF7*nTcL'6\Pu^foQ%D:;hKdQMVRZ#ZGs,F414Re2,Sm[.Ss\1EmLH_'5!Hk+5hgV-%k#.Oe0Og7VWdVp`E2l,)60?&(MZf*HG.6#n[4=TH`4hqF:)@C.IJdqhhoVJ42S--SQL?8)uAt).QadH])QEsAr[GIAiNotYcogbulR1qVc*aL]3+>QdVA+lG5o,Qsc=]pSNj&j7Q<._,(RT1D[*K19HL2q]IjLeB#I`#l5P$LMKJpFeDTh??ik/jK-)2o_Zqlgn)E70Hbi&]j]\CcbU>hHQo+Yg&,nD!+-7cS;hM]I,pUusa#B-/NL]WpY9-$,l3@cA>*ieRjuFdQ)`gqb%FsAS\6DKS_4H5."N<_;m8t0T!>4#V@hMk7em1^[N7c,"uIqbids.P=r=b.)#BbX17Rmd:N;^0Ke7\n4Cd3Qo"hli4$_k\U'oSUM]s2@rc]Ij2D%33UO'C6kQdB]/'gh-)IIt4Vq"k=Lg4H.1uR-GoQ*cOVb?11n0MTDV>m("RtHf%iKq]+>$uQj_/TCV:Rja<1"+!UTh!6!_W",q,fGunp8).fY\mJ4hZl0P7$jl-T[?f:"i!j(U>$uoN`3Th`;Oi\!l3I8N,\_C%Q7-+.2HJJ3IY3j7G_=2NSE:#LZ^7R\A#8LdZ\@E6d%BX+t[/n\^2QO:>ma,H?Dio($3Ej]^!ecj?sQg-StU&ZZBA.-Bl/Oo3Ft(]o;8cI)g1S6_!\rYZ3f?tXU:=3:GOT!FVdM5a0Z+k%#*G&hcN$XSo-F8Ms$Y+_;MiD+3[In'7Hc;K,)`WsB!n#@j5H.FM4G&_*q%8_nX0ZWVm&Vahr#nO3)4pH$_@c;EJ7nfnPdL3m_F_(^NK0K^9o;EuMZ"Bf%A@d,RITr$Zf#/.Da'T*-XKo0SA(;oNXbPg+@_g;*_qQ[0;Y3d5=_D!`tllj:I3IXH6GlbXkMJ7-X7H6P\batAQoDUP!5Fr]*CGKTk\\6WmV3;R]^nJpEr7U=Y6`m\M*2p`uaZqUV8JLANPm0P-gM<5iPfQW*1?.E;gYl1AY\,_L%UjllH#kp#D[.40N<<2)l"Au\ZK/W[q89PfTce$^J2DG==a)b;aKM_>Id%Sa99@+5_Q%IQ`q@4[LNG.qeG)*Dc_2f\2a,.t)Hjb$0CSMu\:ceZ?[qq^4X'IeJnI32$0_V!l\j'nU)Y#B):juV6NaD7ldO0DIIQ=qP:qtgPX[eeK6!LU(Y3+Fl$rORpaeE)j:5$fJ=E?dJ;UXK9&E*$8&%K?a2%$11E*r7FGS&fc-(a+SX:XZML4P"t((5>9kPSGMU"i[L5Qc68_p4K1^tNnI'.[e[nc7'5%D670lHGk?jAB/alaDb%/)[CBjML85JRZ)L:0Ag)`H^l9TZNVJi>HBZ-`>YB5=3I4X@WIdNop&!4iVe9pChu]_`"/COaT"b4'o^2JMO8nq9Da43tl!$>7I2`ZL)1?uaIeXM*>mpimq^MO!:Oq;/:Z^JgdO@rQ:R=;/Un&T%+CTOG7?qj,$[hGb9u*>65XTKa"Gh^2JYBpuG"%QF,X@LN65:.FZJN7^2RT/+mn]]D=mHF]15j8"R\XI8,?)Ed.>/Jd`5*i6;dAR/'P#Gpr/%CUZfO>mrQ^Z5O"A*r,Z`^uq$dT78fhq:5.'!<;T`QJd6&I/^mZkJ*!T;377Ehre#O5l?U9jXeqic8H^eYiWOLH^Um![;;KjS&>kg4q025&e,@%i-4k,FH%bG98&D4kfU+?qbSeHdcY&mi*7Op1i'*bn$2u2rV5M^AU7_Oa=DUEgt?=J\N^jKU4!B!Ns+"_SE=A4ZZBe@'IJEKtXc%!tIW-f^KB_7J6(CFW3lpgjlf:$&m]8K2`AcK2&hkUqoa4_g2:KhXbU%[lqSgXh3r$]C'Jij:Gd9H#33UpZ*5LG96@H-,5dUU"VeKY6)kGW-4U9m2Oq@Fb:dlguh.N*_1F?;,(iMju^5a[Q\bScQ$bCUTV(qgfSE[)N(]e+^(P$`ALnOO+*&-AGp'g.YEbVPj_ndZodDM*_r#ELYnQ`=;1IcTPYe.OO%6?7AqR,#ApTBc/KMk5lMT+9Qf^kV>d,*aK-M->CiGs2007=s%ZH6)em5iK]Fq4/K)U]^\PsqHT#nNR>:seH\eLSjRu8=e;d_RmK90($2u37m+:\X=-XplED_DsU2,M#Zo\@)kLL@ED3A.fU5M)Vt-$[Spq#M>'EJDVm'!1Ssi3@t"9(;RAq/38OrAHK$YaF&3^S(_84J0Nek[M\Z31u-THs0U!2.?s8Q=;^aoc0GJf%GF6pWm!^\:@gc!gf%)r$e(@ucdX2ggaT3OU5`T7,Wsr>ns`u]dBQ&T!1',]L(d\66S\\L?6k=6%-S_HNM(Zn.0_Y##8+q`'AZN:3@$daVCj'a>OQ&#iFL9CT@%[iA0_ZukcR90/A'$,54Fg9"\!O0^/'eI+-TU-dL?3jSfK`Ll[DDT;aO^raJi1XNpH)@!\*^Zb\c1.l>5@@:Q,%n)\kql1$GAT#pp,,t5*<&dR*_TS8Z)2*5R^&hagIrF6CfT"pW[b)gFdh=!McJuch5Wd_prs8FY)1g;cZ4+r9,5_@\$n/LW](Mn+:.3\*'8BeR"jl%m;"5r(4h3L>X/W9KAb`:MJ*!m*jn"Qk[Q2fSH;!1;u)P0BjrK]F#I@hbW%3:n.R5.nbmn,3TS?iSX_[t=PIL4hY[m5OiqKGuR7fl`+RDbNjZ+^UZ.iN4PQ_<;AI:&3-q\.aXG6i7$D%]8!:s+X_V%co`Gao@'T_/F#ch%W?QAc<1Ym%O:O>Ne*Fp:Gr6*<+<_j/tX2o]bShOe-t^G!db"1E57lQN>?4kFj3q-WU$G%:-t/LL'.fV>nD+G=Ml7c4I1%gO6rP[Cqf%BRnL&4o7.@K[93f-01t'/H+`PIe,cd)6!#.[*%qMj\O4nI&aN1BCdoq[B<6U!li95J;`2dCj6:O7e9/jfY["ni#$e7("]01ApAp"X/8OZK?U18$ql#kA%O,$n-\bW]YIp^"j(X?^o:Qu(&Y"mS5c+RNVigf?M%\]Vq!!#$XanIG2uPoq!m"+1G7XlRZC.=&)TfWO(e3@f%p]hhAe7?u%_N=ph&GZZ-+MLi'".0<>.!DXe1^P)--QSO3*(58]OF(lW:4r)M\5$#_9OUd&$\gr#[RWtP5C7UW5!dI';%B^/HK-oRM&jfVa1'15VL'9Rupb;1]kRK4\0HUHUb:?E08D@gH_oE4h?]+uELL$l/,Z#mJ?4(p!*O!.:\B-bW1?C]f.)AY\*eSf5A\kNb7UM_8?i7qF)74=UE^R/:$#$uX($E*<.NL?(,ZUD1U?$QrSll&>"i^/bQJ3Q@Lq,_qOL0TFYQhl#+fQ9B`Z=F64jHnN!+BN'[m*>0b(INO9U%AY#PNe"aa*Z&ML_-)ggRscaMTJM`[7$]Inb44PT[.2',.8Eij##%UQ%a1PW*@NcOc8FVKCL'L7NY!\("m9[dAbS]">;IB/BZ;WK5#O?I`/oV(!hIZQ,:HSU9G2ofM$']sGhj"a#RMQQC@iP6;_cW6`lf+dQgQ9`;t4.i#6sb9=R-32'%mJaGARf-D)mV6eqP#MfM_Iq+0(-Nj<8q*q'fg++9]A,W+`34D3$]*aqKTSip,!&G$;pT,jGh=)n,sQGn.)Yb,[RnMe"&RR.E?re@1CPolWNa@PkUu0jN_U0K7VAn6]HD:!%N&4Jc)(1E9*!"\Na/=UR4qW#j/.SE\rd\Dl.sDEC0.m\TTehdpC3QS5b93.'TW(jI/^JB!*Q1Wk>]a"&&V8lSPslNgS!AMrc-#-h<7hc$f"r^]EnO8m6$X8UUh,0Y36mFiC4K&P,'EAmIg$mJoT0QDVM$uN5ogObt4DF?p7S!g'](uU<'6[$<_mWkn/QD3@V$-"3%e)2<"`PW4#%g"r#eKX\?E&]!e+&G!do33L1WR:Vk&eFK>ad'[(n_hJfPBQ+mDo5CDP_2PW*PGP7RhAo:pQ(?^GN3Ds=*Y?!0WtUVtR=jbLqCBdB*oO\V_pb3IS3Buu9e'.8;0A[QC&j8O*bA8G6jVa*O9(sV,Fq[b$]lt0Gm7*WC4V[80e?[9cnk1/3Vs/jBg0Cs6Gur_^/\LG?cii4KRGg/em#TtedX?@j0?US?HZ3VOKl2fj#^rA&"T3,"/:DCk["J`6l.urm#cVq"7Q.$L`^UM2&:-L#_aa`iqQ@r,-A2a-kI"l`RHg`hQ>18ONhS>;5ZQ2'hB,U@QFV9>CaTUK$YhWb\%!^2,mlZ)"Y5=?k&m@7$dTN]!u*V4.-q:j#/(S&q$L27d;F&0N'6^M,G.J9"s"?ct'B$9uT@l&<2]Ml^eICU;CY(">-\!Tp6(!>5?]RY,mO7+N$acUdX7^l@M`gHs%Y-B:Xa9nJIdiDD:r.FfN[9ib;t[:S<@U[-a^P9nP&gg,aFiI>DRPAer,fN#hML2(4nb-Ra03)7A>ZNdH+-=@nJOgoE\esa[L1phJ\>^==Sn;D/7m`Ok2%gIMXqn8tO)8=1ZefCbRk#aOE4)B7(i.-q/sQ:f3%5^C2VUAYc[6Yr$2Vdb?OkUY"T_+]hne(SN:h,@P+C_U>.0S*:nJ`c$ORg(Rk_)nK?dRMgiDs$97)+UWs2kP!)[n#?cb$(tf.8*PK6WIu7]#XoiBd0cp;e!bDc@)r4Sca9D7UIpajog7[Q#)-ZIt4MK;jd*T/p*eW!MjnPA0!/-2>=8*+uhP.]C=$FTL6W:ZO<.]3$YcdI9TQrHDa7;&K=BL1jJp;Ntangb_%UWXH?IN0Ek]'jX,UM>S]7N%!C?(uo3/%pZecjEAU4Z1.?&>YVkn2Vi\?f/#L_=XX7_kEFgQfAf,+:hd8q;hGMW_RTY(q$:W>1"QH17u,mQSQ3f"1h]dZH>Rf.cYAjYFVt5Z9VK7P`[3(>:Z<4)6As/l:kbHGpE`^/8mc`<(]tLc,HCj>*dilGfbA;97?:j0@E6F?2$dA]:noN,+gE?90dW+>HgJ7Ki`endstream endobj % 'R29': class PDFStream 29 0 obj % page stream << /Filter [ /ASCII85Decode /FlateDecode ] /Length 9712 >> stream Gb"/,H$A#aOoIZ7jZE*FG@NY,0a'`SUm"LsbORAO7Up/Pa[Fh<-J9[!"OV;nTM4bCg%SS(!(GW2'Q%SsZS1od8N_OglFO%.Wt:.Hre9e7BH\F%LbBj(,)jIZ7"h,(,;,RGdu.T4ipACKnW!Dd<]Se=GSX>\k*S^Ug7j3cVC0Yd;O#-culq/FiDaA-ES7&b2t91<_J^;FZ's]_gceV(JB-a17=#r<>/qD2H%CoTo/N[Uh6Vspo9]1A(Q9VRc1*g7BWqJ/o6@N?2@;KQ7:\glE7XA,ED1,mOqu_2I_nf^2M"NRsI=7]FEfH9Zt\_;<+dFEOWtRT/?^X0M$]>JGkapfsh5EA:RrT8V`(6Q#IOFr+9.G\q;-n`a+a\USTic<%VXS8#"4aY9u,sWEb9!Xp6g^Nu?Y'(lVuo3,s69oZMs"]Xp>eV5]iS1/jgOo=d>UVD?I(4t%OpEFj7nGnV)O$W4:j>\BM&SB>YOb,NO'Ns_b8GQEc!eQGO-On6,r]Go?[^R!=WG;dgSP6=ILHktpk]E$J[@4(!XPO[8!qWKobbt-$_a[KeKN*+;76&Hg,=F%#I/MhBYCf*r#]!'ZrV]Z_2Sr++4;RjurYJr,cR5,e@Tb;[1]=buu#C6bc"6+;RLtVrd2cR=VPbOYMN88Ga+\/kZZsh`VaXjX1e(H"sUI$N.cJDJ+i,#6bo]FjdV:@'Q\LnF0eSlIp'6u/F19JU/E\go:Y]43Tth(^KG7a"-S*>s_Gm!00q!DdK!L](l!LGH_&EQWN'!We4_o1)olKCRHd8raYkK5PR*9^3'Vb;M*<7UeK6[AHG=*rW!:&Li5(411R_chSe?iHdu[OQXe)=ACk7*1;%<<6SK?3BAR2jCj/fn6-SEZc"Vr$[NaD\jta%+"kS&B#h[E>Anl9Lk%IsUZZ4?7h4l4crY<,)QFbpH$V2l.S?U#P2a'9C@!pXof:r#sM%rZE&2"0\6,g0PYO>`9+p&s4WUa^MP1H^KC8#gpR^(3G%<*:@ST/-T&1(d,Z^89i>J$?X98:.Q0V>76iOB6'rl51YJ[`_L7SDVg%c64nM&[;'FH>f3bl-or\PK$o0rY88HU\)VE\ek8H\L@*Dl?J'9d&:TD>Y)')nk>M?go'1lGQ`-?7pIGuh@Ru#B!^ZCBHX0P8TokX;^fRb9@*TTUo#-C"?goj>jLC1ii.'F[GPaPd)s+HN3UZon&!+P)C_%-1Uq@5]@K]b\-LW(2k/kD!f5$$\lg,YOc>0r2Pr30)i4hO[2+PS3hj/;A?n2eL'f$oM,`cK)NtBQUFLf;J4%,mS65oU]F_[3uP:[?rcOhE'j\B!82[W\D@XNWV*KIQuS2__!&Dn]j7I5/B'K0QK]r2rnqRtO<788Z;$W&;4L;1n??b#X@P1/rpO@HS+*(gV_(R1qu$ogCJC&YP?BmR`f9m9b$&EYTVEK,>T=e(S;M6<-HmnH\O8]OLKHOt7$?>mQGI1#^5&qr*,L.f6Z4efn<)JM$0qq)oaOb_[f5*OG&$1C2'FZ:(sT"(#e6/^LGUq.S=cce1MQg-$&4K2F]X"C;E"I2!^;Ic%[4A+4(A6);24j>7X6d.MSS<\.eBq9W!Alh$Y><\i#@`h:=i_9`@7Cb/hC%b(@SK@+EI;s]RFaL1,n[6%*iaTlYP;b,,``0MTo'n*dB>b%'N4,-)7sc)?\IhK@U)7R6PoNIuFrGaI^DeH36.bp?]8%ipk,qn+be.>naX,,'-2@-UG2].Q*$i,t]oQUX-_?fK5p9l&k*"m:7h:`M'giPX`Z?$pN_r6O1@QrmIV.T9f7lZpjmuF-^p"E0.T[UOPt?]INMXe!es$h!;8'(35/q1@AU6,"L)76Z6,M!h>ojN%?70;!h%LTg*;&pR"';49R*)nj)`4e@l=4-L%\I@&DB8#6C>)i,3CoI!!qd&3/gGE,H1_\iXs9JdI"J)i.ZNVCtNX'#L/Fi6j5`dFhsr7hO\G43P8plg+m5*XZP%JfBF'JK;D#n;4L2FQ_[,Fp7WHWT/+%&o\eU_24VIbbKNM^a8X#*f04hS[=fLNT@V(r?J5NK09Ln,2jo]&3"m0?53%+mLMB(hEEoBFiXVcQ8kr\mO(i;7?Z6@N93,X/L#PXuV**FC*Pj)0$>ubcSao0u`Rkt9]39$P0lO;om.%R82D3QRN%**ZEL4Ln*\!FNrdR_Z%_fg=ghl/^E\"'a2GiD\a>ZG\Qa2b/H20CfN,EoHdhWO/^foH$0b:=-DcRI4)K\[$1a0).T/]aS['a%I05d)2aF1KZ="^]WN94]nO"hlK]$Lc)RPl?\9igU?l2[nDG\q#frE_69!R1Z;pXiGP'V@ZuE"*_E9?b)kD`LTc8]TIPC??Vm]YZjgc?/P_)5WgL%4g!bJ).<.Rp:mc@oqO`j8?b)GfP$7O_IL'J\^fPb2E)ul.C^[n)cD(G3BUm`goBBIemU!`[g@;JMP\TXLjK\6B1BOWkJ1#1`(XMW1"YZ@1L6rrRTp9_)^EkER4RqrYFr.7\^FA4*NnkNK:p\3]+FFE_@%B6<4!s]Kg*D*Y];/VY]qVRQHJKt&L0<))/DsN<=s:ZHnCY>b/QNV0S5Ug@s1k5.p_Sa%MVUWHdN$JU#;/7dk?5E[nToj%gX53Ye1$im]5"\HYKC?l[j)N:/G#\K\ci3\oh#B?C3'F.ipq8t0W6"5-Bbq>!>dD/)iZk5!,">f3<*&8!$6/Z@.$8@b`6Ef0'n>++HF(Ji8ofI.DOSo-_#NXs$!?3%"KsS0_NhE"8llK%.O&-!KtphosfgDK+W79jF`(=i3r0J4?[Y:h`kX@q!-O`,Q**1i;%rn:Uns,(OH\.h;=1,1$=n&X:=-sYI/eQXdmO-;EiA7r:4W8jIHa;Af,1<]K/8rrYOI@pR4T_s2qV/;?$K[n,LOjP&Sl]&&rV;6u+3p(k;EASf.n;j51BCepkd"BWV!>YicOA&7#L*a`PN<\i%!oFsfh,EUq!tnSdRS+u@CEM=oH^r%pDa_Oe?M4R,3,?;`-S,]^'<^iF$uNkfLB((41O?<@($.Z/@SMS(B%4iMVHOq-7,mK[clh^`7GSPBPrT,K2TNsfrUA]38tbf1*6m0qts*/)%HpmFg2q+SNoK&ZZQ[!_HHX/O6,?#Q0c4@107NBo7]?ALVl];q[!iNM=dVC&4Ine^kfFt'L0QZb4W.)+SR@9=;Zq`p%,LiSX#ZDolbH%)mZ!4#TTD9AB'DjWjU%!n:n?V30/(&[npi>aka.rO6$UMr@HAhnS\giU[3GZFFFf^9RI'N]4A8Nbj>;2Q"q^;`W5`:^9l!m0A;e9-ipfs(M:QuP!'C,@H>WIW,Dms\,laRQ4)4r,@UO/A/LPI,scVs!)3WY24es&uQ]=m2-N`7t%6BHb\'dBC?[]X1>4l-dG)Z-GkB!;op-2N)kga,5pFf4iGLmD,TU5,\'et_bmH;88UsFc9KY78eA"Gd1YFhAm\XCA%RM(W!7jCLV9O$hTHp]#JO=Pf7X[5BS)UK-`.%mQo&ud9AS!d%bPTiOh3PR>C$=PCcBW=7ZE2QVBel5c0PEtjQ>;1O;issH4liSOTbLY?TK4)Lfg0B[D$I?.64kFs*Z03@>f-b:imZmjc&BPpjIs)W_?P4^WLCt',W2(]H:jr3.$'VYioH298n9u&(Pthtl7tWU'+hKq??_^GAMLdj&l[$t5?@"l;7t,oJ7.O3#51n1MY-BtP\64VJ3$Sm!Oh9-!+&0]J3plU"?NeC?hIKiu^>)(@Vpk=,gr`BhpHHl9pZ"b>3d1pGuM,1]H(E?K?]n/$"_#13f6]#^R_[S=4'EGV'19Jlf-\,uY438;DM,NML_7;$eE!@EOD-)[6fg/B<)?h$&<]*3YA)&*!Geu`hXtG606@B*;JF.\h1gE;]ahmZ^_/8A:?i'jN\r]MnHNgoR\3n&+iiVHaqnj!3q/Wm]=jni>IJ9N&N]MUmrELt4WEOh(A&\2C@tt6f/V)rco1j6E^`PnZXS<,<$'+V>2%/qJg/OS..'?LQnabl]49<0[$V21hiIP7](2g15pdn+.a*9mr:dmu?;'<\%.gL2?,7(m]Vq\T!'mCks#XAN+RqO8QtVIB2*/k\'p@Q!"O]RfkR0CWl,DPTm6npN.[7C\\&-QM'4K^>>XftI9a3p#t9$NmboLBLt*3I;9Q8Fdh?"OWNU-t?T8=;mDPoi=0>\0-,s-t'XjehMkr9e4bQOK@qc`n/u5%b.?WWef.Xn5iG7t`!7e3]A.Smq/O?(.Mq;SoDqY9rB+eAfkI>',FYN:'?X6p"s6X:td(lo05A8*&_5Ot.2@@S'g0LcANMpZ>EI;'-H_2*$^#!WK=W+\1kI8j#i=9!YC3,+t*c>pJ4P2d2e"UQ?8V>i@@Dn_/W*RC`f.PJ:abPP0#!E)4O\_!O3QMFY'WB8^LIHlmlmr1L5=/b29\AP#6fhANXq1Vlj/gUG9Bt(&b4lfVXW%.(eF+M.CAS-<_4PI2T$0-JF/qG=W!`3M'o80+'A9=R5,/6]HGNYR95ofU3/bQeBWn,+XKt3P3s/1'kY:ZI4,7F#X']5?>B1f[ID6lLuC,_Pj^g;$QKnbOl'E]$K]S*2/5tdZr(m+k4:[N%T4MdI!!CWNu(*C+Y-+kgD+BL3)P"s=N,TEj0db_9ckfi;V=M%mtd]U9G7!uD-iDo2;e7I@9NL7s\Ep9#j^Y:N1&%.)gjHujjGLk!0,,=%4[2\nfZ=3Uc2Bo'Ok;[r?XYu!EfCE*Oaka1ABiG,'l^2Us31?>"qSQ?9DK_j74ZLPSPW-a4druR!>I=l$RV?:^:m&UP6*j\t9fGN(;;=[?&:2m`$oapKTmiuBh@66&B$/AT3(.ID.T9H$2/"Qj(&-O+22/;W-(,C7?bNVS@DrXp%(-Dt^qI8]J]WWaSoum6Rp&3H#_I4VnG,'r1cs(1AG/LEBX1idn(8'SG3LF%$Ta-qLfKCO4^Y7*VsODG.d##gCFAOV"iKZ:[cZ42S_k4P23QV[h8j;FgAG:9rW?aV71l`E]2ZBL[\qu;1k$eh4W4kl4j*,<0$VQ2XCV?=uWJ^!p<`t-Dk[I#)Z"L][=X#8b_]*5Y-sFJ"=SNl5Gg>la[mbf2fA_(SL!9pTKj4kV!^=$p8'CiWAOP.Df[h#VlO[2:pJVIsnabA508T\N!S93%,=b'+J"/(?hsIN-[/gS\c"Pc.ZKrTob"q9g0g(UR1hfW8mro8'sJY.B:^*j$6l5AGH<84iSbA^KT@X(O)o8n.(c>uqa\DjA<^N-_PEh:4!`pP*j)@Fh04\E$U;,UcOHF_@Y*B1.HnU*^K&%]japa:rniM.TS[Sl^ZT+qPJA5mr+6\[4"kNd3ZRM]?sTfMh#$0kIL'3Qn3H=e;AB!c*p=Y?LanAWn`9*1c)@E&m3&o_\<$&<)il!#il-!/86,P`/n<:XA[lJhZ?akmP6L:Spn15^098`$:"C=5UQ_NF="/hBqh6`)kZ#[B4o;An=)sk`LW$2?F/?6i]QlCO]:--_UY+hg\jniJNt)j7n>gUP^Nc%j>^6IFnA[Ct&!]X.41C#/C(6$ZN`'4R&YG&Gbt4(h?;_lkD#lB0:ILlcrpJb,G`kN:r,hJX_bY:j`>Bm*oU&YWR.&(:H1[VuFo>%fb!dTTU@6\QNE\ePVDmXDk?/d(St39*;=o'_IUgT\9f\D9"cMOL.890spUKgQj9/AU!)G/ZcMd4E:f@rcQ8@q'@Yh3;3>pB<&^I.ofH3*)nGp/mPLTlh0,Lk&6l=gMMb\MdiGUJ#iF">8\/u4/pt*+Hi\k5$5"LDA'7NIc4>4j*GQPX*NSG"PT+C?kp.tIZsRt,5XRds(:)T3l/A.Y^P!5/*VkZ2g#W!M9#@Zg:&f6B1.*)%lZ/9S)jaE3mfNFX_.U*jh/bq#E/=J!4TKRDK3ke.;Xq=Y%%2A]H,u"D(WsW?LCT?*K!-,G%"(5HP:U4(=]gHNgG,Aeq68M`1?1t7s4S)k,5WT4H?g193gqM\`ZR`%@g#=C1id>fr?D8j"5eQ;C.cqWJ*k0'TV3Z@iJSOu0ic5J_=@fIJJ-:fP95E,[4TJ_S>WAa439=I*BST0g?TlPXj$^?og_,Z@8H!3+hT_$#X&\K'rHGMl%X.e5D,nYN0'`alq`dn-3Af_W"Xp0TL2]?8*q@=BQmg#/35S";/=g:;Q3)kD7XMJMH6N+DZ7FCC1K9-`gT':rROICI[MP3<`&q-l[ru,qM=r2`L[F^EoNp`tpTWA!LgE[W@N>%!jN2'OqBO]PFBDIo!6k#15_`-1QA21h9kORA/u6Z,MW&C2/RHWJ3/QmTD/n#l,s+oM!_d_2g:?4[D!W>1n_W[Ff6uK3i`ef*nM>XQUaitNiB[O"M3aDl,><*nW!GG[XKBKq2>7Ve#?%6~>endstream endobj % 'R30': class PDFStream 30 0 obj % page stream << /Filter [ /ASCII85Decode /FlateDecode ] /Length 5060 >> stream Gb"/)D0+GkP5[XFo,k2`Fg]MsL*PthhQ*.=>7s$&o-.ad1[Fi:OcYBT"LnGF=oS*g1dK2Y_C=nj^0PTP@S6jNk\bK,rA<`*p$j^/5Eg\i0%l<3@hoU-EmV?r]c@R]p3_M8l=L&Bd;-&@3JEd;0juVW/Ou(+bK@nT6IP;CM5:5I3Y?%K>-qdqJ(MmE(<^)t(5pT/c_1r@CqmP[j0-Tl%_#NO7@n]9Z%.7F!ORKX"_RfJPTc/,#]8pi==]@G*/KD3(5f`_"A!Ec/CL&)s*AG0F;DjoiL#Qb3m32=MO'Q5#qMYbheK(BP&GWcD'jVrQO8U9h`ZJI4!$[<,D$7M\_()g;Ss9E^q)T9Aq_p8:?S-!\:WpGdNk7NHB>bu\ma0cQLfGbF7bAu-rnQ+q.s<)!XiP3Lm*'M\9nYhA?0f2\kS?h3UM)i_HUFu]noooF$[-l=ZT[Y>B\gGedZ:^tB%>m;f?&#;GROKmejLQG;;>22<"rpBQ3c1Qm:QW7:9FF#*.=\&^THsu)j;`G]>?UClReL"U4Cnn.o6Qs!j4XKT1lR0qaY^d7:IM5#L'stYa^,8S9T/tI3Stpb?NKJMZg5ap?=qtWG91I*$)NMk0m+QG5s4MNEVd6ea4!^V,DDEuiE0n[VJk@MBW$/^mKc^d+UDaaGmlDReE+P^=Pf/&=;;B;U!Jg%h>OR7+A;=`C.C?)][XK2>QM+UV:]JTY*+[Ve(>]@jH7)g;0pTM#,=J_)3>;'#B.8(SM_mC0`mi,$P9a6XL(9fRd?6J3(R!OrsG:\E"Na[0iL[AePbrNXYbY*.Fk,#p)pBfZ$"'8]2_o84J7HGAod==@(B@:u/DVnM4fK27!8R3Reh!!7+hMn`laBKR,m]YE<'h\^pFDd8oJBobP#.mlJ<\Sr0l?W?b3ZFHR_I>]L%\^!)/!)nZ@+-M2NqP[dtci$`lADB%;#t2M!r%uUUgI:38>:mRW%RCeaZ1lN?.Pn'&S6oKmohlPe=eA^hKafMIRss=&m![\iHO`ac6s\K*Yh2\-8XH)N/9iDmROV_CuSa/G`_`ljQt**Zf4.A-Mm:pcM7ZkkPC3W_8RUAP4A[c+td`XmqD_8@q^+\6!'6I"70qF2A<*N[$<qbKDQ\r-<>_sP'4oDBo.U3L*^4@C?)OZ#pj3*;(i!3Gq#!2Z^:;8Pcpi(Q9tC-B_O?^_Nfe\OZm^i4Y7qjgn2+l,5f[KfJ+LM6ul+Hg2_Tq7A1^?23f>>TR3<[Uh.Op=$a%B8$16)=gjN0HB(bRS+JN*nFWTqdt595<6D[U@W$sr/k5c,mQHe2OT1:AiDAUk%pM:k#bHd7r!Md]0OdooF\grI]Z!V8"Q_N7QUF=k3RIM5.@d+?*'rZU?7U1sp"81"S^).ZS/ff%#lhLTIs1[J2&0Aj>E]BmG;779gS.Q[9:9Z0?)RQ1M!0GP#h1!C[AK\@="(!TC0U+g;A^!+`UaIgre7886/p)\hP,:'BD]PFkh)k2L`LX,^ArQ^]B*YZ&i'>^1lgamZ11m`&c5QV+TpubLn$HJ*T@E>S#p-HfIQD#W$>1p`>&C!_o!*_Olf?@[8MsHS5"XMte#4R5gkfJR`]gV=)8Z>mkRAX[[\(D-BhH@9%qj"$2*/,22VUpd%9KC#\"mR?o($tSh/P?AL'%gS03r'B2`'$$28-dsr$b[Y+ib1:\^9sBc.JE>lrC$k1]OrM>Z8Fbklu:!d:fWe]^fCL]^`!F"iB:@?Tot\(U:3W^,em4s=WH'rq^YJUPb;/!q%]lFc7S2Xhee6$iGikcn3-/pjhK86oBlp+5E/,%0?=X,@L$4XOESq[@S.o1Dd3U,@Go]2HmUNWOEB5A`?PpLiL_184J[I)PO!`7b4:BF0=2n/#U7aMG0hD/7hOQ+OE*LIE?F`bYI;[Mp3(hO=c,t1GEtLUf.kGuTf?E;j%mAHtmdRL%-PR8L4M_n6*ml`-bR/3KpnrIWaH#^nW#4eee=Y8-[M0Y^!h8kk6t_![]^c].;2`_P+]*(o!ks.Kldq&Lc[IPkpSR>GZPO-cdp9ClM15FV>!MH!#S"l*Cd>B7SSmY?FUb\X8H;cl"`]a3)PhR]uY4K*-F[4l-#t+S/*cp)%iJ3?i+_mgiM_4_KO="BNYr)P-"HP0*U7R?hMp&i_V'J1FSL2fLAQ%C$fYjc]LeMo`=MBK;p,Sgb"/S3&A[,#<=aekU/TmV!/kqpWn(:dos.]dHO.8DmSVjBFrL)Ak^585cM;T0E>+'iPnU.JD`s<;jFu40k#WUdT$PA2B66OT\[Eb?nd2,\?9RuSN!C'/tNONU:3$PMaM-PBJQ$86N4Xfrb9H`kHAhH:/3?,1;][p7-%c+;"SKG=:BW[(>Bo-![Aq\ae=SY&Hg93[%1+AmkSpCs<0g:[k,tV&PtSeFJ<`:IJ/M-06@he0P2O;-c/dt*h2qMG+)`5ujs:VNgS:\D'\nC9=m>h[@;>QI[bO(Dg5H?li-s.;2SNKqb-ibM9X$^/.#P5>Hj(jYd-7X`iHUf:BAnUnqnf^&V+QT(l@&a($4WUd's+5\*R1ATTOA%a5i4Eo,-"@GlOjaWL*^a;`N($,iMaRRqs4\$*(8.90;Q=K35d^$ki$uq/Tg#-?u7Up4;(hMW_?k$3Y^d8Ybo7_,6SZT2J__Nh7aTiDbo*4hrl#.,=mVI/i&D,l/endstream endobj % 'R31': class PDFOutlines 31 0 obj << /Count 0 /Type /Outlines >> endobj xref 0 32 0000000000 65535 f 0000000113 00000 n 0000000269 00000 n 0000000446 00000 n 0000000690 00000 n 0000000989 00000 n 0000001268 00000 n 0000001547 00000 n 0000001852 00000 n 0000003325 00000 n 0000018888 00000 n 0000019180 00000 n 0000022052 00000 n 0000023591 00000 n 0000042477 00000 n 0000042770 00000 n 0000045642 00000 n 0000047196 00000 n 0000072011 00000 n 0000072304 00000 n 0000074932 00000 n 0000076086 00000 n 0000096077 00000 n 0000096370 00000 n 0000098204 00000 n 0000098342 00000 n 0000098558 00000 n 0000098689 00000 n 0000108370 00000 n 0000118184 00000 n 0000128041 00000 n 0000133248 00000 n trailer << /ID % ReportLab generated PDF document -- digest (http://www.reportlab.com) [(\277\363\363\310\325\347\227'\325Y\371\006\012\235Y7) (\277\363\363\310\325\347\227'\325Y\371\006\012\235Y7)] /Info 25 0 R /Root 24 0 R /Size 32 >> startxref 133300 %%EOF pisa-3.0.32/tests/samples/unicode.css0000644000175000017500000000063211160170401015625 0ustar wmbwmb@font-face { font-family: CODE2000; src: url("font/CODE2000.TTF") } /* @font-face { font-family: arialuni; font-weight: bold; src: url("font/CODE2000.TTF") } @font-face { font-family: arialuni; font-style: italic; src: url("font/CODE2000.TTF") } @font-face { font-family: arialuni; font-weight: bold; font-style: italic; src: url("font/CODE2000.TTF") } */ html { font-family: CODE2000; } pisa-3.0.32/tests/samples/borders.html0000644000175000017500000001310311160170401016010 0ustar wmbwmb

Hello World: class=c1

Goodbye: class=c2

Goodbye: class=c2 padding: 16px;

Goodbye: class=c2 padding: 16px;

Goodbye: class=c2
Next line

Mixed colors: class=c3

Hello World: class=c1
Goodbye: class=c2 
Mixed colors: class=c3

This is line A with line-spacing: 100%, there should not be any space between the lines
This is line B

This is line A with line-spacing: 150%, there should be a gap
This is line B

Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.

Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.

Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea consectetur commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.

Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.

Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.

Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.

Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.

Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.

pisa-3.0.32/tests/samples/img/0000755000175000017500000000000011201057433014245 5ustar wmbwmbpisa-3.0.32/tests/samples/img/denker.png0000644000175000017500000000654211160170401016225 0ustar wmbwmbPNG  IHDRFcS0PLTE -&LB6w`Eq{ǰѽZ | IDATx^u]lWvg`%GrӧPe")E!I!))5`C5`Sl5H./u$K3㢀W9LacN@-M@lؼ|)З3" 3?{(>7Ek_>2d%T $<ᑫTTd컘MaYPC[Ua5i}y+XE]:0ؗ7Pѷc/ӡ{e5.aOR(CF0Sp({NO aҵS zykDh._h4:#XAt3nFwV^wIF}B(}ڙ槡fs)0 H"mҴ ! Ɲ+\u;l{^$ 0 uҙ!ī/$;YZ+ EG7N,@z]4Cdt9 U N"Al] q/ɴtF#H)Ľ3e6gC~P( <a]푼Bd v:QlfG'(>< G&EK"ޓ\Uυq_)3;^UZ[1xX$3_v9t?W^r4TdrđƐ!rs06ݰ6\yaW55A,8AjA-SLym-WU%FUk/T [dZ-@F{wC#e\ٲ:wuqO_箴m?[1$!Zc\I(ʹa}Ώ΍HRPw L\ž1" *ƀIkso|ڀ+PDB?lD3]?փ ÊH_?a~-g:G΋6af{ڽe^hjs*9]B2].˯sG 0AH-^fƧVUu]φ,]Q8s=0e͐HrySř1@6b$޵CvҰV 3DPG$Rߩbx :hC.Hj]eT!59 "I@ZSK{* p#{Ό$tJ<X{wI,q J. >2|d%I'p@j]qӚ?I໑wj sYM(\>K瑈ȵе왷8S\59雡/#jbh( 6.bV̓ɀdDr <Ƅ~Bh+Yܛ,S!7hi GpoLKPػeY;,!NvK["nZM;42$9̓lp` UZx#9úȔ|(4@a} ۩#a`k^" ,kiKFFm!{2'sUfx&r'Q|c3P_#dƘ(eu ruluKVpv'TːYCB!wa=wU,:a̲O%=t{w %Y(YȻI>eTbP|3$Q9J d}6;ֹ? __sͽ*:b$HdyLOv@ۂub3s(Nm_$D^cg<4SKXXA-4stHDNfM:sF?ˌKDIӣZxgPLߩUQ|$U5`*8p})@^M)#BV~\ǒTM:aEfU +d/J7^GXqZ&KC\Y`,ZFuu6#}K#5W RaF꫚QUN y"Ðk#2gJWXU+:3xu W1c،X91UItp~Z ͨ5k33ڪ/V(?)B sy'|h$U?'Cp8xF^kz3VS9yttvEQ"xoFtc:΢&?3M`2Df ~i H8i0,]Z^n1UXR)}7`V6rZn% @1`f}jVoit-'C&Y & KAQk-ƶuZT%Xً!t'Io\pat]IOMwb|ƧML_mz9G٬aCr@+AjX"i0 gyB=~zV`B߶ 4Nc(Y{ @Nf(>3ҡOHbG. zU7<( lÏGƼvJ#'K>hu>)amFZܟf:-;SԎdEXU-F5t :TgNɱJЕ J4Dr<{GnZ/Z%0fc {&?Z +FIENDB`pisa-3.0.32/tests/samples/img/tree.jpg0000644000175000017500000022040311160170401015702 0ustar wmbwmbExifMM* (12<i CASIO COMPUTER CO.,LTD EX-Z40 HHQuickTime 7.0.42006:02:05 20:17:26Mac OS X 10.4.4dl"0220t   |\0100 >  @# 2005:02:27 11:57:202005:02:27 11:57:20< dQVC=@^ ^      f   $ !( " # 1 2p 3 4 A, B C0 D E F G ) H Q R S T U, V W X Y Z0000000000 0000200000000000406071224!@ &9@* 3 P4 P@xBerlin  $ ""&*-*%-"&&%  %%%%%%%%%%%%@" }!1AQa"q2#BR$3br %&'()*456789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz w!1AQaq"2B #3Rbr $4%&'()*56789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz ?dC\<I2~ioƸmP4ֽMh˹-O_D b]$8k'}0KL~mdpjh)GW qd ю[ssW3vrLj,DM=:L0Wճs1VHydI<6[7 !ىwG^Vf݃?1O  wW*KFNF%x$VϹ"~Ǎ>8D*PX'p`MܗS GO`2sX3Ze\,ب܃pNڝ[u \[Y6;u+GjN_4Q]P\ i'y"~8x_kea_ƾ/cuc21r}:(LܐF2^UFz+ڝ?O*Сjj#;vn5D6ǵeb<+CB+,7*~r+t#$6GK?x!t=+sY7G.Nz7c?l<㣲!O!r;m0CA-2p &.g!FaդS&?oDyY7|Js+go#_I4l¸yG+k~.`dYn +g7QdO:$f_' :d[,V""ž^g6wWe7G%rBLr_@x ~.Lpʽ_qzM֖uXn:=I\p?AmmZʸڊr:$@)5E- :2<~e$.ݺP;^)|7mEK{4TfsrGhU=yR ͪK$8"1m;rrOlxj ^DK{i-卣݂ r1ڽM;.|Do|u3i^#l\aX F>u<%/q@"lrȭ I55?ϸ.~:SܝKU0/$6qO<5[evxFgSx|#g<4udC}SĚRY|YP0#RB#|q  FN<zG4gi}Kf`7o-CE'#*ӟҾ_Zk;hO|ݛr|9$}ؚ˙[S>RҦA%p&sJ"%zמ/՞MY6^#tnB>(W JMݘvߥhz iiŨIbv<^\nyqcfwq616UT'=kx2;{,'b Hq|64S,Ab aOA8ϭf淬jWk#F0@ ;`kºA'scUHR ,NpaГF\ݭ&ubs?QeRHZPێp:w9'{馛[m76 !X˯f"M8t:%nۉX"1Alcy˶xۀA$I/]S^$owPA Vp @pw7\qpMm3!SJ4폺 }NֿhZ-.dY@a}7"xշDfu#Xvo3'}Nဥֵ3 vx]I% u>|LbhlrKN'|%G2G8 Z u+6vF?B? ^-ZdgLGclZq,yl5\X۴[rI: 3 IvzSj:}ףOSii.Qa\;~l` 9 2YdNwܳy$IɫXi8V~|Lc^=8dmbqqpj8]FISb;{<Y`y!gX2nzʾP;q]?xW_Il#;^@?PHH>OV&G}b)ʂ[$dwֻf?zUFkhCȌv,'1rII*>Ɏ\1y jc:=-˸m35<,_1ɮIP~g;zlO\VEH9\s^rf$,U{H,z 98Zޑc8b *c }9'kqV--NMfȶtXV:dd=+/5 n'oajBLuR|Q$@nP#gp_0;#>s^KZ]OO֌ω1c ,"@1N93My# h Ɍz޼*U!V1wzK];GY/<ķO-62}kzPqR4]x~~4kwUbtI%ʓwd5oiu ?XEL0FvPUv_w/ߵ޳cs5B;h%]_̡'8<9Jvwr,2=Y#V ^莺,녗kZH:b?_nBtyŜ"Y-?xBz7t?67ze& Ř ĐHx>JI&iG 6IU'@lL&p.CF dqIwu]Jz"ڍ  @䀸J14dgy~%xcҰad2 *\gpYIԝ;cr[s;29Dm{6 &Xs 9 w.\`ݸmon9+ 5nI`@G`-zr1gBJRi5dp'R`q23=>]b[c8Oa=+W[L`B3GZ\;`qv#qx|>f>8yuƩ `uy{%sIy=8׊)Y&Է\rN3~5_dQzs̑AdzJG?UV|Ei$z~ m -7 LdG=O'+Xn>yX$)!Gyd%wGKh lF6'w'f D$Jr38$NInikV]Yce'!ޜ3,+d?_RI\Ìuw|vW71iZ2 dGޯCH1o8d~JI]"F  cb<.ER@FYs{ ܟ\ר#K4c<`9s765yt9YLR6Hє(`~Rb%pM{M:4HcQx}9gN"dl%NVʒm9Fz.,4@9:p?{\t@w21T觹eI6ot[H #pU%1ڹfyYmĩl'Vi䎼#k@m2Q#m1@*I@<~U#_OkX^D=ը ʂi8II_.d+iiu(b*s9 zY`#9\FGhڜi upX }f8~ţy$vF޽5c};K]ˉѓ/~Fm)to\_\2̬ 03=8# k\|BמIk. 4H"RHbÑ6^5uH]SI#Y69GOӔ[e?zeܶt[^ m+ ABr''u|]^i^0$x; 1b@nkYU-}HRT >K,%!/?i/p7۩˓Gp qܛMOšލ jG:8W\2 ӿ?,iEYL03sܘ8z}*jT[˃|@i`ŔmmFG dکZC 8<z*Jr9,Wr`!I4Br,X$$/'5K]F m! ]6K<qf%xx=QIూ b5 s;h$Ia圾@b ?6Js t#ϭR|7kB8AR g=4>z5Hm_{yb&_I>I^p#$Kw'Ņ 5K,,2 8Gޛ$wzmmtc-Cϻ#(s$;p>lPM淾i{Xq|ආ+{ɨAN,E[V$a /"j:{ͮ}LxfeH.;w7~WU,qiiq;KUi"M㜜?=ԣު;Z; k,_cHw9S\ q7I~zP`kzzUbaZ'p@iqJj|RWma=ķII\ %W2ktm>!4M 4ᙇ^pp8Fax4PeH3: q+K &#w';Fqtv9"+t;x(4Ӝ"KpXdSMdJ2cB켑Fsp+SDtsqaa##>r7@;#8?yֵ^71$ܡ% Ѱ!I_y#=5嚮\x!,=HI9t9,9|hpˬ%żQ0nS#~P^H#o9eXXEqs-TKiqpWɹdtbAee6)-* dR;9& t;XYui(csorF)U.+I'wʿүd_ sddp:zVƭSq*č*Ijx\ *:GLn}y%tIKg!G\ȃUE.{sy#p˓p_Lt}Bcw99|`Ĩ*߶2 =*W5WH `ѹ ,B#02Uj5fдGRI$d.#O\xͻ Ah/U}711Oۤ .k_w"|=:v,X$tgzW$G{<2ϑ mr9eDԂA2rɴ<`qӽi`:Gn۲Bmb'>궨,^[3y]:ɩ@@mn773[8<: ocMjBpG3Pf'/[`XZ`m^#ҿ9|KZ]>ԲYBV6;RA985=o>l~٥jBY!][iBH##2B֚e"-%#T 9eu9]4yǟxRLXdldV(fg$j]`zFqɡ[xu4=> #K6hfYw\F,QXn\'Hq_ /Z28f"C=kr}>{ ͜.z9^|p4j-qbIu,B\喯3q;#*m91)?,wq޿/:>5}^HdEk#vAk;w(rkڜQ>uk4mW(k+?Ǣ^O&뫋qqsp]p!;Dy>_Br0x/]Yi7k=Ea1 ;Y8|ۋ.ۘl pf'O1cḳKrsuCcv%ȒFYJI ]?{:g#ҽ!$eH&c3'wFvcrPC:n% qSO5T\7/Pp߷KyeϹd~ I|dڋIakb]]TW5;xb_JѦD0[v~_kXFm%V2}#G1K6|e c GN\0#OnQȟ>FT䓴y89?Je6W M$Ǧ>}"5nz w1 3bNIȯWĒZ> igEC}&C QHZE07~]>-u;D~ _PgY쥂d8Q`ϩ7kR]=%W0\JDwerBr-0 hzF HW2,E1H*o'&^dTQSLMSPEIoes)LpP.wd _"mp`Wڟt[-9_`QwF7.mrk?.mEqck!qq:ݎu"4Xsjh*hİ&.s(YǼ\HͰ郵x!B'k['X7 fc*#=H'i8hUI2||6g.4養9n#3mH<¹.`Q x?om#RRQF@Wvj-OZDIv>Sg_1YCo+V Uk `psׅ }%e},E!aSA;~-& 66l¢fvNA8 潮YVl,D:ھ)Nudŕ~mst5֌ڦ&rd/p3@M"=O+9s1<Hq\4i-Nl6̑@SC7%cᙖ䉈;eqdz}BYiuX-4M82q–|nP)$j~3uYYMhH@DqĊbB1qF[}nOռQKkX$~\1d?60G?/.a[v閲m>vc,+OYhϩ)M](A$}xvkn|S S@PI9,Awd,֧St]&Gnbe7PiM>bFԂ9fun$n"bToF?.ڝub^MC p= g{nos;K̅Yw`qһ{k=O-+¾~u-;r{~b$rC[}rc-ZdV8w@#3#ə<ܒs9ۧ^7#bh=Pv_fe?K<'^Z\knu~a#ÝVO4okZ.kG͇R-vX$c>h!ҖUӵIK+V`b|žU;w,{,zd$+y '=@m ae&w'nƑ=T {*eae mS^c9M99! msSŬgA#;hcȼO)*7I9p^dXL.Wh8b{ r3ֵ徇1"FIvDž봎yR ǰ:5ȭ@@^zw LBs󪓟LcG#/`|#f^ ֡# `OQ54U!4&uħ=litPڲ\$W2ڣFB_3napT0]#o:'.潨3o+ )ۃӵqU)p ެ7cqPӴ|*92BמUK ;vcFK(7|۰A37xJKy-φh`iLY7G-t;VohO"ͻfwAVG\t 9'}Wk[Oz3۟ɜQ>VfNp XXN9V v.eqwP;zWiM%tIÃ,sY_CjdS >K~,v1+.d`^HRLs\ӥ;[ˋ'+)P0'kb0'To1?@<R-7hn0(Bu^'xkH1ypѰQq b$@ ZMyG4+Tu wKxQMlG#p³+A-x;L6WęEڢ5Qt~c6Z3">d%7$vP ۚ_EՎV]:;b@Us p0pIKŽ/-cϐP1 d.3VË7a͢jOym8b6B./#ך{O5LS:vī#1\je_ ?!y:F)sa4yCĂPuѭ58Gj {Vp*v pďlX4ii\\%͋pe1,A`ׁ>VI-ryҖ p#c; ؽcҴ2mm җ@0lws ZdA5وAyc]C0q9ݜqðKgHɑ•S 9  z^2țA1Uqmn%sET;쵕/(]_ wasOS[Dxݙ8Mʍdx\icWp'aa"T,Wv7my 1'+Il81tK<7 ,ʥP,^g*>,BaSyrh$%Cln 9䎙zW>aRF 1 9\VCXٮ[9+fy#6aw##rp?y߈uk.E4GQo'.:nsyZk8 pGZWKF2J>}zX~exֽG6$Pry#'r+]SiZ0H/ T8_7qӼh:*ڙ$Y\1 ',3ca(sԐxI'kɼHU>YA 9\`zv?XKo]mer`r"|/8 3^]xk[$l~؞aVs{Is-u(a:U 9 H!ӵwڞki}5M]e#)T3=K~l_2A!Ӯ"3Ўzg:QGq)rGi\MorA,nX:3ʎ}~ruxq|]"ٰ"bw7d0cnhJ#byPO'{׆IX|')$dϾ:rVZhK$2 oe(0bc_.O _OTr;˛rv .H$^&$/bYRDPT*g(J.gs\8H;gnϊ'1\2_Ch#&TEU[drI g8m_kK++0@ ~`Š"j)+rτ,oa۶ףi>OGc@Ԥ2%"9$efʊՑͫ9-b[i[WFM5y7]+8bR|17+\j% W(.дl?ܒ2ILeoP4Z4ve1!x8W[_sƭsig+*4ۜl n^qN+k Ƨ0íAcm.mW 1WM׷SeLfeV3x pYA9Y-;뻘db#9n# #Ҵ-!E]Ѩ 9Cp?\d6"A1s F0'0H$pq\7?gEDB ™ lׄpp0ޣ!bn 97"s4b!^KC1,.`^HӲnex9N}I1#̆R)Ůl"`o,_zd{֯ZX $IzXrAp}}StM(T8!@=Npsӎk?/E6G ULQ݌P7k= i|2y1d|#o?ϊōiۈxbVl#=y8_92z;̸98ȯ?kz1Vl gpvPx]I:7z:Nss9cX<ۥ+&KGQivmB2Fs'>Iv$bBsF=WcSFX)dM^$~^ZZGŒŌq+G Sw,ee\7͕"-m'MM-/{X%K, SGnj<7qmŕv1g Azx+y'َ#gLsq ?kq0$ IX e,,[dxN2rG1hYV8ugXv9my~{Mo=1[*#ӎ"~ܷrV@3W&Ba:=M,RFC ێ\u"374oou>"_y.{drqs{cin|'Y el!`GF-9c{xb +(fN _:s_o_t^U.4"X wm9 WH"ϽwĒmlĬ[r)bdrpr}ʾ |n+^x_xB{mvYI1$ /`{ ƛ )y?vY<͛͡^3vƖNmx,' 6c''$}ܩyḎ$i ־mHK)˛1lrUDdɷpEbKqpGa_j +fDLG*;pc0F|?}bA$.Nv&1 4|qQ꺶qGn>$;㌮k%Z8E$/8=sN4u&[(MSIe#zUeks=h[ɉyT:xۓm+~RGܩ3X9;@g9$AY:lۉeU %HmcWCg/o,ajmI<=nKYeGS3.p6 .I'w˖u+=qht}af* rdڣ0WZuW:q,4.rZ0i5$܍bCѷsQKAi2yjcr21Ã`b$+6s+\Fv1%[S@ghEO$Klw`:b۸.XG랇coii0AdUUBNIF N-;Tt[; 9f]h%}ZUp1{QEbQz"/3RrI,Xby4΂&fV(ܣ=~K&ܢyyr['$ȿs00,l8,q!`'8n +' {yWi#ۥpZltcp9H bzm$_7K_sIY !RN#893T& 6w4I,N1咥33^C{gfmnUD,YBv;گgk'Y-jqͶ8q_ MȒ H@(|$%>c>[\bXt"A[I,Ǻ8pa[s:KkN /"@ xV*x,HbOC_S['¿~̲n)f,s|pa7-o-6e;$oyѱcQVtsQX[BmPM;4 ?98\u.IjCK2G~que$ҥ,V0d@+5V7&lu s(ze,ݐfAۡ}z?Js;9i=f/H!$x'5xoIBU`x_ ¿;-7G}UWCPBӧ[mamdЌ 9|Ihgll/-X< ESH |$F1b>PI^[{?FGĿɻ啀/"pt p3߈ nkn|`DS$g^%=ap3Ϳ.2sOqކX_hg积$ӏ\$p \0sx c?Ҹt4?S }ԳFVy@\`3- u.i]Kxv/̗G$ʥ(X6Krx $~#$܋m'n(V`3Q5i`vw Ǩ1u|T]_R63V#c-:q%ٍ5 *1RZ|vQod$S9z"<YT#[Sr=Nޭ_X3ĆIc'`b88<]=?VWSuY$ ?nܲ88榒)eWy$9Wϛu=Kv?m啢Yc 'iKFz99_)"92$9 1|dny5 t*UtQ#2av@Nq ;hbX,Zd7VDH2Hs-pm%}W[9{_)ZX cxmݧi2o&_/Pl[x#ySqPw`ǜqkɵk-~qZ\zAnB-e`0AV9Atf?AIK# ӏN`Wͣ5r9\=N:ux7֯ ԡ?! B/. n28lo^[\׏B 4-bAH۳BnOL?}Z4۴0 @r<YEǒ&mn$6F@ jզHg:ڪ.ѼGGc"Y~Rm uZjGqo TI@Q2'DĎXфvFdN:?u 24.6NI$=}[SOIKy*HS15q7M\>&@Uy)uʿJ 3~!klI&x%XApO5=0$$XGhoc ]=>;eP`qt 9_kڞ]֔hʔx3߁zh:eH|';]C}+_mfhKK""Y޽x 9#t7?gΕAPg>·x7V!ed[ V#r~_־wMYBES2=35)u-nc-.dw(UU+6:tҝ@sw׼'O dƌQ/.~V|Mqiч@j-F/Ű[8L!q_ɴV|w Fe0 @bbdiecV[˯FY y=nk.md*@n^9֮6ic\O3|UH#9H5v$wY/o&ڹ<d͂>);Y0K}+rk;mg":c׌Bx?H𶡦ή-pŎvueW>|>=! >5M ėssdos4ٕ^g*q$?giBc!#c]j,Aҭ_^]hx }~pywcUs=}B:^AzQH+xu*%~>b(;۟z:*q0lփs/' 1 Zc6(wG ^ky˲*@nC_W /zzE$4r  )rN85AZͽ uh^*Cr$ Pg~\x{La<$ A[~x Bxn?1g {'2M+ ![p6猀0N{iYf%9* Ǥc[K;5a}Ιfp=ό/.n-#HmvUd?)ܴ0ǹ8WˈD%L+k5haOnAec~[ФO~5d.g.vqv0;O2@YG[I{ҌĒ߰Q iRѕ`T%WM \]KP]zOشī",6w(WNΛf4UQ0:GA^$sBk yItI|e&2T4F W5rëkmqjVqqhcTP7`s?|"qLCHI)C`Als+Na9WPYb$ı7J`aʬ 8<dCt sN %Vnd p9@ʰ\$v]feѷ{T"Ɨ+S-W!I%Wo-L?"Gbho25f85~ Z7}RȲ[EI?2e[7dApgQWX ȯeg/KX/℀ 8 qAOc ~,i`# {xM^K|~vYcI^IG;N`mv! q޼i-FO.!`$|Ǔ얒xm'i,tSXaI8#9z|?j sbvvmd!y6q9ir[dBrV\ *p8|. Xb;W^ce՟ynTw~7^ZDgy{%۷݌`}:?KZO~lt*ֱUF~URBHmV+zK Rmմ4C rZJ.oyuwe>5]Z!+2^'>-N$u(`FfIUV7Vr?pg22^B6Hs~%uc[i2[H.dx?#썕wr޶uc >n b = }/ks2W Eu©mXsm"tZ\ҼM5Ѝ%g &Qɓ;|aYƄ [f^8vb@qf' ٯ>i:}#OV j)+BT vTgXNȽ!6$$+ǑHu;;şmΚu1E­ DH 3( u9yb9f']oYd+[K:I(0x89o,؏i*`p`c8"tl^N2u?}iųT~ڶmyn+ I83k^3mtyL؆HLUb8rϗ4sʍoO2|k`?=O|a-æA"mm*#(K9ƒNITV:y[UV s5uKC`U?>ƃ׵v ǽWH9#y]_G{,%%|oǽ|xn N$gi~^Eo%QV}MzM1Db>F00zgߍsqGV72Wmmly\ŖguIS< =?ҵH)QA շ-99sH9c޻K&-Tnr2AV5(X) SKy(f߳p(۟VmV? lK/EbhF*88@1jZ1$BymʒA#q܃+O6xtcg>0F7 WOL视ɞ)f^W@S_T<:U^7G0*|| 85$bpJ0ftu#EP`}A5nkH`JO3~6cvlF Y@*N;}=G"Ari_Udq-7?4,#YpGoaYgq4EgxCڳ1a-Ylֽx5Hc /!iv($p9~<=c50 FG.ӷcv.PKva2?V9cצxM%rñϸs ⾋UϘnhX9]϶1W9%ƧXβڬsrx=woI"e9 1t *; #:y[v+ᰉH^$o*MتP808>U}}>ʲFL%pUFK6 v ^ēXh?-CUmaёK*JrF`#5H<[TVe1!,ۅ9c=?&a(Rz_BL#?*#8 9W^Gͭqm;zҖH$,B $qך5rdjw7sF zo<+ vͺ1!E}u`]_۸ [GW^"_1^[nUooD2<щV0xRUˮ0e.Txf!O^ǩ'wv !&6I p WCݭf gۯvK1ddI'ls_OKwgz}rU'2#2#7 7xk ydx,7*IdrNB uq.{I=KfMXZA#%J\|Ϲ.FAIRtɻKb c''OֽnM$$_| JLkڥ <ڊ2jǖɱk(u"\H0APGrN3Os\Əy-${e7'HkdԣT vaџ18H>ax- ͹dS Yy#Ţy )D6U|0Gce V\(20,y?H^kJ]yA)߽[N9\fRψO嵻F' Y; <1UVa`GʯFy&kdEKvN+.<2FJW=̷GRGg $`ׯ_{g܈W;H Դq#$|!O'T{k{ۉ#e8򬦙B.eMJ9=GUaJCO|q޶b`&(O[VHee qޠoH#o|㼷u),89;?whtԴ=e͔ J1`>dʹ-%͠nM%#L `\zj=2L&Oa瞣*S&[.^LؒGu ֿ]\:H[+q:v[8Q&|ධ,Fy{bߊ,eԔx=jW)'$G}Y&-s\[)n"0cpdUW2W%x|aHh !e1GZp-3JEZX7g 9V H> pz2[FH>5ĩm`Q(D9-A5HWg?TV!XnoƍC6u9`1r$WxbH4tO3tSQ).|q[H@,hZY[UKDɰMOLy ?|ٮQ3Z埒2+'漦c@\;zܓ⤏iتa,?3l8$qWPNO) 3%;Tuq] VKi&##VtP-9R$x4O#>ZE Dt1:a Y b2k^F5l%[pY%-9c$SPcW$BNHe;?7ċ,Ij9`:.zjz0}t>biBkEEnf[ir adt?3uFʍ.;HF d@܏Wr5#%FbLYeunjay>U4=#P}>n҆ژ32z&%>gy@݉N@gӁ^i]! %6''ӥzuRH.t3΀d88e pL(+T v}cȊ6HfQ {G9NASдnvֽffdG} 1^O?nڑ#>fçޥmZ<#~7fd`uq,P@Nu,p{d* ׶g9"4b®1ߧ +N2K sw[0pYX`znݒU`T6s4gܬ^xI8]꩹MRͥVu$cvv>:m&QLI9h׌~x`O#..,Yq`Uz1SOmH)u'd9m`TI;B{2p UXR>Cz>y1߆^yǧS:mGC +3ӮGQ\Ƒ97+RCo\Ouf ň23knj"!KAQ sBB >_`#\ù2} zW0}!^9k>mcYa4z/R\N0y_KxR+6wwd%Aِ@<Ϧk[fZ҅̌|= 烌~|Jb,v-g<3F0O\ajiZ,k*X@`ڿ@Glc%'^0Dnd*9?5]3XnQ7]Շ!W* 8W<^g.ēSk-ܚ̃e\Gc1ڼ{ {`fYmdm?jJf\[*U$H'WИ%,l8H19b}mbx4_gl3،c]{n|\ͶT8{VI\l(s+m6&5`pr6q5)#7ZˈvS3 u p8xW1Tp\Z@?^;2B1z`usNG*:`QD7s؄ꌯS^eg,YK<W/h׈{]*KA+T O=@5%vxWw=@e^s\}s`?*yyM棬ڮis\,FF@^@:=x#\qa^;1prFS釻-Amool2 TH㓜ׂޚhUu:s<$9<g6$ۙK,1<+6[r0vmCZrK8S`kMc3'-?g](؞Y`y;:F8ھX>v7DOoycgX$rqԼ}e[x}܂9"O;Ӽ11\,sym#y;sDyu(.UtZ,L 0^L.u/?#$vI'ž#&o;--"-y\H?՜ͨZHpw+S󓒊i]Fj3ܫ[=U;uFN:gX8HF~uWd~.6?;B[ǯju Yob[)()ف$ݬP({$~̋#Yo -neތ\IټD+r"U$=03׸igvhňgq؀A9gcISaAXdTC[i SD#t xs\l̊AꢼgLDЭbzT Œ|#>%.A*%9xYGבk v)4.ЃBME3M-14}cWPQb85C:듸gzn_߸eFW{ GW uaX.7$H\3TK\MNv>a~ͮ,ut흤9Q[CRt-i^Ȅ{}!fS&milG8Uct?Ʌ%_&o6vѥWys2ska_í丏As3n9±#} 8,%:fypą L+Jewm^t)|-hؤ3KX|[D_$ Iג*@mlE(*cx&hw!LsAQ sNq+o> h7*Z>~o=Va@~$˚즞?IPde "x\۔/`kǶW }\Eq)w)!v~k,WYHt+ռE>l0'Aǭh>F@W{{޻~Md-YA7=z۽}|"0G_j:ϖI*-l\G4ޯbq)A- KnI[zZQTkouVQizmZYۨ/9'zssjn_i#Q%7fXe|ŁFͱG ZYvXo#޹mH7*Î=땶FzP˜όy-y ͭ[R`2v#Vwnouvr\#7,0Wh<?Zjx<Ҿ/l]«|s9FgX8$vȭ3Fwq>:qWpXqVXz厕8lc{E6sv\AeY'kpG^!9Kʓ\u:{ 籹0A_Q\Nh\y Gnv_xp JRXbC&с;uW +^-ZTw-/!9#Wg [N uj-;Mֵݗ1z:7R51lwd0kv$Z&f(t`qGB b;kfuE;##WEsWv6Be* 8efp]Ew&yv~ r]=kn~kkڷ>vu_ X%ċnke 9=kڎ2[.PKF`-@ռSH.MBywl$B@15H|A`lEv?x_Fn/ MCmǧq&Ir\H8@5U0!^־I'M[MDYXk#i%c+kE :5煮Pi6D'1yl`OL8:ju͊k*dF*'x9ay}/þյ~PFypC 1`<Fr;ͧكq>ERFvGVQ=xQԮc-fo+ 4.O$⿠ci-sl-4R\ujoXwMN«-^Ȭ!8_5:*>[J !^!Eal*d#'@r{yn2]ۣdf]Bkwd17:TxY𞱰2`~;kVF4Ozwg?%E}0dM5SϨ|IxqXd #_TcYt>\Q(pjY}ŅI3*`17F ]/͗uFGco({y6 H+Vm6-"$b6 FN|idY|v$n ޹|Qu!J<gWuFm9;x%O7?=+]#[In9`{Wy]Cc5Ll,ʹMni:;$Y2p?JTCǾA\~ 6G#"|)('B/SYBug<׵i uLjuafO&{+9)Gk67z(XHHJFIFHH AppleMark    % #!,!#'(***.1-)1%)*(  (((((((((((((((((((((((((((((((((((((((((((((((((((  }!1AQa"q2#BR$3br %&'()*456789:CDEFGHIJSTUVWXYZcdefghijstuvwxyzw!1AQaq"2B #3Rbr $4%&'()*56789:CDEFGHIJSTUVWXYZcdefghijstuvwxyzx" ?{h#'" MYѢ֠U\0n/_֙q&Ps35qʄl[.7likxmcBJ([*lbn[铃V|L#I|-*@Yĩִ#@$Ӿ"E8.MvR8w1}?2L?p|ZG$l դgjV0X1.淗M@FѱM/N'ar`n1O]=sr saliwnueEeCLƋ&KID:\^i , sx'|Sȅ̷-X;8d~$OW׎ulbn.TwI UIhv;eۆ#$sҹFKۉ.J) >Ⲟ#'B9?A29xOB3/kmEk9;xje.F?];@¤ks8-z0'Kr"g$Uy8f!VL6#?#]6gqOPy1s?B[6 "fXr@ЁVRg2G!8TS-<= bI<cz "/Q٣Un,az|X% R7nz`|['إѵJ""o;:ٴ:3UmN-gHYnbh2`}PwZKr*Q ?xf2T'Gq'8k4M[Gm)]ZZr88:'?f&UFI-b~bzk~8R{^ihFd#x>RAq4pWPL @2S,Ұ+$|@zuP3mG"rx coqŭ.׵{yfYC#^ߐLi:G-$'+QAw^ʐK!c q@k^SeӔ2H<@ic5,۟NJMTࣕsӚK}Ӫ$P*$Vb9Z޵鋧Eu"Ilq)vIb~bG'Ŕd-@@q-(,۪۰AބdI^ZzjRDd_3r۴K]eSci^zt+EDl$yUlҴ1f#H3ijM5kf;rj톮En*[TeBLHslMӊ%Cd+~Ԍ'p՗]nEgɴ@s?hG\Sj7vBca2xz&yaoq1Y^GuByi g$ghi,&9fGLM;RES =3$s[Ro-d3ddϧuQxOT]G#̏?5Z7}J#.̓Vn7;q|~}LwRKӅsݏUd+DUnXsbI0Hi~kn>}mHukѭO0Yz~}ZHi %WYW,;%wӎ+3@ޱ ieLĜsU?/iu 68Qxx\m{xI\!N^8KD$ztz֩s*;dGB;x8ۉPb~\F:bc%dSXN:'pc&"KvS Zbm2)U9#z]6r%f< zqFk/i5,Kp[ΎcQ2]OFNj:}Bl\.pA'8 ףhյ 7Myc^ۆtM3XT vrn 8⇨kH1O[=9[ vVw{yL9q;;D*a $N+ZݭlAdo?R)XGK+>\\܂q€Cְf;оy˜iCًy|Hǿb%~y 16;zE065F)U1NG5 k3~GTD<~qe_|QIӭ䵚I].@P|RΫJSr]֖1'x2F77o(o\pHrSk# Azqsas[@*4!.נHw3 ү^"y,Lc<j[Q,HIpۈ=ե7piIylG~pOSϥh<)+=?a(0O=jИ@4A=>RDd[FKeI=&Rnp@@@Ȭ"Z_ShBnfbk eTl4LD`zc𤝃su 8Dib@׽q]6ȸW#5#gDyW(~G"alƫ82sѱJ5| Y&y|Gn#^H]*F 瓏B+ǴO'RPq*S [yWeK)aڲYXN{m1WM{VW?VӜ/dsC#o?õ#ۨ&2gWC4'c866&i4-":UlE$.,n!bO~S墊b¶sl)޴r-Ǩ_X[; c- )VEkxmP*I<I4Cw|@_,tkFҧ@Ǔ-Hn;G=y i 0S8Q~ 3QibPŌ5ZDU!-w&!6GOOupErA*9ta{tqM$H7rH6\}:mp]+: )U B8'~QUU  T-tWQG݈hTn%s^|8@v8z u+.c5™#r*Ĺۛ q"'T#v@Czi ~TsW&܃9XcSt,z`Y>BtV H&=X1r`gF߹ֱhƩi2$5xUI.$ | @3խseԮfOSfKLΆ\p=ExwVyuͳ~X,[:Ƴ,v3[Aǖ ÿkN7LJmWĞ7s\? I,2\F=y)XҮXQKnKm- ة#*j4ZUq8Ǧ~oYLĒ Uc$Srp+ѠMwK^dl~xwH{ ܍﷧FDyh(a7å<)9+#y#CJp'as9 ׊kNN B)}hv5>}Cgۿ+5؟QKxb;"cG~̟ƺ!wԩnwJEg}'5z/vmLLKtU?1/ڡfu>@@WjdY+@dg%xi)|aXhnr~qT73RCg.zVmw+У": HZqj9]F 0TtQҩ,b\,F$'?ڢHp; s+WK˷8t $gI#6W`;T{UI,`U&W1H$pERq-Uz-[ $dv9BOb-%Xmd5?A-9{?NF2􎳬*ͮ$x`^_`IE[ 0/Ŀ/?W] RU^~ iZ|]Q)q0,G{ F\G,3p#'Jg2ʸǮ\ZO fG '{r>X,֩\f镑9=s-~Iuw[ZۂT 1?]A֪Ro7Z币&G<~ǥ=ݶۀR36ܒz_o?5o5ϫ:6ikj.EG U'8osɤH"{k:nɘdqҺ#<%1o~UmIC\߳^K#ZḆ94l5*>A'=Wq^k_CBqKQކ}Ölؾ#kY2Ƀ^q B%d=:]NgEl9S<gmav:G#MdS_Cu_BB?Jt?C']GhPI9;]uѫ'g&N{zM,ڇ[i]oHLN-0k^ ^x3\oƝ[QHY5> %BhgI<#uWų]O5D(FHbI{݅ե>Vyto.q'?1qj_\wV .[|/S+ Mw4& "Gy}X|,`tn057^޺;i-{ Z% = Ձ YqGY3,_jI20/)MRU{WۼxFF#0C0$oݱϮG5]j%Q5r%ŢcZ.Of^s*e*Lh$*?+2ڻH/<^ۛV=&6x MyNMqҫ:)g8QpƝV9H̍,w 7>fFݐGǽ[(m25iRH2+ g=cu Kz#z^GP|%¯w¿ ;oBѼŧ/ VZtq'彝F%#?߶֞ƨ5Odžuw{gӥkB.I5|9*ƫ~U) ]>?#O Iaη;ZAխಸqn?}B';+MIklsE6+[.J`g`[9ԓII?_2M#Vjz]># Zh6Ֆ]M)$H-.s.:VWk+mii <\yV;%r2J 1tP^LZV蟖:TcoWŭkM%.NVy 9 ܎3ҽg?_xMr(Fiwy!('ޫ:jI.ړ/|]m]C" 9Gx-}&g1ֿ^ c=[׆0ЮUJvˠ9m_Vrّs7߇åiܼd]mć%aR&TgR+9O=O"G$Y=עZ*&?xgT}8~?pN_qtς< ^^[ $JĀ''9|O.Ѿ'|!Ԭ;ն7}ַ=GĥX:@@;r2'IKq?de|1cma,YZbב@~ 2ġ-J{ûoqmN+]GV6)bՁw"6P;]\w~&U]i2E )(0+!OcRbm!^R#7eT1ax=q[: \YXTH_:tOR۟ -c}C) $L_#Y <GygLE}'T&&])Kef>|Uz~v__|_ໝAm๭qG.4/a@ɚůmg EI7NKȪist% .547בė5m$yO QWai;$fЌw,Di9$MkNPMJvM;?"Yf|C[Od5r rG$кʇh {FG OO <> UddE+6zgv ,MzFPCÖ/g^/omF׷6[țrKݰnnq:nqeeeC]_'3.k vh.4Cb:+K ߅'12-oL!O0ڱ"`(j)[%oLLmgGu4f=xgI& [w`ŦE% arbP1{<9qy+Iu.' ʟ6Mw$NW('9549 r1M?OBF1o}6ój)pF vӭ+'u㴍uQ+m+QMUJaҥ&?',CS/}wIDb$b(0bIBZ%<-[9ڦ5nV)_OC{mf]6-RZ3[6[\&Ǹ}Ɵ ǏRMZm 1s^설}k'2?Iܓy` Lx.t-ujZI5 *>WcXaҭ8 3<᫏iT^/fmoect +ܳD12W|ӼkezfYV]v5Ku`%Dy↠.ks{9<-i&+c"c\7ϵ{1Q222HVMr^U1kJIKp$XNӴm9',,/ ?w*+vPcfx wDA 0ݏ~AWa"x} 싩jw<218 (>aduǾk9u mN;oQX$F$c<}}M>j[~HĊDJ0@| o]>%{9mX_] "h{9fE9PՓr ׹_ҨmƼ~?l? (/w_ZG|y k-kMKM[&Y h |r?jOVҿQ|6EhޝMqwoK6c܊Z8f_rmU{}DZ]|UPѼ%x{z,gM}0XUpeVeHgqaۚO y7;>Sm,l͵ʴe4쪣riy#䓿z(񭕽7 !f;;)㌞+K|V? n$73xn؟m2E`{0e(%fRmw&xZQL&Y`\ ~Sx*SGN[$!IRU&e[sYs.cu|@S5@,Ƨ!DytUߞ88烊l7wWuffK刦+&$:QiñVs^+k_Yi5Ӵ(f^O3D xث#9}KK>, ǫ0PiBUUWbX)-khoCϵ]ŧK@V&N3Z:KZZo-7JUpOS׷s7"þ3Ǐ|Y]/v,iJiS1i#rFS86m枷1 цQVBT`A}ZOhym%l7dsӌ7ǡqZv׺\Y0\\$4bfTm^jE|VNp^<ǀNNH+rGECƷ'cѡGݤ5+8.!Ea#['_ |دw9gGytuK%  L.a5;h[co,9dVoM#@ש[<9a;SHu=B(`D}>gS B h&ֿ7=Sg >O ZͱMǹ0f+Я||rৌ>$.~zZ>fL/`XIHˉy.Y5ZѬ4a m|ko'$W6׺6*%}1TO)"Ҽ]hS*زŸ`;,w8xʝ9k枿sv.JSZU[\Ü閤ƌ99Ư^]׵Mmt{ 3M]Na8fV N.lT+/b^^i9M~! >ď0dIFI|ϴմGP-cgQhfL\q5fego|U*7W:z4ixGDo:_nPo|kGKEŢImr@{Ss9ʫ[t+OeаP9GȆ au{9gzwo/$S cu xAΥ`X7>}?>UӤ]^Y!K 퐡\51s~.cUӣ%z Wf@Nnu}E0Ntf[o 0qe0j?14|X;:V;0$MII nb-ɒ#tW'Ýau* j n"C,BT>]A# >Jm7=-E#QԝN3֩YdUtIlZjF;Ϡ4]Ǐ|1m5s N1sWh*-NJmoNm^=BG 6Ud(r<`Cᙲ6VKK/6[0,$$`grgO[ӝz,`p1̡&zloN2豁LYi&H=oVM[onCK&Xʧkn-F7_'~>+_YEf⻝.FmWF[_^I&^720V1dlg:t YwXz.NHN>)O&m.65oZ Gi7tZ]|B»A\*~9-G#}|u^M# ]O:IJX:|wij>5K;\4~|e5-1>$.k0@TmgvzT+L%{:lo~$l:{}x:$Xǃ"*aӣƟ-QrAqrjoܗd COlHEwRO%➽x]kz~öjvQ0zKġRȎW=8[M[K )Cqo* B1 xY_]šzu%&u߾iP ݽB:&|t׈>-n(uHCiu#"#6BJb|cGJi4uHI47- Gh0WA.gKaoo(( HV c'T\ɝ&w<3  yϑ69oO Ÿ ~ I Vz5V=X[%bYn f"u>dm[>r:~c0@gb΄Dc1=K.Fm[~' ]}RQrS\r{:?ZsV L2m+iw8f}ogE՜W^yHn*͹@+(N9 g%{ۍG>{ixwa/۝o3u+vᅽˈΣ`FGngc=אqk^(|$ִQYh7CbW*j Fŭ෉ O2]NI&5'U@3@s8)M9KmW ~izߊ7KV>Im6yc%6˩m]UfuG(D@!BiS9xM-o]j&cɍZ P'3ғx?FDNև o'/5/h1xvo/I8Y!)%Cp${n!DžmxnMBucdܑl+M4Wct__E#_w< uua}gh,54:fq6Q*D|Ry+׾8x8<0ǢF[AuL% , #ՄQEo_9M*kM36_w{hZDw\60do?-Ɵix]E|7-bte[Y y'rC2ab!Sgߡ N-s-O+h x|7'HҬZMM;ح}0O,8>b9+AO,,-t_ ]Z[$S#QM 2W``ϓì3^gS\Z/}|ַzF$Dsc 8Wq[v2vi%ͳe1m'lB:SԍFM[$D`꾿J|#ۡA)]ɟmOi .54z7>7`3uk̯Ath`kF𮋬w:ŨUN`YF`nh#qzjw.[X};ڝt$SGmWK18iX?z?ė[&':B rq4QiЛMh@eXc6tabt<Jddq/~[|*.#_.?I#nrE"8ʌ1UЕ|A4;%4iv:ޙ GcL"ѣc "D#_ޫ{ZI®3$DCtL>Y ݍcm!5~f.%['PT_'fLoCt:NڤO ;.3ڪ!-Nk;Hv|$yQF{yD1C0U.-K( KԝdyU!VMWNk+t=/T4QjwIr >Yܱ30w$Ihpխ.{>3CQFIGIU ow N͕B=A]ÿK_26iby!-1pͽ rH1*SZ^C5 ^\H\S֬v21~B>hs` Ȅ qqXct˛K{i#WaO`AGg#cJ׭/QoG/(e W4_]F Kq5 QpnlySźSxM6fQFDm(t-b&V@%KRS6&[ج)%C.[$rXe㟘}w?^"cO{ D+̎\)tʊ8=̫'8OxOY;t>]BcrV?8w Q*HUEv0迶Ⴕd"+ytiHw8noFX1pF08B'{QܧF2l}Dx !o6I̞[tR@|6`xH z6QKk;ia0rEy\I[Pc0E`֗7{|&~h2^~/us"ZmqeȃrGCrc 7~jwR|1Fmw<0+Mܑv0A*6 |ceïxGTҠX]Zk O͸ΌBp''꿃$t?OӮIZg$H&a${ Yn۵p'W> /2ș|cAnct+е=N;}S2m4nvf`%ja .x:R$ox%K"c`"e? g* ]/uK hM4N"|+pύKQᘎ\dǠ@|~iZ2OIԖ9.&i!0LFY8.EXNMJYS4Ru(Y9\RP+:a8f g t)RSSSlR|7]'-5{;o,}}kŗ:\ki&.\r\/xdbw.S5={Z<Xi]Y[oA9$c>'xĚ{x#T`pܠ"=|<ͫٳ\=?7g /<9_.f]f !1TE+)'GH4:>xJYX6R%K,mٌ@Hq3[J ̺SVR\ܬ<'>7?8Ck%Q]jSZD.yoYe0$.O1kO'՞~#"-Beoet.X$rhPѣ׼a:hKἙZ[D*kr~K|'a\'=fEmډ&̕VPNHQQq-~yٿ'?g^AlB 0ᘰbFp3ֿL Þ0toL]ɈwÀ`\c E95|74]:OMi[Jr}yqg$pCc,>_kb[⾯j <U eT&+ oτ>-\6{MӢS4Q%myal1y$nVqؼswi~$摌s#N<ڔuO"g-4W<'Z|FYk\ եŮklS勋)MH9+4Q6I?O~ҚټWiZu^xĚ~0ă|%eLdsUspP3 ~?m?D%sgyBNe;vY"E` n*;{ 7I k, F?ṛFDo1]&Pb }Z5q>(xuxI;K]& .g#Χf * =׶qEyI{ge T'_Iڲe_k*ӼG+ YkzK_\HdHT#KÛM*[9W*ԂHl8ۻyl棕}Z>IG ׳vpX7pegWO|(񾍤x{k2Ѡk#$+! IJ׏WڗMeElO޺XdFnfw b|*+Ε~mNJ{;ѭjɭI,/ _e+ Xέui7f}r٠,GxaW7ZmrJeY'O:]3v77d/OjxDO/Ó[DToEB)apNMV7<+oR-5Y2!0rwI'9wUP|Ic?1acZ%چίhV˘[uu#*TSp};ݟڏSNFcN[}+p$l #i#:E_džmM AoAm.Qc:Uƛ%W 12ϕs]RFRr}!?>o4iipeV_d+ Cď5kh>ʃ -"kFX剥U77&T,iXMwC@{d\(eveRǜzB.u˂tXivfݒI#g ԟA#m)&t6 p{3naN;nVi+p>vB# L'M\y@[eʤw8 xLK ޢ3`YTy$m<_'7Vd&Ȏ2 q2^{|PgL/hk-6[t>ܖr$-bۂ[ G\VqU<ݑZ>,nŭm PAI5#M3xL&oI/&TM.0H!:;6LUa¿oπta/Z|8Xn=F+0ZXVfmVf'q"J^jtRv? 5~O\RlfI"1 g''+kk? `\7kFY g8pk/#ьkºMC]+/RdaĠ2I+nXT\cwӢ Ф R Pnx#;Ӟ1Z0kHuo}XȟB[;`GzXd?q`[Ǟ!/[:v^;ML:B.`b@N0>:֡ z;k\WQPa#J?2Pل4(uFo2{~es-?rUմXp>%+;ຓO/I|\Am\$I*yљ#L;RzjG~+|BuKmo.u)^Bij(!@ n?ÚV5ܚe\RIen80m0v%O)_Ӽy 4_HMՑnnM>C >k"  "uCCψy{]:dJkHčA57H6oI6Ԛ_}şq xz`w/C6vn'^><9t[{5xpަZ;yX8 k'iEπaİe@푚=|:?~zF^\[5RǨDH)vGGbFw#gcZI)Z ?~xOGxbY4絋kC,Y.c _ ޿Phz'nɞ[CnF'fYiK aI2@5SM0AkwQ0u9-ҽGx“%Ժƥ Srʑ]m՗F.sN;)aWXZow妛soR,$o)vg ,wrN~oýN㮳hpA(&ϖ CsJ Zd~IQ5<+3|/$dܙP@q\ߋ J&NpF7sW xXuEKbi8XuDHTrІ'**ՈzJռO&_7W,7I$%`o*b &ln%˶$`!C&YY& K`2vhWz/?Ãzv'ѥ Yfc2@  Tد]'GM6k?˩zs4\$\($df# BS>]sn:wƆ^ *- >UFذەyFfۅ?[7~&iZMr"DtA?4.r2&RB1KCo?~?&A"o߻ơUgs1`6s{+xG;{coii-YM^sNlX[F3l\fvʖsVHT:?<9KQ$Ggl>ԅ9,ؒIbIaKk)'^H+ώ#[3?1%@1Db+o~>ֹ \ҦsϾRٴsܜ0T솏>8xEƧ>4y [*vk+Y,A`2~5ՏLXǁ5- Ѷk7PGtAk4YK4(lqNfO#^ S~xc[5'6:Vmʟg&M߼~@;翆ু9ƿfIumRh-8Ț-܌/ N)q#NǦjg]J5WСY'6>ZwQ#O]=-?_ .m5T!Kg*vKe{׺20xܟC~aiOȈ-ւݢWQ!0E|"l灵Z29H{ VU;W*/A[$q_ oN6b~}s^kxCmY|6[]]^%IoL3˨酣& ^$vr˹ ElxfjqwLRI! yw HIfHtx0qܭmʕ?[?d_? >ڞrz}ƲvW7#fVA Ӧ3EηXŨi- 9N93#(0F@*@c1IO|[7ltKx`ibKHq"kl`]JtK2cs d}&qy`'GOyo˜o+1KV>>8zԒnY.dٍq+Bv(f {>^~ xM)m'OoX9#&%bd9prZ;O?S|8n 3ⷈMBMHVwE4qEu x *ѩ'78dB4-7D𥥄,Z[{4\Hdoo:Ip_irqwi~J_sNju_ #j >~O×b]WO]I,۩h-N;7BfN5/@oÛR[5a:vᐆ (Ŝ`Hj,}Q{GjY{k1>vf%@ĀH#'$My~Zu]m@cVj v]By b'_k'x?Tc?~߳j[o>/Tna).we)Vue#~ӿ꺾1-֡{KEֳKwQd+XkSZ 6^^2_XO ǭx{ƞ#O%P|&ei  uSiwi-,6AѳLd$nTU6(~eN;X㎶h--s5ڻɵmI.ʪ*~~^1#_[ CƷ68.F{Rr=)bS[-9U_3􏅟xB%uXŬ:xef†;m|?Y[\կ$xkvGH$ٸyaq=Fo4C|A(/1n6@`޹/9^+5([QvOr@ j ,{0ve?ňD.K[[( 2Q2l;qO=el#\P1cmɪYtIɹC#qRy88Ul-mWzpN})R\G|#Ʒ6i"Xt5Xoi wVgx9t TKCY%X̀7x@[D:v\y6o%?y$DB.z6 w>}*^ jww^$Ȗ!mgr y9H&DwUb$8R>>'i_xCĺܿcj7yV՞\F$,o]c~Ku;D>)u|*`%=[|o=X9>xjJt+uzsr`nd(FmH$ GNu'4} ';D-ůZi>iK$[ߍioQx:qecJʏklYK^1k7% [V?5~!kR4:*,ZNo..S$F_(Q|Y~xE5K-~}>*Ew`ڌ֓NSg 4+o=டOx? < {u5kuui ~giYf \b)I?m,ߍ~.v]׉4kmti7& Ѭ!N+95*MxK75C~־,x{lYl㳂37 DhŁc' rG钬#12ztؚ1WB҅ވa|9ό<~뷶׶(N7s\fݓ$($6No7'&].JY$*"eRʩogԶ:\+~}V7[joPuD~r `9^ sG=nх^Ěޤb7@@'x&QδqvsI,K[ eRʆSZ0qju%2 1B(vL; Ea~kA!ݸ7|=go12S62蚤VQ$gWa#q bjEm$BkFig? K!gw:moVتt+g:}<4lلr62s:KNp₴_0Eid]vtMr~l+ ^ԾjR%rxmd6wwWH|Nܷ~'4=~_]uYVV7(ffya;V;#̯Hv;KQ{+٨חs5[Wn_tm5Ōm+]+,#Yੵ[k9f%3m:v+,rH x9J[|$ssm<)waΕiJ%GE$,6@dW~ddzi*Q3 + uT-n߭*VR3{GtLM޸!FøPڥP0kt]O{({).DI2a fWˈtrZtch!񥖣5:^ay"Y8-8T .l]Dt9VFkyRpzlgR4+/&-7xe1~F:ڿZe|C7) [ADf{ VP+y mL~ 4xkɯt VViwKg4%:-ρCi|G/-쯖|M Zp`m;Hј:œu;?>zN'O),Ago;ZfA0$s. )fF~_uPx{oƥ⸣{.Hī-ChM¤hFerס ^x'ÑiCa`&_64cw[~^1]n=~UEܬ@x~c]Br <8ZN3-zYoMT}ZMkHRgub 1H9f^Mz<,76%rD:h ~`;Ue({<:Iz_.l[__OwUhKv+Hc8@~7hW8=sYsþ#4woך-WMY4SnLV6$XW rM*XB{gkvi.IԇEu~>0ӼKm^9|CK>4&[` .19wV^>H4%J \9;!G95BYͻkt-89%k%]|sZOo51*IPPfA*T3vzl|/[I VWYL240%-<~Ҍ<ӻUo5͕W0\#yd ]@+44w4fg< GEjPJq_q*n2gn×--XX^ׂ|wmn+KNt`6 fu#nEE^n"^(_KyJѓZ_ʰU6›fpXn>5KKh1h<3O"ly.2v&JU"mƜŵS⯃|Oڅ{Fn啥A,HP{WKzx[Ӡh@3JJeϦkڝ -NgŖ˧Jf偰6:^sӀC\^k&|NH}> g&R\ܺ%%G޹wy@'0;V-k{?M/xS|Owqq c[ěO0!s)WB%Ŕw FR[0ds s\yZo3"Y,.$QWhUN8ǁsJįx K tb< HH/NnߨUYZ)S"@_xC@Pu[x*$ PWˑ̍pTi=ǎ >="8 І<yfy$֩\%M{S FUb[mݵOZ%~G Bxwz g,ł40h!r$U4w ïH|IdHYq^6iU?滴zUJp勵Lj|Ue$w> z.@.C5_;=CM[)XH, ( g;z׼G(;v} өN_pok*C*,c8 G+23mhO2F ӭwBa)sGÜӓ+=? W3lwW}.DMD>k$jtwicj 9gBT+;y$uw0qzz _*~.4o~O$v%JTIS"4h r~V_1v<7t$@xu|+&چ`e#XRj=O5QocO#zpb.#g6;ʪSk&͊Y+F)\uKRQOV_=׊5}gy[<awv-xRS"ndxźF⋑uepdi ҙ}0s*>y7;J1#+}g^ .JPC>SY ^1&$}[%cۂ0 Nswyq]jn4K/]<=k'L穉R)Mq˧^Z1,<(r Tm+=0oq;tԒzߠ2m sv-tʉ2BA\W/S|:cXC펉%rS^ml](FN?_ث燾kp0\vJTw(Xs9=+Ou8ZE97GDwwRpS o`U8ʩ<(p-yovH_WMY|E{#-R"iRJ=^p~趚%ҵ-E]}1I00yXZcF?v7A|4ޯ"?'VѾACo1*VQ`Drcn&ו4x+h"PRK3!2dt8#<B jvS+mC5Za]K~5@# (߸6YIw{Ogѭ$ԓef laZB+A+-oGjNT}júNoi/źM^k]d)͹@!`Q^t YTb|sԇ$d4|Jo?_9l}NfVq"lp>u'8eZ~qĺ/֟r>ק۪γ\ۻW۲9/ʤx9J%yG_қgi yGux}i[)r!$1yRggJAF| 4m/~ u'n O]0ڙ#%I]UUON-nj.8{j*6Vz?S_EU?K:i\Aiݬw+10OJS>OÓh1ܼ|b#޻ptzN͵i_sg+ҿSD`AiF ކ*9)̃?x+A8ou_[ $֏ׇ.oԽCc A8kKubw|4Up^W[_ƙtntn!ƥ tؘ{GF&;$50uA@tKY> o5QV2>)B:y#&~׷*Zj67J:N'( 8YDedFܕ㚟}Zxune⧚TN ƤdMcC gQ >;buǤ&s^KぞpqZƵ; 4G"lj-=;__ #K/xrn;bcbRU<#~^i|$>xa1ĺAG$;GjKF:%ѣv2@g$KT&|Q򤳝ɸ7xLxKT֫sݕӤm0FU *TڊWz_tJ\ʹyW$xM^G$O #xdȝKȮOĞ-lb[V&tuA_4F1dTm v m84smkASz/tɫ]oL4[)|)n "U|)D-IƿءK v&*< `m5U*9-Y1l4 <3j3"Mn;54p(!'wcxG%VM[Ro67W(۵\~_G;O-< v2DNp&IΥ緒!#rbz4Re;/n?pǢiω?f{I&xV&d"A* F3Gcg6 g]E叅`K[ۘVhķWd0I6 2% IH,e?6>:gn<Mf{IZ8bbrI'wc!4/-R>.-t7`2o$ tNM14u4?7__4z5uC!REJ1 d`s?\ֿaC៊|Q^+k+Dx@]J#+v =xz 5mEjRvq~_ƃ펧1l`H4+c[i&ǘׁL9UT 5ږϧ^HD{YMš(V<^Vucjpq(70@RYAqge=0Axֿc#χC8ϵ@t$q+lPPwe ;頾15 {4V)wbich,@$yZaWtg%ZkԫuK20rQOٿ 5CO|:#GmlO~s׭{?|cxz]l|"eq <<6I3p--y ӌgsc׿1OWzmmѐ^9  ~&hm١uuq~thO q*jU(Ϳiڤ?;UI"kmڢ\$^{^3ywYh0]]J+g, (gsptȂGx>+lř,FI^~;m9O(alcݨp֨yTn23ڔmYRoD|߈IyHumz*@!Mۊજe8IU~h3_~_Oc_ڧ5"h'hN緓 ?"9qy|;#~~6|B4J;.5&i|ctY䱖U!7nݚkQ}UiZO~_uxf'QUif#-p0VSB%17;#OvXіY61SnE{.29k%z_Co˿iYk/A#A_By#+q%ڦ0>a{?s2{ G~&6]GT"K:]hZޣ5Qqoڭ03$m5K:hzt_7:a♍DX9N׍B)Fcn:NN2v]WO3s^umEͬHHp'+oG,> |MK{ᶺF6]emP`V0rUA@Ib0(Z[rѮҌaBKE}H(oJឩDVsQ/H/#Ud'?O|+>1J Ęc}ܶFHe$,EJQ̭oE*Z#lm~kzލ{'5n W<8$_sm/GI=ǦInһDߺ !13*g5K^י.4W]ᱚ+V D < \޹i^jW>\/ +\2&7Vjy& Hߞ^k>^\x2+(T#pާ5Ӂx)-[_a{&yֹmqk&mCt%bGg=^G:r\ZȷRH9\ԨBU*7vW}}_bg.?|_O!.{llRȻ0lɋf h^*meצC6 erL>UPIB{BxJWE#:wye>eοz2$ aC3n2zҺ{ G㾱 I2z{q}pxztkueRovMDh^+ų4BthLrwǟ__x1;~} !n$U<6F01_7(=|4T8c?iڷ^3ŸKgLg5´HVQ#_+DŽ^'-7#mvT6[vB6@w5ˇ8Ž.3iE(xoZϥA|E<(@8Mݻ.ax@n<'y] hJ6EĂ#U8Rʶ;qJ^&}1e4~ȿ ?NejK Iws7En#$v"pc?7R$/W6lAieyeف䀹5Ib>p?]3*__ ?gcRuCFkgK m6 q Fk?`&~Һ9tK5易I,֫Y@EIaUI=Z(a{|ogEqV7~XAi/= W"*A<%ެcVw}=ʫ$#(*(';f.rRpp~+ xkNpݼW]4̿tr1 esIj-/)*  r]Duv@=db 9 1_{Ư5cQG6I;)2N1\J\oE*Q?iOA"]"P@% y.dp>_7??>t;Y,P rIS1ZmPJ ǡhzgw^ſ |#\Iu}:_1#t]nx,F{U߈}kPuq,+9>Ӕ F1׵ΜfhgĞ69k6SG).~Ϣ {w/}xTO×~|i͢p'tY ceCJ")Sj%NPѣYTS7g `a'J'e]5oN dc*XnH`:q]+SYEjw06{~KYSVkzYN@;$U#o#s炾"\'H)˥b # `q]1Q"NV?pisa-3.0.32/tests/samples/font-and-styles.pdf0000644000175000017500000000745311162761635017240 0ustar wmbwmb%PDF-1.3 % ReportLab Generated PDF document http://www.reportlab.com % 'BasicFonts': class PDFDictionary 1 0 obj % The standard fonts dictionary << /F1 2 0 R /F2 3 0 R /F3 4 0 R /F4 5 0 R >> endobj % 'F1': class PDFType1Font 2 0 obj % Font Helvetica << /BaseFont /Helvetica /Encoding /WinAnsiEncoding /Name /F1 /Subtype /Type1 /Type /Font >> endobj % 'F2': class PDFType1Font 3 0 obj % Font Helvetica-Bold << /BaseFont /Helvetica-Bold /Encoding /WinAnsiEncoding /Name /F2 /Subtype /Type1 /Type /Font >> endobj % 'F3': class PDFType1Font 4 0 obj % Font Helvetica-Oblique << /BaseFont /Helvetica-Oblique /Encoding /WinAnsiEncoding /Name /F3 /Subtype /Type1 /Type /Font >> endobj % 'F4': class PDFType1Font 5 0 obj % Font Times-Roman << /BaseFont /Times-Roman /Encoding /WinAnsiEncoding /Name /F4 /Subtype /Type1 /Type /Font >> endobj % 'Page1': class PDFPage 6 0 obj % Page dictionary << /Contents 13 0 R /MediaBox [ 0 0 595.2756 841.8898 ] /Parent 12 0 R /Resources << /Font 1 0 R /ProcSet [ /PDF /Text /ImageB /ImageC /ImageI ] >> /Rotate 0 /Trans << >> /Type /Page >> endobj % 'R7': class PDFCatalog 7 0 obj % Document Root << /Outlines 9 0 R /PageMode /UseNone /Pages 12 0 R /Type /Catalog >> endobj % 'R8': class PDFInfo 8 0 obj << /Author () /CreationDate (D:20090326212045-01'00') /Keywords () /Producer (pisa HTML to PDF ) /Subject () /Title (Font and Styles) >> endobj % 'R9': class PDFOutlines 9 0 obj << /Count 2 /First 10 0 R /Last 10 0 R /Type /Outlines >> endobj % 'Outline.0': class OutlineEntryObject 10 0 obj << /Count -1 /Dest [ 6 0 R /Fit ] /First 11 0 R /Last 11 0 R /Parent 9 0 R /Title (Normal smaller larger -4 -3 -2 -1 +2 +3 +4 +5 ) >> endobj % 'Outline.2.0': class OutlineEntryObject 11 0 obj << /Dest [ 6 0 R /Fit ] /Parent 10 0 R /Title (Normal smaller larger -4 -3 -2 -1 +2 +3 +4 +5 ) >> endobj % 'R12': class PDFPages 12 0 obj % page tree << /Count 1 /Kids [ 6 0 R ] /Type /Pages >> endobj % 'R13': class PDFStream 13 0 obj % page stream << /Filter [ /ASCII85Decode /FlateDecode ] /Length 1042 >> stream Gb"/%gMYJ*&:KV(Ii.\i)J/6J3u.6]M#n;VC2:bodqg"V0?&*\iTh@gie/TC1hqo$KIkgHjNMkomQ%&=i8@&)qb7L^*h6P5TFAIN:dG5/TAdK8n,;VI/uq'N&su>%:dTa!3/!8Oa7KR46F*9A9.Hn$/s.d85WN6c1'=kHc!hAVFEbGE>"XKoPVPSqM8bc/fVO3/q__-;%dTO1j2\?N&s@cbDtmPY!/(,'dM.h^p%$'jr.\G]0n0_(5h$rK;B]Z.Tb4iEG^B(R$I!(1lM;<.SclXC^CrKVpVjX[TS5/N44pFKcc"-(?"+d1,W2K-DiEGKPC>RX6,IC44'9[;3Y9eob%I[afO]2JhWH,\m-Dd$;(If&&e-j/c-2]-ISH:1MQ3amUMdg\Vk`BYVp^/r,]W!5=W\n"91"h7aM-kDAl@@`E*4"q"'(5%OQ9!KQ#]WP'H`4GW)F`n=Qimu_.-HZorsj=GP,p)>JIqQ+#A"/rG,Aiq[BF7/cJ#JWum,BH,[%0GFsDpq;O\;Q:Jq3QrpYjW`ut`:$*:ReqR\*3S5WNoOcI(Ut,?5Fendstream endobj xref 0 14 0000000000 65535 f 0000000113 00000 n 0000000245 00000 n 0000000410 00000 n 0000000585 00000 n 0000000766 00000 n 0000000933 00000 n 0000001212 00000 n 0000001347 00000 n 0000001566 00000 n 0000001690 00000 n 0000001899 00000 n 0000002048 00000 n 0000002155 00000 n trailer << /ID % ReportLab generated PDF document -- digest (http://www.reportlab.com) [(Y@\000\325\345\020Q\213M\314\300\371\201\261\335\252) (Y@\000\325\345\020Q\213M\314\300\371\201\261\335\252)] /Info 8 0 R /Root 7 0 R /Size 14 >> startxref 3315 %%EOF pisa-3.0.32/tests/samples/font-and-styles.html0000644000175000017500000000361111160170401017402 0ustar wmbwmb Font and Styles

Some common styles set by tags:

Normal Bold Italic Underlined Red Bigger Times Normal

Some common styles set by span. Should look the same as above:

Normal Bold Italic Underlined Red Bigger Times Normal

Font sizes are defined to be relative but in reality all browsers use fixed sizes. We go with the main stream. Here the regular example

Normal 1 2 3 4 5 6 7

The following is inside a <div style="font-size: 16pt">:

Normal smaller larger -4 -3 -2 -1 +2 +3 +4 +5

The following is inside an <h2>:

Normal smaller larger -4 -3 -2 -1 +2 +3 +4 +5

pisa-3.0.32/tests/samples/tables.html0000644000175000017500000000130511160170401015623 0ustar wmbwmb Font and Styles

Simple table:

a b c d
ei fgh
jn k l
m op

 

pisa-3.0.32/tests/samples/utf8.html0000644000175000017500000012071511160170401015246 0ustar wmbwmb UTF-8 Sampler

UTF-8 SAMPLER ¥ · £ · € · $ · ¢ · ₡ · ₢ · ₣ · ₤ · ₥ · ₦ · ₧ · ₨ · ₩ · ₪ · ₫ · ₭ · ₮ · ₯ Frank da Cruz The Kermit Project - Columbia University New York City fdc@columbia.edu Last update: Wed Oct 22 12:36:23 2008 [ PEACE ] [ Poetry ] [ I Can Eat Glass ] [ The Quick Brown Fox ] [ HTML Features ] [ Credits, Tools, Commentary ] UTF-8 is an ASCII-preserving encoding method for Unicode (ISO 10646), the Universal Character Set (UCS). The UCS encodes most of the world's writing systems in a single character set, allowing you to mix languages and scripts within a document without needing any tricks for switching character sets. This web page is encoded directly in UTF-8. As shown HERE, Columbia University's Kermit 95 terminal emulation software can display UTF-8 plain text in Windows 95, 98, ME, NT, XP, or 2000 when using a monospace Unicode font like Andale Mono WT J or Everson Mono Terminal, or the lesser populated Courier New, Lucida Console, or Andale Mono. C-Kermit can handle it too, if you have a Unicode display. As many languages as are representable in your font can be seen on the screen at the same time. This, however, is a Web page. Some Web browsers can handle UTF-8, some can't. And those that can might not have a sufficiently populated font to work with (some browsers might pick glyphs dynamically from multiple fonts; Netscape 6 seems to do this). CLICK HERE for a survey of Unicode fonts for Windows. The subtitle above shows currency symbols of many lands. If they don't appear as blobs, we're off to a good start! Poetry From the Anglo-Saxon Rune Poem (Rune version): ᚠᛇᚻ᛫ᛒᛦᚦ᛫ᚠᚱᚩᚠᚢᚱ᛫ᚠᛁᚱᚪ᛫ᚷᛖᚻᚹᛦᛚᚳᚢᛗ ᛋᚳᛖᚪᛚ᛫ᚦᛖᚪᚻ᛫ᛗᚪᚾᚾᚪ᛫ᚷᛖᚻᚹᛦᛚᚳ᛫ᛗᛁᚳᛚᚢᚾ᛫ᚻᛦᛏ᛫ᛞᚫᛚᚪᚾ ᚷᛁᚠ᛫ᚻᛖ᛫ᚹᛁᛚᛖ᛫ᚠᚩᚱ᛫ᛞᚱᛁᚻᛏᚾᛖ᛫ᛞᚩᛗᛖᛋ᛫ᚻᛚᛇᛏᚪᚾ᛬ From Laȝamon's Brut (The Chronicles of England, Middle English, West Midlands): An preost wes on leoden, Laȝamon was ihoten He wes Leovenaðes sone -- liðe him be Drihten. He wonede at Ernleȝe at æðelen are chirechen, Uppen Sevarne staþe, sel þar him þuhte, Onfest Radestone, þer he bock radde. (The third letter in the author's name is Yogh, missing from many fonts; CLICK HERE for another Middle English sample with some explanation of letters and encoding). From the Tagelied of Wolfram von Eschenbach (Middle High German): Sîne klâwen durh die wolken sint geslagen, er stîget ûf mit grôzer kraft, ich sih in grâwen tägelîch als er wil tagen, den tac, der im geselleschaft erwenden wil, dem werden man, den ich mit sorgen în verliez. ich bringe in hinnen, ob ich kan. sîn vil manegiu tugent michz leisten hiez. Some lines of Odysseus Elytis (Greek): Monotonic: Τη γλώσσα μου έδωσαν ελληνική το σπίτι φτωχικό στις αμμουδιές του Ομήρου. Μονάχη έγνοια η γλώσσα μου στις αμμουδιές του Ομήρου. από το Άξιον Εστί του Οδυσσέα Ελύτη Polytonic: Τὴ γλῶσσα μοῦ ἔδωσαν ἑλληνικὴ τὸ σπίτι φτωχικὸ στὶς ἀμμουδιὲς τοῦ Ὁμήρου. Μονάχη ἔγνοια ἡ γλῶσσα μου στὶς ἀμμουδιὲς τοῦ Ὁμήρου. ἀπὸ τὸ Ἄξιον ἐστί τοῦ Ὀδυσσέα Ἐλύτη The first stanza of Pushkin's Bronze Horseman (Russian): На берегу пустынных волн Стоял он, дум великих полн, И вдаль глядел. Пред ним широко Река неслася; бедный чёлн По ней стремился одиноко. По мшистым, топким берегам Чернели избы здесь и там, Приют убогого чухонца; И лес, неведомый лучам В тумане спрятанного солнца, Кругом шумел. Šota Rustaveli's Veṗxis Ṭq̇aosani, ̣︡Th, The Knight in the Tiger's Skin (Georgian): ვეპხის ტყაოსანი შოთა რუსთაველი ღმერთსი შემვედრე, ნუთუ კვლა დამხსნას სოფლისა შრომასა, ცეცხლს, წყალსა და მიწასა, ჰაერთა თანა მრომასა; მომცნეს ფრთენი და აღვფრინდე, მივჰხვდე მას ჩემსა ნდომასა, დღისით და ღამით ვჰხედვიდე მზისა ელვათა კრთომაასა. Tamil poetry of Cupiramaniya Paarathiyar, சுப்ரமணிய பாரதியார் (1882-1921): யாமறிந்த மொழிகளிலே தமிழ்மொழி போல் இனிதாவது எங்கும் காணோம், பாமரராய் விலங்குகளாய், உலகனைத்தும் இகழ்ச்சிசொலப் பான்மை கெட்டு, நாமமது தமிழரெனக் கொண்டு இங்கு வாழ்ந்திடுதல் நன்றோ? சொல்லீர்! தேமதுரத் தமிழோசை உலகமெலாம் பரவும்வகை செய்தல் வேண்டும். I Can Eat Glass And from the sublime to the ridiculous, here is a certain phrase¹ in an assortment of languages: Sanskrit: काचं शक्नोम्यत्तुम् । नोपहिनस्ति माम् ॥ Sanskrit (standard transcription): kācaṃ śaknomyattum; nopahinasti mām. Classical Greek: ὕαλον ϕαγεῖν δύναμαι· τοῦτο οὔ με βλάπτει. Greek (monotonic): Μπορώ να φάω σπασμένα γυαλιά χωρίς να πάθω τίποτα. Greek (polytonic): Μπορῶ νὰ φάω σπασμένα γυαλιὰ χωρὶς νὰ πάθω τίποτα. Etruscan: (NEEDED) Latin: Vitrum edere possum; mihi non nocet. Old French: Je puis mangier del voirre. Ne me nuit. French: Je peux manger du verre, ça ne me fait pas de mal. Provençal / Occitan: Pòdi manjar de veire, me nafrariá pas. Québécois: J'peux manger d'la vitre, ça m'fa pas mal. Walloon: Dji pou magnî do vêre, çoula m' freut nén må. Champenois: (NEEDED) Lorrain: (NEEDED) Picard: Ch'peux mingi du verre, cha m'foé mie n'ma. Corsican: (NEEDED) Jèrriais: (NEEDED) Kreyòl Ayisyen: Mwen kap manje vè, li pa blese'm. Basque: Kristala jan dezaket, ez dit minik ematen. Catalan / Català: Puc menjar vidre, que no em fa mal. Spanish: Puedo comer vidrio, no me hace daño. Aragones: Puedo minchar beire, no me'n fa mal . Galician: Eu podo xantar cristais e non cortarme. European Portuguese: Posso comer vidro, não me faz mal. Brazilian Portuguese (8): Posso comer vidro, não me machuca. Caboverdiano/Kabuverdianu: M' podê cumê vidru, ca ta maguâ-m'. Papiamentu: Ami por kome glas anto e no ta hasimi daño. Italian: Posso mangiare il vetro e non mi fa male. Milanese: Sôn bôn de magnà el véder, el me fa minga mal. Roman: Me posso magna' er vetro, e nun me fa male. Napoletano: M' pozz magna' o'vetr, e nun m' fa mal. Sicilian: Puotsu mangiari u vitru, nun mi fa mali. Venetian: Mi posso magnare el vetro, no'l me fa mae. Zeneise (Genovese): Pòsso mangiâ o veddro e o no me fà mâ. Romansch (Grischun): Jau sai mangiar vaider, senza che quai fa donn a mai. Romany / Tsigane: (NEEDED) Romanian: Pot să mănânc sticlă și ea nu mă rănește. Esperanto: Mi povas manĝi vitron, ĝi ne damaĝas min. Pictish: (NEEDED) Breton: (NEEDED) Cornish: Mý a yl dybry gwéder hag éf ny wra ow ankenya. Welsh: Dw i'n gallu bwyta gwydr, 'dyw e ddim yn gwneud dolur i mi. Manx Gaelic: Foddym gee glonney agh cha jean eh gortaghey mee. Old Irish (Ogham): ᚛᚛ᚉᚑᚅᚔᚉᚉᚔᚋ ᚔᚈᚔ ᚍᚂᚐᚅᚑ ᚅᚔᚋᚌᚓᚅᚐ᚜ Old Irish (Latin): Con·iccim ithi nglano. Ním·géna. Irish: Is féidir liom gloinne a ithe. Ní dhéanann sí dochar ar bith dom. Scottish Gaelic: S urrainn dhomh gloinne ithe; cha ghoirtich i mi. Anglo-Saxon (Runes): ᛁᚳ᛫ᛗᚨᚷ᛫ᚷᛚᚨᛋ᛫ᛖᚩᛏᚪᚾ᛫ᚩᚾᛞ᛫ᚻᛁᛏ᛫ᚾᛖ᛫ᚻᛖᚪᚱᛗᛁᚪᚧ᛫ᛗᛖ᛬ Anglo-Saxon (Latin): Ic mæg glæs eotan ond hit ne hearmiað me. Middle English: Ich canne glas eten and hit hirtiþ me nouȝt. English: I can eat glass and it doesn't hurt me. English (IPA): [aɪ kæn iːt glɑːs ænd ɪt dɐz nɒt hɜːt miː] (Received Pronunciation) English (Braille): ⠊⠀⠉⠁⠝⠀⠑⠁⠞⠀⠛⠇⠁⠎⠎⠀⠁⠝⠙⠀⠊⠞⠀⠙⠕⠑⠎⠝⠞⠀⠓⠥⠗⠞⠀⠍⠑ Jamaican: Mi kian niam glas han i neba hot mi. Lalland Scots / Doric: Ah can eat gless, it disnae hurt us. Glaswegian: (NEEDED) Gothic (4): 𐌼𐌰𐌲 𐌲𐌻𐌴𐍃 𐌹̈𐍄𐌰𐌽, 𐌽𐌹 𐌼𐌹𐍃 𐍅𐌿 𐌽𐌳𐌰𐌽 𐌱𐍂𐌹𐌲𐌲𐌹𐌸. Old Norse (Runes): ᛖᚴ ᚷᛖᛏ ᛖᛏᛁ ᚧ ᚷᛚᛖᚱ ᛘᚾ ᚦᛖᛋᛋ ᚨᚧ ᚡᛖ ᚱᚧᚨ ᛋᚨᚱ Old Norse (Latin): Ek get etið gler án þess að verða sár. Norsk / Norwegian (Nynorsk): Eg kan eta glas utan å skada meg. Norsk / Norwegian (Bokmål): Jeg kan spise glass uten å skade meg. Føroyskt / Faroese: Eg kann eta glas, skaðaleysur. Íslenska / Icelandic: Ég get etið gler án þess að meiða mig. Svenska / Swedish: Jag kan äta glas utan att skada mig. Dansk / Danish: Jeg kan spise glas, det gør ikke ondt på mig. Sønderjysk: Æ ka æe glass uhen at det go mæ naue. Frysk / Frisian: Ik kin glês ite, it docht me net sear. Nederlands / Dutch: Ik kan glas eten, het doet mij geen kwaad. Kirchröadsj/Bôchesserplat: Iech ken glaas èèse, mer 't deet miech jing pieng. Afrikaans: Ek kan glas eet, maar dit doen my nie skade nie. Lëtzebuergescht / Luxemburgish: Ech kan Glas iessen, daat deet mir nët wei. Deutsch / German: Ich kann Glas essen, ohne mir zu schaden. Ruhrdeutsch: Ich kann Glas verkasematuckeln, ohne dattet mich wat jucken tut. Langenfelder Platt: Isch kann Jlaas kimmeln, uuhne datt mich datt weh dääd. Lausitzer Mundart ("Lusatian"): Ich koann Gloos assn und doas dudd merr ni wii. Odenwälderisch: Iech konn glaasch voschbachteln ohne dass es mir ebbs daun doun dud. Sächsisch / Saxon: 'sch kann Glos essn, ohne dass'sch mer wehtue. Pfälzisch: Isch konn Glass fresse ohne dasses mer ebbes ausmache dud. Schwäbisch / Swabian: I kå Glas frässa, ond des macht mr nix! Bayrisch / Bavarian: I koh Glos esa, und es duard ma ned wei. Allemannisch: I kaun Gloos essen, es tuat ma ned weh. Schwyzerdütsch: Ich chan Glaas ässe, das tuet mir nöd weeh. Hungarian: Meg tudom enni az üveget, nem lesz tőle bajom. Suomi / Finnish: Voin syödä lasia, se ei vahingoita minua. Sami (Northern): Sáhtán borrat lása, dat ii leat bávččas. Erzian: Мон ярсан суликадо, ды зыян эйстэнзэ а ули. Northern Karelian: Mie voin syvvä lasie ta minla ei ole kipie. Southern Karelian: Minä voin syvvä st'oklua dai minule ei ole kibie. Vepsian: (NEEDED) Votian: (NEEDED) Livonian: (NEEDED) Estonian: Ma võin klaasi süüa, see ei tee mulle midagi. Latvian: Es varu ēst stiklu, tas man nekaitē. Lithuanian: Aš galiu valgyti stiklą ir jis manęs nežeidžia Old Prussian: (NEEDED) Sorbian (Wendish): (NEEDED) Czech: Mohu jíst sklo, neublíží mi. Slovak: Môžem jesť sklo. Nezraní ma. Polska / Polish: Mogę jeść szkło i mi nie szkodzi. Slovenian: Lahko jem steklo, ne da bi mi škodovalo. Croatian: Ja mogu jesti staklo i ne boli me. Serbian (Latin): Ja mogu da jedem staklo. Serbian (Cyrillic): Ја могу да једем стакло. Macedonian: Можам да јадам стакло, а не ме штета. Russian: Я могу есть стекло, оно мне не вредит. Belarusian (Cyrillic): Я магу есці шкло, яно мне не шкодзіць. Belarusian (Lacinka): Ja mahu jeści škło, jano mne ne škodzić. Ukrainian: Я можу їсти шкло, й воно мені не пошкодить. Bulgarian: Мога да ям стъкло, то не ми вреди. Georgian: მინას ვჭამ და არა მტკივა. Armenian: Կրնամ ապակի ուտել և ինծի անհանգիստ չըներ։ Albanian: Unë mund të ha qelq dhe nuk më gjen gjë. Turkish: Cam yiyebilirim, bana zararı dokunmaz. Turkish (Ottoman): جام ييه بلورم بڭا ضررى طوقونمز Bangla / Bengali: আমি কাঁচ খেতে পারি, তাতে আমার কোনো ক্ষতি হয় না। Marathi: मी काच खाऊ शकतो, मला ते दुखत नाही. Hindi: मैं काँच खा सकता हूँ और मुझे उससे कोई चोट नहीं पहुंचती. Tamil: நான் கண்ணாடி சாப்பிடுவேன், அதனால் எனக்கு ஒரு கேடும் வராது. Urdu(2): میں کانچ کھا سکتا ہوں اور مجھے تکلیف نہیں ہوتی ۔ Pashto(2): زه شيشه خوړلې شم، هغه ما نه خوږوي Farsi / Persian: .من می توانم بدونِ احساس درد شيشه بخورم Arabic(2): أنا قادر على أكل الزجاج و هذا لا يؤلمني. Aramaic: (NEEDED) Maltese: Nista' niekol il-ħġieġ u ma jagħmilli xejn. Hebrew(2): אני יכול לאכול זכוכית וזה לא מזיק לי. Yiddish(2): איך קען עסן גלאָז און עס טוט מיר נישט װײ. Judeo-Arabic: (NEEDED) Ladino: (NEEDED) Gǝʼǝz: (NEEDED) Amharic: (NEEDED) Twi: Metumi awe tumpan, ɜnyɜ me hwee. Hausa (Latin): Inā iya taunar gilāshi kuma in gamā lāfiyā. Hausa (Ajami) (2): إِنا إِىَ تَونَر غِلَاشِ كُمَ إِن غَمَا لَافِىَا Yoruba(3): Mo lè je̩ dígí, kò ní pa mí lára. Lingala: Nakokí kolíya biténi bya milungi, ekosála ngáí mabé tɛ́. (Ki)Swahili: Naweza kula bilauri na sikunyui. Malay: Saya boleh makan kaca dan ia tidak mencederakan saya. Tagalog: Kaya kong kumain nang bubog at hindi ako masaktan. Chamorro: Siña yo' chumocho krestat, ti ha na'lalamen yo'. Javanese: Aku isa mangan beling tanpa lara. Burmese: က္ယ္ဝန္‌တော္‌၊က္ယ္ဝန္‌မ မ္ယက္‌စားနုိင္‌သည္‌။ ၎က္ရောင္‌့ ထိခုိက္‌မ္ဟု မရ္ဟိပာ။ (9) Vietnamese (quốc ngữ): Tôi có thể ăn thủy tinh mà không hại gì. Vietnamese (nôm) (4): 些 𣎏 世 咹 水 晶 𦓡 空 𣎏 害 咦 Khmer: ខ្ញុំអាចញុំកញ្ចក់បាន ដោយគ្មានបញ្ហារ Lao: ຂອ້ຍກິນແກ້ວໄດ້ໂດຍທີ່ມັນບໍ່ໄດ້ເຮັດໃຫ້ຂອ້ຍເຈັບ. Thai: ฉันกินกระจกได้ แต่มันไม่ทำให้ฉันเจ็บ Mongolian (Cyrillic): Би шил идэй чадна, надад хортой биш Mongolian (Classic) (5): ᠪᠢ ᠰᠢᠯᠢ ᠢᠳᠡᠶᠦ ᠴᠢᠳᠠᠨᠠ ᠂ ᠨᠠᠳᠤᠷ ᠬᠣᠤᠷᠠᠳᠠᠢ ᠪᠢᠰᠢ Dzongkha: (NEEDED) Nepali: (NEEDED) Tibetan: ཤེལ་སྒོ་ཟ་ནས་ང་ན་གི་མ་རེད། Chinese: 我能吞下玻璃而不伤身体。 Chinese (Traditional): 我能吞下玻璃而不傷身體。 Taiwanese(6): Góa ē-tàng chia̍h po-lê, mā bē tio̍h-siong. Japanese: 私はガラスを食べられます。それは私を傷つけません。 Korean: 나는 유리를 먹을 수 있어요. 그래도 아프지 않아요 Bislama: Mi save kakae glas, hemi no save katem mi. Hawaiian: Hiki iaʻu ke ʻai i ke aniani; ʻaʻole nō lā au e ʻeha. Marquesan: E koʻana e kai i te karahi, mea ʻā, ʻaʻe hauhau. Chinook Jargon: Naika məkmək kakshət labutay, pi weyk ukuk munk-sik nay. Navajo: Tsésǫʼ yishą́ągo bííníshghah dóó doo shił neezgai da. Cherokee (and Cree, Ojibwa, Inuktitut, Náhuatl, Quechua, and other American languages): (NEEDED) Garifuna: (NEEDED) Gullah: (NEEDED) Lojban: mi kakne le nu citka le blaci .iku'i le se go'i na xrani mi Nórdicg: Ljœr ye caudran créneþ ý jor cẃran. (Additions, corrections, completions, gratefully accepted.) For testing purposes, some of these are repeated in a monospace font . . . Euro Symbol: €. Greek: Μπορώ να φάω σπασμένα γυαλιά χωρίς να πάθω τίποτα. Íslenska / Icelandic: Ég get etið gler án þess að meiða mig. Polish: Mogę jeść szkło, i mi nie szkodzi. Romanian: Pot să mănânc sticlă și ea nu mă rănește. Ukrainian: Я можу їсти шкло, й воно мені не пошкодить. Armenian: Կրնամ ապակի ուտել և ինծի անհանգիստ չըներ։ Georgian: მინას ვჭამ და არა მტკივა. Hindi: मैं काँच खा सकता हूँ, मुझे उस से कोई पीडा नहीं होती. Hebrew(2): אני יכול לאכול זכוכית וזה לא מזיק לי. Yiddish(2): איך קען עסן גלאָז און עס טוט מיר נישט װײ. Arabic(2): أنا قادر على أكل الزجاج و هذا لا يؤلمني. Japanese: 私はガラスを食べられます。それは私を傷つけません。 Thai: ฉันกินกระจกได้ แต่มันไม่ทำให้ฉันเจ็บ Notes: The "I can eat glass" phrase and initial translations (about 30 of them) were borrowed from Ethan Mollick's I Can Eat Glass page (which disappeared on or about June 2004) and converted to UTF-8. Since Ethan's original page is gone, I should mention that his purpose was to offer travelers a phrase they could use in any country that would command a certain kind of respect, or at least get attention. See Credits for the many additional contributions since then. When submitting new entries, the word "hurt" (if you have a choice) is used in the sense of "cause harm", "do damage", or "bother", rather than "inflict pain" or "make sad". In this vein Otto Stolz comments (as do others further down; personally I think it's better for the purpose of this page to have extra entries and/or to show a greater repertoire of characters than it is to enforce a strict interpretation of the word "hurt"!): This is the meaning I have translated to the Swabian dialect. However, I just have noticed that most of the German variants translate the "inflict pain" meaning. The German example should read: "Ich kann Glas essen ohne mir zu schaden." rather than: "Ich kann Glas essen, ohne mir weh zu tun." (The comma fell victim to the 1996 orthographic reform, cf. http://www.ids-mannheim.de/reform/e3-1.html#P76. You may wish to contact the contributors of the following translations to correct them: Lëtzebuergescht / Luxemburgish: Ech kan Glas iessen, daat deet mir nët wei. Lausitzer Mundart ("Lusatian"): Ich koann Gloos assn und doas dudd merr ni wii. Sächsisch / Saxon: 'sch kann Glos essn, ohne dass'sch mer wehtue. Bayrisch / Bavarian: I koh Glos esa, und es duard ma ned wei. Allemannisch: I kaun Gloos essen, es tuat ma ned weh. Schwyzerdütsch: Ich chan Glaas ässe, das tuet mir nöd weeh. In contrast, I deem the following translations *alright*: Ruhrdeutsch: Ich kann Glas verkasematuckeln, ohne dattet mich wat jucken tut. Pfälzisch: Isch konn Glass fresse ohne dasses mer ebbes ausmache dud. Schwäbisch / Swabian: I kå Glas frässa, ond des macht mr nix! (However, you could remove the commas, on account of http://www.ids-mannheim.de/reform/e3-1.html#P76 and http://www.ids-mannheim.de/reform/e3-1.html#P72, respectively.) I guess, also these examples translate the wrong sense of "hurt", though I do not know these languages well enough to assert them definitely: Nederlands / Dutch: Ik kan glas eten; het doet mij geen pijn. (This one has been changed) Kirchröadsj/Bôchesserplat: Iech ken glaas èèse, mer 't deet miech jing pieng. In the Romanic languages, the variations on "fa male" (it) are probably wrong, whilst the variations on "hace daño" (es) and "damaĝas" (Esperanto) are probably correct; "nocet" (la) is definitely right. The northern Germanic variants of "skada" are probably right, as are the Slavic variants of "škodi/шкоди" (se); however the Slavic variants of " boli" (hv) are probably wrong, as "bolena" means "pain/ache", IIRC. That was from July 2004. In December 2007, Otto writes again: Hello Frank, in days of yore, I had written: > "Ich kann Glas essen ohne mir zu schaden." > (The comma fell victim to the 1996 orthographic reform, cf. http://www.ids-mannheim.de/reform/e3-1.html#P76. The latest revision (2006) of the official German orthography has revived the comma around infinitive clauses commencing with ohne, or 5 other conjunctions, or depending from a noun or from an announcing demonstrative (http://www.ids-mannheim.de/reform/regeln2006.pdf, §75). So, it's again: Ich kann Glas essen, ohne mir zu schaden. Best wishes, Otto Stolz The numbering of the samples is arbitrary, done only to keep track of how many there are, and can change any time a new entry is added. The arrangement is also arbitrary but with some attempt to group related examples together. Note: All languages not listed are wanted, not just the ones that say (NEEDED). Correct right-to-left display of these languages depends on the capabilities of your browser. The period should appear on the left. In the monospace Yiddish example, the Yiddish digraphs should occupy one character cell. Yoruba: The third word is Latin letter small 'j' followed by small 'e' with U+0329, Combining Vertical Line Below. This displays correctly only if your Unicode font includes the U+0329 glyph and your browser supports combining diacritical marks. The Lingala and Indic examples also include combining sequences. Includes Unicode 3.1 (or later) characters beyond Plane 0. The Classic Mongolian example should be vertical, top-to-bottom and left-to-right. But such display is almost impossible. Also no font yet exists which provides the proper ligatures and positional variants for the characters of this script, which works somewhat like Arabic. Taiwanese is also known as Holo or Hoklo, and is related to Southern Min dialects such as Amoy. Contributed by Henry H. Tan-Tenn, who comments, "The above is the romanized version, in a script current among Taiwanese Christians since the mid-19th century. It was invented by British missionaries and saw use in hundreds of published works, mostly of a religious nature. Most Taiwanese did not know Chinese characters then, or at least not well enough to read. More to the point, though, a written standard using Chinese characters has never developed, so a significant minority of words are represented with different candidate characters, depending on one's personal preference or etymological theory. In this sentence, for example, "-tàng", "chia̍h", "mā" and "bē" are problematic using Chinese characters. "Góa" (I/me) and "po-lê" (glass) are as written in other Sinitic languages (e.g. Mandarin, Hakka)." Wagner Amaral of Pinese & Amaral Associados notes that the Brazilian Portuguese sentence for "I can eat glass" should be identical to the Portuguese one, as the word "machuca" means "inflict pain", or rather "injuries". The words "faz mal" would more correctly translate as "cause harm". Burmese: In English the first person pronoun "I" stands for both genders, male and female. In Burmese (except in the central part of Burma) kyundaw (က္ယ္ဝန္‌တော္‌) for male and kyanma (က္ယ္ဝန္‌မ) for female. Using here a fully-compliant Unicode Burmese font -- sadly one and only Padauk Graphite font exists -- rendering using graphite engine. CLICK HERE to test Burmese characters. The Quick Brown Fox The "I can eat glass" sentences do not necessarily show off the orthography of each language to best advantage. In many alphabetic written languages it is possible to include all (or most) letters (or "special" characters) in a single (often nonsense) pangram. These were traditionally used in typewriter instruction; now they are useful for stress-testing computer fonts and keyboard input methods. Here are a few examples (SEND MORE): English: The quick brown fox jumps over the lazy dog. Jamaican: Chruu, a kwik di kwik brong fox a jomp huova di liezi daag de, yu no siit? Irish: "An ḃfuil do ċroí ag bualaḋ ó ḟaitíos an ġrá a ṁeall lena ṗóg éada ó ṡlí do leasa ṫú?" "D'ḟuascail Íosa Úrṁac na hÓiġe Beannaiṫe pór Éava agus Áḋaiṁ." Dutch: Pa's wijze lynx bezag vroom het fikse aquaduct. German: Falsches Üben von Xylophonmusik quält jeden größeren Zwerg. (1) German: Im finſteren Jagdſchloß am offenen Felsquellwaſſer patzte der affig-flatterhafte kauzig-höf‌liche Bäcker über ſeinem verſifften kniffligen C-Xylophon. (2) Swedish: Flygande bäckasiner söka strax hwila på mjuka tuvor. Icelandic: Sævör grét áðan því úlpan var ónýt. Polish: Pchnąć w tę łódź jeża lub ośm skrzyń fig. Czech: Příliš žluťoučký kůň úpěl ďábelské kódy. Slovak: Starý kôň na hŕbe kníh žuje tíško povädnuté ruže, na stĺpe sa ďateľ učí kvákať novú ódu o živote. Greek (monotonic): ξεσκεπάζω την ψυχοφθόρα βδελυγμία Greek (polytonic): ξεσκεπάζω τὴν ψυχοφθόρα βδελυγμία Russian: Съешь же ещё этих мягких французских булок да выпей чаю. Russian: В чащах юга жил-был цитрус? Да, но фальшивый экземпляр! ёъ. Bulgarian: Жълтата дюля беше щастлива, че пухът, който цъфна, замръзна като гьон. Sami (Northern): Vuol Ruoŧa geđggiid leat máŋga luosa ja čuovžža. Hungarian: Árvíztűrő tükörfúrógép. Spanish: El pingüino Wenceslao hizo kilómetros bajo exhaustiva lluvia y frío, añoraba a su querido cachorro. Portuguese: O próximo vôo à noite sobre o Atlântico, põe freqüentemente o único médico. (3) French: Les naïfs ægithales hâtifs pondant à Noël où il gèle sont sûrs d'être déçus et de voir leurs drôles d'œufs abîmés. Esperanto: Eĥoŝanĝo ĉiuĵaŭde. Hebrew: זה כיף סתם לשמוע איך תנצח קרפד עץ טוב בגן. Japanese (Hiragana): いろはにほへど ちりぬるを わがよたれぞ つねならむ うゐのおくやま けふこえて あさきゆめみじ ゑひもせず (4) Notes: Other phrases commonly used in Germany include: "Ein wackerer Bayer vertilgt ja bequem zwo Pfund Kalbshaxe" and, more recently, "Franz jagt im komplett verwahrlosten Taxi quer durch Bayern", but both lack umlauts and esszet. Previously, going for the shortest sentence that has all the umlauts and special characters, I had "Grüße aus Bärenhöfe (und Óechtringen)!" Acute accents are not used in native German words, so I was surprised to discover "Óechtringen" in the Deutsche Bundespost Postleitzahlenbuch: It's a small village in eastern Lower Saxony. The "oe" in this case turns out to be the Lower Saxon "lengthening e" (Dehnungs-e), which makes the previous vowel long (used in a number of Lower Saxon place names such as Soest and Itzehoe), not the "e" that indicates umlaut of the preceding vowel. Many thanks to the Óechtringen-Namenschreibungsuntersuchungskomitee (Alex Bochannek, Manfred Erren, Asmus Freytag, Christoph Päper, plus Werner Lemberg who serves as Óechtringen-Namenschreibungsuntersuchungskomiteerechtschreibungsprüfer) for their relentless pursuit of the facts in this case. Conclusion: the accent almost certainly does not belong on this (or any other native German) word, but neither can it be dismissed as dirt on the page. To add to the mystery, it has been reported that other copies of the same edition of the PLZB do not show the accent! UPDATE (March 2006): David Krings was intrigued enough by this report to contact the mayor of Ebstorf, of which Oechtringen is a borough, who responded: Sehr geehrter Mr. Krings, wenn Oechtringen irgendwo mit einem Akzent auf dem O geschrieben wurde, dann kann das nur ein Fehldruck sein. Die offizielle Schreibweise lautet jedenfalls „Oechtringen“. Mit freundlichen Grüssen Der Samtgemeindebürgermeister i.A. Lothar Jessel From Karl Pentzlin (Kochel am See, Bavaria, Germany): "This German phrase is suited for display by a Fraktur (broken letter) font. It contains: all common three-letter ligatures: ffi ffl fft and all two-letter ligatures required by the Duden for Fraktur typesetting: ch ck ff fi fl ft ll ſch ſi ſſ ſt tz (all in a manner such they are not part of a three-letter ligature), one example of f-l where German typesetting rules prohibit ligating (marked by a ZWNJ), and all German letters a...z, ä,ö,ü,ß, ſ [long s] (all in a manner such that they are not part of a two-letter Fraktur ligature)." Otto Stolz notes that "'Schloß' is now spelled 'Schloss', in contrast to 'größer' (example 4) which has kept its 'ß'. Fraktur has been banned from general use, in 1942, and long-s (ſ) has ceased to be used with Antiqua (Roman) even earlier (the latest Antiqua-ſ I have seen is from 1913, but then I am no expert, so there may well be a later instance." Later Otto confirms the latter theory, "Now I've run across a book “Deutsche Rechtschreibung” (edited by Lutz Mackensen) from 1954 (my reprint is from 1956) that has kept the Antiqua-ſ in its dictionary part (but neither in the preface nor in the appendix)." Diaeresis is not used in Iberian Portuguese. From Yurio Miyazawa: "This poetry contains all the sounds in the Japanese language and used to be the first thing for children to learn in their Japanese class. The Hiragana version is particularly neat because it covers every character in the phonetic Hiragana character set." Yurio also sent the Kanji version: 色は匂へど 散りぬるを 我が世誰ぞ 常ならむ 有為の奥山 今日越えて 浅き夢見じ 酔ひもせず Accented Cyrillic: (This section contributed by Vladimir Marinov.) In Bulgarian it is desirable, customary, or in some cases required to write accents over vowels. Unfortunately, no computer character sets contain the full repertoire of accented Cyrillic letters. With Unicode, however, it is possible to combine any Cyrillic letter with any combining accent. The appearance of the result depends on the font and the rendering engine. Here are two examples. Той видя бялата коса́ по главата и́ и ко́са на рамото и́, и ре́че да и́ рече́: "Пара́та по́ па́ри от па́рата, не ща пари́!", но си поми́сли: "Хей, помисли́ си! А́ и́ река, а́ е скочила в тази река, която щеше да тече́, а не те́че." По пъ́тя пъту́ват кю́рди и югославя́ни. HTML Features Here is the Russian alphabet (uppercase only) coded in three different ways, which should look identical: АБВГДЕЖЗИЙКЛМНОПРСТУФХЦЧШЩЪЫЬЭЮЯ (Literal UTF-8) АБВГДЕЖЗИЙКЛМНОПРСТУФХЦЧШЩЪЫЬЭЮЯ (Decimal numeric character reference) АБВГДЕЖЗИЙКЛМНОПРСТУФХЦЧШЩЪЫЬЭЮЯ (Hexadecimal numeric character reference) In another test, we use HTML language tags to distinguish Bulgarian, Russian, and Serbian, which have different italic forms for lowercase б, г, д, п, and/or т: Bulgarian: [ бгдпт ] [ бгдпт ] Мога да ям стъкло и не ме боли. Russian: [ бгдпт ] [ бгдпт ] Я могу есть стекло, это мне не вредит. Serbian: [ бгдпт ] [ бгдпт ] Могу јести стакло а да ми не шкоди. Credits, Tools, and Commentary Credits: The "I can eat glass" phrase and the initial collection of translations: Ethan Mollick. Transcription / conversion to UTF-8: Frank da Cruz. Albanian: Sindi Keesan. Afrikaans: Johan Fourie, Kevin Poalses. Anglo Saxon: Frank da Cruz. Arabic: Najib Tounsi. Armenian: Vaçe Kundakçı. Belarusian: Alexey Chernyak. Bengali: Somnath Purkayastha, Deepayan Sarkar. Bislama: Dan McGarry. Braille: Frank da Cruz. Bulgarian: Sindi Keesan, Guentcho Skordev, Vladimir Marinov. Burmese: "cetanapa". Cabo Verde Creole: Cláudio Alexandre Duarte. Catalán: Jordi Bancells. Chinese: Jack Soo, Wong Pui Lam. Chinook Jargon: David Robertson. Cornish: Chris Stephens. Croatian: Marjan Baće. Czech: Stanislav Pecha, Radovan Garabík. Dutch: Peter Gotink. Pim Blokland, Rob Daniel, Rob de Wit. Erzian: Jack Rueter. Esperanto: Franko Luin, Radovan Garabík. Estonian: Meelis Roos. Faroese: Jón Gaasedal. Farsi/Persian: Payam Elahi. Finnish: Sampsa Toivanen. French: Luc Carissimo, Anne Colin du Terrail, Sean M. Burke. Galician: Laura Probaos. Georgian: Giorgi Lebanidze. German: Christoph Päper, Otto Stolz, Karl Pentzlin, David Krings, Frank da Cruz. Gothic: Aurélien Coudurier. Greek: Ariel Glenn, Constantine Stathopoulos, Siva Nataraja, Christos Georgiou. Hebrew: Jonathan Rosenne, Tal Barnea. Hausa: Malami Buba, Tom Gewecke. Hawaiian: na Hauʻoli Motta, Anela de Rego, Kaliko Trapp. Hindi: Shirish Kalele, Nitin Dahra. Hungarian: András Rácz, Mark Holczhammer. Icelandic: Andrés Magnússon, Sveinn Baldursson. International Phonetic Alphabet (IPA): Siva Nataraja / Vincent Ramos. Irish: Michael Everson, Marion Gunn, James Kass, Curtis Clark. Italian: Thomas De Bellis. Jamaican: Stephen J. Cherin. Japanese: Makoto Takahashi, Yurio Miyazawa. Karelian: Aleksandr Semakov. Khmer: Tola Sann. Kirchröadsj: Roger Stoffers. Kreyòl: Sean M. Burke. Korean: Jungshik Shin. Langenfelder Platt: David Krings. Lao: Tola Sann. Lëtzebuergescht: Stefaan Eeckels. Lingala: Denis Moyogo Jacquerye (Nkóta ya Kɔ́ngɔ míbalé ). (Nkóta ya Kɔ́ngɔ míbal Lithuanian: Gediminas Grigas. Lojban: Edward Cherlin. Lusatian: Ronald Schaffhirt. Macedonian: Sindi Keesan. Malay: Zarina Mustapha. Maltese: Kenneth Joseph Vella. Manx: Éanna Ó Brádaigh. Marathi: Shirish Kalele. Marquesan: Kaliko Trapp. Middle English: Frank da Cruz. Milanese: Marco Cimarosti. Mongolian: Tom Gewecke. Napoletano: Diego Quintano. Navajo: Tom Gewecke. Nórdicg: Yẃlyan Rott. Norwegian: Herman Ranes. Odenwälderisch: Alexander Heß. Old Irish: Michael Everson. Old Norse: Andrés Magnússon. Papiamentu: Bianca and Denise Zanardi. Pashto: N.R. Liwal. Pfälzisch: Dr. Johannes Sander. Picard: Philippe Mennecier. Polish: Juliusz Chroboczek, Paweł Przeradowski. Portuguese: "Cláudio" Alexandre Duarte, Bianca and Denise Zanardi, Pedro Palhoto Matos, Wagner Amaral. Québécois: Laurent Detillieux. Roman: Pierpaolo Bernardi. Romanian: Juliusz Chroboczek, Ionel Mugurel. Romansch: Alexandre Suter. Ruhrdeutsch: "Timwi". Russian: Alexey Chernyak, Serge Nesterovitch. Sami: Anne Colin du Terrail, Luc Carissimo. Sanskrit: Siva Nataraja / Vincent Ramos. Sächsisch: André Müller. Schwäbisch: Otto Stolz. Scots: Jonathan Riddell. Serbian: Sindi Keesan, Ranko Narancic, Boris Daljevic, Szilvia Csorba, O. Dag. Slovak: G. Adam Stanislav, Radovan Garabík. Slovenian: Albert Kolar. Spanish: Aleida Muñoz, Laura Probaos. Swahili: Ronald Schaffhirt. Swedish: Christian Rose, Bengt Larsson. Taiwanese: Henry H. Tan-Tenn. Tagalog: Jim Soliven. Tamil: Vasee Vaseeharan. Tibetan: D. Germano, Tom Gewecke. Thai: Alan Wood's wife. Turkish: Vaçe Kundakçı, Tom Gewecke, Merlign Olnon. Ukrainian: Michael Zajac. Urdu: Mustafa Ali. Vietnamese: Dixon Au, [James] Đỗ Bá Phước 杜 伯 福. Walloon: Pablo Saratxaga. Welsh: Geiriadur Prifysgol Cymru (Andrew). Yiddish: Mark David. Zeneise: Angelo Pavese. Tools Used to Create This Web Page: The UTF8-aware Kermit 95 terminal emulator on Windows, to a Unix host with the EMACS text editor. Kermit 95 displays UTF-8 and also allows keyboard entry of arbitrary Unicode BMP characters as 4 hex digits, as shown HERE. Hex codes for Unicode values can be found in The Unicode Standard (recommended) and the online code charts. When submissions arrive by email encoded in some other character set (Latin-1, Latin-2, KOI, various PC code pages, JEUC, etc), I use the TRANSLATE command of C-Kermit on the Unix host (where I read my mail) to convert the character set to UTF-8 (I could also use Kermit 95 for this; it has the same TRANSLATE command). That's it -- no "Web authoring" tools, no locales, no "smart" anything. It's just plain text, nothing more. By the way, there's nothing special about EMACS -- any text editor will do, providing it allows entry of arbitrary 8-bit bytes as text, including the 0x80-0x9F "C1" range. EMACS 21.1 actually supports UTF-8; earlier versions don't know about it and display the octal codes; either way is OK for this purpose. Commentary: Date: Wed, 27 Feb 2002 13:21:59 +0100 From: "Bruno DEDOMINICIS" <b.dedominicis@cite-sciences.fr> Subject: Je peux manger du verre, cela ne me fait pas mal. I just found out your website and it makes me feel like proposing an interpretation of the choice of this peculiar phrase. Glass is transparent and can hurt as everyone knows. The relation between people and civilisations is sometimes effusional and more often rude. The concept of breaking frontiers through globalization, in a way, is also an attempt to deny any difference. Isn't "transparency" the flag of modernity? Nothing should be hidden any more, authority is obsolete, and the new powers are supposed to reign through loving and smiling and no more through coercion... Eating glass without pain sounds like a very nice metaphor of this attempt. That is, frontiers should become glass transparent first, and be denied by incorporating them. On the reverse, it shows that through globalization, frontiers undergo a process of displacement, that is, when they are not any more speakable, they become repressed from the speech and are therefore incorporated and might become painful symptoms, as for example what happens when one tries to eat glass. The frontiers that used to separate bodies one from another tend to divide bodies from within and make them suffer.... The chosen phrase then appears as a denial of the symptom that might result from the destitution of traditional frontiers. Best, Bruno De Dominicis, Paris, France Other Unicode pages onsite: Peace in All Languages Frank's Compulsive Guide to Postal Addresses (especially the Index) Representing Middle English on the Web with UTF-8 The Kermit Bibliography (in UTF-8) Interchange of Non-English Computer Text (UTF-8 math and box-drawing) Unicode Table (in UTF-8) Unicode samplers and resources offsite: Unicode Code ConverterUnicode Code Conversion (converts among different Unicode encoding forms and notations). Michael Everson's Bibliography of Typography and Scripts Does your browser support Unicode English? (James Kass) I don't know, I only work here Anyone can be provincial! Transcriptions of "Unicode" Example Unicode Usage for Business Applications UTF-8 and Unicode FAQ for Unix/Linux Unicode fonts: Code 2000 (James Kass) Unicode Fonts for Windows Computers (Alan Wood) Unicode Fonts and Tools for X11 (Markus Kuhn) Everson Mono (Michael Everson) Agfa Monotype [ Kermit 95 ] [ K95 Screen Shots ] [ C-Kermit ] [ Kermit Home ] [ Display Problems? ] [ The Unicode Consortium ] UTF-8 Sampler / The Kermit Project / Columbia University / kermit@columbia.edu

pisa-3.0.32/tests/samples/font/0000755000175000017500000000000011334107025014437 5ustar wmbwmbpisa-3.0.32/tests/samples/tables.pdf0000644000175000017500000000525111162761636015456 0ustar wmbwmb%PDF-1.3 % ReportLab Generated PDF document http://www.reportlab.com % 'BasicFonts': class PDFDictionary 1 0 obj % The standard fonts dictionary << /F1 2 0 R /F2 3 0 R >> endobj % 'F1': class PDFType1Font 2 0 obj % Font Helvetica << /BaseFont /Helvetica /Encoding /WinAnsiEncoding /Name /F1 /Subtype /Type1 /Type /Font >> endobj % 'F2': class PDFType1Font 3 0 obj % Font Times-Roman << /BaseFont /Times-Roman /Encoding /WinAnsiEncoding /Name /F2 /Subtype /Type1 /Type /Font >> endobj % 'Page1': class PDFPage 4 0 obj % Page dictionary << /Contents 8 0 R /MediaBox [ 0 0 595.2756 841.8898 ] /Parent 7 0 R /Resources << /Font 1 0 R /ProcSet [ /PDF /Text /ImageB /ImageC /ImageI ] >> /Rotate 0 /Trans << >> /Type /Page >> endobj % 'R5': class PDFCatalog 5 0 obj % Document Root << /Outlines 9 0 R /PageMode /UseNone /Pages 7 0 R /Type /Catalog >> endobj % 'R6': class PDFInfo 6 0 obj << /Author () /CreationDate (D:20090326212045-01'00') /Keywords () /Producer (pisa HTML to PDF ) /Subject () /Title (Font and Styles) >> endobj % 'R7': class PDFPages 7 0 obj % page tree << /Count 1 /Kids [ 4 0 R ] /Type /Pages >> endobj % 'R8': class PDFStream 8 0 obj % page stream << /Filter [ /ASCII85Decode /FlateDecode ] /Length 761 >> stream Gau0CbAQ&g&A/Ct5O>W]:kio93nN@;t:8E@DIE8RG""ig9_\nqdT!lZ%8A_Y&5+2%eUa-,SKC7n?"=$^LaZln#RaQ6\NreK;"P!Kb0R,!F!Qn;\h"rWe;PetjmlcWCh_,lrb.oIgm/Pc]t'Ncff5Un7Nh=rB+l^EMI'erlXh#Lr%4mTjW<*>rT7,;XnJM24Cc.d+>n+R@)eb'*q>Gs2\d\Sn3*0"3#I>mM=SW0[S%ZJ!]nQtOoK!NnWhYk-VG3cE8@cauCutbi?f]kOi]G%u26Dfr`"HIXQ-!IN5LOUTIdB]J&+(*SgIK[.0N$/HG#lX+q)Ke$ZPt6]TahgLo.N5-E.`4FDW5[0,'"T4(7b=J`@>p#7Y@o1K7e8)^g!=tJ8#P#Sr0nGIm0ks6_o+Xpendstream endobj % 'R9': class PDFOutlines 9 0 obj << /Count 0 /Type /Outlines >> endobj xref 0 10 0000000000 65535 f 0000000113 00000 n 0000000221 00000 n 0000000386 00000 n 0000000553 00000 n 0000000830 00000 n 0000000964 00000 n 0000001180 00000 n 0000001285 00000 n 0000002190 00000 n trailer << /ID % ReportLab generated PDF document -- digest (http://www.reportlab.com) [(Y@\000\325\345\020Q\213M\314\300\371\201\261\335\252) (Y@\000\325\345\020Q\213M\314\300\371\201\261\335\252)] /Info 6 0 R /Root 5 0 R /Size 10 >> startxref 2241 %%EOF pisa-3.0.32/tests/samples/images.html0000644000175000017500000001070611160170401015623 0ustar wmbwmb

Images

Here we are testing if the floating of images work and the inline feature.

Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum. Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum. Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.

Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum. Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum. Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.

Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum. Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum. Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.

pisa-3.0.32/tests/runtests.py0000644000175000017500000000136211160170401014263 0ustar wmbwmbimport sys import os import glob import unittest #Allow us to import the parent module os.chdir(os.path.split(os.path.abspath(__file__))[0]) sys.path.insert(0, os.path.abspath(os.curdir)) sys.path.insert(0, os.path.abspath(os.pardir)) # sys.path.insert(0, os.path.join(os.path.abspath(os.pardir), "src")) def buildTestSuite(): suite = unittest.TestSuite() for testcase in glob.glob('test_*.py'): module = os.path.splitext(testcase)[0] suite.addTest(__import__(module).buildTestSuite()) return suite def main(): results = unittest.TextTestRunner().run(buildTestSuite()) return results if __name__ == "__main__": results = main() if not results.wasSuccessful(): sys.exit(1) pisa-3.0.32/tests/test_uri.py0000644000175000017500000001404511160170401014234 0ustar wmbwmbimport unittest from sx.pisa3.pisa_util import * _datauri = """data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAEYAAACJBAMAAABjvlPWAAAAMFBMVEUAAAAKBgQYFA8tJh5MQjZ3 YEWPgHGynIK+oXvHsJbRvanZ0Mbv6+b48+//+/f///9agwt8AAAM7UlEQVR4XnWXXWwbV3bHZ+Jg gb7NJUdy06dQEmW3AYrQIilFAQKP+CGLSRcQxSEpKTVg8UO0sjVgU7JsuTWQSKQuuS91JEsz46KA VxLFOUz2YbONY07WQLcfAYqFFpst+oFNuECDbNHYvHwp0JeC6rkzkuwizhEgCTM//s//nnvOASgc PjcY+8L6Rf9rX7YY6x4+j+kyZP4lVKiY+gcfICQ8D+GRq1TBrFTyv2Tsu5jfTeuGYVlQ+tPW85hD W6aqVaFhNekbre/QaX2RzHkryFj1RfZdOv8w2JfON7lQ8dG3mK5j5y/ToeuBe5ZlNdcutoXnmWFP lPFSKP5DztRGv8UwG/rvU6myEnCYKHuOTpuxv/VPpdcLtMkPluw8R6fFHr/64mKQFrIAlkWTT57n 5zeL0kAgo6eW5g2ruZf89rkwV1YOjSihpWRkKgZQTKLnZ993uujmbwbG1YDH5XO7fL2R0rkgE54x whO1/k4NbqXVYcUr57f1ostD3j5hnNK1rQfbUwuwpXrrlNJ5gGtE7jxlEGh/c130Z6cBthKReqlQ ilzPZ/1R9gyDsUNEPwWA8qQ7eim4EfER9+WLnf/PXJJIhDaAZpFZcy8R4nKF/ph1nvXzXx5C0lUA mvPJyTK5vLzsk04/Os7VOex02+xfvUOkH5m5gZfdarlnjPSv6I+6yBx3ebvTuKsu+wtV0DNToqyW A2vhAuQZvhJOzHwzPFXYTwLUaVESXGqBUoC9FBbtiMH6dncmAmlzaqKp0RKRxP4kpeG88ma7c8wg wrLGzezo/qIFtEYkQQyUCu6bxexfs6cM+/dxrbK2YjU/aOrmJBEJ6etzDb129fYJ02HsIzW4nAjf tMBKwZokEX84HAG49BfssHPiOZMYCKXMpGVBrnDXI8qg69dv1Yq3GTthOi4fEd03GzhSy4P1rDy/ Hi4szn48/+NOmx0zbQ/qi4V71qfWw/hlfdncIEPR2Wb+nRY7Zrp/LxJBEM7iiFv/VJqZyAxv9fUF Z63aD1jrpM5xURAksbfSQKg2eH84PmguX51oNI2nOo8jWBNBdNszbkbuyBl3Vl70G9bc7RPmdwFJ kJChRgWZ3H1CiCiHfbes2pkT5qeh8wJmc6UpvdcwDc5IIpHCFcgen729F/eLBG0H0rQCyCAhz+GD C8adK1yHdTvtbNx7XhIFiSQL1DDvEgl10pkh7MSrF4+Yxy/GB8YkO8FZWtErChFFEqDgGxhH0w7z tTfuTrwsiaJAetASXcM0QxFkvHSAOQz7VSBOIh5BkvBsA9hd6wpxL8m05pET8pfIdB1G6iOiwOtI BimYi8S91zMSF2XllTZnsEN+FVCJKAk8COm9YcBdzx/tkbxCZOUNdsT8OqziUWxmyEeClcYn8Rgo Pjym+8D2g8znCdVHHCaNw0UbD0sAiiLI2d6T+/pcVacIz4WW0/mx9A+bnBGkcV/44CkzpZ6XHDte ulWoWlsxeJ+8WCQzX3Y50+10P1fjXhRyoDRUwPpkFMZyg/elxJEfxpAhcp9zMLGnNt2wHsY2z1ya efWFxMFhV7CX0zU1QYgsOEFqQR0bLVOYTHnk5G3n7C3mV1WCJZQcRu2hVWsvormz5FTuDfZbZFot FkBGwnt3kgVDI9QaH67LZY//XK/jp/312bI6iXd1FLLivnFPX6kPr/v6BueutG0//9xbiqjKMSSK IfJaYxPqF9ZcSSjNtITuYZt95M6PhRPOjYnISFIQslCnGXcM9pO/5EzrEomVXBHFvjEiICrKxoBJ a77wAtRzj7ifb3y9g9qAK8fbUEQQj/jCQj+tbESLAJQzXfY/qf4e3NaDCAm8AMOKSNL9hYpfGz9h frSwmfEtZ/yGERoaOtdHAM6Lve8XNmHttWaznnub59q9ZcFeaBxql3MqxjmAXUIyBV3LLgDUy69z nfvv4JDvRw2NquEwmkGOSO4CLateANNmurvGp1azqVV1Xc+Gsdr2jL6QLOQWXVHQOHPY3sU90AQw oAFlH46rzZBIct30eVOwxZnHMQRA3xw2AO5iiSTetcRD+gF2htKwj567/1YFk5YJmZsBM0RQRyRS 36lieIV/EqwHnPmkCjqN42jPQy7Ly0jcA2qQol3dwJ1l/gCZVBWg5iEBNTmfz8cJIkl/uUCrGqVa 9VNLexOZ8SrU58ggjvDliXDeI3vj6Ty1o1K/Z1maHz1HUWd7/gbFWNDrRC6s8//LqpqsXMCalFyO Dg/N+aRHLlCMdVWNeHcLDTBLb3GGGk8hmpDTHMkqhIwWLzerdfrnyERpxWZMiibpdjiJf3NjRJIX Jlce3tNKr9gMrdgUvgNDX1Tz+VziZULcsYRG9fAaP3uEW0SkAXWKv/ZUHrgzzgS9pqrNr32I5zo/ TLX8TScbYChYKvVVUUwt9T4YzowkmcCYEqR0Sr2s6zwbWM0de3fyrh3+SZQscaajBArrSgCXLszr tArwPjJ8ZCUS+0m+J5TscJ1Aal1xD43Tmj+mGwDvEUngu5G4pndq08Egz/VzWc1NERIolIhcsT5L v+eRiMi13MnQteyZtzjz61OqigOIjIdc+PT+zDW0g4YCOffU6ZuhpS+5n/8VI2piaCiSxgYJNuYu +7HE/WKPVvKJohy50ubMk8mAioH1xWTVRO0P73LdC7Q8ia7IFcaEDut+FkJoiqjlsCtZ2dybtSxT ITdoaQpHkhxw5vC3H2/39fW9TAZLArlQndi7ZVk7pAfvLCGJ0ulO9xCZdhPuoEvSWyJuWoFN7Ks7 njQyk4IkvtI55MyTGGxw1WCJBAtVmFqxmv54mpb5+iO3OcO6yJT5fN4okeg0QLJhfZwM26kE4dQj m2HIYGuJsl4ikQrspyxraUtGRsGRxW2IzCF7Mgi05BEnAHNV68XZZnimJtNyAidRfLNjM4ftu1Bf I2TGmJPT1dXA7MMBKMtldQoZcpF1bKazB3Ws3u5Llwj2VnB2JwbvjuRUhYiSzBymy5BZQ+a0QsIh d2E9B/V3x1UsDpH+pNU6YcyyT97tJRg9dHsGtHeDCZ+EJftZ9ygX21kAqsi7ST7qEd5lmhJUsGLi 9w5Qx/F8nzMkUeTbOUoNZM7lfZz5szY71rk/g4wYvoYMGV9fAXPNvfgC9ioWh7WP/Ng6YuKaJEiu ZHkBzExPdkCy24J1Haa9s2IzcyjjTqGfbV8kEZdEXmOsoONnDwDrPDSHH5VTS7xYw1hB6S00c8R0 n/gB1vBI2MdETmZNOtdzRp0S5R8/y4yiS5G45kRJlNOjWp54g4GxhPdn/FDHTIzfqfCi/1VRCKTO 5nwkkZVVNfgIma7DYI+ZlCqCOJERcIAGfeIp9dJAXk1/iJ6f6tQpnSPiQlYQAtl+XBjXx5JUTb/d OmEOvxhFZlUgK4vIZLC+waQvSvM3XkfkWOdxzARaJsJLDkNcWRq4YCyat1qtp7lGdRN1pJeyNiN9 z0sj1Ng1V9vsGcYADev6Uslhxkbqq5pRh1X2jE4MGtp5Iv6ew5BrI/UyZ0pXWBfv65gBmsf6lYjN zAWjVc7U38Ar7Toz+HgUmXUJvRIRGVcx0GPYjMpYiznz9R8xqNNVSXThcLizflrxkQ3NqDXM3AFr HzMzANqq5A4vEomksVaLvqIGxRUo8Zs/tJmvAIDG3SnIEkL8zQqtFHO6eRUnfJixEx0DaCRVGz8n hkOkAZTujuhwFRs4jNfqeP7qRrVe0WvnerEzrvsaVlPTORMDmnl0dHYWogaYRVHsFSJ4b7ihAEZ0 Y68XBd/sOvPOopTCJh8/kqbVzTNNHWCmMr8TRGYDDdl+wmkKl0g4rIhp3TAHLF3fWtle2c8blJZu HzH3vVVYUil9z/6iN2CBVjb2clpuhdLy94/PJcMFCvhA7B8xYO6dZn1qxdwYVm9pdPX7LcfzzyeK fwAapevEQybg/VkLJgtLmUGvUadrBy2eq8PGtpTTAHVallQlWNmLIZN0Jwavg0nXb7ecXJHFcL9h 6nRdSf/IT/eDTcgQd8C7tGLS8qjD/Od8lManTUyGX22zFJaMejlHyNmsYZbmQx9ypvVAKxilQdME mu3ZyGqwH6bUWCLuaTDWCuoBZ9p5jUI9fgYdlXpWt6tg6hpCuskdBt+26/ObCjT5TtjGYyhZswJ7 8w8KFUDDGP5O12YoPsCevzMOGtrSoebJT6CogUjuYtvW+UcuDLB6VZ6Bzd83AJY83iggq9Fs4MDp w4+QR6n4xrwfduVKtbrZIyeBS6/FPmh17T78KeVhjG3CRswcWt7cnw5m0fg6Lf3VATvqw1PUjt3l GYCGj2TKE9Eeo54PRVgbfxwdVS3Y2UY1dJUgoaWJqDrdVGf5TsXJsZnHSsQWmtbQlZkgSjS1f6uF RIv/cvY8e7gdDvmpE7BHblrWL1r8JbOZrs0wZuFjHp8NDQWtFnsmEMD4P1oK8Sv7gdVGAAAAAElF TkSuQmCC""" class TestCase(unittest.TestCase): def testAbsouluteUri(self): # URL f = getFile("http://www.holtwick.it") c = f.getFile().read(1) self.assertEqual(len(c), 1) self.assertEqual(c, "<") self.assertEqual(f.mimetype, "text/html") # Path f = getFile("__init__.py") c = f.getFile().read(1) self.assertEqual(len(c), 1) self.assertEqual(c, "f") self.assertEqual(f.mimetype, "text/x-python") # Data URI f = getFile(_datauri) c = f.getFile().read(1) self.assertEqual(len(c), 1) self.assertEqual(c, '\x89') self.assertEqual(f.mimetype, "image/png") def testRelativeUri(self): # URL f = getFile("index", basepath="http://www.holtwick.it") c = f.getFile().read(1) self.assertEqual(len(c), 1) self.assertEqual(c, "<") self.assertEqual(f.mimetype, "text/html") # Path base = os.path.join(os.path.abspath(__file__), os.pardir, os.pardir) f = getFile("tests/__init__.py", base) c = f.getFile().read(1) # print f.mimetype self.assertEqual(len(c), 1) self.assertEqual(c, "f") self.assertEqual(f.mimetype, "text/x-python") def buildTestSuite(): return unittest.defaultTestLoader.loadTestsFromName(__name__) def main(): buildTestSuite() unittest.main() if __name__ == "__main__": main() pisa-3.0.32/tests/tmp/0000755000175000017500000000000011201057433012625 5ustar wmbwmbpisa-3.0.32/tests/tmp/right/0000755000175000017500000000000011201057433013742 5ustar wmbwmbpisa-3.0.32/tests/tmp/right/borders.pdf0000644000175000017500000003136011162761534016112 0ustar wmbwmb%PDF-1.3 % ReportLab Generated PDF document http://www.reportlab.com % 'BasicFonts': class PDFDictionary 1 0 obj % The standard fonts dictionary << /F1 2 0 R /F2 3 0 R /F3 5 0 R >> endobj % 'F1': class PDFType1Font 2 0 obj % Font Helvetica << /BaseFont /Helvetica /Encoding /WinAnsiEncoding /Name /F1 /Subtype /Type1 /Type /Font >> endobj % 'F2': class PDFType1Font 3 0 obj % Font Helvetica-Bold << /BaseFont /Helvetica-Bold /Encoding /WinAnsiEncoding /Name /F2 /Subtype /Type1 /Type /Font >> endobj % 'FormXob.0454a8e1ab4c5497b258dcf4f2ec75d4': class PDFImageXObject 4 0 obj << /BitsPerComponent 8 /ColorSpace /DeviceRGB /Filter [ /ASCII85Decode /FlateDecode ] /Height 137 /Length 6081 /Subtype /Image /Type /XObject /Width 70 >> stream Gb!$LYEC/6'uilXLb]gc-mYrH%mU7M++dQZV8*YT5WTS`M'L$(P.$jc?N>^\JQO*s1jA9OoBS'U\MpRhB6JGJDH,[r=(U7WSo_[<2fi;3^4Ou2h_G-)hf$:.cbH*eq,\O&TT'Jsr5IdL^M;fn++J!SeaT4/0Q`J]!CHYG(")TM5>8ij9nUe&f"_0gNJ;$AkMP%+7QYKYp&GWL%2p38;EJQ.JF7Ol!UA]Ps4fNg:T8I?<#^G<:c(0!*B4+VRWTq,&2c2Mj"H),cTg8M9b=5O8LVMtD4V2044(E.dRdn_5A=JO'Dddg\j^L25]'-VTDu"+2^$iC_Bm%+:C[rD+meUS7n5D?3(`;fjI:ZVIj't@!GU]E*$Aq<@poQ+JFUQ-?Xa]9AX),[.5_C/lUr^o>Ql-="=%qXLgCPY(VmEp;k&X+hZVHe[*?J-dAE"NPodB-ceCak[K7j=qh;D[#D[0Eh?B\a;3jB[f.g&MUi\?u$haePB4H[2i-KaJXfCSX=I;"Ree#54B3WD;n5$hJAS[q(YO@fTSb<&PJ2G6rKQZs2>re`VWD5*_l8/?g;NjNcao0?PpBEohXF#^@0:j7U8LP'*fhK>qYJ[X7jAZT\o!gmFp,"jY?',#1d4g#R`WNi.,1L7I?Bkr^NQqg"i,.c@\1'-4?j&d086FMm\SE&-1m6/g/bQ][EB:Js3[j^CtS^,ieuN6E\.![B*P+D#JER_A0QndX\]$/WR4i9Kd,\7/@jWT9>LniG-QeMgNhP^S3)*E8kK#3$l6g9)WoHOli;-44MC:W).((CR`AR'"qH3Lh!OUJ(HP7,X$eXGD)#FjkVX/3W>ret\%-?BT6!QIgbpRUMC:Q,UTP@^BjMUu5WsrNj>l8OO.o4l>1#?M>UX^V]%XD:&CMmm*g/@(ZWbV;S6"K-O&/Lp0BIK79BN-DKgWdSRZ9:Z\E`<6\AEc1BKQ=Hk++7`78$)VV;9E_s\BO(F1.Rp'#aj-7`q+')jfX,1Q(.San\9Z&3'i]O;Xh%=d?'"/Z?5m#5"&4Pnm4eA!*-LnLO51]*R9,\.F*+"FTusn+pj'ZlDe+[d#r=%4-WG+#Z9#\51)2l#:.QL2GmCPr'Tl#aq&2)mcca1jFgT&N^A&ZW0KSm.8u_F%k@BnJV\Q7;@&pF3H/]t5nt(?`WJ`p'\*PX0EpUe#P#fNlnIZ;3G3mKI_:PdWj-^_A>!0k"9VM"k6=LW0ChR5^L^7*&dJ]^f9p(ZZ#662tomo-$.uHdgVqcGNg.-l'\gGScdbI&,]a=QQpVZW6TcP)ts\+1m=geL=+ARXd6XL5^!n@RDFLHZKEP"Bp,OQr8L`;mcplFAKXFCDCZ=a?PUp%n-1$pIiYKOTE@P:!WQ\m>>m$M&ls9nX?9"[q1g'e3i;5",@uaSjUuD0%&(2@L[SpKH"q98/f[gl>5hT=%!O,%&XOIg*g1"L#e-K")C)$c@pG&LkLEI/BONP`*$;qW[0bmI!MQKni9cN@p>l97?>G,@1aMCfYm\O]+;u?(.dT^11:Y.63M0g9GbD8YfUOZhg$'DEGQdM!g674q"1@=rqW:.C,d-M>NPa;o&#&"6#i#Y_ZoD1Kl7Z*Qd?Jn&K8liniN"gs/FES#*`;ha1Pq`[?VAp+X5qRa\hshBR!d"'\Jn?eW[`CLYcJ!!(H#q;*dUIc3lZD+jr]>fH`CH`f-3VcO/qX:A3Y3+B_h@F'N\4"9Lr'M)?28;khLDDH8Dbd5kP]jnaeMaP-Gn/^_Ao,[Z>R3?fGZL3j<"Am(kU1&]nHFAWE`:I[D:-u1E*&VP".@tiYTFk9TgkmOY:aVrSnj9*ID6n^47#Qs%nP0K/a&>Hb>/(WZQD'Uo_b'#?:HaF(F.!3/\`h3tGM9$*qSP%Wn*X!fg%BN@g:[XI,ERbBAEo!nuVik9GS#fi\lm-K`MXo_4pVmK1RlscuX@KX']AHYV!#dKSo8OT+M'ucgk=qNnfCMru#]=t^0M.sLW[H!MNm:$\#Gtt5Ko9*R-"_ZT!)+a91U,dP@l`tb!o=WE-Z&;OZT:i^l8LgHP8a]GPrZS+nandp-C,T58,@lCQ+JkfrMBl)oilV]&MU^ZUT]updbFYFA#%D[HSG2]a,Tp6;I4)-3/@8`?Y-Rd9S^h#bke_=fY2;p%qsgUS=W'aZ)nY>`RRhEp2.6M]$*G^pDXuVj#01m-Sur9X^+ert?56>C`O"CT69%6uM\p=(qiCH'H;2i$flHkGFXXdZ;Df"?\X-NY2-mtk7eB$pc@bSfcTg,h0K$BJ,2^8InIE\bj&C!4`^it!H>VX(?K>E5-i@UNr&Hg:06Xgb#C8!II._Vhq8MfFT&1_nUJ8=f)cesEZ'fsp'pO'+F(G8=k"F2*UeqrC>K;J9ZqoXPg:#*X6S7+Q=Ns]WkEKH>S$aMI]tPsX/k60l8Q!7dQX-cAKXPOL[OF(8&Z%hTZ@UV0JfM()8f0l/ZHB+MAr;%m$[oT+/%m?Q>qh-j=*-A7QNf#gYI]3d$,+-<5.:G!(E)X(RJ2i#mr"pR;d)4S=@5Tl5jK]ahCj:Rn0Zpf`P%\t,>2Td\-QbaV+Z\h_?&[-o^87ngkF(,iH/63EXjp#V?S?(5C(0uBJ];3h2Qlh);+mQpaSY+p@URdEf?Z@mICe7'$-0ZABb%?L6C#?5+?B[275?-PM>&.Y+a`2I@V6kqhmn,`n'.b<7:Pb2,,hPD"gd:h$/p<9U<8]-Z*Z\!J@/@^(H8lE=7(),Y7ZJn)01$ckLT"a?Y&uu#3?%?"SA_JkBQh7H]6uKY!0L>q.\`.6:Lgh^/^:g1]Iq6n0Me@5FYcZ7Zt$4rZLVJTZm6t0c-_I5>ibIEpO+eSK_MEj.]IGQB7""FAsRdTo^Z$Idc)>sT%6h&h4`H6#+[RTe%*:Gb=hr`?"5P,D&.U1Rro=f$BI0Q*7ChlI-1,Dd4Z>LJ*8BY7!7Jkbjq[nMuF=F=[&l8IPRYc/l&;&6TiN8D7\%`e?-'&DO-p@;5q4\XX/Gcr/Ou1H\f8IG>`I\`$K^ASJFtd8s0bUE)O2,=YG(ne-P;[I@(tf1ok>Ab=?MaJd,".=!=:eiGnQH,>[20,.<2LD$!G4K4K(DZ=YHq336NlKO#hUP)1-_DdAi*rB%OFX)4F\Ae:E5su_]QQ$./GKYf6'>biH[b([p1d.jEa+tA#&Dt;1GY1"9Ad`X(cbh(&>Xp:#G>g*`d+<@QOo@acMnSBSq%dNgGPplO9(,$0#eXs%q9qK_fN&-cRWBs;H;K*J#5(cS;)5?3dG^rmn+S'D+t#cOFMN&3c)K4co$TOI&a?PM>mk,g'"j%?cVn;<,LaWpDir4&JHH1h0k+*W(7-T'n+80p,,n@u$\8eL9U9fQM(OMb+)SNt7:&dnCaAijsbl2ju$L/D$H-ci^LsG^MQ'=B3/9X5q2$tGZ=WlEB?!1[*q4=(R#)K;%GmM3f-*q_n0'1YZ`2$Ak((F=t.2ir`GZZd\#fiF897]16)Ef8hB5b7"?kErE$kGI3\'EUnDXUs*!)R$,UWeCMc@_Y&>:T:m,!3M@H\S0>bMQJXmeo/2#_MaV&>^!V-QF;0rr5;pm@ETlr=b*tQL#',En\Q^6?J*?"&qLh>6SLr,-EmqLImct7$lq.:k<:/Xd**>/Gd-p,rkfpV#=O>S\aC?AP;[-'(T*l''g"GZd5Th,XfiTcCJZV:-(frV62_%Hd_[QJFI*1%,0_2QqR)L-b7S&W4,ue[VK1W:Qh"8<'WK/&X-9BHoRj2$^gN$-*u8cZCmk4`?d\"j:8?aNTnHfl@@00M?M`]3iQAlQKVt#:hqm;GZ2:4b-OH5f+^j#.,9!e_l;+JH:k!-/tj(R`N=OhgMU_Al'.p)pR(RT4Fb"jFrbTh/9Q%P=@u/Wkm.M9=0_'(K3E`84Ir[G>"0rljBui>Yg`YfSBRUPg5]?Gl7U9#Gi0W,agAg&ZFWiR8^QV2kFmK"/<$CkdmHTkGj&h@bE.opm=-cmc"k;)V&!#&+X*;KRs2J.QZ[L*r4lN5'(l5:TWl2&FELFJ`m@?Ce:"TkmON4s\oCUG7/udX5BIpe8BIf?7'N;l:Fb*RT&XekKMIkI-CNjgX!RVLSQgViM<6X,le8a&WFHfkeRl@7Iur77WN=*$PI3R3Fugg"pD!AXn4>k.[O2^K!4Mc^m/=Ke<-/A%Np^6.i_Bs'Fgf"Gar-eImm?4L>)gSC?I6#ANl/1F.GK$,Ag/cGh5BhZfN]0VcLWBWOm\M'VmHGF3#Eo6)$E@F=hT1;HMnp!$endstream endobj % 'F3': class PDFType1Font 5 0 obj % Font Courier << /BaseFont /Courier /Encoding /WinAnsiEncoding /Name /F3 /Subtype /Type1 /Type /Font >> endobj % 'Page1': class PDFPage 6 0 obj % Page dictionary << /Contents 18 0 R /MediaBox [ 0 0 595.2756 841.8898 ] /Parent 17 0 R /Resources << /Font 1 0 R /ProcSet [ /PDF /Text /ImageB /ImageC /ImageI ] /XObject << /FormXob.0454a8e1ab4c5497b258dcf4f2ec75d4 4 0 R >> >> /Rotate 0 /Trans << >> /Type /Page >> endobj % 'Page2': class PDFPage 7 0 obj % Page dictionary << /Contents 19 0 R /MediaBox [ 0 0 595.2756 841.8898 ] /Parent 17 0 R /Resources << /Font 1 0 R /ProcSet [ /PDF /Text /ImageB /ImageC /ImageI ] >> /Rotate 0 /Trans << >> /Type /Page >> endobj % 'R8': class PDFCatalog 8 0 obj % Document Root << /Outlines 10 0 R /PageMode /UseNone /Pages 17 0 R /Type /Catalog >> endobj % 'R9': class PDFInfo 9 0 obj << /Author () /CreationDate (D:20090326211940-01'00') /Keywords () /Producer (pisa HTML to PDF ) /Subject () /Title () >> endobj % 'R10': class PDFOutlines 10 0 obj << /Count 6 /First 11 0 R /Last 16 0 R /Type /Outlines >> endobj % 'Outline.0': class OutlineEntryObject 11 0 obj << /Dest [ 6 0 R /Fit ] /Next 12 0 R /Parent 10 0 R /Title (Hello World: class=c1) >> endobj % 'Outline.1': class OutlineEntryObject 12 0 obj << /Dest [ 6 0 R /Fit ] /Next 13 0 R /Parent 10 0 R /Prev 11 0 R /Title (Goodbye: class=c2 ) >> endobj % 'Outline.2': class OutlineEntryObject 13 0 obj << /Dest [ 6 0 R /Fit ] /Next 14 0 R /Parent 10 0 R /Prev 12 0 R /Title (Goodbye: class=c2 padding: 16px;) >> endobj % 'Outline.3': class OutlineEntryObject 14 0 obj << /Dest [ 6 0 R /Fit ] /Next 15 0 R /Parent 10 0 R /Prev 13 0 R /Title (Goodbye: class=c2 padding: 16px;) >> endobj % 'Outline.4': class OutlineEntryObject 15 0 obj << /Dest [ 6 0 R /Fit ] /Next 16 0 R /Parent 10 0 R /Prev 14 0 R /Title (Goodbye: class=c2Next line ) >> endobj % 'Outline.5': class OutlineEntryObject 16 0 obj << /Dest [ 6 0 R /Fit ] /Parent 10 0 R /Prev 15 0 R /Title (Mixed colors: class=c3) >> endobj % 'R17': class PDFPages 17 0 obj % page tree << /Count 2 /Kids [ 6 0 R 7 0 R ] /Type /Pages >> endobj % 'R18': class PDFStream 18 0 obj % page stream << /Filter [ /ASCII85Decode /FlateDecode ] /Length 2144 >> stream Gb"/)gMYb8&:HLqJ!cQ(C639*^1<*b1ruL(Bnc0m??QV2T&L&p>=]EBRPk.C6n3-:(f6*3pYpq(F:k1e>=;XJWE$j6cX[-g:3"NO2o83e0[$J+alK6`i38Pk)8-Zic-%MNTPf`.Rd6ihJ@C=u.7O23]Q.:C^b9#b2)V!De*d5f^"Z\A+[PN#8%bdJ,#E9%LH"'T6Ac`942^D'm(8iO2MgLSjCGnjQ2s-dh.7d9%'#sTh%`=Xm7('L<,F'mBTgkF_ITplb^WDE+TDX:;WFXpi(0npW8`*clj[J.)]]:t-.['9NDo1f0H^JPAab!s6NbU$Lf=mc;n!o6429230#SsY2rgrM;kjPBT'UY^3jfD>Xicf`R5n[gRriT\>**4.nB$_-jT&Y)s1Ns8X#_U/-'XsXIU.a?qIDoT.iWd^pd0Fs_5mjT7$u>:8$8O[ZF`a^Y+'cRDAh+=/&5`BrT:>$Gh.:=gF2K;FJ#Fmmj)I.MQ;nnnij5*"JB_sJg*Bs?k@W(*9I6s@L>)a$onFpmsd;M[5F4XAn!i:dlEt/0lu4[5tl4S+&-IoeG%1"*LFK)AYW%tZ:SB74LU)_Lth_sD$]L5N-:F.3m-YR',gK3,dOg?Yg@;PUHfN)^1Ih1m4?od;l((?mWh2=IOH3Gfs8kNM/i,]!4/7UDb4cf)ojl_cDT$qegWCQ\/N*0FbmdHdUaY)tG,%;bEuQM["m)VP.ri%6e4eY0%g&K%a_N0`Y:kWl+[a\8k1=?41p1!HGtiF*)JEpj2]4"Wr_hBu&YkCqHPF38WbN9d*i.FUF7(2c.L/"KAMp[L'uWESd-m6HVn>)\2I58EE>HPk*7\0q2>5nC"bm#cC8\P&#$4q-5n\[G!s3sP@'_g]k8SM)H@+F?U=VIiNSWfZBG71;iBrUcA9h;mFThEh(1CGO;7R>VfPE=7.m(Be(%L3?SMg/3P@k$]+Z&BBLt.ZT,'=l9?_734rWF"B;H0qPUE4E1r;%_ER?.bD>_.@FCQUa4g41\'+C`e`0rmjt5ZonFD:(B]7GC;2.KAtdVq*GJ,(/PR87AP\"e8p$+b='\?aqLYmuU+K=l'U'lMQ#t5\m;`!lR0(5gc(s(Z'HSZq6X%nH)fbI?`RJa[I8RgP`O)&3=6Y(^KbH%BLo)!Z;c^SA$[uUPHS_&3`,Dm771QpPqC#9=3lmMJ;(<",F1+N0ll02+E01cDR2n])Q>DldTu`4=6UolP&6HC_R,7Xl93E5FrE<.0~>endstream endobj % 'R19': class PDFStream 19 0 obj % page stream << /Filter [ /ASCII85Decode /FlateDecode ] /Length 665 >> stream Gb!#WbAQ&g&A/tO5Kkhk;HD<%f:qLY(B`q-YghB<+d*0SBg09^fl#7A!IQF$&<_3LGBRRI;=Gg^;d4VjnEI!,/28+eCJeSd_#:Ln4Dm+Toos)Sfo)kJlPA*8?2laB/?R+DpCGg_4-Ql\jO]3AK8ag=lD(Spqsp]UG,TAYXGUc-Bk*mYqRCN-;<^:&(ugN(k,r(?)?7^L>0JH=kel*3mDDZKk.CVZ4f[SZkXLfYj38#IuB,cW+=T>f,N47Pc%>V'r!7_"%c?+7E_C9W5PibYLUB_mY$h*PF^oqEqSmTV\fAQoAB_Ue8rhLUS%JD-0oK+rR0OkdYZUmW6rg9ZC.R$GIr"Bqr0-.bC3X^:MigZA&\n9[@`jI)5ML.bCoh.4Q_b/^2Q<8S-UHPVKl'k=#J>EkQeY\Jm!endstream endobj xref 0 20 0000000000 65535 f 0000000113 00000 n 0000000233 00000 n 0000000398 00000 n 0000000614 00000 n 0000006934 00000 n 0000007093 00000 n 0000007437 00000 n 0000007716 00000 n 0000007852 00000 n 0000008057 00000 n 0000008182 00000 n 0000008337 00000 n 0000008504 00000 n 0000008685 00000 n 0000008866 00000 n 0000009043 00000 n 0000009183 00000 n 0000009298 00000 n 0000011587 00000 n trailer << /ID % ReportLab generated PDF document -- digest (http://www.reportlab.com) [(~q\367.\267C\202G\225_\252\271\253\031\315O) (~q\367.\267C\202G\225_\252\271\253\031\315O)] /Info 9 0 R /Root 8 0 R /Size 20 >> startxref 12369 %%EOF pisa-3.0.32/tests/test_parser.py0000644000175000017500000000104511160170401014725 0ustar wmbwmbimport unittest from sx.pisa3.pisa_parser import pisaParser from sx.pisa3.pisa_context import pisaContext import StringIO _data = """ TITLE BODY """ class TestCase(unittest.TestCase): def testParser(self): c = pisaContext(".") r = pisaParser(_data, c) self.assertEqual(c, r) def buildTestSuite(): return unittest.defaultTestLoader.loadTestsFromName(__name__) def main(): buildTestSuite() unittest.main() if __name__ == "__main__": main() pisa-3.0.32/tests/test_samples.py0000644000175000017500000001245011160170401015077 0ustar wmbwmbimport sys import glob import subprocess import tempfile import os import os.path __version__ = "0.1" class VisualObject: CONVERT = r"C:\Programme\ImageMagick-6.3.8-Q16\convert.exe" DIFF = r"C:\Programme\TortoiseSVN\bin\tortoiseidiff.exe" SUFFIX = ".png" # C:\Programme\gs\gs8.54\bin\gswin32.exe -q -dSAFER -dNOPAUSE -dBATCH -sOutputFile=rl_hello-page%04d.png -sDEVICE=png256 -r144x144 -f test-font-and-styles.pdf # def __init__(self): self.files = [] self.files4del = [] self.folder4del = None def __del__(self): for file in self.files4del: os.remove(file) self.files4del = [] if self.folder4del: os.rmdir(self.folder4del) self.folder4del = None def execute(self, *a): #print #print "EXECUTE", " ".join(a) #print # os.system(" ".join(a)) r = subprocess.Popen(a, stdout=subprocess.PIPE).communicate()[0] # print r return r def showDiff(self, left, right): return self.execute(self.DIFF, "/fit", "/overlay", "/left:" + left, "/right:" + right) def convertFile(self, source, destination): self.execute(self.CONVERT, "-strip", source, destination) def getFiles(self, folder, pattern="*.*"): pattern = os.path.join(folder, pattern) self.files = [os.path.abspath(x) for x in glob.glob(pattern)] self.files.sort() # print "FILES", self.files return self.files def loadFile(self, file, folder=None, delete=True): if folder is None: folder = self.folder4del = tempfile.mkdtemp(prefix="visualdiff-tmp-") delete = True # print "FOLDER", folder, "DELETE", delete source = os.path.abspath(file) destination = os.path.join(folder, os.path.basename(file) + "-%04d" + self.SUFFIX) self.convertFile(source, destination) self.getFiles(folder, os.path.basename(file) + "-????" + self.SUFFIX) if delete: self.files4del = self.files return folder def compare(self, other, chunk=16*1024, show=True): if not self.files: return False, "No files" if len(self.files) <> len(other.files): return False, "Different number of files" for i in range(len(self.files)): left = self.files[i] right = other.files[i] a = open(left, "rb") b = open(right, "rb") diff = a.read() <> b.read() a.close() b.close() del a del b if diff: if show: self.showDiff(left, right) return False, "Difference in file %r" % left return True, "" ''' def getoptions(): from optparse import OptionParser usage = "usage: %prog [options] arg" description = """ Visual Differences """.strip() version = __version__ parser = OptionParser( usage, description=description, version=version, ) #parser.add_option( # "-c", "--css", # help="Path to default CSS file", # dest="css", # ) parser.add_option("-q", "--quiet", action="store_false", dest="verbose", default=True, help="don't print status messages to stdout") parser.set_defaults( # css=None, ) (options, args) = parser.parse_args() #if not (0 < len(args) <= 2): # parser.error("incorrect number of arguments") return options, args def main_command(): options, args = getoptions() print args a = VisualObject() b = VisualObject() a.loadFile("expected/test-loremipsum.pdf") b.files = a.files print a.compare(b) ''' import unittest import sx.pisa3.pisa as pisa import shutil class TestCase(unittest.TestCase): def testSamples(self): # Enable logging pisa.showLogging() # Calculate paths here = os.path.abspath(os.path.join(__file__, os.pardir)) folder = os.path.join(here, "tmp") left = os.path.join(folder, "left") right = os.path.join(folder, "right") # Cleanup old tests and create new structure if os.path.isdir(folder): shutil.rmtree(folder) os.makedirs(left) os.makedirs(right) for name in glob.glob(os.path.join(here, "samples", "*.html")): # print name # Create new PDF bname = os.path.basename(name) fname = os.path.join(right, bname[:-5] + ".pdf") dest = open(fname, "wb") pdf = pisa.pisaDocument( open(name, "rb"), dest, path = name) dest.close() self.assertTrue(not pdf.err, name) # New object r = VisualObject() r.loadFile(fname, right, delete=False) # Expected object l = VisualObject() l.loadFile(name[:-5] + ".pdf", left, delete=False) # Compare both and open Diff if differences result, msg = l.compare(r) self.assertTrue(result, name + ": " + msg) def buildTestSuite(): return unittest.defaultTestLoader.loadTestsFromName(__name__) def main(): buildTestSuite() unittest.main() if __name__ == "__main__": main() pisa-3.0.32/doc/0000755000175000017500000000000011201057433011430 5ustar wmbwmbpisa-3.0.32/doc/pisa-en.html0000644000175000017500000005401711177602650013672 0ustar wmbwmb pisa Documentation

pisa 3.0.32

XHTML/HTML/CSS to PDF converter

Table of Contents

Introduction

pisa is a HTML/XHTML/CSS to PDF converter written in Python and based on Reportlab Toolkit, pyPDF, TechGame Networks CSS Library and HTML5lib. The primary focus is not on generating perfect printable webpages but to use HTML and CSS as commonly known tools to generate PDF files within Applications. For example generating documentations (like this one), generating invoices or other office documents etc.

Installation

As pisa is a Python pakage an installed version of Python <http://www.python.org> is needed. For the moment Python 2.3 to 2.5 is supported. For Python 3000 a special version will be needed, because it is not compatible with the 2.x series. A proper version will be made available as soon as Python 3000 becomes stable.

The easiest way to install pisa is to use easy_install:

$ easy_install pisa

But you may also download the source code of pisa, then enter the main directory and execute this command (on Linux and MacOS you may prepend a sudo command):

$ python setup.py install

pisa needs also some additional Python packages to be installed to work. Please follow the setup instruction for each package:

Windows precompiled version

For Windows a precompiled version exists that includes Python and all needed libraries. The package contains the file xhtml2pdf.exe. Please add the directory where xhtml2pdf.exe is placed to the Windows PATH variable.

The Windows version is distributed via the Website <http://www.xhtml2pdf.com> in the "Download" section.

Command line

If you do not want to integrate pisa in your own application, you may use the command line tool that gives you a simple interface to the features of pisa. Just call xhtml2pdf --help to get the following help informations:


Converting HTML data

To generate a PDF from an HTML file called test.html call:

$ xhtml2pdf -s test.html

The resulting PDF will be called test.pdf (if this file is locked e.g. by the Adobe Reader it will be called test-0.pdf and so on). The -s option takes care that the PDF will be opened directly in the Operating Systems default viewer.

To convert more than one file you may use wildcard patterns like * and ?:

$ xhtml2pdf "test/test-*.html"

You may also directly access pages from the internet:

$ xhtml2pdf -s http://www.xhtml2pdf.com/

Using special properties

If the conversion doesn't work as expected some more informations may be usefull. You may turn on the output of warnings adding -w or even the debugging output by using -d.

Another reason could be, that the parsing failed. Consider trying the -xhtml and -html options. pisa uses the HTMLT5lib parser that offers two internal parsing modes: one for HTML and one for XHTML.

When generating the HTML output pisa uses an internal default CSS definition (otherwise all tags would appear with no diffences). To get an impression of how this one looks like start pisa like this:

$ xhtml2pdf --css-dump > xhtml2pdf-default.css

The CSS will be dumped into the file pisa-default.css. You may modify this or even take a totaly self defined one and hand it in by using the -css option, e.g.:

$ xhtml2pdf --css=xhtml2pdf-default.css test.html  

Python module

XXX TO BE COMPLETED

The integration into a Python program is quite easy. We will start with a simple "Hello World" example:

import ho.pisa as pisa                        (1)

def helloWorld():
  filename = __file__ + ".pdf"                (2)
  pdf = pisa.CreatePDF(                       (3)
    "Hello <strong>World</strong>",
    file(filename, "wb"))
  if not pdf.err:                             (4)
    pisa.startViewer(filename)                (5)

if __name__=="__main__":
  pisa.showLogging()                          (6)
  helloWorld()

Comments:

(1) Import the pisa Python module
(2) Calculate a sample filename. If your demo is saved under test.py the filename will be test.py.pdf.
(3) The function CreatePDF is called with the source and the destination. In this case the source is a string and the destination is a fileobject. Other values will be discussed later (XXX to do!). An object will be returned as result and saved in pdf.
(4) The property pdf.err is checked to find out if errors occured
(5) If no errors occured a helper function will open a PDF Reader with the resulting file
(6) Errors and warnings are written as log entries by using the Python standard module logging. This helper enables printing warnings on the console.

Create PDF

The main function of pisa is called CreatePDF(). It offers the following arguments in this order:

  • src: The source to be parsed. This can be a file handle or a String - or even better - a Unicode object.
  • dest: The destination for the resulting PDF. This has to be a file object wich will not be closed by CreatePDF. (XXX allow file name?)
  • path: The original file path or URL. This is needed to calculate relative paths of images and style sheets. (XXX calculate automatically from src?)
  • link_callback: Handler for special file paths (see below).
  • debug: ** DEPRECATED **
  • show_error_as_pdf: Boolean that indicates that the errors will be dumped into a PDF. This is usefull if that is the only way to show the errors like in simple web applications.
  • default_css: Here you can pass a default CSS definition in as a String. If set to None the predefined CSS of pisa is used.
  • xhtml: Boolean to force parsing the source as XHTML. By default the HTML5 parser tries to guess this.
  • encoding: The encoding name of the source. By default this is guessed by the HTML5 parser. But HTML with no meta information this may not work an then this argument is helpfull.

Link callback

Images, backgrounds and stylesheets are loaded form an HTML document. Normaly pisa expects these files to be found on the local drive. They may also be referenced relative to the original document. But the programmer might want to load form different kind of sources like the Internet via HTTP requests or from a database or anything else. Therefore you may define a link_callback that handles these reuests.

XXX

Web applications

XXX

Defaults

Some notes on some default values:

  • Usually the position (0, 0) in PDF files is found in the lower left corner. For pisa it is the upper left corner like it is for HTML.
  • The default page size is the German DIN A4 with portrait orientation.
  • The name of the first layout template is body, but you better leave the name empty for defining the default template (XXX May be changed in the future!)

Cascading Style Sheets

pisa supports a lot of Cascading Style Sheet (CSS). The following styles are supported:

background-color
border-bottom-color
border-bottom-style
border-bottom-width
border-left-color
border-left-style
border-left-width
border-right-color
border-right-style
border-right-width
border-top-color
border-top-style
border-top-width
color
display
font-family
font-size
font-style
font-weight
height
line-height
list-style-type
margin-bottom
margin-left
margin-right
margin-top
padding-bottom
padding-left
padding-right
padding-top
page-break-after
page-break-before
size
text-align
text-decoration
text-indent
vertical-align
white-space
width
zoom

And it adds some vendor specific styles:

-pdf-frame-border
-pdf-frame-break
-pdf-frame-content
-pdf-keep-with-next
-pdf-next-page
-pdf-outline
-pdf-outline-level
-pdf-outline-open
-pdf-page-break

Layout Definition

Pages and Frames

Pages can be layouted by using some special CSS at-keywords and properties. All special properties start with -pdf- to mark them as vendor specific as defined by CSS 2.1. Layouts may be defined by page using the @page keyword. Then text flows in one or more frames which can be defined within the @page block by using @frame. Example:

@page {
  @frame {
    margin: 1cm;
  }
} 

In the example we define an unnamed page template - though it will be used as the default template - having one frame with 1cm margin to the page borders. The first frame of the page may also be defined within the @page block itself. See the equivalent example:

@page {
  margin: 1cm;
} 

To define more frames just add some more @frame blocks. You may use the following properties to define the dimensions of the frame:

  • marign
  • margin-top
  • margin-left
  • margin-right
  • margin-bottom
  • top
  • left
  • right
  • bottom
  • width
  • height

Here is a more complex example:

@page lastPage {
  top: 1cm;
  left: 2cm;
  right: 2cm;
  height: 2cm;
  @frame middle {
    margin: 3cm;
  }
  @frame footer {
    bottom: 2cm;
    margin-left: 1cm;
    margin-right: 1cm;
    height: 1cm;
  }
} 

Layout scheme:

                 top
     +--------------------------+   ---
     |        margin-top        |   /|\
     |    +---------------+     |    |
     |    |               |     |
     |    |               |     |  height
     |    |               |     |

By default the Frame uses the whole page and is defined to begin in the upper left corner and end in the lower right corner. Now you can add the position of the frame using top, left, bottom and right. If you now add height and you have a value other than zero in top the bottom will be modified. (XXX If you had not defined top but bottom the height will be ...)

Page size and orientation

A page layout may also define the page size and the orientation of the paper using the size property as defined in CSS 3. Here is an example defining page size "DIN A5" with "landscape" orientation (default orientation is "portrait"):

@page {
  size: a5 landscape;
  margin: 1cm;
} 

Here is the complete list of valid page size identifiers:

  • a0 ... a6
  • b0 ... b6
  • letter
  • legal
  • elevenseventeen

PDF watermark/ background

For the use of PDF backgrounds specify the source file in the background-image property, like this:

@page {
  background-image: url(bg.pdf);
}

Static frames

Some frames should be static like headers and footers that means they are on every page but do not change content. The only information that may change is the page number. Here is a simple example that show how to make an element named by ID the content of a static frame. In this case it is the ID footer.

<html>
<style>
@page {
  margin: 1cm;
  margin-bottom: 2.5cm;
  @frame footer {
    -pdf-frame-content: footerContent;
    bottom: 2cm;
    margin-left: 1cm;
    margin-right: 1cm;
    height: 1cm;
  }
}
</style>
<body>
  Some text
  <div id="footerContent">
    This is a footer on page #<pdf:pagenumber>
  </div>
</body>
</html>

For better debugging you may want to add this property for each frame definition: -pdf-frame-border: 1. It will paint a border around the frame.

Fonts

By default there is just a certain set of fonts available for PDF. Here is the complete list - and their repective alias names - pisa knows by default (the names are not case sensitive):

  • Times-Roman: Times New Roman, Times, Georgia, serif
  • Helvetica: Arial, Verdana, Geneva, sansserif, sans
  • Courier: Courier New, monospace, monospaced, mono
  • ZapfDingbats
  • Symbol

But you may also embed new font faces by using the @font-face keyword in CSS like this:

@font-face {
  font-family: Example, "Example Font";
  src: url(example.ttf);
}

The font-family property defines the names under which the embedded font will be known. src defines the place of the fonts source file. This can be a TrueType font or a Postscript font. The file name of the first has to end with .ttf the latter with one of .pfb or .afm. For Postscript font pass just one filename like <name>.afm or <name>.pfb, the missing one will be calculated automatically.

To define other shapes you may do like this:

/* Normal */
@font-face {
   font-family: DejaMono;
   src: url(font/DejaVuSansMono.ttf);
}

/* Bold */
@font-face {
   font-family: DejaMono;
   src: url(font/DejaVuSansMono-Bold.ttf);
   font-weight: bold;
}

/* Italic */
@font-face {
   font-family: DejaMono;
   src: url(font/DejaVuSansMono-Oblique.ttf);
   font-style: italic;
}

/* Bold and italic */
@font-face {
   font-family: DejaMono;
   src: url(font/DejaVuSansMono-BoldOblique.ttf);
   font-weight: bold;
   font-style: italic;
}

Outlines/ Bookmarks

PDF supports outlines (Adobe calls them "bookmarks"). By default pisa defines the <h1> to <h6> tags to be shown in the outline. But you can specify exactly for every tag which outline behaviour it should have. Therefore you may want to use the following vendor specific styles:

  • -pdf-outline
    set it to "true" if the block element should appear in the outline
  • -pdf-outline-level
    set the value starting with "0" for the level on which the outline should appear. Missing predecessors are inserted automatically with the same name as the current outline
  • -pdf-outline-open
    set to "true" if the outline should be shown uncollapsed

Example:

h1 {
  -pdf-outline: true;
-pdf-level: 0; -pdf-open: false; }

Table of Contents

It is possible to automatically generate a Table of Contents (TOC) with pisa. By default all headings from <h1> to <h6> will be inserted into that TOC. But you may change that behaviour by setting the CSS property -pdf-outline to true or false. To generate the TOC simply insert <pdf:toc /> into your document. You then may modify the look of it by defining styles for the pdf:toc tag and the classes pdftoc.pdftoclevel0 to pdftoc.pdftoclevel5. Here is a simple example for a nice looking CSS:

pdftoc {
    color: #666;
}
pdftoc.pdftoclevel0 {
    font-weight: bold;
    margin-top: 0.5em;
}
pdftoc.pdftoclevel1 {
    margin-left: 1em;
}
pdftoc.pdftoclevel2 {
    margin-left: 2em;
    font-style: italic;
} 

Tables

Tables are supported but may behave a little different to the way you might expect them to do. These restriction are due to the underlying table mechanism of ReportLab.

  • The main restriction is that table cells that are longer than one page lead to an error
  • Tables can not float left or right and can not be inlined

Long cells

Pisa is not able to split table cells that are larger than the available space. To work around it you may define what should happen in this case. The -pdf-keep-in-frame-mode can be one of: "error", "overflow", "shrink", "truncate", where "shrink" is the default value.

table {
-pdf-keep-in-frame-mode: shrink;
}

Cell widths

The table renderer is not able to adjust the width of the table automatically. Therefore you should explicitly set the width of the table and to the table rows or cells.

Headers

It is possible to repeat table rows if a page break occurs within a table. The number of repeated rows is passed in the attribute repeat. Example:

<table repeat="1">
  <tr><th>Column 1</th><th>...</th></tr>
  ...
</table>

Borders

Borders are supported. Use corresponding CSS styles.

Images

Size

By default JPG images are supported. If the Python Imaging Library (PIL) is installed the file types supported by it are available too. As mapping pixels to points is not trivial the images may appear bigger in the PDF as in the browser. To adjust this you may want to use the zoom style. Here is a small example:

img { zoom: 80%; }  

Position/ floating

Since Reportlab Toolkit does not yet support the use of images within paragraphs, images are always rendered in a seperate paragraph. Therefore floating is not available yet.

Barcodes

XXX TO BE WRITTEN

<pdf:barcode>

Custom Tags

pisa provides some custom tags. They are all prefixed by the namespace identifier pdf:. As the HTML5 parser used by pisa does not know about these specific tags it may be confused if they are without a block. To avoid problems you may condsider sourrounding them by <div> tags, like this:

<div>
   <pdf:toc />
</div>

Tag-Definitions

pdf:barcode

Creates a barcode.

pdf:pagenumber

Prints current page number. The argument "example" defines the space the page number will require e.g. "00".

pdf:nexttemplate

Defines the template to be used on the next page.

pdf:nextpage

Create a new page after this position.

pdf:nextframe

Jump to next unused frame on the same page or to the first on a new page. You may not jump to a named frame.

pdf:spacer

Creates an object of a specific size.

pdf:toc

Creates a Table of Contents.

License

pisa is copyrighted by Dirk Holtwick, Germany.
pisa is distributed by Dirk Holtwick, Schreiberstra�e 2, 47058 Duisburg, Germany.
pisa is licensed under the GNU Gerneral Public License version 2.

For commercial usage of pisa a developer license can be purchased!

pisa-3.0.32/doc/pisa.css0000644000175000017500000000437311160170401013100 0ustar wmbwmb@media print { @font-face { font-family: "DejaVu Sans Mono", dejamono; src: url(DejaVuSansMono.ttf); } @font-face { font-family: "DejaVu Sans Mono", dejamono; font-weight: bold; src: url(DejaVuSansMono-Bold.ttf); } @font-face { font-family: Calibri; src: url("CALIBRI.TTF"); } @font-face { font-family: Calibri; src: url("CALIBRIB.TTF"); font-weight: bold; } @font-face { font-family: Calibri; src: url("CALIBRII.TTF"); font-style: italic; } @font-face { font-family: Calibri; src: url("CALIBRIZ.TTF"); font-weight: bold; font-style: italic; } @page { -pdf-page-orientation: portrait; -pdf-page-size: a4; /* background-image: url(background.pdf); */ margin-top: 2cm; margin-left: 4cm; margin-right: 2cm; margin-bottom: 3cm; } @page regular { -pdf-page-orientation: portrait; -pdf-page-size: a4; /* background-image: url(background.pdf); */ margin-top: 2cm; margin-left: 4cm; margin-right: 2cm; margin-bottom: 3cm; @frame footer { -pdf-frame-content: footer; bottom: 2cm; left: 4cm; right: 2cm; height: 1cm; } } } html { font-family: Calibri, Arial, Helvetica, sans-serif; font-size: 10pt; } h1 { page-break-before: always; border-bottom: 2px solid #ccc; } pre, code { background: #eee; font-family: dejamono, "DejaVu Sans Mono", "Courier New", Courier, monospace; font-size: 8pt; } code { font-weight: bold; color: #333; /* text-decoration: underline; */ font-size: 8pt; } .del { text-decoration: line-through; } p, pre { margin-top: 1em; margin-bottom: 1em; } .license { font-size: 8px; line-height: 110%; } .title { font-size: 300%; font-weight: bold; margin-top: 20pt; margin-bottom: 20pt; } .subtitle { font-size: 150%; font-weight: bold; margin-top: 20pt; margin-bottom: 20pt; } #footer { text-align: right; } i, em { font-style: normal; color: #990000; font-weight: bold; } a { color: #000066; } pdftoc { } pdftoc.pdftoclevel0 { font-weight: bold; margin-top: 0.5em; } pdftoc.pdftoclevel1 { margin-left: 1em; } pdftoc.pdftoclevel2 { margin-left: 1em; font-weight: normal; } h2 { margin-top: 1.5em; margin-bottom: 0.5em; font-size: 125%; color: #666; } h3 { font-size: 100%; color: #000000; margin-bottom: 0.5em; } pisa-3.0.32/doc/pisa-en.pdf0000644000175000017500000013673311164117630013500 0ustar wmbwmb%PDF-1.3 % ReportLab Generated PDF document http://www.reportlab.com % 'BasicFonts': class PDFDictionary 1 0 obj % The standard fonts dictionary << /F1 2 0 R /F2 3 0 R /F3 7 0 R /F4 12 0 R /F5 13 0 R >> endobj % 'F1': class PDFType1Font 2 0 obj % Font Helvetica << /BaseFont /Helvetica /Encoding /WinAnsiEncoding /Name /F1 /Subtype /Type1 /Type /Font >> endobj % 'F2': class PDFType1Font 3 0 obj % Font Helvetica-Bold << /BaseFont /Helvetica-Bold /Encoding /WinAnsiEncoding /Name /F2 /Subtype /Type1 /Type /Font >> endobj % 'Annot.NUMBER1': class PDFDictionary 4 0 obj << /A << /S /URI /Type /Action /URI (mailto:dirk.holtwick@gmail.com) >> /Border [ 0 0 0 ] /Rect [ 114.3858 649.2669 224.5458 664.2669 ] /Subtype /Link /Type /Annot >> endobj % 'Annot.NUMBER2': class PDFDictionary 5 0 obj << /A << /S /URI /Type /Action /URI (http://www.xhtml2pdf.com) >> /Border [ 0 0 0 ] /Rect [ 114.3858 634.2669 228.8658 649.2669 ] /Subtype /Link /Type /Annot >> endobj % 'Page1': class PDFPage 6 0 obj % Page dictionary << /Annots [ 4 0 R 5 0 R ] /Contents 80 0 R /MediaBox [ 0 0 595.2756 841.8898 ] /Parent 79 0 R /Resources << /Font 1 0 R /ProcSet [ /PDF /Text /ImageB /ImageC /ImageI ] >> /Rotate 0 /Trans << >> /Type /Page >> endobj % 'F3': class PDFType1Font 7 0 obj % Font Times-Roman << /BaseFont /Times-Roman /Encoding /WinAnsiEncoding /Name /F3 /Subtype /Type1 /Type /Font >> endobj % 'Page2': class PDFPage 8 0 obj % Page dictionary << /Contents 81 0 R /MediaBox [ 0 0 595.2756 841.8898 ] /Parent 79 0 R /Resources << /Font 1 0 R /ProcSet [ /PDF /Text /ImageB /ImageC /ImageI ] >> /Rotate 0 /Trans << >> /Type /Page >> endobj % 'Page3': class PDFPage 9 0 obj % Page dictionary << /Contents 82 0 R /MediaBox [ 0 0 595.2756 841.8898 ] /Parent 79 0 R /Resources << /Font 1 0 R /ProcSet [ /PDF /Text /ImageB /ImageC /ImageI ] >> /Rotate 0 /Trans << >> /Type /Page >> endobj % 'Page4': class PDFPage 10 0 obj % Page dictionary << /Contents 83 0 R /MediaBox [ 0 0 595.2756 841.8898 ] /Parent 79 0 R /Resources << /Font 1 0 R /ProcSet [ /PDF /Text /ImageB /ImageC /ImageI ] >> /Rotate 0 /Trans << >> /Type /Page >> endobj % 'Annot.NUMBER3': class PDFDictionary 11 0 obj << /A << /S /URI /Type /Action /URI (http://www.python.org) >> /Border [ 0 0 0 ] /Rect [ 377.0258 738.6419 473.7358 753.6419 ] /Subtype /Link /Type /Annot >> endobj % 'F4': class PDFType1Font 12 0 obj % Font Courier << /BaseFont /Courier /Encoding /WinAnsiEncoding /Name /F4 /Subtype /Type1 /Type /Font >> endobj % 'F5': class PDFType1Font 13 0 obj % Font Courier-Bold << /BaseFont /Courier-Bold /Encoding /WinAnsiEncoding /Name /F5 /Subtype /Type1 /Type /Font >> endobj % 'Annot.NUMBER4': class PDFDictionary 14 0 obj << /A << /S /URI /Type /Action /URI (http://www.reportlab.org/downloads.html) >> /Border [ 0 0 0 ] /Rect [ 129.3858 492.6419 307.7858 507.6419 ] /Subtype /Link /Type /Annot >> endobj % 'Annot.NUMBER5': class PDFDictionary 15 0 obj << /A << /S /URI /Type /Action /URI (http://code.google.com/p/html5lib/) >> /Border [ 0 0 0 ] /Rect [ 129.3858 445.6419 278.9058 460.6419 ] /Subtype /Link /Type /Annot >> endobj % 'Annot.NUMBER6': class PDFDictionary 16 0 obj << /A << /S /URI /Type /Action /URI (http://pybrary.net/pyPdf/) >> /Border [ 0 0 0 ] /Rect [ 129.3858 398.6419 235.5558 413.6419 ] /Subtype /Link /Type /Annot >> endobj % 'Annot.NUMBER7': class PDFDictionary 17 0 obj << /A << /S /URI /Type /Action /URI (http://www.pythonware.com/products/pil/) >> /Border [ 0 0 0 ] /Rect [ 129.3858 336.6419 308.8958 351.6419 ] /Subtype /Link /Type /Annot >> endobj % 'Annot.NUMBER8': class PDFDictionary 18 0 obj << /A << /S /URI /Type /Action /URI (http://www.xhtml2pdf.com) >> /Border [ 0 0 0 ] /Rect [ 348.6358 183.1419 463.1158 198.1419 ] /Subtype /Link /Type /Annot >> endobj % 'Page5': class PDFPage 19 0 obj % Page dictionary << /Annots [ 11 0 R 14 0 R 15 0 R 16 0 R 17 0 R 18 0 R ] /Contents 84 0 R /MediaBox [ 0 0 595.2756 841.8898 ] /Parent 79 0 R /Resources << /Font 1 0 R /ProcSet [ /PDF /Text /ImageB /ImageC /ImageI ] >> /Rotate 0 /Trans << >> /Type /Page >> endobj % 'Page6': class PDFPage 20 0 obj % Page dictionary << /Contents 85 0 R /MediaBox [ 0 0 595.2756 841.8898 ] /Parent 79 0 R /Resources << /Font 1 0 R /ProcSet [ /PDF /Text /ImageB /ImageC /ImageI ] >> /Rotate 0 /Trans << >> /Type /Page >> endobj % 'Page7': class PDFPage 21 0 obj % Page dictionary << /Contents 86 0 R /MediaBox [ 0 0 595.2756 841.8898 ] /Parent 79 0 R /Resources << /Font 1 0 R /ProcSet [ /PDF /Text /ImageB /ImageC /ImageI ] >> /Rotate 0 /Trans << >> /Type /Page >> endobj % 'Page8': class PDFPage 22 0 obj % Page dictionary << /Contents 87 0 R /MediaBox [ 0 0 595.2756 841.8898 ] /Parent 79 0 R /Resources << /Font 1 0 R /ProcSet [ /PDF /Text /ImageB /ImageC /ImageI ] >> /Rotate 0 /Trans << >> /Type /Page >> endobj % 'Page9': class PDFPage 23 0 obj % Page dictionary << /Contents 88 0 R /MediaBox [ 0 0 595.2756 841.8898 ] /Parent 79 0 R /Resources << /Font 1 0 R /ProcSet [ /PDF /Text /ImageB /ImageC /ImageI ] >> /Rotate 0 /Trans << >> /Type /Page >> endobj % 'Page10': class PDFPage 24 0 obj % Page dictionary << /Contents 89 0 R /MediaBox [ 0 0 595.2756 841.8898 ] /Parent 79 0 R /Resources << /Font 1 0 R /ProcSet [ /PDF /Text /ImageB /ImageC /ImageI ] >> /Rotate 0 /Trans << >> /Type /Page >> endobj % 'Page11': class PDFPage 25 0 obj % Page dictionary << /Contents 90 0 R /MediaBox [ 0 0 595.2756 841.8898 ] /Parent 79 0 R /Resources << /Font 1 0 R /ProcSet [ /PDF /Text /ImageB /ImageC /ImageI ] >> /Rotate 0 /Trans << >> /Type /Page >> endobj % 'Page12': class PDFPage 26 0 obj % Page dictionary << /Contents 91 0 R /MediaBox [ 0 0 595.2756 841.8898 ] /Parent 79 0 R /Resources << /Font 1 0 R /ProcSet [ /PDF /Text /ImageB /ImageC /ImageI ] >> /Rotate 0 /Trans << >> /Type /Page >> endobj % 'Page13': class PDFPage 27 0 obj % Page dictionary << /Contents 92 0 R /MediaBox [ 0 0 595.2756 841.8898 ] /Parent 79 0 R /Resources << /Font 1 0 R /ProcSet [ /PDF /Text /ImageB /ImageC /ImageI ] >> /Rotate 0 /Trans << >> /Type /Page >> endobj % 'Page14': class PDFPage 28 0 obj % Page dictionary << /Contents 93 0 R /MediaBox [ 0 0 595.2756 841.8898 ] /Parent 79 0 R /Resources << /Font 1 0 R /ProcSet [ /PDF /Text /ImageB /ImageC /ImageI ] >> /Rotate 0 /Trans << >> /Type /Page >> endobj % 'Page15': class PDFPage 29 0 obj % Page dictionary << /Contents 94 0 R /MediaBox [ 0 0 595.2756 841.8898 ] /Parent 79 0 R /Resources << /Font 1 0 R /ProcSet [ /PDF /Text /ImageB /ImageC /ImageI ] >> /Rotate 0 /Trans << >> /Type /Page >> endobj % 'Page16': class PDFPage 30 0 obj % Page dictionary << /Contents 95 0 R /MediaBox [ 0 0 595.2756 841.8898 ] /Parent 79 0 R /Resources << /Font 1 0 R /ProcSet [ /PDF /Text /ImageB /ImageC /ImageI ] >> /Rotate 0 /Trans << >> /Type /Page >> endobj % 'Page17': class PDFPage 31 0 obj % Page dictionary << /Contents 96 0 R /MediaBox [ 0 0 595.2756 841.8898 ] /Parent 79 0 R /Resources << /Font 1 0 R /ProcSet [ /PDF /Text /ImageB /ImageC /ImageI ] >> /Rotate 0 /Trans << >> /Type /Page >> endobj % 'Page18': class PDFPage 32 0 obj % Page dictionary << /Contents 97 0 R /MediaBox [ 0 0 595.2756 841.8898 ] /Parent 79 0 R /Resources << /Font 1 0 R /ProcSet [ /PDF /Text /ImageB /ImageC /ImageI ] >> /Rotate 0 /Trans << >> /Type /Page >> endobj % 'Page19': class PDFPage 33 0 obj % Page dictionary << /Contents 98 0 R /MediaBox [ 0 0 595.2756 841.8898 ] /Parent 79 0 R /Resources << /Font 1 0 R /ProcSet [ /PDF /Text /ImageB /ImageC /ImageI ] >> /Rotate 0 /Trans << >> /Type /Page >> endobj % 'Page20': class PDFPage 34 0 obj % Page dictionary << /Contents 99 0 R /MediaBox [ 0 0 595.2756 841.8898 ] /Parent 79 0 R /Resources << /Font 1 0 R /ProcSet [ /PDF /Text /ImageB /ImageC /ImageI ] >> /Rotate 0 /Trans << >> /Type /Page >> endobj % 'Page21': class PDFPage 35 0 obj % Page dictionary << /Contents 100 0 R /MediaBox [ 0 0 595.2756 841.8898 ] /Parent 79 0 R /Resources << /Font 1 0 R /ProcSet [ /PDF /Text /ImageB /ImageC /ImageI ] >> /Rotate 0 /Trans << >> /Type /Page >> endobj % 'Page22': class PDFPage 36 0 obj % Page dictionary << /Contents 101 0 R /MediaBox [ 0 0 595.2756 841.8898 ] /Parent 79 0 R /Resources << /Font 1 0 R /ProcSet [ /PDF /Text /ImageB /ImageC /ImageI ] >> /Rotate 0 /Trans << >> /Type /Page >> endobj % 'R37': class PDFCatalog 37 0 obj % Document Root << /Outlines 39 0 R /PageMode /UseNone /Pages 79 0 R /Type /Catalog >> endobj % 'R38': class PDFInfo 38 0 obj << /Author () /CreationDate (D:20090330123150-01'00') /Keywords () /Producer (pisa HTML to PDF ) /Subject () /Title (pisa Documentation) >> endobj % 'R39': class PDFOutlines 39 0 obj << /Count 23 /First 40 0 R /Last 78 0 R /Type /Outlines >> endobj % 'Outline.0': class OutlineEntryObject 40 0 obj << /Dest [ 10 0 R /Fit ] /Next 41 0 R /Parent 39 0 R /Title (Introduction) >> endobj % 'Outline.1': class OutlineEntryObject 41 0 obj << /Count -1 /Dest [ 19 0 R /Fit ] /First 42 0 R /Last 42 0 R /Next 43 0 R /Parent 39 0 R /Prev 40 0 R /Title (Installation) >> endobj % 'Outline.16.0': class OutlineEntryObject 42 0 obj << /Dest [ 19 0 R /Fit ] /Parent 41 0 R /Title (Windows precompiled version) >> endobj % 'Outline.2': class OutlineEntryObject 43 0 obj << /Count -2 /Dest [ 20 0 R /Fit ] /First 44 0 R /Last 45 0 R /Next 46 0 R /Parent 39 0 R /Prev 41 0 R /Title (Command line) >> endobj % 'Outline.17.0': class OutlineEntryObject 44 0 obj << /Dest [ 20 0 R /Fit ] /Next 45 0 R /Parent 43 0 R /Title (Converting HTML data ) >> endobj % 'Outline.17.1': class OutlineEntryObject 45 0 obj << /Dest [ 20 0 R /Fit ] /Parent 43 0 R /Prev 44 0 R /Title (Using special properties) >> endobj % 'Outline.3': class OutlineEntryObject 46 0 obj << /Count -3 /Dest [ 21 0 R /Fit ] /First 47 0 R /Last 49 0 R /Next 50 0 R /Parent 39 0 R /Prev 43 0 R /Title (Python module) >> endobj % 'Outline.18.0': class OutlineEntryObject 47 0 obj << /Dest [ 21 0 R /Fit ] /Next 48 0 R /Parent 46 0 R /Title (Create PDF) >> endobj % 'Outline.18.1': class OutlineEntryObject 48 0 obj << /Dest [ 22 0 R /Fit ] /Next 49 0 R /Parent 46 0 R /Prev 47 0 R /Title (Link callback) >> endobj % 'Outline.18.2': class OutlineEntryObject 49 0 obj << /Dest [ 22 0 R /Fit ] /Parent 46 0 R /Prev 48 0 R /Title (Web applications) >> endobj % 'Outline.4': class OutlineEntryObject 50 0 obj << /Dest [ 23 0 R /Fit ] /Next 51 0 R /Parent 39 0 R /Prev 46 0 R /Title (Defaults) >> endobj % 'Outline.5': class OutlineEntryObject 51 0 obj << /Dest [ 24 0 R /Fit ] /Next 52 0 R /Parent 39 0 R /Prev 50 0 R /Title (Cascading Style Sheets) >> endobj % 'Outline.6': class OutlineEntryObject 52 0 obj << /Count -4 /Dest [ 25 0 R /Fit ] /First 53 0 R /Last 56 0 R /Next 57 0 R /Parent 39 0 R /Prev 51 0 R /Title (Layout Definition) >> endobj % 'Outline.19.0': class OutlineEntryObject 53 0 obj << /Dest [ 25 0 R /Fit ] /Next 54 0 R /Parent 52 0 R /Title (Pages and Frames ) >> endobj % 'Outline.19.1': class OutlineEntryObject 54 0 obj << /Dest [ 26 0 R /Fit ] /Next 55 0 R /Parent 52 0 R /Prev 53 0 R /Title (Page size and orientation ) >> endobj % 'Outline.19.2': class OutlineEntryObject 55 0 obj << /Dest [ 26 0 R /Fit ] /Next 56 0 R /Parent 52 0 R /Prev 54 0 R /Title (PDF watermark/ background ) >> endobj % 'Outline.19.3': class OutlineEntryObject 56 0 obj << /Dest [ 27 0 R /Fit ] /Parent 52 0 R /Prev 55 0 R /Title (Static frames ) >> endobj % 'Outline.7': class OutlineEntryObject 57 0 obj << /Dest [ 28 0 R /Fit ] /Next 58 0 R /Parent 39 0 R /Prev 52 0 R /Title (Fonts) >> endobj % 'Outline.8': class OutlineEntryObject 58 0 obj << /Dest [ 30 0 R /Fit ] /Next 59 0 R /Parent 39 0 R /Prev 57 0 R /Title (Outlines/ Bookmarks ) >> endobj % 'Outline.9': class OutlineEntryObject 59 0 obj << /Dest [ 31 0 R /Fit ] /Next 60 0 R /Parent 39 0 R /Prev 58 0 R /Title (Table of Contents) >> endobj % 'Outline.10': class OutlineEntryObject 60 0 obj << /Count -4 /Dest [ 32 0 R /Fit ] /First 61 0 R /Last 64 0 R /Next 65 0 R /Parent 39 0 R /Prev 59 0 R /Title (Tables) >> endobj % 'Outline.20.0': class OutlineEntryObject 61 0 obj << /Dest [ 32 0 R /Fit ] /Next 62 0 R /Parent 60 0 R /Title (Long cells) >> endobj % 'Outline.20.1': class OutlineEntryObject 62 0 obj << /Dest [ 32 0 R /Fit ] /Next 63 0 R /Parent 60 0 R /Prev 61 0 R /Title (Cell widths ) >> endobj % 'Outline.20.2': class OutlineEntryObject 63 0 obj << /Dest [ 32 0 R /Fit ] /Next 64 0 R /Parent 60 0 R /Prev 62 0 R /Title (Headers) >> endobj % 'Outline.20.3': class OutlineEntryObject 64 0 obj << /Dest [ 32 0 R /Fit ] /Parent 60 0 R /Prev 63 0 R /Title (Borders) >> endobj % 'Outline.11': class OutlineEntryObject 65 0 obj << /Count -2 /Dest [ 33 0 R /Fit ] /First 66 0 R /Last 67 0 R /Next 68 0 R /Parent 39 0 R /Prev 60 0 R /Title (Images) >> endobj % 'Outline.21.0': class OutlineEntryObject 66 0 obj << /Dest [ 33 0 R /Fit ] /Next 67 0 R /Parent 65 0 R /Title (Size ) >> endobj % 'Outline.21.1': class OutlineEntryObject 67 0 obj << /Dest [ 33 0 R /Fit ] /Parent 65 0 R /Prev 66 0 R /Title (Position/ floating ) >> endobj % 'Outline.12': class OutlineEntryObject 68 0 obj << /Dest [ 34 0 R /Fit ] /Next 69 0 R /Parent 39 0 R /Prev 65 0 R /Title (Barcodes) >> endobj % 'Outline.13': class OutlineEntryObject 69 0 obj << /Count -1 /Dest [ 35 0 R /Fit ] /First 70 0 R /Last 70 0 R /Next 78 0 R /Parent 39 0 R /Prev 68 0 R /Title (Custom Tags ) >> endobj % 'Outline.22.0': class OutlineEntryObject 70 0 obj << /Count -7 /Dest [ 35 0 R /Fit ] /First 71 0 R /Last 77 0 R /Parent 69 0 R /Title (Tag-Definitions) >> endobj % 'Outline.23.0': class OutlineEntryObject 71 0 obj << /Dest [ 35 0 R /Fit ] /Next 72 0 R /Parent 70 0 R /Title (pdf:barcode) >> endobj % 'Outline.23.1': class OutlineEntryObject 72 0 obj << /Dest [ 35 0 R /Fit ] /Next 73 0 R /Parent 70 0 R /Prev 71 0 R /Title (pdf:pagenumber) >> endobj % 'Outline.23.2': class OutlineEntryObject 73 0 obj << /Dest [ 35 0 R /Fit ] /Next 74 0 R /Parent 70 0 R /Prev 72 0 R /Title (pdf:nexttemplate) >> endobj % 'Outline.23.3': class OutlineEntryObject 74 0 obj << /Dest [ 35 0 R /Fit ] /Next 75 0 R /Parent 70 0 R /Prev 73 0 R /Title (pdf:nextpage) >> endobj % 'Outline.23.4': class OutlineEntryObject 75 0 obj << /Dest [ 35 0 R /Fit ] /Next 76 0 R /Parent 70 0 R /Prev 74 0 R /Title (pdf:nextframe) >> endobj % 'Outline.23.5': class OutlineEntryObject 76 0 obj << /Dest [ 35 0 R /Fit ] /Next 77 0 R /Parent 70 0 R /Prev 75 0 R /Title (pdf:spacer) >> endobj % 'Outline.23.6': class OutlineEntryObject 77 0 obj << /Dest [ 35 0 R /Fit ] /Parent 70 0 R /Prev 76 0 R /Title (pdf:toc) >> endobj % 'Outline.14': class OutlineEntryObject 78 0 obj << /Dest [ 36 0 R /Fit ] /Parent 39 0 R /Prev 69 0 R /Title (License) >> endobj % 'R79': class PDFPages 79 0 obj % page tree << /Count 22 /Kids [ 6 0 R 8 0 R 9 0 R 10 0 R 19 0 R 20 0 R 21 0 R 22 0 R 23 0 R 24 0 R 25 0 R 26 0 R 27 0 R 28 0 R 29 0 R 30 0 R 31 0 R 32 0 R 33 0 R 34 0 R 35 0 R 36 0 R ] /Type /Pages >> endobj % 'R80': class PDFStream 80 0 obj % page stream << /Filter [ /ASCII85Decode /FlateDecode ] /Length 437 >> stream Gat%^:JZU.&B4)`I"s_j7L*NA(@YjND0r4<[2_=$;X#:-:_8K9Dt!*d0pjkYfjqBMH#Ml4[nC,P7Ckr+gkT9s#`(dV!HQP#Z,I#GH&'ET-tCo(P,hE/Z!Jd9j4)Lg0V:^t_p`Q-;83'8Qdr\F0.mnSEA?CCL2AkA,9Q;uC`7X80Z-.fS&oG_,]PrE0L,$r>)RcW^H$%!-P@JncVu1>"endstream endobj % 'R81': class PDFStream 81 0 obj % page stream << /Filter [ /ASCII85Decode /FlateDecode ] /Length 1220 >> stream GauJ"?#Q2d'F*Lm9)T:`ZC=eu"6!aV9p]]pVR6e1Y8qR[[-j94KC]Du)0kkP).r=?\(hS+a>qd\9KT(%s(VfEpfG``t^55/R,E)'QS/+8=M;f<5:)Lki?9=5Fr7ae9DIBm:?#B)bI!B"mr/aD`qt@D/2@QK#np>rZtSalV=.\?$D;bDr$(F7?Ye&\,6ugA,MWkeQleYK%^LK+Yuh:iI6CkC>)`ZHP#X_sXra$9<^=qd2Ns]<7MEIp/O5,;8:)\UeA#=hWWd%dYstpW'\s/QO0X$P)(f_2\3Q"S_mkuZY-@KiP`+E#-sW!:Z/9Il:L/r4ojO+A8^3UJ/t:B/`Xb,U\EX:uTF^=&0J>=CWHfAR)^D"n??jeTI,JQPEC'jDK2UfK^?['`'5E(E&,,8nBsAbMS7+\+u"T0lQNem3fm0JhDB._om!^"&0d,IUVF#VHt+'9cFZWF'_-l)?AE,=(g[c:at$d.(+tqAi@iPa.XCQp=(u+CJf?2`ib=10L3:FA_$,fhHH(Cso,iQ1^OO)&457d,9;J,b^L!Xfp)+C]jO&$W\_/bQNfdD89H:>Vr=@1,FIoWlTp:/A)R[KUIZ0-.m_r\RK]n;&[8+@mo*OP[p4S'G[Kof5a0WQmK%:dn$(_.Q^u87V/m.)jWiZBqna8`/>f$endstream endobj % 'R82': class PDFStream 82 0 obj % page stream << /Filter [ /ASCII85Decode /FlateDecode ] /Length 426 >> stream Gau1)?#,'H'Sc&ar=A@.2e^E,C)V<,&(sAV/^#4ICJ2]aD(BEeIkatc@7?T?5sg`uk<,p\\:)H3itROY?:Z1>ZN8>'$tb&,1EIRmTZ_$nae\VfP\+/)Ec,Z^#;DuhNS/_%?fR9^S8)P@Bo>Qk4%FKK+(^(BQe.^O2/`lkl2;Xu!R'Yf@2Wnq8693e0l:A,UQle=C9kDoW-h''>p3/:S;J-*9,g<'F\5_&ik1/A;-5V6k*HX^8nA!dCqY,H-f93@UtKCF-^@2sn`h=_bHf/Hibb@J9^=I'M4co;?d!q^3HTbkb^QO/IP%c)oMg=Rbpc7HqR+ZSn=0+B4(hE\S@ZhMTE^JkrT*N:gs)pS1OrVPTP/X'G&afPGPiK]95/'rendstream endobj % 'R83': class PDFStream 83 0 obj % page stream << /Filter [ /ASCII85Decode /FlateDecode ] /Length 651 >> stream Gat=&997d\&ABCZ+2/t(YpKtAFmP$'-!IQH%R'0t#nFHjG1JB@q=h9k@1,E#Wa]+kBBFQbQm/aVom>BM6]TQYJqh>scj?*_TAakJn%JKbs(#%h-K?pT&Z6lkBB-q]SgWHf*q+oE8(dK](7^u[16Ph(#%<[X3/]S>PqPEJ7lZrlTRi:l@UGd0(pp#IGK>7T"SueN$K=_XD)V7#=MQ?/5>;IHCrJ.!"o178T@5biO++b^&!,&@[h?$d=I7/`7k\kP.[2%P;G=En5UC/QJ9gn-',(PA`9AnP-8+0Y-HHm(bQsWk'OF8&kjoTY`:AFJ"Cnc[&I2Jm,K3iWnn";7(]p!6fbmb5Hon&4#]6t2]Wma9GEr[]a&W>;(W-,I*L&RdC;`Db&-;u8nIKMVnn6`Y*flBKpM%^Qc>:]_hsmma,AM4`X]u=3%s$HH[*lsGZe[m23!dl*ZM)%dUoJiZhl$LpPl+>D:*ODXDJ'r[r!]hk+5:;0NB%h(Md3tqj47Xe_P2Fa/@mA:l>d!rd6Z;k![9l,tc?k0pPnr^8n9>(FQR"gm$mb@m(gYn,3Gf^`Xj~>endstream endobj % 'R84': class PDFStream 84 0 obj % page stream << /Filter [ /ASCII85Decode /FlateDecode ] /Length 2000 >> stream Gau`T=`<%a&:P.Os"F`Ti2"JP>i%bD+DpD^JC?!QJFpZCYnC-deeFJ0@9NWE1Wr.[FU'O.'9YoScLoGm2H]`mS'T1XIN-,]dKZ2YBF;2k>Spba+/A#F^7!/^Ru*@?Gmhe]f0c>NS?[DG4F>lr"e^;5i3;AJ:f=:^i3^f9W]$0%iEkXM=q(&1?1j,\?6_LnR[7UZFtd#NQRjpcR*K@#U70oA`$gm+Q8*0WIrVH/.-D3YH6LbCV9bPs:,4K.7`)3U)KKcBrL$Rp/\SrH2E04XsuFAQUX4%lXUO%%HeFXEZ_DYKtLC<,7BFi=!m*+Q?L#YCYf7/$BVdY9lnO-!Ai%]O0t%%XY2Ydf`i[-])/m?['e2XC\j$eV)$'U)`dkADWJ4f?rBh3bl$nM4D#QXOXN%mu4LF`Pnr""@bQfDB"I>++sph[Kj)me%+j_^BN>Q%CtAn%,*76Y^*cMqX'>pE1#s<'bgM4Y8Wb+Rq^(^C"m8oX)q7ON@J#m6HYA@Kc^i)mkTqg&Z0)R02^a]/1kJgbWZn>.S";cr(qO5a$Gk9]XhVROFuZaAe;:kuYpe7*lnnJBe4uC[V4Pd%$a4NMA@`p3t==dRS4k#2)I!>7KWW(3IX>!2m.a%LrQ,Xi@om="KWu^l[<)f@QmDa4<'O2)TM?;0S2?02'6:7NROdR@@Ru1_D;CFqtIJhdOef!B\:P43Mc#0[hHBrj#2A)5?l?X9/bWd!;oq],4Gn[EmNj18RK1mTg6FP"HA+;?dCV'Xhi-+45rF5[EN_0kYODUMUd)8X!O5!oMnZOF]_H'K+9I$mt3"e2P/W1\cq8AuG7SuP%(?!^%EtibI=jeW9.*;">t!_tjCC*Sf1-kFI,rf>#\16h4uPPJ2&[c98p(Y"74*d:S-Q'F4H$*G8#a1]DqDC+_e[>rVm%JEe0j1)Oh"MGd^A>,M,e?"""]2q7N_A'^.2CUccM.5>GjQ(s-1iL);f+_*#E,33SFt61jP-?9[`bIB!iJh-WafJL!c`]W%BC;Kdu3#_n7ifk`OW_H"h1^Gu5)kn!br>^3]m71u7LAqnhr;rrLc!NPk~>endstream endobj % 'R85': class PDFStream 85 0 obj % page stream << /Filter [ /ASCII85Decode /FlateDecode ] /Length 1994 >> stream Gb!#\D/\/e&H6"/s5>X?=;o\JWAdHR[\<$<]qE9s`ks^-?Pn^,[7I#AdS]u3G=P65e_9Re]!dG,/$aE4QfjsP,DS#QEr1'H_[f\UHHq('0MR(Eb_,-fphBTo_-;9Vp2/)\k(\>4EsMK-<+(8_:sIsn9XT*Jdsi;?mC2-KQgi2jpD6oWY-5YiGkpB@"u!r#6=:U'04EAfL+IX^YIE?4X5*tT!mW!F7mdK$k!Ynu:3bYc'&np!f$#k<9K'o$/G/fT4B$MXMAWY+OIarc2-C40p%i=TdX&:)bB*.mTCKq4%'Bj&)07^-%,8)u(uEUM]`2-ZBko)dTPM>_R-UE;:pUEW$-?ac_N*9\?1>IFIi-O>'3M4[`!Qi_TGE6TaJOZRo1Bi+/J:gu8Qq52$<1;].*F04$'VCKZ/$uJ.p-NmAg(Tk'bB)'AR/+bbX*/6Vfu%n707S"Q^P5'od$n4pH&$[hJ<*`euTWZ1H^nZu[!DFmL4;S+j@2A2T^AZ]V;KN7[EA!'l+K8-V,;Cm5[@n%0A=,+>k4FCAHd,)GdkJeaTb8i>lqSu`W3qR$A4VY5_u8GK5nREL<%*Pn+WtIQ,!:&o*+WmkC!^2rbB@)='M)=\Y8NdQ/g]`:&JLOIMVSTBu))N,`43q6-Nq=CBW<1'AbVKPea`\/>P9`r1;6LJFH($UNeGN.A'jNeTK-fmk\eOY>03`p7d=3W/oB`ri(aIFX^t&aIoVre$7SkqF#bfanTA*Hp!e#0PoD8rH;S)Up9mWrpF>ZI,oOmN/,Z>7SKq`+N@%=iZ"uXWk&A-6,#_$)+d7UQOT3ucSRQ-YYHC)-d+&NcmIX^b$.obqfWpd2!*04(fuWq^n>?PED41d.cU+d&[+IVa[UM+DjKuT$#@#\U%34pGeAN:4;Ao^Es+U[_M]_Z%GTah#u;u+L^UD%C7RL>m604JVhIGj="%3b%-L;9ZPWfEGgeR9U9a2^"BP;b!D\n@V2io%.sc(C1i)Q7LTCTCI5JUJC%q6\W+R)q+N1ZFJu6SfT;=KtA296OTTTFV#Y_ASU-`,6\g1@^e5)P,#;L#7:U3J*gBRrur(Z(=$9Z?>:?&*s!o^b06(m8Ukao9:j"SW:lmH/DVI'K)co0'H)Gk_OLi_@P1W+iRXQIr(/s:/+&9\G?%ok]rd_$,8Wf?b=YT\u.7?B6a405LJ7p7f~>endstream endobj % 'R86': class PDFStream 86 0 obj % page stream << /Filter [ /ASCII85Decode /FlateDecode ] /Length 2329 >> stream Gb!;e?ZX[U&:\>In$'i2b#&a2EFL`Eh*>0SB$*q`3-`M<7^85si)i:NalV:79!Y!IELioeNZNF[>LotNT74DQ:h\m=CAnEYGWC;PY:*3P"r!Y8dY5L`>RVZ;pgu.Ic_e':3hGY'cQhh;hruA&FTS)]@Z95h(R>RR+EL^=k7\@BR=iu_8C-c#3&Cnl\pD2jY8j3P/HY/S!]btc,#[b1#%+H^k%hU,#d4JO0;"hA?UH=$lMMBJ.lQM92["cRE*?O:C\6Ighhm3`oa:D>PkYa]RhV[:n\$On@9Z7HUsn`N2;=qa?Rs_OSm0b'C6d(4!cnrc0e^JJa@SLuf7uT`R`;.[Tq=^(E='&<`GjY3:kt3W^KI7BO)=c-Xi'>JT4.4!?=(G#]=1k.(P@Y;>"rn#Y35V9933dDe(p1.2d-DA%T/D[WFT^r7`T-B%!!.8UqdL^L_P6[U6GamC.7%oLLh1?TMd+8Hq\0DU8%H-k4$Hjfm:p'=MQ:-j3S8u.b&D,^R:\hlpuK5:=WRIZMk*`G<%6aTo9,3jH@FAnIG/j/K=L_(ZUg-i,i5`J6suUV$!0c4.`-`+&D.n%&HH+!KJKri3G\Y&\sF(DEE'8p8u#AYB((uorYbQ]oB:D]fV&;hSir0kE]HB[-sY@p$Ns.[8kPP+furulO^ho))uUeS92TJU'X/:OK%(*?uIheb&gXB0i`MTq0qdN_\O8aQq%Tn#1Z%(WTpSdd,fp^R_(e1,bME,'2A'cJTYD\bjDo,,SG"=dm;>;?Q3To)/`176r-?9YUX>T#8HCaF?k%!VQ"OQO.AkQBR;-uY&,s/R_0U6QY2X[$rP2mMlZ`B:f&BBIk<)>dYm#6IiuHTG1fOoZhnaIGl[V1`368U-R3'@7f;=S*`j3HCRMsfP./7EMDRI46Bo2P^Je])UT&F4kr1c\HU;#3Qd1SskK]R+S[q\poh;@7\C'EI]g'gkqpe9W$iacK,0fSl:E^-)!365Q&jgl6b*?Gns8Dq_q<[*_=o"!-'Ugi5,#[%d\=\.T,@M4*'0>1i;ngQ"6:G\C]+]J0;Z8a^N=T:jM`]D`Sh:r)?.2H0cX$'.!3RVaD)%XHUGc9LF6=E/u_lJB$OWW7^2r3.^;3pMd=h)W@>Y($u;IS9\m=?*$nr^>4"$P^@&So[/is8[Zana+PQIJ69?[BEMm2,Dj7AZ)U$g+jR8G?69`]'dfLHPnRFPn\GC/ap0qu\Nc.GA_)L')F8qT==W^=s9U.eNC:)`)TQsiNXAPB(oMtq\>5W-HjC;SU7BC(:FJ5.4(EPd8#:,A)Vu~>endstream endobj % 'R87': class PDFStream 87 0 obj % page stream << /Filter [ /ASCII85Decode /FlateDecode ] /Length 1170 >> stream Gau`R9lJcG&A8=iJ!a_L[#?G:QFt9)DU8AtOWjibLB7W2;%dZ$F@\Hls8C6iZ<]Q#;kmQu/NifpMc%/BH=29T-#l-(MSY)N;L55N43KI=5,oMXs2MfCnMRqOYi&tG<0pF'TI"$giq:aYlAa#qB.*^CX4g/EGD]o(g$nt3WCE\)H5Mf`GH%-@]^tiAL%.6M8+U\YQ>BmpML,/TFT#]C)kPY^a8^'0Y*D(3#Y@uQ9[L&.tH+OCVT]"f;:X]k0`J8$"&+';'p%b#1GedIH5SUI_Jgb+HN58,bhS-"WE_NE5jC8sB.5$2*LDV5A:2LfD9a7Gq`4YbM$g2];](c@k89D3mF!u]rR;`W=oEmk1iOdO\/#,CE&1$\',`i0f7/]KUm_)W350+!62\e=:M%E1YHnnkHAsI;qMEr%7.mnim%)JA>Lln>Mbag<N5eY=uC9[u8jE-al%;>j:Pn*2_MdOdVd`"/fSQb5S3]sOknbBR.qEW$O*Y2=WlGAc=l&J3YZ$%WHB[KC\k,.&uF[ih!'<6mOSh)drhs``nJ9l8Y,k.m_"56!f4jmU\[%.Is)U*>5JO0mn`_M*#De(L5[[q\@Hh=g+hT0k@c.hrY:crhI*\Kt\&Yu\r;P*8Y8"?n"NsUJuV&LBuQ@tY\llQ;hp@"o"QpT'FH)NVn;'N9$,=I:%T@+F)#7Nd.FkXfL*hTt'"+fP-R4LI[!pMBdeV6'b'7?^V+OH;25^]63l3TNP>@\=j.U!Xk>$9f6dKN*TAW()JP%fdNeH5k%H;Feo\8FKbkDR$0./p$Z%J4G1jHI\-Rds'\#`dYEU5';HFWYA`D"A7YT_-Qm$-endstream endobj % 'R88': class PDFStream 88 0 obj % page stream << /Filter [ /ASCII85Decode /FlateDecode ] /Length 776 >> stream Gau`P>>O!-(k"p65FfD%"=?ml-JmK8<]172=>Peh^)6.BhU8nn%]K9tZe[H<(bMbB[+=N]Qg\1nj%omP:&X8R*$6u,%4PtH/-h/+N9h1LZbqD#5A7BmdYL;*5K+`k6,]M9T'^F2.:(73]ACTWiINRU><#)M$Sk5>Uh%7FbYD^_d(TTE)ht#:UHf%_J=`LEO;0uHp2`[LY6OA<^1:<3B:hX<(kq;I+i-%.$8?rP42ttN`[SLhj'hoHk%0+cJ.`Vq[S%_h+\Q<\_K1^>8/*=UAjDMi,;(0S^T69tjLd*=[:\3f85cP/pBq5hh(8NP3T@8=kXo!/d7u8*,seh@bO/uEg[fUk7VXPP.O-FA&s`>Q=Xh3405=@tIo4jAZ@eCT9")VlN#Rp!H7m4()j4DAH=NBhSt@7Z>4@[keq"TM],Nu7RMWpUAgX`YPr-pX1@>;n#f]ArV2HaB=]i.DKj<0i`6Gm\KmF@MKua_kPqIb;(b1Llq0V!,BcM^V]XGRV0,@gn'_7T(2Wbdt>pZdp[ut^FDR$Zg>f1Ebi`lE+^]SEjue&pi,gpiNYMJKeQ.9mIh%B`lh8G;nlt9JsOQhGC+[p/&&C`E'NCE<4(75Y>).<]CF:`[,15eiP?TeZ+"!~>endstream endobj % 'R89': class PDFStream 89 0 obj % page stream << /Filter [ /ASCII85Decode /FlateDecode ] /Length 1274 >> stream Gatm!3%"$&9^Z9qIUK47N5b-7Gs!B7s(;^RlT3mWMD]q"!#]JhMRH3D=[BmpS;:;lB7f>X-r3YL=BC(.KpmmTbJ`&_A`s$f`Mu6$1?eH"tF/ce7R(0o%3*oZP#\P:VGoopSe2*@S&4G5d+#,6s\'gHTh"6#J"R3eBXkKO'^Q$G5!8FGr&'5-t'm;dQTs3R:i*Q/G$P.UWi^Ae3cXHqD)f6f8t56nD'cWJ6WpKKC!W*JoLm-CMH:4ji(Op,ph##KD7O\E1//f&56Qd*_`K_2$7ZNb?uKZ>j/WHl_$d4OgV6VR&^EZcak;\[/9;E7UQpcGU@@%d'%^fGPVYS2I&/XLepMNlC[1Z*Wi!E42h_cK9ukdg`V"=k?\6j+]7^OKmB`V<\Jh9\b@TdoLI3)S1mhq%?n1Fu:5=9VTX0>K[b7i.`ecJ'6";].<*^Nhp&'=Gjf/)Ik5hQE;:>=A$9\UnuSAE@n"nNGH0n\aUN:QV*k&^N.geoV]],EVWpeO3`>SHF,Q4rXV&Z3J0H^\JcjR&eC]H!PVr0m@H*W70WZHI:#1j2<-Be"jg#I]q+@EJJP5.t5.2ma(T%;hkj6fTS(ga9`gW;e.3rMZI0S#AK0=OA@o>=S.bU-Dk2rA9A;8P;SVZoJ1jh-,s,"LTioGD.!$:P;%gsVqU3j'.q\.8$E%shVmuSFr]?PSV=%p>Bi2;N8k3sU816=tZB7su1A)APCY;6,XjP[ZC\[okc$6RWf]HVlDAS"Vm*t11(Q%n[)QXUK3E3f'NIdPjE)2^i2`doPRr-_+d28IG-*#G60nqhmhendstream endobj % 'R90': class PDFStream 90 0 obj % page stream << /Filter [ /ASCII85Decode /FlateDecode ] /Length 1712 >> stream Gb!ku95iiK&AACjJ!d"C5T#W0D_HP*VHY/HP/`gi]uUt+CSQY0d;ac4s1LctP-%-31RJAh4:b_C*Wk\-.I[\.8'a;`f\c?IW$`;PFH$Xr5TH7:^VUQlgB7&Q]`%ZVg7G6f+\=hA6K&\b*cd-QM>&WR;%l[(1\L+#Ij5[1S#h5.Z?=#@ZL/`^`8g%KXA/uE$G;/uq'i^qt4U>Dl^Kk4GI!5f>K:>Y<"E&f;7m3-UoE/>TpQ6fYWop)PEnbK*lVQRsl??B%$1g:f;0ZfN>f8I(AZ%h!GA!I<4M,=EFmto<"FT3e.#gWZV3UD,?YJN.sCF!:BRo!I[(rKXW;2c*ff-oo^YJkRIC.f24*n`?+&S2QoN..R"dL-3]Ba@dcORT!pVSd^@[aD-g*FAM0rkQ_'Hmp60%?+7??",Qs(ANu4=F<)3SD&pH/g,$Vjj>=]g32or@YQ*2[$6>@J%]X81U^:1G\^%N=cUGb[!^F\E,uJr3Z5\Qc"M'&",Z[`RY77(\'37:pXc%>3-oX2Wj-\OlOPb[mnH=FF*dJZ9\__]Gc/l!&Arei@C1f@GUZnHR)>qC^[92CcK-`+ON#!lnKce!cS6:f'iD9&M%C,]2%:kt%[WEUMN[rEKq3jZ9q$$Wms'^;R-"]J#K4pD]0rt,$$+u5FO,\@*Sp^QAmdL!Pq6_1Z&:0;,lL^a890B8NIoR9o4ok*9@=IMKd,H7umq)&s2)fKFQE[KY!sol(Bo8Jg26dIJ'*?#/!X5mSEWqRNA>JU\A3HH;`$q$>q-XkoRZR4G=2CZm&'88&l+Mb15!@+^3X@"'bAEN-1Sda:(Q(4]&`n]p2p)p/U]uGVEKU2mF;]pe`sVrmS83p&2UQ"Go2J\&%jaLLMpIM2BR4SE_30aHO^LaN%Vs#\8bpG&E05J]XP6Fd7PV]=ocsL:V06o'\*,il%B_Q!<"5JcQlDg[B]KnM*3$S`=4N$lr%9o%"qhoh_16rk%:$`CXAr:QJK!(Ledl[e\dREk;jMEDU*;XTi9H3q"&het`/f=NrTEZ=G@ce:6Xh]r:VEK/J7RN;b0[2[7<@\J^G/B*9S:c[P'@YgWa#(_U;?E5jh*b)WjhNp%rsDnrC<838'#.[r]*`R&U!T[mtL/;!WmiGG5I.)\i,DeRbbW<]X544#$`R4O8Zk%rU'>9225:Y3g3r;;jeHP2$@I&,a"9mF!So9X=#0!,ml-?t!4endstream endobj % 'R91': class PDFStream 91 0 obj % page stream << /Filter [ /ASCII85Decode /FlateDecode ] /Length 1875 >> stream Gb"/)>BALX'RnA%rkk-fOgYim^:,cMDO5'MZCQ0]6QUIa=F`=7;qlt"2uDM,8@APOZ*DAn]$jB@?u-kJ>X*WtKL-3!WVS]J_qP36q\1H2_$$].9GlR#DhH5kYNeRJd?GQfE%MlBQh1^4E)%/]r!EXXA.#?7^!/oh5PY2Sqs0S%O@Ja(?(\n[4r%adOr-<:lgd*bUsJ?![CH!:D4sh!g)4PsR6tM7Il];DH@;FXu:Uc`_FI\$e[Q8!2O2Kr*g%>7&?Pg$!C-OnQ#L3bUPK*>EFYFU0)]!,ZpSn':u/ctY$%urAjtD?>8`L>`6M];SmkX%ZLqe"TN#2m1-88QP?%@fjKr"aJieL*^^;/4Br2Kd(_:r)86&E`0$"CVMA0IZsD45FV':sU_sK+7t*,uKMQ".\\5[.*&6J;3[0U4aEn*G:q5cZ2tE1!>!6^l)qC;FBt7lXY/RV^q!92r>k%0Gu%3WXdLMc]huk=`a/2+Xm_]VA1:tUOJK2=E>&fZSQZDK/.K.,`C]C>Q[S]7)_+kF.\29:U\`@CSKW+qV4Q2=J`l0cZ^bG5BMFKm*endstream endobj % 'R92': class PDFStream 92 0 obj % page stream << /Filter [ /ASCII85Decode /FlateDecode ] /Length 1244 >> stream GatU3gMYb*&:G(NIi*!/Z3j]0o$'.mV+r[sccJCYjra'[5Y:bIl'fCh^(EV9NC[BnbdPuRFK;&&?0?Aj_D"4j4N*eIO:iJ[BHTi<8Vk8$-B1Rk&/uk.Nm;F4-A4J"-g`Gs+E#E-YXHWT<%!J'M4DjE/j[Fl.41G\BE>c!:6kD^;@/]rO_YRTNZJA\*YL]6q72mZA1:]&9=:3[u!fHn_!L_lFW-?%X'\60^VQVbXTG5%R]&E]0h2iA-+/1s7[TW%[??O1lV%P8W@$U6h,qE+I;(2Q;Ubh5McpL5Ddf!!gHpGca`XYL?o7W)r*^M0*!>0`?m/.L%2Hm@JKEb3P?-T;"EFsa$XT#`H4r5sDeO73GA(6(NhM&J-hn8;6t5Q4Y\X"p\Q-_lh"#F3+6V5NA8/h#o*LBg_0iH0Q.pA*Guc$Y!eS&MC$rY[EtRbb)XP&&_P=r+rUk)c6!.HB1W;$gJ*:=P-*Lqendstream endobj % 'R93': class PDFStream 93 0 obj % page stream << /Filter [ /ASCII85Decode /FlateDecode ] /Length 1869 >> stream Gb!Sm=`<%a&:P.Os"NZ#@`W?QnkP(:c/GH`OsVoGLVb\pC1V8!6fqfW..Z7W];-]N(+GC2Mdm,1[C^L.1HU@c_8'EXs+W8@%,g-.!bDqeJ6KmCi'"^ZSj'^803Y!Fe0Lo(Hf0.e0R_D=g?&DqVs?3lq_g!t5!e=Q,L.YX$Aj>E-D@1?l,oh6%h`n$gYd..J2J].Bb2q4<9gll)jjR"h[/1l1I8XYYfH2bgeUP9OA7gX)"+:qaTUi1H3huE&W&h>,a$,-n79+bBS?7:WPBEhr%]&Pb]$+Tg2<.jHWnDFB/4g3TGqRI(,aV-oose*Wf;ZW$!!GS0hsai1[[T33AeL,%Q"\%&(H3@eNtP2\Y%G'0;(`oT:#<[>H>GFGcJl(g0G9hRX(?#3qe$:c>&gZA@so3dt0G5??n;XWR9uHrPg@k[4:cS@Md;*04[o++pie[VmZ94P01Fh(p^++!HRA=eKL+_;EpO$psH'ZKG8fp6CFUM'L-Q@%nV2MaZ(X\^t1An9ei53,Kb6Xi2!od-IVMYFs:ii/"5pcaHc[5!pUTei*,CqG\r.$[N!fG#1WP63md`js4E:Y%C53/<]2d%(mn"FYW#>\*(#V\7hPb=#;c8(HmkaV5\Vj]mO]]rDb='Q^\-dn:QI0G/V78Bn]:Fr`[:*3a4cG5`TRFNp&M1BA$DG-Dm5QJk6.(;'2k/S4EK&:*Ad(PHeWJE)g%FXmU;k3RYH$*\@X_9bY92./ETf>l0RF/7oeE,(^RUK2]Ke3LTeZUrZP"a(C/UZTD0,l$cV+@H,YtP0tKUJh6Z(\m_\[3#EkEf2#WgBWF[Nbp1)RFi)7XcH-qj45t36;qe*_i)?,9hs##YoD(0d@S/84s1aP_QdJk*%l[NV+-2`F&:mMXb`3I]RgmKbc"[%5(+2T$3bQ~>endstream endobj % 'R94': class PDFStream 94 0 obj % page stream << /Filter [ /ASCII85Decode /FlateDecode ] /Length 300 >> stream GarVJbA+pK&A/t[%s(DG=aMIJQEG(>H>pYHqLO``8Khs2'QWKR=-Dm^V*u$/41dR!7d;meF1'&H78bmC^i$uG'PrI^)b5Zkr1D4b8a8tof9AlP$\uDi^m#'G\Tij-*4b'VDJ)MP-@:P8'$K&iQX,5"h_6J_3;"Lm*WTK(dJ*(=*5d6t",:K8%cZR?t//8(H-a$rpJK"q@$aXZ6$ghh$2WU6gZCD"q#S>BJR-lng(&`%\FoW18E`Xck?V>UH^bX>GV~>endstream endobj % 'R95': class PDFStream 95 0 obj % page stream << /Filter [ /ASCII85Decode /FlateDecode ] /Length 1180 >> stream Gb!#Z?#Q3''Rc%,s)?L9>0.G4Dn;uAS)%]ROD:8>a1P+8@+,*CR3A_5otTsd!USas\B[^s`lL-Wgs:&eE%0H7U#nEgiA,tB.gjdW,Qmiau5h8'BZSh5j/60Y-1=6)OjNUl?J^lMOQ\47YT68JHlnK;n"1ci'g0tQ%JtA/PD`G>d`dc+]Y[WmGag@5#,Vi42@[1"&Gi[BpK67L].7gj!\9tni*/=hBq!h4uO,2p$,`W>_[a!:aiq9a6#9R&l1^m*13kK)@+HIP(KUr9pLof=qTNArc%;:AgDM&;i0k",/Z]50pVo\5`JjE%MV/\g1H3L7Ejh2o^cO;;tKh*;9(VJhZ##\LRS2ECp3>EV#S-G$EIi1@njCie4!+1Kdi7X%:2T6K*ABbIG=)ep/h==':[&@EP)PmVDb11OJclN2:HI[A%\na&DUi*!6^71SrIC&QN3c@M8=q\SER[K@[Ch-=GBN:'%102ID@B:OajFm-2If\>R,Bj~>endstream endobj % 'R96': class PDFStream 96 0 obj % page stream << /Filter [ /ASCII85Decode /FlateDecode ] /Length 1210 >> stream Gatm:9lK&M&A8=iIi+gpmfHog8tr+tdDMhU\%id81qFCR$Y**n>=nHZoVP+*s5"nFfrN&W5LMq*'p7t0]GYaE$n2*1s*%Y`q[BXr(bcG&%P/kKA09d.m.0.oIos1KZ%)sKP^l:1%FQ@glu2u1Z2P]Yq$?FRPhTrQG.WKs>#2jX_ENa9YS*&>S`"Ua$1Zluc2=a'3Ze8YVo39Kj4!9FeP/ZDt3)n+sh$P!JpBrj/rsj'$_g&jdWOQ?nAk4H,+0OWZJ%(UZgR^:58051Xdf=pVu3&2=Jf0Ma;2dTu8BVho'(s%=>il&5S97)=r`"q-"C<\n,\MY<[i5Gt.)c`X=$86KV^W)L!]TQ837^[RSa68#^HAR3=O7L.:"*dbj70q-Pr5DFH7Fh^%$;(B?CV>s4NW&arVQkkZs>pu%SeSk"Q$=jVK03s/>1,aTM61oc?(p^+KnMmZU^+%Eo&s>iHmdJ=g3)I@=MQLF[tqWK02r@.,[sRXr:;E28^6+[L6dM"+lD2(=m($V-Lo[+Y,*mIe$>fjB$2!og\$&)B*0=lGODE>g6O)Ar3VT0itQEZb5u%b,fEQ.s8".>H^N#VB3Y;Z=rra$"RY[I@N?W%5bY$ijNSHf8!ck+"6g%ROMJ`9T.3u`k@+pRBB0;U'1J21na6YkFsdhSZf^[Ke\(f]rWq=IfJZT-)%U06K+4tiOEXX^Ws*HaNHTbC?FnX$e[AX4;(EM6TWX*L&.eVH>Zbj;FMgUqOk'_?knc?FuHWRl>PqdpYh31l"M(q(F\(<2`lBGr]V.<_`i:C`6rK5AMNRFhYgQ;*9C[^PF*X-,im^'EEp1i&bY(LT+4;B%N5fqc&l*\4I/ij%N7![Y`"$+"OMia_Yn[Ae\hBKhFibV7Y>A)[dgm4eY5CRS%@In1m9MJs\S&)#kKFmT1\B2M?f6sLcBPTV7=h9@`V"B%CLR'#V0me,#UQkFVBATuT%J0VM0`T_niQ1oY3b6T<(4,hoqeg_(Dh6)irrC]iGtJ~>endstream endobj % 'R97': class PDFStream 97 0 obj % page stream << /Filter [ /ASCII85Decode /FlateDecode ] /Length 1579 >> stream Gb!;d95iiK&AACjIi.h=/fI4/>A:^)9m=2Q;BXZ&[pEa)ZFQ)c/OdWo'`IJ@;R.8gI`0o.J0mUaLn*Ed^A2AO$4d&5q_p+ch%\.!:nTF7F.b_e@\ULZ9![iuo_YO[l>d-MV8C!=d8(k9!s%N\Q*<<^=o<;N$;.#h.+jJTfQ](?+3ZN09$4'J.X>OI5H'PObI3+.+GlZC5iGri\Rf*,8DE"_X6[/O&2e8Tek),5;*Q[gpJ.3a>5cGp+n)"j]%s"j5hgaK\K-$@SA"MkKARtLY"*DYoX[LiUkP;FOSlT1G6GlZlr[J*\7\7RO6,ZBNCK;j%m)!u1fH&6,OT.cSG0&TYiF1L4:d47%=k'L!KO9]Pbhf9ZtO,!Yu*`J*1)OU'%Cf6`U.EZmm+?JMCjW:+WW6as4@jGK&P,Pj%,8TK;E0D*"\1Se>BS.Hmn$f-&,e1V!G+527=Q;&TM0IU9!@2QA.&NL?cG4(hKcL*rpBr`.G/G:S6[C`PHbGs9:LA8W%GA9#M[fFgb:lSs5^(K`!G+Ge,9oQmbYH4f5IW91=*<2iu+`P0/-hsiUk;XFj2:!N@^7QOF0h*g5.*2j-]8g?tZMcAopCF]s?i#'+8S@;YrTe,^TVMPD54(LKDendstream endobj % 'R98': class PDFStream 98 0 obj % page stream << /Filter [ /ASCII85Decode /FlateDecode ] /Length 952 >> stream Gatm8?#SFN'Rd17s);F#*h#R]E5Wf/6&J*kEI#X2J*poWdh3>Lh%K-iiOS%>Lm:0sZ".[bbNo7JZX5bEu:7H89$*d#.:>[AI%3h="Va,Z/YWHfSp'_':fRRE@SQmRd!qAV]d'!)27JIYu(j=ZZ[?Vl,Jb(qTmE(LAcXcaJ%!FL6OYpk[>96P;Gkd?Jk>?Oa_etc6]1AVJr(M@TDH*!@/gfj7^V0Zd$^1?j`Lc',k"[$&nU6E?*sYA4$/Mgi6S`Ae#)P2EP$^;=BJ,*m/KsOY?V$n6[-D]^om'R32Veu0g_0'TrU'Mt]pZm3[qendstream endobj % 'R99': class PDFStream 99 0 obj % page stream << /Filter [ /ASCII85Decode /FlateDecode ] /Length 379 >> stream Gau1(>>#&Q&;B!Lq]F*n'fqgUFuP86&(O^7WkAQ%C[JQ!Z1]O>pW[;ebEfGPOs,LH9[h%DZi4n$jMNg[A1.+B2V1!:T!a<7_Oft\XM&QA550-k^?=XAA'sYo_:UqI8(4pO-Jjj+!ZI#g]TXfO/9eP?f8qWfe%RiLiVd=a4)W?$sr`tl;T.FT9,':=f[&Q.jdNHJ?Ii+\'e/=I8D!M@pUc""$_C9$cL_;af$I\cAVoYZ6K_AqGqLBZp,UmiEjn!i-"hY>j(o67u]Hir0t1]i2+!0k>uT`Pfq!>NCQBr?T'4&JH~>endstream endobj % 'R100': class PDFStream 100 0 obj % page stream << /Filter [ /ASCII85Decode /FlateDecode ] /Length 1295 >> stream Gau0CD,91O&H7^.Ii.Q#DRI!Zo=d8VF9fjg:4!U)q/RS+`[QWh/p7VVnCJNtD0T]U4%'KZ6tZ?li'mWt?splbUIF`MJK$]Ti*b:TB`P_+O^s!>U^X_+AoJ,Jo$6^WXqN2Bp.4>\fa&eCP]bj`1&WA]UW`UsNBSY.m==;G,dq,N>P:3pF/Lq;e7t$$>'?KV:$??940,AemQf<]80O6tca.^d/Y*\sC"%q1)-j<\V2A8Dd0sL=\;&&-T+/0nI]/Ej)E1`OD%UkbUNETQRbSj!EOGL<1%6W/2)=jbC)^D=BkTuiEN1!*FU4Fe$_%_<\F_Oj3d[XQZN#:0<7<<*@j=jl\f`O8e+b,ZL0Z6X$][F$IX]:($$B<=\UoIEe[WNbY\PZKIF9B8WCA6!\n`1J#rAYc$qkjn?Km;Nh5j6P-KeSVDI^50m_qA[U2hg9>?1-O]ZS"B0Z,C@^S&fLs"147oabZ)LZB6r3?t\+.h'j87OYf[HeM(&^JIC0i%fHtq!PfP_:[?X/Ue1#Ec??WCqm,&:8WV^e"u]-g')n\B;*pD$*lf^PS[Ym]D`\.J[K@c9mP,,XpN7%n0ht)&o7,;Mr6V?<6!J;.->W[sb)U7$Zm!Ncoa^=UR\SrF*p&PMaWn`UIE5Tf!?>76)^K>=+X5]2B^dc/^S9,Z4Dlq6saOgP'6NAMp!&:2XbN:J%*tVA>N#<[^MT>bc.[1iPrWNlPsX`T*8!`4^q]2.Tt-$:UXi.86)!(?Nn9`?#)L6R.an:rfsWlKq6T!UeMf0;CQR"l5!u>CUi:CEfAaR8,dKe&ANu%-:%.J*BR6Vg)nL-%3W@32pq)W1K4@di&I53]rr\Drb%C~>endstream endobj % 'R101': class PDFStream 101 0 obj % page stream << /Filter [ /ASCII85Decode /FlateDecode ] /Length 577 >> stream Gat='bAQ&g&A/tO5>5s3OjG:$M:/eSm2XouM:Gf_H8%5r4WI'di4gp658#uZ'*P$8K&#J3lmsS*o2.TI"hmJD9dhDWF:[XL(XWXUUZ(.Y%_@RqPS5*_!W7I-4QOB?p&f8&pNsiKH[$SAbiSHs(QuRa'OZM+b5K\'72`&U!KJK8eEJ@mh^7P5^8tkN(t8N1fTmM@g['agRrOOs\>BVR,.gLX,HOXq#k=XLPJHKWR&O&N[G2G`0dHe.j*'.MfkQg2Z[g4]6:37Sa5X07LD!+IQZ=eGm@pM;n,<->A$:8X2:?6Qd;$4,A;4WIZ-j/mY4C^XV%8o[8mTBsL)a@PQ/iTq@Gin@2d.NpBt-UCdS_AhS"TP:HfC'Bme9EH>f%59WS=p_FjfR:&\64db-tDaBZj(a1b4FImm#XqV:9LFH(104loG2DL7P>:0QOHZrbo;"glED'noZ"cqk@RuC#``$8=_4t\ZNL<endstream endobj xref 0 102 0000000000 65535 f 0000000113 00000 n 0000000259 00000 n 0000000424 00000 n 0000000611 00000 n 0000000859 00000 n 0000001087 00000 n 0000001396 00000 n 0000001563 00000 n 0000001842 00000 n 0000002121 00000 n 0000002415 00000 n 0000002643 00000 n 0000002805 00000 n 0000002989 00000 n 0000003247 00000 n 0000003500 00000 n 0000003744 00000 n 0000004002 00000 n 0000004231 00000 n 0000004577 00000 n 0000004857 00000 n 0000005137 00000 n 0000005417 00000 n 0000005698 00000 n 0000005979 00000 n 0000006260 00000 n 0000006541 00000 n 0000006822 00000 n 0000007103 00000 n 0000007384 00000 n 0000007665 00000 n 0000007946 00000 n 0000008227 00000 n 0000008508 00000 n 0000008789 00000 n 0000009071 00000 n 0000009353 00000 n 0000009491 00000 n 0000009715 00000 n 0000009841 00000 n 0000009988 00000 n 0000010196 00000 n 0000010343 00000 n 0000010551 00000 n 0000010710 00000 n 0000010869 00000 n 0000011078 00000 n 0000011226 00000 n 0000011392 00000 n 0000011543 00000 n 0000011701 00000 n 0000011873 00000 n 0000012086 00000 n 0000012241 00000 n 0000012420 00000 n 0000012599 00000 n 0000012748 00000 n 0000012903 00000 n 0000013073 00000 n 0000013241 00000 n 0000013443 00000 n 0000013591 00000 n 0000013756 00000 n 0000013916 00000 n 0000014059 00000 n 0000014261 00000 n 0000014404 00000 n 0000014559 00000 n 0000014718 00000 n 0000014926 00000 n 0000015107 00000 n 0000015256 00000 n 0000015423 00000 n 0000015592 00000 n 0000015757 00000 n 0000015923 00000 n 0000016086 00000 n 0000016229 00000 n 0000016355 00000 n 0000016650 00000 n 0000017231 00000 n 0000018596 00000 n 0000019166 00000 n 0000019961 00000 n 0000022106 00000 n 0000024245 00000 n 0000026719 00000 n 0000028034 00000 n 0000028954 00000 n 0000030373 00000 n 0000032230 00000 n 0000034250 00000 n 0000035639 00000 n 0000037653 00000 n 0000038097 00000 n 0000039422 00000 n 0000040777 00000 n 0000042501 00000 n 0000043597 00000 n 0000044121 00000 n 0000045563 00000 n trailer << /ID % ReportLab generated PDF document -- digest (http://www.reportlab.com) [(\226\304\243\331\214\257\323\273\003\366g\336\240\254\333H) (\226\304\243\331\214\257\323\273\003\366g\336\240\254\333H)] /Info 38 0 R /Root 37 0 R /Size 102 >> startxref 46258 %%EOF pisa-3.0.32/doc/screen.css0000644000175000017500000000073011160170401013414 0ustar wmbwmbbody { margin: 2em; counter-reset: Ebene01; } h1:before { content: counter(Ebene01) " "; counter-increment: Ebene01; } h1 { counter-reset: Ebene02; background: #CCCC99; } h2:before { content: counter(Ebene01) "." counter(Ebene02) " "; counter-increment: Ebene02; } h2 { border-bottom: 2px solid #CCCC99; } pre { padding: 0.5em; } a, code { background: #CCCC99; color: #333333; } code { font-weight: bold; } @media screen { .pdf { display: none; } }pisa-3.0.32/pisa.py0000644000175000017500000000075611160170402012175 0ustar wmbwmb#!/usr/local/bin/python # -*- coding: ISO-8859-1 -*- ############################################# ## (C)opyright by Dirk Holtwick, 2002-2007 ## ## All rights reserved ## ############################################# __version__ = "$Revision: 221 $" __author__ = "$Author: holtwick $" __date__ = "$Date: 2008-05-31 18:56:27 +0200 (Sa, 31 Mai 2008) $" __svnid__ = "$Id: pisa.py 221 2008-05-31 16:56:27Z holtwick $" import ho.pisa as pisa pisa.command() pisa-3.0.32/._CHANGELOG.txt0000644000175000017500000000027311201057400013124 0ustar wmbwmbMac OS X  2ATTR&*F##com.macromates.caret{ column = 49; line = 32; }pisa-3.0.32/ho/0000755000175000017500000000000011201057433011271 5ustar wmbwmbpisa-3.0.32/ho/__init__.py0000644000175000017500000000106211160170402013375 0ustar wmbwmb# -*- coding: ISO-8859-1 -*- ############################################# ## (C)opyright by Dirk Holtwick, 2002-2007 ## ## All rights reserved ## ############################################# __version__ = "$Revision: 128 $" __author__ = "$Author: holtwick $" __date__ = "$Date: 2008-01-10 21:26:42 +0100 (Do, 10 Jan 2008) $" __svnid__ = "$Id: __init__.py 128 2008-01-10 20:26:42Z holtwick $" # Also look in other packages with the same name from pkgutil import extend_path __path__ = extend_path(__path__, __name__) pisa-3.0.32/ho/pisa/0000755000175000017500000000000011201057433012225 5ustar wmbwmbpisa-3.0.32/ho/pisa/__init__.py0000644000175000017500000000100211160170402014323 0ustar wmbwmb# -*- coding: ISO-8859-1 -*- ############################################# ## (C)opyright by Dirk Holtwick, 2002-2007 ## ## All rights reserved ## ############################################# """ In the near future pisa will be moved into the namespace "ho" This is a helper for migration """ __reversion__ = "$Revision: 160 $" __author__ = "$Author: holtwick $" __date__ = "$Date: 2008-03-12 16:40:03 +0100 (Mi, 12 Mrz 2008) $" from sx.pisa3.pisa import * __version__ = VERSION pisa-3.0.32/README.txt0000644000175000017500000000140311160170402012353 0ustar wmbwmbHELP ==== > xhtml2pdf -h REQUIREMENTS ============ - Reportlab Toolkit 2.2+ - html5lib 0.11.1+ - pyPdf 1.11+ (optional) EXAMPLES ======== > xhtml2pdf -s test\test-loremipsum.html > xhtml2pdf -s http://www.python.org > xhtml2pdf test\test-*.html PYTHON INTEGRATION ================== Some simple demos of how to integrate PISA into a Python program may be found here: test\simple.py CONTACT ======= dirk.holtwick@gmail.com LICENSE ======= This software is dual licensed: (1) GNU General Public License Version 2.0 (GPLv2) see http://www.gnu.org/licenses/gpl-2.0.html (2) Commercial license, see http://www.htmltopdf.org for more informations pisa-3.0.32/demo/0000755000175000017500000000000011201057433011607 5ustar wmbwmbpisa-3.0.32/demo/tgpisa/0000755000175000017500000000000011201057433013076 5ustar wmbwmbpisa-3.0.32/demo/tgpisa/tgpisa/0000755000175000017500000000000011201057433014365 5ustar wmbwmbpisa-3.0.32/demo/tgpisa/tgpisa/__init__.py0000644000175000017500000000000011160170353016465 0ustar wmbwmbpisa-3.0.32/demo/tgpisa/tgpisa/controllers.py0000644000175000017500000000373311160170353017314 0ustar wmbwmbfrom turbogears import controllers, expose, flash # from tgpisa import model import pkg_resources try: pkg_resources.require("SQLObject>=0.8,<=0.10.0") except pkg_resources.DistributionNotFound: import sys print >> sys.stderr, """You are required to install SQLObject but appear not to have done so. Please run your projects setup.py or run `easy_install SQLObject`. """ sys.exit(1) # import logging # log = logging.getLogger("tgpisa.controllers") from turbogears.decorator import weak_signature_decorator import sx.pisa3 as pisa import cStringIO as StringIO import cherrypy def pdf(filename=None, content_type="application/pdf"): def entangle(func): def decorated(func, *args, **kw): def kwpop(default, *names): for name in names: if kw.has_key(name): return kw.pop(name) return default # get the output from the decorated function output = func(*args, **kw) dst = StringIO.StringIO() result = pisa.CreatePDF( StringIO.StringIO(output), dst ) # print cherrypy.url("index.html") if not result.err: cherrypy.response.headers["Content-Type"] = content_type if filename: cherrypy.response.headers["Content-Disposition"] = "attachment; filename=" + filename output = dst.getvalue() return output return decorated return weak_signature_decorator(entangle) class Root(controllers.RootController): @expose() def index(self): import time return """Open PDF...""" @pdf(filename="test.pdf") @expose(template="tgpisa.templates.welcome") def pdf(self): import time # log.debug("Happy TurboGears Controller Responding For Duty") flash("Your application is now running") return dict(now=time.ctime()) pisa-3.0.32/demo/tgpisa/tgpisa/templates/0000755000175000017500000000000011201057433016363 5ustar wmbwmbpisa-3.0.32/demo/tgpisa/tgpisa/templates/__init__.py0000644000175000017500000000000011160170353020463 0ustar wmbwmbpisa-3.0.32/demo/tgpisa/tgpisa/templates/login.kid0000644000175000017500000000572511160170353020176 0ustar wmbwmb Login

Login

${message}

pisa-3.0.32/demo/tgpisa/tgpisa/templates/welcome.kid0000644000175000017500000000506111160170353020512 0ustar wmbwmb Welcome to TurboGears
  1. Model

    Design models in the model.py.
    Edit dev.cfg to use a different backend, or start with a pre-configured SQLite database.
    Use script tg-admin sql create to create the database tables.

  2. View

    Edit html-like templates in the /templates folder;
    Put all static contents in the /static folder.

  3. Controller

    Edit controllers.py and build your website structure with the simplicity of Python objects.
    TurboGears will automatically reload itself when you modify your project.

If you create something cool, please let people know, and consider contributing something back to the community.
pisa-3.0.32/demo/tgpisa/tgpisa/templates/master.kid0000644000175000017500000000402511160170353020351 0ustar wmbwmb Your title goes here
Login Welcome ${tg.identity.user.display_name or tg.identity.user.user_name}. Logout
page content
pisa-3.0.32/demo/tgpisa/tgpisa/model.py0000644000175000017500000000104411160170353016037 0ustar wmbwmbfrom turbogears.database import PackageHub # import some basic SQLObject classes for declaring the data model # (see http://www.sqlobject.org/SQLObject.html#declaring-the-class) from sqlobject import SQLObject, SQLObjectNotFound, RelatedJoin # import some datatypes for table columns from SQLObject # (see http://www.sqlobject.org/SQLObject.html#column-types for more) from sqlobject import StringCol, UnicodeCol, IntCol, DateTimeCol __connection__ = hub = PackageHub('tgpisa') # your data model # class YourDataClass(SQLObject): # pass pisa-3.0.32/demo/tgpisa/tgpisa/static/0000755000175000017500000000000011201057433015654 5ustar wmbwmbpisa-3.0.32/demo/tgpisa/tgpisa/static/images/0000755000175000017500000000000011201057433017121 5ustar wmbwmbpisa-3.0.32/demo/tgpisa/tgpisa/static/images/tg_under_the_hood.png0000644000175000017500000000765211160170352023321 0ustar wmbwmbPNG  IHDRD#gAMAOX2tEXtSoftwareAdobe ImageReadyqe<PLTEŦĻs8ziǜsljIƗji3٥sުd@wIrG߹rwCoęZ& ]KڳtS漡Զ½mDzT੃]{;˳bQ۾U:`LVs)ѻJF!ׂYm]1|XFʬ⽑htcxC&õѾk;!xK4O$iZ8ͥ]zS&AvT|f;qCSY1|̱ǔiQ㷣bLg+ t3Ƒ\cƻմֻԴW)㸕t\nuoTŠ}ωfT‰P˿{R=eڪ}Qi[`.hWʾ~MɻtN#9 ؟go@&A_3oG1±x._{>~ ЧpͶbj>L.~R/ϝnǮ÷KFѷfWǢX!ὈQ, 0IDATxԚ XWib@N8h 5X( "EEb-T|Xj-"j}`kJZ1P5ƾVִD{gɀT~/K{933ݼtX !Z9&hI! 25_1ohHhjLQ> K_^L#%z5Q#0%CLPW8 Zɛ9ZW_S%V<@۳5I_Z^xgTԌwΟ/+?yA%R*0t aeeae11+;;ls̬p րx'{yՅ 7y R 99{kR?, =?yҤkx]3ik`mX)MtLQ?FΤ.gt90gW^w^{\\j>8x^{{mܰJ) rC3gmq \ (l€?z'Y3241ec2t{;I p9UL.Av8!KA>dryyLyۡGcA3)8d`l8s v @.czy~#lB29;OxW#NϞ/nT)@]ky `E jö_~jI\_w>~}PiRk/zok'^ (.•oY~˷+Ǝ[v68!i;>~((=zZ-LV쁭[7o98B$W}4@p.f{W7W^_\L'ÑC\ȕR3@9>pWdDԨnf{2_8rʂYW;@ yGe/葧(]_{{e}MJ<\'FipIΔ4Z7ռز,)QLB5%0AlKYIU{ݭ>}ꖏZ7Urޡ;`ktg Lpy!^i_HϴgA)䜵Bae5sdQ555m?*%_1E#V*GML hn. (.xQ1?:*:jg|TH k! I+RDg~T7TD/Cz*y'OX3Zۨ_s8)ݖҠੑӾz5UVV/u\E>ZSP`)u N<󣍯guE;e)13%*x H+OiS8W씵Z՛"ƍE5-€E+Wsp.NFntrZ%'}\6qnܙe9=Qr1w1Y玔qJIr.񔢢U;lt"8eb*4*;#frZRKuf%9`jQ㫢 01կ•NY i)uW)M+hgΤ>X:6:cP i!7龚Z_"zӀ_|@E,oFhZ[͛RW@%mp2>րa5vn3฾h: ./?wjܸZBQ5$SOޑ\dC >eZARB-7&Uo&G ERAxGRy`nJ"6I:<2690=@> vF _mw!@ rL'Ʌ::q![o!a5m2p@ 3`( u  2 7P_wXlr[PM[hSRщ0F$жK\BX}/YMXʞãm ڟv]$#]Ϛ6v[JAh>47v".Ie{副O Ggwv>/NSa*Dru.xJ']-]s],t͡5. ;\ )p"p}zA'l4s"TddZ}vhN :.^blw2`&^̾iLoZZ#gх0ꭤ&SyI ks+7',Z =91(ItxD .Az lYI,:%5}h!b'2ǰ&Yz [<"E<.o;^k6^Y8fW 'a,6j{ H< z"ZQ PbL@c1L0gEgn Htdt".'a D0} -Û0,4gPтɬo8KP-CfUZ)nBr A$Q5%1\օKD\zM6ӣ @+`p{VLYdmk ٮ7$KgnӶ4ւ͠ j?ZtԴwGG$E LUj|7%"ܞ#LhrO`f"A 8F%X^6Do4P Gz ܍q#s$҂Lϟ@7~VLUh]nzzczplOdg; Z@[l-fX`0VZ<|7~OF`6­h]!!)@yHk3;[̹ jj5t5[Nߺ= ~lIENDB`pisa-3.0.32/demo/tgpisa/tgpisa/static/images/under_the_hood_blue.png0000644000175000017500000000515311160170352023630 0ustar wmbwmbPNG  IHDR(+gAMA7tEXtSoftwareAdobe ImageReadyqe<PLTE2|٢a=9裏e}ֽĴҏ%ØIꮮפְ]B҈®̡̥ɻȡٍ]ŷzرQ׿ط|-Ðܲ㖬ŽdSksYIDATxbh h: hen#.@,SU^%~}=%aPg{ ]48g +ٱx ۱@,Y%~^35`UU~^a^~~d,@ \h)y)'&0I g qprp\ Yc̨UP6`.fx [MH2X@&P(](͘Vjjfʘef1-!= z@u0=jj \< ,&@pgpˀ a`bbhmejmefj1[9`,]L66 3 ~l`y h7H!\7'#P.]:jb^ B 8C#E[[mZ[E۹Z[[[ڙ,t8VFm~b@70K2V10s'͕ISh+ HMbat9 D# bRhmmbbomjm``omMlml 2J03ImKjgPTL,&0A5°Gy0gsshY@!"ʺQTHQA bdĹݭiKk|@"ncfkj, G5Q["B(50zYMR-NYVD[PHXVfVFy&LA^j;K `hE y `h@>`1 հ>Al7hHb'$$0Krić PFHu@PAIH"7W,fA;`h)#_UY*q'BrH# (;\E٘E\ ąxDEm;\32:KRK]K] ۈ h$ P3D~OVNZ霆`Wi*@Hbb,l "" L[RDRRdbg ZYU|B Aqq-!f&yI!!Iynnfy- fPO ԌP"'Kp]eo..YlL: `fWoL@A (ldfu ( 6 ln: deaQcDyRaDq B^ 'W3ǫoг*jBVYm6 J5! %^~acAVJ("Yr||rAr|Rrm|ArRRmmm\Rj*Жm9KԀgMUMU7U,{ ]h @96.6) V֐ocnや;)' RkkאUꎠ2CX5V5&-}x@8 H1# ,8P@ (k/P!+(("koꨐQ uYR\\jgoGv0١Β%0DA*a]1Ks^MA^^V^^^P J", Ѧ J`|Rĕ4 ))m{n\:X(ک *QHu1Y58@E+QugF' ֹKvAAWAVg/YSSdi0g 88[K@: Xr bh8 h u@ Rg1M^@lIENDB`pisa-3.0.32/demo/tgpisa/tgpisa/static/images/ok.png0000644000175000017500000006223111160170352020244 0ustar wmbwmbPNG  IHDR00WsBIT|d pHYs  ~tEXtSoftwareMacromedia Fireworks 8hxMprVWxW[0ᇈFxl$܉R%7i ڻY$U k]Z=#z^ۮo:뚶o붏ڮmq.jQ7}tm5MW7]|Mm]`0 `0 #^׹dzOs?>P/Fhv&m)/MJ)CiI(%l k#(Ӯv+@'VߛQ")yRF~- s/s{nOKNN{̿ 88f|9I~`RN+g/^Yqruh =So`\ 7+ԣ؉>hl% (mBWE迡d(t m^ `t[ka 39m;k! -xʓL'dTxtFN|p;_/Igz'H?`c>n˩^VwOF (ȼSz'kn-}TtM~8z}pc4jx)Ip޸7\ZхR?<yii Bz,+s5YӉN8 ߳e.Od.:}{{WT}q \ ?ēCrB= (i'_?tG5:4Lao\+yMsn62=|g0 `0 `0 Gn%sDHmkBF)3mkTSx]KZI&{*,4BXL^.ۛ+c0"*]o:1`V.pb4BWWXX!C#!@lXDwqBs\u|\UG'S>vz~Sr65zmx7(jE4kxc<ڪ4jQXo>l4{]ـ3oX>Tkmul]]4=lԡYc`3L/ȐQVUz?O1t扙vN̴YavcW3;Qؘ n 6 a`6d Sb( @9gd3t2B&KPؐC/onz}Jvx$6VPY2UL [5PC*< E| 7[Hkn *CtX%GZ'5v]0JC;B +d } výBt˫ #'PQ-&b';R5[f5@_ƪVM7]1zDNQP1!˦>Q+c:hM=mZ# xi#EL ^L^+9fFL;eūrW: IL9]sb<H8LGE#Hn,,> ,.>4RC|5\0K/sj|<2`Ow 3ic%@"DCm :a ;}]iF5,Y85!c:!%PR-Ce1,L ~h)il CP-z^M"S1)8&818x*V")s$Y\,3 LdӕWEÎ<'dѳ\-ɘQ`Ȇ= AO|Ozz Y8Z0%]QvOi $%y(4x1M ßp?}x; RO5d̻43!'n`PymhEGZcQ$!䞙oo=S]j _Nw<9aO<f%Όy'V LJ&NYޑ'ds^BB =~An ^b*5R>Ė `q5Ndh8G5}-MC@~L˱:х,#iLà ǵĀut-Ĩ?4/ 7n4D9DqOIV#"JG&p E)`RS.Pu?^y8c3+-ŀk\?$L0 %>aǑ,%H7XC/CmBOOĞ 4CYASqL NI<,pby9mV9q&ԎAŚ6EJY:£(ɁIƷvJELC=HIA7Y%=&ͰS8S]*{x"œO){ć;4֮ai/ӏxy1!cr1 )B3Uɝ{BK;/0J\6I~).Cf,&BjcΰFfF[/IJW,hJ'P ;?GL' &#ZW杴Bv)2wSYYKZA ?y4#^d>i妗l2A4/mUT>q~գIB-Mo6bl7J/U-hof[ :nP;.q5$7|z2(MK:7|jwJN!Y{-GjTnt5{10$;\4h|QX{U ߛz_/yZ\^vM|쮣jb!ĚxG`߼_R,s*&(;?%l+BJ?ڳ5oUFϨ+~GQC{.|DKaNg|KxGo&/Y?cыh,4qO7o=XB/c#t z1x+cV/7i;$ Q7'_9BvwnܡI'q(҄jNuUe-Z[9/LtƎ_'ş gNg8䁩G G6i[Bvd-˷&=F4I?I3+^Er< O4$R3z!H\Zp5B҄>\tY|me=iǿ3ql=8g㙳q!g㜍s6Ƨt~sF5#[9#猜3r #7\|z9#ϜEn9g䜑gd?LQ9:Ysst9GK8zs'dk9䜜s999䜓c*N9g33rbFhr&`|&\o9?w.6v̄"q>.g㜍p9#_Fg匜3r>.gLsFg}q9: stL/'3rN99 3Ea|&\fFP*y>'6YY1+MV9[ȨCGOܗfq&}t$h9ڥ^=,y|i%pNOJ5 c ѭ[\>D,q,~N!Gt\)ܨR|EG71Σh6^o 8c|YsF9g<ϟ6#?0V)_0< `ˁUʣN9h-r?˸ 4DLRidi+e1RiI3.3ցs@o瓿CV~5t_\c'p>B^~ktVz:t>*Y<| ]ȧP>)=^Kg±җ+~KY1fEE_ y|;x=q7C3^Eiے}F&d,@3 [jWGODzеXyȺOg\cGC<(ҩW?Uϯ%|nd/GG%+E=}Uħ_l]~.r#ewK¤+ޖ"jCh_GMM$gF>Nv7%h_WZ!!^C|OƸs33yWd眗s^y9 ˁ?~pec&Ͱi,,T1C4vGҺ_/\Ecn}.1sDj͌|{_O){pCqgJٸgڅƯd~z?Ipqɷ)?bY@Vw} e^*V3HgoMYIu`,Vd3EfT-__My#ez26D4F% Kc'19Gn\p~ >{5s)0\˸HƥoBlOhjcJ7 ?_"_]xQ`Ny'"[$%|~@>% bw|$$ s) h@8#3aE|3^ooD³KQè?ҙqO|7dqtx\ X矆u#4/¤AH3Hh.ɿC^${wɾD }zs{>7 a%%Grq.!N b /uDh떟QqQ,MVRS\,ߛ> R+=2ė|99i'GO?[tϭ}Zs,ZZ}{O{?ze17k{ljJiDgqtA{1ǟĭ]Ho`ƉYVZ7ӮZsF%]7YHe1.,w6GՏ^C}↕QOf6~8c*]*ŨPOר F Jbe璑v'_O]£wH'pKd\Sފ3P='VՅg4{7^Uty_5vutpĤut]k"+ؘeYIWok.I3{k.y-},~5Yx|UJ9}<|m\#wC;`޺,$F]X6Jm90㒭S3/ ]7ux!CxC똣\/']WK-mRPUH~LRh zF!.;1$6{45V5|64pScD^Kj~% ,c8-f߱жIw42-OaNL=/9fQr*ύ[{2zV5o'1 JhF݌eSiB1o|eP=$2iH٠O8ݮ ku_rh<'rj=^{WiUzجרi:|kڰ֨.d6Al. *<ʃ:[p'p.x~@pw=BM;kT׶}}{thgpW7'&R,+֫RbSkn?dWˏ}CbZ辵|z;_/N%eÍFlw`l= Ǭec?8 DQmT`m/$"kz?mRM(mkBSx]N07xS#WCJ4M8\f2;Q%aϩ:*I% :kXn´ACR95įΡ;>P4Mvhe LeJXZ1P6"%3%Kgŏ<4 GD1@^'u[ mkBTWx흍8 FSHI!)$FRHnw HYx3ꇤsaaaaxIǏ'U{o_ھgW9 o'GW {>~Jlo߾)*/N\ϱov[iZ_ձaJΝ/:6O- 92b?Tlk%?_21B sY5>:>c=1Ow y^- ڶ,XzusM#גU]>H_yYv!ۉ_mi Rus]Xm_g)YY)m]y,m z1aaaxEߓGקo/Y\k6xjgH|yu.\aæM&wk#ϐ$?]Mo\Ⱦ,/ڥQ@~6s?)}, l gX #vQg Bٙ^uのuhm?}{].~}v_J;xogJY]޳@.)oqC?}>@Xߘ'-(W? źvƔOʙRv[K?[A}?-wmՑ}g\=c}M ggg DŽ-B^k_g?F? v0||؎=ǧHPgs/hؑI t~{n^}ZyD5XWvO)"c0vY Z|~_%/,p\ɹyΰZ/;/xs_9?Pܯ5ݻ\[y|č8gʱL{? 0 0 _k3>z_\S |<)b|7aaaxn.ta?l^Cvkؽ#~e)3<3^kdlc&jK+o"e<.ʞ`^(3zu l+6v<ï k7]/lc[`On}򚄫 G뎱zt^v2)?;Wmr5ocIz?Ozx{&!ez."ѯ 1Gg{+ҏlw<=}GݽFƨ^)zIpG K֜{{e G12ۭqiumf>.}~a? 0 0 [u+7Svq֭y΅ ?ނ}XwŶv?ߩDZۓ-q/?߳=<~#>Fk"qzrQo 9r,nY[;o:)@-`ק-7({߯S@µK9֠ɸ>:n3 _[_*mtcmC>qSL=<6;ǫsaaa{xˌ\ފpx?0׋#5zяc]x^l򼠕(f:~٣^lin59W~\;?vn6erUbS~v^U O7O(|;+SG4|?f*?rW~2oNٟS9~daևmH6mX[J~s.ym4ٶO|Bd/b5ɿyU? 0 0 0 0 0 0 0.P~*1@G\⟿KrKXs2(ߥ纎J8'>X@▼QQbqwx b)_K|v 1M6kee-2Ǜ59?K^E~9ϱQﱮYF8N?~;:=J<-tĒyNAgC \NXKs)'^Kg\~2}6}Գ)n]Or^j~"{p29w6/.z-v:+M{WJYZ굢`% Ҥl9ힶկ#OUz+U?;sd~vND7*.Y+v:ye;8}~|+ÑޅN9}{Bƞ#txխsXɿkSV/uJ=o G<ջL'L:D]6jfgLz/+ؽ[{rCMYq~[{yy czA;w9zszWHVax3 % amkBTDxSv&6b3ShhM4DTD }Gr},^miTK`Y >ϗC1??fu`w 6F_3u?gggϚ U3b7૫],L h/z+ߧb ԠFb&Ŀ-w2rg!⊊hc`:˘?: ϰOYq+~t^/P^=P=p̙ ?nqt{Wϟ3.ySr/U~lw(:"=BA]n&>F~o1o9G"ܮk-b9W1ܕ޾?DFvm{o@"V.Wg/FK٣qh]Bcd,rwj(~r:BߐհRG{R lI{k㼸ޓk>u1ӰCpFFvwn{6v8"E?ں3` Z8 !yiC4tRwlU{i38 v=p>E˱=Rtn*;"Mk>bݯqgFfO~7k~6fڷ!f1fg{K1EܷՏBE͈jڦ8Gl&-D^Uyy1'? R&8ֶZ;Fog*a7kn&/TvsFLYn^RqͰ1 gBYYQ\nh߇qvP եOdHguu8߅n_5W'V?|c/G ZB?7CW8h*({|PPQ, Q}>_̅\Q+0v5GA没lYЖ`f %@JNX'` oN(sA|7OU=eOUWCPQaé``v @`^ B Z2{\Ik^c}Ni)(r?MUU9*s)sw}{|~L=~ݰeݷek6l~7$yo_zoN}s?oR##tf%1;}mkBTx흍) q ĉ8D^>׻gI@XjjgiЃ`0 `0 ?ϟ|:seQ3|ӧO|:2|.};7eGFO6_Qv]T]^ˮg{>pjzkuo{yye?{-x/ D:3D&򈼹e^Hyi#/OGzϪ߯_~ :sMe#M3Y#=2 QЙ[\s=E8}E>GȩT ڲTg-}VfoSVwzV}./>~!?U1<#}=F[ ~QڋBN..+푹^edLo+[\-k dW(}6q$#?z6Bөi?L7!3O_Q}Пuo[=tkȋM!'}/Ƈdr2_Cﲨ: `0 :8o=+8-4}۞cĥXdq{bUq©ήm!ƶg*ΪU\z[GA=^+ru{LV U?)V>ғ)x|Yҁgi\yi^cUo*= !TY?rfgWsʽVn*VX#=Fϫ+[F~yH\L~[O҇h5ݵTow|Sfӟ+);F;:x )/OS yUo2e)Ve3'wgGg=J^`0  ľu kU,Ksؑ5nY,bXw{ w&3QהNQev ]ƷgcH˞i{A3I8hwduwUIWq8I>+@pQşGcZ\ƪUߝ]/:3d;ɫ:gB9R|GW~w2;fzt|+i5nΟgZY|<1NyŬ|E7k?z/k><=Α}N΅>uWydʬdz `0 *\?W8GY:Dgcg< 2+'W6qn؟{ru"wU쏘~c#T?+y{Q,,^qF/Xv8.֩g3}ȸOP ~n%hUG4(_sn|W}Tg&x^c,Fѭ+ <#+}/Uw8BRh_|33!mr\7U9m({ѝpvew[xG]߱?g;,nҽow8]וb?OV=Z_#ve?vN_WrYLo;1g9pV^G~>[_vNOS3 `0Q[ veO\k^8֔v<Zbz\Opbn$~}oz3ј mK vU]^iNWA#x딫jt q :E= z%օq)CcYEqyRG-+u (K\hP'*^ء^q=m=y|Kvūe\rȊ4={W1;=ݷxp;o@>ȘT\Ԏ+C=*ɫ|GJOCW]x1.ﵠ9_Eб Vq)v(ʑ}[GwǺ{-oSdו_˞׃2;iT&w*w:g׭SOsj%Z[~_˯d֮+w]7 `0]kIu+eL]ւoA^;=GR?v쯱;<y o$N1紈=:ߥPVu< <&3KyC/4r)i=*/|Ύ^]QNН1qGw>ù{ ?Kv:A}E:_n+{u=rq͓̳]>>d}+|L01`0 leg:׺񶊝`W,3O?]\9P~[kOWiGc~)-<w.3q}'vuw$Vnv(r52S;Wk_Kϔ8B/hEՠ'9w?K;x:x<|@cϽVyc@ۖSw8Bq]=2lBe6V}eR( VeZT4ade2ޒ+nYBTqSߔ<[&=f[|szP)G}{Zׅ3n7jpWwftEw[ǽ;`l? `0 `0 `{~i`oLy>uoi\qK|}7Svu9G쯿c¾#>,jow{ՆݲL=mW2u_8دjo?kD߱mw>#}E:OۡO;y`$jwymkBT6x횉m0]HI!)$FR?6c>>~sm+vuՑνYu8uN?WP>1JsWiV_uKEϸ/rˆ_gKW]ױEYcl,[TYHT}xL#}A GV7^}>iҞ-i;}LJX&TP3T#ߨgJl e'=?͘ona|7>?ǐU%;/mN/IfQփz{G}?v✽3X~j{zTAO^ʰ>?sy|G)PL&6'tl~3~Ffv^|I>5.z {/_ۿpg4$@ 4F6 }Y>ΰ=Nb`'n ϳ%S }:eR18k KamB 7IE_Qѳ; rdL'm~OP! vP0AA6m(Oj:լm~OM '|,I:kP3 x[3Is 3.6fC1˽:GfF b_TxӐ zlM5wiK4 xl}6X&HdY|"}֩`+&OdOɪQqm~OV+rs[Ӟ*vrх؟~ +.fVrmPXK`H`)Evw/o{^s{}+ ?u1t#,s#8Ey}y hKKp/Zb|ų*]殻fV`p}i'*[43ׁm훑<1)F $+ ~}[ۀv찭-0GTN3Jo9Kt$}:ms_vpGWmt~Vu?Xnt_RV8eg?4ctO~=>9X]>6_ xH 9bo9,oWs>|2%|jԩ?T>]Ze8@ @>@81Hn=;vjQ﷿wEgF_^^m~O8Y󙦚X!]Ǫ S}tѪ$ӱ-E LXR'I_A`LAR!ٻo{EsNuL|SIቃ=9ioX1tڭ-3) B=Wp4 @61 \yG=?UA{ p#c9q 9 _b-2Pc@ۻy+03**s"*9H-Xtg|%?}*_X=>+ a6 E ;cFȚB2E"8?}K>,rv/nPa)ekFCI뜹sN@L K6' ąޚ]K+VMg 8{TDo{Wn> rf7$R\g-.TkEQs~o:ɗ +1ցְ`$F́\@yP=swv9y`g0k[jD=e>4VHSv ypЊ۵9=wu?rB8 & o{r6H-Kh߳[kP`9qG4XǟߣuKzЎH#9,q6WĻk1"Jo{vNƦm%$")̫WT[F'ql66PDK:}@Ep sm~OgO={Ua[@WwR3|bC)(6'(D\^rCW?e>$r-rPӞ6rs[f A>.l$\pL@66L뿖79_mp5JdIeрqxBXF5w# ,6'`8o`֮&7:CJd9[b6'Q6]͍GMsC|!lSj~rVɾR[;xŹ]ڀOkʐ`Tz 4#xw~tW[=CMFCz~*pWw+7PM`s2k'޲V"kȵsNR0\Yo;Zm+y9Hx0p Gm5/pb^ر,ZkR?eӶpk3E'c_ZH;w\F0<ȁ7S~]w$_C! 6'#ĿQ \c1'X zŵ_61@(0*WB`!6%aL> QN?KOJSp Nñ&Od<bZ cO Xsp1fhn]Qj%ڳk(9!ح-z&}z~f&Ģ~K*5ʄCDIQB~?{vmP^f5 =r0tI@Q10 u"i u汅vD'a`Mn1,7N6 H5 xg6ag'dk92y' QZs>:q8֩',6Xv`9 "RijBv-h+h<$>`"6ξhLf30o%2\H鿾>r 8oⰧ1<L-eOSI_U; __#0<-~?3EQƝ+rᖜΡ<r,phQz_\h<࠯FD_jw]^̓O~ ? e8$R(--<1q!y2oʁ֢ߪ:s|qg6(u<0c:':o` p=abwhıϺT,ifVzejwSU 4M,o{Bx|w$pIukZ6 w2rK 7D/_)MCXʡnS]Sv0_ |}GqX0ح &G=k%У!Q׿ڳ66d^B&h'3Q:_oo  h|vkyg&rٱz]7B{inH ;,~gݡwM_r3!Mxw3b\/:ZB+@qW8;j?\NrsO &t <|}9愺~ Կ= q<pMmuɺ}EGWvU@J]'ƟsR&SJ!gz.+"%pB H'ϑd6'씂X ~E//=xS<#___GZa<;= H\azQìеPg8vV< AV ۄZ8ZO~!s~$lR?m3ҏ;,52՝^_z ;jg? =8sI0 @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @44Բ-JIDATh{L[?Ɓ$$!P^Ihyf떤MjNG5mҴMUդiu֭]EI, 1ȃ1cl{6PP,Xǿs~{~ע^6mܫ` 3l2o%k6v} 6Jjt{kwrS!*{f=Ieyrql)Ϝ4weo Dɓϳfenɻ^kNt'3 J \86ˬq0>g> T/=xL-\y{\UsVM7+3`tP6N2H$lS?9)p=] كRP[pAͧYp Y l1dqEbh& 4BZ]Ĥ} @cLJbhCW rq֐d+'W )SYK t?OJ\Azw3{6%8M](ڊ[omaC N(qԝS4wB%g;G\ mt*\.cX2rS5MF~EC>\T`OO ߅u]\pT<ƴso{o|?=k&j>x|Fhy,S8FAi p 7adžZXlIIځw~4(-$ sH( Ғױ!o=?>U HL&J($My<ۣ/~kldn!qg,bq|J$@7iW4$022k}<[,NѶ khC)oR.%;p-Wiydk}D"Q( ׼F/HNJ/=Hd8G5tzkt vi,ɡQC~S|*Ql6jr`D]2Goͅ_A!r=!ˁwȎ$-n $,!'O3ҦUД,;$t7,0XPzH%`&VbfPي\8y~UO+l$[3P.]U^gҦ)%J*nr _"JJGf}dBm'VBYԃh6J 44h )%vUJ%oI /+2]ƒkcDPHT'<ul"#'!v Yh%<^OFvx !b P%H2{ ?/kɇU` \怳qdLO=̘s Ȼp'.< ;npAR`N87\jQ ¼ipV@(4q+>#\h]G QeAEë)7ʦ1+|rԔur8F&=* r|2PQdYgR vjnB>9(p #hϺT`"X5x KW 7t7sW$wdK&AUjmR8.$~O~ &9}>Yj(|᱊D~G ."px\:r(Ψe>8N~)a$(e1C#T,B9(^vR8 S~)ԩnL?WRE *P8’&$qq2dW3Dn4 .g cUʎxEn8?/:(PRhPEXT;y/~xW!lgg׻&q xp |WBRx9U<% "?X$xcx̂C+9 @bdf&LZΙoJ΂"Cu^3#% ɾ(1d eZ]?Wj gizH P‡k7gHm G`}(U=SpZ RHŁUO"P x^U)E Xd)FqUE@2j> aB;>'@vbŖO:VƶIavoa[@æ MƐ?gt#{dS3'_@›Bqs|&o7y W}_D$ B`Bq_5n3YA.S12Dv 0ikӠ9&n Dx V'F TcsBds˿@$PeD|#AmyoO]@!Fǡ}JMMf"EjB Jxf<衑($$23{NF7*A2fIR\Mk_vG,%'o$0 E1Q}B.ĭQĹ-Up͚QӐNe n"= ¶.ypwF'b@ Q1J.Ap9;97yA8rc% $_xa"쥞kJx%, % (t)Ť/0?{6'f-ʓ0X'PV0aW Rg?x-T(U_,RvfN **"OTj / O@% Q3f3IوqW^c%9QP,>!d1#yH0!}yK[,HF2ڐ 5H.$]PcZnƵ$2&DWyd!ZWȉ(Rǁ?7 9EfFK, bXD%]4+Pʓ,!i1l!~x4w^Ǽxc2rdt?kn/gxl0U i hȎԬFVO"OJy0qʉÊ&Uf B@Ԙ=-€#Zklvs0n U:XѪ_QC"7q|Y0e cA\bqܳECgnU5\iwjrD%iz507 vA=0 1vus˓j,߆B6҉"{8C~>YԜdj+({@J3!ikH6xMhu<] T)nd lY1YčFPr@6hD6Z5* Tr+RBN%(u:W#xΖwvQ(d< &է?IH0#|%qc=~'Hk]I*+,R5W5 d~aC34CcuPr6"MŢBB&6mnD Ѝ'"4n"\kSY\{E1q-4f@rń-̉L)۸(R !;ud@j)4d1%Q iD=$Q'pa#C=)%oC Ԉ[ &'4B5#8.J+*5jI('={5 @̌djO5*uFTƧ)P_Z@w6 @t\$'oڔ5 y$2+U|75¤eeGD@)ƒ6pCc+zɜx%2 &LH33~ӢٴL91h72P/*.e\)/Y&L]&(*bH3T}BJ[# 4C"L'"-mꕐأkk<Qj ;x)b+ sV.Hpj2%LJcV28*q{2F(= n>[$ETŽ3+̹ɾ],4xP2p d"+4^YU┸IrN6) MJ#1"fQq0 1CrUmI'ؙi~P4F871,T<:M1ư |~]xL&+Xaϼ1<'F4mp63 DtvV4="&n[8AF.ȕ@ *b`.Gٳ:1*I$4Pwބ& #&Y1)f6\WW:;,nu[ ̆@x6a$gpMzn97h`yj ﹤̬2%B79JRee.Ju1ї I@`dMf/ +dOG(T!;M%[Uag @t?^2 [Mr #SA .B]ϕ@>V$@yv'YX:eOeIwH_@ʍ級AAJbPvFLglo?f)#]Rd"kHiZb*t×HM͓`ȭՌdc"kUL:Ȇ*H#)mGۈmBHgt)N#iq>q CD#ytsJq}850 PpѴHhYzR ebn,e7\cL,Mח%6JDZ }$K%$5lK5`W®E $ I#`dh+Lwk7Yp0 DAB'yp(O~81ij1& +_a>,5QZI aFȗ2c.d1H>-/ 4w2,-4iy {x e-~f}$0pk2_fTd@̥ mYg9Xؙ2;"6^8oFs?{I+>T-l?<^Z^J[vs-1EL3¨]В>)s8K,AZHz}Z?nd¤Dƿ1~3"r2 Wxρ\Z ,+!0DOߊ_9A4hb:$Ԑ{$,\gS'B&j,#v5/9F18?'lS%TI)2IFX`5zt#3369PDIlL\ZLVpot+Nfu/ĝOo<,IH0ß8W̎|JJmAZ9ɥ h0|7u`^}azw%a<vdݒ bIܽcQ`!'q3O/oco=Pk1dC~G ςsڅ4]"Jr4"2OVq5􄷩'Bqk%j D%A:@"ФQ"Rp@Pq"emb"C΃ zsS{.4Q\s 5Ϝѧљgci(1=3E#GY4ddJϫWUq?st3xҭ0˙oUV|i}lc <(6o,Xؑ/^?\m-{x߸cs~Nƍ^,!@I(jPz賀GPSwRI,Ŕm'Y;L.Gf2j=0$ԹI] 8F^aM=~jNm<0\@A}|u^otfx>lÙަTu@9pbGK&B!3YL3-1mnMҷGfӧ'F11WBN*W9zsiX%:n9|wH Z$B+sxi=tE[:7OwǎArD5*1[/Z碔Iqr` IDAT|MCӓ{v~/$iFyʬ+QW8" 55dGf3KL;qv5 qk@j=CNIR0rc~Z@٦Xgk0wpO\]>ӎn;Q#ع(IdoS ~R7.]ǟݲ*&'!.T_\D}xDu+p6|]15WظprrP,i  Rj}CY:bxfPLJR$ q *Oq݈K t  KvbL^urh߈w'rO_>=?9epa4}X ˧q[OU?܎=r؃'׉\BMgfX[]{f+g^ɼ}LKH@:,g6"#':6e,Dk{GA#Fo 9 7ED"w.C'.6 _?7BZg{#>Hnq֓ k&6k!\c] a IH}9j cZ`N|fFd13"&8m,d~8^ s%3A{ X 6K[AIic=+2֋aAKDbb2\[ؚ/_+A<o< {2'`\Lsk3#]Ƨv'|s u\c@;_?鄨h*K3͋V>-~pq6/5o1oF+PN.d1UD2BYaߍ} C岤BN'!D^#"~փd9<=SYz5 M7ecHT !R<ȦɈٹ14 5ӟa =%0kjCE.:J@*"tВ_lis ;n%nVy7 +9I8|Sh˥ ۛb75[ׄ^oq7:0߄1ƕV= }ͥUIe&"5Q"NSf0<:E|]ن5 t+_Uh, Bמڃ#Ms 7ŒO]Gy0`aW .C7?mop̂E[KlC'#%=X֡nC'welA$=-x~_׆SuujeOoƅMigu=9|ŋƦfqƧp{q3CB3ipxә+іӝKƶSqpg"ù z4~y~`xb| ;~y/.^Kk{sh?~`'(k1 Ov7> } P,gB[p]sks׹ [Qy(w`dՃeR8aQVt{sД}GS 8\;{}82>-}QW + lp棺D1m0|&7XV)[.[̘*5ϋ y<h\^tl%Z; ~y{R9)fx/'c> ^!׏m )0;6fI,,F;M\':Y~o\_vM_27Ò$fh,l3Gqdk\rV'yx4.Njvbjhr8`eh<}E밠Uv4^U|Ql2S(֩ߛvL,}+P\9`,eλŌsޜ(,_sO&)3eܔ?>'uMUF,QIא 2C.R4̄MՕx^Bơ1)%ᘉOp q{P(`@̔,=x ^+QʼXE+CMأzrzrʟt\ W}~ҨQgoɞ|f (u^;?9-irq ~{mceR VS– O_~Tv,va_1'lDM*ٜb Y3sxo_*E]`m%pu8$&G|<_}zdg On]ҤMJ7Vӗt9mf %B)@7]r8֡i\/b`,hM{A] 75[G{`܁(WbTf܏oL|wVqn,& %22w"m2b?Jqj1vӘ)@ao6Cc,\Jp}#~Ar_tZ/#V%OY<;тcÚ$ ,Q5'9:PZk)Y3j[2{cˀDdH٤]@,( Im Si\v:1};3GwRG5nնlNl3#X.oZ/F:OZ.[Ö b`m@8@&D&ܺ^[7&3[qqaŽ&[aݖBW}gAҼBRLh#XQ|}s:J%O3Zxl)J2M&UJsX,Ƿ;r&:;ƒYa+Oqn#_/{w>z`=#kBԾbRl>7UrͶ j_a_#|PHb085NNXffdN)c k>[c@3-;ЋVphp&du] R+kL5 Т¤2~K'&lL|HZ5h3 <93dgV86Z? }3. BoĂ$&35b9s+yȉ|a&M!KՌEg&qB1~n9J\ ֒/&TܩB}<6Nᓿ٢єƻִhKLS>0j73כ7(Bo %8XkW. "X-h>\Ť13CZ[DH|5d"-[-ʸ2~˹T*}XݣsZ&`vZ }ېA8eEɜL PRAE(#H-XU2!XH@><V.abT2ic>Tz6\4bTf>ʞKjr>:oimCe}/ϱ:۞VJ [j8W+Z1' ^ ƍ[r?!ĖrVos FܓsuBrx"Xb cљCB$ €eĜAk}7dg4199/䌐Đ#ׁ“WUaxGqxt&N mO1Rf~|v(J."&X`i͹gY1\U+O@H/d O-\g"!]k¿?9#zO+9MZ/>4L8xQ|FH-BV^!h2V&|+DYYs#xg5O&ƪ_Y 0#bޯa13z5G9|gtෞ$ XpOK.eqi}Q7%]9y@.>KXk)=1d02Jz;b_z`-QY&fJokeZÚikc_+z @{~ F᭍.' –'LG)ZEo(C^&ta+4:wϳ"͛OB2w."ظ0tq1؆Hu€!|L3>{6=|h=2"Q{/XS;*c㝶x@pE>9|}ڻ彭xѲTsʜ \afבqi [Gp`lZ+L_+nxӱxiHHg`dafbTXQwR4Le #MD7ՅJ]YuWb ]WI9ȩNXEF!V$Lu)<|M8pqqs&뉷K [=e('>UU!ڴ(%.Bm94"U3)o B+WYV}/ɾܸQѣy,'t5j9 BYhs|W>v"~|!C141 XnɃʃfw8$oKHؖR|PdY$?9qBh8n#Ue;W.}/TKj@z#5m/H41: BCpbNRl CZ'r8zό r͸xP'x}_ikҩpxAGo\ǻӝ?-%fi}Nie HwjaNr+8p1\T ҎYc;2hNȁTG?@DuN#S4>}!1Fibak4bY{4SǭHgmŻH~WRp zvik"o?pXcN_֍SoZѡgeWzB{:#zp~m c.ȧsg'[FaIñ ^1 fЩ+␃eurQ!s+;g:( '`)kʻBDӳfds(vFs[#1H,f] bD i$Y|(A }"FDfH~@(21ZD0ce_ 5*qɒ7Sxhm1sNȢ+Kg.橃`fr8J9"71? JWW"=ѓ$力 @IIllFa|s!P& Vw.t^2]983t!}RR9 1ؚ±]Y`ak=EHaF$8 @Qà>]ۅl+ b|~} F_>+n?\+&'B\U'#7~@#<>-]+^^Ӂ:y[L5b]d [dB\cd+\BF+a&i+7a"ZVup&GI~E2 %Wq 3ik̅g&jɾuP=fd:P2#L Dp R`RP}P.B/GqMt?NH46^!,tq |xvȅ:őQ}lW+xU| VH=5BK=Hui nHu{W)I Y3cxl̵eV[񞉢cJaNyA&")l}dCA+PդnЇ팜{Ƨ{1{xй¶Qcޱ^"ܼy3ʔ9[}kKt >ugapZ)wca[]udqRN3i3!81[(%i#r .ofEمГ+Nƹ+z- -5͍¨,mK)K`xr?z98yQ'r)މaço~t ?UmU'ʭ[|w7O=K|Jw9O>2w=-&{f~_O\wM>^y\;7?-^/U NZ񻪈0WM˦Y;nd?%S )D8e?u!pEھ BՆprSa4F u]&r; a"<%snfٖkbI1x:.]d $7^`VyuDWR6<'Ma\k\!Ȅۈ(N"1hֱIp0Qklj$J^|Q3񏛎 LΙ;g[x ^kyHnh_L R.?]9TOi9siD@zdSsa@;qå'^{Ŧ=Sd[~~dž1eYkzsaBW巨Og'Ziku'/ݲ,Eo=rW&iɦpMڣz3-$d0>=k؎O1L@ eY3.LϨ9a}û Wtc)|E{Oa|+ L &I#1خ8WGi5P!AC`?sPBYphCsSx: Q! Ix#LcPmiTם'NiPAl0Q^#5HdGu0uʼnW5.֤Nc?!ܺinf 2Ў%0ĭY߼EkёKԁA_-ppmyq{30ZtcL&JB'fu~~"cYьW5{*r|x X3(տi>|:2(JgA,R [sÅ_==gFgGH6R%ĨZd_ua~3`٦0mÝ;d^ܼy`P8f=(1!,Ew ( h[nDm](NaF|鶭+OuYܖ'smMɃ mE>҈^m?m Ĵ!:tjkLZ@1<;*mdYO OO-J&J)T<2qj`qHI2%$Sx'@sdU,#J P&Xׄ'%{(#pk Is"(AQ[P)^u>X۝{gwR-4f9wbbv`!)VJ:B#(#羜 O,Pzv—E7M /+p7~ B{ɂM-hB! 㙽|R]u >MřY3'P@ǙkLB_>KgpBlT{`l o]D_^n 7aQLQ(߉-X4KFZgu^.]7םɯXӉ/>4B9WP3sL‰F%" ,}q%SX{#a' &VO[t8_fֻa!}f U)8Ah=YR;)rȞY4x/#%n#ƅwIAi7i^)'k"!<y%I1H%<0v9 P}׆Sl?t̖=y:9<9߃{1+:Z o> ֜#u3.=N85 ^CqjW߷:q*|ug36 hLY{k$!})[30>M)yF@D`Q t5ذʸۏ; H&G-ჷ7~g.AK&uvah),&k΃;as`=n|=q"v%dGNf[on I"yZql :ϼMY{ëB<.?|g &fP!X@;@Rgbyw =OfZ8yM59 8B݂(r_A!c| He Xʑ=&鶃"R.m7Q k 46m#,חkJܩZ8Pn@X5jd^x!_] ϛt˕LLuӦK6ㆣdNw{^,o4%ɃL`Mbf~)iѤ)=>ݵ)guɡvں2kiGspJe"jnuvad$!|aO8y0X֑ǘ}6VՅ cÂdцkS)6Ҍkف7Lz}J$hmVIQr|޽! yXQ/ 5B2#waq,̃Zn ơqӲGeaA!aWjcT y[ˤBÛR]\jfC gaT)&]#Hpj?f$\b~)hPXFԎ (l\TB f͍6gA3nN¦Ϛ]O͂(ٖN]ދW!$a욜 ґf^^8#LGa]= g>qӼs n DQ!xɤnN޾Z'` `|Υ{06WDa ""n| T2}ҽ Aqj(@- +5 ^w|5WCӖ+`&\ dsq^C laywɝ1*[O:^@||068=2|q)\mȩeȧppb2T8Aҙ|hbI(<]Mi4K9$%+gfU~,VZS\Fn?+ .m߸XI8\F / ܰ*W5*/"A nI| 796'OG2 #EH4ܘa93n1-pIɨ0ܬ!]42ML1&FqꔬY5RSl*vٵ|&cE< eShyƽ)d6$7P coKslw+x'l0 3J~ϧ#||yP=/S$ХL ũq)ݣv͋3 V~WHSƨMHʟj3fz=CZo;e!~8o7AjKC_& QG/X*]_T1A0O᪓9/"Fx+!m**R4P$3*"D 4hu;9ϕE~[ `0n{ ~?|vVv@RMxɝppkc`#cOi?k 1BㆨSfuY}Xeb#P1ʓPt;XɕUzJu"N,RGz@ LItI bR:!W[cRaiEP BHaVΌJUeTǩJ7 T\KGHS>crt-##UX$=p?1L>#]+Nfd;a$)u,0i)HBI% ͐bn9⌕S`bds,'nXIOUBbbl7aȱCÒ0/J}:1fEP3c paI9&?#꩚^CۑY`vD/l@Hk{qZWF^9:22\m`f"8W6> b6ii^tgS5 Y1k>ECG֟h}(jp>e$4"E`b?aMG5|>oY&3LaLP|'"-WۍLI{CBS݋w㢥-X\bWue&J*-āGf^]2 %ԩV :L_O1ZV^.16 ;`?fwyy z0)PYp ;L}#&h@R HR8w܁;h1#4tOl)]YM ;{⵵5wJ6x s>y4ebp9ydNhat :C=cSŒn~?~?_*f _> WnW,⾝16=XEG=▃)D+͉0ӄ=gTon| ?yg,+-~61m^?Бuy!T` yҤ~$&A`k# R {&cu`^q G$5>vbtĆcw;!Wm<#3ERs~;v "d,:r2OGf}>05!wceByf|NŻ1BG@rx`vh8k9]9|~C6:+0\sce+g+g&rM7m~%]JXfX\: ۆM#_6IHG W3_eq5/~kt-}Huj58px2ɥZ·ǬV12oV=81"[YO_JsbE>gc;Y0r`ڛemxf3ut o^Lt!6iNǬaٹǴg K;OabV URG\bK[NDW6rݜ' ڧ&ZP@*6RoEX\tDxӉCGqrHw&bDZ=rOZnyӈ@yπI xg?ߋSmЙ8wqhɁ$vc>wahbl!2 f#i 22Id3,A\/1EK"\i\0_+4% %%ktw!0\tra84(ԠְA:ɾ!V ӗO%;HԸ1EiD_γE;u} vQݒyڳL:,]X~ד(HwZÊk6#hѫ]~Ta)" p_=q(!I]xmCݰkNrmX҉k`ȬtWiִ ǚ@QZr.~$hA A(9a~ D"2*@wЇ1DSYf5t)k!D], $ MFrZ\.nKGM֑X-aFfn ) fڢ^G]uǙǘ<@z$?ݱ>GWEL8Ö1*ִOߵ FԊ%xҗ\;>pS:W B.\>wE)DM2K4nz`እ-bi ws(pt",iN9(i3sCxh(Fvp5YΗ\zۏbMGSsEܻ06,qўax mx m8<]މ9.lKZShN+.CնhJA=\|@3>ۍ5"M_GMπY|l"YՔN>hjb|Ψzddw RҀ8YN' ੱY<84"Gs9ir>ܷtʾyCWol;" K%vn[W_gk\ L_^c>HE`4<v_d\Ź㳙m)=*${ jx:%>&(@O?s}B7j,U(P&8!$>p,r2cam{kAkͻvDHw7l*{ӌ͸QLT·Bg7<"GGXs+~12݈Ͽ$,jwf:3 'cx)0Ɛ\Z%jK Cqhhܸ{&7;^"Ϯ,CW6xn~~qѪx(&G&YKjr(pfc8ܻEtWo'),.?rW,Ku60H$f7mW_F'uótxFjGg⧇aey>o$ND}գYfW^, -0yȶeK旅,,Kd6BڀW w.;3=ۯ8j?\ťsw ['fMJh l2mu=տΑ&8 ( pmI ؒ#dd0Iv3tN #ŊZrh0uP9i8y6 /Ч ǹMւ>v{ g >qPG,upbUL;V}VN{c`Aٰ8tC :Ģ^9xNԀ7*🷢5Ojγ+?|`wrQ?wߝC 6!~]㚝Т>#_'p0]@'.܏2BPI]|5?ƇzTe+_x?Odctd*UK IDATpDX=BHSAWFP 's Ci]#d|Cڃ>'md7kR Icn&9|M}^7.Bm5~_~w3RoYjAZ_"SAJs= ]Ӣ<&1Uԛ}o2M))Dy4͆ފ kTkev}cs M_EʶIsk Q=0 .p=+HTc|ŧv>9w#w񫷦_J'iϼ^\>Nm6~M|ߕSGgd 1[d,`ʭ_??o=8S?kw fb8wCL6@iGPo _O|lU|:-+E}o~+71.מC+a%I-mHϽ]ZS LTȿ|`[u[FU+W_<çKol 3߼G?W˟{~;xt1!l@j8z}N 5 md@3!9NA mcPY/(zUCl1yÅ<?b 5'_7FrŎSV\.w7Z{V=|pc3&4Kq\8̀s :5Ouzybii0utvyZXoԝo¢E?rۏ2"Gg-.9/qd[S|=oap*?h,. ދw?]y /_˗> W"u< qb1})1ܿQ.Gw>z w}}>z~^w>><|?L Q /bbEg&xp^ΝӧnD~Rx?YS.38n\$8c|0SxSp01m]S}?\ߺ㳇+gמÿW} wc٨. | _~x@Y-;5]Swmr/Y>Y2"7 A$L 7=0̚]0pNQl+o3?G"gϨ+Pϸ>9iS nZE~^sy5! A_tRNgj&Yc {PW%)vUME}Rij饈qG켠a&VKƹkCNPb~)B-K6K+'҃8tU`SD ͼ8a&'{q%{xqwA 5->ÃFGϿp?ٛ_ '.bpflaVG m7vʼn6L,w)gdsK٩NwryY92kh°?4v6 9>N`#a!*2 "lcK~#00@|G?9skAnlBnh܎ɴ|lb0=,=9`pGQ?DYUyY9$-@!p iBz:p41F7^OQ  b8܆ځ #Km97+7P ȍM|^ /'ggv Vmϼ}K?E~:^{hl2]˟QNKVQ3owgb$HB7t<㆑@!3v;s90q?.VĽ#|Σ) &[@ FP2ubkIN{hܮr*A=ShN3QK8G$,YiUxSL'|CoYCAD fH.'ೣs j*j%P#i,Q:ū{Wy~z9>MEk<9 vNkF@zhvBcF J:rF|)R,0XǨY c1aIF32 1B GAËqug0'W1WJWB)Y^9?vQq\=>Duόs77>}W_ CW#?vNϟ,6mio=FN>%;:(q>N߹2S>ib)fTՕh0D6pY@ׂ<%e8>? cnWjڴa FGҵ!66 pF/GsK?qY;dI޽s}]+_ %N,ϱS rsǨYݗTruH8#81M'."֬ A|gyb'X׀yfJQڰz$-!9zW[ZihYqdUD]u~K~AQ< p 7^D+LR`s>Q$$ |o^svhg'' 2<f`G9|x EAы/2W2Mb0Dq$sCkuGC(CF '^?$ɪڡ^CmPD mI.{6+H=g_!%vs֫$,_XgI:܈sg*,)d3b0S[:ZJS'Pa '[B5kx(beE*;N ';NRC~w!-QfexJJ9UM]N%0tP3s׳ L>6A((d:G[!ĄHA8N ײ P]qc#O%Ł(y]8>9碟sD뎕_! |FZSų-+Y {|#)_} d1X-GoAN&xy+"N!.Ii 7_ #c h;#R y@ ^BG3P?3)ǀb[ usqyjcf[ӑN~#+d/76|Bz} pSŘ Hy]Qga|GnI脽"p:La#9mfSȎEdEs$,uNhr u43^(ArԴCצ\g r3dX/\Us'azFY~eqy!9Bv2epg\$5U 饣=7>عM\]Ў"Km^w~r,yK0jx~T#xu\RX⹍ 7lswo n.D+lJ0$oðyQP){"zy#&>b~9qv^JWBQKTTN 9]F!5ת*9UWpp-3E _dUi2NFC(vIT9 U;%I+FLCP$<7`cN  A@֩sz>u g#9EL *%R@>YK8P$:%!-6fDI#{6wovu/&;VDWJ)!0pxmhbl\$ٚ_-=%d!Ea%8L>b"[S~_A)$"@ވ" $7HjvW91* uA[y40J Db?%0SW_u%YX#0(H*^r=%{,}πeOV8m8 j0slÆ5%Ak8H L]`(qDr_]/Zcs9i2Ag"O3 u9`Agj ):"hmվ6Jm1w:K2Dڇ-6mWuJL$&Y:-pPx4/W;P1 L`o$7I8\ӂ`<8\* v+f}!xޛ twaH@&:AJ p}$Z`ƴbi `Kay'L'T%Aؐ݁a$uCi9'KGKhS4[= @?8#c=YK6z0^FR?2Axq#È_}´VɷsC:EfW]8\(/U Cib3XyZ`=n#aB 8+LU##=ƒ;kDvfF ޙN  %c+S םbޣ +Eq Kݱ~mb{\vwq͚!~BQuSEؾ /b+&B6ԏ@C-0uov'ewS6e~1O$.d$! dJr1dI3wK A 772et5RK`9V̸3-poZtU:CWlBvr{$ Ui8X<'7'S0T`Tv2,T*H\T̘*b D+`ţeK~Xű>y3#kКK;S)\w`+,<xi3@T m}h>ҋ'j\P`ܞ8X(A SkSo-WOJD}N* %\!h|H sYeVnVv؆1/D>>_NrA} 1. Z} s`"ت:2,CTTmǔMpb)iZ鑱 ^].Q1z =W`P3 Uð3WjehrmAU^a #¡V5f (qݮ$(-5H[S᱌0b˝-G5ۧA/|v1qP Y,9xq688'R2g\UM|i8w:h,."Y~W"]׼B6SrA(Cjߟq& fE#cbIJc7bP|cpP>y7ׇcB/Q <35r=jomK1wvgVh0NX ʹ,}_D u^q, ︿'*$_.QrQRvdI IZA$XGV||bˉ@LpLfXj/&(/]C7١Q&ϲ|?n"6y'GԴ="mZKz{*Ǝ$m `*cBvz~xܙ0t]}OVvq_Yn/B!|Oi8Pl{s ]FJdӌ3:rZF{J#o B{yi&V%\qT (#G(ců2`^Xxid$s#X'>^q++`c`ʌL6_αY1h{qR_ P@ۜ&<^L>mF5[a ]&Ћ4HG2AOe#6MYUwV Of" `g +;B9RLnՖ!\`Kn18?+-DZZKw[2 gCף)AL; 88ugb"Pb-p玾u]SE)[b &Bz +YUW*ü)b%Q{lCRmKضI캓8VѫEl^oʵ(W]M?&E3m15yCAFR2ݦFJ!U-} {Q8 X 3xy7C11 ;܌yj}j&n{MOY,"tYi8 ٽ\@ b%:^*L ]A3?VS 㬎]1a"h%։hslUWFU^LFC|Jo37T y7S<̰[|;#.lg{ymM x`y6.KH+Y\qF><xk^ [d8Z*\u>-uܹ@w3xɘKC=1-RBiUN(Q1qen` %U LHe*~3bnsRJ:R2!qSv_ 5bgJ+R4dS2a1xxTNzNJ+–7Y'0N(m9{80w5@4v?` B&<]6bl+f@J qGÖF q<ROv $,áb+7dNw\oנCQїx/J/;EF-&$ [8[@S9mn1Is-\gNM(g孈tfZlOvLuDtu(Ɉֿ7Qs[-DŽg58`aS䜦(nD:LސMȂAnzgIU>6+C@ߪ:Lx0-p}R+rlX&sleX[ѸM' r+ס76S1a IFL0sc}},0>όHdh ag@0S ejaQ+\T2)p$2"$*iU flԚApe~Dtn}xk^`w )E^]Sanh J^wD+Հ`s CǹPCesEU;u)$ KC*Ŭ3[a&%rX&[%a'W- )+fL"wN M)O0#}lflj#hrַVf0#DE_0ދQo68ό*.)Hm02)Y% CUVGȨfiO<rD(S9,pX v̞OV򽓗ilOk9Q!]iU[U EA'a-W^DHg#HDg(IރSحQ5v%~.N2u4!&3oï1(1P7ZZf+R P4:`q`XT"pdQ7nJJa3X0UQ56FVuW64\1R9b2nt"hQ8!Jy$*E |gKš6bJA#!CmdfYRns34H ܛ} E)HUQADt]%!vXT+lJ{5ɀ܌[seq(Fp] :=ay(pbpɄu㞾V'wdƜޕKP6+v2dhD 4HWֶ4` `(]y,B= L+5mP} Ʌ)@fcGkfLbcpWBnqOU9)SlM!CYXB֟* *7`U7-YFPU[PY $gfT5IX@ ]V!͢dcĢI( v-繹 3+'CPCRͯBPTP;&qQBp6?v:s^[՚-a)v53f%\b$$Wg~ `Ej TIC c߮`QqvN=*Ue4!\olmŪ yJa+#'YJ0k@vΕr-X_GfrՆWW!P:U e(aTdo⚧T}$e'XuFFhLWC5r\Ժ@$9A\>Uzle+zmIL'V"FBp#J7!Ӯueep=pM8ZysU4Wc#X:0Rɪ*r:}VNfJ'p:DA+[&rbd$l{Ƚ҂Inŕad9dJ}p︈d'o  \Cd"[ J~IENDB`pisa-3.0.32/demo/tgpisa/tgpisa/static/images/favicon.ico0000644000175000017500000000207111160170352021242 0ustar wmbwmbGIF89aM]]]Cqqq|||ӑan/-.ͣӴ򓓓̾ίuRƴZ0T%`ԇmbn01onniiiؐiV}QQQGGGC&ÛT*fff```sA.{-M"WWWSfAZ2wgc[Hp$>l1l:pPI򞾜jlqL̞沶䌍beiۅ=ߏ썐nqvwzľHuuvՂLMMSUYzCt6\_cxxx󅉏NPS]`d2.on:::QSWֶ˦PHfhmABBöƻ՝ISSSbcéssgggXXXZZ[ȿ|$##ͺ!Created with The GIMP,4a!y3PeHfD$ <͊HXMc ʁp0:Hctq wbE'Ę4iRx{oXBQUGZP#UR]  t-( ϗ.5Q:TPiŚ(ьlj16ls"@˹kexK#F 2>}\bD*$h5 碆1cb6q#U0$#_NH D蛬`-a@;pisa-3.0.32/demo/tgpisa/tgpisa/static/images/info.png0000644000175000017500000000551111160170352020564 0ustar wmbwmbPNG  IHDR00WsBIT|dtEXtSoftwarewww.inkscape.org< IDAThՙoy眹\^DhY$R %JVbR5[S[IIڦ-@>ohpZ;Fcˊun%,Qxo^gfgNH:AYy̻b} Fff|*ܦZ)S)y!DG+:!3w3 ﳴ0eB·{ѱ.x3~ ^iViPB Bu,YY+֫ơQ3x'p5Y9縷1R (%]YEwNq h`yHr\)xYO|ĩ3|P#L-XA`Z:7`c 5)QiDT+^{_x+_&,4;7ٗ_bsEz )ETJ@Jh/B^*ksξs,(xCS`y3hH!()P"!GqW]9?pdAn/ܑ,4)J TJFI@ e ]MƱxm >Qs9xU11ƤI-$yJ%e+I1qh<_7n޺IPY6MFhư]Tz^XPwYc9[ bSܼu.]LՈ\F:!hY@Jۚ}ݏX\K9 V̕jL;Υ<;w?V-[8@HX-(X³+5q/Tq,a\EJe%,"վ)$B hc@*К(ҸDD$KV,5a`DWC tgjqL!%4A#8B$܍I 6l6Z#ȎH)SpBF&18R!H,r;eDR2IJ !J \TZkmRxE dF+`aFeR"RA\Ka[JRcK265?dw kW{ےnԂ)N@Ă2M!q ~A$턥={  8qlFiX̯X C=-T0& Kı$LXVB9,Ó'05uMz=ȸVㅠ\o5B {< Khi7O1ߛP2 R 396u <_/2s"{SXJpvVז2żEw" BF<^2ԛ;144y=u e4յY{sXRݧdu,&l֡PCь=L7FI$-ɹW@MP{3i#(ךd]Kkȴz!]?<_k~5B>_sWQa\j:U?uTIU$RV_dIIw^?ġyPX//xɺMc>RtQ1&MR8a|tOM= l 8.~u3 JFQbZ\$}AV9N?qaa7{l8K xvR ֒m0IeB0e9 xjC[1^z%&0gpQBY rPR>{ځ*+p.k,Rb!yklff|?=r-mw',QlHo^*eepyR:j@R,:J>sBQqCEFFczzN2J)tl0Juny&'xccٷ z?E) uWK!ˆE67k4 rNom5cP27wl.P[ضC6Y]`c}Fll[ot?ͭ[>08hٿ}H|- %-]{w_B*hDfnnX cnRږֆ8" űf}LimzΣQUHh6(·⏿"&"8N'6O,-_f^#R*ReJJTefYXXZ2vW*%",ks]U85c8F똥\rW,G1+1}}LM=ѣOݏm-RuB YR!Z?qLakp3l67sS `68.8.dM>ܱǝQlANryyN 1: configfile = sys.argv[1] elif exists(join(setupdir, "setup.py")): configfile = join(setupdir, "dev.cfg") elif exists(join(curdir, "prod.cfg")): configfile = join(curdir, "prod.cfg") else: try: configfile = pkg_resources.resource_filename( pkg_resources.Requirement.parse("tgpisa"), "config/default.cfg") except pkg_resources.DistributionNotFound: raise ConfigurationError("Could not find default configuration.") turbogears.update_config(configfile=configfile, modulename="tgpisa.config") from tgpisa.controllers import Root turbogears.start_server(Root()) pisa-3.0.32/demo/tgpisa/tgpisa/json.py0000644000175000017500000000046711160170353015720 0ustar wmbwmb# A JSON-based API(view) for your app. # Most rules would look like: # @jsonify.when("isinstance(obj, YourClass)") # def jsonify_yourclass(obj): # return [obj.val1, obj.val2] # @jsonify can convert your objects to following types: # lists, dicts, numbers and strings from turbojson.jsonify import jsonify pisa-3.0.32/demo/tgpisa/tgpisa/release.py0000644000175000017500000000064511160170353016365 0ustar wmbwmb# Release information about tgpisa version = "1.0" # description = "Your plan to rule the world" # long_description = "More description about your plan" # author = "Your Name Here" # email = "YourEmail@YourDomain" # copyright = "Vintage 2006 - a good year indeed" # if it's open source, you might want to specify these # url = "http://yourcool.site/" # download_url = "http://yourcool.site/download" # license = "MIT" pisa-3.0.32/demo/tgpisa/start-tgpisa.py0000644000175000017500000000074111160170353016075 0ustar wmbwmb#!C:\Python25\python.exe # -*- coding: utf-8 -*- """Start script for the tgpisa TurboGears project. This script is only needed during development for running from the project directory. When the project is installed, easy_install will create a proper start script. """ import sys from tgpisa.commands import start, ConfigurationError if __name__ == "__main__": try: start() except ConfigurationError, exc: sys.stderr.write(str(exc)) sys.exit(1) pisa-3.0.32/demo/tgpisa/setup.py0000644000175000017500000000462411160170353014617 0ustar wmbwmb# -*- coding: utf-8 -*- from setuptools import setup, find_packages from turbogears.finddata import find_package_data import os execfile(os.path.join("tgpisa", "release.py")) packages=find_packages() package_data = find_package_data(where='tgpisa', package='tgpisa') if os.path.isdir('locales'): packages.append('locales') package_data.update(find_package_data(where='locales', exclude=('*.po',), only_in_packages=False)) setup( name="tgpisa", version=version, # uncomment the following lines if you fill them out in release.py #description=description, #author=author, #author_email=email, #url=url, #download_url=download_url, #license=license, install_requires=[ "TurboGears >= 1.0.4.3", "SQLObject>=0.8,<=0.10.0" ], zip_safe=False, packages=packages, package_data=package_data, keywords=[ # Use keywords if you'll be adding your package to the # Python Cheeseshop # if this has widgets, uncomment the next line # 'turbogears.widgets', # if this has a tg-admin command, uncomment the next line # 'turbogears.command', # if this has identity providers, uncomment the next line # 'turbogears.identity.provider', # If this is a template plugin, uncomment the next line # 'python.templating.engines', # If this is a full application, uncomment the next line # 'turbogears.app', ], classifiers=[ 'Development Status :: 3 - Alpha', 'Operating System :: OS Independent', 'Programming Language :: Python', 'Topic :: Software Development :: Libraries :: Python Modules', 'Framework :: TurboGears', # if this is an application that you'll distribute through # the Cheeseshop, uncomment the next line # 'Framework :: TurboGears :: Applications', # if this is a package that includes widgets that you'll distribute # through the Cheeseshop, uncomment the next line # 'Framework :: TurboGears :: Widgets', ], test_suite='nose.collector', entry_points = { 'console_scripts': [ 'start-tgpisa = tgpisa.commands:start', ], }, # Uncomment next line and create a default.cfg file in your project dir # if you want to package a default configuration in your egg. #data_files = [('config', ['default.cfg'])], ) pisa-3.0.32/demo/tgpisa/sample-prod.cfg0000644000175000017500000000503511160170353016006 0ustar wmbwmb[global] # This is where all of your settings go for your production environment. # You'll copy this file over to your production server and provide it # as a command-line option to your start script. # Settings that are the same for both development and production # (such as template engine, encodings, etc.) all go in # tgpisa/config/app.cfg # DATABASE # pick the form for your database # sqlobject.dburi="postgres://username@hostname/databasename" # sqlobject.dburi="mysql://username:password@hostname:port/databasename" # sqlobject.dburi="sqlite:///file_name_and_path" # If you have sqlite, here's a simple default to get you started # in development sqlobject.dburi="sqlite://%(current_dir_uri)s/devdata.sqlite" # if you are using a database or table type without transactions # (MySQL default, for example), you should turn off transactions # by prepending notrans_ on the uri # sqlobject.dburi="notrans_mysql://username:password@hostname:port/databasename" # for Windows users, sqlite URIs look like: # sqlobject.dburi="sqlite:///drive_letter:/path/to/file" # SERVER server.environment="production" # Sets the number of threads the server uses # server.thread_pool = 1 # if this is part of a larger site, you can set the path # to the TurboGears instance here # server.webpath="" # Set to True if you are deploying your App behind a proxy # e.g. Apache using mod_proxy # base_url_filter.on = False # Set to True if your proxy adds the x_forwarded_host header # base_url_filter.use_x_forwarded_host = True # If your proxy does not add the x_forwarded_host header, set # the following to the *public* host url. # (Note: This will be overridden by the use_x_forwarded_host option # if it is set to True and the proxy adds the header correctly. # base_url_filter.base_url = "http://www.example.com" # Set to True if you'd like to abort execution if a controller gets an # unexpected parameter. False by default # tg.strict_parameters = False # LOGGING # Logging configuration generally follows the style of the standard # Python logging module configuration. Note that when specifying # log format messages, you need to use *() for formatting variables. # Deployment independent log configuration is in tgpisa/config/log.cfg [logging] [[handlers]] [[[access_out]]] # set the filename as the first argument below args="('server.log',)" class='FileHandler' level='INFO' formatter='message_only' [[loggers]] [[[tgpisa]]] level='ERROR' qualname='tgpisa' handlers=['error_out'] [[[access]]] level='INFO' qualname='turbogears.access' handlers=['access_out'] propagate=0 pisa-3.0.32/demo/tgpisa/test.cfg0000644000175000017500000000101111160170353014530 0ustar wmbwmb[global] # You can place test-specific configuration options here (like test db uri, etc) # DATABASE sqlobject.dburi = "sqlite:///:memory:" # LOGGING [logging] [[formatters]] [[[full_content]]] format='*(asctime)s *(name)s *(levelname)s *(message)s' [[handlers]] [[[test_out]]] class='StreamHandler' level='DEBUG' args='(sys.stdout,)' formatter='full_content' [[loggers]] [[[tgpisa]]] level='DEBUG' qualname='tgpisa' handlers=['test_out'] [[[turbogears]]] level='INFO' qualname='turbogears' handlers=['test_out'] pisa-3.0.32/demo/tgpisa/dev.cfg0000644000175000017500000000356611160170353014350 0ustar wmbwmb[global] # This is where all of your settings go for your development environment # Settings that are the same for both development and production # (such as template engine, encodings, etc.) all go in # tgpisa/config/app.cfg # DATABASE # pick the form for your database # sqlobject.dburi="postgres://username@hostname/databasename" # sqlobject.dburi="mysql://username:password@hostname:port/databasename" # sqlobject.dburi="sqlite:///file_name_and_path" # If you have sqlite, here's a simple default to get you started # in development sqlobject.dburi="sqlite://%(current_dir_uri)s/devdata.sqlite" # if you are using a database or table type without transactions # (MySQL default, for example), you should turn off transactions # by prepending notrans_ on the uri # sqlobject.dburi="notrans_mysql://username:password@hostname:port/databasename" # for Windows users, sqlite URIs look like: # sqlobject.dburi="sqlite:///drive_letter:/path/to/file" # SERVER # Some server parameters that you may want to tweak # server.socket_port=8080 # Enable the debug output at the end on pages. # log_debug_info_filter.on = False server.environment="development" autoreload.package="tgpisa" # Auto-Reload after code modification # autoreload.on = True # Set to True if you'd like to abort execution if a controller gets an # unexpected parameter. False by default tg.strict_parameters = True # LOGGING # Logging configuration generally follows the style of the standard # Python logging module configuration. Note that when specifying # log format messages, you need to use *() for formatting variables. # Deployment independent log configuration is in tgpisa/config/log.cfg [logging] [[loggers]] [[[tgpisa]]] level='DEBUG' qualname='tgpisa' handlers=['debug_out'] [[[allinfo]]] level='INFO' handlers=['debug_out'] [[[access]]] level='INFO' qualname='turbogears.access' handlers=['access_out'] propagate=0 pisa-3.0.32/demo/wsgi/0000755000175000017500000000000011201057433012560 5ustar wmbwmbpisa-3.0.32/demo/wsgi/pisawsgidemo.py0000644000175000017500000000235711160170353015635 0ustar wmbwmb#!/bin/python2.5 # -*- coding: UTF-8 -*- ############################################# ## (C)opyright by Dirk Holtwick, 2008 ## ## All rights reserved ## ############################################# __version__ = "$Revision: 103 $" __author__ = "$Author: holtwick $" __date__ = "$Date: 2007-10-31 17:08:54 +0100 (Mi, 31 Okt 2007) $" __svnid__ = "$Id: pisa.py 103 2007-10-31 16:08:54Z holtwick $" from wsgiref.simple_server import make_server import logging import sx.pisa3.pisa_wsgi as pisa_wsgi def SimpleApp(environ, start_response): # That's the magic! # # Set the environment variable "pisa.topdf" to the filename # you would like to have for the resulting PDF environ["pisa.topdf"] = "index.pdf" # Simple Hello World example start_response( '200 OK', [ ('content-type', "text/html"), ]) return ["Hello World"] if __name__ == '__main__': HOST = '' PORT = 8080 logging.basicConfig(level=logging.DEBUG) app = SimpleApp # Add PISA WSGI Middleware app = pisa_wsgi.PisaMiddleware(app) httpd = make_server(HOST, PORT, app) print "Serving HTTP on port %d..." % PORT httpd.serve_forever() pisa-3.0.32/demo/cherrypy/0000755000175000017500000000000011201057433013454 5ustar wmbwmbpisa-3.0.32/demo/cherrypy/demo-cherrypy.conf0000644000175000017500000000014011160170352017105 0ustar wmbwmb[global] server.socket_host = "localhost" server.socket_port = 8080 server.thread_pool = 10 pisa-3.0.32/demo/cherrypy/demo-cherrypy.py0000644000175000017500000000422011160170352016613 0ustar wmbwmb#!/usr/local/bin/python # -*- coding: ISO-8859-1 -*- ############################################# ## (C)opyright by Dirk Holtwick, 2008 ## ## All rights reserved ## ############################################# import cherrypy as cp import sx.pisa3 as pisa import cStringIO as StringIO try: import kid except: kid = None class PDFDemo(object): """ Simple demo showing a form where you can enter some HTML code. After sending PISA is used to convert HTML to PDF and publish it directly. """ @cp.expose def index(self): if kid: return file("demo-cherrypy.html","r").read() return """ Please enter some HTML code:

""" @cp.expose def download(self, data): if kid: data = """ PDF Demo %s """ % data test = kid.Template(source=data) data = test.serialize(output='xhtml') result = StringIO.StringIO() pdf = pisa.CreatePDF( StringIO.StringIO(data), result ) if pdf.err: return "We had some errors in HTML" else: cp.response.headers["content-type"] = "application/pdf" return result.getvalue() cp.tree.mount(PDFDemo()) if __name__ == '__main__': import os.path cp.config.update(os.path.join(__file__.replace(".py", ".conf"))) cp.server.quickstart() cp.engine.start() pisa-3.0.32/demo/cherrypy/demo-cherrypy.html0000644000175000017500000000126511160170352017135 0ustar wmbwmb PDF Demo

PDF Demo

Please enter some HTML (and KID) code:


pisa-3.0.32/demo/djangoproject/0000755000175000017500000000000011201057433014440 5ustar wmbwmbpisa-3.0.32/demo/djangoproject/__init__.py0000644000175000017500000000000011160170353016540 0ustar wmbwmbpisa-3.0.32/demo/djangoproject/ezpdf.py0000644000175000017500000000150611160170353016125 0ustar wmbwmb#! /usr/bin/python # -*- encoding: utf-8 -*- from django.template.loader import get_template from django.template import Context from django.http import HttpResponse import cStringIO as StringIO from sx.pisa3 import pisaDocument import cgi def render_to_pdf(template_src, context_dict): ''' Renderiza el template con el contexto. Envía al cliente la Respuesta HTTP del contenido PDF para el template renderizado. ''' template = get_template(template_src) context = Context(context_dict) html = template.render(context) result = StringIO.StringIO() pdf = pisaDocument(StringIO.StringIO(html.encode("ISO-8859-1")), result) if not pdf.err: return HttpResponse(result.getvalue(), mimetype='application/pdf') return HttpResponse('We had some errors
%s
' % cgi.escape(html)) pisa-3.0.32/demo/djangoproject/templates/0000755000175000017500000000000011201057433016436 5ustar wmbwmbpisa-3.0.32/demo/djangoproject/templates/base.html0000644000175000017500000000142611160170353020242 0ustar wmbwmb {%block title%} {%endblock%}
{%block page_header%}

pisa htmltopdf

Python module for HTML/CSS to PDF conversion - Ezpdf example


{%endblock%} {%block content%} {%endblock%}
{%block page_foot%} {%endblock%}
pisa-3.0.32/demo/djangoproject/templates/entries.html0000644000175000017500000000050211160170353020773 0ustar wmbwmb{% extends "base.html" %} {% block title %}{{title}}{% endblock %} {% block content %} {% for entry in blog_entries %}

{{ entry.id }} {{ entry.title|upper }}

{{ entry.body }}

{% endfor %} {% endblock %} {%block page_foot%} Sample page {{block.super}} {%endblock%} pisa-3.0.32/demo/djangoproject/manage.py0000644000175000017500000000151411160170353016244 0ustar wmbwmb#!/usr/bin/env python from django.core.management import execute_manager # Patch for Python 2.5 try: import sitecustomize except: pass # Set logging import logging try: logging.basicConfig( level=logging.WARN, format="%(levelname)s [%(name)s] %(pathname)s line %(lineno)d in %(funcName)s: %(message)s") except: logging.basicConfig() try: import settings # Assumed to be in the same directory. except ImportError: import sys sys.stderr.write("Error: Can't find the file 'settings.py' in the directory containing %r. It appears you've customized things.\nYou'll have to run django-admin.py, passing it your settings module.\n(If the file settings.py does indeed exist, it's causing an ImportError somehow.)\n" % __file__) sys.exit(1) if __name__ == "__main__": execute_manager(settings) pisa-3.0.32/demo/djangoproject/._views.py0000644000175000017500000000027311160170353016367 0ustar wmbwmbMac OS X  2ATTR&(|##com.macromates.caret{ column = 41; line = 43; }pisa-3.0.32/demo/djangoproject/django-admin.py0000644000175000017500000000020011160170353017333 0ustar wmbwmb#!/usr/bin/env python from django.core import management if __name__ == "__main__": management.execute_from_command_line() pisa-3.0.32/demo/djangoproject/settings.py0000644000175000017500000000031511160170353016652 0ustar wmbwmb# Django settings for the example project. import os DEBUG = True TEMPLATE_DEBUG = DEBUG ROOT_URLCONF = 'djangoproject.urls' TEMPLATE_DIRS = ( os.path.join(os.path.dirname(__file__), 'templates'), ) pisa-3.0.32/demo/djangoproject/views.py0000644000175000017500000000403611160170353016153 0ustar wmbwmb#! /usr/bin/python # -*- encoding: utf-8 -*- from django import http from django.shortcuts import render_to_response from django.template.loader import get_template from django.template import Context import ho.pisa as pisa import cStringIO as StringIO import cgi def index(request): return http.HttpResponse("""

Example 1

Please enter some HTML code:


Example 2

%s
' % cgi.escape(html)) def ezpdf_sample(request): blog_entries = [] for i in range(1,10): blog_entries.append({ 'id': i, 'title':'Playing with pisa 3.0.16 and dJango Template Engine', 'body':'This is a simple example..' }) return render_to_pdf('entries.html',{ 'pagesize':'A4', 'title':'My amazing blog', 'blog_entries':blog_entries}) pisa-3.0.32/demo/djangoproject/urls.py0000644000175000017500000000034511160170353016002 0ustar wmbwmbfrom django.conf.urls.defaults import * urlpatterns = patterns('', (r'^$', 'djangoproject.views.index'), (r'^download', 'djangoproject.views.download'), (r'^ezpdf_sample', 'djangoproject.views.ezpdf_sample'), ) pisa-3.0.32/._setup.py0000644000175000017500000000027011177602650012622 0ustar wmbwmbMac OS X  2ATTR&*:  com.macromates.caretxR<[k0?'3/«

Example with template """) def download(request): if request.POST: result = StringIO.StringIO() pdf = pisa.CreatePDF( StringIO.StringIO(request.POST["data"]), result ) if not pdf.err: return http.HttpResponse( result.getvalue(), mimetype='application/pdf') return http.HttpResponse('We had some errors') def render_to_pdf(template_src, context_dict): template = get_template(template_src) context = Context(context_dict) html = template.render(context) result = StringIO.StringIO() pdf = pisa.pisaDocument(StringIO.StringIO(html.encode("ISO-8859-1")), result) if not pdf.err: return http.HttpResponse(result.getvalue(), mimetype='application/pdf') return http.HttpResponse('We had some errors

Source: http://www.columbia.edu/kermit/utf8.html