pax_global_header00006660000000000000000000000064125532453070014520gustar00rootroot0000000000000052 comment=d0e08b90f588798a859cf1c69680b195a643b9fc PyPDF2-1.25.1/000077500000000000000000000000001255324530700126125ustar00rootroot00000000000000PyPDF2-1.25.1/.gitignore000066400000000000000000000000341255324530700145770ustar00rootroot00000000000000*.pyc *.swp .DS_Store build PyPDF2-1.25.1/CHANGELOG000066400000000000000000000444111255324530700140300ustar00rootroot00000000000000Version 1.25, 2015-07-07 ------------------------ BUGFIXES: - Added Python 3 algorithm for ASCII85Decode. Fixes issue when reading reportlab-generated files with Py 3 (jerickbixly) - Recognize more escape sequence which would otherwise throw an exception (manuelzs, robertsoakes) - Fixed overflow error in generic.py. Occurred when reading a too-large int in Python 2 (by Raja Jamwal) - Allow access to files which were encrypted with an empty password. Previously threw a "File has not been decrypted" exception (Elena Williams) - Do not attempt to decode an empty data stream. Previously would cause an error in decode algorithms (vladir) - Fixed some type issues specific to Py 2 or Py 3 - Fix issue when stream data begins with whitespace (soloma83) - Recognize abbreviated filter names (AlmightyOatmeal and Matthew Weiss) - Copy decryption key from PdfFileReader to PdfFileMerger. Allows usage of PdfFileMerger with encrypted files (twolfson) - Fixed bug which occurred when a NameObject is present at end of a file stream. Threw a "Stream has ended unexpectedly" exception (speedplane) FEATURES: - Initial work on a test suite; to be expanded in future. Tests and Resources directory added, README updated (robertsoakes) - Added document cloning methods to PdfFileWriter: appendPagesFromReader, cloneReaderDocumentRoot, and cloneDocumentFromReader. See official documentation (robertsoakes) - Added method for writing to form fields: updatePageFormFieldValues. This will be enhanced in the future. See official documentation (robertsoakes) - New addAttachment method. See documentation. Support for adding and extracting embedded files to be enhanced in the future (moshekaplan) - Added methods to get page number of given PageObject or Destination: getPageNumber and getDestinationPageNumber. See documentation (mozbugbox) OTHER ENHANCEMENTS: - Enhanced type handling (Brent Amrhein) - Enhanced exception handling in NameObject (sbywater) - Enhanced extractText method output (peircej) - Better exception handling - Enhanced regex usage in NameObject class (speedplane) Version 1.24, 2014-12-31 ------------------------ - Bugfixes for reading files in Python 3 (by Anthony Tuininga and pqqp) - Appropriate errors are now raised instead of infinite loops (by naure and Cyrus Vafadari) - Bugfix for parsing number tokens with leading spaces (by Maxim Kamenkov) - Don't crash on bad /Outlines reference (by eshellman) - Conform tabs/spaces and blank lines to PEP 8 standards - Utilize the readUntilRegex method when reading Number Objects (by Brendan Jurd) - More bugfixes for Python 3 and clearer exception handling - Fixed encoding issue in merger (with eshellman) - Created separate folder for scripts Version 1.23, 2014-08-11 ------------------------ - Documentation now available at http://pythonhosted.org//PyPDF2 - Bugfix in pagerange.py for when __init__.__doc__ has no value (by Vladir Cruz) - Fix typos in OutlinesObject().add() (by shilluc) - Re-added a missing return statement in a utils.py method - Corrected viewing mode names (by Jason Scheirer) - New PdfFileWriter method: addJS() (by vfigueiro) - New bookmark features: color, boldness, italics, and page fit (by Joshua Arnott) - New PdfFileReader method: getFields(). Used to extract field information from PDFs with interactive forms. See documentation for details - Converted README file to markdown format (by Stephen Bussard) - Several improvements to overall performance and efficiency (by mozbugbox) - Fixed a bug where geospatial information was not scaling along with its page - Fixed a type issue and a Python 3 issue in the decryption algorithms (with Francisco Vieira and koba-ninkigumi) - Fixed a bug causing an infinite loop in the ASCII 85 decoding algorithm (by madmaardigan) - Annotations (links, comment windows, etc.) are now preserved when pages are merged together - Used the Destination class in addLink() and addBookmark() so that the page fit option could be properly customized Version 1.22, 2014-05-29 ------------------------ - Added .DS_Store to .gitignore (for Mac users) (by Steve Witham) - Removed __init__() implementation in NameObject (by Steve Witham) - Fixed bug (inf. loop) when merging pages in Python 3 (by commx) - Corrected error when calculating height in scaleTo() - Removed unnecessary code from DictionaryObject (by Georges Dubus) - Fixed bug where an exception was thrown upon reading a NULL string (by speedplane) - Allow string literals (non-unicode strings in Python 2) to be passed to PdfFileReader - Allow ConvertFunctionsToVirtualList to be indexed with slices and longs (in Python 2) (by Matt Gilson) - Major improvements and bugfixes to addLink() method (see documentation in source code) (by Henry Keiter) - General code clean-up and improvements (with Steve Witham and Henry Keiter) - Fixed bug that caused crash when comments are present at end of dictionary Version 1.21, 2014-04-21 ------------------------ - Fix for when /Type isn't present in the Pages dictionary (by Rob1080) - More tolerance for extra whitespace in Indirect Objects - Improved Exception handling - Fixed error in getHeight() method (by Simon Kaempflein) - implement use of utils.string_type to resolve Py2-3 compatibility issues - Prevent exception for multiple definitions in a dictionary (with carlosfunk) (only when strict = False) - Fixed errors when parsing a slice using pdfcat on command line (by Steve Witham) - Tolerance for EOF markers within 1024 bytes of the actual end of the file (with David Wolever) - Added overwriteWarnings parameter to PdfFileReader constructor, if False PyPDF2 will NOT overwrite methods from Python's warnings.py module with a custom implementation. - Fix NumberObject and NameObject constructors for compatibility with PyPy (Rüdiger Jungbeck, Xavier Dupré, shezadkhan137, Steven Witham) - Utilize utils.Str in pdf.py and pagerange.py to resolve type issues (by egbutter) - Improvements in implementing StringIO for Python 2 and BytesIO for Python 3 (by Xavier Dupré) - Added /x00 to Whitespaces, defined utils.WHITESPACES to clarify code (by Maxim Kamenkov) - Bugfix for merging 3 or more resources with the same name (by lucky-user) - Improvements to Xref parsing algorithm (by speedplane) Version 1.20, 2014-01-27 ------------------------ - Official Python 3+ support (with contributions from TWAC and cgammans) Support for Python versions 2.6 and 2.7 will be maintained - Command line concatenation (see pdfcat in sample code) (by Steve Witham) - New FAQ; link included in README - Allow more (although unnecessary) escape sequences - Prevent exception when reading a null object in decoding parameters - Corrected error in reading destination types (added a slash since they are name objects) - Corrected TypeError in scaleTo() method - addBookmark() method in PdfFileMerger now returns bookmark (so nested bookmarks can be created) - Additions to Sample Code and Sample PDFs - changes to allow 2up script to work (see sample code) (by Dylan McNamee) - changes to metadata encoding (by Chris Hiestand) - New methods for links: addLink() (by Enrico Lambertini) and removeLinks() - Bugfix to handle nested bookmarks correctly (by Jamie Lentin) - New methods removeImages() and removeText() available for PdfFileWriter (by Tien Haï) - Exception handling for illegal characters in Name Objects Version 1.19, 2013-10-08 ------------------------ BUGFIXES: - Removed pop in sweepIndirectReferences to prevent infinite loop (provided by ian-su-sirca) - Fixed bug caused by whitespace when parsing PDFs generated by AutoCad - Fixed a bug caused by reading a 'null' ASCII value in a dictionary object (primarily in PDFs generated by AutoCad). FEATURES: - Added new folders for PyPDF2 sample code and example PDFs; see README for each folder - Added a method for debugging purposes to show current location while parsing - Ability to create custom metadata (by jamma313) - Ability to access and customize document layout and view mode (by Joshua Arnott) OTHER: - Added and corrected some documentation - Added some more warnings and exception messages - Removed old test/debugging code UPCOMING: - More bugfixes (We have received many problematic PDFs via email, we will work with them) - Documentation - It's time for PyPDF2 to get its own documentation since it has grown much since the original pyPdf - A FAQ to answer common questions Version 1.18, 2013-08-19 ------------------------ - Fixed a bug where older verions of objects were incorrectly added to the cache, resulting in outdated or missing pages, images, and other objects (from speedplane) - Fixed a bug in parsing the xref table where new xref values were overwritten; also cleaned up code (from speedplane) - New method mergeRotatedAroundPointPage which merges a page while rotating it around a point (from speedplane) - Updated Destination syntax to respect PDF 1.6 specifications (from jamma313) - Prevented infinite loop when a PdfFileReader object was instantiated with an empty file (from Jerome Nexedi) Other Changes: - Downloads now available via PyPI https://pypi.python.org/pypi?:action=display&name=PyPDF2 - Installation through pip library is fixed Version 1.17, 2013-07-25 ------------------------ - Removed one (from pdf.py) of the two Destination classes. Both classes had the same name, but were slightly different in content, causing some errors. (from Janne Vanhala) - Corrected and Expanded README file to demonstrate PdfFileMerger - Added filter for LZW encoded streams (from Michal Horejsek) - PyPDF2 issue tracker enabled on Github to allow community discussion and collaboration Versions -1.16, -2013-06-30 --------------------------- - Note: This ChangeLog has not been kept up-to-date for a while. Hopefully we can keep better track of it from now on. Some of the changes listed here come from previous versions 1.14 and 1.15; they were only vaguely defined. With the new _version.py file we should have more structured and better documented versioning from now on. - Defined PyPDF2.__version__ - Fixed encrypt() method (from Martijn The) - Improved error handling on PDFs with truncated streams (from cecilkorik) - Python 3 support (from kushal-kumaran) - Fixed example code in README (from Jeremy Bethmont) - Fixed an bug caused by DecimalError Exception (from Adam Morris) - Many other bug fixes and features by: jeansch Anton Vlasenko Joseph Walton Jan Oliver Oelerich Fabian Henze And any others I missed. Thanks for contributing! Version 1.13, 2010-12-04 ------------------------ - Fixed a typo in code for reading a "\b" escape character in strings. - Improved __repr__ in FloatObject. - Fixed a bug in reading octal escape sequences in strings. - Added getWidth and getHeight methods to the RectangleObject class. - Fixed compatibility warnings with Python 2.4 and 2.5. - Added addBlankPage and insertBlankPage methods on PdfFileWriter class. - Fixed a bug with circular references in page's object trees (typically annotations) that prevented correctly writing out a copy of those pages. - New merge page functions allow application of a transformation matrix. - To all patch contributors: I did a poor job of keeping this ChangeLog up-to-date for this release, so I am missing attributions here for any changes you submitted. Sorry! I'll do better in the future. Version 1.12, 2008-09-02 ------------------------ - Added support for XMP metadata. - Fix reading files with xref streams with multiple /Index values. - Fix extracting content streams that use graphics operators longer than 2 characters. Affects merging PDF files. Version 1.11, 2008-05-09 ------------------------ - Patch from Hartmut Goebel to permit RectangleObjects to accept NumberObject or FloatObject values. - PDF compatibility fixes. - Fix to read object xref stream in correct order. - Fix for comments inside content streams. Version 1.10, 2007-10-04 ------------------------ - Text strings from PDF files are returned as Unicode string objects when pyPdf determines that they can be decoded (as UTF-16 strings, or as PDFDocEncoding strings). Unicode objects are also written out when necessary. This means that string objects in pyPdf can be either generic.ByteStringObject instances, or generic.TextStringObject instances. - The extractText method now returns a unicode string object. - All document information properties now return unicode string objects. In the event that a document provides docinfo properties that are not decoded by pyPdf, the raw byte strings can be accessed with an "_raw" property (ie. title_raw rather than title) - generic.DictionaryObject instances have been enhanced to be easier to use. Values coming out of dictionary objects will automatically be de-referenced (.getObject will be called on them), unless accessed by the new "raw_get" method. DictionaryObjects can now only contain PdfObject instances (as keys and values), making it easier to debug where non-PdfObject values (which cannot be written out) are entering dictionaries. - Support for reading named destinations and outlines in PDF files. Original patch by Ashish Kulkarni. - Stream compatibility reading enhancements for malformed PDF files. - Cross reference table reading enhancements for malformed PDF files. - Encryption documentation. - Replace some "assert" statements with error raising. - Minor optimizations to FlateDecode algorithm increase speed when using PNG predictors. Version 1.9, 2006-12-15 ----------------------- - Fix several serious bugs introduced in version 1.8, caused by a failure to run through our PDF test suite before releasing that version. - Fix bug in NullObject reading and writing. Version 1.8, 2006-12-14 ----------------------- - Add support for decryption with the standard PDF security handler. This allows for decrypting PDF files given the proper user or owner password. - Add support for encryption with the standard PDF security handler. - Add new pythondoc documentation. - Fix bug in ASCII85 decode that occurs when whitespace exists inside the two terminating characters of the stream. Version 1.7, 2006-12-10 ----------------------- - Fix a bug when using a single page object in two PdfFileWriter objects. - Adjust PyPDF to be tolerant of whitespace characters that don't belong during a stream object. - Add documentInfo property to PdfFileReader. - Add numPages property to PdfFileReader. - Add pages property to PdfFileReader. - Add extractText function to PdfFileReader. Version 1.6, 2006-06-06 ----------------------- - Add basic support for comments in PDF files. This allows us to read some ReportLab PDFs that could not be read before. - Add "auto-repair" for finding xref table at slightly bad locations. - New StreamObject backend, cleaner and more powerful. Allows the use of stream filters more easily, including compressed streams. - Add a graphics state push/pop around page merges. Improves quality of page merges when one page's content stream leaves the graphics in an abnormal state. - Add PageObject.compressContentStreams function, which filters all content streams and compresses them. This will reduce the size of PDF pages, especially after they could have been decompressed in a mergePage operation. - Support inline images in PDF content streams. - Add support for using .NET framework compression when zlib is not available. This does not make pyPdf compatible with IronPython, but it is a first step. - Add support for reading the document information dictionary, and extracting title, author, subject, producer and creator tags. - Add patch to support NullObject and multiple xref streams, from Bradley Lawrence. Version 1.5, 2006-01-28 ----------------------- - Fix a bug where merging pages did not work in "no-rename" cases when the second page has an array of content streams. - Remove some debugging output that should not have been present. Version 1.4, 2006-01-27 ----------------------- - Add capability to merge pages from multiple PDF files into a single page using the PageObject.mergePage function. See example code (README or web site) for more information. - Add ability to modify a page's MediaBox, CropBox, BleedBox, TrimBox, and ArtBox properties through PageObject. See example code (README or web site) for more information. - Refactor pdf.py into multiple files: generic.py (contains objects like NameObject, DictionaryObject), filters.py (contains filter code), utils.py (various). This does not affect importing PdfFileReader or PdfFileWriter. - Add new decoding functions for standard PDF filters ASCIIHexDecode and ASCII85Decode. - Change url and download_url to refer to new pybrary.net web site. Version 1.3, 2006-01-23 ----------------------- - Fix new bug introduced in 1.2 where PDF files with \r line endings did not work properly anymore. A new test suite developed with various PDF files should prevent regression bugs from now on. - Fix a bug where inheriting attributes from page nodes did not work. Version 1.2, 2006-01-23 ----------------------- - Improved support for files with CRLF-based line endings, fixing a common reported problem stating "assertion error: assert line == "%%EOF"". - Software author/maintainer is now officially a proud married person, which is sure to result in better software... somehow. Version 1.1, 2006-01-18 ----------------------- - Add capability to rotate pages. - Improved PDF reading support to properly manage inherited attributes from /Type=/Pages nodes. This means that page groups that are rotated or have different media boxes or whatever will now work properly. - Added PDF 1.5 support. Namely cross-reference streams and object streams. This release can mangle Adobe's PDFReference16.pdf successfully. Version 1.0, 2006-01-17 ----------------------- - First distutils-capable true public release. Supports a wide variety of PDF files that I found sitting around on my system. - Does not support some PDF 1.5 features, such as object streams, cross-reference streams. PyPDF2-1.25.1/LICENSE000066400000000000000000000031051255324530700136160ustar00rootroot00000000000000Copyright (c) 2006-2008, Mathieu Fenniak Some contributions copyright (c) 2007, Ashish Kulkarni Some contributions copyright (c) 2014, Steve Witham All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. * The name of the author may not be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. PyPDF2-1.25.1/MANIFEST.in000066400000000000000000000000221255324530700143420ustar00rootroot00000000000000include CHANGELOG PyPDF2-1.25.1/PDF_Samples/000077500000000000000000000000001255324530700147075ustar00rootroot00000000000000PyPDF2-1.25.1/PDF_Samples/AutoCad_Diagram.pdf000066400000000000000000001730461255324530700203610ustar00rootroot00000000000000%PDF-1.6 %ޭ 4 0 obj << /Length 16453 /Filter /FlateDecode /DecodeParms << /Predictor 1 >> >> stream x}ˎ;n|yi/S 0 ' #q*=H#oqEJU8@ӅM$E??}.?g?ǨyN`U<z'pz?ǿ w'~k|=:gV;𘀷}kPz|;,HkX#s9ہc#ĵV:cevl+qp+^5.x5|fҌl Voϊϳc*cn>gXk&g0᭺78`OYRb3$mvM"b-4/F, }1si `)X#sƊKF\>Vv:\[gr?!5'Y ^lڐَ53LY͍18c3Sr`+Nm1<ϟ sV;eZmHA+Q>`y^lUs+fĖEf!κ>{a Ql[q VCگr1k`zvo9=p }>oR?w?4L*?CNr`ю/`끫?ܸ/8|@˚큟i~ҸKR`T|Rmb c\óF%on/M>\GݬYx<.Sƙ_g:_k;RӄK]9I%->LfHSyTN3 :!zYE ^_4m%x+fߏE_K|\ůvڵr(dE:i=Ϟγ=ӬfhSr؅;xYacq+ia2{&yQEӀм:)42oe[_iw#v&Y\6ΫȺ/j&?h5EKXV@2YP%MNUQq$H}eGy q۾OݷV;>%Ѡ"`}$3/cF]Mwh~>Dž&|z~ۏ;םql+;.=~i\S5O?wivm׫e\i@|t:oYEHĞIMk2Lgae\ZB9]Yk0Ǽ/vI6t?ǵFKg26XHP}g;OXru5y?nV C13lTh@벓c3Χ)%$oϸ惕i|_Wg\G'8So{A??=OwzyU\v 1;BJmCy>Z˺p>õ0Me:%-iGL>LzgD Ynw};%lzi#e4_a߫ɠSHLfeaTZNny,Dٹz8|IyXs'NZW|EKҲumkf'+*HM+wѧFfTz9(AUe4Ynjl%MYl$x Aso=gff2a0v5N9lm`[QwG?{G /Ϻ݇ P=09f|l\i4>Mk[<<\4vО#Me6́W`7D+NGhz2`Ⱦ-H6:¨Y{΀10I1nWYr`kc>XlDTc;4af}rL g7XOO&U6A3 CK|>["lXl2ٚ/P6r9 *7;ڸbbߒΚplc;HsVO?B⢏ 7;;ӯ͍lGES6ʦHF6~u풝,Ch>ruqaLQe!ϔlքb{㙶Ry7d?{m6Ďqۼuȭlz$ւEK`E&o.AS7l߂dv ո&1Ϝ#2ː=eFOJ>uI]ۉXdU5&y[0'(kF&1B4o1C0 syj?m96L t)Mc?Q\fzq#x;Hd~;syT nt,Q.Ra mkkP:Fv{v;\7 X=к"֕O9`sKlt[:wʭc۩oM$&iw g延6e7l:wj-ٱ4kXkHyܩiktd떰H:ʻփ(İżY+̴&jH-NQoΩ06 >[Kgv vmȜJwN \;;9yTzђ&fzm.wr^4]8MOZovsw[a^+'r ZY-v~o#lj7w7J-4="`!f-KΎ ҉ {.kLhJ^a!mXŴ_ߓ9>pR_JHM}Fpn $#+,IFPd"Gk[D GJrDiUX+JE.+<2?PR̢diR aRLۀewnyWŊC>Ɂ6SQ Gƀ۸p? O?)E|\cRlI@뵣֎̬L tsv1\etG Z6L3&7P1Ϧ&fWvi7;JzcFkLi/-cDj8 D"h ֝·f8 [7t :`I$s9N˨b`gQW5&ϩI)ir[A18z:'VϞa2Yَ=V&Ic\b0<~8e[ 6w<[.L݆N]5۳Lŷ-1g*l=e!L۽!I%.2,X`0d/F2beHZc*r3g<,r{eSʐ涘SZ) hpƺ=W)VaF3E}ׯymDϟ?QNu7_: tnڑ'گx ~ٻMi5V(R-Er22TSp|2i]Z&%-lumVl^:_mBd8 w.9^6"ͼGy9٣7v"U_=\+Ka [N%[AOK~J~ۀuJOҍ5]A_.-MXFi3AbRHY^fG7ҵl^UrA @72S) M˝QiԭoӶsf7,O|$;ڬk)3ƴD[zV֫ OYFǃny_>//~ \܈1G}<34Cto]٨>#V]Na4m2t|DiA.~qUjՁ#, E_x=pK.kp-"VOSyF4jLjy#jE4iq7+51q/~LRFn9mk#˫n,˲7d#NoVYg5F߉ sIC .dk-Vc#;{}:X{t. 0W+n6m0*j&@A"$l,m+OFgIdυ* ;;Vbfەn|,TpKK3xM}"Ý2,ojS$+?\0eJsPf ^(T\lFp0bܐ/ VC]S6?5Z.<n176U9g}IlP)/E-:;rqҝ'*]O% ](:p`htJtz\$wݵu. x{&oژLl|Qgrkz jµ=G \P -h7-ciCɹi]zH<. Y(ĿmgKm~Vaֹ1y62#%ѢXhr5]b'p!cn_>|"QtOҚvtxpw]aj.6FOU2 Y$fve|!X,ZT[Hָ2ϼ- dY.^2VLJy?e>2H+m VZՌYPeJz[T ]fxyӂz&VŘ _[p,/BryJ c%_UٺR"'H:yH$ K^ P|=b5!ufCEFyT~6(\%=TVVpgZgK774fyCi 4kB+3qָ9k ]{N]]%Y]39JA3*l5ːKUfw(TaYZPfzbP;4谥jyK o'_,@V8Dz2|nVnRT [<*7'X[!;Z\_\qsn42V4(a7ܒ.ŠڀNJͬ 3cu`>7[yAq5ʴw8`OMIoc;fh'I̔8i4w8).9]"෨ >-ZcMH9yuhϙ(N^|4Qkx`;/f64c[CJmh682|\l{cP1m@4Xcq/uƮA#3q5&f꧿j6QM jmT6IxdOLO|6E\$PB2+Z|1E+= ̑&LzEZ1<8#ԓbuv[ĜYcK]-r 8m>glSc1g^>gMqfÝ/ƵSPq 71!̙VZ7N/Q'6 H;ރnp0j=j8.XG4;knA96og}uAꝳo$Dp8ŭIz^w/3j38hpY)_历]~L}YYyV`kC}6DV>3Vwmݹy]7-U̺{öX5Ԅ.V9w!h!6ԃɚ՛ɒ*\얂WD<6T:Wŗ) jЍ+[T^ZS6Ce-C ,мCmŗEw:m5+E7/475yWѯjh*\Zgfb@_k/ nVسZڃw}Ӹ^K&ϧî3|I۫c4SH{b8 2+ŞVC ^nP}΄v=*64֨ٚjH%Ud2WFG.\pǷ [ }d2YŢ>p˞+Q)c Zޜ+p=_Y)k E{U+fKܲ|oO:=%)D+Z3z5dcЩn/mZFYX[URv컫eݝ,6)X~ʛ!17a0w8jO "D[EM8np{5Wtt<3v4 1 2Źx(TGT5-¬6kVcyC$o«@J/8GLxR\\+dw͵+F KҬm&d/s8ũheӳFj>jӼOEqw˚%[@b tAzHo{jc0 aE7':7Xu^^b(WVGUw~%&9Cœz}(KϊtTA&"QYCm3"VT;$(QTt]W6V7˿%UG6FDgYC᫯ x1+SD+V.tm%/D0/6ӯNxEPB_Վ}v*Բ=Q`q9S$_k^V 3LVC>ߌx£<ߌV_.KDD8/p8cղ.e/*;J8ՊČ93j=ȅblJ`9^69m,n"7s,ukZ-bC>֊2jH&;oME8=/FMEE4V)L VTg [Z'j. ׷z) oT [@\OMZ"նD/׉oОڐ=WT4 JpSQlϊl1ig2d]vmۍ+"-O\ /NnJ)>׸F>ۢy.jIq] FtYO:[Q9?ֈPVy(`m="Hr_xQsD(!;ms(+^8RER+x7b^X^0ql{p""Y.WqAuMINp#T~=nVVwHI)jxhVOg׽8;BXMCWkZ};Sƛ$W e'$jPe%iSgģ+s}D<^OykQpp}+kģ^#]{x~;퓜ƱȁBxp{}hD8v pģaK+]Y\r5 AJmD3=+W,D& ְ6qkb?Z#9%t|aYɄmhJWpUJ,LГ`"(m!r!3Xx{㤮=E\Svv`k}<C O}~XfY{3{MPJ~= E-3,<ʪWTy_cVw Y_~IA~%MXÜUhKU4~48jD~ ~{_z!B1=.F#`+pwaGcuŠX?<<ϵ8<㨟~@VrO82G_p̙h\Rj;cԆS2Oqxη~j@+ckX?|;\nqukԧdX ٵ"֯9Znn1n?d&pXqwG-S+Xf퇛lXV->Cva|?#}TX%bA~J|$'O~_Fl;b+.cڙQo/#5n~Y+#Z+#Zxm.j9aX?2 s{ɚTo)"n_;bw/䷽dƣcSg#_seO6"_l.-2RCW$BZ5g~Zc"̹i1glm?G_8nWs^HGG_X".-g(b[{˜YCѢ=Z툣mEPB7\ xX퀘zNRd ,PæwwFd@  !@4SAo%EcFMiNvi]07`jQSp:ݜ`LaOƩ'3**wMX^Y8Qy(Oҳ[hv-0NGG's |Y \CzmtWI3 ,G`g99Nݛg~vM?>_LA 1$:Yfu֘-_&.| ro/ImjeiYޫY>%,ը,볮,Fe5>Iec^m9EiGK5f#H玃![Bc[YSvC+41uL&"#]mgۿ!qAӂ>S.U_/Xx#fi'j MQ@ՐlO!t:CgY[?FQ#)̢|ѕe{=Sl6ߚ}Yc9s4g{bHӳM" e@u7rc)kheQZbPPu>4~lN\w=ϐVS|1Y #Rf`ryfXfP!j+1gZ.c%M.zqg0KĊ%տ 0x!˰F+uSIvoV+zdmx.p߇Vut'hDN/aW+1֯1xRn7û%kAeOZݿbѿ~=(3;F3_~z?U~R+<痽Lsj)QC{p(UㆤQ2gOĪќ2 #T[`4ZS~Y33ik_3hMyGP.p6n6&he1!&?"$-^tQvs𙲼Pe1 m"3ٴtާ͒NMn4Z\kg`vm"nM8_nn7_}l*_ Bc)c+b$#_x>߮=3A}QYcp-I՘ZdX/4`n|XĹF6fuɶ5}Wg]OG3|y&O옗NE?8O` t{a_t+zMt@$Jܝ Y)8R'3XLdp Y{3Sx3ӣox9] Wl᭛U%t<Ǝ-|Ӣ>ojn /*J÷CY\r:_LdȌ;-9E.{x_zJ2w  _ /!z_Ҋb3ry)x1;#rWQ-^,d7^menlSK_je@xfOy:TcCXGD>|:>WD#s<5Fxf.^or*q7||l?:~KY$k T(J0kt+-\9ux<|xkp !燲-z%`j.\T nx<||Tp~gq3σ*d=pp#G9mI0س/";z(22䋷K:{<\@b7)CImdL둏??o?/?:VFB>~/pɆ%uǿH?1=Z爐__}18g/`(ćºT~G5T͋Q&/D R+Wˉ{>ch<_ڮߺۛ endstream endobj 5 0 obj << /Type /FontDescriptor /FontName /ArialMT /FontFamily (Arial) /FontWeight 400 /FontBBox [-665 -325 2000 1006] /Ascent 728 /Descent -210 /CapHeight -34 /Leading 33 /Flags 42 /ItalicAngle 0 /StemV 80 >> endobj 6 0 obj << /Type /Font /Subtype /TrueType /Name /F0 /BaseFont /ArialMT /FontDescriptor 5 0 R /Encoding /WinAnsiEncoding /FirstChar 32 /LastChar 255 /Widths 3 0 R >> endobj 8 0 obj << /Length 754 /Filter /FlateDecode /DecodeParms << /Predictor 1 >> >> stream xMo0 t܀,[k(5vIĭ?ZIm$ۤ ~!CfV))s< "2F:-%/^EȧKv>e^nӹW>ݘʹ/ƌzjq"ç9̧s&<<~1Ƨr~? nRj@yOue>Q9LԗA,擦Jbެm,F:"4yz^Y[1eYa!-j[5ix6⅃xnN4mc+DD,Nb^ټxiQБnu%~ w!r4曢I.h)| mi"KڬRM {q05N"]tnlŦA+iw'tR[leo‹w^wUfodHmQg;٭-WtKݧ*^oe2'G 9ˤէgOSn^9] /BitsPerComponent 8 /Length 20902 /Filter /FlateDecode /DecodeParms << /Predictor 15 /Colors 1 /BitsPerComponent 8 /Columns 1175 >> >> stream x]V:aq>̇u" 4iڦ$(sVDMxݔ|Y>^hKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKY,&]p] ] GQgfI^] ] Ge.g^] ]Lx!EQ|ԨVgҥKH.it %mbs3t&ҡKx]B:t ϡKHLk>zg1Cg.!15}4oK̞|8H?(ηңK.!=a¹iU.a9@5 6]Bzt %G0 ]Bzs^=]B]Bzt %G0̽.y0%5J ]B]Bzt %G0I}dzoXVt #٣sѦO{6]Bzt %G0}V\Z5H+ Wf rbdTХKH.a0KH.a:4_Zu31cJ5 KH.it %oQysXGEQVq'~fKG͕~3Epc"y[gȈ.!>qK[Vr3$..fq2g%%%KKKKKKKKKKKKKKKKKKKK@뤋A].%$] ] ] ] ] ] ] ] ] ] ] ]8Zʽ8hKx?tI:CKxy9`xD}%i]ˣKC%H\4KyڿO]]MC ].A]t >iܯX,}[P7OO8_%L..aZt m8FlV,B;UHA ן0 uʨQ2\Avt.M.!H\n.ԧ}ATY41ST{)2;"EOʇg 3KIrKBB3.@EV{Z77[[:6$um_rxI&=5vfsyW Fbbόw8ijSNMNH.ѥХ0]BY]j?g <9d~#^/ssoánQCbTcsT$MLLR]J.] K%tԥ KzڭV+w(0dfgux8}k zZo0{6?nT@tTK%tK}2]..ٴt:w5![_0B[ wIoO?:koO]c `w*alR]ʀ..D2Kk.qVoΧ?>1zg~/g_Vhk->yݠTdBK.D]2i+ r }w3t|4?Ł#ꘒOV{ώ?|;wH~ט/2K^s5'%#kJxt.F0]K% %KsϗͲMc K;6\sS]D\Iy>:My-6ԓXۑL-[K|`d@jҟOt)GR[.ECH.yן9hTBMT0`=|Є_%fCo׺sGjMV+gڣmـi[}UuESK']ptDK.%!޲OBVEiNRvvB1A79riu9DT[~&SUQmÊsj}j8O&=D"k_]~j?5}{٨i? EdkN{w?ڭC5R{pGZYĽ芹ٸdw )nWun6Z5Z3O@=Mꇹ&~j^OK%]ht.EF0$]vϦrM˥놅w??Ž,?>cLC͑L}[;T'nG2x75ۚ yYެ1ɤ=2Kt)22ui]FWnTV3X6vhz\V-jқGywԻ9=V.ӕw˗zt'*]unz˫*O&[|پƜv\WWQ dik8T_k~̟Yj<]VZq6@7N?}~9XTD"KƢ%]55Sl G_;mn-l~|ڑ.ѥ$].ѥ$]!~>=sީ{eSxlQr_o]299ѯKK|a3TZ[]uwo@yCZ wI?޶K;}D$Гgs>,DKti]x*OS߁߷{~em_Nnxեѥ}1N}7xjGA@.|惫=A>n*m+_ۯ/ nvI<3`DKr%]+ %s\c= f{vD? uɼK'cե汒z{ys 7IN.l}jE30]n_2Rjt.EF8ERdtIY9m1oos>O9LB3U~kSTUV{v P_ -JKz?MphQ'ӥMy fy\){DI}RAhKB* +tg@gԂ/YLfna:%{!i=*D"Kҥ].Ifܣy|\Gc[_7\alY{dc};dHTo][cLzԃҲZZ(Tb)rS1x{1c %7L izn;K|ӗܔ?}_.l2%3$׾'sRK%<4].ѥѥl]{ yw{-33FfqZl_"ԥjUwfWo՜|qWIFs>SfCz>)h.7|p)0K2Pq.R\tI|U.}^s]2/􄼽8gN=y3{Ox]}wQglSDy{jԱO%IGҷA4f;RJ3~"YG= O˧fX??Ubϥ I3Qѥ#].DRKk]J^ =.`Ҥ7#̜8SfB4-@ٖqncމΝP nq) vr! x4cm<¿KvDɽZUw0W{!^hVrx}sѥ׫X.o.;V]RKoI3Q%].͸GERdtI4.2Kw31Tѧ7TsC͓- P~<7m~WnL]2O[pkwHlH8օzx?R#P3d/Kx4sIO3{\.82n4]K)ƚ. fܣKt)X%Ҍ{T=O(ʍKƻ%Mx.vCءML/2KរL3֭.Ws]s?V)RK3^Li=*D"Kҥdu ~^O5p;U~j P]]wTKO'b>]z2q]2 ]rWh~i=*D"Kti4D"Ktiz.Ǽ!2%okR%v[gOld#FNυ9>Tqfm_%qͅǹKAR1kKKpTNs>XӥCϖ.A:&ȩԽ|K0-]qq?`5 }MyAzHwɌ.- g7l~ܽg6ۗO%Uۥms᧧gKM DC_Nd[tohzt__Kt.ѥ].ѥtPlv?+3Rx In'{:~V_F'z&].ѥѦSKYز:ω{fֲ}gsKv 钾N.ԻDKJ3.Ng붇bUiTΜVܕ?]ŢKDDR'DDR]*%-A..t[w.Y tI}ti ]oOY=OuTόN٥5zvt)8MKt.@N-2]:Vh|m8{إ~MK})wT7KY t:IqPoUoVvAΎ}蓩].ѥ].ѥѦý.4>r{o]nJVTNץM\(]2+K?«=3)7-fM.bx]RջTtKutiDKutiDKu]r6:6*yU `տ}uISTnKmKw~)$rkҌy 5Q6}@e~ZEs]*W?KҗOI2Y~O.FR].FR].FR]KM|Kշ{/[߿=DGOwP|rIJ̯ݪGEۭKd~~5/RvIo/WOwRx8b̔tҥ]Kti]Kti]2e}CD\ziT۟j;/=٥"KYfͯVS پd>R}t7]^j=]:4V[\'^*u-=t)=D0t)=D0]rPM}w7]2»QvSuPXnN]r Rwkz(L9 L~~je. !'iL|V6oUۗ~D}kn!rp9!ooԚG1=4Ttw͹>u@cHGӪۡB9ZI3%]K%]KMݥjCC] JNkNKϴ(^xw.9.K.Jf6ۣ.5~fKjA?>}: z5܈~{t.EFht.EFh.sbmԺMϸ_}zğF>]*} o76P46Qk7Q:y]kʿQtzU(=ץ %5h].a4D"KmKXJS `ޓ{M.K[Ԋ`8ՙC.55#XǸY9.y1'] \J-`,J{;RGw7]O oT78w6ERdt.6a'>oyrnjxNBnPzWDW{s;swGt.EF0]K%6q65˥ܕ&Mf>ԣK?o_?E]}OsuIQˎ9cMxOKfgjKݾ>ץtw\^ku/a,D"K.ѥF˿})Ч׏ۇad5QEIKի.偂ߡ٥gJwɜޢ.v=~wi>t߾} fNQ juI} _zz]K%FRdt eRwXݮVΠAevoι»bA_^I躤x:w>I&bȳN2kl{WQZ){"ڑ;VmU~6'X vVWa l&BmG.}}O%]ht.EF0Z.|N][ۚyios{j.l¹.}29߉c%}ow>&.鷅ـ~i;33t{}W3 >o蒚i.ѥFKt)22uN:iQuӛnHPDŽxwM]Cw.yۗLTS|+o۞v ܦG;cV~So 64MJYuIMWwI.ѥFԥr3o?o3zZ䦅~1I~ZOBV?3ӿ{95;vңKY~|IάfPo+K;/U#> M~(4SKt)2].aL]^V5]*Af%*BwL %w[]jn_2igJ6})֕Э*Kv/W%7p-!;^@_/]a6t[{_YЇozAˆ*%DRdt %]h9^n&=+]gx_v$67ׅK-gd~gJeVZK>mmtꕨ gkz~M iӥO{~t))D"3.aD"3.aǙlەjc1:aK=2+tsV䎓3.ۍ.8Q[$e6Dlַw@Gti)X7z-]KH,D"s+.YdgħOJ3Buj5bC9mnHuOpr[??ޮځNFLyʏ/apT&<]7\w΄ FRdt %]h)wn6in6n~]m,Z/u݃"هٸoK30mm!K!Qv]j70_@RkGq<'KEQ)G“ߤ RxRLt ѥ$ҥzK׫zআy8\М%3%.I9]>051qyDiTmRIfw JyХ]B7@2K6aFL771uD)~\{]r ozrЉO>LB'9x@y`w6t.eDЅ.ХL%5i| 6zvU)n{=[>ҮyKՕȜ˻e} &Ά.GҡK2ubNݜ {Μ4]ZU'?1N'$m<>NsizpE"q~D^༭I.[T  =|9qӴ^9i:t.M. ]KSK"KfoKZ®\[uo72p6vfS"c>D&DD҄dt韾 }gw_>3l\:MKL~ܶ4m6viw#.% |bxWP6+dZq_N^ UͲWp9!Ap/Wԝ]KӠKF4Imj{'߶5Ttw^hzk0R t.F]Kѥ$KpӾDw%{nnR_Ězuo.%@Ditno.kv>;)_zە&L L.%@DitɧbsT~%6{fOcPg(wuc`t.%HC .MiKt ] KR)>V)ѥ>R|RtK}ХXFHCHCH#Kl] .xGt 4t 4t 4t 4t 4t 4t 4t 4t 4t 4t 4t 4t 4t 4t 4t 4t 4t 4t 4t 4t 4t 4t 4t 4t 4t 4t 4t 4t 4t 4t 4t 4t 4t 4t 4t 4t 4t 4t 4t 4t 4t 4t 4t 4t 4t 4t 4t 4t 4t 4t 4t 4t 4t 4t 4t 4t 4t 4t 4t 4t 4t 4t 4t xG]scV}SG{wޱ]'\ )KKLtZP-8nnߘ")sGrC7EܑХ)r2w,Gr֤%`%9KKrcxiR#>@>Rz e9y%aB, ^ s'$gIj;%9KW#eHYx蒜%2w,GNb蒜%KL<D?CM[.ux bKR*t x]JeKrחdERsOzAf.%<.BERKnחdERsz/ǔ?>41E.t)41E.t) tn6b1xK2Us/0]ߘ" ]ߘ" ]ߘ"ʤX?1E.f |x9.oL ]J.oL ]JeG=1WOϧ\)rqst:}~~N1CR*S>t .2ߍ~c)^^٠Kt 1Х]B t)&wM[כ]‹KL<-M K Ҙ;<t.Yt)D,.)bL]³s|6{fti~c\R*ti~c\R*2gߘBrL/.%$@FKt ХQuit?7?r, p]7ХTХTuVFFU.K<@RKSBRKSBRݥԯ>a94)rKХ)rKХ)rK*rN~<՝Ɣi~c\wtxQti~c\R*RYVg41j/LA7ХQХQ>.&\Vz_%5GRrt /."Kxt)ۗ6ƨ9{TS`>G]BtiD]EdsObK>Ǎ܍er(41E.t)41E.t)41E.t)t韞32E[_*7~K0]ߘ" ]ߘ"ʌt4SAR% ߇.eХTؾ41r|Ati|Ati>syK]ʂ.Х,0vbp|R/~ ׄU%fARt .eANj*at8W^_z],v @Kt)  }ÄDd٨Oz}kzoե;'Ϛ?9 Rzt .GWՕΚx Rf_`3/ըW+7!Rbt E?slUTngS>3ߩCt Ȃ. @,Ld]dH.s&Sڲd%64]K%2].3,{ @7CHC`0@@걩.FyFdLhnՇP(v3K%it)<ͻH ͈nkzWpx%+BХ0]J.M&Aֆ;uÇĿo.%FRbt .%Ft郍utK%`0]K{n]e!t)1 FK`t)bnS1R^pwQt bХ0]J.ѥVΞN !K%`]K'l !K%]zK]]]m6޻;w K\.uɼ7yBAңK0t)=CzvwMI<.@Rt jZ߇G|>nWyK FzK@Vt@%KK m\...a%%=%<<2N sb@Rt 4t إ7n.a.art)  @K.c ^`M%L.k.art)XSt /rn5nwLHB]jJ).ѥ ].Y`;2iRoSk_Ur.ѥ ].¶>_g]&XצTcz.art)  P?(nZm6(^C Wu%ovRt .eAv~G: ]K%`$]FK%`~У!5vo`]ƣKq%`~Rz}y^]xMVuE ].ѥ0rv}RZ,+Kp^JKht ХD4](|Aaz-^v^{܋1%L.eARt `t>{EFh7uk}]*Gfۛ]?{!t)  @K@.zcIEⱨSsR[? DGK0in7Puq(t x.GaRzt @5H_rߛZG_ؾbp/7]BRt .eATC m]#__w񹷢ThE:&GKt)  w$bs1@9Nn&GKt)  B~W]Ro %L..art t %pgzL.eAB;Aá^e}m/~+aL[KY%`]p|ѮU=4k?S/F ]J.OKI%`zbV꡵I_|>*G+ᾛjfgлBO9&GKt)  pY,ժ(~G=Fו{4-TU%SA09]FR#̏QԋA$]KY%`~i zK}3+yKt)  @Ks{t\np݁0]ʂ.Х,rw@Vz^9cjm]nK]]ѥi%ۨx~ۥOh %0ѥ,0]ʂ.O^bxY[6-uX4 I]Yt ХD0zE&OADKo.A$zV`̤roXh[i3xnu#3"'oRzt .GVUQU_nW&ԗZ'&mQLO]KY%`jlQwj;Lw݇E@v\ .art)  ůL.^qbfOJU溢K]ʅ.}ѥ\WK%(/=L.=Lޥh}U|>/hvZp:zG^ѥ]`&u)wz渊nuJƬvϟV7ɌaRRt x]J.}*ue\;Dn8>eqF^].Х0zQn6x<>=\ Q\͜X޺DxGt)= CңKzT^ɜZЯL%t.!t)  @KGlwy[/M<Zu]PO$ZW5Q7|z_vz:Lcrt)  @K/^[[}~{'d19 ]K%/]'crt);<@KuxxWrd@Tvȏ.art)ErKH9?@5^%nkK.ER\t w0:t). p>n(ߙzf?ݕ4Rt .eAY̩%M5ާK@]ʂ.Х,09"ԥjUZN =&GKt)  б1Yp&GKt) @|&O~<%...Zz9KK\.ޚz2N|" ]] ] |6Wf:BuɜR^iii5,i@@'\ii:/;CL..&/] ] 1pV&XiQ^5`zךsܜ\%%%BǢ(>MI @@Us帺[{S/...U..&tT',t xt 4t GHC8A/̉YI%%,;L@ϣKKK۸^jSRʺj\.o..rEzt8U7/S/Z ]] ] nn%Aݼri>>>Z/N%%p]%%%%ҨnK&CHs<P%2{1]]u8%=%%uDAHCt^%CGBHCt 4t 4t x2%=%V+sp0@v2b%}%%q%%%%%r\.nQ^)@`bEQ..fѤ$RMt xt 4t GHCHCHCHCHCHCHCHCHCHCHCHCHCHCHCHCHCHCHCHCHCHCHCHCHCHCHCHCHCHCHCHCHCHCHCHCHCHCHCHCHCHCHCHCHCH? endstream endobj 11 0 obj << /Length 112 /Filter /FlateDecode /DecodeParms << /Predictor 1 >> >> stream x10ݧ +uBUȃ 7~3Ps]F,gQU 6m@0] /BitsPerComponent 8 /Length 10673 /Filter /FlateDecode /DecodeParms << /Predictor 15 /Colors 1 /BitsPerComponent 8 /Columns 354 >> >> stream x]r:Fyⳟ'/T붚`cR$h[Hl݀rP,rP,rP,rP,rP,rP,rP,rP,rP,rP,rP,rP,rP,rP,rP,rP,rP,rP,rP,rP,rP,rP,rP,rP,rP,rP,rP,rP,rP,rP,rP,rP,rP,rP,rP,rP,rP,rP,rP,rP,rP,rP,rP,rP,rP,rP,rP,rP,rP,rP,rP,rP,rP,rP,rP,rP,rP,rP,rP,rP,rP,rP,rP,rP,rP,rP,rP,rP,r!gP(.y{z6?f3Dq6`vJqh>8]vߢ1GA1[P<Bj {nk^h?"$(Fq cNvGb`:,ؠA_YVGBD,ۂ ׌ vxN7Q|>RֵxtGXg(;]_|lHÖqK7E׼zÙ]%Pr8gלv5???vam ţQ-T|α,d Lqc4yra#Ox%P|m/Q0Vvɟm>vgb9(P(+412K o}aYݗחחח!eolh%^ VSl8Z.Y8IeTj(,ߔCeiԮw9(o>G4ZMi~:mj:MrP,rP,g:M#ӏɌ_C_ -qQ\nu*kn߮q~lk`_MSڗsTɂP< XV>q'wa9nx?r|?V t8XΓ)\ 䟇v:ɤ^emA1L'eE_P<AgR~p{ዚx6(*+dw;:n'޼~V8P,+ۖ{匍`.qͤb(l&(;*M6P(++gXNGcrC1Q&(b95㻵#XsǍމ!&pXmUMŷP<rP,: 6l,rP,jkg[,zn({b/"fGܗkxR|x`ȒG1P,v44>[LuŴKl6y7?j6=(PP|sȣ v9ꌋz6V--odey$ˠ>Qir'+K~, -_z|x)Ve86=ݮK(5+yN/F1Q<{N>ؐSh`bx]r{n4X~hF[ĉ(B6յG)]UW5#X;y}RoiP\űX(F-f'?w\猪ߴ*5 WTnJG(=B1R} rLZvDecѢ|kѣ>TPAPCAߋfSՀ&"V-l{9Db9Z>\=WIXm{Ny"@=b=(DX-#V~sz[m?DۿF=gAqx(OF>cX_puCvFX3ef>'b@y=ݺőLSJx (.b9(hſ^]W~lk4n!8|2Va Q):ga,mMky]$(͏o(cLtR3s-Kt^7}(Fq.}RG!&;P< A;*Nkr>?ہe;O`GdEhz"bC/+q@UZv`nh3ʓm܏&/(b9(Ql).6%P<ؔ6>W(Q{gQoI;X{1KxQ|j 6\ >tAJz)aR>T(6P9gq[5xqSŒn<&}#3|OWcSy3{al2P,rP,gyx3H,;ww]cۜHɏ((.≃Uvϸ|6^g9`|`j1Kx@qذBŸBvV3ZW 5.eW͋x6(FH0ގ*Ό| H_͸ڡvw^h|L'ڰMh_:2lQ{(7 {wK XU'2l@ߋV9ThCNx3іWpg%᎛NLFq:زCMFq:زCNa(m|t4NN׃׃ߒHB]*:4Dm@xB9+^;i8\ T\VN6u/q/?4rP,r*p#v;ˇ ܥM8Q`deP\4db)enA78w~:rrr=Q\r@]5)A)A.KNWڛw9v@DPlP,rP,%{84Sub9(܊OJ9n+Ay1f]S~dv~eP,rخ}SʕY9VKSj>8eUN(.b9V|Ns LwjgmD,Pai!|i#Qy>[߇S75u. */rx*dYA;bsA`_GQb꺻s+ݢ/:7MG]c^M,"A1 ?Q\:R̒>MGO(]7G7Ziw(F+>#ϴ>BdXmԱގQ>??;_3t(.,(b9if uY9M3tƫSw47IģwkFw8/z$4]'ȝC1X弰ٺ'UlD楎Ok#Qr^Iqsԕ)f%L1ɾ^by5ũP-k=boAqUV|gH ;6p7űޣ\k(.mx|vKDy~ʍ}4$IQ;N b8{)m߹YW6w-m~ m![4mZ" Yžj[mѶ L$f6,"3}~WGq ,(C[v~E sEBq ,(ξ]6-)&]R0+2(΂,(3.o"ͻP&*2x>Yi%_V5|}P,"(g>h#UǶjw_9~@XX}ESϻO-3`Z(VqHW{ޛ7{/DjU%Akidŭzūj9ҪPJ{AchT5(PlcǕiKAf2(b9o_H[m??$ΰ( (.b9okuS#׭SEw6 ; g4o/7y?P,rP,xxC0G얟٣qW_Y ŽX()=xٶrmNӌ(b9(pn[pH~GpE}IBq =k•ܪyjAq ( ~s慻hsP,r^B]g(J95f8+Aq=(^l{GWARxrLbSPŕP<r2 +cMHgxJ_^7a(΁ P,g*Ys DfL6,Dq b9(c=(~@kb9(3^FVGjOUdS!(^ A[#ɔ???ֱ OM13C-|:e(\,}ѮmvjָUۖr3kb9(A1j:Z#+AA(s2FZ4-c +vp~P,rP,rI pd&:wkscXb9(r#iiUii(b9(3ƑXn0; &˛3(YP,gwW_0;ܔHŠX/ ]#9ՑɌP\#8 a(b98L2ӝ]}-FARovy]ma~6Q<A Vu3(b9Ⱥ's[Fq APYd(Lգkb9(*j-1'_ߧ3L?D1Q6(b)Vh8j D۟ y&p`!o+rP,rP,rIOhSvdrP,rMԓX66n<5wk^jP,rI *f?]>%!LGvK0+n1>Ay&Ň>z{wre:V!5Tv 6咻(.(N8ZsƆ)~!nUl4onUC(.P/wk}k\MC()l2h;Lkw#re3)IG1G@k kGHim?TbSPb {/lhHܜbQ uB]ox6>a-uNP\X(_3 6drذF6 (.b9ox͵&n6L~Z_@AṘORn[dՐ_. ryӛ @AW|Oq&(b9(LGm;XN'Iģx (b9/xSڥRz%X(6MiS쿶)C(.b9(P?a/?o i{TS*SŷϠ%P<yF1͇Ao4D+]φbSsP\#8 XC76a1@^1Ъ6XL* @$>m)Gvy"e]P,rFP@p9z.KURۭ{kQ\#8 l{6#l`ɏMjq9֔%G_AUS1zN+u XKxAq :_pG5AO$LEUsH8_yH)(}P,Z{3SCUŮPqKk҆[fnXX؄X_7zTL1J[?SZ q.8,@qRl$Jk{wZHQbkb9(39n2v0u"_Q\ X弇X:wѧ](.b9oxM}:BO%Ŧ3Agjj]z) m#ri<ĊbYP,Ǘ=Y䭒_Q,r>HxJ9MoVъ%A7C#2!^n9X}Îh9ﴘ|#ymK/57 2ֶڮچ(6P(cKv LI_ܜ /惭XrP,gpȖNJ0O$,KxȞ.3z&uk8@Aڴ)ۀ7R*owwѪK(.Ip:"[bm8Q6(]5MfNYmZ*"ԅئalk_\qѝ < Ng]ڲIbZJ(.0(F˙ ?Z%el]gƪ(=PeMvU_4oǝjA?XXb8(gVw64w9OͭQ,rP,W{}k'3o4*S<%P,Mڽv{Tn^לNz_KsE]7`{XTHOPOn> >> stream x\ݏem}LZٷIp 2^̇3KRsysDs/pӉnr_ hޒ(]/_=(]BNw\=|?U_߾qB'p~w?rz~.CJ_!޼_͟o~Z "-x}>_>}ҕ|Ǘ[|ou8!;y||-/uy"zBB 7_"}a\]7o/>]`p|熗6r 35ǗW/>3@ {?2kH8م 0rpQBxM6+1~H!laa#82adx0UtcU T1~>Z!68w~\pxH񧗻^>}D ov{eŜkj߇ۗ>|$ nQۇ_>^^/ߑ$酵y{ϟ>? Z! y~g?>z;2;|~?y*%^몌{W^#Z<LJ_O?GQởRNJIZ$T=FW1N@:F5:ǎ[n5Wܽ8+ 9c {$[(i9z&*fDSc !LkwJ"!aҘ6D;PP[E^F㚼}(L9W9dƱҦ}3Ñpˉ+X l(+S9ugp yF^c8Y #- 9ktpZp.3vlPIlN #IHl8Λ+~TX.:ʹy;q#uLGh5 bֻq:[t7QwLZk,*RKdXvKRQmؼB5X1ob&Ērd֨Ȇ uwzQ8ŒD?L:ՙǃ(:D#9C7hK DAnv>OgpML)W#3A4oiAqi:qoN&qԊؙq9xqi&ⲩr4{8ƖE\Di9#k?ggAG2O}VJg!w2\`nf :96ȩɇ)hL3jR>rr#&W"VzrdZskYyLJ.ǜ;;l|vM:ֹjDmڱj$Z5e3AmFԤUV+Uب aYd=71(1E ִ>Ȯdץ!ZJ-,m+d ~ȂwwtZ9aI#T9z,f+a!тtZCd)E@'!g@ô*##ĐČi*yvtǔܒ=9r1h~z:4 fŮ; q _8>I9hk/ЊWpPF)Io|2U쇋fM}p ^su=}[{V{\3V [tqZ\On]O n\߸rbqzq΁ [wS]zv}w>ZkzZӵŮZZpZ瞼⻢u:?{4*qIw AzH 5&Ncs YH0m zjhFm7H&A%0M>K)@ܵƭS4ߏp^Pˤ͒T! =h7p ,odC35u,V:R8bR"e;)[I*%CQ2iomN[HXo67lpMkcoMgˬ΍7O4odc 9ƛ4<΄ƛS4޼ߝo87moܦ7޺c,QJx봌oƴ4L6^x3qjo{lqNPL㍳j4:=5xsM_xBƛ]عiG[a8xҦW˹ן=6޺z+7BiZ\Yoƽ`ZoSoqIۣ*zzxu x34d&LX4,xc;NPLcLƛQx39zh57Afrx7Q~27ix3~67=4,_o4c㍵Zxc|4:=ofooӦf4޺&ƟhV%io"{6:=!BmbWji۸cAD2}]Ԧc8kƴ]/{Įm$Nz^ft-Kuk>UGYQOzcͦ:TWOƦ /Sy8;f#Eҷ0m4=sSc=g>mXj]&`qRLX.5 0ְKI\msqw0f1x*5͕s RCncp#Lrfh$PP:y@.Cπ]3or00#:C".8u u>nZ&ԙE٣l1$kpd,.4]n.Ayq8Nܑi\ǺQCr|Mٹ<,qRQ~8Q hjs  (}=φ32\)0&:єg t̚y:kfhD?Y3̚1sKN iΚEgrcY35aΚ欙iǒi#z( zΚ:}(sJ5-sh999k39h"bp&?Ǒlr?gr?arܧ=՚)m'J% cD)Mrmn5UnK'6OM]'5 c}z>2ܧM97L!gst}͹6\,is՜T%γ{3_` ơ Ut:*4Uc*[AQ.(wme23CM~δ9fMΆ@Ξ9 3g0sLΒd@vXr,YxYXsbYrFHkⳛ79KM]fʚ,od]BHQk͜3R^#sT\"DgʅceA|rN˹Jxrsrb#.;IД$*DOS.lS3)y=a.s.Jm- ) ν6 ,e }wӡ CԞ{( K&Zdƪi[$>\Kos̏TƒKn=gp|88 Ha/ mԄy1 9\q?o=F Nt:4^ +2X'U'c)Zל ? 1 S|%;ġ|ܙN~,n| >>|hh ! ߩ{ot-N+ĉm '֨z N&8ū1g,81e3Ed zFopM;GFOp'a <_/^)>x.=4gn9CsSOU j8P $'Cײ?<,y 9R4)$S"8`@  ~0y ABhg<7y xJꌇr2|B- M>{)2u?x8ipV‡H! 7E2~:>UE c5>Q[4~d8HthC"Ij@NɢhsjE]թ:ݼպjݒB+:8uѠBJBT/F/Fwƭ Jbh1Tq65\E:5:{Afkv| udETZ,ZmЊպ5$v;5x1YI؁Fk TR4Dlb ԔDg"'*EjjaE%l[:gP4:V<1s< fJhS ͋"g! HZ M*zJhW "Jr -*5D$YI"H%NM -_*mJhS "V)EU%ފX4ZnК>%ԫ!@$\7$ *)X4f$d5?Sx+&45XS!ZIHbM%))g+E,USRպzպE vJZZZlѨJ.EuHAJ|J|5Zs>%!X4њ"IJo4TB{T;k̨$kHobR"I).6y&jh7%f= "]xIlV UIЬ-4odlyOOwd-ZF%A{qt|jP-dE3qJBQCh+Nw8%>~n':9њkp}1%&ɨS'_q}JF=<>9E`kJRh(ZrVXU-Zj Qh-:x7SZZl\/p=-EJ*!ę}̟O~g|Jޣ,Z :::U)4:yIhg"5q Qk>Ͽ{F#MQooTfٯB`{Ei4@djT^4]v8^^;+٣[!Xtsznt[!#7Ic% zA_nטZ"c@,󯚐 >0e?N9=G~Џ#Z¼T\?2#L݉>H곟lb$~#)M71\i> endobj 2 0 obj << /Type /OCG /Name (Dimensions\(ISO\)) >> endobj 7 0 obj << /Type /OCG /Name (Symbols\(ISO\)) >> endobj 10 0 obj << /Type /OCG /Name (0) >> endobj 13 0 obj << /Type /OCG /Name (AREA) >> endobj 16 0 obj << /Type /Page /Parent 15 0 R /MediaBox [0 0 842 1191] /Contents [4 0 R 8 0 R 11 0 R 14 0 R ] /Rotate 270 /VP [ << /Measure << /Subtype /RL /A [ << /C 1 /U (\ ) >>] /D [ << /C 1 /U (\ ) >>] /X [ << /C 0.44234 /U (\ ) >>] /R (\ ) /Type /Measure >> /Type /Viewport /BBox [77 2 763 1187] >>] /Resources << /ProcSet [ /PDF /Text /ImageC] /XObject << /Xop1 9 0 R /Xop2 12 0 R >> /Font << /F1 6 0 R >> /Properties << /oc1 1 0 R /oc2 2 0 R /oc3 7 0 R /oc4 10 0 R /oc5 13 0 R >> >> >> endobj 15 0 obj << /Type /Pages /Kids [16 0 R ] /Count 1 >> endobj 17 0 obj << /Type /Catalog /Pages 15 0 R /OCProperties << /OCGs [ 1 0 R 2 0 R 7 0 R 10 0 R 13 0 R] /D << /Order [ 10 0 R 13 0 R 2 0 R 7 0 R 1 0 R] /OFF [] >> >> /PageMode /UseOC /PageLayout /SinglePage >> endobj 18 0 obj << /Creator (AutoCAD\ 2012\ -\ English\ 2012\ \(18.2s\ \(LMS\ Tech\)\)) /Title (Model) /Producer (pdfplot10.hdi\ 10.2.51.0) /CreationDate (D:20130829102832) /ModDate (D:20130829102832) >> endobj xref 0 19 0000000000 65535 f 0000061297 00000 n 0000061359 00000 n 0000060373 00000 n 0000000015 00000 n 0000016576 00000 n 0000016794 00000 n 0000061417 00000 n 0000016966 00000 n 0000017826 00000 n 0000061472 00000 n 0000040534 00000 n 0000040753 00000 n 0000061515 00000 n 0000053231 00000 n 0000062072 00000 n 0000061561 00000 n 0000062132 00000 n 0000062347 00000 n trailer << /Size 19 /Root 17 0 R /Info 18 0 R >> startxref 62552 %%EOF PyPDF2-1.25.1/PDF_Samples/AutoCad_Simple.pdf000066400000000000000000000057071255324530700202440ustar00rootroot00000000000000%PDF-1.6 %ޭ 3 0 obj << /Length 152 /Filter /FlateDecode /DecodeParms << /Predictor 1 >> >> stream xU 00_`tT YJ%UAݴBxdX9՘0\aѤIe/C\R 0E.g5|` J4YսomW/Cggkֹu3"`o>vpܝ- endstream endobj 4 0 obj << /Type /FontDescriptor /FontName /ArialMT /FontFamily (Arial) /FontWeight 400 /FontBBox [-665 -325 2000 1006] /Ascent 728 /Descent -210 /CapHeight -34 /Leading 33 /Flags 42 /ItalicAngle 0 /StemV 80 >> endobj 5 0 obj << /Type /Font /Subtype /TrueType /Name /F0 /BaseFont /ArialMT /FontDescriptor 4 0 R /Encoding /WinAnsiEncoding /FirstChar 32 /LastChar 255 /Widths 2 0 R >> endobj 6 0 obj << /Length 150 /Filter /FlateDecode /DecodeParms << /Predictor 1 >> >> stream xM= @:k֎ZX:UJ*v]$CI`1p a$0KuX?>I2? d׶ӇnOvTְ(iF^> endobj 8 0 obj << /Type /Page /Parent 7 0 R /MediaBox [0 0 595 842] /Contents [3 0 R 6 0 R ] /Rotate 270 /VP [ << /Measure << /Subtype /RL /A [ << /C 1 /U (\ ) >>] /D [ << /C 1 /U (\ ) >>] /X [ << /C 0.68767 /U (\ ) >>] /R (\ ) /Type /Measure >> /Type /Viewport /BBox [69 31 524 811] >>] /Resources << /ProcSet [ /PDF /Text] /Font << /F1 5 0 R >> /Properties << /oc1 1 0 R >> >> >> endobj 7 0 obj << /Type /Pages /Kids [8 0 R ] /Count 1 >> endobj 9 0 obj << /Type /Catalog /Pages 7 0 R /OCProperties << /OCGs [ 1 0 R] /D << /Order [ 1 0 R] /OFF [] >> >> /PageMode /UseOC /PageLayout /SinglePage >> endobj 10 0 obj << /Creator (AutoCAD\ 2012\ -\ English\ 2012\ \(18.2s\ \(LMS\ Tech\)\)) /Title (Model) /Producer (pdfplot10.hdi\ 10.2.51.0) /CreationDate (D:20130827124142) /ModDate (D:20130827124142) >> endobj xref 0 11 0000000000 65535 f 0000001843 00000 n 0000000919 00000 n 0000000015 00000 n 0000000273 00000 n 0000000491 00000 n 0000000663 00000 n 0000002291 00000 n 0000001893 00000 n 0000002349 00000 n 0000002510 00000 n trailer << /Size 11 /Root 9 0 R /Info 10 0 R >> startxref 2715 %%EOF PyPDF2-1.25.1/PDF_Samples/README.txt000066400000000000000000000015051255324530700164060ustar00rootroot00000000000000PDF Sample Folder ----------------- PDF files are generated by a large variety of sources for many different purposes. One of the goals of PyPDF2 is to be able to read/write any PDF instance that Adobe can. This is a catalog of various PDF files. The files may not have worked with PyPDF2 but do now, they may be complicated or unconventional files, or they may just be good for testing. The purpose is to insure that when changes to PyPDF2 are made, we keep them in mind. If you have confidential PDFs that don't work with PyPDF2, feel free to still e-mail them for debugging - we won't add PDFs without expressed permission. (This folder is available through GitHub only) Feel free to add any type of PDF file or sample code, either by 1) sending it via email to PyPDF2@phaseit.net 2) including it in a pull request on GitHubPyPDF2-1.25.1/PDF_Samples/SF424_page2.pdf000066400000000000000000003635551255324530700172430ustar00rootroot00000000000000%PDF-1.3 1 0 obj << /Kids [ 4 0 R ] /Type /Pages /Count 1 >> endobj 2 0 obj << /Producer (Python PDF Library \055 http\072\057\057pybrary\056net\057pyPdf\057) >> endobj 3 0 obj << /Type /Catalog /Pages 1 0 R >> endobj 4 0 obj << /Contents 5 0 R /Parent 1 0 R /Resources << /ExtGState << /GS0 6 0 R >> /Font << /TT1 7 0 R /TT0 9 0 R /TT2 11 0 R >> /ProcSet [ /PDF /Text ] >> /Rotate 0 /CropBox [ 0 0 612 792 ] /MediaBox [ 0 0 612 792 ] /Annots 13 0 R /Type /Page >> endobj 5 0 obj << /Length 1924 /Filter /FlateDecode >> stream HW]oF}ׯ%%~S"vP`Ah, "i}Ϲh p~{bL77EZͲ4F+QBe2CSHAaGT>J"R8ŦTUX.֑V<7WXr}VaJc"NBncME <B lp KjNC\kb4Õ6 P fiڤJ(J< x;{thh΁ΕE@9ŷXh_ݝ8Y[*snnV-LXn;NYԜ2/2h*+Y=Reoui1eqKOI}@Rf wPYɗU}-Y1>wfR+c4 gڧJii>*nD"g M%zbIH]qn͟E6"=uCg2s^blZ;(OEY>gd^9DLP,BTłD8愊ln"yy)u#1vn#gMksdbl5IHEa%cn̕#J UOwm+K~] fvr|2L͸~nZO #@IQ˪;7:[yuWmHn#sb0k\- ?lZCiRFj-;q+Y|0f,o'aaX.WD B#&>jG_FEw G31,¨`}WWk[{9I,ߚ57Z8np%=Nְm4 q:tr٧S 9\j3IlYAʌe >Q~ [|F:Tsk`5=ob?9̥Rk+| ee7#mEުo?ug*dБUW5 *=]6^@<>q(ڀ }GB;4ADpn/Y1~ѶzM?f 7j2Vryԍ.Jnh> \ջ@Ӎ.X#}Y}v$;śO ov'4gLhnQ;߶Ȏo9e'ZL֥e/0)ڔ-! endstream endobj 6 0 obj << /OPM 1 /Type /ExtGState /SM 0.02000 /OP false /SA false /op false >> endobj 7 0 obj << /FirstChar 32 /Widths [ 278 0 355 556 556 889 667 191 333 333 389 584 278 333 278 278 556 556 556 556 556 556 556 556 556 556 278 278 584 584 584 556 0 667 667 722 722 667 611 778 722 278 500 667 556 833 722 778 667 778 722 667 611 722 667 944 667 667 611 278 0 278 0 556 0 556 556 500 556 556 278 556 556 222 222 500 222 833 556 556 556 556 333 500 278 556 500 722 500 500 500 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 556 ] /Encoding /WinAnsiEncoding /Type /Font /BaseFont /ArialMT /LastChar 167 /FontDescriptor 8 0 R /Subtype /TrueType >> endobj 8 0 obj << /FontBBox [ -665 -325 2028 1006 ] /StemV 88 /Descent -211 /XHeight 515 /Flags 32 /FontStretch /Normal /Ascent 905 /FontName /ArialMT /Type /FontDescriptor /FontWeight 400 /ItalicAngle 0 /FontFamily (Arial) /CapHeight 718 >> endobj 9 0 obj << /FirstChar 32 /Widths [ 278 333 474 556 556 889 722 238 333 333 389 584 278 333 278 278 556 556 556 556 556 556 556 556 556 556 333 0 584 584 584 611 975 722 722 722 722 667 611 778 722 278 556 722 611 833 722 778 667 778 722 667 611 722 667 944 667 667 611 333 0 333 0 0 0 556 611 556 611 556 333 611 611 278 278 556 278 889 611 611 611 611 389 556 333 611 556 778 556 556 500 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 278 ] /Encoding /WinAnsiEncoding /Type /Font /BaseFont /Arial-BoldMT /LastChar 183 /FontDescriptor 10 0 R /Subtype /TrueType >> endobj 10 0 obj << /FontBBox [ -628 -376 2034 1010 ] /StemV 138 /Descent -211 /XHeight 515 /Flags 32 /FontStretch /Normal /Ascent 905 /FontName /Arial-BoldMT /Type /FontDescriptor /FontWeight 700 /ItalicAngle 0 /FontFamily (Arial) /CapHeight 718 >> endobj 11 0 obj << /FirstChar 0 /Widths [ 750 750 750 750 750 750 750 750 750 750 750 750 750 750 750 750 750 750 750 750 750 750 750 750 750 750 750 750 750 750 750 750 278 278 355 556 556 889 667 191 333 333 389 584 278 333 278 278 556 556 556 556 556 556 556 556 556 556 278 278 584 584 584 556 1015 667 667 722 722 667 611 778 722 278 500 667 556 833 722 778 667 778 722 667 611 722 667 944 667 667 611 278 278 278 469 556 333 556 556 500 556 556 278 556 556 222 222 500 222 833 556 556 556 556 333 500 278 556 500 722 500 500 500 334 260 334 584 350 556 350 222 556 333 1000 556 556 333 1000 667 333 1000 350 611 350 350 222 222 333 333 350 556 1000 333 1000 500 333 944 350 500 667 278 333 556 556 556 556 260 556 333 737 370 556 584 333 737 552 400 549 333 333 333 576 537 278 333 333 365 556 834 834 834 611 667 667 667 667 667 667 1000 722 667 667 667 667 278 278 278 278 722 722 778 778 778 778 778 584 778 722 722 722 722 667 667 611 556 556 556 556 556 556 889 500 556 556 556 556 278 278 278 278 556 556 556 556 556 556 556 549 611 556 556 556 556 500 556 500 ] /Encoding /WinAnsiEncoding /Type /Font /BaseFont /Arial /LastChar 255 /FontDescriptor 12 0 R /Subtype /TrueType >> endobj 12 0 obj << /FontBBox [ -665 -325 2028 1006 ] /StemV 88 /Descent -325 /XHeight 519 /Flags 32 /FontStretch /Normal /Ascent 1006 /FontName /Arial /Type /FontDescriptor /FontWeight 400 /ItalicAngle 0 /FontFamily (Arial) /CapHeight 716 >> endobj 13 0 obj [ 14 0 R 32 0 R 292 0 R 296 0 R 298 0 R 300 0 R 301 0 R 304 0 R 306 0 R 309 0 R 312 0 R 315 0 R 320 0 R 322 0 R 323 0 R 324 0 R 325 0 R 326 0 R 327 0 R 52 0 R ] endobj 14 0 obj << /Parent 15 0 R /MK << /BG [ 1 1 1 ] /IF << >> >> /F 4 /Rect [ 473.13000 758.03700 574.70600 771.59100 ] /Type /Annot /AP << /N 17 0 R >> /P 4 0 R /Subtype /Widget >> endobj 15 0 obj << /DA (\057HeBo 12 Tf 0 g) /T (Hider2) /Ff 65536 /FT /Btn /Kids [ 14 0 R 16 0 R 40 0 R ] >> endobj 16 0 obj << /Parent 15 0 R /MK << /BG [ 1 1 1 ] /IF << >> >> /F 4 /Rect [ 471.91800 758.68000 573.49400 772.23400 ] /Type /Annot /AP << /N 17 0 R >> /P 18 0 R /Subtype /Widget >> endobj 17 0 obj << /BBox [ 0 0 101.57600 13.55380 ] /Resources << /ProcSet [ /PDF ] >> /Length 30 /Type /XObject /FormType 1 /Matrix [ 1 0 0 1 0 0 ] /Subtype /Form >> stream 1 g 0 0 101.5764 13.5538 re f endstream endobj 18 0 obj << /Contents 19 0 R /Parent 20 0 R /Resources << /ExtGState << /GS0 6 0 R >> /Font << /TT1 9 0 R /TT0 7 0 R /TT2 38 0 R >> /ProcSet [ /PDF /Text ] >> /Rotate 0 /CropBox [ 0 0 612 792 ] /MediaBox [ 0 0 612 792 ] /Annots 200 0 R /Type /Page >> endobj 19 0 obj << /Length 4297 /Filter /FlateDecode >> stream HWM۸ϯ@m@N/[zv)vh[(HVU}< Q1TC )pЯ*b r"唊S&)9.Fk6Ib43eP6wn Dq(avuO2 )E#veB$O,*ٖ |5߀jD}EQ@I M^J,5 e \e.Rx#S}B a{i*cf0O,#BxRON7;=云=Wֽ}ϐkk\Nv5z8nXd`!Fؐell <1)R:3geD1萺aiZO|)Kbu}dI0͚33#U@TɗxihGj44J.qoι@N!J0Khm-B{m9ǁ}Gc=psm}Z-ê?GC- ;p'CUEV VܒtCL[4 -޺?&M}J%1Wh#CsByqڗ :쨢/E ұ(.DTs$R@%SnΫSf[ "QpYg9S%1`vE0~(^ Y L%;侴)EٟRC Iy+9NnX\ g|&q3g#3}˄qP4'5ϵ8TsdՖ k;y ,08p؈ `"ÁxZMFT}1x5 _:Z1TYNE߉ h3cd1j:C} sr"}ץpڬa~k|mNB %7,#D*SQkj1T^뫫!>̨v^aS+hY9/VOs^NŞvk2/m秆QEYG([fh2\5/,;\^[>"b_ɰ̬ՊFkS[]'i."v_ :[P- 9ȨvY׼Ϊ-2Ht寥(>\J .tLH̼t!ԯ=Կg0h]aer\l*YR|QGQ4 ::QƍuO4{U;a߲Av4JշXnX)Ma,"eYgnvJDKSEkŷatf ۄKpk&< RaPm ! 5z^l7h;Kx^+}ʾ"^J[WV5b>rjQ4tު\̉ c1 ОBvj|& һ%w w&BoIi!<"D-{:G]jm"ڝeH|lc< ZGaXT--l`ujY<o(IW-w'L NΗbMwCKL1Bdd7%OJ~wbC0aM{E=N[\*vWd2 Jvm n0zĕ-Y>.CW-w榒$ . ֚]!R>=Y;M {am鈢 v|0-׿'/V~Z)-nSN-vU $}˒]+[7)dzn e֐X&@\g3܎&2miՎX]g˂XoU7vjז ?\  8DeiGtǦA\\J oKd*O|'/CKDLv]ↀV,N{j~)N}<48awbh"[kTW$@xCh×$wDezN$eœ\8xW-1*aa~#gO+ΡRI7x? 4D8܈[3w3s͡32rB $g ;>E>N+v]}ʅh_$.}K/s*4IœTI:{avz~!A&>^7|,ZJ ܗard}I0W0ϔ~lnH97Ϊq8Eʕ-Y*OY2pUeL~ФQP>Q*e;lrmYH?~x[{&E(ڞ&YKWurӓ-5fZ.GO`!ZX YbB%jc9T} %)^PCISܬ:\F1-dI;n33^T1`Ǫx>XtՋb@4XÐ SVt9޽12='%_ytt~օPIoppl^kNSS^s@ξ2Ӷ6ڹmts;[f'fML uuL[g)kU9kU׳j&nĭv39G\?W+㜱E͸*kkwl-e%4*G^c/ 6,7{T03 An8Ռ/5F讵(򚎠ҝMΊ;'@"pE+|B>vnXqØfD$~|+*lRϏПiD[܁o7D{ <]5<s.oǀ⌀ akgٛ;0o20oCk=,8j3Ls<^{ITŨ)6⛇.nD| * m|+oD%\@CLQ*s{(x8 +h^Q n+g!KskuO(W>7I8`J7n_<1FB$2pxSu-`j9hBe0҂? ;P@hraIi(.VDRwԚsa ͼ7hD-=@cé}xP@b xWIl.Jq V뒻cby埈O(sW2eȅ2^q9!]R^kKtб7G ku+8-s8v@u}B=^!k5d\SulJs򯋥]`iV򈡰+`7KS5Y x 0}O@}~#ފScQ{$~ޖ챣I@Ua$G&4plU:nb+3*X}u<'T3Iv iVF%m~-z\JTKWe= E#9~HL#Ӗ8-}4*s4UYm|Y`qmr1Y }ݢ[)*ݧ'F endstream endobj 20 0 obj << /Parent 21 0 R /Kids [ 23 0 R 4 0 R 18 0 R 36 0 R 67 0 R 85 0 R ] /Count 6 /Type /Pages >> endobj 21 0 obj << /Parent 22 0 R /Kids [ 20 0 R ] /Count 6 /Type /Pages >> endobj 22 0 obj << /Kids [ 21 0 R ] /Count 6 /Type /Pages >> endobj 23 0 obj << /Contents 24 0 R /Parent 20 0 R /Resources << /ExtGState << /GS0 6 0 R >> /Font << /TT1 11 0 R /TT0 7 0 R /TT2 9 0 R >> /ProcSet [ /PDF /Text ] >> /Rotate 0 /CropBox [ 0 0 612 792 ] /MediaBox [ 0 0 612 792 ] /Annots 25 0 R /Type /Page >> endobj 24 0 obj << /Length 3275 /Filter /FlateDecode >> stream HWr8}WLhͱ)o8X٭ddhKI] )r RÓ_nx\R(1|8T;1u=`[Ϧ ba<0Rr;J)GG:iZ*eӉJJS|Oe,{ V4 J% )HuUiv8` Ŝ[,ʁ/F+s^H>RBA|Wr-خZU 6|+ԩtEM^O "*z*qb)~Gx⣛c|F $n,wutu/ o7C骶kLuklMf Rf͚6oAovf'cfUͺ.x[wd5˦RwCaZ {޽Qw+xBYRvBUBa''jnsmbgmF g4< a\lT[1gcNu{m/k_[Юy3CԬpY1Glv"nٜXC]tyBLnl2:UۥUyO\vf_r7z$HqKP tqB0RdaSG-B fJ#+xH͕+Rٛ4|G$UX<3T;1Jǯ >D\TPA(G> ѧ`kHRLO 3`W" CHOU? ČBnO`]%>!efl`j${ڒD2;6! `WM"OγA (Ĺ!.J{ͯ7rZ}I }M /#.̚fѬ6T,=FHZ?K}q$զO鐭_gS\[ϼAXxs%hksxR愘]dDNBV9.B8.̌V:`S/d3gm.eUM]xFnpўf ifra_ٚKpK9&r NGkOb)r{1ˋH[J$-.AZQg6l)RsǦ1bq׬ҳYQh(!]|xd0[A:{OB̉B?TO.~ 7]ӠUa`RTH߳=Sy;F'4'k&5~^cPk:Dx#ʾ\>Oq}-~Jۼmb%9^z9-9XzIr٦LΥ4$9RTgS^ ڢmhDТ >/~ @(2F.GJ)TlM,QiE{JN|dKs$(ȸlٶȶq#VyK~lvfG4w~Hh6Y;#\#H‘VɫP&տu89#B6y}COBg֛g"<7 >*|e 6OI:Wov8h+8}Bk]:.+e)kB 6j38IC)U'Ƒ8r{9JV&?6n4J3h\+D=s}ԡqR6f 6[SܭZ_z@u:>ܬM-y?PxOHd!i*m*yz |Bn'[!h ,V-=z=*}Ձ `ĺՃ6 3,&&̈́苻|N_,f遵V4+b fˤ?d𓺫mi!kkS~e~L,F*lz4TTDz[k#>q1Ruy:}GT<\7{bQA g*mrX`ɒf P]Jk q{}$"XY"?OqJk,UiYR0[>ŎPNB\%id--RbeU?%~b }{\'`<zWJ)B,AqS^vTU+JîUE1֓u㴴v(Utָ*kh_Zۣ*>Xqv M5WLvU}r{q[칂s 2Y|A6hUQW^cFsVJ鵓|e%F9^ǖ%u#hw(\RCšy4ű9c4F^t;iÒBRrk@=Ψ/n q4I,\bۧI?K~lO_ endstream endobj 25 0 obj [ 26 0 R 30 0 R 92 0 R 96 0 R 100 0 R 104 0 R 108 0 R 112 0 R 116 0 R 117 0 R 118 0 R 121 0 R 122 0 R 123 0 R 124 0 R 125 0 R 126 0 R 128 0 R 129 0 R 130 0 R 131 0 R 132 0 R 133 0 R 134 0 R 135 0 R 136 0 R 137 0 R 138 0 R 139 0 R 143 0 R 144 0 R 145 0 R 146 0 R 150 0 R 151 0 R 152 0 R 155 0 R 158 0 R 159 0 R 44 0 R 164 0 R 168 0 R 169 0 R 172 0 R 174 0 R 177 0 R 180 0 R 183 0 R 186 0 R 189 0 R 192 0 R 195 0 R ] endobj 26 0 obj << /Ff 65537 /H /N /MK << /CA (03\05731\0572012) /BG [ 1 1 1 ] >> /F 4 /Rect [ 532.37500 760.24500 579.72800 771.14500 ] /Type /Annot /P 23 0 R /FT /Btn /AP << /N 27 0 R >> /DA (\057Helv 8 Tf 0 g) /T (03\05731\0572012) /Subtype /Widget >> endobj 27 0 obj << /BBox [ 0 0 47.35300 10.89950 ] /Resources << /Font << /Helv 28 0 R >> /ProcSet [ /PDF /Text ] >> /Length 114 /Type /XObject /FormType 1 /Matrix [ 1 0 0 1 0 0 ] /Subtype /Form >> stream 1 g 0 0 47.353 10.8995 re f q 1 1 45.353 8.8995 re W n 0 g BT /Helv 8 Tf 0 g 3.678 2.8292 Td (03/31/2012) Tj ET Q endstream endobj 28 0 obj << /Encoding 29 0 R /Type /Font /Subtype /Type1 /BaseFont /Helvetica /Name /Helv >> endobj 29 0 obj << /Type /Encoding /Differences [ 24 /breve /caron /circumflex /dotaccent /hungarumlaut /ogonek /ring /tilde 39 /quotesingle 96 /grave 128 /bullet /dagger /daggerdbl /ellipsis /emdash /endash /florin /fraction /guilsinglleft /guilsinglright /minus /perthousand /quotedblbase /quotedblleft /quotedblright /quoteleft /quoteright /quotesinglbase /trademark /fi /fl /Lslash /OE /Scaron /Ydieresis /Zcaron /dotlessi /lslash /oe /scaron /zcaron 160 /Euro 164 /currency 166 /brokenbar 168 /dieresis /copyright /ordfeminine 172 /logicalnot /.notdef /registered /macron /degree /plusminus /twosuperior /threesuperior /acute /mu 183 /periodcentered /cedilla /onesuperior /ordmasculine 188 /onequarter /onehalf /threequarters 192 /Agrave /Aacute /Acircumflex /Atilde /Adieresis /Aring /AE /Ccedilla /Egrave /Eacute /Ecircumflex /Edieresis /Igrave /Iacute /Icircumflex /Idieresis /Eth /Ntilde /Ograve /Oacute /Ocircumflex /Otilde /Odieresis /multiply /Oslash /Ugrave /Uacute /Ucircumflex /Udieresis /Yacute /Thorn /germandbls /agrave /aacute /acircumflex /atilde /adieresis /aring /ae /ccedilla /egrave /eacute /ecircumflex /edieresis /igrave /iacute /icircumflex /idieresis /eth /ntilde /ograve /oacute /ocircumflex /otilde /odieresis /divide /oslash /ugrave /uacute /ucircumflex /udieresis /yacute /thorn /ydieresis ] >> endobj 30 0 obj << /Parent 31 0 R /MK << /BG [ 1 1 1 ] >> /F 4 /Rect [ 517.58700 736.35700 573.66100 752.56500 ] /Type /Annot /AP << /N 33 0 R >> /P 23 0 R /Subtype /Widget >> endobj 31 0 obj << /DA (\057HeBo 12 Tf 0 g) /T (Hider) /Ff 65536 /FT /Btn /Kids [ 30 0 R 32 0 R 34 0 R 35 0 R ] >> endobj 32 0 obj << /Parent 31 0 R /MK << /BG [ 1 1 1 ] /IF << >> >> /F 4 /Rect [ 517.79900 736.11900 573.87300 752.32700 ] /Type /Annot /AP << /N 33 0 R >> /P 4 0 R /Subtype /Widget >> endobj 33 0 obj << /BBox [ 0 0 56.07420 16.20810 ] /Resources << /ProcSet [ /PDF ] >> /Length 29 /Type /XObject /FormType 1 /Matrix [ 1 0 0 1 0 0 ] /Subtype /Form >> stream 1 g 0 0 56.0742 16.2081 re f endstream endobj 34 0 obj << /Parent 31 0 R /MK << /BG [ 1 1 1 ] /IF << >> >> /F 4 /Rect [ 518.25300 735.47600 574.32700 751.68400 ] /Type /Annot /AP << /N 33 0 R >> /P 18 0 R /Subtype /Widget >> endobj 35 0 obj << /Parent 31 0 R /MK << /BG [ 1 1 1 ] /IF << >> >> /F 4 /Rect [ 517.94800 735.78100 574.02200 751.98900 ] /Type /Annot /AP << /N 33 0 R >> /P 36 0 R /Subtype /Widget >> endobj 36 0 obj << /Contents 37 0 R /Parent 20 0 R /Resources << /ExtGState << /GS0 6 0 R >> /Font << /TT1 38 0 R /TT0 7 0 R /TT2 9 0 R >> /ProcSet [ /PDF /Text ] >> /Rotate 0 /CropBox [ 0 0 612 792 ] /MediaBox [ 0 0 612 792 ] /Annots 39 0 R /Type /Page >> endobj 37 0 obj << /Length 927 /Filter /FlateDecode >> stream HtUKo8W̑\"EIXC^dYveW~gnkG]a?&7U@KҦ̠j ER9TP4[gTcY|jeÈGw£moe'+ FIW8[+"?XAf>^YvxG* CPmS޲ */"/$D:b,]2k1k.]6WYSZ-`NXq>y~؀ s$m.d MluFxmbF#lcVs_96&@j8DzY?=m&5Ljy}߬sb,/UVeTZL%JL66D^Jg+򢌦zu9A1Ki(MKk.:D-QvQFpPZHXMQƋSG" 5z:"y0H#zO&,."a:-vGZl>>|1c^c(Mw2S"MRx#qy'8J)Ȕ+ p@R{mn|h> endobj 39 0 obj [ 40 0 R 35 0 R 41 0 R 42 0 R ] endobj 40 0 obj << /Parent 15 0 R /MK << /BG [ 1 1 1 ] /IF << >> >> /F 4 /Rect [ 475.02600 758.98500 576.60200 772.53900 ] /Type /Annot /AP << /N 17 0 R >> /P 36 0 R /Subtype /Widget >> endobj 41 0 obj << /Ff 8392704 /MK << >> /F 4 /Rect [ 34.28570 51.64370 515.35700 684.85700 ] /Type /Annot /P 36 0 R /FT /Tx /DA (\057Helv 10 Tf 0 g) /T (DebtDelinquencyExplain) /TU (If applicable\054 explain your agency\047s Federal Debt Delinquency here\056) /Subtype /Widget >> endobj 42 0 obj << /Parent 43 0 R /H /P /MK << /TP 1 /IF << >> /I 45 0 R >> /A 88 0 R /Rect [ 6.32196 7.50092 41.32170 44.16740 ] /Type /Annot /AP << /N 90 0 R /D 91 0 R >> /P 36 0 R /Subtype /Widget >> endobj 43 0 obj << /Ff 65536 /Kids [ 44 0 R 52 0 R 57 0 R 42 0 R 62 0 R 80 0 R ] /FT /Btn /DA (\057HeBo 12 Tf 0 g) /T (home) /TU (Click here to go to Toolkit homepage \050main menu\051\056) >> endobj 44 0 obj << /Parent 43 0 R /H /P /MK << /TP 1 /IF << >> /I 45 0 R >> /A 48 0 R /Rect [ 29.32200 24.50090 64.32170 61.16740 ] /Type /Annot /AP << /N 50 0 R /D 51 0 R >> /P 23 0 R /Subtype /Widget >> endobj 45 0 obj << /Filter [ /FlateDecode ] /Matrix [ 1 0 0 1 -306 -396 ] /Resources << /XObject << /im1 46 0 R >> /ProcSet 47 0 R >> /Name /FRM /Length 51 /Type /XObject /FormType 1 /BBox [ 162 246 450 546 ] /Subtype /Form >> stream H+T5P0B#KK=S#C3##3=#\^\C|^@^P  endstream endobj 46 0 obj << /Filter /CCITTFaxDecode /Name /im1 /ColorSpace /DeviceGray /DecodeParms << /K -1 /Columns 800 >> /Length 5364 /Type /XObject /BitsPerComponent 1 /Height 832 /Width 800 /Subtype /Image >> stream  ؠa1&a1&B;Q-Ťw -C hYnP O @/r P\r|$pn :p â/K|&‡K:>IxPVKl+΁ZR0D{u@J0C:{ mQ Bl=>5#3k~6¶h NuaR&뾭 oo8 Ҳ~npjC=xa^C{UKK VTX'wۥo)%o֤wTnT2ULoݵbJ'y mlû[oV&2?4X: >AwX°AwMIB_]Z .rU^ Dk l=.v`֒ i (o6 b- i'A 5t2҇ ]Hlzu^U^ *dI$Ia+BBiI7 ]-+j·i KJmj gqIi]26-$­SU^0W^ $앆l %a:o!ۋ D ڋj=IVҰNiE[I%l VI"LB$0H$UP*,$%ސKIp *II]J;uTmۅZIݣ"iN+avװ'tA$ge]$;ZOjD*Zn]m$6=-Iv~"V@[jaPmm$5l4]H%IU^XL% 60H/~hZׂNý VvKPJtǺU wn %𪗥a*PAo* %}փzAS n_T%N  頵]U鮟Wk 5 5=A}N 7_OMzMCV'H7uZL7_m Շ~Zն0Siia:|6ktm0&N0>3i aKA ᶤ3#QNiCR8'xp +M$ݠ0 l|BavAvXI{od &A]NOkcJp2A n.:nq I KkM\+ qISI׿a{JJ߰]CL>{iXKRS hƵ &nh[ZE S~r`j@RmtdNj NNP o `tǮ'i]=' Ki~}8W6; l!m-Am PM1L0A ae7) PAv ؄j#uXht]@1;0M'm^{Zes&v82jV ^!`xj3%P<@̋A\Dd O`_ FA!a􈃐0p@A`9R0@*| uRQVCaP"j' +C (%bhSX9(2A3A*pBh 5#z,i ;mCAQ ' 4I( _l- AV3A(#.$΀C+HXIkNh옉$*Ȩdg" I$qaI%\n@@$ xcd鴽RXOL?'mHڨ$ l5MM' Sm鄈f=`4CFB!GA6Au[h O Ohh$ඖv Vflа_ `h'!b]=ⷃWAn !Fw# $+zRH+ma Wu@@(MЧjJκAm-5Aշ[st!ۄB:};m5ݶ i6%Mz]{M I:ZKmݥU6 0 w R.l0 `Rm~a (A-|?l 5Mk!`}Cb -.z<Ѯ%(WIW:$ &O}%_҅+!ҷZk{5JuA%U_A%Av@K!"Y xM귭T z }R[Y* ۥ ͼEOj,mT {_MID6^?n^ kIE;uIRnn@ AFnZ i+{a$ RbخiV m$ bI%ABv$z{I:yP Av۩!Gj  O 7HiA$ d ҽToc< p4AB <^dRZ ABI76wJA/ a<7ՇP 6@!9mZ Aw D |&Ȼᄐ@]ߑ3PrAgV;6<(Ds#;+~ew l>MA[8u+@x0X0U#',LcM+w /P+ EMl4$>@cF_ xQ I]0XJCMzgc4" c"? -nRw \7k h oa޻Uui*/ -(݇wӭf۵I~]{pkҤ@%J_M0ۏuH*ׂozI}$ۆ zAB$*{ 284 __ZCUTOn*%QA~t /I/o :K*❻ @ KAV^v{tۻU zNn[_Uv U1KJ~C!`7_m߄H%ʀU Ud(}.wAIU[u%}%AA-$*tRJloIj_zU]{߯U]A+T}{jTTUAUEKJj5u!.t_ק}(뭽 m knI${R(Aj!A4tw\ umkZ^J i:M%BcT+]ir 61=*Z3 L5 eJmyOKZw^2IUw(ӾyI*TT/0Nu`ā/ &z^ M.۬*o_U!KzTۮBOukoI:U0y ju*S_׿{?5I~S@Qmi-_{X=:]h?T2@4/iz_Uuk^꾾T.VZ_itkUU ]~ݯc~֕+uKUnץ괿p^f_KU]-l?jKx/k8ke-$U Z.(/jnz\VivZW;P !i RA$ZtzJPKd6n)i$QqZ {_],kRI%TC(*x6t%/ P+I%Z2 b]R 2`DZJᓆ VWKCK22R2\/_2Kt%aPPxa\҅AT}$B0_i+T  8]zr/2ke wiԘ/!p`*jl l0in  }1 .=gdv]k{$>ۢ k~iH&;ݶS4{l4 @{a"߶حT6OvnA5m ߶mNnk mt &m=\.m:okmݷat{nwo~OÂ! mCtd;npA66tt[eC-I}nM4 00VKvAa7L "!IqA]{ +ᇈVۆ]iY *M[ jZ mI@`˅3avY0; 62nhܛ^Y7 3 p#ҽ'D3tM|zjD l <%iR`Ac`$FM ɵCkfl%Օ&D3%RMxtnE砛nn!l0꛷H(aH6}I6M &A~`h$AIa&mh0 A6 ;l ~ii: ; 'REA#5M$~Sa!Aa$PMAbVD!6OZl:m-640i?i۫ AڴID 0 6 ntڽL=Mެ ߦ FZW۴0a/ -mխAH0in. M7A n`vnm2B[ 0Mv*ݥI -T{ZJ6-7ۨW݆Z +vam mavW AE [l2i+ pwjڨhe +}8Im$+Ԏڶ jI%5s%a+aji ]Th #`C^mi&v+픁m(pfXk mPiwJڶR:iRmctR7 T߸i%(]'{U+o[I& vzV iu$o꿽-¯"RRUvUwނ݄ޡ۶K?W[o ~7vrᕷo.ߡ m}dqtݜwoV.Ok[q][]An@!Z_A_VO@ul W[uppe+h/J+im6 [jd6M~ XPz a 0@ꡅAFEe !6慹 @5mᯰ+-C I endstream endobj 47 0 obj [ /PDF /ImageB ] endobj 48 0 obj << /F 49 0 R /S /Launch >> endobj 49 0 obj << /F (toolkit\056pdf) /Type /Filespec >> endobj 50 0 obj << /Filter /FlateDecode /BBox [ 0 0 34.99970 36.66650 ] /Resources << /XObject << /FRM 45 0 R >> /ProcSet [ /PDF ] >> /Length 90 /Type /XObject /FormType 1 /Matrix [ 1 0 0 1 0 0 ] /Subtype /Form >> stream HT=@P=wS8(Bcd*) Bs¹L;U2|~SXdZ8'hFM? o/7 endstream endobj 51 0 obj << /Filter /FlateDecode /BBox [ 0 0 34.99970 36.66650 ] /Resources << /XObject << /FRM 45 0 R >> /ProcSet [ /PDF ] >> /Length 142 /Type /XObject /FormType 1 /Matrix [ 1 0 0 1 0 0 ] /Subtype /Form >> stream H\1AE{NDf鍝66F_Ȭ٬y#frjdf?7f QPEI]ɳV}:{ƽ > /I 45 0 R >> /A 53 0 R /Rect [ 29.32200 24.50090 64.32170 61.16740 ] /Type /Annot /AP << /N 55 0 R /D 56 0 R >> /P 4 0 R /Subtype /Widget >> endobj 53 0 obj << /F 54 0 R /S /Launch >> endobj 54 0 obj << /F (toolkit\056pdf) /Type /Filespec >> endobj 55 0 obj << /Filter /FlateDecode /BBox [ 0 0 34.99970 36.66650 ] /Resources << /XObject << /FRM 45 0 R >> /ProcSet [ /PDF ] >> /Length 90 /Type /XObject /FormType 1 /Matrix [ 1 0 0 1 0 0 ] /Subtype /Form >> stream HT=@P=wS8(Bcd*) Bs¹L;U2|~SXdZ8'hFM? o/7 endstream endobj 56 0 obj << /Filter /FlateDecode /BBox [ 0 0 34.99970 36.66650 ] /Resources << /XObject << /FRM 45 0 R >> /ProcSet [ /PDF ] >> /Length 142 /Type /XObject /FormType 1 /Matrix [ 1 0 0 1 0 0 ] /Subtype /Form >> stream H\1AE{NDf鍝66F_Ȭ٬y#frjdf?7f QPEI]ɳV}:{ƽ > /I 45 0 R >> /A 58 0 R /Rect [ 29.32200 24.50090 64.32170 61.16740 ] /Type /Annot /AP << /N 60 0 R /D 61 0 R >> /P 18 0 R /Subtype /Widget >> endobj 58 0 obj << /F 59 0 R /S /Launch >> endobj 59 0 obj << /F (toolkit\056pdf) /Type /Filespec >> endobj 60 0 obj << /Filter /FlateDecode /BBox [ 0 0 34.99970 36.66650 ] /Resources << /XObject << /FRM 45 0 R >> /ProcSet [ /PDF ] >> /Length 90 /Type /XObject /FormType 1 /Matrix [ 1 0 0 1 0 0 ] /Subtype /Form >> stream HT=@P=wS8(Bcd*) Bs¹L;U2|~SXdZ8'hFM? o/7 endstream endobj 61 0 obj << /Filter /FlateDecode /BBox [ 0 0 34.99970 36.66650 ] /Resources << /XObject << /FRM 45 0 R >> /ProcSet [ /PDF ] >> /Length 142 /Type /XObject /FormType 1 /Matrix [ 1 0 0 1 0 0 ] /Subtype /Form >> stream H\1AE{NDf鍝66F_Ȭ٬y#frjdf?7f QPEI]ɳV}:{ƽ > /I 45 0 R >> /A 63 0 R /Rect [ 29.32200 24.50090 64.32170 61.16740 ] /Type /Annot /AP << /N 65 0 R /D 66 0 R >> /P 67 0 R /Subtype /Widget >> endobj 63 0 obj << /F 64 0 R /S /Launch >> endobj 64 0 obj << /F (toolkit\056pdf) /Type /Filespec >> endobj 65 0 obj << /Filter /FlateDecode /BBox [ 0 0 34.99970 36.66650 ] /Resources << /XObject << /FRM 45 0 R >> /ProcSet [ /PDF ] >> /Length 90 /Type /XObject /FormType 1 /Matrix [ 1 0 0 1 0 0 ] /Subtype /Form >> stream HT=@P=wS8(Bcd*) Bs¹L;U2|~SXdZ8'hFM? o/7 endstream endobj 66 0 obj << /Filter /FlateDecode /BBox [ 0 0 34.99970 36.66650 ] /Resources << /XObject << /FRM 45 0 R >> /ProcSet [ /PDF ] >> /Length 142 /Type /XObject /FormType 1 /Matrix [ 1 0 0 1 0 0 ] /Subtype /Form >> stream H\1AE{NDf鍝66F_Ȭ٬y#frjdf?7f QPEI]ɳV}:{ƽ > /Font << /T1_2 70 0 R /T1_0 73 0 R /T1_1 76 0 R >> /ProcSet [ /PDF /Text ] >> /Rotate 0 /CropBox [ 0 0 612 792 ] /MediaBox [ 0 0 612 792 ] /Annots 79 0 R /Type /Page >> endobj 68 0 obj << /Length 9250 /Filter /FlateDecode >> stream HWs }WwZ_zst:%?XRvRbzP&w?, ow3{$yX'A'yy4,Nj.6 tE'Y0mɪK6z*GD)c,Ҋ%meQk[pCTYKUH L]JX^u4mMN4ijgwƷ >l˨DE'dL`u}vB5;[a9&XSNܩq |vpW5EB-杆:XXULoveǜD,SrsJ'dW q].NO#9wv:AZ7ZqVKN?LE4B)$HIч9jʏv>Z\< zc"3.~p_CG(ԕ5\Oؙ ` fckv~2LJ$q(Jz 857ܥN5Z#[;9xrb⻕-͐!()F@sIO'gOi*[)! :> 0-y3OZVYרUt$,y=Tܮo8_v$+ qϘ,J> 4އT #$#Wonp (Näӗ~$~bDXB%"JAqb G.PAj#B\OZCvVxJou?TSf<9uuPs}ec,x D=" >-Yev3փ˽=1`AջMWű-ǐg4&s52+I _]6r W叝[Qf*(DŽ"b,i0@YIP H'~Oޑƾ~6:β=vLi5M&묩=`?Yey<}&):ֳk 0N@ZDi<lim=mj3_jvvfM 5y?[+/fiu3YMdv0IŐ2~bw:%ʗ6q lUPf4$¶,+bk25B)Qxd_`ᑽAԄ/"P Sqd-A㛨 -q0P`&0a2k3-FhCEBJ؍-l\Λ` "Z/y9 NjU\6~RCV ;fm/{ƾ9*dxA C2΅nIšT2Y,/rN<_h8q<`Y≈T<ڠG6L-Yov x]N.ɒM]Ip9nS"pO qf%ct08^f9˅V^ц:xp5j"lZp-.#J`Nϝe1?_'"nFpr >8:H%Kk DCmԀU)FBtmQ/";Оqx3z -c@{p ywP X1kLI"5FZ2t;&%`4uӎԟ"5 cB$p4v, "S&d"NDY|@LV~w!t|+:$C d=[M`{[3/dH7 D9{ {;-O=oعm+Ѧ#!%2ZzfKt,}}S^{p`trI'RB{H=Rsw^_|Ĺv](HZ4д. !ѻ}}G]+1]G~-ӈ^r `ѳETgKj zg3^XWHM28#ti $q-hF]T"ˁlGw^P$ mv2sPᗞ^OV=v׌v[0'ةstbϱ4=oBcm3irz1C7dL~,.wCzޡmkOE-`SGGq%4{=G)tsW"6;M,w7Q;pWԵyj pjM\V&"fJꦋɛo (,.ʠ0EaqD,X|Y# (h5M,8&($\)m,va.=;.m͐ WKs7WrlM-Wykz%9n EbjbAE=Lal͵5Ulaۢa}`fmצj6EЫZFjB9\d Iʳ |#ԕ(ͩ 5 “X-̲VL~&I[ɶ1BcT߈I4@w{Tl[ǃ}+VM΍ lL3smr.swwL[/ 1lbξz20{]}~wy]j8~􊙫c$3S33ty+̹cDLkKud?:Ͳ.!օf%~)4m{?-s] ߬Qw&. S6螙?!MFG熏vH!zGW"!wS*Yv7|s@?^΢Q9$tPKV]QF &rAթAV{IaR7ڑ+*ːIC.wEGBm'ÿnMҒn|!D9ś!:3(Di{1y&̀YD(n'aѻ-gTCN@He:d>¦,.4ulG6r2SWSOT9Ѩ~d\#ߚo#gD u)?ރD FE<|0V[E,xR w?zn>DH)@%S_? N(!9{E/:3Xܛн΅2&E~bp5I33!׆5>,;V <\ŭ `.L<|X(K@"zd;< n@9-D6gQ>0`uBrN@Jϵ79`Wݦwxa̝UIMMGu7T1u zp 0}KؙR%L)(қBa/|;1gN~C'wL_\~1ߩkŜ'5AFk[/yB?%܂s/sM^btZ-4 ~d@`ǿT#]אTPPk.Cⵎ$r璒}) رr )#t'BaX.?1uvU5YU>^ܜYږnmlauV7VnLp]]~wy]j81jS ê g٘iA<>q @Qbfs8S)t/.oE_~A֦ޔetF7*0c,\/JDҐ$ _DCto`Ծ;-?{ft-RPպl5<ԋ7RL5]$7&]IE^P]@^⹻; }w~l/A`=gA6w嗞$cF:w_?1y0P~?8D/.Yϔ$5v+s(VW}ћA:T? ͐f Slg%2{iHXH.?ʇݟ.{kma,@%6? P^xPI` .|௝˜65 "|e] țTbqg6m&+f]gmCq %~-eWhӢ)]f. N &C?-|;5udwY{ZvoЏ)7I]jj)znZ mp JF/o J;bPLt>JÊ$|͊rҰzTbBN(^JtE,|{gP>7Gn[>/݃1wQrzm%CAhk[zx~=#o?1UkS~eyF$ם/ï}bT?hۈu8 '5Bݑ]/h>.|*XA9ߞISoLڧ^d(2됝[Cuޝgf^yfVHWW~]j8~Vۖ@"l<_%<DCQLq\'Z4 ޯҢYre=V :>H9}-JmPa.u49*]#̳ WNN o[&?;qhqnƔC.n{[{,Vwn{EWϽӴ\qkʼ./+#P gRAYe* 0`/^`eibxfY~h70M{_&*){ߋŐ%@f*?D&'$s%LfI>CKWa-g[C#2> RևvJc })?2 q|=Kbcp$p2:JF^͍U ߔ&`\/qNvmwH.I=!z9͊GjqF?IJ1${ul]$>O֖fS{GdjH ,RQ9rUTLÙ{ά>_DeW~]j8~N֢s"Nl1g)Ca蔊q0z[P*&6Lk*_գ:Ĕ*o%a:Ȼb ƇH EXxE!7FOB؊a|䑷 gy82NTZLj  !d'2jKEie(tnҔC.JGj\~]j8~Np;%Qn%X!ǝŖ_\~/{}6|ƿd qSV2r{|Cr(gSA9Lݬ[fŖ 38OmJlWKsFW(L/߲rծP&8EdvtYd~~I^MXʻVƀ(Wn:ϫvңH?UEza*OqjzWu.0"3Γ瘀>??y ;L|Eam,sipkD1xςl-tb+oxhtknuCkx3 늢GD­߲Uck!U Wcgw,h$ ~AW!eVTYm$GJ݄uf^¸#Xp lKvKC[1=&.܋~ɰxOf>\aQiFC&))DNlm('L>Q&Kl;MeYfEini(ӚHd6hVKKC;C8؄2"|b\2s5+r!gFY#pQBIXkJإEnJRK'@4JvmUJX$\NŠCÃڎlԠi%*5";V1Md2/uv)ɲѲ&l”Ħ'!:o*ӽxd7ѱn}- E96,a(@@ZhXX/1:Ks8[Ι>Tmfo3*eb <~EWIhr]d0&OAi20&Oʜ/$qp+&qɡ)N9t>x{0|8z9zŲZV@-zE(BZ%a?!CO[#ua 6z%^##TI0IC¢i7дp%~p.6 En-M'v@M;!Ѧh@%vߎ) 锡(xuK}z[/6]Utmo' \͌[StA@YueXv{ٕ9_]˨7v8E:iWKW\d& 2Rj2CuVFN <)푢P{&> endobj 70 0 obj << /FirstChar 32 /Widths [ 250 0 0 0 0 0 0 0 333 333 0 0 250 0 250 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 556 0 0 333 0 0 0 0 0 0 0 0 667 556 611 0 0 0 0 0 0 0 0 0 0 0 0 444 500 444 500 444 333 500 500 278 0 500 278 778 500 500 500 500 333 389 278 500 500 722 0 500 ] /Encoding /WinAnsiEncoding /Type /Font /BaseFont /LJIGPN+Times-Roman /LastChar 121 /FontDescriptor 71 0 R /Subtype /Type1 >> endobj 71 0 obj << /FontBBox [ 0 -218 775 683 ] /StemV 116 /MissingWidth 250 /FontFile3 72 0 R /Flags 4 /Descent -218 /Ascent 683 /FontName /LJIGPN+Times-Roman /Type /FontDescriptor /ItalicAngle 0 /CharSet (\057y\057n\057c\057o\057d\057p\057e\057q\057f\057r\057g\057F\057s\057h\057R\057t\057i\057S\057u\057T\057I\057v\057k\057w\057l\057a\057m\057b\057parenright\057space\057comma\057period\057parenleft) /CapHeight 683 >> endobj 72 0 obj << /Length 3666 /Filter /FlateDecode /Subtype /Type1C >> stream xeVyT[?i Rj%&Zm+ܪmb[(SKdb IHH´I e cKG; UV[UiwЪ[~{_uY'|{o~",+$N"nUU,ESl`Zl ~nc/6{r0248f>6JTHsD&>n{922R/BI\,~(KJX^UWKlZS(JgҥwъEEf? z! VqTL@]\⽋Xr㱰C2B t:d }E+Jl(T/0} OuR^&CGTajm&PK6h-tť:@Pk*R s &9/D.^zysBmMu@6j :b *JrdR#:N;jK ,]0E!5c)R=IZb+;0~Noh/yWva,PFo36d5 NE{:|w}p*;Cx(U^?|OO ]> #1[zY}CN1ش0~x Њ1O uSL{gfuM3euٹ@ze/g# n!յ5P T&kr{52Yg'P !*Ő`f5͗Ѣcg fsѠV@EFPԍ/ߟ: UӆbnΣ+F)^c:0.)H4X( բ6:}3\fr88 Z֠w[_ yGܘP ##}䃈aQ/y[|/BZzAxU`\[[| ,._ZlRwsU )$RwGS*pMnTouazj:-8_նև?.?"d-n'z\lP2{?H/ܟ"@Jt4u6hӔ&\#a"Ƅ^2nt/m}GxbI~@k~א7 g~4:!ٰ{+45`˷[pq@ Fp蝘bz6,slǥ%U3TBu]z9y?X̐@\R1?K*D5zu サX]Vw]#2TKBѰ;@l|߈LB% ђވIʏ/I ]D4u{R쵵`tg ^UZӵJ=_zp5X.\h!wrohz-}1هU#3_M΄2佑vvJcvn=s?Y?t?\~G`yYhNZxZܧeG`G޵ӳ53nNa$t V:ŔȊW _*.wesXw$RvpG~͉> endobj 74 0 obj << /FontBBox [ 0 -219 824 744 ] /StemV 123 /MissingWidth 278 /FontFile3 75 0 R /Flags 4 /Descent -219 /Ascent 744 /FontName /SMMIZF+Helvetica-Bold /Type /FontDescriptor /ItalicAngle 0 /CharSet (\057four\057L\057A\057y\057n\057c\057M\057B\057z\057o\057d\057Y\057N\057C\057p\057e\057seven\057O\057D\057q\057f\057P\057E\057r\057g\057F\057s\057h\057colon\057R\057G\057t\057i\057S\057H\057u\057j\057T\057I\057v\057U\057w\057l\057a\057V\057x\057m\057b\057question\057parenright\057space\057hyphen\057period\057slash\057one\057two\057quoteright\057three\057parenleft) /CapHeight 744 >> endobj 75 0 obj << /Length 3855 /Filter /FlateDecode /Subtype /Type1C >> stream x]Ww\T׶>#9G (XPЧ"Uņ 04XbP(*Fkh$]ՠF[{̨yy .k}[ZG`d2_lrvlVbt&9F)ā=AF5ڛڕA̬=]fԈhGt7c$Oפf$'d/aĈ͌qssSG~zLOUAvl&-%65C=NNNV'%d#cbbcm"cP$&'iç;ǎ=Ɖ;;1%jY:025S=K-aˌa@Əg0 3Y`1"f&3qd3%Lɸ2Alf:csƂa ez2ӏa$Ƙ^g\ezXQㅑ`ia<޸|P*ױn\2w7= cafdɯ^5]gLi6,lc[̯Z0.Aਹ,e{h+):"K|͚kH9 dF^,nզѝ?S6^ g_)؄7tRX7{BY^m)ښ•o(.CNmv~WgU+WjY렆pP[+uStިmo94S8ߎgpڜhgZr6Kᙐ\~Ax8 }8~v*zk+ƻ ;TJ-!W/\{kd(:K%7ݔ# xS 氯r3KGn`8>0Zg%gVFc5X\#3NFT/)LGUթ ťЕEKcenJ B_\@(m1\n"ae&Gr<^hQOX`nx%^@7;7t#0 `'P.tl{%޼pJPOrqqe}ح@MQc1piiuFpo*EV6rD&9a!!juKeeHt|)q* '9zNG#籴^/nkků)1ER ҅uW$34ʨQ1W)'xP[`rLn!U9;bx L&7I}*u,%B:s=>ANxaewϫϰ%!sx0` in蠰P!]`A&CPTLmҚOſ׬~H4F|08ˎGUdWDd,!=ˏ.[w`~ShZV(^M8,+nP$0hs[7;ΖkPV=uIo[m߽'oqgܚ^5EWq,:ۡ)ytSuʐ*b&X:iԮЋ: FVecPZ0Nc^GpOS{G]@p < I(W CS=4'AhnSM9:-i'kfҵ  +?Xtx+{*eNX)LlbweqIb;.}SBQGfLqPUPwRwwJ €/`8M#)B" tW0uZ\>'R/\h൤&UZ_EE?5? j5YT C5Ez2FxTSSp>IVCk}q$=e"C6wZNz*OnFp}hEL9в!۠Psg7[=y|]CJ_h#%#G:JA> `&X4w%fJs\\)N-|F|\]kw=L[H~"WJjj'MVBW9z_ST5*mXfQ0Q9QkQjK- ٵ׏[V,ݲ$P_H[nCʰoÈ ̠gPN1OP#/8X+DXLeoJV\G|,+MaA6kwj=|~s̓_򦄓ICK1pl1=ߟ;C߻WۻrGFYUEr."jL:S ֊m8P:;>*?cY: _>ƽ|gWSZ;l.j/Ћ%(\0 C.9{Gȟ4D.CC}&--(>OvB]oG+6oPVm\SO] *8G8JeN;ZYm1=QY`JTVC 5ߊ[Ҷl|M%TpA0\zUN?;0n3?SjG)ܼT!O]\NxESJCHS1ZIY#KP)ug#N_c{W}o#ϨV RuS jv"gG- 8似Ehpbc=yJ{3Dz:ߣ[+NA f}:]-eTsK)4>2xcj9gQSaOQ%aZ/}2(G 8H''Jҙܻא T_Xx؏b^^K߼XAks\*@Is(>{:N'h`)F\V T9 v2H;f3|Uv:!F&`ԟ6O@HD*W U r方zF9m6T TH!}I5{O+{{,D~at@q-YS_o\;59#GMf}ּ-&*)(=50o*>PVup1rҞRkxj/FZ^unfǟ^"5h(_Nn=}0q jG+5 C,+Nm.ݶwѪӄ\8+*~+S%s9JNP D0&`Op@#% ia>*iSMPVa?X tvg#B' ᜃ#nSOp^r$%]+ O>,0݀uлrH]-]ϒG< }N27B:ЍNmboJa_ QM <Ϥ/V䲐,^`45c) endstream endobj 76 0 obj << /FirstChar 32 /Widths [ 278 0 355 0 0 0 0 0 333 333 0 584 278 333 278 278 556 556 556 556 556 556 556 556 556 556 278 0 0 0 0 0 0 667 667 722 722 667 611 778 722 278 500 667 556 833 722 778 667 778 722 667 611 722 667 944 667 0 611 0 0 0 0 0 0 556 556 500 556 556 278 556 556 222 222 500 222 833 556 556 556 556 333 500 278 556 500 722 500 500 500 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 221 333 333 350 556 ] /Encoding /WinAnsiEncoding /Type /Font /BaseFont /KQGFIY+Helvetica /LastChar 150 /FontDescriptor 77 0 R /Subtype /Type1 >> endobj 77 0 obj << /FontBBox [ -18 -218 929 741 ] /StemV 139 /MissingWidth 278 /FontFile3 78 0 R /Flags 4 /Descent -218 /Ascent 741 /FontName /KQGFIY+Helvetica /Type /FontDescriptor /ItalicAngle 0 /CharSet (\057four\057L\057A\057y\057n\057c\057X\057five\057M\057B\057quotedblright\057z\057o\057d\057six\057N\057C\057p\057e\057Z\057seven\057O\057D\057q\057f\057eight\057P\057E\057endash\057r\057g\057nine\057Q\057F\057s\057h\057colon\057R\057G\057t\057i\057S\057H\057u\057j\057T\057I\057v\057k\057U\057J\057bullet\057w\057quotedblleft\057l\057a\057V\057K\057x\057m\057b\057W\057parenright\057plus\057space\057comma\057hyphen\057quotedbl\057period\057slash\057zero\057one\057two\057quoteright\057three\057parenleft) /CapHeight 741 >> endobj 78 0 obj << /Length 4835 /Filter /FlateDecode /Subtype /Type1C >> stream x}W XS׶>!#2M" *3APp@I@ul H"ePA08j{{o'޾}Krr=_k (}=J $&iy+?V',.d1BBdd,wߌ5[&? xgdd$%XE/f|Dl2I(QF27]hZo2K2+0SīʘoD 5S.V a:sG+6V; N>28C4D46qه4N7r`"c PDƌ+8["g|5G޸&8*gn9atU=Cwƣ۪u$wz>/{,Ʉ5"#Gs{Ë2 ޚjB"d6r:yNAU_oϯn12^VX<c/1h 6`>*΢gA0 ,iګTBC, 8(a!p Ѱާ19_7`!@dxS%G)!418 NU0!M iSn)̺TХ QY.sPmꡚsnX"e|YV?:s%j̫MJ |tS;=͞,pt1ݐI+x<͎5"~+l|Nn85m3`wcp 8n;6>6Z γ_$5YKB%E5J4Q%iskrkN%TOr&I lX=ͧy̗ЛW!JoޜRA#J``SYRE:{)rZ_xs8}9>`5 v Ru ]ʸ_oxd'E`&7:(;!\;|)lPguE5)}&mMFb`>x=@W[ʣNm;Ury}s*؁v Rw^N@vhMȍ1|00T.p"85ʮ ]- B0O7}pb!іK ?֕TXpN H r>HpU8.g`Sp͛'HJ`_Q.eĝM ad:IG5R\jwnP _FwJ+Xu=BGUA)ܞ/Q!I{Bz/uo,3Z{A{_T0ZHA}]9XsCqs: !MEVeQ˜A +4㡘wRhva/Whhc#R,mZa 1==T?t;^x׶P$Zn+~Iĵ6$pw"cį- cc{8{)ZZۼ =D?}f2g˪ DR}nbg{:Q˱x%q~078[`y.Nu,Kim?~C`x zow佫AnEēUykƢ1qŸ\s!B@iY^!:W` o-Z):߹s%ob#useS.&4;uwcE0c/.0Swl]?cW.h!YRNCZɐxĖr,ΓJY V,)F6ݘT缶 cS?]*Kobƀ|tK0$_(xa[ Z $z$XnZΈM$P]VD<nG6: Ypvdٵ~4Ȃ` V.yI;ߋݑ3 _>w!l o]]H>82Et**%0tL'?XQgꤤƒOZ 1,m^9 Z)dlMENӟe\[ν)U_+=x.񶫝\*K D_/ D Vl CsQ䋙?|zfe ϓ@ѣڳ5U=4^X?Zrtf'A̦e]o@Ķ0iU3ZI]zA&җq#bwgfkw֟h󽴀':D մkfIa/Y(aJw|URIF ϶uA?VlUh`+SMmV~BQNAC_a_!Fc;=)4M2AUnբw4^ H Y8 gty]-)t(k^fO([v,Yt5^r<{%^]])W۔ Ę>R-lmaVAFJ&Jk2@>LAfpim⯚&[RLO[Gi/跼5" >=Ylև4B=vީb?C=I_;|[r0*͓mHHdgnN۱}NRا3[|ncHVrϊa$_GϾ]'90+'%u'1 Jjl>9P&U~2Ry9|M;|kI4 -ÿ_"͇o8I>Yƍ4@HċoU̟lG9|0 E4xRE/i+.h"Ck!і:#~sӝֻg$ل@%?yymo\nX$9?E+֯'_+=pnEuׇoL Is{,^ J& N5\j08"s&R3?<#4(a j^ <τ*̽{`:gM v1ĶDH]b !.v!_x_}ځ\j#|s!v6-&2gICl{,jx-ް oE%氐9-E5 i1;Z1 !b;];BV@ś?l5ѰYYqtr T $Y Yc[a 5 a'v*ϊ&;, K.I B4EL*᱅L{_nB~N3{oDoe7ŝ;4KJÛU_}]ȑK?oDlykɒKݬU[>X^*}bmsQqfv~ uoGBQYIAw_7t^8uyݻϤ/]spYפ,fV ,xN¶foNN&ھ)` ߘZzbDP- EU+/mˈ{]\bx㎼O.<&)v^MswS*,]$Q4zK D%fpaΡAs܂[Q޾?LT7A-鮼3?lt p6~xrA(! ;ފ_w\>zr.Xx4Jݜ0Klt늿V#,#.Xs)nSގ=+4b==uVD4{pSpnP V#bg?H܅{Wp),9^*m/m5eуQKѦ%xAԉ()ne#~-> /I 45 0 R >> /A 81 0 R /Rect [ 29.32200 24.50090 64.32170 61.16740 ] /Type /Annot /AP << /N 83 0 R /D 84 0 R >> /P 85 0 R /Subtype /Widget >> endobj 81 0 obj << /F 82 0 R /S /Launch >> endobj 82 0 obj << /F (toolkit\056pdf) /Type /Filespec >> endobj 83 0 obj << /Filter /FlateDecode /BBox [ 0 0 34.99970 36.66650 ] /Resources << /XObject << /FRM 45 0 R >> /ProcSet [ /PDF ] >> /Length 90 /Type /XObject /FormType 1 /Matrix [ 1 0 0 1 0 0 ] /Subtype /Form >> stream HT=@P=wS8(Bcd*) Bs¹L;U2|~SXdZ8'hFM? o/7 endstream endobj 84 0 obj << /Filter /FlateDecode /BBox [ 0 0 34.99970 36.66650 ] /Resources << /XObject << /FRM 45 0 R >> /ProcSet [ /PDF ] >> /Length 142 /Type /XObject /FormType 1 /Matrix [ 1 0 0 1 0 0 ] /Subtype /Form >> stream H\1AE{NDf鍝66F_Ȭ٬y#frjdf?7f QPEI]ɳV}:{ƽ > /Font << /T1_2 76 0 R /T1_0 70 0 R /T1_1 73 0 R >> /ProcSet [ /PDF /Text ] >> /Rotate 0 /CropBox [ 0 0 612 792 ] /MediaBox [ 0 0 612 792 ] /Annots 87 0 R /Type /Page >> endobj 86 0 obj << /Length 4907 /Filter /FlateDecode >> stream HWYs~GCwfыKR);HHx֯OwOw") vv~:)3'|+6<8G%cީ? cVUP͡1}#P#\%o9|(\AVPB޺t&bu(ѵ%5u- G_Ec+7"ĈDg1 ݢ|_:JO9 ^+PGkn rF!Kquu*:.tPf5/C [3{7}]3Zz_+AR ~#_=Hᒦz$KBj5 ggs#c_>aL}G7Ns5 Pd+tO xϜ3;eyW[-[KrDʷg,78h㓔 `Oˣ|uqy'5ovqI#~sjġFNL1PH&L{ &j)kQһiMHkC~H4(Ii#$ڏ)y?$ ItnC gS)J't5fr_Ng͎ M7GQ9z7쨭 'Mj4ï7nG+Ls4Ȇm2~aL&I)2Jr6S*tkީ8 ~%(M-q*\q h ':2r{pU:'sR@U'`ڗS4eQl~:| z`>}:tb}U @~? lggm}#{&moK]1*jt<{\9Hn?Z2BzҦjg%,(GS1}jlUTe]} C+*˶+ҷ X/ȱ!s]U`.LjO,Ѫ.ʮ0B'H): /u Sg4nI˸=^hW|G,dHlK/r%8@X2Mo`T6c->3&'j9DqWOUDa,J%F Y{S#F. (CJ5Ae7҇@WFFApuHN濰jf.s')Ŝlwls #B-N6Eeе oJiaJGW@O, '#[*jG<+N]ξf]yܠ_qJwt>b9nl6|&ܿ<퓲yqG+썂۷QВ_ Q[Z@xS%VrF ?ƽ$NY!"[ Q\'"Խ7%3|/5]EmoJ1 胨-5hTHIuf&[h呹cK~JVumJrnП) ':*ĠU }QHc2l"Hۚ|hbC ͟Jy 8 ]8:VC g+rD:H>&p-0R55}LWѰYG9s묏esim篭Js٢5U) caULf3hL``9e1 -2cn 7ޗ~D ޗ R.#2g!W|hڢvE_m"E.?p%W0@ ;|u7w=L(UN&C;x+eO'+- W@A-b?@BPOe0]y枅M!0 ݷdH+Q "y6$4X3q䗪|Ĥy$`2v={YeEW7fPz;Gj(Dc+D'Ɓw~? )iubu/4iEf<ҧ`z>ֳ;g2¼g8ꪌt̗ nY㪫KS7f(jɼu=6n^B=ЇyCp-[s08&.RAe te,q\Pfquop?}zV@ ttGML;g͓])=JNt O~R(հ6`ҞmV,د0"UI+lw0[,㲏GqGREe[3|ܪNc]I$lQwLYbҌ+6.GtV؅V1i"cA̫4ѸYٹ(d>jCQ3ގ)MQ[Z='$+c˨Vu:&Q%RJ6v3mV%AH* CtElEKӕEgϺtQB_nj^ ,0ؗp)tE':DJ%iH};ǷS0PSZI)[~.c(M^ÿ:dhx7r=cJ3bMnMس /Dӏ0g\0?YF+Oە2`hy("q}%N^8\sڃ'7Uh;"' ^_9Wd:IES6>V5BJ]/ﲾlY$@I_> <_t0]hؠ&bʣIl aE|`OE3QSc FR5ջnV$3rwe-5Kکe][S87sy]R|.A+MxJӔcN[6UVfJe&V)vGi|d# luvt]R+ tnӏF L B[}%1m3/pV v%6+JOS.jpG/(6ǎu}P+FsI+ C` z"S@8G]P1[oxҽJ51P7 DXi@o-5vf 0@)4ܦOG?A(Cxc+k5'WZ8vs_[HWXu6T>2P[Dr`k'w"(U!FUTX@0=3> endobj 89 0 obj << /F (toolkit\056pdf) /Type /Filespec >> endobj 90 0 obj << /Filter /FlateDecode /BBox [ 0 0 34.99970 36.66650 ] /Resources << /XObject << /FRM 45 0 R >> /ProcSet [ /PDF ] >> /Length 90 /Type /XObject /FormType 1 /Matrix [ 1 0 0 1 0 0 ] /Subtype /Form >> stream HT=@P=wS8(Bcd*) Bs¹L;U2|~SXdZ8'hFM? o/7 endstream endobj 91 0 obj << /Filter /FlateDecode /BBox [ 0 0 34.99970 36.66650 ] /Resources << /XObject << /FRM 45 0 R >> /ProcSet [ /PDF ] >> /Length 142 /Type /XObject /FormType 1 /Matrix [ 1 0 0 1 0 0 ] /Subtype /Form >> stream H\1AE{NDf鍝66F_Ȭ٬y#frjdf?7f QPEI]ɳV}:{ƽ > /F 4 /P 23 0 R /Rect [ 33.73610 701.72900 42.26390 710.27100 ] /Type /Annot /AS /Off /FT /Btn /AP << /N << /Yes 93 0 R >> /D << /Off 94 0 R /Yes 95 0 R >> >> /T (SubmissionTypePreapplication) /TU (Submission Type \055 Preapplication) /Subtype /Widget >> endobj 93 0 obj << /Filter /FlateDecode /BBox [ 0 0 8.52780 8.54199 ] /Resources << /ProcSet [ /PDF ] >> /Length 64 /Type /XObject /FormType 1 /Matrix [ 1 0 0 1 0 0 ] /Subtype /Form >> stream H*2T0T0352Q&F E\\y\F B.THP! "o* 0 endstream endobj 94 0 obj << /BBox [ 0 0 8.52780 8.54199 ] /Resources << /ProcSet [ /PDF ] >> /Length 33 /Type /XObject /FormType 1 /Matrix [ 1 0 0 1 0 0 ] /Subtype /Form >> stream 0.749023 g 0 0 8.5278 8.542 re f endstream endobj 95 0 obj << /Filter /FlateDecode /BBox [ 0 0 8.52780 8.54199 ] /Resources << /ProcSet [ /PDF ] >> /Length 87 /Type /XObject /FormType 1 /Matrix [ 1 0 0 1 0 0 ] /Subtype /Form >> stream H237402VH2P0P352Q&F E\i\\ fq3x8Wklb63007TB(! ]3 endstream endobj 96 0 obj << /MK << /CA (8) >> /F 4 /P 23 0 R /Rect [ 33.44920 685.36200 41.97690 694.90500 ] /Type /Annot /AS /Off /FT /Btn /AP << /N << /Yes 97 0 R >> /D << /Off 98 0 R /Yes 99 0 R >> >> /T (SubmissionTypeApplication) /TU (Submission Type \055 Application) /Subtype /Widget >> endobj 97 0 obj << /Filter /FlateDecode /BBox [ 0 0 8.52769 9.54303 ] /Resources << /ProcSet [ /PDF ] >> /Length 66 /Type /XObject /FormType 1 /Matrix [ 1 0 0 1 0 0 ] /Subtype /Form >> stream H*2T0T03527W0351V(J 2r MMrFz@* *o* 0Ư endstream endobj 98 0 obj << /BBox [ 0 0 8.52769 9.54303 ] /Resources << /ProcSet [ /PDF ] >> /Length 33 /Type /XObject /FormType 1 /Matrix [ 1 0 0 1 0 0 ] /Subtype /Form >> stream 0.749023 g 0 0 8.5277 9.543 re f endstream endobj 99 0 obj << /Filter /FlateDecode /BBox [ 0 0 8.52769 9.54303 ] /Resources << /ProcSet [ /PDF ] >> /Length 87 /Type /XObject /FormType 1 /Matrix [ 1 0 0 1 0 0 ] /Subtype /Form >> stream HD 0 ''d *&@Duw⩨E.P*{"9Ef *j̉Z6Zgwota-]9 endstream endobj 100 0 obj << /MK << /CA (8) >> /F 4 /P 23 0 R /Rect [ 33.23610 669.22900 41.76390 677.77100 ] /Type /Annot /AS /Off /FT /Btn /AP << /N << /Yes 101 0 R >> /D << /Off 102 0 R /Yes 103 0 R >> >> /T (SubmissionTypeChanged) /TU (Check this box if requested by agency to change or correct previously submitted application\056) /Subtype /Widget >> endobj 101 0 obj << /Filter /FlateDecode /BBox [ 0 0 8.52780 8.54199 ] /Resources << /ProcSet [ /PDF ] >> /Length 64 /Type /XObject /FormType 1 /Matrix [ 1 0 0 1 0 0 ] /Subtype /Form >> stream H*2T0T0352Q&F E\\y\F B.THP! "o* 0 endstream endobj 102 0 obj << /BBox [ 0 0 8.52780 8.54199 ] /Resources << /ProcSet [ /PDF ] >> /Length 33 /Type /XObject /FormType 1 /Matrix [ 1 0 0 1 0 0 ] /Subtype /Form >> stream 0.749023 g 0 0 8.5278 8.542 re f endstream endobj 103 0 obj << /Filter /FlateDecode /BBox [ 0 0 8.52780 8.54199 ] /Resources << /ProcSet [ /PDF ] >> /Length 87 /Type /XObject /FormType 1 /Matrix [ 1 0 0 1 0 0 ] /Subtype /Form >> stream H237402VH2P0P352Q&F E\i\\ fq3x8Wklb63007TB(! ]3 endstream endobj 104 0 obj << /MK << /CA (8) >> /F 4 /P 23 0 R /Rect [ 172.73600 702.22900 181.26400 710.77100 ] /Type /Annot /AS /Off /FT /Btn /AP << /N << /Yes 105 0 R >> /D << /Off 106 0 R /Yes 107 0 R >> >> /T (AppTypeNew) /TU (Check for app being submitted for first time\056) /Subtype /Widget >> endobj 105 0 obj << /Filter /FlateDecode /BBox [ 0 0 8.52802 8.54199 ] /Resources << /ProcSet [ /PDF ] >> /Length 61 /Type /XObject /FormType 1 /Matrix [ 1 0 0 1 0 0 ] /Subtype /Form >> stream H*2T0T035&F E\\y\F B.DH\! ,g/ 0S2& endstream endobj 106 0 obj << /BBox [ 0 0 8.52802 8.54199 ] /Resources << /ProcSet [ /PDF ] >> /Length 32 /Type /XObject /FormType 1 /Matrix [ 1 0 0 1 0 0 ] /Subtype /Form >> stream 0.749023 g 0 0 8.528 8.542 re f endstream endobj 107 0 obj << /Filter /FlateDecode /BBox [ 0 0 8.52802 8.54199 ] /Resources << /ProcSet [ /PDF ] >> /Length 84 /Type /XObject /FormType 1 /Matrix [ 1 0 0 1 0 0 ] /Subtype /Form >> stream H237402VH2P0P35&F E\i\\ f`a3p8Wkl4300W+ŋ  endstream endobj 108 0 obj << /MK << /CA (8) >> /F 4 /P 23 0 R /Rect [ 173.23600 685.72900 181.76400 694.27100 ] /Type /Annot /AS /Off /FT /Btn /AP << /N << /Yes 109 0 R >> /D << /Off 110 0 R /Yes 111 0 R >> >> /T (AppTypeContinuation) /TU (Check Continuation to request an extension for an additional funding\057budget period for a project with a projected completion date\056) /Subtype /Widget >> endobj 109 0 obj << /Filter /FlateDecode /BBox [ 0 0 8.52802 8.54199 ] /Resources << /ProcSet [ /PDF ] >> /Length 61 /Type /XObject /FormType 1 /Matrix [ 1 0 0 1 0 0 ] /Subtype /Form >> stream H*2T0T035&F E\\y\F B.DH\! ,g/ 0S2& endstream endobj 110 0 obj << /BBox [ 0 0 8.52802 8.54199 ] /Resources << /ProcSet [ /PDF ] >> /Length 32 /Type /XObject /FormType 1 /Matrix [ 1 0 0 1 0 0 ] /Subtype /Form >> stream 0.749023 g 0 0 8.528 8.542 re f endstream endobj 111 0 obj << /Filter /FlateDecode /BBox [ 0 0 8.52802 8.54199 ] /Resources << /ProcSet [ /PDF ] >> /Length 84 /Type /XObject /FormType 1 /Matrix [ 1 0 0 1 0 0 ] /Subtype /Form >> stream H237402VH2P0P35&F E\i\\ f`a3p8Wkl4300W+ŋ  endstream endobj 112 0 obj << /MK << /CA (8) >> /F 4 /P 23 0 R /Rect [ 172.69500 669.58300 181.22300 678.12600 ] /Type /Annot /AS /Off /FT /Btn /AP << /N << /Yes 113 0 R >> /D << /Off 114 0 R /Yes 115 0 R >> >> /T (AppTypeRevision) /TU (Check for any change in Federal Government\047s financial obligation or contingent liability from existing obligation\056) /Subtype /Widget >> endobj 113 0 obj << /Filter /FlateDecode /BBox [ 0 0 8.52800 8.54297 ] /Resources << /ProcSet [ /PDF ] >> /Length 63 /Type /XObject /FormType 1 /Matrix [ 1 0 0 1 0 0 ] /Subtype /Form >> stream H*2T0T035& E\\y\F B.DHT! "k) 0T endstream endobj 114 0 obj << /BBox [ 0 0 8.52800 8.54297 ] /Resources << /ProcSet [ /PDF ] >> /Length 32 /Type /XObject /FormType 1 /Matrix [ 1 0 0 1 0 0 ] /Subtype /Form >> stream 0.749023 g 0 0 8.528 8.543 re f endstream endobj 115 0 obj << /Filter /FlateDecode /BBox [ 0 0 8.52800 8.54297 ] /Resources << /ProcSet [ /PDF ] >> /Length 86 /Type /XObject /FormType 1 /Matrix [ 1 0 0 1 0 0 ] /Subtype /Form >> stream H237402VH2P0P35& E\i\\ f`a3p8Wklj53007U+!d [ endstream endobj 116 0 obj << /Ff 8388608 /MK << >> /F 4 /Rect [ 269 701 423.50000 713 ] /Type /Annot /P 23 0 R /FT /Tx /T (RevisionABCDE) /TU (A\075\053Funds B\075\055Funds C\075\053Time D\075\055Time E\075Other) /Subtype /Widget >> endobj 117 0 obj << /Ff 8388608 /MK << >> /F 4 /Rect [ 269.25000 669 439.25000 681 ] /Type /Annot /P 23 0 R /FT /Tx /T (RevisionOther) /TU (Describe any other reason for revision\056) /Subtype /Widget >> endobj 118 0 obj << /Ff 12582912 /AA << /F 119 0 R /K 120 0 R >> /MK << >> /F 4 /Rect [ 34.45400 632.45700 158.04600 643.54300 ] /Type /Annot /P 23 0 R /FT /Tx /T (DateRecvdByFed) /TU (Leave blank\056 Federal agency will assign date\056) /Subtype /Widget >> endobj 119 0 obj << /S /JavaScript /JS (AFDate\137FormatEx\050\042mm\057dd\057yyyy\042\051\073) >> endobj 120 0 obj << /S /JavaScript /JS (AFDate\137KeystrokeEx\050\042mm\057dd\057yyyy\042\051\073) >> endobj 121 0 obj << /Ff 8388608 /MK << >> /F 4 /Rect [ 174 631.50000 410 642.50000 ] /Type /Annot /P 23 0 R /FT /Tx /T (ApplicantId) /TU (Applicant Identifier) /Subtype /Widget >> endobj 122 0 obj << /Ff 8388608 /MK << >> /F 4 /Rect [ 34.50000 595 272 606 ] /Type /Annot /P 23 0 R /FT /Tx /T (FedEntityID) /TU (Federal Entity Identifier) /Subtype /Widget >> endobj 123 0 obj << /Ff 8388608 /MK << >> /F 4 /Rect [ 279.60700 595.07100 477.60700 606.07100 ] /Type /Annot /P 23 0 R /FT /Tx /T (FedAwardId) /TU (Federal Award Identifier) /Subtype /Widget >> endobj 124 0 obj << /Ff 12582912 /AA << /F 119 0 R /K 120 0 R >> /MK << >> /F 4 /Rect [ 146.45400 553.95700 197.54600 565.04300 ] /Type /Annot /P 23 0 R /FT /Tx /T (DateRecvdByState) /TU (Date received by State \050State use only\056\051) /Subtype /Widget >> endobj 125 0 obj << /Ff 8392704 /MK << >> /F 4 /Rect [ 312.91000 554.39900 549.94700 565.45700 ] /Type /Annot /P 23 0 R /FT /Tx /DA (\057Helv 10 Tf 0 g) /T (StateApplicationIdentifier) /TU (State Application Identifier assigned by state \050if applicable\051) /Subtype /Widget >> endobj 126 0 obj << /Ff 12582912 /AA << /F 127 0 R >> /MK << >> /F 4 /Rect [ 98.37760 512.72300 571.11100 524.86400 ] /Type /Annot /P 23 0 R /FT /Tx /T (ApplicantLegalName) /TU (Name registered with Central Contractor Registry ) /Subtype /Widget >> endobj 127 0 obj << /S /JavaScript /JS (AutoTab\050this\054 event\054 \042EIN\0560\042\051\073) >> endobj 128 0 obj << /Ff 12582912 /MK << >> /F 4 /Rect [ 278.78100 475.79300 386.90500 488.01600 ] /Type /Annot /P 23 0 R /FT /Tx /MaxLen 11 /T (DUNS) /TU (Organizational DUNS number) /Subtype /Widget >> endobj 129 0 obj << /Ff 12582912 /MK << >> /F 4 /Rect [ 109.62100 435.97600 542.45800 448.10700 ] /Type /Annot /P 23 0 R /FT /Tx /T (ApplicantStreet1) /TU (Applicant street address 1) /Subtype /Widget >> endobj 130 0 obj << /Ff 12582912 /MK << >> /F 4 /Rect [ 109.58200 419.43500 542.41800 431.56500 ] /Type /Annot /P 23 0 R /FT /Tx /T (ApplicantStreet2) /TU (Applicant street address 2) /Subtype /Widget >> endobj 131 0 obj << /Ff 12582912 /MK << >> /F 4 /Rect [ 109.67200 403.37100 385.50400 415.45700 ] /Type /Annot /P 23 0 R /FT /Tx /T (ApplicantCity) /TU (Applicant city) /Subtype /Widget >> endobj 132 0 obj << /Ff 12582912 /MK << >> /F 4 /Rect [ 109.08400 386.45700 345.91600 398.54300 ] /Type /Annot /P 23 0 R /FT /Tx /T (ApplicantCounty) /TU (Applicant county) /Subtype /Widget >> endobj 133 0 obj << /Ff 12582912 /MK << >> /F 4 /Rect [ 108.45500 370.44500 553.88500 382.02700 ] /Type /Annot /P 23 0 R /FT /Tx /T (ApplicantState) /TU (Applicant state) /Subtype /Widget >> endobj 134 0 obj << /Ff 12582912 /MK << >> /F 4 /Rect [ 109.08400 354.95700 345.91600 367.04300 ] /Type /Annot /P 23 0 R /FT /Tx /T (ApplicantProvince) /TU (Applicant province) /Subtype /Widget >> endobj 135 0 obj << /Ff 12582912 /MK << >> /F 4 /Rect [ 109.46100 338.92300 505.75300 349.50600 ] /Type /Annot /P 23 0 R /FT /Tx /T (ApplicantCountry) /TU (Applicant country) /Subtype /Widget >> endobj 136 0 obj << /Ff 12582912 /MK << >> /F 4 /Rect [ 109.04200 322.68600 346.23200 333.26400 ] /Type /Annot /P 23 0 R /FT /Tx /T (Zip Code) /TU (Applicant zip code) /Subtype /Widget >> endobj 137 0 obj << /Ff 12582912 /MK << >> /F 4 /Rect [ 34.78030 265.32900 270.84400 276.41400 ] /Type /Annot /P 23 0 R /FT /Tx /T (Dept) /TU (Enter department name) /Subtype /Widget >> endobj 138 0 obj << /Ff 12582912 /MK << >> /F 4 /Rect [ 279.65100 265.96600 515.27100 277.53400 ] /Type /Annot /P 23 0 R /FT /Tx /T (Division) /TU (enter division name) /Subtype /Widget >> endobj 139 0 obj << /Ff 5111808 /I [ 0 ] /MK << /BG [ 1 1 1 ] >> /F 4 /Opt 140 0 R /DV 141 0 R /Rect [ 89.36660 224.46700 142.63300 235.53300 ] /Type /Annot /P 23 0 R /FT /Ch /AP << /N 142 0 R >> /V ( ) /T (ContactPrefix) /TU (Choose prefix for Contact Person \050Dr\056\054 Mr\056\054 Mrs\056\054 Ms\056\051) /Subtype /Widget >> endobj 140 0 obj [ ( ) (Dr\056) (Mr\056) (Mrs\056) (Ms\056) ] endobj 141 0 obj ( ) endobj 142 0 obj << /Filter /FlateDecode /BBox [ 0 0 53.26640 11.06600 ] /Resources << /Font << /Helv 28 0 R >> /ProcSet [ /PDF /Text ] >> /Length 109 /Type /XObject /FormType 1 /Matrix [ 1 0 0 1 0 0 ] /Subtype /Form >> stream H4; @wj2N̶*&B_Yٰ*OWtA5QyUfvbG0UOR. {ZO+% ΧGdim+ml endstream endobj 143 0 obj << /Ff 12582912 /MK << >> /F 4 /Rect [ 286.75000 224.40700 560.91300 235.98500 ] /Type /Annot /P 23 0 R /FT /Tx /T (ContactFirstname) /TU (Enter contact person\047s first name\056) /Subtype /Widget >> endobj 144 0 obj << /MK << >> /F 4 /Rect [ 88.27180 208.85800 287.80700 219.43000 ] /Type /Annot /P 23 0 R /FT /Tx /T (ContactMiddlename) /TU (Enter contact person\047s middle name\056) /Subtype /Widget >> endobj 145 0 obj << /Ff 12582912 /MK << >> /F 4 /Rect [ 89.62100 192.42200 560.64800 203.99500 ] /Type /Annot /P 23 0 R /FT /Tx /T (ContactLastname) /TU (Enter contact person\047s last name\056) /Subtype /Widget >> endobj 146 0 obj << /V ( ) /Ff 5111808 /I [ 0 ] /MK << /BG [ 1 1 1 ] >> /F 4 /Opt 147 0 R /DV 148 0 R /Rect [ 89.54700 176.46500 182.95300 187.53500 ] /Type /Annot /P 23 0 R /FT /Ch /AP << /N 149 0 R >> /DA (\057Helv 0 Tf 0 g) /T (ContactSuffix) /TU (Choose suffix for Contact Person \050Ph\056D\056\054 Jr\056\054 Sr\056\051) /Subtype /Widget >> endobj 147 0 obj [ ( ) (Jr\056) (Ph\056D\056) (Sr\056) ] endobj 148 0 obj ( ) endobj 149 0 obj << /Filter /FlateDecode /BBox [ 0 0 93.40600 11.07000 ] /Resources << /Font << /Helv 28 0 R >> /ProcSet [ /PDF /Text ] >> /Length 108 /Type /XObject /FormType 1 /Matrix [ 1 0 0 1 0 0 ] /Subtype /Form >> stream H,= @wWfqWmW4\ *Hh!?"ߏrP PI6bBi+**tooF6qQktъIAmAox:R# endstream endobj 150 0 obj << /MK << >> /F 4 /Rect [ 60 155.50000 412.50000 167 ] /Type /Annot /P 23 0 R /FT /Tx /T (ContactTitle) /TU (Enter title of person to be contacted about this application\056) /Subtype /Widget >> endobj 151 0 obj << /MK << >> /F 4 /Rect [ 34.25000 118.75000 507.25000 130.25000 ] /Type /Annot /P 23 0 R /FT /Tx /T (ContactOrgAffiliation) /TU (Organizational affiliation of person to be contacted about this application\056) /Subtype /Widget >> endobj 152 0 obj << /Ff 12582912 /AA << /F 153 0 R /K 154 0 R >> /MK << >> /F 4 /Rect [ 113.75200 97.82630 312.37200 110.00800 ] /Type /Annot /P 23 0 R /FT /Tx /T (ContactTelephone) /TU (Phone number for contact person\056) /Subtype /Widget >> endobj 153 0 obj << /S /JavaScript /JS (AFSpecial\137Format\0502\051\073) >> endobj 154 0 obj << /S /JavaScript /JS (AFSpecial\137Keystroke\0502\051\073) >> endobj 155 0 obj << /Ff 12582912 /AA << /F 156 0 R /K 157 0 R >> /MK << >> /F 4 /Rect [ 371.95200 98.21620 570.55100 109.79900 ] /Type /Annot /P 23 0 R /FT /Tx /T (ContactFax) /TU (FAX number for contact person\056) /Subtype /Widget >> endobj 156 0 obj << /S /JavaScript /JS (AFSpecial\137Format\0502\051\073) >> endobj 157 0 obj << /S /JavaScript /JS (AFSpecial\137Keystroke\0502\051\073) >> endobj 158 0 obj << /Ff 12582912 /MK << >> /F 4 /Rect [ 73.73480 78.70670 544.37500 89.78260 ] /Type /Annot /P 23 0 R /FT /Tx /T (ContactEmail) /TU (E\055mail address for contact person\056) /Subtype /Widget >> endobj 159 0 obj << /Ff 65536 /H /P /MK << /CA (Print) /BG [ 0 0.50195 0.25098 ] /BC [ 0.25098 0 0.25098 ] /IF << >> >> /Subtype /Widget /A 160 0 R /BS << /W 1 /S /I >> /Rect [ 520.42100 32.67090 573.31300 47.54700 ] /Type /Annot /FT /Btn /AP << /N 162 0 R /D 163 0 R >> /DA (\057Helv 8 Tf 1 1 1 rg) /T (Printopts) /TU (Popup menu showing printing options\056) /P 23 0 R >> endobj 160 0 obj << /S /JavaScript /JS 161 0 R >> endobj 161 0 obj << /Length 230 /Filter [ /FlateDecode ] >> stream Hj1'w գeTPZ5D|fPQ!af2?ʣy,5%sgڽk fqN8!_Ř|M 4ZAVöPئiZgAY^eQC^-*\S xb]RD>Fa> ;3xf<D N J۽I+2iҍ \ endstream endobj 162 0 obj << /Filter [ /FlateDecode ] /BBox [ 0 0 52.89200 14.87610 ] /Resources << /Font << /Helv 28 0 R >> /ProcSet [ /PDF /Text ] >> /Length 185 /Type /XObject /FormType 1 /Matrix [ 1 0 0 1 0 0 ] /Subtype /Form >> stream HlP 0 +rKMնWAQ elojK䅐!M& P!a<Ε[C L5hƚ%`(~{-avdNm߆7Ơ9ѹǨX"s tv6yP98-+í{1ao$E endstream endobj 163 0 obj << /Filter [ /FlateDecode ] /BBox [ 0 0 52.89200 14.87610 ] /Resources << /Font << /Helv 28 0 R >> /ProcSet [ /PDF /Text ] >> /Length 183 /Type /XObject /FormType 1 /Matrix [ 1 0 0 1 0 0 ] /Subtype /Form >> stream HlO10 04iC P$mj+iCپ;gR(-Kc0-HTHfMkho54DH/׆f?#<+8X]OVeDa]`DwNFQ endstream endobj 164 0 obj << /Ff 65536 /H /P /MK << /CA (Reset Fields) /BG [ 0.79214 0.22353 0.20784 ] /BC [ 0.25098 0 0.25098 ] /IF << >> >> /Subtype /Widget /A 165 0 R /BS << /W 1 /S /I >> /Rect [ 284.57400 31.01800 349.03700 47.54700 ] /Type /Annot /FT /Btn /AP << /N 166 0 R /D 167 0 R >> /DA (\057Helv 10 Tf 1 1 1 rg) /T (reset) /TU (resets all fields) /P 23 0 R >> endobj 165 0 obj << /S /ResetForm >> endobj 166 0 obj << /Filter [ /FlateDecode ] /BBox [ 0 0 64.46300 16.52900 ] /Resources << /Font << /Helv 28 0 R >> /ProcSet [ /PDF /Text ] >> /Length 207 /Type /XObject /FormType 1 /Matrix [ 1 0 0 1 0 0 ] /Subtype /Form >> stream HlP0 a 'cEE"' $X>}vLh:A2̕ BBZo'8!H-X(Wcy;eY.h!6[8?Y)o͘ "i$Cd6ئ0 {E0aOCz6H>8*^ .KI endstream endobj 167 0 obj << /Filter [ /FlateDecode ] /BBox [ 0 0 64.46300 16.52900 ] /Resources << /Font << /Helv 28 0 R >> /ProcSet [ /PDF /Text ] >> /Length 213 /Type /XObject /FormType 1 /Matrix [ 1 0 0 1 0 0 ] /Subtype /Form >> stream HlPAN1 >¡ZWH<+.]$eU> /Subtype /Text /Name /Comment /RC (\074\077xml version\075\0421\0560\042\077\076\074body xmlns\075\042http\072\057\057www\056w3\056org\0571999\057xhtml\042 xmlns\072xfa\075\042http\072\057\057www\056xfa\056org\057schema\057xfa\055data\0571\0560\057\042 xfa\072APIVersion\075\042Acrobat\0727\0560\0568\042 xfa\072spec\075\0422\0560\0562\042 \076\074p dir\075\042ltr\042\076\074span dir\075\042ltr\042 style\075\042font\055size\07210\0560pt\042\076SF\055424 standard \050Core\051 data set and cover sheet\054 established in July 31\054 2003\054 was deployed in October 2003 for use by the agencies with competitive grant programs\056\074\057span\076\074\057p\076\074\057body\076) /P 23 0 R >> endobj 169 0 obj << /Parent 168 0 R /F 28 /Rect [ 382.57400 605.97000 607.57400 713.97000 ] /Type /Annot /Open false /Subtype /Popup >> endobj 170 0 obj << /Filter /FlateDecode /BBox [ 0 0 20 18 ] /Resources << /ProcSet [ /PDF ] >> /Length 326 /Type /XObject /FormType 1 /Matrix [ 1 0 0 1 0 0 ] /Subtype /Form >> stream HL1n0 DdRfr $p4{8c|Lr?$K'%nAveG5 nk5tLF8wIW:o.ٸq*9½GN\Ԋ!O[pF3RB!|tvw<郞lv]psQL f d8=~glK1yî @8+ LKhꄛxOq*2zţy1ywNuwC6iuT*N!s? uI qm1$}6\-`っ endstream endobj 171 0 obj << /Filter /FlateDecode /BBox [ 0 0 20 18 ] /Resources << /ProcSet [ /PDF ] >> /Length 328 /Type /XObject /FormType 1 /Matrix [ 1 0 0 1 0 0 ] /Subtype /Form >> stream HL=N1 Xqki^CxBCq<β~IVH(|RΗ.=k7"\"UΑ]dD:8±uuq:E!fR6 o#9rpZ QX*rI5=%{7l>A`][]e1Dl:j:A$٫@ޘw)5The")h'yp/q {I82V\`Ce#H#Dn\7BQ27]fp\!&z endstream endobj 172 0 obj << /Parent 173 0 R /Ff 12582912 /AA << /K 198 0 R >> /MK << /BG [ 1 1 1 ] /BC [ 0.50195 0.50195 0.50195 ] >> /F 4 /MaxLen 1 /Rect [ 50.17350 476.80200 59.26450 489.19800 ] /Type /Annot /P 23 0 R /FT /Tx /AP << /N 199 0 R >> /T (0) /Q 1 /Subtype /Widget >> endobj 173 0 obj << /Kids [ 172 0 R 174 0 R 177 0 R 180 0 R 183 0 R 186 0 R 189 0 R 192 0 R 195 0 R ] /T (EIN) >> endobj 174 0 obj << /Parent 173 0 R /Ff 12582912 /AA << /K 175 0 R >> /MK << /BG [ 1 1 1 ] /BC [ 0.50195 0.50195 0.50195 ] >> /F 4 /MaxLen 1 /Rect [ 142.73600 476.80200 151.82600 489.19800 ] /Type /Annot /P 23 0 R /FT /Tx /AP << /N 176 0 R >> /T (8) /Q 1 /Subtype /Widget >> endobj 175 0 obj << /S /JavaScript /JS (AutoTab\050this\054 event\054 \042DUNS\042\051\073) >> endobj 176 0 obj << /Filter /FlateDecode /BBox [ 0 0 9.09094 12.39670 ] /Resources << /ProcSet [ /PDF ] >> /Length 60 /Type /XObject /FormType 1 /Matrix [ 1 0 0 1 0 0 ] /Subtype /Form >> stream H2TH2P0P34T04343W(JJ235045Vp1@ w B endstream endobj 177 0 obj << /Parent 173 0 R /Ff 12582912 /AA << /K 178 0 R >> /MK << /BG [ 1 1 1 ] /BC [ 0.50195 0.50195 0.50195 ] >> /F 4 /MaxLen 1 /Rect [ 60.91740 476.80200 70.00820 489.19800 ] /Type /Annot /P 23 0 R /FT /Tx /AP << /N 179 0 R >> /T (1) /Q 1 /Subtype /Widget >> endobj 178 0 obj << /S /JavaScript /JS (AutoTab\050this\054 event\054 \042EIN\0562\042\051\073) >> endobj 179 0 obj << /Length 58 /Filter /FlateDecode /BBox [ 0 0 9.09091 12.39670 ] /Resources << /ProcSet [ /PDF ] >> /Subtype /Form >> stream H2THW0BK=KKC#=cK3sT4=S#wCr-  ʣ endstream endobj 180 0 obj << /Parent 173 0 R /Ff 12582912 /AA << /K 181 0 R >> /MK << /BG [ 1 1 1 ] /BC [ 0.50195 0.50195 0.50195 ] >> /F 4 /MaxLen 1 /Rect [ 78.27270 476.80200 87.36360 489.19800 ] /Type /Annot /P 23 0 R /FT /Tx /AP << /N 182 0 R >> /T (2) /Q 1 /Subtype /Widget >> endobj 181 0 obj << /S /JavaScript /JS (AutoTab\050this\054 event\054 \042EIN\0563\042\051\073) >> endobj 182 0 obj << /Length 58 /Filter /FlateDecode /BBox [ 0 0 9.09091 12.39670 ] /Resources << /ProcSet [ /PDF ] >> /Subtype /Form >> stream H2THW0BK=KKC#=cK3sT4=S#wCr-  ʣ endstream endobj 183 0 obj << /Parent 173 0 R /Ff 12582912 /AA << /K 184 0 R >> /MK << /BG [ 1 1 1 ] /BC [ 0.50195 0.50195 0.50195 ] >> /F 4 /MaxLen 1 /Rect [ 89.01650 476.80200 98.10740 489.19800 ] /Type /Annot /P 23 0 R /FT /Tx /AP << /N 185 0 R >> /T (3) /Q 1 /Subtype /Widget >> endobj 184 0 obj << /S /JavaScript /JS (AutoTab\050this\054 event\054 \042EIN\0564\042\051\073) >> endobj 185 0 obj << /Length 58 /Filter /FlateDecode /BBox [ 0 0 9.09091 12.39670 ] /Resources << /ProcSet [ /PDF ] >> /Subtype /Form >> stream H2THW0BK=KKC#=cK3sT4=S#wCr-  ʣ endstream endobj 186 0 obj << /Parent 173 0 R /Ff 12582912 /AA << /K 187 0 R >> /MK << /BG [ 1 1 1 ] /BC [ 0.50195 0.50195 0.50195 ] >> /F 4 /MaxLen 1 /Rect [ 99.76030 476.80200 108.85100 489.19800 ] /Type /Annot /P 23 0 R /FT /Tx /AP << /N 188 0 R >> /T (4) /Q 1 /Subtype /Widget >> endobj 187 0 obj << /S /JavaScript /JS (AutoTab\050this\054 event\054 \042EIN\0565\042\051\073) >> endobj 188 0 obj << /Length 58 /Filter /FlateDecode /BBox [ 0 0 9.09091 12.39670 ] /Resources << /ProcSet [ /PDF ] >> /Subtype /Form >> stream H2THW0BK=KKC#=cK3sT4=S#wCr-  ʣ endstream endobj 189 0 obj << /Parent 173 0 R /Ff 12582912 /AA << /K 190 0 R >> /MK << /BG [ 1 1 1 ] /BC [ 0.50195 0.50195 0.50195 ] >> /F 4 /MaxLen 1 /Rect [ 110.50400 476.80200 119.59500 489.19800 ] /Type /Annot /P 23 0 R /FT /Tx /AP << /N 191 0 R >> /T (5) /Q 1 /Subtype /Widget >> endobj 190 0 obj << /S /JavaScript /JS (AutoTab\050this\054 event\054 \042EIN\0566\042\051\073) >> endobj 191 0 obj << /Length 58 /Filter /FlateDecode /BBox [ 0 0 9.09091 12.39670 ] /Resources << /ProcSet [ /PDF ] >> /Subtype /Form >> stream H2THW0BK=KKC#=cK3sT4=S#wCr-  ʣ endstream endobj 192 0 obj << /Parent 173 0 R /Ff 12582912 /AA << /K 193 0 R >> /MK << /BG [ 1 1 1 ] /BC [ 0.50195 0.50195 0.50195 ] >> /F 4 /MaxLen 1 /Rect [ 121.24800 476.80200 130.33900 489.19800 ] /Type /Annot /P 23 0 R /FT /Tx /AP << /N 194 0 R >> /T (6) /Q 1 /Subtype /Widget >> endobj 193 0 obj << /S /JavaScript /JS (AutoTab\050this\054 event\054 \042EIN\0567\042\051\073) >> endobj 194 0 obj << /Length 58 /Filter /FlateDecode /BBox [ 0 0 9.09091 12.39670 ] /Resources << /ProcSet [ /PDF ] >> /Subtype /Form >> stream H2THW0BK=KKC#=cK3sT4=S#wCr-  ʣ endstream endobj 195 0 obj << /Parent 173 0 R /Ff 12582912 /AA << /K 196 0 R >> /MK << /BG [ 1 1 1 ] /BC [ 0.50195 0.50195 0.50195 ] >> /F 4 /MaxLen 1 /Rect [ 131.99200 476.80200 141.08300 489.19800 ] /Type /Annot /P 23 0 R /FT /Tx /AP << /N 197 0 R >> /T (7) /Q 1 /Subtype /Widget >> endobj 196 0 obj << /S /JavaScript /JS (AutoTab\050this\054 event\054 \042EIN\0568\042\051\073) >> endobj 197 0 obj << /Length 58 /Filter /FlateDecode /BBox [ 0 0 9.09091 12.39670 ] /Resources << /ProcSet [ /PDF ] >> /Subtype /Form >> stream H2THW0BK=KKC#=cK3sT4=S#wCr-  ʣ endstream endobj 198 0 obj << /S /JavaScript /JS (AutoTab\050this\054 event\054 \042EIN\0561\042\051\073) >> endobj 199 0 obj << /Length 58 /Filter /FlateDecode /BBox [ 0 0 9.09091 12.39670 ] /Resources << /ProcSet [ /PDF ] >> /Subtype /Form >> stream H2THW0BK=KKC#=cK3sT4=S#wCr-  ʣ endstream endobj 200 0 obj [ 16 0 R 34 0 R 201 0 R 202 0 R 203 0 R 207 0 R 210 0 R 213 0 R 217 0 R 221 0 R 225 0 R 229 0 R 233 0 R 237 0 R 243 0 R 247 0 R 251 0 R 255 0 R 259 0 R 263 0 R 267 0 R 271 0 R 273 0 R 274 0 R 275 0 R 276 0 R 280 0 R 281 0 R 284 0 R 287 0 R 288 0 R 290 0 R 291 0 R 57 0 R ] endobj 201 0 obj << /Ff 12582912 /MK << >> /F 4 /Rect [ 95.22000 700.71100 144.65900 711.80200 ] /Type /Annot /P 18 0 R /FT /Tx /T (CongDistApplicant) /TU (enter applicant\047s Congressional District) /Subtype /Widget >> endobj 202 0 obj << /Ff 8388608 /MK << >> /F 4 /Rect [ 415.75200 700.71700 465.68300 712.30600 ] /Type /Annot /P 18 0 R /FT /Tx /T (CongDistProject) /TU (Enter Congressional Districts affected\056) /Subtype /Widget >> endobj 203 0 obj << /Ff 65536 /MK << /CA (Attachments) /BG [ 0.75293 ] /BC [ 0 0 1 ] /IF << >> >> /A 204 0 R /Rect [ 183.22500 662.75000 257.92300 677.20800 ] /Type /Annot /P 18 0 R /FT /Btn /AP << /N 205 0 R >> /DA (\057HeBo 9 Tf 0 g) /T (Attachments) /TU (Click here to open attachments tab\056) /Subtype /Widget >> endobj 204 0 obj << /N /ShowHideAttachments /S /Named >> endobj 205 0 obj << /Filter /FlateDecode /BBox [ 0 0 74.69800 14.45800 ] /Resources << /Font << /HeBo 206 0 R >> /ProcSet [ /PDF /Text ] >> /Length 129 /Type /XObject /FormType 1 /Matrix [ 1 0 0 1 0 0 ] /Subtype /Form >> stream H4 @D)Y͖$ʂ c̙JOhjWXxC_F;cK[:0#v)Z\яA;he8 Ll;e2pL8/c"i endstream endobj 206 0 obj << /Encoding 29 0 R /Type /Font /Subtype /Type1 /BaseFont /Helvetica-Bold /Name /HeBo >> endobj 207 0 obj << /Ff 12582912 /AA << /F 208 0 R /K 209 0 R >> /MK << >> /F 4 /Rect [ 94.03120 626.34100 144.19200 638.42200 ] /Type /Annot /P 18 0 R /FT /Tx /T (FundingStartDate) /TU (enter the requested starting date) /Subtype /Widget >> endobj 208 0 obj << /S /JavaScript /JS (AFDate\137FormatEx\050\042mm\057dd\057yyyy\042\051\073) >> endobj 209 0 obj << /S /JavaScript /JS (AFDate\137KeystrokeEx\050\042mm\057dd\057yyyy\042\051\073) >> endobj 210 0 obj << /Ff 12582912 /AA << /F 211 0 R /K 212 0 R >> /MK << >> /F 4 /Rect [ 415.55700 626.61900 465.64900 639.70500 ] /Type /Annot /P 18 0 R /FT /Tx /T (FundingEndDate) /TU (enter the requested ending date) /Subtype /Widget >> endobj 211 0 obj << /S /JavaScript /JS (AFDate\137FormatEx\050\042mm\057dd\057yyyy\042\051\073) >> endobj 212 0 obj << /S /JavaScript /JS (AFDate\137KeystrokeEx\050\042mm\057dd\057yyyy\042\051\073) >> endobj 213 0 obj << /AA << /F 214 0 R /K 215 0 R >> /MK << /BG [ 1 1 1 ] >> /F 4 /Rect [ 112.84600 586.69400 259.01100 597.74300 ] /Type /Annot /P 18 0 R /FT /Tx /AP << /N 216 0 R >> /DA (\057Helv 9 Tf 0\056251 0 0\056251 rg) /T (FundingFederal) /TU (enter Federal Funding requested) /Q 2 /Subtype /Widget >> endobj 214 0 obj << /S /JavaScript /JS (AFNumber\137Format\0502\054 0\054 0\054 0\054 \042\042\054 true\051\073) >> endobj 215 0 obj << /S /JavaScript /JS (AFNumber\137Keystroke\0502\054 0\054 0\054 0\054 \042\042\054 true\051\073) >> endobj 216 0 obj << /BBox [ 0 0 146.16500 11.04900 ] /Resources << /ProcSet [ /PDF ] >> /Length 28 /Type /XObject /FormType 1 /Matrix [ 1 0 0 1 0 0 ] /Subtype /Form >> stream 1 g 0 0 146.165 11.049 re f endstream endobj 217 0 obj << /AA << /F 218 0 R /K 219 0 R >> /MK << /BG [ 1 1 1 ] >> /F 4 /Rect [ 112.84600 570.68600 259.01100 581.73500 ] /Type /Annot /P 18 0 R /FT /Tx /AP << /N 220 0 R >> /DA (\057Helv 9 Tf 0\056251 0 0\056251 rg) /T (fundingApplicant) /TU (enter applicant funding) /Q 2 /Subtype /Widget >> endobj 218 0 obj << /S /JavaScript /JS (AFNumber\137Format\0502\054 0\054 0\054 0\054 \042\042\054 true\051\073) >> endobj 219 0 obj << /S /JavaScript /JS (AFNumber\137Keystroke\0502\054 0\054 0\054 0\054 \042\042\054 true\051\073) >> endobj 220 0 obj << /BBox [ 0 0 146.16500 11.04900 ] /Resources << /ProcSet [ /PDF ] >> /Length 28 /Type /XObject /FormType 1 /Matrix [ 1 0 0 1 0 0 ] /Subtype /Form >> stream 1 g 0 0 146.165 11.049 re f endstream endobj 221 0 obj << /AA << /F 222 0 R /K 223 0 R >> /MK << /BG [ 1 1 1 ] >> /F 4 /Rect [ 112.84600 554.50400 259.01100 565.55300 ] /Type /Annot /P 18 0 R /FT /Tx /AP << /N 224 0 R >> /DA (\057Helv 9 Tf 0\056251 0 0\056251 rg) /T (fundingState) /TU ( enter State funding) /Q 2 /Subtype /Widget >> endobj 222 0 obj << /S /JavaScript /JS (AFNumber\137Format\0502\054 0\054 0\054 0\054 \042\042\054 true\051\073) >> endobj 223 0 obj << /S /JavaScript /JS (AFNumber\137Keystroke\0502\054 0\054 0\054 0\054 \042\042\054 true\051\073) >> endobj 224 0 obj << /BBox [ 0 0 146.16500 11.04900 ] /Resources << /ProcSet [ /PDF ] >> /Length 28 /Type /XObject /FormType 1 /Matrix [ 1 0 0 1 0 0 ] /Subtype /Form >> stream 1 g 0 0 146.165 11.049 re f endstream endobj 225 0 obj << /AA << /F 226 0 R /K 227 0 R >> /MK << /BG [ 1 1 1 ] >> /F 4 /Rect [ 112.84600 538.14900 259.01100 549.19800 ] /Type /Annot /P 18 0 R /FT /Tx /AP << /N 228 0 R >> /DA (\057Helv 9 Tf 0\056251 0 0\056251 rg) /T (fundinglocal) /TU (enter local funding) /Q 2 /Subtype /Widget >> endobj 226 0 obj << /S /JavaScript /JS (AFNumber\137Format\0502\054 0\054 0\054 0\054 \042\042\054 true\051\073) >> endobj 227 0 obj << /S /JavaScript /JS (AFNumber\137Keystroke\0502\054 0\054 0\054 0\054 \042\042\054 true\051\073) >> endobj 228 0 obj << /BBox [ 0 0 146.16500 11.04900 ] /Resources << /ProcSet [ /PDF ] >> /Length 28 /Type /XObject /FormType 1 /Matrix [ 1 0 0 1 0 0 ] /Subtype /Form >> stream 1 g 0 0 146.165 11.049 re f endstream endobj 229 0 obj << /AA << /F 230 0 R /K 231 0 R >> /MK << /BG [ 1 1 1 ] >> /F 4 /Rect [ 112.84600 521.79300 259.01100 532.84200 ] /Type /Annot /P 18 0 R /FT /Tx /AP << /N 232 0 R >> /DA (\057Helv 9 Tf 0\056251 0 0\056251 rg) /T (fundingother) /TU (enter other funding) /Q 2 /Subtype /Widget >> endobj 230 0 obj << /S /JavaScript /JS (AFNumber\137Format\0502\054 0\054 0\054 0\054 \042\042\054 true\051\073) >> endobj 231 0 obj << /S /JavaScript /JS (AFNumber\137Keystroke\0502\054 0\054 0\054 0\054 \042\042\054 true\051\073) >> endobj 232 0 obj << /BBox [ 0 0 146.16500 11.04900 ] /Resources << /ProcSet [ /PDF ] >> /Length 28 /Type /XObject /FormType 1 /Matrix [ 1 0 0 1 0 0 ] /Subtype /Form >> stream 1 g 0 0 146.165 11.049 re f endstream endobj 233 0 obj << /AA << /F 234 0 R /K 235 0 R >> /MK << /BG [ 1 1 1 ] >> /F 4 /Rect [ 112.84600 505.61200 259.01100 516.66100 ] /Type /Annot /P 18 0 R /FT /Tx /AP << /N 236 0 R >> /DA (\057Helv 9 Tf 0\056251 0 0\056251 rg) /T (fundingprogincome) /TU (enter program income) /Q 2 /Subtype /Widget >> endobj 234 0 obj << /S /JavaScript /JS (AFNumber\137Format\0502\054 0\054 0\054 0\054 \042\042\054 true\051\073) >> endobj 235 0 obj << /S /JavaScript /JS (AFNumber\137Keystroke\0502\054 0\054 0\054 0\054 \042\042\054 true\051\073) >> endobj 236 0 obj << /BBox [ 0 0 146.16500 11.04900 ] /Resources << /ProcSet [ /PDF ] >> /Length 28 /Type /XObject /FormType 1 /Matrix [ 1 0 0 1 0 0 ] /Subtype /Form >> stream 1 g 0 0 146.165 11.049 re f endstream endobj 237 0 obj << /AA << /F 238 0 R /C 239 0 R /K 240 0 R /V 241 0 R >> /MK << /BG [ 1 1 1 ] >> /F 4 /Rect [ 112.84600 489.25600 259.01100 500.30500 ] /Type /Annot /P 18 0 R /FT /Tx /AP << /N 242 0 R >> /DA (\057Helv 9 Tf 0 g) /T (fundingtotal) /TU (total funding \050this field auto calculates\051) /Q 2 /Subtype /Widget >> endobj 238 0 obj << /S /JavaScript /JS (AFNumber\137Format\0502\054 0\054 0\054 0\054 \042\042\054 true\051\073) >> endobj 239 0 obj << /S /JavaScript /JS (AFSimple\137Calculate\050\042SUM\042\054 new Array \050\042fundingapplicant\042\054 \042fundingfa\042\054 \042fundinglocal\042\054 \042fundingother\042\054 \042fundingprogincome\042\054 \042fundingstate\042\051\051\073) >> endobj 240 0 obj << /S /JavaScript /JS (AFNumber\137Keystroke\0502\054 0\054 0\054 0\054 \042\042\054 true\051\073) >> endobj 241 0 obj << /S /JavaScript /JS (if \050event\056value\075\0750\051 event\056value\075\042\042\073) >> endobj 242 0 obj << /BBox [ 0 0 146.16500 11.04900 ] /Resources << /ProcSet [ /PDF ] >> /Length 28 /Type /XObject /FormType 1 /Matrix [ 1 0 0 1 0 0 ] /Subtype /Form >> stream 1 g 0 0 146.165 11.049 re f endstream endobj 243 0 obj << /MK << /CA (8) >> /F 4 /P 18 0 R /Rect [ 33.97200 454.66300 42.01300 462.69900 ] /Type /Annot /AS /Off /FT /Btn /AP << /N << /Yes 244 0 R >> /D << /Off 245 0 R /Yes 246 0 R >> >> /T (eo12372Yes) /TU (Check if submission is subject to and was made available for review under E\056O\056 12372\056) /Subtype /Widget >> endobj 244 0 obj << /Filter /FlateDecode /BBox [ 0 0 8.04100 8.03601 ] /Resources << /ProcSet [ /PDF ] >> /Length 61 /Type /XObject /FormType 1 /Matrix [ 1 0 0 1 0 0 ] /Subtype /Form >> stream H*2T0T030f E\\y\FzFP\.ma`cd A2\\ endstream endobj 245 0 obj << /BBox [ 0 0 8.04100 8.03601 ] /Resources << /ProcSet [ /PDF ] >> /Length 32 /Type /XObject /FormType 1 /Matrix [ 1 0 0 1 0 0 ] /Subtype /Form >> stream 0.749023 g 0 0 8.041 8.036 re f endstream endobj 246 0 obj << /Filter /FlateDecode /BBox [ 0 0 8.04100 8.03601 ] /Resources << /ProcSet [ /PDF ] >> /Length 85 /Type /XObject /FormType 1 /Matrix [ 1 0 0 1 0 0 ] /Subtype /Form >> stream H237402VH2P0P301f E\i\\ f`a3p8W)T, D[*)0BL1W @' endstream endobj 247 0 obj << /Ff 12582912 /AA << /F 248 0 R /K 249 0 R >> /MK << /BG [ 1 1 1 ] /BC [ 1 1 1 ] >> /F 4 /BS << /W 2 /S /S >> /Rect [ 421.39200 452.45000 470.89400 463.97900 ] /Type /Annot /P 18 0 R /FT /Tx /AP << /N 250 0 R >> /T (SEODate) /TU (enter date submitted to EO12372 process) /Subtype /Widget >> endobj 248 0 obj << /S /JavaScript /JS (AFDate\137FormatEx\050\042mm\057dd\057yyyy\042\051\073) >> endobj 249 0 obj << /S /JavaScript /JS (AFDate\137KeystrokeEx\050\042mm\057dd\057yyyy\042\051\073) >> endobj 250 0 obj << /BBox [ 0 0 49.50200 11.52900 ] /Resources << /ProcSet [ /PDF ] >> /Length 57 /Type /XObject /FormType 1 /Matrix [ 1 0 0 1 0 0 ] /Subtype /Form >> stream 1 g 0 0 49.502 11.529 re f 1 G 2 w 1 1 47.502 9.529 re s endstream endobj 251 0 obj << /MK << /CA (8) >> /F 4 /P 18 0 R /Rect [ 33.48000 436.30100 42.52000 447.33600 ] /Type /Annot /AS /Off /FT /Btn /AP << /N << /Yes 252 0 R >> /D << /Off 253 0 R /Yes 254 0 R >> >> /T (eo12372notselected) /TU (Check if submission is subject to E\056O\056 12372\054 but was not selected for review\056) /Subtype /Widget >> endobj 252 0 obj << /Filter /FlateDecode /BBox [ 0 0 9.04001 11.03500 ] /Resources << /ProcSet [ /PDF ] >> /Length 63 /Type /XObject /FormType 1 /Matrix [ 1 0 0 1 0 0 ] /Subtype /Form >> stream H*2T0T030Q306U(J 2RrMrFz@^3BHsrbn endstream endobj 253 0 obj << /BBox [ 0 0 9.04001 11.03500 ] /Resources << /ProcSet [ /PDF ] >> /Length 32 /Type /XObject /FormType 1 /Matrix [ 1 0 0 1 0 0 ] /Subtype /Form >> stream 0.749023 g 0 0 9.04 11.035 re f endstream endobj 254 0 obj << /Filter /FlateDecode /BBox [ 0 0 9.04001 11.03500 ] /Resources << /ProcSet [ /PDF ] >> /Length 85 /Type /XObject /FormType 1 /Matrix [ 1 0 0 1 0 0 ] /Subtype /Form >> stream HDA@@D}Nn3} +' JIpRfM>`\9c, Q5?@S endstream endobj 255 0 obj << /MK << /CA (8) >> /F 4 /P 18 0 R /Rect [ 33.98000 421.39400 43.02000 431.42900 ] /Type /Annot /AS /Off /FT /Btn /AP << /N << /Yes 256 0 R >> /D << /Off 257 0 R /Yes 258 0 R >> >> /T (eo12372No) /TU (Check if program is NOT covered by E\056O\056 12372\056) /Subtype /Widget >> endobj 256 0 obj << /Filter /FlateDecode /BBox [ 0 0 9.04001 10.03500 ] /Resources << /ProcSet [ /PDF ] >> /Length 63 /Type /XObject /FormType 1 /Matrix [ 1 0 0 1 0 0 ] /Subtype /Form >> stream H*2T0T030Q306U(J 2*r%L,.g( 0bk endstream endobj 257 0 obj << /BBox [ 0 0 9.04001 10.03500 ] /Resources << /ProcSet [ /PDF ] >> /Length 32 /Type /XObject /FormType 1 /Matrix [ 1 0 0 1 0 0 ] /Subtype /Form >> stream 0.749023 g 0 0 9.04 10.035 re f endstream endobj 258 0 obj << /Filter /FlateDecode /BBox [ 0 0 9.04001 10.03500 ] /Resources << /ProcSet [ /PDF ] >> /Length 85 /Type /XObject /FormType 1 /Matrix [ 1 0 0 1 0 0 ] /Subtype /Form >> stream HDɻ 0| N-2H _' 7> /F 4 /P 18 0 R /Rect [ 33.23760 384.76300 42.27760 393.79800 ] /Type /Annot /AS /Off /FT /Btn /AP << /N << /Yes 260 0 R >> /D << /Off 261 0 R /Yes 262 0 R >> >> /T (DelinquentFedDebtYes) /TU (Check Yes if agency is delinquent on any federal debt\056) /Subtype /Widget >> endobj 260 0 obj << /Filter /FlateDecode /BBox [ 0 0 9.04001 9.03500 ] /Resources << /ProcSet [ /PDF ] >> /Length 61 /Type /XObject /FormType 1 /Matrix [ 1 0 0 1 0 0 ] /Subtype /Form >> stream H*2T0T030Ʀ E\\y\FzFP\.mn`cd A2\\} endstream endobj 261 0 obj << /BBox [ 0 0 9.04001 9.03500 ] /Resources << /ProcSet [ /PDF ] >> /Length 31 /Type /XObject /FormType 1 /Matrix [ 1 0 0 1 0 0 ] /Subtype /Form >> stream 0.749023 g 0 0 9.04 9.035 re f endstream endobj 262 0 obj << /Filter /FlateDecode /BBox [ 0 0 9.04001 9.03500 ] /Resources << /ProcSet [ /PDF ] >> /Length 83 /Type /XObject /FormType 1 /Matrix [ 1 0 0 1 0 0 ] /Subtype /Form >> stream H4A 0yE^PmgxE % 3QeD'Ոn 3Ӄ+nX v!ӌc ~| endstream endobj 263 0 obj << /MK << /CA (8) >> /F 4 /P 18 0 R /Rect [ 97.97340 384.83400 107.01300 393.86900 ] /Type /Annot /AS /Off /FT /Btn /AP << /N << /Yes 264 0 R >> /D << /Off 265 0 R /Yes 266 0 R >> >> /T (DelinquentFedDebtNo) /TU (Check No if agency is NOT delinquent on any federal debt\056) /Subtype /Widget >> endobj 264 0 obj << /Filter /FlateDecode /BBox [ 0 0 9.03960 9.03497 ] /Resources << /ProcSet [ /PDF ] >> /Length 62 /Type /XObject /FormType 1 /Matrix [ 1 0 0 1 0 0 ] /Subtype /Form >> stream H*2T0T0304S E\\y\FzFP\.mn`cd A2\\ endstream endobj 265 0 obj << /BBox [ 0 0 9.03960 9.03497 ] /Resources << /ProcSet [ /PDF ] >> /Length 33 /Type /XObject /FormType 1 /Matrix [ 1 0 0 1 0 0 ] /Subtype /Form >> stream 0.749023 g 0 0 9.0396 9.035 re f endstream endobj 266 0 obj << /Filter /FlateDecode /BBox [ 0 0 9.03960 9.03497 ] /Resources << /ProcSet [ /PDF ] >> /Length 84 /Type /XObject /FormType 1 /Matrix [ 1 0 0 1 0 0 ] /Subtype /Form >> stream H237402VH2P0P304S E\i\\ qsx8WH#D, D+)0BL1W @& endstream endobj 267 0 obj << /MK << /CA (8) >> /F 4 /P 18 0 R /Rect [ 33.45260 319.38200 42.49250 328.41600 ] /Type /Annot /AS /Off /FT /Btn /AP << /N << /Yes 268 0 R >> /D << /Off 269 0 R /Yes 270 0 R >> >> /T (CertificationsIagree) /TU (Check this box if you agree to statements in item 21\056) /Subtype /Widget >> endobj 268 0 obj << /Filter /FlateDecode /BBox [ 0 0 9.03990 9.03400 ] /Resources << /ProcSet [ /PDF ] >> /Length 60 /Type /XObject /FormType 1 /Matrix [ 1 0 0 1 0 0 ] /Subtype /Form >> stream H*2T0T030S& E\\y\FzP\.m`e!@\\`?@ endstream endobj 269 0 obj << /BBox [ 0 0 9.03990 9.03400 ] /Resources << /ProcSet [ /PDF ] >> /Length 33 /Type /XObject /FormType 1 /Matrix [ 1 0 0 1 0 0 ] /Subtype /Form >> stream 0.749023 g 0 0 9.0399 9.034 re f endstream endobj 270 0 obj << /Filter /FlateDecode /BBox [ 0 0 9.03990 9.03400 ] /Resources << /ProcSet [ /PDF ] >> /Length 83 /Type /XObject /FormType 1 /Matrix [ 1 0 0 1 0 0 ] /Subtype /Form >> stream H237402VH2P0P30S& E\i\\ qsx8W1T( D+)@Y0q*x1W @͵ endstream endobj 271 0 obj << /Ff 5111808 /I [ 0 ] /MK << /BG [ 1 1 1 ] >> /F 4 /Opt 140 0 R /DV 141 0 R /Rect [ 93.93820 252.25300 147.20500 263.31900 ] /Type /Annot /P 18 0 R /FT /Ch /AP << /N 272 0 R >> /V ( ) /T (AuthPrefix) /TU (Choose prefix for Authorized Representative \050Dr\056\054 Mr\056\054 Mrs\056\054 Ms\056\051) /Subtype /Widget >> endobj 272 0 obj << /Filter /FlateDecode /BBox [ 0 0 53.26680 11.06600 ] /Resources << /Font << /Helv 28 0 R >> /ProcSet [ /PDF /Text ] >> /Length 110 /Type /XObject /FormType 1 /Matrix [ 1 0 0 1 0 0 ] /Subtype /Form >> stream H4 @Lud[EHc!\|@A Cf<="Ϋr0"eS+y%_tXwBi>üSK"mm`t>ǃOET8t endstream endobj 273 0 obj << /Ff 12582912 /MK << >> /F 4 /Rect [ 285.18000 251.74800 559.85200 262.81800 ] /Type /Annot /P 18 0 R /FT /Tx /T (AuthFirstname) /TU (Enter authorized representative\047s first name\056) /Subtype /Widget >> endobj 274 0 obj << /Ff 12582912 /MK << >> /F 4 /Rect [ 91.57820 235.71400 291.11800 247.28700 ] /Type /Annot /P 18 0 R /FT /Tx /T (AuthMiddlename) /TU (Enter authorized representative\047s middle name\056) /Subtype /Widget >> endobj 275 0 obj << /Ff 12582912 /MK << >> /F 4 /Rect [ 92.37660 218.44500 565.13600 231.01300 ] /Type /Annot /P 18 0 R /FT /Tx /T (AuthLastname) /TU (Enter authorized representative\047s last name\056) /Subtype /Widget >> endobj 276 0 obj << /V 277 0 R /Ff 5111808 /I 278 0 R /MK << /BG [ 1 1 1 ] >> /F 4 /Opt 147 0 R /DV 148 0 R /Rect [ 92.54700 203.46500 186.45300 213.53500 ] /Type /Annot /P 18 0 R /FT /Ch /AP << /N 279 0 R >> /DA (\057Helv 10 Tf 0 g) /T (AuthSuffix) /TU (Choose prefix for Authorized Representative \050Dr\056\054 Mr\056\054 Mrs\056\054 Ms\056\051) /Subtype /Widget >> endobj 277 0 obj ( ) endobj 278 0 obj [ 0 ] endobj 279 0 obj << /Filter /FlateDecode /BBox [ 0 0 93.90600 10.07000 ] /Resources << /Font << /Helv 28 0 R >> /ProcSet [ /PDF /Text ] >> /Length 102 /Type /XObject /FormType 1 /Matrix [ 1 0 0 1 0 0 ] /Subtype /Form >> stream H, @@SK6 ̖:(I7X ]aTbv9-g[*w> /F 4 /Rect [ 67.94500 182.35400 419.77900 194.42400 ] /Type /Annot /P 18 0 R /FT /Tx /T (AuthTitle) /TU (Enter authorized representative\047s title\056) /Subtype /Widget >> endobj 281 0 obj << /Ff 4194304 /AA << /F 282 0 R /K 283 0 R >> /MK << >> /F 4 /Rect [ 114.36700 162.37900 313.33900 174.42500 ] /Type /Annot /P 18 0 R /FT /Tx /T (AuthTelephone) /TU (Enter authorized representative\047s telephone number\056) /Subtype /Widget >> endobj 282 0 obj << /S /JavaScript /JS (AFSpecial\137Format\0502\051\073) >> endobj 283 0 obj << /S /JavaScript /JS (AFSpecial\137Keystroke\0502\051\073) >> endobj 284 0 obj << /Ff 4194304 /AA << /F 285 0 R /K 286 0 R >> /MK << >> /F 4 /Rect [ 368.56400 162.34100 568.53600 174.38600 ] /Type /Annot /P 18 0 R /FT /Tx /T (AuthFax) /TU (Enter authorized representative\047s fax number\056) /Subtype /Widget >> endobj 285 0 obj << /S /JavaScript /JS (AFSpecial\137Format\0502\051\073) >> endobj 286 0 obj << /S /JavaScript /JS (AFSpecial\137Keystroke\0502\051\073) >> endobj 287 0 obj << /Ff 12582912 /MK << >> /F 4 /Rect [ 74.65940 141.25400 546.30000 153.33000 ] /Type /Annot /P 18 0 R /FT /Tx /T (AuthEmail) /TU (Enter authorized representative\047s e\055mail address\056) /Subtype /Widget >> endobj 288 0 obj << /H /I /NM (5af31d83\0559ce0\0554975\055a8fd\055bd570b1980c6) /C [ 0 0 1 ] /Border [ 0 0 1 ] /A 289 0 R /Rect [ 157.69700 381.87200 224.00100 396.01100 ] /Type /Annot /P 18 0 R /BS << /W 1 /Type /Border /S /S >> /Subtype /Link >> endobj 289 0 obj << /D [ 36 0 R /FitR -280 -9 893 801 ] /S /GoTo >> endobj 290 0 obj << /MK << >> /F 4 /Rect [ 186.24900 122.33200 314.04200 133.77100 ] /Type /Annot /P 18 0 R /FT /Tx /T (AuthSignature) /TU (Authorized representative\047s signature goes here\056) /Subtype /Widget >> endobj 291 0 obj << /MK << >> /F 4 /Rect [ 382.50500 122.06600 510.69600 133.47100 ] /Type /Annot /P 18 0 R /FT /Tx /T (AuthDateSigned) /TU (Enter date signed by authorized representative\056) /Subtype /Widget >> endobj 292 0 obj << /Ff 4849664 /I [ 0 ] /MK << /BG [ 1 1 1 ] >> /F 4 /Opt 293 0 R /DV 294 0 R /Rect [ 36.06390 700.58900 173.07900 712.69500 ] /Type /Annot /P 4 0 R /FT /Ch /AP << /N 295 0 R >> /V ( ) /T (ApplicantType1) /TU (Choose type of applicant from the list of values presented\056) /Subtype /Widget >> endobj 293 0 obj [ ( ) (A\056 State) (B\056 Municipal) (C\056 County) (D\056 Township) (E\056 Interstate) (F\056 Intermunicipal) (G\056 Special District) (H\056 Independent School District) (I\056 State Controlled Institution of Higher Learning) (J\056 Private University) (K\056 Indian Tribe) (L\056 Individual) (M\056 Profit Organization) (N\056 Other \050Specify\051) (O\056 Not for Profit Organization) ] endobj 294 0 obj ( ) endobj 295 0 obj << /Filter /FlateDecode /BBox [ 0 0 137.01500 12.10600 ] /Resources << /Font << /Helv 28 0 R >> /ProcSet [ /PDF /Text ] >> /Length 109 /Type /XObject /FormType 1 /Matrix [ 1 0 0 1 0 0 ] /Subtype /Form >> stream H4= @wWf1"X@TA"h(gj)>JmĄXy(ڑwI#-TV72>ھ. endstream endobj 296 0 obj << /Ff 4849664 /I [ 0 ] /MK << /BG [ 1 1 1 ] >> /F 4 /Opt 293 0 R /DV 294 0 R /Rect [ 36.06390 668.51800 173.07900 679.62400 ] /Type /Annot /P 4 0 R /FT /Ch /AP << /N 297 0 R >> /V ( ) /T (ApplicantType2) /TU (Choose type of applicant from the list of values presented\056) /Subtype /Widget >> endobj 297 0 obj << /Filter /FlateDecode /BBox [ 0 0 137.01500 11.10600 ] /Resources << /Font << /Helv 28 0 R >> /ProcSet [ /PDF /Text ] >> /Length 112 /Type /XObject /FormType 1 /Matrix [ 1 0 0 1 0 0 ] /Subtype /Form >> stream H4˱ 0<&&U8|AJ7t=w%tIqGFՋ4oxd7 ϓtPw>D]qcC1*fӀ~ endstream endobj 298 0 obj << /V ( ) /Ff 4849664 /I [ 0 ] /MK << /BG [ 1 1 1 ] >> /F 4 /Opt 293 0 R /DV 294 0 R /Rect [ 36.06390 635.44700 173.07900 647.55300 ] /Type /Annot /P 4 0 R /FT /Ch /AP << /N 299 0 R >> /DA (\057Helv 0 Tf 0 g) /T (ApplicantType3) /TU (Choose type of applicant from the list of values presented\056) /Subtype /Widget >> endobj 299 0 obj << /Filter /FlateDecode /BBox [ 0 0 137.01500 12.10600 ] /Resources << /Font << /Helv 28 0 R >> /ProcSet [ /PDF /Text ] >> /Length 109 /Type /XObject /FormType 1 /Matrix [ 1 0 0 1 0 0 ] /Subtype /Form >> stream H4= @wWf1"X@TA"h(gj)>JmĄXy(ڑwI#-TV72>ھ. endstream endobj 300 0 obj << /Ff 8388608 /MK << >> /F 4 /Rect [ 35.28570 603.42900 271.07100 614.28600 ] /Type /Annot /P 4 0 R /FT /Tx /T (ApplicantOther) /TU (Enter other applicant type\056) /Subtype /Widget >> endobj 301 0 obj << /Ff 12582912 /MK << >> /F 4 /DV 302 0 R /Rect [ 35.59480 565.07500 509.83400 578.63800 ] /Type /Annot /P 4 0 R /FT /Tx /AP << /N 303 0 R >> /V (U\056S\056 Department of Interior\054 Fish and Wildlife Service) /T (FederalAgencyName) /TU (Enter name of Federal agency\056) /Subtype /Widget >> endobj 302 0 obj (U\056S\056 Department of Interior\054 Fish and Wildlife Service) endobj 303 0 obj << /Filter [ /FlateDecode ] /BBox [ 0 0 474.23900 13.56300 ] /Resources << /Font << /Helv 28 0 R >> /ProcSet [ /PDF /Text ] >> /Length 183 /Type /XObject /FormType 1 /Matrix [ 1 0 0 1 0 0 ] /Subtype /Form >> stream H4α0>51 ]Uf"Ekk?3o\`dL2IR̔jA ,,7}a m Q09ҁp lHH?]{놱%Lb m߇٘S17DQ5iG-}[qcL?P`+c>! endstream endobj 304 0 obj << /Parent 305 0 R /Ff 12582912 /AA << /K 318 0 R >> /MK << /BG [ 1 1 1 ] /BC [ 0.50195 0.50195 0.50195 ] >> /F 4 /MaxLen 1 /Rect [ 43.73540 530.25500 53.65230 541.65200 ] /Type /Annot /FT /Tx /AP << /N 319 0 R >> /Subtype /Widget /T (1) /TU (CFDA number digit 1) /Q 1 /P 4 0 R >> endobj 305 0 obj << /Kids [ 304 0 R 306 0 R 309 0 R 312 0 R 315 0 R ] /T (cfda) >> endobj 306 0 obj << /Parent 305 0 R /Ff 12582912 /AA << /K 307 0 R >> /MK << /BG [ 1 1 1 ] /BC [ 0.50195 0.50195 0.50195 ] >> /F 4 /MaxLen 1 /Rect [ 55.30530 530.25500 65.22240 541.65200 ] /Type /Annot /P 4 0 R /FT /Tx /AP << /N 308 0 R >> /T (2) /Q 1 /Subtype /Widget >> endobj 307 0 obj << /S /JavaScript /JS (AutoTab\050this\054 event\054 \042cfda\0563\042\051\073) >> endobj 308 0 obj << /Filter /FlateDecode /BBox [ 0 0 9.91710 11.39700 ] /Resources << /ProcSet [ /PDF ] >> /Length 59 /Type /XObject /FormType 1 /Matrix [ 1 0 0 1 0 0 ] /Subtype /Form >> stream H2TH2P0PԳ447T0434W(JJ235045Vp1@ endstream endobj 309 0 obj << /Parent 305 0 R /Ff 12582912 /AA << /K 310 0 R >> /MK << /BG [ 1 1 1 ] /BC [ 0.50195 0.50195 0.50195 ] >> /F 4 /MaxLen 1 /Rect [ 73.48730 530.25500 83.40440 541.65200 ] /Type /Annot /FT /Tx /AP << /N 311 0 R >> /Subtype /Widget /T (3) /TU (CFDA number digit 3) /Q 1 /P 4 0 R >> endobj 310 0 obj << /S /JavaScript /JS (AutoTab\050this\054 event\054 \042cfda\0564\042\051\073) >> endobj 311 0 obj << /Filter /FlateDecode /BBox [ 0 0 9.91710 11.39700 ] /Resources << /ProcSet [ /PDF ] >> /Length 59 /Type /XObject /FormType 1 /Matrix [ 1 0 0 1 0 0 ] /Subtype /Form >> stream H2TH2P0PԳ447T0434W(JJ235045Vp1@ endstream endobj 312 0 obj << /Parent 305 0 R /Ff 12582912 /AA << /K 313 0 R >> /MK << /BG [ 1 1 1 ] /BC [ 0.50195 0.50195 0.50195 ] >> /F 4 /MaxLen 1 /Rect [ 85.05730 530.25500 94.97430 541.65200 ] /Type /Annot /FT /Tx /AP << /N 314 0 R >> /Subtype /Widget /T (4) /TU (CFDA number digit 4) /Q 1 /P 4 0 R >> endobj 313 0 obj << /S /JavaScript /JS (AutoTab\050this\054 event\054 \042cfda\0565\042\051\073) >> endobj 314 0 obj << /Filter /FlateDecode /BBox [ 0 0 9.91701 11.39700 ] /Resources << /ProcSet [ /PDF ] >> /Length 58 /Type /XObject /FormType 1 /Matrix [ 1 0 0 1 0 0 ] /Subtype /Form >> stream H2TH2P0PԳ44W0434W(JJ235045Vp1@ < r endstream endobj 315 0 obj << /Parent 305 0 R /Ff 12582912 /AA << /K 316 0 R >> /MK << /BG [ 1 1 1 ] /BC [ 0.50195 0.50195 0.50195 ] >> /F 4 /MaxLen 1 /Rect [ 96.62730 530.25500 106.54500 541.65200 ] /Type /Annot /FT /Tx /AP << /N 317 0 R >> /Subtype /Widget /T (5) /TU (CFDA number digit 5) /Q 1 /P 4 0 R >> endobj 316 0 obj << /S /JavaScript /JS (AutoTab\050this\054 event\054 \042CFDATitleProgram\0561\042\051\073) >> endobj 317 0 obj << /Filter /FlateDecode /BBox [ 0 0 9.91769 11.39700 ] /Resources << /ProcSet [ /PDF ] >> /Length 59 /Type /XObject /FormType 1 /Matrix [ 1 0 0 1 0 0 ] /Subtype /Form >> stream H2TH2P0PԳ447W0434W(JJ235045Vp1@ w endstream endobj 318 0 obj << /S /JavaScript /JS (AutoTab\050this\054 event\054 \042cfda\0562\042\051\073) >> endobj 319 0 obj << /Filter /FlateDecode /BBox [ 0 0 9.91690 11.39700 ] /Resources << /ProcSet [ /PDF ] >> /Length 59 /Type /XObject /FormType 1 /Matrix [ 1 0 0 1 0 0 ] /Subtype /Form >> stream H2TH2P0PԳ44T0434W(JJ235045Vp1@ endstream endobj 320 0 obj << /Parent 321 0 R /Ff 12582912 /MK << >> /F 4 /Rect [ 34.65610 488.58600 517.13900 509.17100 ] /Type /Annot /P 4 0 R /FT /Tx /DA (\057Helv 9 Tf 0 g) /T (1) /TU (enter CFDA Program Title) /Subtype /Widget >> endobj 321 0 obj << /Kids [ 320 0 R ] /T (CFDATitleProgram) >> endobj 322 0 obj << /Ff 12582912 /MK << >> /F 4 /Rect [ 33.54440 450.02900 350.09900 465.11400 ] /Type /Annot /P 4 0 R /FT /Tx /DA (\057Helv 10 Tf 0 g) /T (FundingOpNumber) /TU (enter funding opportunity \043 from announcement on Grants\056Gov) /Subtype /Widget >> endobj 323 0 obj << /Ff 12587008 /MK << >> /F 4 /Rect [ 33.25850 379.95800 516.74100 430.79300 ] /Type /Annot /P 4 0 R /FT /Tx /DA (\057Helv 10 Tf 0 g) /T (FundingOpTtitle) /TU (enter funding opportunity title from announcement on Grants\056Gov) /Subtype /Widget >> endobj 324 0 obj << /Ff 12582912 /MK << >> /F 4 /Rect [ 34.72290 343.45800 348.27700 355.54200 ] /Type /Annot /P 4 0 R /FT /Tx /DA (\057Helv 10 Tf 0 g) /T (CompetitionNumber) /TU (competition ID \043 from announcement on Grants\056Gov) /Subtype /Widget >> endobj 325 0 obj << /Ff 12587008 /MK << >> /F 4 /Rect [ 34.75870 274.95800 517.24100 324.18500 ] /Type /Annot /P 4 0 R /FT /Tx /DA (\057Helv 10 Tf 0 g) /T (DescriptiveTitle\050competition\051) /TU (Enter descriptive title from announcement on Grants\056Gov) /Subtype /Widget >> endobj 326 0 obj << /Ff 12587008 /MK << >> /F 4 /Rect [ 35.19450 198.90100 517.59100 250.15400 ] /Type /Annot /P 4 0 R /FT /Tx /DA (\057Helv 10 Tf 0 g) /T (AreasAffected) /TU (enter areas affected by projects \050cities\054 counties\054 states\054 etc\056\051) /Subtype /Widget >> endobj 327 0 obj << /Ff 12587008 /MK << >> /F 4 /Rect [ 33.68730 131.92200 516.17000 174.72100 ] /Type /Annot /P 4 0 R /FT /Tx /DA (\057Helv 10 Tf 0 g) /T (DescriptiveTitle) /TU (enter the descriptive title of your project) /Subtype /Widget >> endobj xref 0 328 0000000000 65535 f 0000000009 00000 n 0000000068 00000 n 0000000169 00000 n 0000000218 00000 n 0000000472 00000 n 0000002469 00000 n 0000002556 00000 n 0000003162 00000 n 0000003404 00000 n 0000004048 00000 n 0000004297 00000 n 0000005487 00000 n 0000005729 00000 n 0000005906 00000 n 0000006091 00000 n 0000006200 00000 n 0000006386 00000 n 0000006601 00000 n 0000006859 00000 n 0000011230 00000 n 0000011340 00000 n 0000011416 00000 n 0000011477 00000 n 0000011734 00000 n 0000015083 00000 n 0000015514 00000 n 0000015769 00000 n 0000016099 00000 n 0000016199 00000 n 0000017526 00000 n 0000017702 00000 n 0000017817 00000 n 0000018002 00000 n 0000018215 00000 n 0000018401 00000 n 0000018587 00000 n 0000018844 00000 n 0000019844 00000 n 0000021034 00000 n 0000021082 00000 n 0000021268 00000 n 0000021549 00000 n 0000021752 00000 n 0000021945 00000 n 0000022150 00000 n 0000022446 00000 n 0000028034 00000 n 0000028067 00000 n 0000028110 00000 n 0000028168 00000 n 0000028490 00000 n 0000028865 00000 n 0000029069 00000 n 0000029112 00000 n 0000029170 00000 n 0000029492 00000 n 0000029867 00000 n 0000030072 00000 n 0000030115 00000 n 0000030173 00000 n 0000030495 00000 n 0000030870 00000 n 0000031075 00000 n 0000031118 00000 n 0000031176 00000 n 0000031498 00000 n 0000031873 00000 n 0000032136 00000 n 0000041460 00000 n 0000041506 00000 n 0000041922 00000 n 0000042344 00000 n 0000046101 00000 n 0000046622 00000 n 0000047217 00000 n 0000051163 00000 n 0000051721 00000 n 0000052453 00000 n 0000057379 00000 n 0000057406 00000 n 0000057611 00000 n 0000057654 00000 n 0000057712 00000 n 0000058034 00000 n 0000058409 00000 n 0000058672 00000 n 0000063653 00000 n 0000063680 00000 n 0000063723 00000 n 0000063781 00000 n 0000064103 00000 n 0000064478 00000 n 0000064769 00000 n 0000065036 00000 n 0000065251 00000 n 0000065541 00000 n 0000065826 00000 n 0000066095 00000 n 0000066310 00000 n 0000066600 00000 n 0000066948 00000 n 0000067216 00000 n 0000067432 00000 n 0000067723 00000 n 0000068015 00000 n 0000068280 00000 n 0000068495 00000 n 0000068783 00000 n 0000069172 00000 n 0000069437 00000 n 0000069652 00000 n 0000069940 00000 n 0000070310 00000 n 0000070577 00000 n 0000070792 00000 n 0000071082 00000 n 0000071314 00000 n 0000071518 00000 n 0000071776 00000 n 0000071875 00000 n 0000071977 00000 n 0000072157 00000 n 0000072335 00000 n 0000072530 00000 n 0000072789 00000 n 0000073069 00000 n 0000073318 00000 n 0000073417 00000 n 0000073620 00000 n 0000073824 00000 n 0000074028 00000 n 0000074217 00000 n 0000074410 00000 n 0000074601 00000 n 0000074798 00000 n 0000074993 00000 n 0000075181 00000 n 0000075367 00000 n 0000075556 00000 n 0000075886 00000 n 0000075948 00000 n 0000075969 00000 n 0000076316 00000 n 0000076534 00000 n 0000076740 00000 n 0000076955 00000 n 0000077302 00000 n 0000077359 00000 n 0000077380 00000 n 0000077726 00000 n 0000077938 00000 n 0000078186 00000 n 0000078430 00000 n 0000078507 00000 n 0000078587 00000 n 0000078823 00000 n 0000078900 00000 n 0000078980 00000 n 0000079191 00000 n 0000079565 00000 n 0000079615 00000 n 0000079923 00000 n 0000080350 00000 n 0000080775 00000 n 0000081137 00000 n 0000081174 00000 n 0000081623 00000 n 0000082078 00000 n 0000083307 00000 n 0000083443 00000 n 0000083964 00000 n 0000084487 00000 n 0000084760 00000 n 0000084874 00000 n 0000085149 00000 n 0000085244 00000 n 0000085509 00000 n 0000085782 00000 n 0000085881 00000 n 0000086093 00000 n 0000086366 00000 n 0000086465 00000 n 0000086677 00000 n 0000086950 00000 n 0000087049 00000 n 0000087261 00000 n 0000087535 00000 n 0000087634 00000 n 0000087846 00000 n 0000088121 00000 n 0000088220 00000 n 0000088432 00000 n 0000088707 00000 n 0000088806 00000 n 0000089018 00000 n 0000089293 00000 n 0000089392 00000 n 0000089604 00000 n 0000089703 00000 n 0000089915 00000 n 0000090205 00000 n 0000090426 00000 n 0000090644 00000 n 0000090962 00000 n 0000091019 00000 n 0000091387 00000 n 0000091493 00000 n 0000091735 00000 n 0000091834 00000 n 0000091936 00000 n 0000092175 00000 n 0000092274 00000 n 0000092376 00000 n 0000092685 00000 n 0000092801 00000 n 0000092920 00000 n 0000093134 00000 n 0000093437 00000 n 0000093553 00000 n 0000093672 00000 n 0000093886 00000 n 0000094182 00000 n 0000094298 00000 n 0000094417 00000 n 0000094631 00000 n 0000094926 00000 n 0000095042 00000 n 0000095161 00000 n 0000095375 00000 n 0000095670 00000 n 0000095786 00000 n 0000095905 00000 n 0000096119 00000 n 0000096420 00000 n 0000096536 00000 n 0000096655 00000 n 0000096869 00000 n 0000097196 00000 n 0000097312 00000 n 0000097575 00000 n 0000097694 00000 n 0000097804 00000 n 0000098018 00000 n 0000098354 00000 n 0000098619 00000 n 0000098834 00000 n 0000099123 00000 n 0000099433 00000 n 0000099532 00000 n 0000099634 00000 n 0000099876 00000 n 0000100216 00000 n 0000100484 00000 n 0000100700 00000 n 0000100990 00000 n 0000101286 00000 n 0000101554 00000 n 0000101770 00000 n 0000102060 00000 n 0000102369 00000 n 0000102634 00000 n 0000102848 00000 n 0000103135 00000 n 0000103447 00000 n 0000103713 00000 n 0000103929 00000 n 0000104217 00000 n 0000104525 00000 n 0000104789 00000 n 0000105005 00000 n 0000105292 00000 n 0000105630 00000 n 0000105978 00000 n 0000106204 00000 n 0000106431 00000 n 0000106654 00000 n 0000107023 00000 n 0000107044 00000 n 0000107067 00000 n 0000107407 00000 n 0000107623 00000 n 0000107886 00000 n 0000107963 00000 n 0000108043 00000 n 0000108294 00000 n 0000108371 00000 n 0000108451 00000 n 0000108679 00000 n 0000108928 00000 n 0000108996 00000 n 0000109212 00000 n 0000109425 00000 n 0000109736 00000 n 0000110145 00000 n 0000110166 00000 n 0000110514 00000 n 0000110825 00000 n 0000111176 00000 n 0000111511 00000 n 0000111859 00000 n 0000112062 00000 n 0000112373 00000 n 0000112456 00000 n 0000112882 00000 n 0000113180 00000 n 0000113263 00000 n 0000113535 00000 n 0000113635 00000 n 0000113899 00000 n 0000114197 00000 n 0000114297 00000 n 0000114561 00000 n 0000114859 00000 n 0000114959 00000 n 0000115222 00000 n 0000115521 00000 n 0000115633 00000 n 0000115897 00000 n 0000115997 00000 n 0000116261 00000 n 0000116486 00000 n 0000116549 00000 n 0000116814 00000 n 0000117080 00000 n 0000117336 00000 n 0000117614 00000 n 0000117895 00000 n trailer << /Size 328 /Root 3 0 R /Info 2 0 R >> startxref 118139 %%EOF PyPDF2-1.25.1/PyPDF2/000077500000000000000000000000001255324530700136165ustar00rootroot00000000000000PyPDF2-1.25.1/PyPDF2/__init__.py000066400000000000000000000003221255324530700157240ustar00rootroot00000000000000from .pdf import PdfFileReader, PdfFileWriter from .merger import PdfFileMerger from .pagerange import PageRange, parse_filename_page_ranges from ._version import __version__ __all__ = ["pdf", "PdfFileMerger"] PyPDF2-1.25.1/PyPDF2/_version.py000066400000000000000000000000271255324530700160130ustar00rootroot00000000000000__version__ = '1.25.1' PyPDF2-1.25.1/PyPDF2/filters.py000066400000000000000000000315571255324530700156530ustar00rootroot00000000000000# vim: sw=4:expandtab:foldmethod=marker # # Copyright (c) 2006, Mathieu Fenniak # All rights reserved. # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions are # met: # # * Redistributions of source code must retain the above copyright notice, # this list of conditions and the following disclaimer. # * Redistributions in binary form must reproduce the above copyright notice, # this list of conditions and the following disclaimer in the documentation # and/or other materials provided with the distribution. # * The name of the author may not be used to endorse or promote products # derived from this software without specific prior written permission. # # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" # AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE # ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE # LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR # CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF # SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS # INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN # CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) # ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE # POSSIBILITY OF SUCH DAMAGE. """ Implementation of stream filters for PDF. """ __author__ = "Mathieu Fenniak" __author_email__ = "biziqe@mathieu.fenniak.net" from .utils import PdfReadError, ord_, chr_ from sys import version_info if version_info < ( 3, 0 ): from cStringIO import StringIO else: from io import StringIO import struct try: import zlib def decompress(data): return zlib.decompress(data) def compress(data): return zlib.compress(data) except ImportError: # Unable to import zlib. Attempt to use the System.IO.Compression # library from the .NET framework. (IronPython only) import System from System import IO, Collections, Array def _string_to_bytearr(buf): retval = Array.CreateInstance(System.Byte, len(buf)) for i in range(len(buf)): retval[i] = ord(buf[i]) return retval def _bytearr_to_string(bytes): retval = "" for i in range(bytes.Length): retval += chr(bytes[i]) return retval def _read_bytes(stream): ms = IO.MemoryStream() buf = Array.CreateInstance(System.Byte, 2048) while True: bytes = stream.Read(buf, 0, buf.Length) if bytes == 0: break else: ms.Write(buf, 0, bytes) retval = ms.ToArray() ms.Close() return retval def decompress(data): bytes = _string_to_bytearr(data) ms = IO.MemoryStream() ms.Write(bytes, 0, bytes.Length) ms.Position = 0 # fseek 0 gz = IO.Compression.DeflateStream(ms, IO.Compression.CompressionMode.Decompress) bytes = _read_bytes(gz) retval = _bytearr_to_string(bytes) gz.Close() return retval def compress(data): bytes = _string_to_bytearr(data) ms = IO.MemoryStream() gz = IO.Compression.DeflateStream(ms, IO.Compression.CompressionMode.Compress, True) gz.Write(bytes, 0, bytes.Length) gz.Close() ms.Position = 0 # fseek 0 bytes = ms.ToArray() retval = _bytearr_to_string(bytes) ms.Close() return retval class FlateDecode(object): def decode(data, decodeParms): data = decompress(data) predictor = 1 if decodeParms: try: predictor = decodeParms.get("/Predictor", 1) except AttributeError: pass # usually an array with a null object was read # predictor 1 == no predictor if predictor != 1: columns = decodeParms["/Columns"] # PNG prediction: if predictor >= 10 and predictor <= 15: output = StringIO() # PNG prediction can vary from row to row rowlength = columns + 1 assert len(data) % rowlength == 0 prev_rowdata = (0,) * rowlength for row in range(len(data) // rowlength): rowdata = [ord_(x) for x in data[(row*rowlength):((row+1)*rowlength)]] filterByte = rowdata[0] if filterByte == 0: pass elif filterByte == 1: for i in range(2, rowlength): rowdata[i] = (rowdata[i] + rowdata[i-1]) % 256 elif filterByte == 2: for i in range(1, rowlength): rowdata[i] = (rowdata[i] + prev_rowdata[i]) % 256 else: # unsupported PNG filter raise PdfReadError("Unsupported PNG filter %r" % filterByte) prev_rowdata = rowdata output.write(''.join([chr(x) for x in rowdata[1:]])) data = output.getvalue() else: # unsupported predictor raise PdfReadError("Unsupported flatedecode predictor %r" % predictor) return data decode = staticmethod(decode) def encode(data): return compress(data) encode = staticmethod(encode) class ASCIIHexDecode(object): def decode(data, decodeParms=None): retval = "" char = "" x = 0 while True: c = data[x] if c == ">": break elif c.isspace(): x += 1 continue char += c if len(char) == 2: retval += chr(int(char, base=16)) char = "" x += 1 assert char == "" return retval decode = staticmethod(decode) class LZWDecode(object): """Taken from: http://www.java2s.com/Open-Source/Java-Document/PDF/PDF-Renderer/com/sun/pdfview/decode/LZWDecode.java.htm """ class decoder(object): def __init__(self, data): self.STOP=257 self.CLEARDICT=256 self.data=data self.bytepos=0 self.bitpos=0 self.dict=[""]*4096 for i in range(256): self.dict[i]=chr(i) self.resetDict() def resetDict(self): self.dictlen=258 self.bitspercode=9 def nextCode(self): fillbits=self.bitspercode value=0 while fillbits>0 : if self.bytepos >= len(self.data): return -1 nextbits=ord(self.data[self.bytepos]) bitsfromhere=8-self.bitpos if bitsfromhere>fillbits: bitsfromhere=fillbits value |= (((nextbits >> (8-self.bitpos-bitsfromhere)) & (0xff >> (8-bitsfromhere))) << (fillbits-bitsfromhere)) fillbits -= bitsfromhere self.bitpos += bitsfromhere if self.bitpos >=8: self.bitpos=0 self.bytepos = self.bytepos+1 return value def decode(self): """ algorithm derived from: http://www.rasip.fer.hr/research/compress/algorithms/fund/lz/lzw.html and the PDFReference """ cW = self.CLEARDICT; baos="" while True: pW = cW; cW = self.nextCode(); if cW == -1: raise PdfReadError("Missed the stop code in LZWDecode!") if cW == self.STOP: break; elif cW == self.CLEARDICT: self.resetDict(); elif pW == self.CLEARDICT: baos+=self.dict[cW] else: if cW < self.dictlen: baos += self.dict[cW] p=self.dict[pW]+self.dict[cW][0] self.dict[self.dictlen]=p self.dictlen+=1 else: p=self.dict[pW]+self.dict[pW][0] baos+=p self.dict[self.dictlen] = p; self.dictlen+=1 if (self.dictlen >= (1 << self.bitspercode) - 1 and self.bitspercode < 12): self.bitspercode+=1 return baos @staticmethod def decode(data,decodeParams=None): return LZWDecode.decoder(data).decode() class ASCII85Decode(object): def decode(data, decodeParms=None): if version_info < ( 3, 0 ): retval = "" group = [] x = 0 hitEod = False # remove all whitespace from data data = [y for y in data if not (y in ' \n\r\t')] while not hitEod: c = data[x] if len(retval) == 0 and c == "<" and data[x+1] == "~": x += 2 continue #elif c.isspace(): # x += 1 # continue elif c == 'z': assert len(group) == 0 retval += '\x00\x00\x00\x00' x += 1 continue elif c == "~" and data[x+1] == ">": if len(group) != 0: # cannot have a final group of just 1 char assert len(group) > 1 cnt = len(group) - 1 group += [ 85, 85, 85 ] hitEod = cnt else: break else: c = ord(c) - 33 assert c >= 0 and c < 85 group += [ c ] if len(group) >= 5: b = group[0] * (85**4) + \ group[1] * (85**3) + \ group[2] * (85**2) + \ group[3] * 85 + \ group[4] assert b < (2**32 - 1) c4 = chr((b >> 0) % 256) c3 = chr((b >> 8) % 256) c2 = chr((b >> 16) % 256) c1 = chr(b >> 24) retval += (c1 + c2 + c3 + c4) if hitEod: retval = retval[:-4+hitEod] group = [] x += 1 return retval else: if isinstance(data, str): data = data.encode('ascii') n = b = 0 out = bytearray() for c in data: if ord('!') <= c and c <= ord('u'): n += 1 b = b*85+(c-33) if n == 5: out += struct.pack(b'>L',b) n = b = 0 elif c == ord('z'): assert n == 0 out += b'\0\0\0\0' elif c == ord('~'): if n: for _ in range(5-n): b = b*85+84 out += struct.pack(b'>L',b)[:n-1] break return bytes(out) decode = staticmethod(decode) def decodeStreamData(stream): from .generic import NameObject filters = stream.get("/Filter", ()) if len(filters) and not isinstance(filters[0], NameObject): # we have a single filter instance filters = (filters,) data = stream._data # If there is not data to decode we should not try to decode the data. if data: for filterType in filters: if filterType == "/FlateDecode" or filterType == "/Fl": data = FlateDecode.decode(data, stream.get("/DecodeParms")) elif filterType == "/ASCIIHexDecode" or filterType == "/AHx": data = ASCIIHexDecode.decode(data) elif filterType == "/LZWDecode" or filterType == "/LZW": data = LZWDecode.decode(data, stream.get("/DecodeParms")) elif filterType == "/ASCII85Decode" or filterType == "/A85": data = ASCII85Decode.decode(data) elif filterType == "/Crypt": decodeParams = stream.get("/DecodeParams", {}) if "/Name" not in decodeParams and "/Type" not in decodeParams: pass else: raise NotImplementedError("/Crypt filter with /Name or /Type not supported yet") else: # unsupported filter raise NotImplementedError("unsupported filter %s" % filterType) return data PyPDF2-1.25.1/PyPDF2/generic.py000066400000000000000000001301111255324530700156010ustar00rootroot00000000000000# vim: sw=4:expandtab:foldmethod=marker # # Copyright (c) 2006, Mathieu Fenniak # All rights reserved. # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions are # met: # # * Redistributions of source code must retain the above copyright notice, # this list of conditions and the following disclaimer. # * Redistributions in binary form must reproduce the above copyright notice, # this list of conditions and the following disclaimer in the documentation # and/or other materials provided with the distribution. # * The name of the author may not be used to endorse or promote products # derived from this software without specific prior written permission. # # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" # AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE # ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE # LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR # CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF # SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS # INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN # CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) # ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE # POSSIBILITY OF SUCH DAMAGE. """ Implementation of generic PDF objects (dictionary, number, string, and so on) """ __author__ = "Mathieu Fenniak" __author_email__ = "biziqe@mathieu.fenniak.net" import re from .utils import readNonWhitespace, RC4_encrypt, skipOverComment from .utils import b_, u_, chr_, ord_ from .utils import PdfStreamError import warnings from . import filters from . import utils import decimal import codecs import sys #import debugging ObjectPrefix = b_('/<[tf(n%') NumberSigns = b_('+-') IndirectPattern = re.compile(b_(r"(\d+)\s+(\d+)\s+R[^a-zA-Z]")) def readObject(stream, pdf): tok = stream.read(1) stream.seek(-1, 1) # reset to start idx = ObjectPrefix.find(tok) if idx == 0: # name object return NameObject.readFromStream(stream, pdf) elif idx == 1: # hexadecimal string OR dictionary peek = stream.read(2) stream.seek(-2, 1) # reset to start if peek == b_('<<'): return DictionaryObject.readFromStream(stream, pdf) else: return readHexStringFromStream(stream) elif idx == 2: # array object return ArrayObject.readFromStream(stream, pdf) elif idx == 3 or idx == 4: # boolean object return BooleanObject.readFromStream(stream) elif idx == 5: # string object return readStringFromStream(stream) elif idx == 6: # null object return NullObject.readFromStream(stream) elif idx == 7: # comment while tok not in (b_('\r'), b_('\n')): tok = stream.read(1) tok = readNonWhitespace(stream) stream.seek(-1, 1) return readObject(stream, pdf) else: # number object OR indirect reference if tok in NumberSigns: # number return NumberObject.readFromStream(stream) peek = stream.read(20) stream.seek(-len(peek), 1) # reset to start if IndirectPattern.match(peek) != None: return IndirectObject.readFromStream(stream, pdf) else: return NumberObject.readFromStream(stream) class PdfObject(object): def getObject(self): """Resolves indirect references.""" return self class NullObject(PdfObject): def writeToStream(self, stream, encryption_key): stream.write(b_("null")) def readFromStream(stream): nulltxt = stream.read(4) if nulltxt != b_("null"): raise utils.PdfReadError("Could not read Null object") return NullObject() readFromStream = staticmethod(readFromStream) class BooleanObject(PdfObject): def __init__(self, value): self.value = value def writeToStream(self, stream, encryption_key): if self.value: stream.write(b_("true")) else: stream.write(b_("false")) def readFromStream(stream): word = stream.read(4) if word == b_("true"): return BooleanObject(True) elif word == b_("fals"): stream.read(1) return BooleanObject(False) else: raise utils.PdfReadError('Could not read Boolean object') readFromStream = staticmethod(readFromStream) class ArrayObject(list, PdfObject): def writeToStream(self, stream, encryption_key): stream.write(b_("[")) for data in self: stream.write(b_(" ")) data.writeToStream(stream, encryption_key) stream.write(b_(" ]")) def readFromStream(stream, pdf): arr = ArrayObject() tmp = stream.read(1) if tmp != b_("["): raise utils.PdfReadError("Could not read array") while True: # skip leading whitespace tok = stream.read(1) while tok.isspace(): tok = stream.read(1) stream.seek(-1, 1) # check for array ending peekahead = stream.read(1) if peekahead == b_("]"): break stream.seek(-1, 1) # read and append obj arr.append(readObject(stream, pdf)) return arr readFromStream = staticmethod(readFromStream) class IndirectObject(PdfObject): def __init__(self, idnum, generation, pdf): self.idnum = idnum self.generation = generation self.pdf = pdf def getObject(self): return self.pdf.getObject(self).getObject() def __repr__(self): return "IndirectObject(%r, %r)" % (self.idnum, self.generation) def __eq__(self, other): return ( other != None and isinstance(other, IndirectObject) and self.idnum == other.idnum and self.generation == other.generation and self.pdf is other.pdf ) def __ne__(self, other): return not self.__eq__(other) def writeToStream(self, stream, encryption_key): stream.write(b_("%s %s R" % (self.idnum, self.generation))) def readFromStream(stream, pdf): idnum = b_("") while True: tok = stream.read(1) if not tok: # stream has truncated prematurely raise PdfStreamError("Stream has ended unexpectedly") if tok.isspace(): break idnum += tok generation = b_("") while True: tok = stream.read(1) if not tok: # stream has truncated prematurely raise PdfStreamError("Stream has ended unexpectedly") if tok.isspace(): if not generation: continue break generation += tok r = readNonWhitespace(stream) if r != b_("R"): raise utils.PdfReadError("Error reading indirect object reference at byte %s" % utils.hexStr(stream.tell())) return IndirectObject(int(idnum), int(generation), pdf) readFromStream = staticmethod(readFromStream) class FloatObject(decimal.Decimal, PdfObject): def __new__(cls, value="0", context=None): try: return decimal.Decimal.__new__(cls, utils.str_(value), context) except: return decimal.Decimal.__new__(cls, str(value)) def __repr__(self): if self == self.to_integral(): return str(self.quantize(decimal.Decimal(1))) else: # XXX: this adds useless extraneous zeros. return "%.5f" % self def as_numeric(self): return float(b_(repr(self))) def writeToStream(self, stream, encryption_key): stream.write(b_(repr(self))) class NumberObject(int, PdfObject): NumberPattern = re.compile(b_('[^+-.0-9]')) ByteDot = b_(".") def __new__(cls, value): val = int(value) try: return int.__new__(cls, val) except OverflowError: return int.__new__(cls, 0) def as_numeric(self): return int(b_(repr(self))) def writeToStream(self, stream, encryption_key): stream.write(b_(repr(self))) def readFromStream(stream): num = utils.readUntilRegex(stream, NumberObject.NumberPattern) if num.find(NumberObject.ByteDot) != -1: return FloatObject(num) else: return NumberObject(num) readFromStream = staticmethod(readFromStream) ## # Given a string (either a "str" or "unicode"), create a ByteStringObject or a # TextStringObject to represent the string. def createStringObject(string): if isinstance(string, utils.string_type): return TextStringObject(string) elif isinstance(string, utils.bytes_type): try: if string.startswith(codecs.BOM_UTF16_BE): retval = TextStringObject(string.decode("utf-16")) retval.autodetect_utf16 = True return retval else: # This is probably a big performance hit here, but we need to # convert string objects into the text/unicode-aware version if # possible... and the only way to check if that's possible is # to try. Some strings are strings, some are just byte arrays. retval = TextStringObject(decode_pdfdocencoding(string)) retval.autodetect_pdfdocencoding = True return retval except UnicodeDecodeError: return ByteStringObject(string) else: raise TypeError("createStringObject should have str or unicode arg") def readHexStringFromStream(stream): stream.read(1) txt = "" x = b_("") while True: tok = readNonWhitespace(stream) if not tok: # stream has truncated prematurely raise PdfStreamError("Stream has ended unexpectedly") if tok == b_(">"): break x += tok if len(x) == 2: txt += chr(int(x, base=16)) x = b_("") if len(x) == 1: x += b_("0") if len(x) == 2: txt += chr(int(x, base=16)) return createStringObject(b_(txt)) def readStringFromStream(stream): tok = stream.read(1) parens = 1 txt = b_("") while True: tok = stream.read(1) if not tok: # stream has truncated prematurely raise PdfStreamError("Stream has ended unexpectedly") if tok == b_("("): parens += 1 elif tok == b_(")"): parens -= 1 if parens == 0: break elif tok == b_("\\"): tok = stream.read(1) if tok == b_("n"): tok = b_("\n") elif tok == b_("r"): tok = b_("\r") elif tok == b_("t"): tok = b_("\t") elif tok == b_("b"): tok = b_("\b") elif tok == b_("f"): tok = b_("\f") elif tok == b_("c"): tok = b_("\c") elif tok == b_("("): tok = b_("(") elif tok == b_(")"): tok = b_(")") elif tok == b_("/"): tok = b_("/") elif tok == b_("\\"): tok = b_("\\") elif tok in (b_(" "), b_("/"), b_("%"), b_("<"), b_(">"), b_("["), b_("]"), b_("#"), b_("_"), b_("&"), b_('$')): # odd/unnessecary escape sequences we have encountered tok = b_(tok) elif tok.isdigit(): # "The number ddd may consist of one, two, or three # octal digits; high-order overflow shall be ignored. # Three octal digits shall be used, with leading zeros # as needed, if the next character of the string is also # a digit." (PDF reference 7.3.4.2, p 16) for i in range(2): ntok = stream.read(1) if ntok.isdigit(): tok += ntok else: break tok = b_(chr(int(tok, base=8))) elif tok in b_("\n\r"): # This case is hit when a backslash followed by a line # break occurs. If it's a multi-char EOL, consume the # second character: tok = stream.read(1) if not tok in b_("\n\r"): stream.seek(-1, 1) # Then don't add anything to the actual string, since this # line break was escaped: tok = b_('') else: raise utils.PdfReadError(r"Unexpected escaped string: %s" % tok) txt += tok return createStringObject(txt) ## # Represents a string object where the text encoding could not be determined. # This occurs quite often, as the PDF spec doesn't provide an alternate way to # represent strings -- for example, the encryption data stored in files (like # /O) is clearly not text, but is still stored in a "String" object. class ByteStringObject(utils.bytes_type, PdfObject): ## # For compatibility with TextStringObject.original_bytes. This method # returns self. original_bytes = property(lambda self: self) def writeToStream(self, stream, encryption_key): bytearr = self if encryption_key: bytearr = RC4_encrypt(encryption_key, bytearr) stream.write(b_("<")) stream.write(utils.hexencode(bytearr)) stream.write(b_(">")) ## # Represents a string object that has been decoded into a real unicode string. # If read from a PDF document, this string appeared to match the # PDFDocEncoding, or contained a UTF-16BE BOM mark to cause UTF-16 decoding to # occur. class TextStringObject(utils.string_type, PdfObject): autodetect_pdfdocencoding = False autodetect_utf16 = False ## # It is occasionally possible that a text string object gets created where # a byte string object was expected due to the autodetection mechanism -- # if that occurs, this "original_bytes" property can be used to # back-calculate what the original encoded bytes were. original_bytes = property(lambda self: self.get_original_bytes()) def get_original_bytes(self): # We're a text string object, but the library is trying to get our raw # bytes. This can happen if we auto-detected this string as text, but # we were wrong. It's pretty common. Return the original bytes that # would have been used to create this object, based upon the autodetect # method. if self.autodetect_utf16: return codecs.BOM_UTF16_BE + self.encode("utf-16be") elif self.autodetect_pdfdocencoding: return encode_pdfdocencoding(self) else: raise Exception("no information about original bytes") def writeToStream(self, stream, encryption_key): # Try to write the string out as a PDFDocEncoding encoded string. It's # nicer to look at in the PDF file. Sadly, we take a performance hit # here for trying... try: bytearr = encode_pdfdocencoding(self) except UnicodeEncodeError: bytearr = codecs.BOM_UTF16_BE + self.encode("utf-16be") if encryption_key: bytearr = RC4_encrypt(encryption_key, bytearr) obj = ByteStringObject(bytearr) obj.writeToStream(stream, None) else: stream.write(b_("(")) for c in bytearr: if not chr_(c).isalnum() and c != b_(' '): stream.write(b_("\\%03o" % ord_(c))) else: stream.write(b_(chr_(c))) stream.write(b_(")")) class NameObject(str, PdfObject): delimiterPattern = re.compile(b_(r"\s+|[\(\)<>\[\]{}/%]")) surfix = b_("/") def writeToStream(self, stream, encryption_key): stream.write(b_(self)) def readFromStream(stream, pdf): debug = False if debug: print((stream.tell())) name = stream.read(1) if name != NameObject.surfix: raise utils.PdfReadError("name read error") name += utils.readUntilRegex(stream, NameObject.delimiterPattern, ignore_eof=True) if debug: print(name) try: return NameObject(name.decode('utf-8')) except (UnicodeEncodeError, UnicodeDecodeError) as e: # Name objects should represent irregular characters # with a '#' followed by the symbol's hex number if not pdf.strict: warnings.warn("Illegal character in Name Object", utils.PdfReadWarning) return NameObject(name) else: raise utils.PdfReadError("Illegal character in Name Object") readFromStream = staticmethod(readFromStream) class DictionaryObject(dict, PdfObject): def raw_get(self, key): return dict.__getitem__(self, key) def __setitem__(self, key, value): if not isinstance(key, PdfObject): raise ValueError("key must be PdfObject") if not isinstance(value, PdfObject): raise ValueError("value must be PdfObject") return dict.__setitem__(self, key, value) def setdefault(self, key, value=None): if not isinstance(key, PdfObject): raise ValueError("key must be PdfObject") if not isinstance(value, PdfObject): raise ValueError("value must be PdfObject") return dict.setdefault(self, key, value) def __getitem__(self, key): return dict.__getitem__(self, key).getObject() ## # Retrieves XMP (Extensible Metadata Platform) data relevant to the # this object, if available. #

# Stability: Added in v1.12, will exist for all future v1.x releases. # @return Returns a {@link #xmp.XmpInformation XmlInformation} instance # that can be used to access XMP metadata from the document. Can also # return None if no metadata was found on the document root. def getXmpMetadata(self): metadata = self.get("/Metadata", None) if metadata == None: return None metadata = metadata.getObject() from . import xmp if not isinstance(metadata, xmp.XmpInformation): metadata = xmp.XmpInformation(metadata) self[NameObject("/Metadata")] = metadata return metadata ## # Read-only property that accesses the {@link # #DictionaryObject.getXmpData getXmpData} function. #

# Stability: Added in v1.12, will exist for all future v1.x releases. xmpMetadata = property(lambda self: self.getXmpMetadata(), None, None) def writeToStream(self, stream, encryption_key): stream.write(b_("<<\n")) for key, value in list(self.items()): key.writeToStream(stream, encryption_key) stream.write(b_(" ")) value.writeToStream(stream, encryption_key) stream.write(b_("\n")) stream.write(b_(">>")) def readFromStream(stream, pdf): debug = False tmp = stream.read(2) if tmp != b_("<<"): raise utils.PdfReadError("Dictionary read error at byte %s: stream must begin with '<<'" % utils.hexStr(stream.tell())) data = {} while True: tok = readNonWhitespace(stream) if tok == b_('\x00'): continue elif tok == b_('%'): stream.seek(-1, 1) skipOverComment(stream) continue if not tok: # stream has truncated prematurely raise PdfStreamError("Stream has ended unexpectedly") if debug: print(("Tok:", tok)) if tok == b_(">"): stream.read(1) break stream.seek(-1, 1) key = readObject(stream, pdf) tok = readNonWhitespace(stream) stream.seek(-1, 1) value = readObject(stream, pdf) if not data.get(key): data[key] = value elif pdf.strict: # multiple definitions of key not permitted raise utils.PdfReadError("Multiple definitions in dictionary at byte %s for key %s" \ % (utils.hexStr(stream.tell()), key)) else: warnings.warn("Multiple definitions in dictionary at byte %s for key %s" \ % (utils.hexStr(stream.tell()), key), utils.PdfReadWarning) pos = stream.tell() s = readNonWhitespace(stream) if s == b_('s') and stream.read(5) == b_('tream'): eol = stream.read(1) # odd PDF file output has spaces after 'stream' keyword but before EOL. # patch provided by Danial Sandler while eol == b_(' '): eol = stream.read(1) assert eol in (b_("\n"), b_("\r")) if eol == b_("\r"): # read \n after if stream.read(1) != b_('\n'): stream.seek(-1, 1) # this is a stream object, not a dictionary assert "/Length" in data length = data["/Length"] if debug: print(data) if isinstance(length, IndirectObject): t = stream.tell() length = pdf.getObject(length) stream.seek(t, 0) data["__streamdata__"] = stream.read(length) if debug: print("here") #if debug: print(binascii.hexlify(data["__streamdata__"])) e = readNonWhitespace(stream) ndstream = stream.read(8) if (e + ndstream) != b_("endstream"): # (sigh) - the odd PDF file has a length that is too long, so # we need to read backwards to find the "endstream" ending. # ReportLab (unknown version) generates files with this bug, # and Python users into PDF files tend to be our audience. # we need to do this to correct the streamdata and chop off # an extra character. pos = stream.tell() stream.seek(-10, 1) end = stream.read(9) if end == b_("endstream"): # we found it by looking back one character further. data["__streamdata__"] = data["__streamdata__"][:-1] else: if debug: print(("E", e, ndstream, debugging.toHex(end))) stream.seek(pos, 0) raise utils.PdfReadError("Unable to find 'endstream' marker after stream at byte %s." % utils.hexStr(stream.tell())) else: stream.seek(pos, 0) if "__streamdata__" in data: return StreamObject.initializeFromDictionary(data) else: retval = DictionaryObject() retval.update(data) return retval readFromStream = staticmethod(readFromStream) class TreeObject(DictionaryObject): def __init__(self): DictionaryObject.__init__(self) def hasChildren(self): return '/First' in self def __iter__(self): return self.children() def children(self): if not self.hasChildren(): raise StopIteration child = self['/First'] while True: yield child if child == self['/Last']: raise StopIteration child = child['/Next'] def addChild(self, child, pdf): childObj = child.getObject() child = pdf.getReference(childObj) assert isinstance(child, IndirectObject) if '/First' not in self: self[NameObject('/First')] = child self[NameObject('/Count')] = NumberObject(0) prev = None else: prev = self['/Last'] self[NameObject('/Last')] = child self[NameObject('/Count')] = NumberObject(self[NameObject('/Count')] + 1) if prev: prevRef = pdf.getReference(prev) assert isinstance(prevRef, IndirectObject) childObj[NameObject('/Prev')] = prevRef prev[NameObject('/Next')] = child parentRef = pdf.getReference(self) assert isinstance(parentRef, IndirectObject) childObj[NameObject('/Parent')] = parentRef def removeChild(self, child): childObj = child.getObject() if NameObject('/Parent') not in childObj: raise ValueError("Removed child does not appear to be a tree item") elif childObj[NameObject('/Parent')] != self: raise ValueError("Removed child is not a member of this tree") found = False prevRef = None prev = None curRef = self[NameObject('/First')] cur = curRef.getObject() lastRef = self[NameObject('/Last')] last = lastRef.getObject() while cur != None: if cur == childObj: if prev == None: if NameObject('/Next') in cur: # Removing first tree node nextRef = cur[NameObject('/Next')] next = nextRef.getObject() del next[NameObject('/Prev')] self[NameObject('/First')] = nextRef self[NameObject('/Count')] = self[NameObject('/Count')] - 1 else: # Removing only tree node assert self[NameObject('/Count')] == 1 del self[NameObject('/Count')] del self[NameObject('/First')] if NameObject('/Last') in self: del self[NameObject('/Last')] else: if NameObject('/Next') in cur: # Removing middle tree node nextRef = cur[NameObject('/Next')] next = nextRef.getObject() next[NameObject('/Prev')] = prevRef prev[NameObject('/Next')] = nextRef self[NameObject('/Count')] = self[NameObject('/Count')] - 1 else: # Removing last tree node assert cur == last del prev[NameObject('/Next')] self[NameObject('/Last')] = prevRef self[NameObject('/Count')] = self[NameObject('/Count')] - 1 found = True break prevRef = curRef prev = cur if NameObject('/Next') in cur: curRef = cur[NameObject('/Next')] cur = curRef.getObject() else: curRef = None cur = None if not found: raise ValueError("Removal couldn't find item in tree") del childObj[NameObject('/Parent')] if NameObject('/Next') in childObj: del childObj[NameObject('/Next')] if NameObject('/Prev') in childObj: del childObj[NameObject('/Prev')] def emptyTree(self): for child in self: childObj = child.getObject() del childObj[NameObject('/Parent')] if NameObject('/Next') in childObj: del childObj[NameObject('/Next')] if NameObject('/Prev') in childObj: del childObj[NameObject('/Prev')] if NameObject('/Count') in self: del self[NameObject('/Count')] if NameObject('/First') in self: del self[NameObject('/First')] if NameObject('/Last') in self: del self[NameObject('/Last')] class StreamObject(DictionaryObject): def __init__(self): self._data = None self.decodedSelf = None def writeToStream(self, stream, encryption_key): self[NameObject("/Length")] = NumberObject(len(self._data)) DictionaryObject.writeToStream(self, stream, encryption_key) del self["/Length"] stream.write(b_("\nstream\n")) data = self._data if encryption_key: data = RC4_encrypt(encryption_key, data) stream.write(data) stream.write(b_("\nendstream")) def initializeFromDictionary(data): if "/Filter" in data: retval = EncodedStreamObject() else: retval = DecodedStreamObject() retval._data = data["__streamdata__"] del data["__streamdata__"] del data["/Length"] retval.update(data) return retval initializeFromDictionary = staticmethod(initializeFromDictionary) def flateEncode(self): if "/Filter" in self: f = self["/Filter"] if isinstance(f, ArrayObject): f.insert(0, NameObject("/FlateDecode")) else: newf = ArrayObject() newf.append(NameObject("/FlateDecode")) newf.append(f) f = newf else: f = NameObject("/FlateDecode") retval = EncodedStreamObject() retval[NameObject("/Filter")] = f retval._data = filters.FlateDecode.encode(self._data) return retval class DecodedStreamObject(StreamObject): def getData(self): return self._data def setData(self, data): self._data = data class EncodedStreamObject(StreamObject): def __init__(self): self.decodedSelf = None def getData(self): if self.decodedSelf: # cached version of decoded object return self.decodedSelf.getData() else: # create decoded object decoded = DecodedStreamObject() decoded._data = filters.decodeStreamData(self) for key, value in list(self.items()): if not key in ("/Length", "/Filter", "/DecodeParms"): decoded[key] = value self.decodedSelf = decoded return decoded._data def setData(self, data): raise utils.PdfReadError("Creating EncodedStreamObject is not currently supported") class RectangleObject(ArrayObject): """ This class is used to represent *page boxes* in PyPDF2. These boxes include: * :attr:`artBox ` * :attr:`bleedBox ` * :attr:`cropBox ` * :attr:`mediaBox ` * :attr:`trimBox ` """ def __init__(self, arr): # must have four points assert len(arr) == 4 # automatically convert arr[x] into NumberObject(arr[x]) if necessary ArrayObject.__init__(self, [self.ensureIsNumber(x) for x in arr]) def ensureIsNumber(self, value): if not isinstance(value, (NumberObject, FloatObject)): value = FloatObject(value) return value def __repr__(self): return "RectangleObject(%s)" % repr(list(self)) def getLowerLeft_x(self): return self[0] def getLowerLeft_y(self): return self[1] def getUpperRight_x(self): return self[2] def getUpperRight_y(self): return self[3] def getUpperLeft_x(self): return self.getLowerLeft_x() def getUpperLeft_y(self): return self.getUpperRight_y() def getLowerRight_x(self): return self.getUpperRight_x() def getLowerRight_y(self): return self.getLowerLeft_y() def getLowerLeft(self): return self.getLowerLeft_x(), self.getLowerLeft_y() def getLowerRight(self): return self.getLowerRight_x(), self.getLowerRight_y() def getUpperLeft(self): return self.getUpperLeft_x(), self.getUpperLeft_y() def getUpperRight(self): return self.getUpperRight_x(), self.getUpperRight_y() def setLowerLeft(self, value): self[0], self[1] = [self.ensureIsNumber(x) for x in value] def setLowerRight(self, value): self[2], self[1] = [self.ensureIsNumber(x) for x in value] def setUpperLeft(self, value): self[0], self[3] = [self.ensureIsNumber(x) for x in value] def setUpperRight(self, value): self[2], self[3] = [self.ensureIsNumber(x) for x in value] def getWidth(self): return self.getUpperRight_x() - self.getLowerLeft_x() def getHeight(self): return self.getUpperRight_y() - self.getLowerLeft_y() lowerLeft = property(getLowerLeft, setLowerLeft, None, None) """ Property to read and modify the lower left coordinate of this box in (x,y) form. """ lowerRight = property(getLowerRight, setLowerRight, None, None) """ Property to read and modify the lower right coordinate of this box in (x,y) form. """ upperLeft = property(getUpperLeft, setUpperLeft, None, None) """ Property to read and modify the upper left coordinate of this box in (x,y) form. """ upperRight = property(getUpperRight, setUpperRight, None, None) """ Property to read and modify the upper right coordinate of this box in (x,y) form. """ class Field(TreeObject): """ A class representing a field dictionary. This class is accessed through :meth:`getFields()` """ def __init__(self, data): DictionaryObject.__init__(self) attributes = ("/FT", "/Parent", "/Kids", "/T", "/TU", "/TM", "/Ff", "/V", "/DV", "/AA") for attr in attributes: try: self[NameObject(attr)] = data[attr] except KeyError: pass fieldType = property(lambda self: self.get("/FT")) """ Read-only property accessing the type of this field. """ parent = property(lambda self: self.get("/Parent")) """ Read-only property accessing the parent of this field. """ kids = property(lambda self: self.get("/Kids")) """ Read-only property accessing the kids of this field. """ name = property(lambda self: self.get("/T")) """ Read-only property accessing the name of this field. """ altName = property(lambda self: self.get("/TU")) """ Read-only property accessing the alternate name of this field. """ mappingName = property(lambda self: self.get("/TM")) """ Read-only property accessing the mapping name of this field. This name is used by PyPDF2 as a key in the dictionary returned by :meth:`getFields()` """ flags = property(lambda self: self.get("/Ff")) """ Read-only property accessing the field flags, specifying various characteristics of the field (see Table 8.70 of the PDF 1.7 reference). """ value = property(lambda self: self.get("/V")) """ Read-only property accessing the value of this field. Format varies based on field type. """ defaultValue = property(lambda self: self.get("/DV")) """ Read-only property accessing the default value of this field. """ additionalActions = property(lambda self: self.get("/AA")) """ Read-only property accessing the additional actions dictionary. This dictionary defines the field's behavior in response to trigger events. See Section 8.5.2 of the PDF 1.7 reference. """ class Destination(TreeObject): """ A class representing a destination within a PDF file. See section 8.2.1 of the PDF 1.6 reference. :param str title: Title of this destination. :param int page: Page number of this destination. :param str typ: How the destination is displayed. :param args: Additional arguments may be necessary depending on the type. :raises PdfReadError: If destination type is invalid. Valid ``typ`` arguments (see PDF spec for details): /Fit No additional arguments /XYZ [left] [top] [zoomFactor] /FitH [top] /FitV [left] /FitR [left] [bottom] [right] [top] /FitB No additional arguments /FitBH [top] /FitBV [left] """ def __init__(self, title, page, typ, *args): DictionaryObject.__init__(self) self[NameObject("/Title")] = title self[NameObject("/Page")] = page self[NameObject("/Type")] = typ # from table 8.2 of the PDF 1.7 reference. if typ == "/XYZ": (self[NameObject("/Left")], self[NameObject("/Top")], self[NameObject("/Zoom")]) = args elif typ == "/FitR": (self[NameObject("/Left")], self[NameObject("/Bottom")], self[NameObject("/Right")], self[NameObject("/Top")]) = args elif typ in ["/FitH", "/FitBH"]: self[NameObject("/Top")], = args elif typ in ["/FitV", "/FitBV"]: self[NameObject("/Left")], = args elif typ in ["/Fit", "/FitB"]: pass else: raise utils.PdfReadError("Unknown Destination Type: %r" % typ) def getDestArray(self): return ArrayObject([self.raw_get('/Page'), self['/Type']] + [self[x] for x in ['/Left', '/Bottom', '/Right', '/Top', '/Zoom'] if x in self]) def writeToStream(self, stream, encryption_key): stream.write(b_("<<\n")) key = NameObject('/D') key.writeToStream(stream, encryption_key) stream.write(b_(" ")) value = self.getDestArray() value.writeToStream(stream, encryption_key) key = NameObject("/S") key.writeToStream(stream, encryption_key) stream.write(b_(" ")) value = NameObject("/GoTo") value.writeToStream(stream, encryption_key) stream.write(b_("\n")) stream.write(b_(">>")) title = property(lambda self: self.get("/Title")) """ Read-only property accessing the destination title. :rtype: str """ page = property(lambda self: self.get("/Page")) """ Read-only property accessing the destination page number. :rtype: int """ typ = property(lambda self: self.get("/Type")) """ Read-only property accessing the destination type. :rtype: str """ zoom = property(lambda self: self.get("/Zoom", None)) """ Read-only property accessing the zoom factor. :rtype: int, or ``None`` if not available. """ left = property(lambda self: self.get("/Left", None)) """ Read-only property accessing the left horizontal coordinate. :rtype: int, or ``None`` if not available. """ right = property(lambda self: self.get("/Right", None)) """ Read-only property accessing the right horizontal coordinate. :rtype: int, or ``None`` if not available. """ top = property(lambda self: self.get("/Top", None)) """ Read-only property accessing the top vertical coordinate. :rtype: int, or ``None`` if not available. """ bottom = property(lambda self: self.get("/Bottom", None)) """ Read-only property accessing the bottom vertical coordinate. :rtype: int, or ``None`` if not available. """ class Bookmark(Destination): def writeToStream(self, stream, encryption_key): stream.write(b_("<<\n")) for key in [NameObject(x) for x in ['/Title', '/Parent', '/First', '/Last', '/Next', '/Prev'] if x in self]: key.writeToStream(stream, encryption_key) stream.write(b_(" ")) value = self.raw_get(key) value.writeToStream(stream, encryption_key) stream.write(b_("\n")) key = NameObject('/Dest') key.writeToStream(stream, encryption_key) stream.write(b_(" ")) value = self.getDestArray() value.writeToStream(stream, encryption_key) stream.write(b_("\n")) stream.write(b_(">>")) def encode_pdfdocencoding(unicode_string): retval = b_('') for c in unicode_string: try: retval += b_(chr(_pdfDocEncoding_rev[c])) except KeyError: raise UnicodeEncodeError("pdfdocencoding", c, -1, -1, "does not exist in translation table") return retval def decode_pdfdocencoding(byte_array): retval = u_('') for b in byte_array: c = _pdfDocEncoding[ord_(b)] if c == u_('\u0000'): raise UnicodeDecodeError("pdfdocencoding", utils.barray(b), -1, -1, "does not exist in translation table") retval += c return retval _pdfDocEncoding = ( u_('\u0000'), u_('\u0000'), u_('\u0000'), u_('\u0000'), u_('\u0000'), u_('\u0000'), u_('\u0000'), u_('\u0000'), u_('\u0000'), u_('\u0000'), u_('\u0000'), u_('\u0000'), u_('\u0000'), u_('\u0000'), u_('\u0000'), u_('\u0000'), u_('\u0000'), u_('\u0000'), u_('\u0000'), u_('\u0000'), u_('\u0000'), u_('\u0000'), u_('\u0000'), u_('\u0000'), u_('\u02d8'), u_('\u02c7'), u_('\u02c6'), u_('\u02d9'), u_('\u02dd'), u_('\u02db'), u_('\u02da'), u_('\u02dc'), u_('\u0020'), u_('\u0021'), u_('\u0022'), u_('\u0023'), u_('\u0024'), u_('\u0025'), u_('\u0026'), u_('\u0027'), u_('\u0028'), u_('\u0029'), u_('\u002a'), u_('\u002b'), u_('\u002c'), u_('\u002d'), u_('\u002e'), u_('\u002f'), u_('\u0030'), u_('\u0031'), u_('\u0032'), u_('\u0033'), u_('\u0034'), u_('\u0035'), u_('\u0036'), u_('\u0037'), u_('\u0038'), u_('\u0039'), u_('\u003a'), u_('\u003b'), u_('\u003c'), u_('\u003d'), u_('\u003e'), u_('\u003f'), u_('\u0040'), u_('\u0041'), u_('\u0042'), u_('\u0043'), u_('\u0044'), u_('\u0045'), u_('\u0046'), u_('\u0047'), u_('\u0048'), u_('\u0049'), u_('\u004a'), u_('\u004b'), u_('\u004c'), u_('\u004d'), u_('\u004e'), u_('\u004f'), u_('\u0050'), u_('\u0051'), u_('\u0052'), u_('\u0053'), u_('\u0054'), u_('\u0055'), u_('\u0056'), u_('\u0057'), u_('\u0058'), u_('\u0059'), u_('\u005a'), u_('\u005b'), u_('\u005c'), u_('\u005d'), u_('\u005e'), u_('\u005f'), u_('\u0060'), u_('\u0061'), u_('\u0062'), u_('\u0063'), u_('\u0064'), u_('\u0065'), u_('\u0066'), u_('\u0067'), u_('\u0068'), u_('\u0069'), u_('\u006a'), u_('\u006b'), u_('\u006c'), u_('\u006d'), u_('\u006e'), u_('\u006f'), u_('\u0070'), u_('\u0071'), u_('\u0072'), u_('\u0073'), u_('\u0074'), u_('\u0075'), u_('\u0076'), u_('\u0077'), u_('\u0078'), u_('\u0079'), u_('\u007a'), u_('\u007b'), u_('\u007c'), u_('\u007d'), u_('\u007e'), u_('\u0000'), u_('\u2022'), u_('\u2020'), u_('\u2021'), u_('\u2026'), u_('\u2014'), u_('\u2013'), u_('\u0192'), u_('\u2044'), u_('\u2039'), u_('\u203a'), u_('\u2212'), u_('\u2030'), u_('\u201e'), u_('\u201c'), u_('\u201d'), u_('\u2018'), u_('\u2019'), u_('\u201a'), u_('\u2122'), u_('\ufb01'), u_('\ufb02'), u_('\u0141'), u_('\u0152'), u_('\u0160'), u_('\u0178'), u_('\u017d'), u_('\u0131'), u_('\u0142'), u_('\u0153'), u_('\u0161'), u_('\u017e'), u_('\u0000'), u_('\u20ac'), u_('\u00a1'), u_('\u00a2'), u_('\u00a3'), u_('\u00a4'), u_('\u00a5'), u_('\u00a6'), u_('\u00a7'), u_('\u00a8'), u_('\u00a9'), u_('\u00aa'), u_('\u00ab'), u_('\u00ac'), u_('\u0000'), u_('\u00ae'), u_('\u00af'), u_('\u00b0'), u_('\u00b1'), u_('\u00b2'), u_('\u00b3'), u_('\u00b4'), u_('\u00b5'), u_('\u00b6'), u_('\u00b7'), u_('\u00b8'), u_('\u00b9'), u_('\u00ba'), u_('\u00bb'), u_('\u00bc'), u_('\u00bd'), u_('\u00be'), u_('\u00bf'), u_('\u00c0'), u_('\u00c1'), u_('\u00c2'), u_('\u00c3'), u_('\u00c4'), u_('\u00c5'), u_('\u00c6'), u_('\u00c7'), u_('\u00c8'), u_('\u00c9'), u_('\u00ca'), u_('\u00cb'), u_('\u00cc'), u_('\u00cd'), u_('\u00ce'), u_('\u00cf'), u_('\u00d0'), u_('\u00d1'), u_('\u00d2'), u_('\u00d3'), u_('\u00d4'), u_('\u00d5'), u_('\u00d6'), u_('\u00d7'), u_('\u00d8'), u_('\u00d9'), u_('\u00da'), u_('\u00db'), u_('\u00dc'), u_('\u00dd'), u_('\u00de'), u_('\u00df'), u_('\u00e0'), u_('\u00e1'), u_('\u00e2'), u_('\u00e3'), u_('\u00e4'), u_('\u00e5'), u_('\u00e6'), u_('\u00e7'), u_('\u00e8'), u_('\u00e9'), u_('\u00ea'), u_('\u00eb'), u_('\u00ec'), u_('\u00ed'), u_('\u00ee'), u_('\u00ef'), u_('\u00f0'), u_('\u00f1'), u_('\u00f2'), u_('\u00f3'), u_('\u00f4'), u_('\u00f5'), u_('\u00f6'), u_('\u00f7'), u_('\u00f8'), u_('\u00f9'), u_('\u00fa'), u_('\u00fb'), u_('\u00fc'), u_('\u00fd'), u_('\u00fe'), u_('\u00ff') ) assert len(_pdfDocEncoding) == 256 _pdfDocEncoding_rev = {} for i in range(256): char = _pdfDocEncoding[i] if char == u_("\u0000"): continue assert char not in _pdfDocEncoding_rev _pdfDocEncoding_rev[char] = i PyPDF2-1.25.1/PyPDF2/merger.py000066400000000000000000000516131255324530700154570ustar00rootroot00000000000000# vim: sw=4:expandtab:foldmethod=marker # # Copyright (c) 2006, Mathieu Fenniak # All rights reserved. # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions are # met: # # * Redistributions of source code must retain the above copyright notice, # this list of conditions and the following disclaimer. # * Redistributions in binary form must reproduce the above copyright notice, # this list of conditions and the following disclaimer in the documentation # and/or other materials provided with the distribution. # * The name of the author may not be used to endorse or promote products # derived from this software without specific prior written permission. # # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" # AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE # ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE # LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR # CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF # SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS # INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN # CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) # ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE # POSSIBILITY OF SUCH DAMAGE. from .generic import * from .utils import isString, str_ from .pdf import PdfFileReader, PdfFileWriter from .pagerange import PageRange from sys import version_info if version_info < ( 3, 0 ): from cStringIO import StringIO StreamIO = StringIO else: from io import BytesIO from io import FileIO as file StreamIO = BytesIO class _MergedPage(object): """ _MergedPage is used internally by PdfFileMerger to collect necessary information on each page that is being merged. """ def __init__(self, pagedata, src, id): self.src = src self.pagedata = pagedata self.out_pagedata = None self.id = id class PdfFileMerger(object): """ Initializes a PdfFileMerger object. PdfFileMerger merges multiple PDFs into a single PDF. It can concatenate, slice, insert, or any combination of the above. See the functions :meth:`merge()` (or :meth:`append()`) and :meth:`write()` for usage information. :param bool strict: Determines whether user should be warned of all problems and also causes some correctable problems to be fatal. Defaults to ``True``. """ def __init__(self, strict=True): self.inputs = [] self.pages = [] self.output = PdfFileWriter() self.bookmarks = [] self.named_dests = [] self.id_count = 0 self.strict = strict def merge(self, position, fileobj, bookmark=None, pages=None, import_bookmarks=True): """ Merges the pages from the given file into the output file at the specified page number. :param int position: The *page number* to insert this file. File will be inserted after the given number. :param fileobj: A File Object or an object that supports the standard read and seek methods similar to a File Object. Could also be a string representing a path to a PDF file. :param str bookmark: Optionally, you may specify a bookmark to be applied at the beginning of the included file by supplying the text of the bookmark. :param pages: can be a :ref:`Page Range ` or a ``(start, stop[, step])`` tuple to merge only the specified range of pages from the source document into the output document. :param bool import_bookmarks: You may prevent the source document's bookmarks from being imported by specifying this as ``False``. """ # This parameter is passed to self.inputs.append and means # that the stream used was created in this method. my_file = False # If the fileobj parameter is a string, assume it is a path # and create a file object at that location. If it is a file, # copy the file's contents into a BytesIO (or StreamIO) stream object; if # it is a PdfFileReader, copy that reader's stream into a # BytesIO (or StreamIO) stream. # If fileobj is none of the above types, it is not modified decryption_key = None if isString(fileobj): fileobj = file(fileobj, 'rb') my_file = True elif isinstance(fileobj, file): fileobj.seek(0) filecontent = fileobj.read() fileobj = StreamIO(filecontent) my_file = True elif isinstance(fileobj, PdfFileReader): orig_tell = fileobj.stream.tell() fileobj.stream.seek(0) filecontent = StreamIO(fileobj.stream.read()) fileobj.stream.seek(orig_tell) # reset the stream to its original location fileobj = filecontent if hasattr(fileobj, '_decryption_key'): decryption_key = fileobj._decryption_key my_file = True # Create a new PdfFileReader instance using the stream # (either file or BytesIO or StringIO) created above pdfr = PdfFileReader(fileobj, strict=self.strict) if decryption_key is not None: pdfr._decryption_key = decryption_key # Find the range of pages to merge. if pages == None: pages = (0, pdfr.getNumPages()) elif isinstance(pages, PageRange): pages = pages.indices(pdfr.getNumPages()) elif not isinstance(pages, tuple): raise TypeError('"pages" must be a tuple of (start, stop[, step])') srcpages = [] if bookmark: bookmark = Bookmark(TextStringObject(bookmark), NumberObject(self.id_count), NameObject('/Fit')) outline = [] if import_bookmarks: outline = pdfr.getOutlines() outline = self._trim_outline(pdfr, outline, pages) if bookmark: self.bookmarks += [bookmark, outline] else: self.bookmarks += outline dests = pdfr.namedDestinations dests = self._trim_dests(pdfr, dests, pages) self.named_dests += dests # Gather all the pages that are going to be merged for i in range(*pages): pg = pdfr.getPage(i) id = self.id_count self.id_count += 1 mp = _MergedPage(pg, pdfr, id) srcpages.append(mp) self._associate_dests_to_pages(srcpages) self._associate_bookmarks_to_pages(srcpages) # Slice to insert the pages at the specified position self.pages[position:position] = srcpages # Keep track of our input files so we can close them later self.inputs.append((fileobj, pdfr, my_file)) def append(self, fileobj, bookmark=None, pages=None, import_bookmarks=True): """ Identical to the :meth:`merge()` method, but assumes you want to concatenate all pages onto the end of the file instead of specifying a position. :param fileobj: A File Object or an object that supports the standard read and seek methods similar to a File Object. Could also be a string representing a path to a PDF file. :param str bookmark: Optionally, you may specify a bookmark to be applied at the beginning of the included file by supplying the text of the bookmark. :param pages: can be a :ref:`Page Range ` or a ``(start, stop[, step])`` tuple to merge only the specified range of pages from the source document into the output document. :param bool import_bookmarks: You may prevent the source document's bookmarks from being imported by specifying this as ``False``. """ self.merge(len(self.pages), fileobj, bookmark, pages, import_bookmarks) def write(self, fileobj): """ Writes all data that has been merged to the given output file. :param fileobj: Output file. Can be a filename or any kind of file-like object. """ my_file = False if isString(fileobj): fileobj = file(fileobj, 'wb') my_file = True # Add pages to the PdfFileWriter # The commented out line below was replaced with the two lines below it to allow PdfFileMerger to work with PyPdf 1.13 for page in self.pages: self.output.addPage(page.pagedata) page.out_pagedata = self.output.getReference(self.output._pages.getObject()["/Kids"][-1].getObject()) #idnum = self.output._objects.index(self.output._pages.getObject()["/Kids"][-1].getObject()) + 1 #page.out_pagedata = IndirectObject(idnum, 0, self.output) # Once all pages are added, create bookmarks to point at those pages self._write_dests() self._write_bookmarks() # Write the output to the file self.output.write(fileobj) if my_file: fileobj.close() def close(self): """ Shuts all file descriptors (input and output) and clears all memory usage. """ self.pages = [] for fo, pdfr, mine in self.inputs: if mine: fo.close() self.inputs = [] self.output = None def addMetadata(self, infos): """ Add custom metadata to the output. :param dict infos: a Python dictionary where each key is a field and each value is your new metadata. Example: ``{u'/Title': u'My title'}`` """ self.output.addMetadata(infos) def setPageLayout(self, layout): """ Set the page layout :param str layout: The page layout to be used Valid layouts are: /NoLayout Layout explicitly not specified /SinglePage Show one page at a time /OneColumn Show one column at a time /TwoColumnLeft Show pages in two columns, odd-numbered pages on the left /TwoColumnRight Show pages in two columns, odd-numbered pages on the right /TwoPageLeft Show two pages at a time, odd-numbered pages on the left /TwoPageRight Show two pages at a time, odd-numbered pages on the right """ self.output.setPageLayout(layout) def setPageMode(self, mode): """ Set the page mode. :param str mode: The page mode to use. Valid modes are: /UseNone Do not show outlines or thumbnails panels /UseOutlines Show outlines (aka bookmarks) panel /UseThumbs Show page thumbnails panel /FullScreen Fullscreen view /UseOC Show Optional Content Group (OCG) panel /UseAttachments Show attachments panel """ self.output.setPageMode(mode) def _trim_dests(self, pdf, dests, pages): """ Removes any named destinations that are not a part of the specified page set. """ new_dests = [] prev_header_added = True for k, o in list(dests.items()): for j in range(*pages): if pdf.getPage(j).getObject() == o['/Page'].getObject(): o[NameObject('/Page')] = o['/Page'].getObject() assert str_(k) == str_(o['/Title']) new_dests.append(o) break return new_dests def _trim_outline(self, pdf, outline, pages): """ Removes any outline/bookmark entries that are not a part of the specified page set. """ new_outline = [] prev_header_added = True for i, o in enumerate(outline): if isinstance(o, list): sub = self._trim_outline(pdf, o, pages) if sub: if not prev_header_added: new_outline.append(outline[i-1]) new_outline.append(sub) else: prev_header_added = False for j in range(*pages): if pdf.getPage(j).getObject() == o['/Page'].getObject(): o[NameObject('/Page')] = o['/Page'].getObject() new_outline.append(o) prev_header_added = True break return new_outline def _write_dests(self): dests = self.named_dests for v in dests: pageno = None pdf = None if '/Page' in v: for i, p in enumerate(self.pages): if p.id == v['/Page']: v[NameObject('/Page')] = p.out_pagedata pageno = i pdf = p.src break if pageno != None: self.output.addNamedDestinationObject(v) def _write_bookmarks(self, bookmarks=None, parent=None): if bookmarks == None: bookmarks = self.bookmarks last_added = None for b in bookmarks: if isinstance(b, list): self._write_bookmarks(b, last_added) continue pageno = None pdf = None if '/Page' in b: for i, p in enumerate(self.pages): if p.id == b['/Page']: #b[NameObject('/Page')] = p.out_pagedata args = [NumberObject(p.id), NameObject(b['/Type'])] #nothing more to add #if b['/Type'] == '/Fit' or b['/Type'] == '/FitB' if b['/Type'] == '/FitH' or b['/Type'] == '/FitBH': if '/Top' in b and not isinstance(b['/Top'], NullObject): args.append(FloatObject(b['/Top'])) else: args.append(FloatObject(0)) del b['/Top'] elif b['/Type'] == '/FitV' or b['/Type'] == '/FitBV': if '/Left' in b and not isinstance(b['/Left'], NullObject): args.append(FloatObject(b['/Left'])) else: args.append(FloatObject(0)) del b['/Left'] elif b['/Type'] == '/XYZ': if '/Left' in b and not isinstance(b['/Left'], NullObject): args.append(FloatObject(b['/Left'])) else: args.append(FloatObject(0)) if '/Top' in b and not isinstance(b['/Top'], NullObject): args.append(FloatObject(b['/Top'])) else: args.append(FloatObject(0)) if '/Zoom' in b and not isinstance(b['/Zoom'], NullObject): args.append(FloatObject(b['/Zoom'])) else: args.append(FloatObject(0)) del b['/Top'], b['/Zoom'], b['/Left'] elif b['/Type'] == '/FitR': if '/Left' in b and not isinstance(b['/Left'], NullObject): args.append(FloatObject(b['/Left'])) else: args.append(FloatObject(0)) if '/Bottom' in b and not isinstance(b['/Bottom'], NullObject): args.append(FloatObject(b['/Bottom'])) else: args.append(FloatObject(0)) if '/Right' in b and not isinstance(b['/Right'], NullObject): args.append(FloatObject(b['/Right'])) else: args.append(FloatObject(0)) if '/Top' in b and not isinstance(b['/Top'], NullObject): args.append(FloatObject(b['/Top'])) else: args.append(FloatObject(0)) del b['/Left'], b['/Right'], b['/Bottom'], b['/Top'] b[NameObject('/A')] = DictionaryObject({NameObject('/S'): NameObject('/GoTo'), NameObject('/D'): ArrayObject(args)}) pageno = i pdf = p.src break if pageno != None: del b['/Page'], b['/Type'] last_added = self.output.addBookmarkDict(b, parent) def _associate_dests_to_pages(self, pages): for nd in self.named_dests: pageno = None np = nd['/Page'] if isinstance(np, NumberObject): continue for p in pages: if np.getObject() == p.pagedata.getObject(): pageno = p.id if pageno != None: nd[NameObject('/Page')] = NumberObject(pageno) else: raise ValueError("Unresolved named destination '%s'" % (nd['/Title'],)) def _associate_bookmarks_to_pages(self, pages, bookmarks=None): if bookmarks == None: bookmarks = self.bookmarks for b in bookmarks: if isinstance(b, list): self._associate_bookmarks_to_pages(pages, b) continue pageno = None bp = b['/Page'] if isinstance(bp, NumberObject): continue for p in pages: if bp.getObject() == p.pagedata.getObject(): pageno = p.id if pageno != None: b[NameObject('/Page')] = NumberObject(pageno) else: raise ValueError("Unresolved bookmark '%s'" % (b['/Title'],)) def findBookmark(self, bookmark, root=None): if root == None: root = self.bookmarks for i, b in enumerate(root): if isinstance(b, list): res = self.findBookmark(bookmark, b) if res: return [i] + res elif b == bookmark or b['/Title'] == bookmark: return [i] return None def addBookmark(self, title, pagenum, parent=None): """ Add a bookmark to this PDF file. :param str title: Title to use for this bookmark. :param int pagenum: Page number this bookmark will point to. :param parent: A reference to a parent bookmark to create nested bookmarks. """ if parent == None: iloc = [len(self.bookmarks)-1] elif isinstance(parent, list): iloc = parent else: iloc = self.findBookmark(parent) dest = Bookmark(TextStringObject(title), NumberObject(pagenum), NameObject('/FitH'), NumberObject(826)) if parent == None: self.bookmarks.append(dest) else: bmparent = self.bookmarks for i in iloc[:-1]: bmparent = bmparent[i] npos = iloc[-1]+1 if npos < len(bmparent) and isinstance(bmparent[npos], list): bmparent[npos].append(dest) else: bmparent.insert(npos, [dest]) return dest def addNamedDestination(self, title, pagenum): """ Add a destination to the output. :param str title: Title to use :param int pagenum: Page number this destination points at. """ dest = Destination(TextStringObject(title), NumberObject(pagenum), NameObject('/FitH'), NumberObject(826)) self.named_dests.append(dest) class OutlinesObject(list): def __init__(self, pdf, tree, parent=None): list.__init__(self) self.tree = tree self.pdf = pdf self.parent = parent def remove(self, index): obj = self[index] del self[index] self.tree.removeChild(obj) def add(self, title, pagenum): pageRef = self.pdf.getObject(self.pdf._pages)['/Kids'][pagenum] action = DictionaryObject() action.update({ NameObject('/D') : ArrayObject([pageRef, NameObject('/FitH'), NumberObject(826)]), NameObject('/S') : NameObject('/GoTo') }) actionRef = self.pdf._addObject(action) bookmark = TreeObject() bookmark.update({ NameObject('/A'): actionRef, NameObject('/Title'): createStringObject(title), }) self.pdf._addObject(bookmark) self.tree.addChild(bookmark) def removeAll(self): for child in [x for x in self.tree.children()]: self.tree.removeChild(child) self.pop() PyPDF2-1.25.1/PyPDF2/pagerange.py000066400000000000000000000126361255324530700161310ustar00rootroot00000000000000#!/usr/bin/env python """ Representation and utils for ranges of PDF file pages. Copyright (c) 2014, Steve Witham . All rights reserved. This software is available under a BSD license; see https://github.com/mstamy2/PyPDF2/blob/master/LICENSE """ import re from .utils import isString _INT_RE = r"(0|-?[1-9]\d*)" # A decimal int, don't allow "-0". PAGE_RANGE_RE = "^({int}|({int}?(:{int}?(:{int}?)?)))$".format(int=_INT_RE) # groups: 12 34 5 6 7 8 class ParseError(Exception): pass PAGE_RANGE_HELP = """Remember, page indices start with zero. Page range expression examples: : all pages. -1 last page. 22 just the 23rd page. :-1 all but the last page. 0:3 the first three pages. -2 second-to-last page. :3 the first three pages. -2: last two pages. 5: from the sixth page onward. -3:-1 third & second to last. The third, "stride" or "step" number is also recognized. ::2 0 2 4 ... to the end. 3:0:-1 3 2 1 but not 0. 1:10:2 1 3 5 7 9 2::-1 2 1 0. ::-1 all pages in reverse order. """ class PageRange(object): """ A slice-like representation of a range of page indices, i.e. page numbers, only starting at zero. The syntax is like what you would put between brackets [ ]. The slice is one of the few Python types that can't be subclassed, but this class converts to and from slices, and allows similar use. o PageRange(str) parses a string representing a page range. o PageRange(slice) directly "imports" a slice. o to_slice() gives the equivalent slice. o str() and repr() allow printing. o indices(n) is like slice.indices(n). """ def __init__(self, arg): """ Initialize with either a slice -- giving the equivalent page range, or a PageRange object -- making a copy, or a string like "int", "[int]:[int]" or "[int]:[int]:[int]", where the brackets indicate optional ints. {page_range_help} Note the difference between this notation and arguments to slice(): slice(3) means the first three pages; PageRange("3") means the range of only the fourth page. However PageRange(slice(3)) means the first three pages. """ if isinstance(arg, slice): self._slice = arg return if isinstance(arg, PageRange): self._slice = arg.to_slice() return m = isString(arg) and re.match(PAGE_RANGE_RE, arg) if not m: raise ParseError(arg) elif m.group(2): # Special case: just an int means a range of one page. start = int(m.group(2)) stop = start + 1 if start != -1 else None self._slice = slice(start, stop) else: self._slice = slice(*[int(g) if g else None for g in m.group(4, 6, 8)]) # Just formatting this when there is __doc__ for __init__ if __init__.__doc__: __init__.__doc__ = __init__.__doc__.format(page_range_help=PAGE_RANGE_HELP) @staticmethod def valid(input): """ True if input is a valid initializer for a PageRange. """ return isinstance(input, slice) or \ isinstance(input, PageRange) or \ (isString(input) and bool(re.match(PAGE_RANGE_RE, input))) def to_slice(self): """ Return the slice equivalent of this page range. """ return self._slice def __str__(self): """ A string like "1:2:3". """ s = self._slice if s.step == None: if s.start != None and s.stop == s.start + 1: return str(s.start) indices = s.start, s.stop else: indices = s.start, s.stop, s.step return ':'.join("" if i == None else str(i) for i in indices) def __repr__(self): """ A string like "PageRange('1:2:3')". """ return "PageRange(" + repr(str(self)) + ")" def indices(self, n): """ n is the length of the list of pages to choose from. Returns arguments for range(). See help(slice.indices). """ return self._slice.indices(n) PAGE_RANGE_ALL = PageRange(":") # The range of all pages. def parse_filename_page_ranges(args): """ Given a list of filenames and page ranges, return a list of (filename, page_range) pairs. First arg must be a filename; other ags are filenames, page-range expressions, slice objects, or PageRange objects. A filename not followed by a page range indicates all pages of the file. """ pairs = [] pdf_filename = None did_page_range = False for arg in args + [None]: if PageRange.valid(arg): if not pdf_filename: raise ValueError("The first argument must be a filename, " \ "not a page range.") pairs.append( (pdf_filename, PageRange(arg)) ) did_page_range = True else: # New filename or end of list--do all of the previous file? if pdf_filename and not did_page_range: pairs.append( (pdf_filename, PAGE_RANGE_ALL) ) pdf_filename = arg did_page_range = False return pairs PyPDF2-1.25.1/PyPDF2/pdf.py000066400000000000000000003637531255324530700147620ustar00rootroot00000000000000# -*- coding: utf-8 -*- # # vim: sw=4:expandtab:foldmethod=marker # # Copyright (c) 2006, Mathieu Fenniak # Copyright (c) 2007, Ashish Kulkarni # # All rights reserved. # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions are # met: # # * Redistributions of source code must retain the above copyright notice, # this list of conditions and the following disclaimer. # * Redistributions in binary form must reproduce the above copyright notice, # this list of conditions and the following disclaimer in the documentation # and/or other materials provided with the distribution. # * The name of the author may not be used to endorse or promote products # derived from this software without specific prior written permission. # # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" # AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE # ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE # LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR # CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF # SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS # INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN # CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) # ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE # POSSIBILITY OF SUCH DAMAGE. """ A pure-Python PDF library with an increasing number of capabilities. See README for links to FAQ, documentation, homepage, etc. """ __author__ = "Mathieu Fenniak" __author_email__ = "biziqe@mathieu.fenniak.net" __maintainer__ = "Phaseit, Inc." __maintainer_email = "PyPDF2@phaseit.net" import string import math import struct import sys from sys import version_info if version_info < ( 3, 0 ): from cStringIO import StringIO else: from io import StringIO if version_info < ( 3, 0 ): BytesIO = StringIO else: from io import BytesIO from . import filters from . import utils import warnings import codecs from .generic import * from .utils import readNonWhitespace, readUntilWhitespace, ConvertFunctionsToVirtualList from .utils import isString, b_, u_, ord_, chr_, str_, formatWarning if version_info < ( 2, 4 ): from sets import ImmutableSet as frozenset if version_info < ( 2, 5 ): from md5 import md5 else: from hashlib import md5 import uuid class PdfFileWriter(object): """ This class supports writing PDF files out, given pages produced by another class (typically :class:`PdfFileReader`). """ def __init__(self): self._header = b_("%PDF-1.3") self._objects = [] # array of indirect objects # The root of our page tree node. pages = DictionaryObject() pages.update({ NameObject("/Type"): NameObject("/Pages"), NameObject("/Count"): NumberObject(0), NameObject("/Kids"): ArrayObject(), }) self._pages = self._addObject(pages) # info object info = DictionaryObject() info.update({ NameObject("/Producer"): createStringObject(codecs.BOM_UTF16_BE + u_("PyPDF2").encode('utf-16be')) }) self._info = self._addObject(info) # root object root = DictionaryObject() root.update({ NameObject("/Type"): NameObject("/Catalog"), NameObject("/Pages"): self._pages, }) self._root = None self._root_object = root def _addObject(self, obj): self._objects.append(obj) return IndirectObject(len(self._objects), 0, self) def getObject(self, ido): if ido.pdf != self: raise ValueError("pdf must be self") return self._objects[ido.idnum - 1] def _addPage(self, page, action): assert page["/Type"] == "/Page" page[NameObject("/Parent")] = self._pages page = self._addObject(page) pages = self.getObject(self._pages) action(pages["/Kids"], page) pages[NameObject("/Count")] = NumberObject(pages["/Count"] + 1) def addPage(self, page): """ Adds a page to this PDF file. The page is usually acquired from a :class:`PdfFileReader` instance. :param PageObject page: The page to add to the document. Should be an instance of :class:`PageObject` """ self._addPage(page, list.append) def insertPage(self, page, index=0): """ Insert a page in this PDF file. The page is usually acquired from a :class:`PdfFileReader` instance. :param PageObject page: The page to add to the document. This argument should be an instance of :class:`PageObject`. :param int index: Position at which the page will be inserted. """ self._addPage(page, lambda l, p: l.insert(index, p)) def getPage(self, pageNumber): """ Retrieves a page by number from this PDF file. :param int pageNumber: The page number to retrieve (pages begin at zero) :return: the page at the index given by *pageNumber* :rtype: :class:`PageObject` """ pages = self.getObject(self._pages) # XXX: crude hack return pages["/Kids"][pageNumber].getObject() def getNumPages(self): """ :return: the number of pages. :rtype: int """ pages = self.getObject(self._pages) return int(pages[NameObject("/Count")]) def addBlankPage(self, width=None, height=None): """ Appends a blank page to this PDF file and returns it. If no page size is specified, use the size of the last page. :param float width: The width of the new page expressed in default user space units. :param float height: The height of the new page expressed in default user space units. :return: the newly appended page :rtype: :class:`PageObject` :raises PageSizeNotDefinedError: if width and height are not defined and previous page does not exist. """ page = PageObject.createBlankPage(self, width, height) self.addPage(page) return page def insertBlankPage(self, width=None, height=None, index=0): """ Inserts a blank page to this PDF file and returns it. If no page size is specified, use the size of the last page. :param float width: The width of the new page expressed in default user space units. :param float height: The height of the new page expressed in default user space units. :param int index: Position to add the page. :return: the newly appended page :rtype: :class:`PageObject` :raises PageSizeNotDefinedError: if width and height are not defined and previous page does not exist. """ if width is None or height is None and \ (self.getNumPages() - 1) >= index: oldpage = self.getPage(index) width = oldpage.mediaBox.getWidth() height = oldpage.mediaBox.getHeight() page = PageObject.createBlankPage(self, width, height) self.insertPage(page, index) return page def addJS(self, javascript): """ Add Javascript which will launch upon opening this PDF. :param str javascript: Your Javascript. >>> output.addJS("this.print({bUI:true,bSilent:false,bShrinkToFit:true});") # Example: This will launch the print window when the PDF is opened. """ js = DictionaryObject() js.update({ NameObject("/Type"): NameObject("/Action"), NameObject("/S"): NameObject("/JavaScript"), NameObject("/JS"): NameObject("(%s)" % javascript) }) self._root_object.update({ NameObject("/OpenAction"): self._addObject(js) }) def addAttachment(self, fname, fdata): """ Embed a file inside the PDF. :param str fname: The filename to display. :param str fdata: The data in the file. Reference: https://www.adobe.com/content/dam/Adobe/en/devnet/acrobat/pdfs/PDF32000_2008.pdf Section 7.11.3 """ # We need 3 entries: # * The file's data # * The /Filespec entry # * The file's name, which goes in the Catalog # The entry for the file """ Sample: 8 0 obj << /Length 12 /Type /EmbeddedFile >> stream Hello world! endstream endobj """ file_entry = DecodedStreamObject() file_entry.setData(fdata) file_entry.update({ NameObject("/Type"): NameObject("/EmbeddedFile") }) # The Filespec entry """ Sample: 7 0 obj << /Type /Filespec /F (hello.txt) /EF << /F 8 0 R >> >> """ efEntry = DictionaryObject() efEntry.update({ NameObject("/F"):file_entry }) filespec = DictionaryObject() filespec.update({ NameObject("/Type"): NameObject("/Filespec"), NameObject("/F"): createStringObject(fname), # Perhaps also try TextStringObject NameObject("/EF"): efEntry }) # Then create the entry for the root, as it needs a reference to the Filespec """ Sample: 1 0 obj << /Type /Catalog /Outlines 2 0 R /Pages 3 0 R /Names << /EmbeddedFiles << /Names [(hello.txt) 7 0 R] >> >> >> endobj """ embeddedFilesNamesDictionary = DictionaryObject() embeddedFilesNamesDictionary.update({ NameObject("/Names"): ArrayObject([createStringObject(fname), filespec]) }) embeddedFilesDictionary = DictionaryObject() embeddedFilesDictionary.update({ NameObject("/EmbeddedFiles"): embeddedFilesNamesDictionary }) # Update the root self._root_object.update({ NameObject("/Names"): embeddedFilesDictionary }) def appendPagesFromReader(self, reader, after_page_append=None): """ Copy pages from reader to writer. Includes an optional callback parameter which is invoked after pages are appended to the writer. :param reader: a PdfFileReader object from which to copy page annotations to this writer object. The writer's annots will then be updated :callback after_page_append (function): Callback function that is invoked after each page is appended to the writer. Callback signature: :param writer_pageref (PDF page reference): Reference to the page appended to the writer. """ # Get page count from writer and reader reader_num_pages = reader.getNumPages() writer_num_pages = self.getNumPages() # Copy pages from reader to writer for rpagenum in range(0, reader_num_pages): reader_page = reader.getPage(rpagenum) self.addPage(reader_page) writer_page = self.getPage(writer_num_pages+rpagenum) # Trigger callback, pass writer page as parameter if callable(after_page_append): after_page_append(writer_page) def updatePageFormFieldValues(self, page, fields): ''' Update the form field values for a given page from a fields dictionary. Copy field texts and values from fields to page. :param page: Page reference from PDF writer where the annotations and field data will be updated. :param fields: a Python dictionary of field names (/T) and text values (/V) ''' # Iterate through pages, update field values for j in range(0, len(page['/Annots'])): writer_annot = page['/Annots'][j].getObject() for field in fields: if writer_annot.get('/T') == field: writer_annot.update({ NameObject("/V"): TextStringObject(fields[field]) }) def cloneReaderDocumentRoot(self, reader): ''' Copy the reader document root to the writer. :param reader: PdfFileReader from the document root should be copied. :callback after_page_append ''' self._root_object = reader.trailer['/Root'] def cloneDocumentFromReader(self, reader, after_page_append=None): ''' Create a copy (clone) of a document from a PDF file reader :param reader: PDF file reader instance from which the clone should be created. :callback after_page_append (function): Callback function that is invoked after each page is appended to the writer. Signature includes a reference to the appended page (delegates to appendPagesFromReader). Callback signature: :param writer_pageref (PDF page reference): Reference to the page just appended to the document. ''' self.cloneReaderDocumentRoot(reader) self.appendPagesFromReader(reader, after_page_append) def encrypt(self, user_pwd, owner_pwd = None, use_128bit = True): """ Encrypt this PDF file with the PDF Standard encryption handler. :param str user_pwd: The "user password", which allows for opening and reading the PDF file with the restrictions provided. :param str owner_pwd: The "owner password", which allows for opening the PDF files without any restrictions. By default, the owner password is the same as the user password. :param bool use_128bit: flag as to whether to use 128bit encryption. When false, 40bit encryption will be used. By default, this flag is on. """ import time, random if owner_pwd == None: owner_pwd = user_pwd if use_128bit: V = 2 rev = 3 keylen = int(128 / 8) else: V = 1 rev = 2 keylen = int(40 / 8) # permit everything: P = -1 O = ByteStringObject(_alg33(owner_pwd, user_pwd, rev, keylen)) ID_1 = ByteStringObject(md5(b_(repr(time.time()))).digest()) ID_2 = ByteStringObject(md5(b_(repr(random.random()))).digest()) self._ID = ArrayObject((ID_1, ID_2)) if rev == 2: U, key = _alg34(user_pwd, O, P, ID_1) else: assert rev == 3 U, key = _alg35(user_pwd, rev, keylen, O, P, ID_1, False) encrypt = DictionaryObject() encrypt[NameObject("/Filter")] = NameObject("/Standard") encrypt[NameObject("/V")] = NumberObject(V) if V == 2: encrypt[NameObject("/Length")] = NumberObject(keylen * 8) encrypt[NameObject("/R")] = NumberObject(rev) encrypt[NameObject("/O")] = ByteStringObject(O) encrypt[NameObject("/U")] = ByteStringObject(U) encrypt[NameObject("/P")] = NumberObject(P) self._encrypt = self._addObject(encrypt) self._encrypt_key = key def write(self, stream): """ Writes the collection of pages added to this object out as a PDF file. :param stream: An object to write the file to. The object must support the write method and the tell method, similar to a file object. """ if hasattr(stream, 'mode') and 'b' not in stream.mode: warnings.warn("File <%s> to write to is not in binary mode. It may not be written to correctly." % stream.name) debug = False import struct if not self._root: self._root = self._addObject(self._root_object) externalReferenceMap = {} # PDF objects sometimes have circular references to their /Page objects # inside their object tree (for example, annotations). Those will be # indirect references to objects that we've recreated in this PDF. To # address this problem, PageObject's store their original object # reference number, and we add it to the external reference map before # we sweep for indirect references. This forces self-page-referencing # trees to reference the correct new object location, rather than # copying in a new copy of the page object. for objIndex in range(len(self._objects)): obj = self._objects[objIndex] if isinstance(obj, PageObject) and obj.indirectRef != None: data = obj.indirectRef if data.pdf not in externalReferenceMap: externalReferenceMap[data.pdf] = {} if data.generation not in externalReferenceMap[data.pdf]: externalReferenceMap[data.pdf][data.generation] = {} externalReferenceMap[data.pdf][data.generation][data.idnum] = IndirectObject(objIndex + 1, 0, self) self.stack = [] if debug: print(("ERM:", externalReferenceMap, "root:", self._root)) self._sweepIndirectReferences(externalReferenceMap, self._root) del self.stack # Begin writing: object_positions = [] stream.write(self._header + b_("\n")) for i in range(len(self._objects)): idnum = (i + 1) obj = self._objects[i] object_positions.append(stream.tell()) stream.write(b_(str(idnum) + " 0 obj\n")) key = None if hasattr(self, "_encrypt") and idnum != self._encrypt.idnum: pack1 = struct.pack("` for details. """ pageRef = self.getObject(self._pages)['/Kids'][pagenum] action = DictionaryObject() zoomArgs = [] for a in args: if a is not None: zoomArgs.append(NumberObject(a)) else: zoomArgs.append(NullObject()) dest = Destination(NameObject("/"+title + " bookmark"), pageRef, NameObject(fit), *zoomArgs) destArray = dest.getDestArray() action.update({ NameObject('/D') : destArray, NameObject('/S') : NameObject('/GoTo') }) actionRef = self._addObject(action) outlineRef = self.getOutlineRoot() if parent == None: parent = outlineRef bookmark = TreeObject() bookmark.update({ NameObject('/A'): actionRef, NameObject('/Title'): createStringObject(title), }) if color is not None: bookmark.update({NameObject('/C'): ArrayObject([FloatObject(c) for c in color])}) format = 0 if italic: format += 1 if bold: format += 2 if format: bookmark.update({NameObject('/F'): NumberObject(format)}) bookmarkRef = self._addObject(bookmark) parent = parent.getObject() parent.addChild(bookmarkRef, self) return bookmarkRef def addNamedDestinationObject(self, dest): destRef = self._addObject(dest) nd = self.getNamedDestRoot() nd.extend([dest['/Title'], destRef]) return destRef def addNamedDestination(self, title, pagenum): pageRef = self.getObject(self._pages)['/Kids'][pagenum] dest = DictionaryObject() dest.update({ NameObject('/D') : ArrayObject([pageRef, NameObject('/FitH'), NumberObject(826)]), NameObject('/S') : NameObject('/GoTo') }) destRef = self._addObject(dest) nd = self.getNamedDestRoot() nd.extend([title, destRef]) return destRef def removeLinks(self): """ Removes links and annotations from this output. """ pages = self.getObject(self._pages)['/Kids'] for page in pages: pageRef = self.getObject(page) if "/Annots" in pageRef: del pageRef['/Annots'] def removeImages(self, ignoreByteStringObject=False): """ Removes images from this output. :param bool ignoreByteStringObject: optional parameter to ignore ByteString Objects. """ pages = self.getObject(self._pages)['/Kids'] for j in range(len(pages)): page = pages[j] pageRef = self.getObject(page) content = pageRef['/Contents'].getObject() if not isinstance(content, ContentStream): content = ContentStream(content, pageRef) _operations = [] seq_graphics = False for operands, operator in content.operations: if operator == b_('Tj'): text = operands[0] if ignoreByteStringObject: if not isinstance(text, TextStringObject): operands[0] = TextStringObject() elif operator == b_("'"): text = operands[0] if ignoreByteStringObject: if not isinstance(text, TextStringObject): operands[0] = TextStringObject() elif operator == b_('"'): text = operands[2] if ignoreByteStringObject: if not isinstance(text, TextStringObject): operands[2] = TextStringObject() elif operator == b_("TJ"): for i in range(len(operands[0])): if ignoreByteStringObject: if not isinstance(operands[0][i], TextStringObject): operands[0][i] = TextStringObject() if operator == b_('q'): seq_graphics = True if operator == b_('Q'): seq_graphics = False if seq_graphics: if operator in [b_('cm'), b_('w'), b_('J'), b_('j'), b_('M'), b_('d'), b_('ri'), b_('i'), b_('gs'), b_('W'), b_('b'), b_('s'), b_('S'), b_('f'), b_('F'), b_('n'), b_('m'), b_('l'), b_('c'), b_('v'), b_('y'), b_('h'), b_('B'), b_('Do'), b_('sh')]: continue if operator == b_('re'): continue _operations.append((operands, operator)) content.operations = _operations pageRef.__setitem__(NameObject('/Contents'), content) def removeText(self, ignoreByteStringObject=False): """ Removes images from this output. :param bool ignoreByteStringObject: optional parameter to ignore ByteString Objects. """ pages = self.getObject(self._pages)['/Kids'] for j in range(len(pages)): page = pages[j] pageRef = self.getObject(page) content = pageRef['/Contents'].getObject() if not isinstance(content, ContentStream): content = ContentStream(content, pageRef) for operands,operator in content.operations: if operator == b_('Tj'): text = operands[0] if not ignoreByteStringObject: if isinstance(text, TextStringObject): operands[0] = TextStringObject() else: if isinstance(text, TextStringObject) or \ isinstance(text, ByteStringObject): operands[0] = TextStringObject() elif operator == b_("'"): text = operands[0] if not ignoreByteStringObject: if isinstance(text, TextStringObject): operands[0] = TextStringObject() else: if isinstance(text, TextStringObject) or \ isinstance(text, ByteStringObject): operands[0] = TextStringObject() elif operator == b_('"'): text = operands[2] if not ignoreByteStringObject: if isinstance(text, TextStringObject): operands[2] = TextStringObject() else: if isinstance(text, TextStringObject) or \ isinstance(text, ByteStringObject): operands[2] = TextStringObject() elif operator == b_("TJ"): for i in range(len(operands[0])): if not ignoreByteStringObject: if isinstance(operands[0][i], TextStringObject): operands[0][i] = TextStringObject() else: if isinstance(operands[0][i], TextStringObject) or \ isinstance(operands[0][i], ByteStringObject): operands[0][i] = TextStringObject() pageRef.__setitem__(NameObject('/Contents'), content) def addLink(self, pagenum, pagedest, rect, border=None, fit='/Fit', *args): """ Add an internal link from a rectangular area to the specified page. :param int pagenum: index of the page on which to place the link. :param int pagedest: index of the page to which the link should go. :param rect: :class:`RectangleObject` or array of four integers specifying the clickable rectangular area ``[xLL, yLL, xUR, yUR]``, or string in the form ``"[ xLL yLL xUR yUR ]"``. :param border: if provided, an array describing border-drawing properties. See the PDF spec for details. No border will be drawn if this argument is omitted. :param str fit: Page fit or 'zoom' option (see below). Additional arguments may need to be supplied. Passing ``None`` will be read as a null value for that coordinate. Valid zoom arguments (see Table 8.2 of the PDF 1.7 reference for details): /Fit No additional arguments /XYZ [left] [top] [zoomFactor] /FitH [top] /FitV [left] /FitR [left] [bottom] [right] [top] /FitB No additional arguments /FitBH [top] /FitBV [left] """ pageLink = self.getObject(self._pages)['/Kids'][pagenum] pageDest = self.getObject(self._pages)['/Kids'][pagedest] #TODO: switch for external link pageRef = self.getObject(pageLink) if border is not None: borderArr = [NameObject(n) for n in border[:3]] if len(border) == 4: dashPattern = ArrayObject([NameObject(n) for n in border[3]]) borderArr.append(dashPattern) else: borderArr = [NumberObject(0)] * 3 if isString(rect): rect = NameObject(rect) elif isinstance(rect, RectangleObject): pass else: rect = RectangleObject(rect) zoomArgs = [] for a in args: if a is not None: zoomArgs.append(NumberObject(a)) else: zoomArgs.append(NullObject()) dest = Destination(NameObject("/LinkName"), pageDest, NameObject(fit), *zoomArgs) #TODO: create a better name for the link destArray = dest.getDestArray() lnk = DictionaryObject() lnk.update({ NameObject('/Type'): NameObject('/Annot'), NameObject('/Subtype'): NameObject('/Link'), NameObject('/P'): pageLink, NameObject('/Rect'): rect, NameObject('/Border'): ArrayObject(borderArr), NameObject('/Dest'): destArray }) lnkRef = self._addObject(lnk) if "/Annots" in pageRef: pageRef['/Annots'].append(lnkRef) else: pageRef[NameObject('/Annots')] = ArrayObject([lnkRef]) _valid_layouts = ['/NoLayout', '/SinglePage', '/OneColumn', '/TwoColumnLeft', '/TwoColumnRight', '/TwoPageLeft', '/TwoPageRight'] def getPageLayout(self): """ Get the page layout. See :meth:`setPageLayout()` for a description of valid layouts. :return: Page layout currently being used. :rtype: str, None if not specified """ try: return self._root_object['/PageLayout'] except KeyError: return None def setPageLayout(self, layout): """ Set the page layout :param str layout: The page layout to be used Valid layouts are: /NoLayout Layout explicitly not specified /SinglePage Show one page at a time /OneColumn Show one column at a time /TwoColumnLeft Show pages in two columns, odd-numbered pages on the left /TwoColumnRight Show pages in two columns, odd-numbered pages on the right /TwoPageLeft Show two pages at a time, odd-numbered pages on the left /TwoPageRight Show two pages at a time, odd-numbered pages on the right """ if not isinstance(layout, NameObject): if layout not in self._valid_layouts: warnings.warn("Layout should be one of: {}".format(', '.join(self._valid_layouts))) layout = NameObject(layout) self._root_object.update({NameObject('/PageLayout'): layout}) pageLayout = property(getPageLayout, setPageLayout) """Read and write property accessing the :meth:`getPageLayout()` and :meth:`setPageLayout()` methods.""" _valid_modes = ['/UseNone', '/UseOutlines', '/UseThumbs', '/FullScreen', '/UseOC', '/UseAttachments'] def getPageMode(self): """ Get the page mode. See :meth:`setPageMode()` for a description of valid modes. :return: Page mode currently being used. :rtype: str, None if not specified """ try: return self._root_object['/PageMode'] except KeyError: return None def setPageMode(self, mode): """ Set the page mode. :param str mode: The page mode to use. Valid modes are: /UseNone Do not show outlines or thumbnails panels /UseOutlines Show outlines (aka bookmarks) panel /UseThumbs Show page thumbnails panel /FullScreen Fullscreen view /UseOC Show Optional Content Group (OCG) panel /UseAttachments Show attachments panel """ if not isinstance(mode, NameObject): if mode not in self._valid_modes: warnings.warn("Mode should be one of: {}".format(', '.join(self._valid_modes))) mode = NameObject(mode) self._root_object.update({NameObject('/PageMode'): mode}) pageMode = property(getPageMode, setPageMode) """Read and write property accessing the :meth:`getPageMode()` and :meth:`setPageMode()` methods.""" class PdfFileReader(object): """ Initializes a PdfFileReader object. This operation can take some time, as the PDF stream's cross-reference tables are read into memory. :param stream: A File object or an object that supports the standard read and seek methods similar to a File object. Could also be a string representing a path to a PDF file. :param bool strict: Determines whether user should be warned of all problems and also causes some correctable problems to be fatal. Defaults to ``True``. :param warndest: Destination for logging warnings (defaults to ``sys.stderr``). :param bool overwriteWarnings: Determines whether to override Python's ``warnings.py`` module with a custom implementation (defaults to ``True``). """ def __init__(self, stream, strict=True, warndest = None, overwriteWarnings = True): if overwriteWarnings: # have to dynamically override the default showwarning since there are no # public methods that specify the 'file' parameter def _showwarning(message, category, filename, lineno, file=warndest, line=None): if file is None: file = sys.stderr try: file.write(formatWarning(message, category, filename, lineno, line)) except IOError: pass warnings.showwarning = _showwarning self.strict = strict self.flattenedPages = None self.resolvedObjects = {} self.xrefIndex = 0 self._pageId2Num = None # map page IndirectRef number to Page Number if hasattr(stream, 'mode') and 'b' not in stream.mode: warnings.warn("PdfFileReader stream/file object is not in binary mode. It may not be read correctly.", utils.PdfReadWarning) if isString(stream): fileobj = open(stream, 'rb') stream = BytesIO(b_(fileobj.read())) fileobj.close() self.read(stream) self.stream = stream self._override_encryption = False def getDocumentInfo(self): """ Retrieves the PDF file's document information dictionary, if it exists. Note that some PDF files use metadata streams instead of docinfo dictionaries, and these metadata streams will not be accessed by this function. :return: the document information of this PDF file :rtype: :class:`DocumentInformation` or ``None`` if none exists. """ if "/Info" not in self.trailer: return None obj = self.trailer['/Info'] retval = DocumentInformation() retval.update(obj) return retval documentInfo = property(lambda self: self.getDocumentInfo(), None, None) """Read-only property that accesses the :meth:`getDocumentInfo()` function.""" def getXmpMetadata(self): """ Retrieves XMP (Extensible Metadata Platform) data from the PDF document root. :return: a :class:`XmpInformation` instance that can be used to access XMP metadata from the document. :rtype: :class:`XmpInformation` or ``None`` if no metadata was found on the document root. """ try: self._override_encryption = True return self.trailer["/Root"].getXmpMetadata() finally: self._override_encryption = False xmpMetadata = property(lambda self: self.getXmpMetadata(), None, None) """ Read-only property that accesses the :meth:`getXmpMetadata()` function. """ def getNumPages(self): """ Calculates the number of pages in this PDF file. :return: number of pages :rtype: int :raises PdfReadError: if file is encrypted and restrictions prevent this action. """ # Flattened pages will not work on an Encrypted PDF; # the PDF file's page count is used in this case. Otherwise, # the original method (flattened page count) is used. if self.isEncrypted: try: self._override_encryption = True self.decrypt('') return self.trailer["/Root"]["/Pages"]["/Count"] except: raise utils.PdfReadError("File has not been decrypted") finally: self._override_encryption = False else: if self.flattenedPages == None: self._flatten() return len(self.flattenedPages) numPages = property(lambda self: self.getNumPages(), None, None) """ Read-only property that accesses the :meth:`getNumPages()` function. """ def getPage(self, pageNumber): """ Retrieves a page by number from this PDF file. :param int pageNumber: The page number to retrieve (pages begin at zero) :return: a :class:`PageObject` instance. :rtype: :class:`PageObject` """ ## ensure that we're not trying to access an encrypted PDF #assert not self.trailer.has_key("/Encrypt") if self.flattenedPages == None: self._flatten() return self.flattenedPages[pageNumber] namedDestinations = property(lambda self: self.getNamedDestinations(), None, None) """ Read-only property that accesses the :meth:`getNamedDestinations()` function. """ # A select group of relevant field attributes. For the complete list, # see section 8.6.2 of the PDF 1.7 reference. def getFields(self, tree = None, retval = None, fileobj = None): """ Extracts field data if this PDF contains interactive form fields. The *tree* and *retval* parameters are for recursive use. :param fileobj: A file object (usually a text file) to write a report to on all interactive form fields found. :return: A dictionary where each key is a field name, and each value is a :class:`Field` object. By default, the mapping name is used for keys. :rtype: dict, or ``None`` if form data could not be located. """ fieldAttributes = {"/FT" : "Field Type", "/Parent" : "Parent", "/T" : "Field Name", "/TU" : "Alternate Field Name", "/TM" : "Mapping Name", "/Ff" : "Field Flags", "/V" : "Value", "/DV" : "Default Value"} if retval == None: retval = {} catalog = self.trailer["/Root"] # get the AcroForm tree if "/AcroForm" in catalog: tree = catalog["/AcroForm"] else: return None if tree == None: return retval self._checkKids(tree, retval, fileobj) for attr in fieldAttributes: if attr in tree: # Tree is a field self._buildField(tree, retval, fileobj, fieldAttributes) break if "/Fields" in tree: fields = tree["/Fields"] for f in fields: field = f.getObject() self._buildField(field, retval, fileobj, fieldAttributes) return retval def _buildField(self, field, retval, fileobj, fieldAttributes): self._checkKids(field, retval, fileobj) try: key = field["/TM"] except KeyError: try: key = field["/T"] except KeyError: # Ignore no-name field for now return if fileobj: self._writeField(fileobj, field, fieldAttributes) fileobj.write("\n") retval[key] = Field(field) def _checkKids(self, tree, retval, fileobj): if "/Kids" in tree: # recurse down the tree for kid in tree["/Kids"]: self.getFields(kid.getObject(), retval, fileobj) def _writeField(self, fileobj, field, fieldAttributes): order = ["/TM", "/T", "/FT", "/Parent", "/TU", "/Ff", "/V", "/DV"] for attr in order: attrName = fieldAttributes[attr] try: if attr == "/FT": # Make the field type value more clear types = {"/Btn":"Button", "/Tx":"Text", "/Ch": "Choice", "/Sig":"Signature"} if field[attr] in types: fileobj.write(attrName + ": " + types[field[attr]] + "\n") elif attr == "/Parent": # Let's just write the name of the parent try: name = field["/Parent"]["/TM"] except KeyError: name = field["/Parent"]["/T"] fileobj.write(attrName + ": " + name + "\n") else: fileobj.write(attrName + ": " + str(field[attr]) + "\n") except KeyError: # Field attribute is N/A or unknown, so don't write anything pass def getNamedDestinations(self, tree=None, retval=None): """ Retrieves the named destinations present in the document. :return: a dictionary which maps names to :class:`Destinations`. :rtype: dict """ if retval == None: retval = {} catalog = self.trailer["/Root"] # get the name tree if "/Dests" in catalog: tree = catalog["/Dests"] elif "/Names" in catalog: names = catalog['/Names'] if "/Dests" in names: tree = names['/Dests'] if tree == None: return retval if "/Kids" in tree: # recurse down the tree for kid in tree["/Kids"]: self.getNamedDestinations(kid.getObject(), retval) if "/Names" in tree: names = tree["/Names"] for i in range(0, len(names), 2): key = names[i].getObject() val = names[i+1].getObject() if isinstance(val, DictionaryObject) and '/D' in val: val = val['/D'] dest = self._buildDestination(key, val) if dest != None: retval[key] = dest return retval outlines = property(lambda self: self.getOutlines(), None, None) """ Read-only property that accesses the :meth:`getOutlines()` function. """ def getOutlines(self, node=None, outlines=None): """ Retrieves the document outline present in the document. :return: a nested list of :class:`Destinations`. """ if outlines == None: outlines = [] catalog = self.trailer["/Root"] # get the outline dictionary and named destinations if "/Outlines" in catalog: try: lines = catalog["/Outlines"] except utils.PdfReadError: # this occurs if the /Outlines object reference is incorrect # for an example of such a file, see https://unglueit-files.s3.amazonaws.com/ebf/7552c42e9280b4476e59e77acc0bc812.pdf # so continue to load the file without the Bookmarks return outlines if "/First" in lines: node = lines["/First"] self._namedDests = self.getNamedDestinations() if node == None: return outlines # see if there are any more outlines while True: outline = self._buildOutline(node) if outline: outlines.append(outline) # check for sub-outlines if "/First" in node: subOutlines = [] self.getOutlines(node["/First"], subOutlines) if subOutlines: outlines.append(subOutlines) if "/Next" not in node: break node = node["/Next"] return outlines def _getPageNumberByIndirect(self, indirectRef): """Generate _pageId2Num""" if self._pageId2Num is None: id2num = {} for i, x in enumerate(self.pages): id2num[x.indirectRef.idnum] = i self._pageId2Num = id2num if isinstance(indirectRef, int): idnum = indirectRef else: idnum = indirectRef.idnum ret = self._pageId2Num.get(idnum, -1) return ret def getPageNumber(self, page): """ Retrieve page number of a given PageObject :param PageObject page: The page to get page number. Should be an instance of :class:`PageObject` :return: the page number or -1 if page not found :rtype: int """ indirectRef = page.indirectRef ret = self._getPageNumberByIndirect(indirectRef) return ret def getDestinationPageNumber(self, destination): """ Retrieve page number of a given Destination object :param Destination destination: The destination to get page number. Should be an instance of :class:`Destination` :return: the page number or -1 if page not found :rtype: int """ indirectRef = destination.page ret = self._getPageNumberByIndirect(indirectRef) return ret def _buildDestination(self, title, array): page, typ = array[0:2] array = array[2:] return Destination(title, page, typ, *array) def _buildOutline(self, node): dest, title, outline = None, None, None if "/A" in node and "/Title" in node: # Action, section 8.5 (only type GoTo supported) title = node["/Title"] action = node["/A"] if action["/S"] == "/GoTo": dest = action["/D"] elif "/Dest" in node and "/Title" in node: # Destination, section 8.2.1 title = node["/Title"] dest = node["/Dest"] # if destination found, then create outline if dest: if isinstance(dest, ArrayObject): outline = self._buildDestination(title, dest) elif isString(dest) and dest in self._namedDests: outline = self._namedDests[dest] outline[NameObject("/Title")] = title else: raise utils.PdfReadError("Unexpected destination %r" % dest) return outline pages = property(lambda self: ConvertFunctionsToVirtualList(self.getNumPages, self.getPage), None, None) """ Read-only property that emulates a list based upon the :meth:`getNumPages()` and :meth:`getPage()` methods. """ def getPageLayout(self): """ Get the page layout. See :meth:`setPageLayout()` for a description of valid layouts. :return: Page layout currently being used. :rtype: ``str``, ``None`` if not specified """ try: return self.trailer['/Root']['/PageLayout'] except KeyError: return None pageLayout = property(getPageLayout) """Read-only property accessing the :meth:`getPageLayout()` method.""" def getPageMode(self): """ Get the page mode. See :meth:`setPageMode()` for a description of valid modes. :return: Page mode currently being used. :rtype: ``str``, ``None`` if not specified """ try: return self.trailer['/Root']['/PageMode'] except KeyError: return None pageMode = property(getPageMode) """Read-only property accessing the :meth:`getPageMode()` method.""" def _flatten(self, pages=None, inherit=None, indirectRef=None): inheritablePageAttributes = ( NameObject("/Resources"), NameObject("/MediaBox"), NameObject("/CropBox"), NameObject("/Rotate") ) if inherit == None: inherit = dict() if pages == None: self.flattenedPages = [] catalog = self.trailer["/Root"].getObject() pages = catalog["/Pages"].getObject() t = "/Pages" if "/Type" in pages: t = pages["/Type"] if t == "/Pages": for attr in inheritablePageAttributes: if attr in pages: inherit[attr] = pages[attr] for page in pages["/Kids"]: addt = {} if isinstance(page, IndirectObject): addt["indirectRef"] = page self._flatten(page.getObject(), inherit, **addt) elif t == "/Page": for attr, value in list(inherit.items()): # if the page has it's own value, it does not inherit the # parent's value: if attr not in pages: pages[attr] = value pageObj = PageObject(self, indirectRef) pageObj.update(pages) self.flattenedPages.append(pageObj) def _getObjectFromStream(self, indirectReference): # indirect reference to object in object stream # read the entire object stream into memory debug = False stmnum, idx = self.xref_objStm[indirectReference.idnum] if debug: print(("Here1: %s %s"%(stmnum, idx))) objStm = IndirectObject(stmnum, 0, self).getObject() if debug: print(("Here2: objStm=%s.. stmnum=%s data=%s"%(objStm, stmnum, objStm.getData()))) # This is an xref to a stream, so its type better be a stream assert objStm['/Type'] == '/ObjStm' # /N is the number of indirect objects in the stream assert idx < objStm['/N'] streamData = BytesIO(b_(objStm.getData())) for i in range(objStm['/N']): readNonWhitespace(streamData) streamData.seek(-1, 1) objnum = NumberObject.readFromStream(streamData) readNonWhitespace(streamData) streamData.seek(-1, 1) offset = NumberObject.readFromStream(streamData) readNonWhitespace(streamData) streamData.seek(-1, 1) if objnum != indirectReference.idnum: # We're only interested in one object continue if self.strict and idx != i: raise utils.PdfReadError("Object is in wrong index.") streamData.seek(objStm['/First']+offset, 0) if debug: pos = streamData.tell() streamData.seek(0, 0) lines = streamData.readlines() for i in range(0, len(lines)): print((lines[i])) streamData.seek(pos, 0) try: obj = readObject(streamData, self) except utils.PdfStreamError as e: # Stream object cannot be read. Normally, a critical error, but # Adobe Reader doesn't complain, so continue (in strict mode?) e = sys.exc_info()[1] warnings.warn("Invalid stream (index %d) within object %d %d: %s" % \ (i, indirectReference.idnum, indirectReference.generation, e), utils.PdfReadWarning) if self.strict: raise utils.PdfReadError("Can't read object stream: %s"%e) # Replace with null. Hopefully it's nothing important. obj = NullObject() return obj if self.strict: raise utils.PdfReadError("This is a fatal error in strict mode.") return NullObject() def getObject(self, indirectReference): debug = False if debug: print(("looking at:", indirectReference.idnum, indirectReference.generation)) retval = self.cacheGetIndirectObject(indirectReference.generation, indirectReference.idnum) if retval != None: return retval if indirectReference.generation == 0 and \ indirectReference.idnum in self.xref_objStm: retval = self._getObjectFromStream(indirectReference) elif indirectReference.generation in self.xref and \ indirectReference.idnum in self.xref[indirectReference.generation]: start = self.xref[indirectReference.generation][indirectReference.idnum] if debug: print((" Uncompressed Object", indirectReference.idnum, indirectReference.generation, ":", start)) self.stream.seek(start, 0) idnum, generation = self.readObjectHeader(self.stream) if idnum != indirectReference.idnum and self.xrefIndex: # Xref table probably had bad indexes due to not being zero-indexed if self.strict: raise utils.PdfReadError("Expected object ID (%d %d) does not match actual (%d %d); xref table not zero-indexed." \ % (indirectReference.idnum, indirectReference.generation, idnum, generation)) else: pass # xref table is corrected in non-strict mode elif idnum != indirectReference.idnum: # some other problem raise utils.PdfReadError("Expected object ID (%d %d) does not match actual (%d %d)." \ % (indirectReference.idnum, indirectReference.generation, idnum, generation)) assert generation == indirectReference.generation retval = readObject(self.stream, self) # override encryption is used for the /Encrypt dictionary if not self._override_encryption and self.isEncrypted: # if we don't have the encryption key: if not hasattr(self, '_decryption_key'): raise utils.PdfReadError("file has not been decrypted") # otherwise, decrypt here... import struct pack1 = struct.pack(">read", stream) # start at the end: stream.seek(-1, 2) if not stream.tell(): raise utils.PdfReadError('Cannot read an empty file') last1K = stream.tell() - 1024 + 1 # offset of last 1024 bytes of stream line = b_('') while line[:5] != b_("%%EOF"): if stream.tell() < last1K: raise utils.PdfReadError("EOF marker not found") line = self.readNextEndLine(stream) if debug: print(" line:",line) # find startxref entry - the location of the xref table line = self.readNextEndLine(stream) try: startxref = int(line) except ValueError: # 'startxref' may be on the same line as the location if not line.startswith(b_("startxref")): raise utils.PdfReadError("startxref not found") startxref = int(line[9:].strip()) warnings.warn("startxref on same line as offset") else: line = self.readNextEndLine(stream) if line[:9] != b_("startxref"): raise utils.PdfReadError("startxref not found") # read all cross reference tables and their trailers self.xref = {} self.xref_objStm = {} self.trailer = DictionaryObject() while True: # load the xref table stream.seek(startxref, 0) x = stream.read(1) if x == b_("x"): # standard cross-reference table ref = stream.read(4) if ref[:3] != b_("ref"): raise utils.PdfReadError("xref table read error") readNonWhitespace(stream) stream.seek(-1, 1) firsttime = True; # check if the first time looking at the xref table while True: num = readObject(stream, self) if firsttime and num != 0: self.xrefIndex = num warnings.warn("Xref table not zero-indexed. ID numbers for objects will %sbe corrected." % \ ("" if not self.strict else "not "), utils.PdfReadWarning) #if table not zero indexed, could be due to error from when PDF was created #which will lead to mismatched indices later on firsttime = False readNonWhitespace(stream) stream.seek(-1, 1) size = readObject(stream, self) readNonWhitespace(stream) stream.seek(-1, 1) cnt = 0 while cnt < size: line = stream.read(20) # It's very clear in section 3.4.3 of the PDF spec # that all cross-reference table lines are a fixed # 20 bytes (as of PDF 1.7). However, some files have # 21-byte entries (or more) due to the use of \r\n # (CRLF) EOL's. Detect that case, and adjust the line # until it does not begin with a \r (CR) or \n (LF). while line[0] in b_("\x0D\x0A"): stream.seek(-20 + 1, 1) line = stream.read(20) # On the other hand, some malformed PDF files # use a single character EOL without a preceeding # space. Detect that case, and seek the stream # back one character. (0-9 means we've bled into # the next xref entry, t means we've bled into the # text "trailer"): if line[-1] in b_("0123456789t"): stream.seek(-1, 1) offset, generation = line[:16].split(b_(" ")) offset, generation = int(offset), int(generation) if generation not in self.xref: self.xref[generation] = {} if num in self.xref[generation]: # It really seems like we should allow the last # xref table in the file to override previous # ones. Since we read the file backwards, assume # any existing key is already set correctly. pass else: self.xref[generation][num] = offset cnt += 1 num += 1 readNonWhitespace(stream) stream.seek(-1, 1) trailertag = stream.read(7) if trailertag != b_("trailer"): # more xrefs! stream.seek(-7, 1) else: break readNonWhitespace(stream) stream.seek(-1, 1) newTrailer = readObject(stream, self) for key, value in list(newTrailer.items()): if key not in self.trailer: self.trailer[key] = value if "/Prev" in newTrailer: startxref = newTrailer["/Prev"] else: break elif x.isdigit(): # PDF 1.5+ Cross-Reference Stream stream.seek(-1, 1) idnum, generation = self.readObjectHeader(stream) xrefstream = readObject(stream, self) assert xrefstream["/Type"] == "/XRef" self.cacheIndirectObject(generation, idnum, xrefstream) streamData = BytesIO(b_(xrefstream.getData())) # Index pairs specify the subsections in the dictionary. If # none create one subsection that spans everything. idx_pairs = xrefstream.get("/Index", [0, xrefstream.get("/Size")]) if debug: print(("read idx_pairs=%s"%list(self._pairs(idx_pairs)))) entrySizes = xrefstream.get("/W") assert len(entrySizes) >= 3 if self.strict and len(entrySizes) > 3: raise utils.PdfReadError("Too many entry sizes: %s" %entrySizes) def getEntry(i): # Reads the correct number of bytes for each entry. See the # discussion of the W parameter in PDF spec table 17. if entrySizes[i] > 0: d = streamData.read(entrySizes[i]) return convertToInt(d, entrySizes[i]) # PDF Spec Table 17: A value of zero for an element in the # W array indicates...the default value shall be used if i == 0: return 1 # First value defaults to 1 else: return 0 def used_before(num, generation): # We move backwards through the xrefs, don't replace any. return num in self.xref.get(generation, []) or \ num in self.xref_objStm # Iterate through each subsection last_end = 0 for start, size in self._pairs(idx_pairs): # The subsections must increase assert start >= last_end last_end = start + size for num in range(start, start+size): # The first entry is the type xref_type = getEntry(0) # The rest of the elements depend on the xref_type if xref_type == 0: # linked list of free objects next_free_object = getEntry(1) next_generation = getEntry(2) elif xref_type == 1: # objects that are in use but are not compressed byte_offset = getEntry(1) generation = getEntry(2) if generation not in self.xref: self.xref[generation] = {} if not used_before(num, generation): self.xref[generation][num] = byte_offset if debug: print(("XREF Uncompressed: %s %s"%( num, generation))) elif xref_type == 2: # compressed objects objstr_num = getEntry(1) obstr_idx = getEntry(2) generation = 0 # PDF spec table 18, generation is 0 if not used_before(num, generation): if debug: print(("XREF Compressed: %s %s %s"%( num, objstr_num, obstr_idx))) self.xref_objStm[num] = (objstr_num, obstr_idx) elif self.strict: raise utils.PdfReadError("Unknown xref type: %s"% xref_type) trailerKeys = "/Root", "/Encrypt", "/Info", "/ID" for key in trailerKeys: if key in xrefstream and key not in self.trailer: self.trailer[NameObject(key)] = xrefstream.raw_get(key) if "/Prev" in xrefstream: startxref = xrefstream["/Prev"] else: break else: # bad xref character at startxref. Let's see if we can find # the xref table nearby, as we've observed this error with an # off-by-one before. stream.seek(-11, 1) tmp = stream.read(20) xref_loc = tmp.find(b_("xref")) if xref_loc != -1: startxref -= (10 - xref_loc) continue # No explicit xref table, try finding a cross-reference stream. stream.seek(startxref, 0) found = False for look in range(5): if stream.read(1).isdigit(): # This is not a standard PDF, consider adding a warning startxref += look found = True break if found: continue # no xref table found at specified location raise utils.PdfReadError("Could not find xref table at specified location") #if not zero-indexed, verify that the table is correct; change it if necessary if self.xrefIndex and not self.strict: loc = stream.tell() for gen in self.xref: if gen == 65535: continue for id in self.xref[gen]: stream.seek(self.xref[gen][id], 0) try: pid, pgen = self.readObjectHeader(stream) except ValueError: break if pid == id - self.xrefIndex: self._zeroXref(gen) break #if not, then either it's just plain wrong, or the non-zero-index is actually correct stream.seek(loc, 0) #return to where it was def _zeroXref(self, generation): self.xref[generation] = dict( (k-self.xrefIndex, v) for (k, v) in list(self.xref[generation].items()) ) def _pairs(self, array): i = 0 while True: yield array[i], array[i+1] i += 2 if (i+1) >= len(array): break def readNextEndLine(self, stream): debug = False if debug: print(">>readNextEndLine") line = b_("") while True: # Prevent infinite loops in malformed PDFs if stream.tell() == 0: raise utils.PdfReadError("Could not read malformed PDF file") x = stream.read(1) if debug: print((" x:", x, "%x"%ord(x))) if stream.tell() < 2: raise utils.PdfReadError("EOL marker not found") stream.seek(-2, 1) if x == b_('\n') or x == b_('\r'): ## \n = LF; \r = CR crlf = False while x == b_('\n') or x == b_('\r'): if debug: if ord(x) == 0x0D: print(" x is CR 0D") elif ord(x) == 0x0A: print(" x is LF 0A") x = stream.read(1) if x == b_('\n') or x == b_('\r'): # account for CR+LF stream.seek(-1, 1) crlf = True if stream.tell() < 2: raise utils.PdfReadError("EOL marker not found") stream.seek(-2, 1) stream.seek(2 if crlf else 1, 1) #if using CR+LF, go back 2 bytes, else 1 break else: if debug: print(" x is neither") line = x + line if debug: print((" RNEL line:", line)) if debug: print("leaving RNEL") return line def decrypt(self, password): """ When using an encrypted / secured PDF file with the PDF Standard encryption handler, this function will allow the file to be decrypted. It checks the given password against the document's user password and owner password, and then stores the resulting decryption key if either password is correct. It does not matter which password was matched. Both passwords provide the correct decryption key that will allow the document to be used with this library. :param str password: The password to match. :return: ``0`` if the password failed, ``1`` if the password matched the user password, and ``2`` if the password matched the owner password. :rtype: int :raises NotImplementedError: if document uses an unsupported encryption method. """ self._override_encryption = True try: return self._decrypt(password) finally: self._override_encryption = False def _decrypt(self, password): encrypt = self.trailer['/Encrypt'].getObject() if encrypt['/Filter'] != '/Standard': raise NotImplementedError("only Standard PDF encryption handler is available") if not (encrypt['/V'] in (1, 2)): raise NotImplementedError("only algorithm code 1 and 2 are supported") user_password, key = self._authenticateUserPassword(password) if user_password: self._decryption_key = key return 1 else: rev = encrypt['/R'].getObject() if rev == 2: keylen = 5 else: keylen = encrypt['/Length'].getObject() // 8 key = _alg33_1(password, rev, keylen) real_O = encrypt["/O"].getObject() if rev == 2: userpass = utils.RC4_encrypt(key, real_O) else: val = real_O for i in range(19, -1, -1): new_key = b_('') for l in range(len(key)): new_key += b_(chr(utils.ord_(key[l]) ^ i)) val = utils.RC4_encrypt(new_key, val) userpass = val owner_password, key = self._authenticateUserPassword(userpass) if owner_password: self._decryption_key = key return 2 return 0 def _authenticateUserPassword(self, password): encrypt = self.trailer['/Encrypt'].getObject() rev = encrypt['/R'].getObject() owner_entry = encrypt['/O'].getObject() p_entry = encrypt['/P'].getObject() id_entry = self.trailer['/ID'].getObject() id1_entry = id_entry[0].getObject() real_U = encrypt['/U'].getObject().original_bytes if rev == 2: U, key = _alg34(password, owner_entry, p_entry, id1_entry) elif rev >= 3: U, key = _alg35(password, rev, encrypt["/Length"].getObject() // 8, owner_entry, p_entry, id1_entry, encrypt.get("/EncryptMetadata", BooleanObject(False)).getObject()) U, real_U = U[:16], real_U[:16] return U == real_U, key def getIsEncrypted(self): return "/Encrypt" in self.trailer isEncrypted = property(lambda self: self.getIsEncrypted(), None, None) """ Read-only boolean property showing whether this PDF file is encrypted. Note that this property, if true, will remain true even after the :meth:`decrypt()` method is called. """ def getRectangle(self, name, defaults): retval = self.get(name) if isinstance(retval, RectangleObject): return retval if retval == None: for d in defaults: retval = self.get(d) if retval != None: break if isinstance(retval, IndirectObject): retval = self.pdf.getObject(retval) retval = RectangleObject(retval) setRectangle(self, name, retval) return retval def setRectangle(self, name, value): if not isinstance(name, NameObject): name = NameObject(name) self[name] = value def deleteRectangle(self, name): del self[name] def createRectangleAccessor(name, fallback): return \ property( lambda self: getRectangle(self, name, fallback), lambda self, value: setRectangle(self, name, value), lambda self: deleteRectangle(self, name) ) class PageObject(DictionaryObject): """ This class represents a single page within a PDF file. Typically this object will be created by accessing the :meth:`getPage()` method of the :class:`PdfFileReader` class, but it is also possible to create an empty page with the :meth:`createBlankPage()` static method. :param pdf: PDF file the page belongs to. :param indirectRef: Stores the original indirect reference to this object in its source PDF """ def __init__(self, pdf=None, indirectRef=None): DictionaryObject.__init__(self) self.pdf = pdf self.indirectRef = indirectRef def createBlankPage(pdf=None, width=None, height=None): """ Returns a new blank page. If ``width`` or ``height`` is ``None``, try to get the page size from the last page of *pdf*. :param pdf: PDF file the page belongs to :param float width: The width of the new page expressed in default user space units. :param float height: The height of the new page expressed in default user space units. :return: the new blank page: :rtype: :class:`PageObject` :raises PageSizeNotDefinedError: if ``pdf`` is ``None`` or contains no page """ page = PageObject(pdf) # Creates a new page (cf PDF Reference 7.7.3.3) page.__setitem__(NameObject('/Type'), NameObject('/Page')) page.__setitem__(NameObject('/Parent'), NullObject()) page.__setitem__(NameObject('/Resources'), DictionaryObject()) if width is None or height is None: if pdf is not None and pdf.getNumPages() > 0: lastpage = pdf.getPage(pdf.getNumPages() - 1) width = lastpage.mediaBox.getWidth() height = lastpage.mediaBox.getHeight() else: raise utils.PageSizeNotDefinedError() page.__setitem__(NameObject('/MediaBox'), RectangleObject([0, 0, width, height])) return page createBlankPage = staticmethod(createBlankPage) def rotateClockwise(self, angle): """ Rotates a page clockwise by increments of 90 degrees. :param int angle: Angle to rotate the page. Must be an increment of 90 deg. """ assert angle % 90 == 0 self._rotate(angle) return self def rotateCounterClockwise(self, angle): """ Rotates a page counter-clockwise by increments of 90 degrees. :param int angle: Angle to rotate the page. Must be an increment of 90 deg. """ assert angle % 90 == 0 self._rotate(-angle) return self def _rotate(self, angle): currentAngle = self.get("/Rotate", 0) self[NameObject("/Rotate")] = NumberObject(currentAngle + angle) def _mergeResources(res1, res2, resource): newRes = DictionaryObject() newRes.update(res1.get(resource, DictionaryObject()).getObject()) page2Res = res2.get(resource, DictionaryObject()).getObject() renameRes = {} for key in list(page2Res.keys()): if key in newRes and newRes[key] != page2Res[key]: newname = NameObject(key + str(uuid.uuid4())) renameRes[key] = newname newRes[newname] = page2Res[key] elif key not in newRes: newRes[key] = page2Res.raw_get(key) return newRes, renameRes _mergeResources = staticmethod(_mergeResources) def _contentStreamRename(stream, rename, pdf): if not rename: return stream stream = ContentStream(stream, pdf) for operands, operator in stream.operations: for i in range(len(operands)): op = operands[i] if isinstance(op, NameObject): operands[i] = rename.get(op,op) return stream _contentStreamRename = staticmethod(_contentStreamRename) def _pushPopGS(contents, pdf): # adds a graphics state "push" and "pop" to the beginning and end # of a content stream. This isolates it from changes such as # transformation matricies. stream = ContentStream(contents, pdf) stream.operations.insert(0, [[], "q"]) stream.operations.append([[], "Q"]) return stream _pushPopGS = staticmethod(_pushPopGS) def _addTransformationMatrix(contents, pdf, ctm): # adds transformation matrix at the beginning of the given # contents stream. a, b, c, d, e, f = ctm contents = ContentStream(contents, pdf) contents.operations.insert(0, [[FloatObject(a), FloatObject(b), FloatObject(c), FloatObject(d), FloatObject(e), FloatObject(f)], " cm"]) return contents _addTransformationMatrix = staticmethod(_addTransformationMatrix) def getContents(self): """ Accesses the page contents. :return: the ``/Contents`` object, or ``None`` if it doesn't exist. ``/Contents`` is optional, as described in PDF Reference 7.7.3.3 """ if "/Contents" in self: return self["/Contents"].getObject() else: return None def mergePage(self, page2): """ Merges the content streams of two pages into one. Resource references (i.e. fonts) are maintained from both pages. The mediabox/cropbox/etc of this page are not altered. The parameter page's content stream will be added to the end of this page's content stream, meaning that it will be drawn after, or "on top" of this page. :param PageObject page2: The page to be merged into this one. Should be an instance of :class:`PageObject`. """ self._mergePage(page2) def _mergePage(self, page2, page2transformation=None, ctm=None, expand=False): # First we work on merging the resource dictionaries. This allows us # to find out what symbols in the content streams we might need to # rename. newResources = DictionaryObject() rename = {} originalResources = self["/Resources"].getObject() page2Resources = page2["/Resources"].getObject() newAnnots = ArrayObject() for page in (self, page2): if "/Annots" in page: annots = page["/Annots"] if isinstance(annots, ArrayObject): for ref in annots: newAnnots.append(ref) for res in "/ExtGState", "/Font", "/XObject", "/ColorSpace", "/Pattern", "/Shading", "/Properties": new, newrename = PageObject._mergeResources(originalResources, page2Resources, res) if new: newResources[NameObject(res)] = new rename.update(newrename) # Combine /ProcSet sets. newResources[NameObject("/ProcSet")] = ArrayObject( frozenset(originalResources.get("/ProcSet", ArrayObject()).getObject()).union( frozenset(page2Resources.get("/ProcSet", ArrayObject()).getObject()) ) ) newContentArray = ArrayObject() originalContent = self.getContents() if originalContent is not None: newContentArray.append(PageObject._pushPopGS( originalContent, self.pdf)) page2Content = page2.getContents() if page2Content is not None: if page2transformation is not None: page2Content = page2transformation(page2Content) page2Content = PageObject._contentStreamRename( page2Content, rename, self.pdf) page2Content = PageObject._pushPopGS(page2Content, self.pdf) newContentArray.append(page2Content) # if expanding the page to fit a new page, calculate the new media box size if expand: corners1 = [self.mediaBox.getLowerLeft_x().as_numeric(), self.mediaBox.getLowerLeft_y().as_numeric(), self.mediaBox.getUpperRight_x().as_numeric(), self.mediaBox.getUpperRight_y().as_numeric()] corners2 = [page2.mediaBox.getLowerLeft_x().as_numeric(), page2.mediaBox.getLowerLeft_y().as_numeric(), page2.mediaBox.getUpperLeft_x().as_numeric(), page2.mediaBox.getUpperLeft_y().as_numeric(), page2.mediaBox.getUpperRight_x().as_numeric(), page2.mediaBox.getUpperRight_y().as_numeric(), page2.mediaBox.getLowerRight_x().as_numeric(), page2.mediaBox.getLowerRight_y().as_numeric()] if ctm is not None: ctm = [float(x) for x in ctm] new_x = [ctm[0]*corners2[i] + ctm[2]*corners2[i+1] + ctm[4] for i in range(0, 8, 2)] new_y = [ctm[1]*corners2[i] + ctm[3]*corners2[i+1] + ctm[5] for i in range(0, 8, 2)] else: new_x = corners2[0:8:2] new_y = corners2[1:8:2] lowerleft = [min(new_x), min(new_y)] upperright = [max(new_x), max(new_y)] lowerleft = [min(corners1[0], lowerleft[0]), min(corners1[1], lowerleft[1])] upperright = [max(corners1[2], upperright[0]), max(corners1[3], upperright[1])] self.mediaBox.setLowerLeft(lowerleft) self.mediaBox.setUpperRight(upperright) self[NameObject('/Contents')] = ContentStream(newContentArray, self.pdf) self[NameObject('/Resources')] = newResources self[NameObject('/Annots')] = newAnnots def mergeTransformedPage(self, page2, ctm, expand=False): """ This is similar to mergePage, but a transformation matrix is applied to the merged stream. :param PageObject page2: The page to be merged into this one. Should be an instance of :class:`PageObject`. :param tuple ctm: a 6-element tuple containing the operands of the transformation matrix :param bool expand: Whether the page should be expanded to fit the dimensions of the page to be merged. """ self._mergePage(page2, lambda page2Content: PageObject._addTransformationMatrix(page2Content, page2.pdf, ctm), ctm, expand) def mergeScaledPage(self, page2, scale, expand=False): """ This is similar to mergePage, but the stream to be merged is scaled by appling a transformation matrix. :param PageObject page2: The page to be merged into this one. Should be an instance of :class:`PageObject`. :param float scale: The scaling factor :param bool expand: Whether the page should be expanded to fit the dimensions of the page to be merged. """ # CTM to scale : [ sx 0 0 sy 0 0 ] return self.mergeTransformedPage(page2, [scale, 0, 0, scale, 0, 0], expand) def mergeRotatedPage(self, page2, rotation, expand=False): """ This is similar to mergePage, but the stream to be merged is rotated by appling a transformation matrix. :param PageObject page2: the page to be merged into this one. Should be an instance of :class:`PageObject`. :param float rotation: The angle of the rotation, in degrees :param bool expand: Whether the page should be expanded to fit the dimensions of the page to be merged. """ rotation = math.radians(rotation) return self.mergeTransformedPage(page2, [math.cos(rotation), math.sin(rotation), -math.sin(rotation), math.cos(rotation), 0, 0], expand) def mergeTranslatedPage(self, page2, tx, ty, expand=False): """ This is similar to mergePage, but the stream to be merged is translated by appling a transformation matrix. :param PageObject page2: the page to be merged into this one. Should be an instance of :class:`PageObject`. :param float tx: The translation on X axis :param float ty: The translation on Y axis :param bool expand: Whether the page should be expanded to fit the dimensions of the page to be merged. """ return self.mergeTransformedPage(page2, [1, 0, 0, 1, tx, ty], expand) def mergeRotatedTranslatedPage(self, page2, rotation, tx, ty, expand=False): """ This is similar to mergePage, but the stream to be merged is rotated and translated by appling a transformation matrix. :param PageObject page2: the page to be merged into this one. Should be an instance of :class:`PageObject`. :param float tx: The translation on X axis :param float ty: The translation on Y axis :param float rotation: The angle of the rotation, in degrees :param bool expand: Whether the page should be expanded to fit the dimensions of the page to be merged. """ translation = [[1, 0, 0], [0, 1, 0], [-tx, -ty, 1]] rotation = math.radians(rotation) rotating = [[math.cos(rotation), math.sin(rotation), 0], [-math.sin(rotation), math.cos(rotation), 0], [0, 0, 1]] rtranslation = [[1, 0, 0], [0, 1, 0], [tx, ty, 1]] ctm = utils.matrixMultiply(translation, rotating) ctm = utils.matrixMultiply(ctm, rtranslation) return self.mergeTransformedPage(page2, [ctm[0][0], ctm[0][1], ctm[1][0], ctm[1][1], ctm[2][0], ctm[2][1]], expand) def mergeRotatedScaledPage(self, page2, rotation, scale, expand=False): """ This is similar to mergePage, but the stream to be merged is rotated and scaled by appling a transformation matrix. :param PageObject page2: the page to be merged into this one. Should be an instance of :class:`PageObject`. :param float rotation: The angle of the rotation, in degrees :param float scale: The scaling factor :param bool expand: Whether the page should be expanded to fit the dimensions of the page to be merged. """ rotation = math.radians(rotation) rotating = [[math.cos(rotation), math.sin(rotation), 0], [-math.sin(rotation), math.cos(rotation), 0], [0, 0, 1]] scaling = [[scale, 0, 0], [0, scale, 0], [0, 0, 1]] ctm = utils.matrixMultiply(rotating, scaling) return self.mergeTransformedPage(page2, [ctm[0][0], ctm[0][1], ctm[1][0], ctm[1][1], ctm[2][0], ctm[2][1]], expand) def mergeScaledTranslatedPage(self, page2, scale, tx, ty, expand=False): """ This is similar to mergePage, but the stream to be merged is translated and scaled by appling a transformation matrix. :param PageObject page2: the page to be merged into this one. Should be an instance of :class:`PageObject`. :param float scale: The scaling factor :param float tx: The translation on X axis :param float ty: The translation on Y axis :param bool expand: Whether the page should be expanded to fit the dimensions of the page to be merged. """ translation = [[1, 0, 0], [0, 1, 0], [tx, ty, 1]] scaling = [[scale, 0, 0], [0, scale, 0], [0, 0, 1]] ctm = utils.matrixMultiply(scaling, translation) return self.mergeTransformedPage(page2, [ctm[0][0], ctm[0][1], ctm[1][0], ctm[1][1], ctm[2][0], ctm[2][1]], expand) def mergeRotatedScaledTranslatedPage(self, page2, rotation, scale, tx, ty, expand=False): """ This is similar to mergePage, but the stream to be merged is translated, rotated and scaled by appling a transformation matrix. :param PageObject page2: the page to be merged into this one. Should be an instance of :class:`PageObject`. :param float tx: The translation on X axis :param float ty: The translation on Y axis :param float rotation: The angle of the rotation, in degrees :param float scale: The scaling factor :param bool expand: Whether the page should be expanded to fit the dimensions of the page to be merged. """ translation = [[1, 0, 0], [0, 1, 0], [tx, ty, 1]] rotation = math.radians(rotation) rotating = [[math.cos(rotation), math.sin(rotation), 0], [-math.sin(rotation), math.cos(rotation), 0], [0, 0, 1]] scaling = [[scale, 0, 0], [0, scale, 0], [0, 0, 1]] ctm = utils.matrixMultiply(rotating, scaling) ctm = utils.matrixMultiply(ctm, translation) return self.mergeTransformedPage(page2, [ctm[0][0], ctm[0][1], ctm[1][0], ctm[1][1], ctm[2][0], ctm[2][1]], expand) ## # Applys a transformation matrix the page. # # @param ctm A 6 elements tuple containing the operands of the # transformation matrix def addTransformation(self, ctm): """ Applies a transformation matrix to the page. :param tuple ctm: A 6-element tuple containing the operands of the transformation matrix. """ originalContent = self.getContents() if originalContent is not None: newContent = PageObject._addTransformationMatrix( originalContent, self.pdf, ctm) newContent = PageObject._pushPopGS(newContent, self.pdf) self[NameObject('/Contents')] = newContent def scale(self, sx, sy): """ Scales a page by the given factors by appling a transformation matrix to its content and updating the page size. :param float sx: The scaling factor on horizontal axis. :param float sy: The scaling factor on vertical axis. """ self.addTransformation([sx, 0, 0, sy, 0, 0]) self.mediaBox = RectangleObject([ float(self.mediaBox.getLowerLeft_x()) * sx, float(self.mediaBox.getLowerLeft_y()) * sy, float(self.mediaBox.getUpperRight_x()) * sx, float(self.mediaBox.getUpperRight_y()) * sy]) if "/VP" in self: viewport = self["/VP"] if isinstance(viewport, ArrayObject): bbox = viewport[0]["/BBox"] else: bbox = viewport["/BBox"] scaled_bbox = RectangleObject([ float(bbox[0]) * sx, float(bbox[1]) * sy, float(bbox[2]) * sx, float(bbox[3]) * sy]) if isinstance(viewport, ArrayObject): self[NameObject("/VP")][NumberObject(0)][NameObject("/BBox")] = scaled_bbox else: self[NameObject("/VP")][NameObject("/BBox")] = scaled_bbox def scaleBy(self, factor): """ Scales a page by the given factor by appling a transformation matrix to its content and updating the page size. :param float factor: The scaling factor (for both X and Y axis). """ self.scale(factor, factor) def scaleTo(self, width, height): """ Scales a page to the specified dimentions by appling a transformation matrix to its content and updating the page size. :param float width: The new width. :param float height: The new heigth. """ sx = width / float(self.mediaBox.getUpperRight_x() - self.mediaBox.getLowerLeft_x ()) sy = height / float(self.mediaBox.getUpperRight_y() - self.mediaBox.getLowerLeft_y ()) self.scale(sx, sy) def compressContentStreams(self): """ Compresses the size of this page by joining all content streams and applying a FlateDecode filter. However, it is possible that this function will perform no action if content stream compression becomes "automatic" for some reason. """ content = self.getContents() if content is not None: if not isinstance(content, ContentStream): content = ContentStream(content, self.pdf) self[NameObject("/Contents")] = content.flateEncode() def extractText(self): """ Locate all text drawing commands, in the order they are provided in the content stream, and extract the text. This works well for some PDF files, but poorly for others, depending on the generator used. This will be refined in the future. Do not rely on the order of text coming out of this function, as it will change if this function is made more sophisticated. :return: a unicode string object. """ text = u_("") content = self["/Contents"].getObject() if not isinstance(content, ContentStream): content = ContentStream(content, self.pdf) # Note: we check all strings are TextStringObjects. ByteStringObjects # are strings where the byte->string encoding was unknown, so adding # them to the text here would be gibberish. for operands, operator in content.operations: if operator == b_("Tj"): _text = operands[0] if isinstance(_text, TextStringObject): text += _text elif operator == b_("T*"): text += "\n" elif operator == b_("'"): text += "\n" _text = operands[0] if isinstance(_text, TextStringObject): text += operands[0] elif operator == b_('"'): _text = operands[2] if isinstance(_text, TextStringObject): text += "\n" text += _text elif operator == b_("TJ"): for i in operands[0]: if isinstance(i, TextStringObject): text += i text += "\n" return text mediaBox = createRectangleAccessor("/MediaBox", ()) """ A :class:`RectangleObject`, expressed in default user space units, defining the boundaries of the physical medium on which the page is intended to be displayed or printed. """ cropBox = createRectangleAccessor("/CropBox", ("/MediaBox",)) """ A :class:`RectangleObject`, expressed in default user space units, defining the visible region of default user space. When the page is displayed or printed, its contents are to be clipped (cropped) to this rectangle and then imposed on the output medium in some implementation-defined manner. Default value: same as :attr:`mediaBox`. """ bleedBox = createRectangleAccessor("/BleedBox", ("/CropBox", "/MediaBox")) """ A :class:`RectangleObject`, expressed in default user space units, defining the region to which the contents of the page should be clipped when output in a production enviroment. """ trimBox = createRectangleAccessor("/TrimBox", ("/CropBox", "/MediaBox")) """ A :class:`RectangleObject`, expressed in default user space units, defining the intended dimensions of the finished page after trimming. """ artBox = createRectangleAccessor("/ArtBox", ("/CropBox", "/MediaBox")) """ A :class:`RectangleObject`, expressed in default user space units, defining the extent of the page's meaningful content as intended by the page's creator. """ class ContentStream(DecodedStreamObject): def __init__(self, stream, pdf): self.pdf = pdf self.operations = [] # stream may be a StreamObject or an ArrayObject containing # multiple StreamObjects to be cat'd together. stream = stream.getObject() if isinstance(stream, ArrayObject): data = b_("") for s in stream: data += s.getObject().getData() stream = BytesIO(b_(data)) else: stream = BytesIO(b_(stream.getData())) self.__parseContentStream(stream) def __parseContentStream(self, stream): # file("f:\\tmp.txt", "w").write(stream.read()) stream.seek(0, 0) operands = [] while True: peek = readNonWhitespace(stream) if peek == b_('') or ord_(peek) == 0: break stream.seek(-1, 1) if peek.isalpha() or peek == b_("'") or peek == b_('"'): operator = utils.readUntilRegex(stream, NameObject.delimiterPattern, True) if operator == b_("BI"): # begin inline image - a completely different parsing # mechanism is required, of course... thanks buddy... assert operands == [] ii = self._readInlineImage(stream) self.operations.append((ii, b_("INLINE IMAGE"))) else: self.operations.append((operands, operator)) operands = [] elif peek == b_('%'): # If we encounter a comment in the content stream, we have to # handle it here. Typically, readObject will handle # encountering a comment -- but readObject assumes that # following the comment must be the object we're trying to # read. In this case, it could be an operator instead. while peek not in (b_('\r'), b_('\n')): peek = stream.read(1) else: operands.append(readObject(stream, None)) def _readInlineImage(self, stream): # begin reading just after the "BI" - begin image # first read the dictionary of settings. settings = DictionaryObject() while True: tok = readNonWhitespace(stream) stream.seek(-1, 1) if tok == b_("I"): # "ID" - begin of image data break key = readObject(stream, self.pdf) tok = readNonWhitespace(stream) stream.seek(-1, 1) value = readObject(stream, self.pdf) settings[key] = value # left at beginning of ID tmp = stream.read(3) assert tmp[:2] == b_("ID") data = b_("") while True: # Read the inline image, while checking for EI (End Image) operator. tok = stream.read(1) if tok == b_("E"): # Check for End Image tok2 = stream.read(1) if tok2 == b_("I"): # Sometimes that data will contain EI, so check for the Q operator. tok3 = stream.read(1) info = tok + tok2 while tok3 in utils.WHITESPACES: info += tok3 tok3 = stream.read(1) if tok3 == b_("Q"): stream.seek(-1, 1) break else: stream.seek(-1,1) data += info else: stream.seek(-1, 1) data += tok else: data += tok return {"settings": settings, "data": data} def _getData(self): newdata = BytesIO() for operands, operator in self.operations: if operator == "INLINE IMAGE": newdata.write("BI") dicttext = StringIO() operands["settings"].writeToStream(dicttext, None) newdata.write(dicttext.getvalue()[2:-2]) newdata.write("ID ") newdata.write(operands["data"]) newdata.write("EI") else: for op in operands: op.writeToStream(newdata, None) newdata.write(b_(" ")) newdata.write(b_(operator)) newdata.write(b_("\n")) return newdata.getvalue() def _setData(self, value): self.__parseContentStream(BytesIO(b_(value))) _data = property(_getData, _setData) class DocumentInformation(DictionaryObject): """ A class representing the basic document metadata provided in a PDF File. This class is accessible through :meth:`getDocumentInfo()` All text properties of the document metadata have *two* properties, eg. author and author_raw. The non-raw property will always return a ``TextStringObject``, making it ideal for a case where the metadata is being displayed. The raw property can sometimes return a ``ByteStringObject``, if PyPDF2 was unable to decode the string's text encoding; this requires additional safety in the caller and therefore is not as commonly accessed. """ def __init__(self): DictionaryObject.__init__(self) def getText(self, key): retval = self.get(key, None) if isinstance(retval, TextStringObject): return retval return None title = property(lambda self: self.getText("/Title")) """Read-only property accessing the document's **title**. Returns a unicode string (``TextStringObject``) or ``None`` if the title is not specified.""" title_raw = property(lambda self: self.get("/Title")) """The "raw" version of title; can return a ``ByteStringObject``.""" author = property(lambda self: self.getText("/Author")) """Read-only property accessing the document's **author**. Returns a unicode string (``TextStringObject``) or ``None`` if the author is not specified.""" author_raw = property(lambda self: self.get("/Author")) """The "raw" version of author; can return a ``ByteStringObject``.""" subject = property(lambda self: self.getText("/Subject")) """Read-only property accessing the document's **subject**. Returns a unicode string (``TextStringObject``) or ``None`` if the subject is not specified.""" subject_raw = property(lambda self: self.get("/Subject")) """The "raw" version of subject; can return a ``ByteStringObject``.""" creator = property(lambda self: self.getText("/Creator")) """Read-only property accessing the document's **creator**. If the document was converted to PDF from another format, this is the name of the application (e.g. OpenOffice) that created the original document from which it was converted. Returns a unicode string (``TextStringObject``) or ``None`` if the creator is not specified.""" creator_raw = property(lambda self: self.get("/Creator")) """The "raw" version of creator; can return a ``ByteStringObject``.""" producer = property(lambda self: self.getText("/Producer")) """Read-only property accessing the document's **producer**. If the document was converted to PDF from another format, this is the name of the application (for example, OSX Quartz) that converted it to PDF. Returns a unicode string (``TextStringObject``) or ``None`` if the producer is not specified.""" producer_raw = property(lambda self: self.get("/Producer")) """The "raw" version of producer; can return a ``ByteStringObject``.""" def convertToInt(d, size): if size > 8: raise utils.PdfReadError("invalid size in convertToInt") d = b_("\x00\x00\x00\x00\x00\x00\x00\x00") + b_(d) d = d[-8:] return struct.unpack(">q", d)[0] # ref: pdf1.8 spec section 3.5.2 algorithm 3.2 _encryption_padding = b_('\x28\xbf\x4e\x5e\x4e\x75\x8a\x41\x64\x00\x4e\x56') + \ b_('\xff\xfa\x01\x08\x2e\x2e\x00\xb6\xd0\x68\x3e\x80\x2f\x0c') + \ b_('\xa9\xfe\x64\x53\x69\x7a') # Implementation of algorithm 3.2 of the PDF standard security handler, # section 3.5.2 of the PDF 1.6 reference. def _alg32(password, rev, keylen, owner_entry, p_entry, id1_entry, metadata_encrypt=True): # 1. Pad or truncate the password string to exactly 32 bytes. If the # password string is more than 32 bytes long, use only its first 32 bytes; # if it is less than 32 bytes long, pad it by appending the required number # of additional bytes from the beginning of the padding string # (_encryption_padding). password = b_((str_(password) + str_(_encryption_padding))[:32]) # 2. Initialize the MD5 hash function and pass the result of step 1 as # input to this function. import struct m = md5(password) # 3. Pass the value of the encryption dictionary's /O entry to the MD5 hash # function. m.update(owner_entry.original_bytes) # 4. Treat the value of the /P entry as an unsigned 4-byte integer and pass # these bytes to the MD5 hash function, low-order byte first. p_entry = struct.pack('= 3 and not metadata_encrypt: m.update(b_("\xff\xff\xff\xff")) # 7. Finish the hash. md5_hash = m.digest() # 8. (Revision 3 or greater) Do the following 50 times: Take the output # from the previous MD5 hash and pass the first n bytes of the output as # input into a new MD5 hash, where n is the number of bytes of the # encryption key as defined by the value of the encryption dictionary's # /Length entry. if rev >= 3: for i in range(50): md5_hash = md5(md5_hash[:keylen]).digest() # 9. Set the encryption key to the first n bytes of the output from the # final MD5 hash, where n is always 5 for revision 2 but, for revision 3 or # greater, depends on the value of the encryption dictionary's /Length # entry. return md5_hash[:keylen] # Implementation of algorithm 3.3 of the PDF standard security handler, # section 3.5.2 of the PDF 1.6 reference. def _alg33(owner_pwd, user_pwd, rev, keylen): # steps 1 - 4 key = _alg33_1(owner_pwd, rev, keylen) # 5. Pad or truncate the user password string as described in step 1 of # algorithm 3.2. user_pwd = b_((user_pwd + str_(_encryption_padding))[:32]) # 6. Encrypt the result of step 5, using an RC4 encryption function with # the encryption key obtained in step 4. val = utils.RC4_encrypt(key, user_pwd) # 7. (Revision 3 or greater) Do the following 19 times: Take the output # from the previous invocation of the RC4 function and pass it as input to # a new invocation of the function; use an encryption key generated by # taking each byte of the encryption key obtained in step 4 and performing # an XOR operation between that byte and the single-byte value of the # iteration counter (from 1 to 19). if rev >= 3: for i in range(1, 20): new_key = '' for l in range(len(key)): new_key += chr(ord_(key[l]) ^ i) val = utils.RC4_encrypt(new_key, val) # 8. Store the output from the final invocation of the RC4 as the value of # the /O entry in the encryption dictionary. return val # Steps 1-4 of algorithm 3.3 def _alg33_1(password, rev, keylen): # 1. Pad or truncate the owner password string as described in step 1 of # algorithm 3.2. If there is no owner password, use the user password # instead. password = b_((password + str_(_encryption_padding))[:32]) # 2. Initialize the MD5 hash function and pass the result of step 1 as # input to this function. m = md5(password) # 3. (Revision 3 or greater) Do the following 50 times: Take the output # from the previous MD5 hash and pass it as input into a new MD5 hash. md5_hash = m.digest() if rev >= 3: for i in range(50): md5_hash = md5(md5_hash).digest() # 4. Create an RC4 encryption key using the first n bytes of the output # from the final MD5 hash, where n is always 5 for revision 2 but, for # revision 3 or greater, depends on the value of the encryption # dictionary's /Length entry. key = md5_hash[:keylen] return key # Implementation of algorithm 3.4 of the PDF standard security handler, # section 3.5.2 of the PDF 1.6 reference. def _alg34(password, owner_entry, p_entry, id1_entry): # 1. Create an encryption key based on the user password string, as # described in algorithm 3.2. key = _alg32(password, 2, 5, owner_entry, p_entry, id1_entry) # 2. Encrypt the 32-byte padding string shown in step 1 of algorithm 3.2, # using an RC4 encryption function with the encryption key from the # preceding step. U = utils.RC4_encrypt(key, _encryption_padding) # 3. Store the result of step 2 as the value of the /U entry in the # encryption dictionary. return U, key # Implementation of algorithm 3.4 of the PDF standard security handler, # section 3.5.2 of the PDF 1.6 reference. def _alg35(password, rev, keylen, owner_entry, p_entry, id1_entry, metadata_encrypt): # 1. Create an encryption key based on the user password string, as # described in Algorithm 3.2. key = _alg32(password, rev, keylen, owner_entry, p_entry, id1_entry) # 2. Initialize the MD5 hash function and pass the 32-byte padding string # shown in step 1 of Algorithm 3.2 as input to this function. m = md5() m.update(_encryption_padding) # 3. Pass the first element of the file's file identifier array (the value # of the ID entry in the document's trailer dictionary; see Table 3.13 on # page 73) to the hash function and finish the hash. (See implementation # note 25 in Appendix H.) m.update(id1_entry.original_bytes) md5_hash = m.digest() # 4. Encrypt the 16-byte result of the hash, using an RC4 encryption # function with the encryption key from step 1. val = utils.RC4_encrypt(key, md5_hash) # 5. Do the following 19 times: Take the output from the previous # invocation of the RC4 function and pass it as input to a new invocation # of the function; use an encryption key generated by taking each byte of # the original encryption key (obtained in step 2) and performing an XOR # operation between that byte and the single-byte value of the iteration # counter (from 1 to 19). for i in range(1, 20): new_key = b_('') for l in range(len(key)): new_key += b_(chr(ord_(key[l]) ^ i)) val = utils.RC4_encrypt(new_key, val) # 6. Append 16 bytes of arbitrary padding to the output from the final # invocation of the RC4 function and store the 32-byte result as the value # of the U entry in the encryption dictionary. # (implementator note: I don't know what "arbitrary padding" is supposed to # mean, so I have used null bytes. This seems to match a few other # people's implementations) return val + (b_('\x00') * 16), key PyPDF2-1.25.1/PyPDF2/utils.py000066400000000000000000000172311255324530700153340ustar00rootroot00000000000000# Copyright (c) 2006, Mathieu Fenniak # All rights reserved. # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions are # met: # # * Redistributions of source code must retain the above copyright notice, # this list of conditions and the following disclaimer. # * Redistributions in binary form must reproduce the above copyright notice, # this list of conditions and the following disclaimer in the documentation # and/or other materials provided with the distribution. # * The name of the author may not be used to endorse or promote products # derived from this software without specific prior written permission. # # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" # AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE # ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE # LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR # CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF # SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS # INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN # CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) # ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE # POSSIBILITY OF SUCH DAMAGE. """ Utility functions for PDF library. """ __author__ = "Mathieu Fenniak" __author_email__ = "biziqe@mathieu.fenniak.net" import sys try: import __builtin__ as builtins except ImportError: # Py3 import builtins xrange_fn = getattr(builtins, "xrange", range) _basestring = getattr(builtins, "basestring", str) bytes_type = type(bytes()) # Works the same in Python 2.X and 3.X string_type = getattr(builtins, "unicode", str) int_types = (int, long) if sys.version_info[0] < 3 else (int,) # Make basic type tests more consistent def isString(s): """Test if arg is a string. Compatible with Python 2 and 3.""" return isinstance(s, _basestring) def isInt(n): """Test if arg is an int. Compatible with Python 2 and 3.""" return isinstance(n, int_types) def isBytes(b): """Test if arg is a bytes instance. Compatible with Python 2 and 3.""" return isinstance(b, bytes_type) #custom implementation of warnings.formatwarning def formatWarning(message, category, filename, lineno, line=None): file = filename.replace("/", "\\").rsplit("\\", 1)[1] # find the file name return "%s: %s [%s:%s]\n" % (category.__name__, message, file, lineno) def readUntilWhitespace(stream, maxchars=None): """ Reads non-whitespace characters and returns them. Stops upon encountering whitespace or when maxchars is reached. """ txt = b_("") while True: tok = stream.read(1) if tok.isspace() or not tok: break txt += tok if len(txt) == maxchars: break return txt def readNonWhitespace(stream): """ Finds and reads the next non-whitespace character (ignores whitespace). """ tok = WHITESPACES[0] while tok in WHITESPACES: tok = stream.read(1) return tok def skipOverWhitespace(stream): """ Similar to readNonWhitespace, but returns a Boolean if more than one whitespace character was read. """ tok = WHITESPACES[0] cnt = 0; while tok in WHITESPACES: tok = stream.read(1) cnt+=1 return (cnt > 1) def skipOverComment(stream): tok = stream.read(1) stream.seek(-1, 1) if tok == b_('%'): while tok not in (b_('\n'), b_('\r')): tok = stream.read(1) def readUntilRegex(stream, regex, ignore_eof=False): """ Reads until the regular expression pattern matched (ignore the match) Raise PdfStreamError on premature end-of-file. :param bool ignore_eof: If true, ignore end-of-line and return immediately """ name = b_('') while True: tok = stream.read(16) if not tok: # stream has truncated prematurely if ignore_eof == True: return name else: raise PdfStreamError("Stream has ended unexpectedly") m = regex.search(tok) if m is not None: name += tok[:m.start()] stream.seek(m.start()-len(tok), 1) break name += tok return name class ConvertFunctionsToVirtualList(object): def __init__(self, lengthFunction, getFunction): self.lengthFunction = lengthFunction self.getFunction = getFunction def __len__(self): return self.lengthFunction() def __getitem__(self, index): if isinstance(index, slice): indices = xrange_fn(*index.indices(len(self))) cls = type(self) return cls(indices.__len__, lambda idx: self[indices[idx]]) if not isInt(index): raise TypeError("sequence indices must be integers") len_self = len(self) if index < 0: # support negative indexes index = len_self + index if index < 0 or index >= len_self: raise IndexError("sequence index out of range") return self.getFunction(index) def RC4_encrypt(key, plaintext): S = [i for i in range(256)] j = 0 for i in range(256): j = (j + S[i] + ord_(key[i % len(key)])) % 256 S[i], S[j] = S[j], S[i] i, j = 0, 0 retval = b_("") for x in range(len(plaintext)): i = (i + 1) % 256 j = (j + S[i]) % 256 S[i], S[j] = S[j], S[i] t = S[(S[i] + S[j]) % 256] retval += b_(chr(ord_(plaintext[x]) ^ t)) return retval def matrixMultiply(a, b): return [[sum([float(i)*float(j) for i, j in zip(row, col)] ) for col in zip(*b)] for row in a] def markLocation(stream): """Creates text file showing current location in context.""" # Mainly for debugging RADIUS = 5000 stream.seek(-RADIUS, 1) outputDoc = open('PyPDF2_pdfLocation.txt', 'w') outputDoc.write(stream.read(RADIUS)) outputDoc.write('HERE') outputDoc.write(stream.read(RADIUS)) outputDoc.close() stream.seek(-RADIUS, 1) class PyPdfError(Exception): pass class PdfReadError(PyPdfError): pass class PageSizeNotDefinedError(PyPdfError): pass class PdfReadWarning(UserWarning): pass class PdfStreamError(PdfReadError): pass if sys.version_info[0] < 3: def b_(s): return s else: B_CACHE = {} def b_(s): bc = B_CACHE if s in bc: return bc[s] if type(s) == bytes: return s else: r = s.encode('latin-1') if len(s) < 2: bc[s] = r return r def u_(s): if sys.version_info[0] < 3: return unicode(s, 'unicode_escape') else: return s def str_(b): if sys.version_info[0] < 3: return b else: if type(b) == bytes: return b.decode('latin-1') else: return b def ord_(b): if sys.version_info[0] < 3 or type(b) == str: return ord(b) else: return b def chr_(c): if sys.version_info[0] < 3: return c else: return chr(c) def barray(b): if sys.version_info[0] < 3: return b else: return bytearray(b) def hexencode(b): if sys.version_info[0] < 3: return b.encode('hex') else: import codecs coder = codecs.getencoder('hex_codec') return coder(b)[0] def hexStr(num): return hex(num).replace('L', '') WHITESPACES = [b_(x) for x in [' ', '\n', '\r', '\t', '\x00']] PyPDF2-1.25.1/PyPDF2/xmp.py000066400000000000000000000325071255324530700150030ustar00rootroot00000000000000import re import datetime import decimal from .generic import PdfObject from xml.dom import getDOMImplementation from xml.dom.minidom import parseString from .utils import u_ RDF_NAMESPACE = "http://www.w3.org/1999/02/22-rdf-syntax-ns#" DC_NAMESPACE = "http://purl.org/dc/elements/1.1/" XMP_NAMESPACE = "http://ns.adobe.com/xap/1.0/" PDF_NAMESPACE = "http://ns.adobe.com/pdf/1.3/" XMPMM_NAMESPACE = "http://ns.adobe.com/xap/1.0/mm/" # What is the PDFX namespace, you might ask? I might ask that too. It's # a completely undocumented namespace used to place "custom metadata" # properties, which are arbitrary metadata properties with no semantic or # documented meaning. Elements in the namespace are key/value-style storage, # where the element name is the key and the content is the value. The keys # are transformed into valid XML identifiers by substituting an invalid # identifier character with \u2182 followed by the unicode hex ID of the # original character. A key like "my car" is therefore "my\u21820020car". # # \u2182, in case you're wondering, is the unicode character # \u{ROMAN NUMERAL TEN THOUSAND}, a straightforward and obvious choice for # escaping characters. # # Intentional users of the pdfx namespace should be shot on sight. A # custom data schema and sensical XML elements could be used instead, as is # suggested by Adobe's own documentation on XMP (under "Extensibility of # Schemas"). # # Information presented here on the /pdfx/ schema is a result of limited # reverse engineering, and does not constitute a full specification. PDFX_NAMESPACE = "http://ns.adobe.com/pdfx/1.3/" iso8601 = re.compile(""" (?P[0-9]{4}) (- (?P[0-9]{2}) (- (?P[0-9]+) (T (?P[0-9]{2}): (?P[0-9]{2}) (:(?P[0-9]{2}(.[0-9]+)?))? (?PZ|[-+][0-9]{2}:[0-9]{2}) )? )? )? """, re.VERBOSE) class XmpInformation(PdfObject): """ An object that represents Adobe XMP metadata. Usually accessed by :meth:`getXmpMetadata()` """ def __init__(self, stream): self.stream = stream docRoot = parseString(self.stream.getData()) self.rdfRoot = docRoot.getElementsByTagNameNS(RDF_NAMESPACE, "RDF")[0] self.cache = {} def writeToStream(self, stream, encryption_key): self.stream.writeToStream(stream, encryption_key) def getElement(self, aboutUri, namespace, name): for desc in self.rdfRoot.getElementsByTagNameNS(RDF_NAMESPACE, "Description"): if desc.getAttributeNS(RDF_NAMESPACE, "about") == aboutUri: attr = desc.getAttributeNodeNS(namespace, name) if attr != None: yield attr for element in desc.getElementsByTagNameNS(namespace, name): yield element def getNodesInNamespace(self, aboutUri, namespace): for desc in self.rdfRoot.getElementsByTagNameNS(RDF_NAMESPACE, "Description"): if desc.getAttributeNS(RDF_NAMESPACE, "about") == aboutUri: for i in range(desc.attributes.length): attr = desc.attributes.item(i) if attr.namespaceURI == namespace: yield attr for child in desc.childNodes: if child.namespaceURI == namespace: yield child def _getText(self, element): text = "" for child in element.childNodes: if child.nodeType == child.TEXT_NODE: text += child.data return text def _converter_string(value): return value def _converter_date(value): m = iso8601.match(value) year = int(m.group("year")) month = int(m.group("month") or "1") day = int(m.group("day") or "1") hour = int(m.group("hour") or "0") minute = int(m.group("minute") or "0") second = decimal.Decimal(m.group("second") or "0") seconds = second.to_integral(decimal.ROUND_FLOOR) milliseconds = (second - seconds) * 1000000 tzd = m.group("tzd") or "Z" dt = datetime.datetime(year, month, day, hour, minute, seconds, milliseconds) if tzd != "Z": tzd_hours, tzd_minutes = [int(x) for x in tzd.split(":")] tzd_hours *= -1 if tzd_hours < 0: tzd_minutes *= -1 dt = dt + datetime.timedelta(hours=tzd_hours, minutes=tzd_minutes) return dt _test_converter_date = staticmethod(_converter_date) def _getter_bag(namespace, name, converter): def get(self): cached = self.cache.get(namespace, {}).get(name) if cached: return cached retval = [] for element in self.getElement("", namespace, name): bags = element.getElementsByTagNameNS(RDF_NAMESPACE, "Bag") if len(bags): for bag in bags: for item in bag.getElementsByTagNameNS(RDF_NAMESPACE, "li"): value = self._getText(item) value = converter(value) retval.append(value) ns_cache = self.cache.setdefault(namespace, {}) ns_cache[name] = retval return retval return get def _getter_seq(namespace, name, converter): def get(self): cached = self.cache.get(namespace, {}).get(name) if cached: return cached retval = [] for element in self.getElement("", namespace, name): seqs = element.getElementsByTagNameNS(RDF_NAMESPACE, "Seq") if len(seqs): for seq in seqs: for item in seq.getElementsByTagNameNS(RDF_NAMESPACE, "li"): value = self._getText(item) value = converter(value) retval.append(value) else: value = converter(self._getText(element)) retval.append(value) ns_cache = self.cache.setdefault(namespace, {}) ns_cache[name] = retval return retval return get def _getter_langalt(namespace, name, converter): def get(self): cached = self.cache.get(namespace, {}).get(name) if cached: return cached retval = {} for element in self.getElement("", namespace, name): alts = element.getElementsByTagNameNS(RDF_NAMESPACE, "Alt") if len(alts): for alt in alts: for item in alt.getElementsByTagNameNS(RDF_NAMESPACE, "li"): value = self._getText(item) value = converter(value) retval[item.getAttribute("xml:lang")] = value else: retval["x-default"] = converter(self._getText(element)) ns_cache = self.cache.setdefault(namespace, {}) ns_cache[name] = retval return retval return get def _getter_single(namespace, name, converter): def get(self): cached = self.cache.get(namespace, {}).get(name) if cached: return cached value = None for element in self.getElement("", namespace, name): if element.nodeType == element.ATTRIBUTE_NODE: value = element.nodeValue else: value = self._getText(element) break if value != None: value = converter(value) ns_cache = self.cache.setdefault(namespace, {}) ns_cache[name] = value return value return get dc_contributor = property(_getter_bag(DC_NAMESPACE, "contributor", _converter_string)) """ Contributors to the resource (other than the authors). An unsorted array of names. """ dc_coverage = property(_getter_single(DC_NAMESPACE, "coverage", _converter_string)) """ Text describing the extent or scope of the resource. """ dc_creator = property(_getter_seq(DC_NAMESPACE, "creator", _converter_string)) """ A sorted array of names of the authors of the resource, listed in order of precedence. """ dc_date = property(_getter_seq(DC_NAMESPACE, "date", _converter_date)) """ A sorted array of dates (datetime.datetime instances) of signifigance to the resource. The dates and times are in UTC. """ dc_description = property(_getter_langalt(DC_NAMESPACE, "description", _converter_string)) """ A language-keyed dictionary of textual descriptions of the content of the resource. """ dc_format = property(_getter_single(DC_NAMESPACE, "format", _converter_string)) """ The mime-type of the resource. """ dc_identifier = property(_getter_single(DC_NAMESPACE, "identifier", _converter_string)) """ Unique identifier of the resource. """ dc_language = property(_getter_bag(DC_NAMESPACE, "language", _converter_string)) """ An unordered array specifying the languages used in the resource. """ dc_publisher = property(_getter_bag(DC_NAMESPACE, "publisher", _converter_string)) """ An unordered array of publisher names. """ dc_relation = property(_getter_bag(DC_NAMESPACE, "relation", _converter_string)) """ An unordered array of text descriptions of relationships to other documents. """ dc_rights = property(_getter_langalt(DC_NAMESPACE, "rights", _converter_string)) """ A language-keyed dictionary of textual descriptions of the rights the user has to this resource. """ dc_source = property(_getter_single(DC_NAMESPACE, "source", _converter_string)) """ Unique identifier of the work from which this resource was derived. """ dc_subject = property(_getter_bag(DC_NAMESPACE, "subject", _converter_string)) """ An unordered array of descriptive phrases or keywrods that specify the topic of the content of the resource. """ dc_title = property(_getter_langalt(DC_NAMESPACE, "title", _converter_string)) """ A language-keyed dictionary of the title of the resource. """ dc_type = property(_getter_bag(DC_NAMESPACE, "type", _converter_string)) """ An unordered array of textual descriptions of the document type. """ pdf_keywords = property(_getter_single(PDF_NAMESPACE, "Keywords", _converter_string)) """ An unformatted text string representing document keywords. """ pdf_pdfversion = property(_getter_single(PDF_NAMESPACE, "PDFVersion", _converter_string)) """ The PDF file version, for example 1.0, 1.3. """ pdf_producer = property(_getter_single(PDF_NAMESPACE, "Producer", _converter_string)) """ The name of the tool that created the PDF document. """ xmp_createDate = property(_getter_single(XMP_NAMESPACE, "CreateDate", _converter_date)) """ The date and time the resource was originally created. The date and time are returned as a UTC datetime.datetime object. """ xmp_modifyDate = property(_getter_single(XMP_NAMESPACE, "ModifyDate", _converter_date)) """ The date and time the resource was last modified. The date and time are returned as a UTC datetime.datetime object. """ xmp_metadataDate = property(_getter_single(XMP_NAMESPACE, "MetadataDate", _converter_date)) """ The date and time that any metadata for this resource was last changed. The date and time are returned as a UTC datetime.datetime object. """ xmp_creatorTool = property(_getter_single(XMP_NAMESPACE, "CreatorTool", _converter_string)) """ The name of the first known tool used to create the resource. """ xmpmm_documentId = property(_getter_single(XMPMM_NAMESPACE, "DocumentID", _converter_string)) """ The common identifier for all versions and renditions of this resource. """ xmpmm_instanceId = property(_getter_single(XMPMM_NAMESPACE, "InstanceID", _converter_string)) """ An identifier for a specific incarnation of a document, updated each time a file is saved. """ def custom_properties(self): if not hasattr(self, "_custom_properties"): self._custom_properties = {} for node in self.getNodesInNamespace("", PDFX_NAMESPACE): key = node.localName while True: # see documentation about PDFX_NAMESPACE earlier in file idx = key.find(u_("\u2182")) if idx == -1: break key = key[:idx] + chr(int(key[idx+1:idx+5], base=16)) + key[idx+5:] if node.nodeType == node.ATTRIBUTE_NODE: value = node.nodeValue else: value = self._getText(node) self._custom_properties[key] = value return self._custom_properties custom_properties = property(custom_properties) """ Retrieves custom metadata properties defined in the undocumented pdfx metadata schema. :return: a dictionary of key/value items for custom metadata properties. :rtype: dict """ PyPDF2-1.25.1/README.md000066400000000000000000000013341255324530700140720ustar00rootroot00000000000000#PyPDF2 PyPDF2 is a pure-python PDF library capable of splitting, merging together, cropping, and transforming the pages of PDF files. It can also add custom data, viewing options, and passwords to PDF files. It can retrieve text and metadata from PDFs as well as merge entire files together. Homepage http://mstamy2.github.io/PyPDF2/ ##Examples Please see `sample code` folder ##Documentation Documentation is available at https://pythonhosted.org/PyPDF2/ ##FAQ Please see http://mstamy2.github.io/PyPDF2/FAQ.html ##Tests PyPDF2 includes a test suite built on the unittest framework. All tests are located in the "Tests" folder. Tests can be run from the command line by: ```bash python -m unittest Tests.tests ```PyPDF2-1.25.1/Resources/000077500000000000000000000000001255324530700145645ustar00rootroot00000000000000PyPDF2-1.25.1/Resources/crazyones.pdf000066400000000000000000000262701255324530700173030ustar00rootroot00000000000000%PDF-1.5 % 7 0 obj <> stream x}V]o@|5)JVQ*d>\` swu~}=خ>vggfA,'K]y όUA7`oFیACEL;'ؓɌj^PzuOKgnK%3Էt|PwN'%{8sӚ 0pS.jFݩ,%vJwcYS;?2J9_(X 5\pΏ vj;!9iP୾2K.bzamlK?_0^&otk]k..mFzsoRQ endstream endobj 12 0 obj <> stream x]Ukp]Ytq\ (j4Ibj3 S 6+` ~aY%[XkҮiӲ--dicp0kJӦL2ә^ ]ӹ3ߏsϞ+! D2s͚W)`qnnToiDjNZ5)ORdʌzyvΘ̩:_,h,B*Ϟ(g@~nVS^_;qOMd*bQB!ʉ %&M,!VD8$η;4BBg$rJKO7lLn$ͽfQܘܐJ)?ߑ,7yG,f {_joysB8(C{96W]l>!K\69[ԭr1@ ]~8O_Uގ@'t )eH'0 TQ,V eB"/n6wM.z nJsK1JL(jTh \pe/HqO+s%bsJI sBe jpWjo]%x?N$G#2, ̃ہ ݆IwǮɟ(i1f[,E4/i_;~l4. FZicbmW`[Ԋ" .)!Sda)wpqZ;v: ~b`s՟\g Ԡ1k@~O'Bp!Kdr%*mԖ& &&kJljnBK}'|C~A6]d:`0^_E "`?yTް/≠N[D@h4 qM}u{A*39ODpee,Bx]Z]fg~[}\ݭWpx(2thp}h=TO]9peblQ~ppzsChEGwG~*v5e6vN gNC+n|^0X%MS)֦Jz\:Tq^T5A"tɀ,jS:^tw9F7ת⿿}:*?Ն jBH0|'';N j)կ 蠣S ".> Y٩V(ѕKeBxRI rӜ!Z[vS&g=vDˡZMW6h5%BnPn\|AV-NpFm}SҵA&o±9<6kR5"3gC Cs:%;ZtˍNS 4!Kt'~$1* Q.TSb>\ 0 >1}Slyk 9;AK2G( ܬ>ztAOb> <7Xu^'KtŏtLL5.K jG^$O@K 5Mk5vO|Իu[ (/@eye=;fZxHXkTٯ47hAsj!FBd/iTkthv|wTLx.>1PZp6: y1d&/V2NŦmn%&ËDh@1٤*Cy#{'3x.5ϐ"'f)JH&df v3~@3}t@LЮs.Xq ^3^t(LM2W{ ϸiWDzC>Aynh`Zz1YY\oFWd- 3v'{ଫb CBnL(Lidyִ@V'G/ +Glx endstream endobj 14 0 obj <> stream x]kpWY] )fA%@&$i. O&1`a[~Jڕ,)!6vyLyHI[4isLsfܹsUDj*R};'o[6yJ9B"WӟoN}"I͔9oJLO96#&2%iIUԹK3_~mCm!nⒺ9Uo Ti?$^!E#yӉE|Kdlb##)H!6_nիԿH5>R2YyZ0[^k&NuPKrw8+y:7& TUVMSB!o_{m/fft'[X%ֶ V,HZt[( .@@d B;>2pzTȋu9-|y5o[݊bIheƿS&3>~8QbKVunâ-BOb!8=R8j܂](ZW bzۅ(Qn+yj]0F!_ŃP0|W#m6@Nugkv60P*'X4G;*vG  8Jlr|gtϣj|ZQ(~?}`EaOSupp%h @'&.涱/\| [NVF֦7~rI׮i?119>sܦ5C8q; YPt9|S-X6]0 7]<^/3Q|eɳQ]P0ՀccW4<\`y3K~#*48kL 袼C$p J>.C^ P=R, Re`~ûd!eO x7ՉĩG$V[$%;k\z9Eu,Fiq;v;zEˋ ȧkݠskOX?4蠙mp!mˮ] g+YPv4*x4EFoy%AKu.W+7W*HNܹAƑғ[[UT_P֡5ǖ~M߅{F~+ Hd,P\0y;0_ q*z?tRa rt]RhͩI<'O<9n{lʶ(lb0V.%kt!x>_4YZ6J*i2ZL`BM.> tv h/3\߿)8Ne[@yANKk(Pbܯu[Ve",ѽ8O\fmtb(@!`r\\ޭP[ZL9-nz]փu}c>J\=xTXc{=:}I<4I&!f6]*lo!O'ڇʏ!rk `tX[3sC&#d,vA3zH>ibz>QڙitVTؘ5Yqx endstream endobj 16 0 obj <> stream xڍX |Sei齗Qn",R]M4iMINiM۴iҍRv<2*AFG|]P?K,sCEp8IVnJNY9{k-7/ȃD䡘ȴoF{}_/M#71*'E2b<z`ּO/I 2R 4?}HrsEb "XKl""ΝHpyxb"17b;,7xxxXB,%ˉJb^#|V2>-1310'S;%بEqc8ju7F}s1^'wzb _O3$ۓ1KS9 $e̱UȌ0 a;Y"CSFr˄Kz2X@-=1a?E`I0̒X2ϩs/gjepVjTPLKmm McI;4)ɗ$8rNLa2UA*Pfǰy;xڠU۪,Q*A%b<lϋٞK 8pYQfu S9* GӢ(Iu BR8I5M-': aWeyHiY,hnjg,Euq,L3Me)Eu4V~Vx(!%Z-qlZ{G(ݯzg]B$ky/m.=rX uDĢ"' AL7;vy{QϞ# (AF+"^?x}x<쪔&,*zZeS֙kL;Ύ61J}9 T˪o4FEGJ3h=;/Z.ZCa_Ɣך(5٪twҜ )YWz[ov#Шl)M a=, Afnz+P2YW jt Dd|ub>q*1C40#S`eε}x4hMW^uPo; Q;XH##;spgy Ns#o^?pnˉMԖ$9 zC<9v*)Q(TƠ$7r%AT*kCa韡bh0LV@o#  ^jg~'6ZS.)<(V JvURa0owc#=Wc_ө2jz0mCͿ )bNyMvi,ɷUX>Mdm_@ hUlo6ݻO2PnR-đʠ~YŔB*e j}iߤ) B׃NG'5$}%Y`g;V>Ď~58[Cň)Ac~c-fv)ž~y- 3@VÞhwiO*L*s dF`)aM5y\k9 T?Jps.sSl+J:gq}la!*kL6-6a49BivⰙU*K[l߳ջͻu "i0 ,-6!D~WA~]wqĨ8)1 m&Ksfe̙+QKh#YbN7ma+l&/m*PuAW%ocNzt^Gg#UGj2u~~9k#%c;ϜyoYu vqF0sX,~@5p j{M}˃CG{_?r6j:ll1ܩ,{$5JJ&Z<_lAk * =}2/_ r >=W .jkKS kI9 HJGf;NԤ> O )X)1jfPS'~87E#{-.wh͢{Q[mY=0@DHgV"!rPԧCUpoTмޔ#4ַh&OlE;w] 3DY]ji$j SQwou㻯qϣ" P]\ Z+h7^XcU$K1Oׇ̜xgopl9qk4V S|ul,'M"]$iҡzZcѻQ]ԁ6:Iڔ4c;%oh`i h+.\F,]ysS5)(D~I(UiT⭐YMhon ꁡIC{ZKN:>(TCG:݅&9t4M0 57YLV]1OU.KK!z 6L ^Rc/ 641,Q0 ,kwſJժ2L}Ƣ@LnMc^+uEbLFMkGC*Rw -uh H)lC{wGbB?\=ƱZct1n}ҍEW.DuVT]]"_>aP%:4@ T-r>3ݾPVYvQ@'߀ڥ>V!a`vBSEP0iن %&}@)!GQeў(}T{& 4& 4q'Gf")hueSޔD9,"E"K)CeC^-XcD㏰T\P|l{FKutl%1.)֣"_1̚5? ̧|;UӊK)Wv6ٜ5:[ۑzp[wYtiQ*ފ(p|卻Od}afSG =P %7+J:O NިuTo!_°H==) GQVe(K)A0nG.~ ;UX#ˢ",.~$W*]MUWU:KO/s~Q`/ ]:T :pͨ}p#@&KW~)#Wq4@S4v.>ptPmƳ~{A4!]|,E>+M*(̈́%|Cc=OBv%"3w.ܣT(%'`+Ӕyl";@ Ƣ/OQFHΠ}_6}&I3`̂3b2)=3?wG#7y&vU\Va!'R~A Jf,$\Z{W6qd'Wp l &0yF[1?Q[mi5+,}y/&UýՄixʡwV1e@j"ͷʀ^6QoMoaT%.ԫ,12\jvu <27 DEA`;=4'r$3Rk9+iM;Vy|cx+բu+>ʠ~W{y"KS82 s#x-|)w;ߪRP',-޺nۚM) i|oC׊lݹ=˦QCF> stream x]Pn -/E"Œ<>Aqp)@ٝMw휍#LoFc xT׋ 7*|iooC+^t{@8uw5ҹɃ '5WG|'[B]u-Ai$fdjm[3t_`QĤK"ͬMoDɷ\$H*m endstream endobj 9 0 obj <> stream xUmO0ί7&w'FmQmL@ TnD*IiJӱI|q|#DpFH I%LPH% `Jt;m x]@)gi\>zA6̳Еczӑ[t[Mjܷ*D>K'wi ò8oWi1C/4;z! $b]\fq#wCU\P?3S'\JRˏor:[Vdr(:,3tO ;YKRpɣ*A1^2}r>v z<'.&}{>Go4` fk>sf8n 2:V Lԫ$z+=Kd%1P6YO&#= endstream endobj 22 0 obj <<0f88455ebb8b4e2ee3518ebbf9ed40fe>]/Size 23/W[1 2 2]/Filter/FlateDecode/Length 76>> stream x% @0VQE 0Y*{Z DLT@Db|=]ʢ 1 endstream endobj startxref 11160 %%EOF PyPDF2-1.25.1/Resources/crazyones.txt000066400000000000000000000013331255324530700173420ustar00rootroot00000000000000TheCrazyOnesOctober14,1998Herestothecrazyones.Themis˝ts.Therebels.Thetroublemakers.Theroundpegsinthesquareholes.Theoneswhoseethingsdi˙erently.Theyrenotfondofrules.Andtheyhavenorespectforthestatusquo.Youcanquotethem,disagreewiththem,glorifyorvilifythem.Abouttheonlythingyoucantdoisignorethem.Becausetheychangethings.Theyinvent.Theyimagine.Theyheal.Theyexplore.Theycreate.Theyinspire.Theypushthehumanraceforward.Maybetheyhavetobecrazy.Howelsecanyoustareatanemptycanvasandseeaworkofart?Orsitinsilenceandhearasongthatsneverbeenwritten?Orgazeataredplanetandseealaboratoryonwheels?Wemaketoolsforthesekindsofpeople.Whilesomeseethemasthecrazyones,weseegenius.Becausethepeoplewhoarecrazyenoughtothinktheycanchangetheworld,aretheoneswhodo.PyPDF2-1.25.1/Sample_Code/000077500000000000000000000000001255324530700147655ustar00rootroot00000000000000PyPDF2-1.25.1/Sample_Code/README.txt000066400000000000000000000005661255324530700164720ustar00rootroot00000000000000PyPDF2 Sample Code Folder ------------------------- This will contain demonstrations of the many features PyPDF2 is capable of. Example code should make it easy for users to know how to use all aspects of PyPDF2. Feel free to add any type of PDF file or sample code, either by 1) sending it via email to PyPDF2@phaseit.net 2) including it in a pull request on GitHubPyPDF2-1.25.1/Sample_Code/basic_features.py000066400000000000000000000027631255324530700203260ustar00rootroot00000000000000from PyPDF2 import PdfFileWriter, PdfFileReader output = PdfFileWriter() input1 = PdfFileReader(open("document1.pdf", "rb")) # print how many pages input1 has: print "document1.pdf has %d pages." % input1.getNumPages() # add page 1 from input1 to output document, unchanged output.addPage(input1.getPage(0)) # add page 2 from input1, but rotated clockwise 90 degrees output.addPage(input1.getPage(1).rotateClockwise(90)) # add page 3 from input1, rotated the other way: output.addPage(input1.getPage(2).rotateCounterClockwise(90)) # alt: output.addPage(input1.getPage(2).rotateClockwise(270)) # add page 4 from input1, but first add a watermark from another PDF: page4 = input1.getPage(3) watermark = PdfFileReader(open("watermark.pdf", "rb")) page4.mergePage(watermark.getPage(0)) output.addPage(page4) # add page 5 from input1, but crop it to half size: page5 = input1.getPage(4) page5.mediaBox.upperRight = ( page5.mediaBox.getUpperRight_x() / 2, page5.mediaBox.getUpperRight_y() / 2 ) output.addPage(page5) # add some Javascript to launch the print window on opening this PDF. # the password dialog may prevent the print dialog from being shown, # comment the the encription lines, if that's the case, to try this out output.addJS("this.print({bUI:true,bSilent:false,bShrinkToFit:true});") # encrypt your new PDF and add a password password = "secret" output.encrypt(password) # finally, write "output" to document-output.pdf outputStream = file("PyPDF2-output.pdf", "wb") output.write(outputStream) PyPDF2-1.25.1/Sample_Code/basic_merging.py000066400000000000000000000011331255324530700201260ustar00rootroot00000000000000from PyPDF2 import PdfFileMerger merger = PdfFileMerger() input1 = open("document1.pdf", "rb") input2 = open("document2.pdf", "rb") input3 = open("document3.pdf", "rb") # add the first 3 pages of input1 document to output merger.append(fileobj = input1, pages = (0,3)) # insert the first page of input2 into the output beginning after the second page merger.merge(position = 2, fileobj = input2, pages = (0,1)) # append entire input3 document to the end of the output document merger.append(input3) # Write to an output PDF document output = open("document-output.pdf", "wb") merger.write(output) PyPDF2-1.25.1/Sample_Code/makesimple.py000077500000000000000000000017211255324530700174720ustar00rootroot00000000000000#!/usr/bin/env python "Make some simple multipage pdf files." from __future__ import print_function from sys import argv from reportlab.pdfgen import canvas point = 1 inch = 72 TEXT = """%s page %d of %d a wonderful file created with Sample_Code/makesimple.py""" def make_pdf_file(output_filename, np): title = output_filename c = canvas.Canvas(output_filename, pagesize=(8.5 * inch, 11 * inch)) c.setStrokeColorRGB(0,0,0) c.setFillColorRGB(0,0,0) c.setFont("Helvetica", 12 * point) for pn in range(1, np + 1): v = 10 * inch for subtline in (TEXT % (output_filename, pn, np)).split( '\n' ): c.drawString( 1 * inch, v, subtline ) v -= 12 * point c.showPage() c.save() if __name__ == "__main__": nps = [None, 5, 11, 17] for i, np in enumerate(nps): if np: filename = "simple%d.pdf" % i make_pdf_file(filename, np) print ("Wrote", filename) PyPDF2-1.25.1/Sample_Code/makesimple.sh000077500000000000000000000006361255324530700174600ustar00rootroot00000000000000#!/bin/sh n=1 for np in 5 11 17; do p=1 f=simple$n.pdf while expr $p \<= $np > /dev/null; do if [ $p != 1 ]; then echo " \c" fi echo "$f page $p of $np" echo "" echo "an incredible, yet simple example" echo "Created with Sample_Code/makesimple.sh" p=$(expr $p + 1) done | enscript --no-header -o - |ps2pdf - $f echo $f n=$(expr $n + 1) donePyPDF2-1.25.1/Scripts/000077500000000000000000000000001255324530700142415ustar00rootroot00000000000000PyPDF2-1.25.1/Scripts/2-up.py000066400000000000000000000030221255324530700153730ustar00rootroot00000000000000from PyPDF2 import PdfFileWriter, PdfFileReader import sys import math def main(): if (len(sys.argv) != 3): print("usage: python 2-up.py input_file output_file") sys.exit(1) print ("2-up input " + sys.argv[1]) input1 = PdfFileReader(open(sys.argv[1], "rb")) output = PdfFileWriter() for iter in range (0, input1.getNumPages()-1, 2): lhs = input1.getPage(iter) rhs = input1.getPage(iter+1) lhs.mergeTranslatedPage(rhs, lhs.mediaBox.getUpperRight_x(),0, True) output.addPage(lhs) print (str(iter) + " "), sys.stdout.flush() print("writing " + sys.argv[2]) outputStream = file(sys.argv[2], "wb") output.write(outputStream) print("done.") if __name__ == "__main__": main() from PyPDF2 import PdfFileWriter, PdfFileReader import sys import math def main(): if (len(sys.argv) != 3): print("usage: python 2-up.py input_file output_file") sys.exit(1) print ("2-up input " + sys.argv[1]) input1 = PdfFileReader(open(sys.argv[1], "rb")) output = PdfFileWriter() for iter in range (0, input1.getNumPages()-1, 2): lhs = input1.getPage(iter) rhs = input1.getPage(iter+1) lhs.mergeTranslatedPage(rhs, lhs.mediaBox.getUpperRight_x(),0, True) output.addPage(lhs) print (str(iter) + " "), sys.stdout.flush() print("writing " + sys.argv[2]) outputStream = open(sys.argv[2], "wb") output.write(outputStream) print("done.") if __name__ == "__main__": main() PyPDF2-1.25.1/Scripts/pdfcat000066400000000000000000000054571255324530700154400ustar00rootroot00000000000000#!/usr/bin/env python """ Concatenate pages from pdf files into a single pdf file. Page ranges refer to the previously-named file. A file not followed by a page range means all the pages of the file. PAGE RANGES are like Python slices. {page_range_help} EXAMPLES pdfcat -o output.pdf head.pdf content.pdf :6 7: tail.pdf -1 Concatenate all of head.pdf, all but page seven of content.pdf, and the last page of tail.pdf, producing output.pdf. pdfcat chapter*.pdf >book.pdf You can specify the output file by redirection. pdfcat chapter?.pdf chapter10.pdf >book.pdf In case you don't want chapter 10 before chapter 2. """ # Copyright (c) 2014, Steve Witham . # All rights reserved. This software is available under a BSD license; # see https://github.com/mstamy2/PyPDF2/LICENSE from __future__ import print_function import argparse from PyPDF2.pagerange import PAGE_RANGE_HELP def parse_args(): parser = argparse.ArgumentParser( description=__doc__.format(page_range_help=PAGE_RANGE_HELP), formatter_class=argparse.RawDescriptionHelpFormatter) parser.add_argument("-o", "--output", metavar="output_file") parser.add_argument("-v", "--verbose", action="store_true", help="show page ranges as they are being read") parser.add_argument("first_filename", nargs=1, metavar="filename [page range...]") # argparse chokes on page ranges like "-2:" unless caught like this: parser.add_argument("fn_pgrgs", nargs=argparse.REMAINDER, metavar="filenames and/or page ranges") args = parser.parse_args() args.fn_pgrgs.insert(0, args.first_filename[0]) return args from sys import stderr, stdout, exit import os import traceback from collections import defaultdict from PyPDF2 import PdfFileMerger, parse_filename_page_ranges if __name__ == "__main__": args = parse_args() filename_page_ranges = parse_filename_page_ranges(args.fn_pgrgs) if args.output: output = open(args.output, "wb") else: stdout.flush() output = os.fdopen(stdout.fileno(), "wb") merger = PdfFileMerger() in_fs = dict() try: for (filename, page_range) in filename_page_ranges: if args.verbose: print(filename, page_range, file=stderr) if filename not in in_fs: in_fs[filename] = open(filename, "rb") merger.append(in_fs[filename], pages=page_range) except: print(traceback.format_exc(), file=stderr) print("Error while reading " + filename, file=stderr) exit(1) merger.write(output) # In 3.0, input files must stay open until output is written. # Not closing the in_fs because this script exits now. PyPDF2-1.25.1/Tests/000077500000000000000000000000001255324530700137145ustar00rootroot00000000000000PyPDF2-1.25.1/Tests/__init__.py000066400000000000000000000000001255324530700160130ustar00rootroot00000000000000PyPDF2-1.25.1/Tests/tests.py000066400000000000000000000022761255324530700154370ustar00rootroot00000000000000import os, sys, unittest # Configure path environment TESTS_ROOT = os.path.abspath(os.path.dirname(__file__)) PROJECT_ROOT = os.path.dirname(TESTS_ROOT) RESOURCE_ROOT = os.path.join(PROJECT_ROOT, 'Resources') sys.path.append(PROJECT_ROOT) # Test imports import unittest from PyPDF2 import PdfFileReader class PdfReaderTestCases(unittest.TestCase): def test_PdfReaderFileLoad(self): ''' Test loading and parsing of a file. Extract text of the file and compare to expected textual output. Expected outcome: file loads, text matches expected. ''' with open(os.path.join(RESOURCE_ROOT, 'crazyones.pdf'), 'rb') as inputfile: # Load PDF file from file ipdf = PdfFileReader(inputfile) ipdf_p1 = ipdf.getPage(0) # Retrieve the text of the PDF pdftext_file = open(os.path.join(RESOURCE_ROOT, 'crazyones.txt'), 'r') pdftext = pdftext_file.read() ipdf_p1_text = ipdf_p1.extractText() # Compare the text of the PDF to a known source self.assertEqual(ipdf_p1_text.encode('utf-8', errors='ignore'), pdftext, msg='PDF extracted text differs from expected value.\n\nExpected:\n\n%r\n\nExtracted:\n\n%r\n\n' % (pdftext, ipdf_p1_text.encode('utf-8', errors='ignore')))PyPDF2-1.25.1/setup.py000066400000000000000000000033651255324530700143330ustar00rootroot00000000000000#!/usr/bin/env python from distutils.core import setup import re long_description = """ A Pure-Python library built as a PDF toolkit. It is capable of: - extracting document information (title, author, ...) - splitting documents page by page - merging documents page by page - cropping pages - merging multiple pages into a single page - encrypting and decrypting PDF files - and more! By being Pure-Python, it should run on any Python platform without any dependencies on external libraries. It can also work entirely on StringIO objects rather than file streams, allowing for PDF manipulation in memory. It is therefore a useful tool for websites that manage or manipulate PDFs. """ VERSIONFILE="PyPDF2/_version.py" verstrline = open(VERSIONFILE, "rt").read() VSRE = r"^__version__ = ['\"]([^'\"]*)['\"]" mo = re.search(VSRE, verstrline, re.M) if mo: verstr = mo.group(1) else: raise RuntimeError("Unable to find version string in %s." % (VERSIONFILE)) setup( name="PyPDF2", version=verstr, description="PDF toolkit", long_description=long_description, author="Mathieu Fenniak", author_email="biziqe@mathieu.fenniak.net", maintainer="Phaseit, Inc.", maintainer_email="PyPDF2@phaseit.net", url="http://mstamy2.github.com/PyPDF2", classifiers = [ "Development Status :: 5 - Production/Stable", "Intended Audience :: Developers", "License :: OSI Approved :: BSD License", "Programming Language :: Python :: 2", "Programming Language :: Python :: 3", "Operating System :: OS Independent", "Topic :: Software Development :: Libraries :: Python Modules", ], packages=["PyPDF2"], )