pax_global_header00006660000000000000000000000064150423667450014526gustar00rootroot0000000000000052 comment=f744140762989f0431ac65e2d16787a3d5fab130 endesive-2.19.1/000077500000000000000000000000001504236674500134225ustar00rootroot00000000000000endesive-2.19.1/.gitignore000066400000000000000000000023721504236674500154160ustar00rootroot00000000000000# Byte-compiled / optimized / DLL files __pycache__/ *.py[cod] *$py.class # C extensions *.so # Distribution / packaging .Python build/ develop-eggs/ dist/ downloads/ eggs/ .eggs/ lib/ lib64/ parts/ sdist/ var/ wheels/ *.egg-info/ .installed.cfg *.egg MANIFEST # PyInstaller # Usually these files are written by a python script from a template # before PyInstaller builds the exe, so as to inject date/other infos into it. *.manifest *.spec # Installer logs pip-log.txt pip-delete-this-directory.txt # Unit test / coverage reports htmlcov/ .tox/ .coverage .coverage.* .cache nosetests.xml coverage.xml *.cover .hypothesis/ .pytest_cache/ # Translations *.mo *.pot # Django stuff: *.log local_settings.py db.sqlite3 # Flask stuff: instance/ .webassets-cache # Scrapy stuff: .scrapy # Sphinx documentation docs/_build/ # PyBuilder target/ # Jupyter Notebook .ipynb_checkpoints # pyenv .python-version # celery beat schedule file celerybeat-schedule # SageMath parsed files *.sage.py # Environments .env .venv env/ venv/ ENV/ env.bak/ venv.bak/ # Spyder project settings .spyderproject .spyproject # Rope project settings .ropeproject # mkdocs documentation /site # mypy .mypy_cache/ examples/endesive examples/*.txt examples/*.pdf examples/*.xml .idea/ endesive-2.19.1/LICENSE000066400000000000000000000020641504236674500144310ustar00rootroot00000000000000MIT License Copyright (c) 2018 Grzegorz Makarewicz Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. endesive-2.19.1/LICENSE.pdf-annotate000066400000000000000000000020611504236674500170050ustar00rootroot00000000000000MIT License Copyright (c) 2018-present Autodesk Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. endesive-2.19.1/LICENSE.pyfpdf000066400000000000000000000167201504236674500157240ustar00rootroot00000000000000GNU LESSER GENERAL PUBLIC LICENSE Version 3, 29 June 2007 Copyright (C) 2007 Free Software Foundation, Inc. Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. This version of the GNU Lesser General Public License incorporates the terms and conditions of version 3 of the GNU General Public License, supplemented by the additional permissions listed below. 0. Additional Definitions. As used herein, "this License" refers to version 3 of the GNU Lesser General Public License, and the "GNU GPL" refers to version 3 of the GNU General Public License. "The Library" refers to a covered work governed by this License, other than an Application or a Combined Work as defined below. An "Application" is any work that makes use of an interface provided by the Library, but which is not otherwise based on the Library. Defining a subclass of a class defined by the Library is deemed a mode of using an interface provided by the Library. A "Combined Work" is a work produced by combining or linking an Application with the Library. The particular version of the Library with which the Combined Work was made is also called the "Linked Version". The "Minimal Corresponding Source" for a Combined Work means the Corresponding Source for the Combined Work, excluding any source code for portions of the Combined Work that, considered in isolation, are based on the Application, and not on the Linked Version. The "Corresponding Application Code" for a Combined Work means the object code and/or source code for the Application, including any data and utility programs needed for reproducing the Combined Work from the Application, but excluding the System Libraries of the Combined Work. 1. Exception to Section 3 of the GNU GPL. You may convey a covered work under sections 3 and 4 of this License without being bound by section 3 of the GNU GPL. 2. Conveying Modified Versions. If you modify a copy of the Library, and, in your modifications, a facility refers to a function or data to be supplied by an Application that uses the facility (other than as an argument passed when the facility is invoked), then you may convey a copy of the modified version: a) under this License, provided that you make a good faith effort to ensure that, in the event an Application does not supply the function or data, the facility still operates, and performs whatever part of its purpose remains meaningful, or b) under the GNU GPL, with none of the additional permissions of this License applicable to that copy. 3. Object Code Incorporating Material from Library Header Files. The object code form of an Application may incorporate material from a header file that is part of the Library. You may convey such object code under terms of your choice, provided that, if the incorporated material is not limited to numerical parameters, data structure layouts and accessors, or small macros, inline functions and templates (ten or fewer lines in length), you do both of the following: a) Give prominent notice with each copy of the object code that the Library is used in it and that the Library and its use are covered by this License. b) Accompany the object code with a copy of the GNU GPL and this license document. 4. Combined Works. You may convey a Combined Work under terms of your choice that, taken together, effectively do not restrict modification of the portions of the Library contained in the Combined Work and reverse engineering for debugging such modifications, if you also do each of the following: a) Give prominent notice with each copy of the Combined Work that the Library is used in it and that the Library and its use are covered by this License. b) Accompany the Combined Work with a copy of the GNU GPL and this license document. c) For a Combined Work that displays copyright notices during execution, include the copyright notice for the Library among these notices, as well as a reference directing the user to the copies of the GNU GPL and this license document. d) Do one of the following: 0) Convey the Minimal Corresponding Source under the terms of this License, and the Corresponding Application Code in a form suitable for, and under terms that permit, the user to recombine or relink the Application with a modified version of the Linked Version to produce a modified Combined Work, in the manner specified by section 6 of the GNU GPL for conveying Corresponding Source. 1) Use a suitable shared library mechanism for linking with the Library. A suitable mechanism is one that (a) uses at run time a copy of the Library already present on the user's computer system, and (b) will operate properly with a modified version of the Library that is interface-compatible with the Linked Version. e) Provide Installation Information, but only if you would otherwise be required to provide such information under section 6 of the GNU GPL, and only to the extent that such information is necessary to install and execute a modified version of the Combined Work produced by recombining or relinking the Application with a modified version of the Linked Version. (If you use option 4d0, the Installation Information must accompany the Minimal Corresponding Source and Corresponding Application Code. If you use option 4d1, you must provide the Installation Information in the manner specified by section 6 of the GNU GPL for conveying Corresponding Source.) 5. Combined Libraries. You may place library facilities that are a work based on the Library side by side in a single library together with other library facilities that are not Applications and are not covered by this License, and convey such a combined library under terms of your choice, if you do both of the following: a) Accompany the combined library with a copy of the same work based on the Library, uncombined with any other library facilities, conveyed under the terms of this License. b) Give prominent notice with the combined library that part of it is a work based on the Library, and explaining where to find the accompanying uncombined form of the same work. 6. Revised Versions of the GNU Lesser General Public License. The Free Software Foundation may publish revised and/or new versions of the GNU Lesser General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Library as you received it specifies that a certain numbered version of the GNU Lesser General Public License "or any later version" applies to it, you have the option of following the terms and conditions either of that published version or of any later version published by the Free Software Foundation. If the Library as you received it does not specify a version number of the GNU Lesser General Public License, you may choose any version of the GNU Lesser General Public License ever published by the Free Software Foundation. If the Library as you received it specifies that a proxy can decide whether future versions of the GNU Lesser General Public License shall apply, that proxy's public statement of acceptance of any version is permanent authorization for you to choose that version for the Library. endesive-2.19.1/LICENSE.pypdf2000066400000000000000000000031051504236674500156310ustar00rootroot00000000000000Copyright (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. endesive-2.19.1/MANIFEST.in000066400000000000000000000002041504236674500151540ustar00rootroot00000000000000include LICENSE.pyfpdf include LICENSE.pypdf2 include LICENSE.pdf-annotate include endesive/pdf/PyPDF2_annotate/fonts/Helvetica.ttf endesive-2.19.1/Makefile000066400000000000000000000006001504236674500150560ustar00rootroot00000000000000test: rm -rf tests/fixtures/softhsm2 tests/fixtures/softhsm2.conf tests/fixtures/cert-* tests/fixtures/demo2_* vpython3 -m coverage run --omit "endesive/pdf/PyPDF2/*","endesive/pdf/PyPDF2_annotate/*","endesive/pdf/fpdf/*","endesive/pdf/pdf.py","/usr/lib/*" -m unittest discover tests vpy3-coverage3 report -m mypy: mypy endesive --ignore-missing-imports --check-untyped --strict endesive-2.19.1/README.rst000066400000000000000000000076121504236674500151170ustar00rootroot00000000000000.. image:: https://img.shields.io/pypi/v/endesive.svg :target: https://pypi.python.org/pypi/endesive Description =========== Python library for digital signing and verification of digital signatures in mail, PDF and XML documents. The ASN.1 implementation depends on `asn1crypto`_. Cryptographic routines depends on `cryptography`_ library. For certificate verification `cryptography`_ library is used. This library implements S/MIME handler which can encrypt and decrypt S/MIME messages using a public RSA key, in AES-128/192/256 CBC/OFB modes. It can also sign and verify S/MIME messages. This library implements CAdES-B handler for signing and verifying PDF documents in Adobe.PPKLite/adbe.pkcs7.detached form. It can sign documents during generation using a modified version of `pyfpdf`_ which is included in this library. It can also sign documents generated by external programms. This library implements XADES BES/T with enveloped and enveloping format for creating signed xml files. This library implements CMS handler for signing and verifying plain text files with detached signature files. License ======= This software is licensed under the MIT License. See the LICENSE file in the top distribution directory for the full license text. ## Requirements * Python 3.* * `cryptography`_ * `asn1crypto`_ * `lxml`_ * `pykcs11`_ * `Pillow`_ Examples ======== cert-make.py Create required certificates (password is 1234) cert-make-hsm.py Create required certificates for SoftHSM (password is secret1) pdf-make.py Create simple two paged PDF document which is used in pdf-sign-cms.py. pdf-sign-cms.py Create signature in externally created PDF. pdf-sign-cms-hsm.py Create signature in externally created PDF but signed with key stored in SoftHSM. pdf-sign-fpdf.py Create signature while creating PDF. pdf-verify.py Verify prevously generated files (cms/pdf). plain-make.py Create simple UTF-8 text file. plain-openssl.sh Sign, encrypt and decrypt text file with help of openssl executable. plain-sign-attr.py Sign text file with 'extended' CMS attributes. plain-sign-noattr.py Sign text file without 'extended' CMS attributes. plain-verify.py Verify all generated signatures for text file. smime-make.py Create simple UTF-8 text file for use in following examples. smime-openssl.sh Create signed S/MIME file, encrypted S/MIME file and decrypt generated S/MIME file with help of openssl executable. smime-encrypt.py Create encrypted S/MIME file. smime-decrypt.py Decrypt encrypted S/MIME file. smime-sign-attr.py Create signed S/MIME file with 'extended' CMS attributes. smime-sign-noattr.py Create signed S/MIME file without 'extended' CMS attributes. smime-verify.py Verify all generated S/MIME files. xml-make.py Create simple xml file for use in following examples. xml-hsm-certum-enveloped.py XADES enveloped mode with real certificate (BES/T). xml-hsm-certum-enveloping.py XADES enveloping mode with real certificate (BES/T). xml-hsm-softhsm2-enveloped.py XADES enveloped mode with SoftHSM certificate (BES). xml-hsm-softhsm2-enveloping.py XADES enveloping mode with SoftHSM certificate (BES). Tools ===== Online pdf validator `pdfvalidator`_ or `verapdf`_. Offline Apache `pdfbox`_ java based validator. Validate electronic signatures: `ec_europa`_ or `pkitools_net`_. .. _cryptography: https://github.com/pyca/cryptography .. _asn1crypto: https://github.com/wbond/asn1crypto .. _pyfpdf: https://github.com/reingart/pyfpdf .. _lxml: https://pypi.org/project/lxml/ .. _pykcs11: https://pypi.org/project/pykcs11/ .. _Pillow: https://pypi.org/project/Pillow/ .. _pdfvalidator: https://www.pdf-online.com/osa/validate.aspx .. _verapdf: https://demo.verapdf.org/ .. _pdfbox: https://pdfbox.apache.org/ .. _ec_europa: https://ec.europa.eu/cefdigital/DSS/webapp-demo/validation .. _pkitools_net: https://pkitools.net/pages/validator/pdf.html endesive-2.19.1/docs/000077500000000000000000000000001504236674500143525ustar00rootroot00000000000000endesive-2.19.1/docs/.gitignore000066400000000000000000000000041504236674500163340ustar00rootroot00000000000000_*/ endesive-2.19.1/docs/Makefile000066400000000000000000000011721504236674500160130ustar00rootroot00000000000000# Minimal makefile for Sphinx documentation # # You can set these variables from the command line, and also # from the environment for the first two. SPHINXOPTS ?= SPHINXBUILD ?= sphinx-build SOURCEDIR = . BUILDDIR = _build # Put it first so that "make" without argument is like "make help". help: @$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) .PHONY: help Makefile # Catch-all target: route all unknown targets to Sphinx using the new # "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS). %: Makefile @$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) endesive-2.19.1/docs/conf.py000066400000000000000000000023571504236674500156600ustar00rootroot00000000000000import os import sys sys.path.insert(0, os.path.abspath('..')) # Configuration file for the Sphinx documentation builder. # # For the full list of built-in configuration values, see the documentation: # https://www.sphinx-doc.org/en/master/usage/configuration.html # -- Project information ----------------------------------------------------- # https://www.sphinx-doc.org/en/master/usage/configuration.html#project-information project = 'endesive' copyright = '2025, Grzegorz Makarewicz' author = 'Grzegorz Makarewicz' #release = '1.0.0' # -- General configuration --------------------------------------------------- # https://www.sphinx-doc.org/en/master/usage/configuration.html#general-configuration extensions = [ 'sphinx.ext.autodoc', 'sphinx.ext.viewcode', 'sphinx.ext.napoleon', ] templates_path = ['_templates'] exclude_patterns = [ '_build', 'Thumbs.db', '.DS_Store', 'examples', 'tests', 'endesive/pdf/fpdf*', 'endesive/pdf/PyPDF2*', 'endesive/pdf/PyPDF2_annotate*', ] # -- Options for HTML output ------------------------------------------------- # https://www.sphinx-doc.org/en/master/usage/configuration.html#options-for-html-output html_theme = 'sphinx_rtd_theme' html_static_path = ['_static'] endesive-2.19.1/docs/endesive.email.rst000066400000000000000000000014341504236674500177760ustar00rootroot00000000000000endesive.email package ====================== Submodules ---------- endesive.email.decrypt module ----------------------------- .. automodule:: endesive.email.decrypt :members: :undoc-members: :show-inheritance: endesive.email.encrypt module ----------------------------- .. automodule:: endesive.email.encrypt :members: :undoc-members: :show-inheritance: endesive.email.sign module -------------------------- .. automodule:: endesive.email.sign :members: :undoc-members: :show-inheritance: endesive.email.verify module ---------------------------- .. automodule:: endesive.email.verify :members: :undoc-members: :show-inheritance: Module contents --------------- .. automodule:: endesive.email :members: :undoc-members: :show-inheritance: endesive-2.19.1/docs/endesive.pdf.PyPDF2.rst000066400000000000000000000025261504236674500204660ustar00rootroot00000000000000endesive.pdf.PyPDF2 package =========================== Submodules ---------- endesive.pdf.PyPDF2.filters module ---------------------------------- .. automodule:: endesive.pdf.PyPDF2.filters :members: :undoc-members: :show-inheritance: endesive.pdf.PyPDF2.generic module ---------------------------------- .. automodule:: endesive.pdf.PyPDF2.generic :members: :undoc-members: :show-inheritance: endesive.pdf.PyPDF2.merger module --------------------------------- .. automodule:: endesive.pdf.PyPDF2.merger :members: :undoc-members: :show-inheritance: endesive.pdf.PyPDF2.pagerange module ------------------------------------ .. automodule:: endesive.pdf.PyPDF2.pagerange :members: :undoc-members: :show-inheritance: endesive.pdf.PyPDF2.pdf module ------------------------------ .. automodule:: endesive.pdf.PyPDF2.pdf :members: :undoc-members: :show-inheritance: endesive.pdf.PyPDF2.utils module -------------------------------- .. automodule:: endesive.pdf.PyPDF2.utils :members: :undoc-members: :show-inheritance: endesive.pdf.PyPDF2.xmp module ------------------------------ .. automodule:: endesive.pdf.PyPDF2.xmp :members: :undoc-members: :show-inheritance: Module contents --------------- .. automodule:: endesive.pdf.PyPDF2 :members: :undoc-members: :show-inheritance: endesive-2.19.1/docs/endesive.pdf.PyPDF2_annotate.annotations.rst000066400000000000000000000031601504236674500247060ustar00rootroot00000000000000endesive.pdf.PyPDF2\_annotate.annotations package ================================================= Submodules ---------- endesive.pdf.PyPDF2\_annotate.annotations.base module ----------------------------------------------------- .. automodule:: endesive.pdf.PyPDF2_annotate.annotations.base :members: :undoc-members: :show-inheritance: endesive.pdf.PyPDF2\_annotate.annotations.image module ------------------------------------------------------ .. automodule:: endesive.pdf.PyPDF2_annotate.annotations.image :members: :undoc-members: :show-inheritance: endesive.pdf.PyPDF2\_annotate.annotations.points module ------------------------------------------------------- .. automodule:: endesive.pdf.PyPDF2_annotate.annotations.points :members: :undoc-members: :show-inheritance: endesive.pdf.PyPDF2\_annotate.annotations.rect module ----------------------------------------------------- .. automodule:: endesive.pdf.PyPDF2_annotate.annotations.rect :members: :undoc-members: :show-inheritance: endesive.pdf.PyPDF2\_annotate.annotations.signature module ---------------------------------------------------------- .. automodule:: endesive.pdf.PyPDF2_annotate.annotations.signature :members: :undoc-members: :show-inheritance: endesive.pdf.PyPDF2\_annotate.annotations.text module ----------------------------------------------------- .. automodule:: endesive.pdf.PyPDF2_annotate.annotations.text :members: :undoc-members: :show-inheritance: Module contents --------------- .. automodule:: endesive.pdf.PyPDF2_annotate.annotations :members: :undoc-members: :show-inheritance: endesive-2.19.1/docs/endesive.pdf.PyPDF2_annotate.config.rst000066400000000000000000000025651504236674500236260ustar00rootroot00000000000000endesive.pdf.PyPDF2\_annotate.config package ============================================ Submodules ---------- endesive.pdf.PyPDF2\_annotate.config.appearance module ------------------------------------------------------ .. automodule:: endesive.pdf.PyPDF2_annotate.config.appearance :members: :undoc-members: :show-inheritance: endesive.pdf.PyPDF2\_annotate.config.constants module ----------------------------------------------------- .. automodule:: endesive.pdf.PyPDF2_annotate.config.constants :members: :undoc-members: :show-inheritance: endesive.pdf.PyPDF2\_annotate.config.graphics\_state module ----------------------------------------------------------- .. automodule:: endesive.pdf.PyPDF2_annotate.config.graphics_state :members: :undoc-members: :show-inheritance: endesive.pdf.PyPDF2\_annotate.config.location module ---------------------------------------------------- .. automodule:: endesive.pdf.PyPDF2_annotate.config.location :members: :undoc-members: :show-inheritance: endesive.pdf.PyPDF2\_annotate.config.metadata module ---------------------------------------------------- .. automodule:: endesive.pdf.PyPDF2_annotate.config.metadata :members: :undoc-members: :show-inheritance: Module contents --------------- .. automodule:: endesive.pdf.PyPDF2_annotate.config :members: :undoc-members: :show-inheritance: endesive-2.19.1/docs/endesive.pdf.PyPDF2_annotate.fonts.rst000066400000000000000000000003431504236674500235020ustar00rootroot00000000000000endesive.pdf.PyPDF2\_annotate.fonts package =========================================== Module contents --------------- .. automodule:: endesive.pdf.PyPDF2_annotate.fonts :members: :undoc-members: :show-inheritance: endesive-2.19.1/docs/endesive.pdf.PyPDF2_annotate.rst000066400000000000000000000023321504236674500223520ustar00rootroot00000000000000endesive.pdf.PyPDF2\_annotate package ===================================== Subpackages ----------- .. toctree:: :maxdepth: 4 endesive.pdf.PyPDF2_annotate.annotations endesive.pdf.PyPDF2_annotate.config endesive.pdf.PyPDF2_annotate.fonts endesive.pdf.PyPDF2_annotate.util Submodules ---------- endesive.pdf.PyPDF2\_annotate.annotator module ---------------------------------------------- .. automodule:: endesive.pdf.PyPDF2_annotate.annotator :members: :undoc-members: :show-inheritance: endesive.pdf.PyPDF2\_annotate.graphics module --------------------------------------------- .. automodule:: endesive.pdf.PyPDF2_annotate.graphics :members: :undoc-members: :show-inheritance: endesive.pdf.PyPDF2\_annotate.pdfrw module ------------------------------------------ .. automodule:: endesive.pdf.PyPDF2_annotate.pdfrw :members: :undoc-members: :show-inheritance: endesive.pdf.PyPDF2\_annotate.pdfttf module ------------------------------------------- .. automodule:: endesive.pdf.PyPDF2_annotate.pdfttf :members: :undoc-members: :show-inheritance: Module contents --------------- .. automodule:: endesive.pdf.PyPDF2_annotate :members: :undoc-members: :show-inheritance: endesive-2.19.1/docs/endesive.pdf.PyPDF2_annotate.util.rst000066400000000000000000000025221504236674500233270ustar00rootroot00000000000000endesive.pdf.PyPDF2\_annotate.util package ========================================== Submodules ---------- endesive.pdf.PyPDF2\_annotate.util.font\_metrics module ------------------------------------------------------- .. automodule:: endesive.pdf.PyPDF2_annotate.util.font_metrics :members: :undoc-members: :show-inheritance: endesive.pdf.PyPDF2\_annotate.util.geometry module -------------------------------------------------- .. automodule:: endesive.pdf.PyPDF2_annotate.util.geometry :members: :undoc-members: :show-inheritance: endesive.pdf.PyPDF2\_annotate.util.text module ---------------------------------------------- .. automodule:: endesive.pdf.PyPDF2_annotate.util.text :members: :undoc-members: :show-inheritance: endesive.pdf.PyPDF2\_annotate.util.true\_type\_font module ---------------------------------------------------------- .. automodule:: endesive.pdf.PyPDF2_annotate.util.true_type_font :members: :undoc-members: :show-inheritance: endesive.pdf.PyPDF2\_annotate.util.validation module ---------------------------------------------------- .. automodule:: endesive.pdf.PyPDF2_annotate.util.validation :members: :undoc-members: :show-inheritance: Module contents --------------- .. automodule:: endesive.pdf.PyPDF2_annotate.util :members: :undoc-members: :show-inheritance: endesive-2.19.1/docs/endesive.pdf.fpdf.rst000066400000000000000000000024271504236674500204010ustar00rootroot00000000000000endesive.pdf.fpdf package ========================= Submodules ---------- endesive.pdf.fpdf.fonts module ------------------------------ .. automodule:: endesive.pdf.fpdf.fonts :members: :undoc-members: :show-inheritance: endesive.pdf.fpdf.fpdf module ----------------------------- .. automodule:: endesive.pdf.fpdf.fpdf :members: :undoc-members: :show-inheritance: endesive.pdf.fpdf.html module ----------------------------- .. automodule:: endesive.pdf.fpdf.html :members: :undoc-members: :show-inheritance: endesive.pdf.fpdf.php module ---------------------------- .. automodule:: endesive.pdf.fpdf.php :members: :undoc-members: :show-inheritance: endesive.pdf.fpdf.py3k module ----------------------------- .. automodule:: endesive.pdf.fpdf.py3k :members: :undoc-members: :show-inheritance: endesive.pdf.fpdf.template module --------------------------------- .. automodule:: endesive.pdf.fpdf.template :members: :undoc-members: :show-inheritance: endesive.pdf.fpdf.ttfonts module -------------------------------- .. automodule:: endesive.pdf.fpdf.ttfonts :members: :undoc-members: :show-inheritance: Module contents --------------- .. automodule:: endesive.pdf.fpdf :members: :undoc-members: :show-inheritance: endesive-2.19.1/docs/endesive.pdf.rst000066400000000000000000000013361504236674500174610ustar00rootroot00000000000000endesive.pdf package ==================== Subpackages ----------- .. toctree:: :maxdepth: 4 endesive.pdf.PyPDF2 endesive.pdf.PyPDF2_annotate endesive.pdf.fpdf Submodules ---------- endesive.pdf.cms module ----------------------- .. automodule:: endesive.pdf.cms :members: :undoc-members: :show-inheritance: endesive.pdf.pdf module ----------------------- .. automodule:: endesive.pdf.pdf :members: :undoc-members: :show-inheritance: endesive.pdf.verify module -------------------------- .. automodule:: endesive.pdf.verify :members: :undoc-members: :show-inheritance: Module contents --------------- .. automodule:: endesive.pdf :members: :undoc-members: :show-inheritance: endesive-2.19.1/docs/endesive.plain.rst000066400000000000000000000007461504236674500200170ustar00rootroot00000000000000endesive.plain package ====================== Submodules ---------- endesive.plain.sign module -------------------------- .. automodule:: endesive.plain.sign :members: :undoc-members: :show-inheritance: endesive.plain.verify module ---------------------------- .. automodule:: endesive.plain.verify :members: :undoc-members: :show-inheritance: Module contents --------------- .. automodule:: endesive.plain :members: :undoc-members: :show-inheritance: endesive-2.19.1/docs/endesive.rst000066400000000000000000000012671504236674500167140ustar00rootroot00000000000000endesive package ================ Subpackages ----------- .. toctree:: :maxdepth: 4 endesive.email endesive.pdf endesive.plain endesive.xades Submodules ---------- endesive.hsm module ------------------- .. automodule:: endesive.hsm :members: :undoc-members: :show-inheritance: endesive.signer module ---------------------- .. automodule:: endesive.signer :members: :undoc-members: :show-inheritance: endesive.verifier module ------------------------ .. automodule:: endesive.verifier :members: :undoc-members: :show-inheritance: Module contents --------------- .. automodule:: endesive :members: :undoc-members: :show-inheritance: endesive-2.19.1/docs/endesive.xades.rst000066400000000000000000000005131504236674500200100ustar00rootroot00000000000000endesive.xades package ====================== Submodules ---------- endesive.xades.bes module ------------------------- .. automodule:: endesive.xades.bes :members: :undoc-members: :show-inheritance: Module contents --------------- .. automodule:: endesive.xades :members: :undoc-members: :show-inheritance: endesive-2.19.1/docs/index.rst000066400000000000000000000010001504236674500162020ustar00rootroot00000000000000.. endesive documentation master file, created by sphinx-quickstart on Thu Jun 19 22:09:04 2025. You can adapt this file completely to your liking, but it should at least contain the root `toctree` directive. endesive documentation ====================== Add your content using ``reStructuredText`` syntax. See the `reStructuredText `_ documentation for details. .. toctree:: :maxdepth: 2 :caption: Contents: modules endesive-2.19.1/docs/make.bat000066400000000000000000000013751504236674500157650ustar00rootroot00000000000000@ECHO OFF pushd %~dp0 REM Command file for Sphinx documentation if "%SPHINXBUILD%" == "" ( set SPHINXBUILD=sphinx-build ) set SOURCEDIR=. set BUILDDIR=_build %SPHINXBUILD% >NUL 2>NUL if errorlevel 9009 ( echo. echo.The 'sphinx-build' command was not found. Make sure you have Sphinx echo.installed, then set the SPHINXBUILD environment variable to point echo.to the full path of the 'sphinx-build' executable. Alternatively you echo.may add the Sphinx directory to PATH. echo. echo.If you don't have Sphinx installed, grab it from echo.https://www.sphinx-doc.org/ exit /b 1 ) if "%1" == "" goto help %SPHINXBUILD% -M %1 %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% %O% goto end :help %SPHINXBUILD% -M help %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% %O% :end popd endesive-2.19.1/docs/modules.rst000066400000000000000000000000751504236674500165560ustar00rootroot00000000000000endesive ======== .. toctree:: :maxdepth: 4 endesive endesive-2.19.1/endesive/000077500000000000000000000000001504236674500152245ustar00rootroot00000000000000endesive-2.19.1/endesive/__init__.py000066400000000000000000000002401504236674500173310ustar00rootroot00000000000000"""Python ENDESIVE library.""" __author__ = 'Grzegorz Makarewicz' __license__ = 'MIT' __version__ = '2.19.0' __all__ = [__author__, __license__, __version__] endesive-2.19.1/endesive/email/000077500000000000000000000000001504236674500163135ustar00rootroot00000000000000endesive-2.19.1/endesive/email/__init__.py000066400000000000000000000002041504236674500204200ustar00rootroot00000000000000# *-* coding: utf-8 *-* from .decrypt import decrypt from .encrypt import encrypt from .sign import sign from .verify import verify endesive-2.19.1/endesive/email/decrypt.py000066400000000000000000000073721504236674500203500ustar00rootroot00000000000000# *-* coding: utf-8 *-* import sys from email import message_from_string from asn1crypto import cms from cryptography.hazmat.backends import default_backend from cryptography.hazmat.primitives import hashes from cryptography.hazmat.primitives.ciphers import Cipher, algorithms, modes from cryptography.hazmat.primitives.asymmetric import padding from cryptography.hazmat.primitives.asymmetric.types import PrivateKeyTypes class DecryptedData(object): def decrypt(self, data: str, key: PrivateKeyTypes) -> bytes: msg = message_from_string(data) data = None for part in msg.walk(): # multipart/* are just containers if part.get_content_maintype() == 'multipart': continue if part.get_content_type() not in ( 'application/x-pkcs7-mime', 'application/pkcs7-mime', ): continue data = part.get_payload(decode=True) break if data is None: raise ValueError('No encrypted part found in the message') signed_data = cms.ContentInfo.load(data)['content'] # signed_data.debug() algo = signed_data['encrypted_content_info']['content_encryption_algorithm']['algorithm'].native param = signed_data['encrypted_content_info']['content_encryption_algorithm']['parameters'].native edata = signed_data['encrypted_content_info']['encrypted_content'].native pkey = signed_data['recipient_infos'].native[0]['encrypted_key'] keyalgo = signed_data['recipient_infos'].native[0]['key_encryption_algorithm'] if keyalgo['algorithm'] == 'rsaes_oaep': keyparam = keyalgo['parameters'] mga = keyparam['mask_gen_algorithm'] mgh = getattr(hashes, mga['parameters']['algorithm'].upper())() pad = padding.OAEP( mgf=getattr(padding, mga['algorithm'].upper())(algorithm=mgh), algorithm=getattr(hashes, keyparam['hash_algorithm']['algorithm'].upper())(), label=keyparam['p_source_algorithm']['parameters'] ) udata = key.decrypt(pkey, pad) elif keyalgo['algorithm'] == 'rsaes_pkcs1v15': udata = key.decrypt(pkey, padding.PKCS1v15()) else: raise ValueError('Unknown key algorithm', keyalgo['algorithm']) algorithm, mode = algo.split('_', 1) algorithm = algorithm.upper() if algorithm in ( 'AES128', 'AES192', 'AES256', ): cipher = Cipher( algorithms.AES(udata), getattr(modes, mode.upper())(param), default_backend() ) elif algorithm == 'TRIPLEDES': # XXX will be removed in version 48.0.0 from cryptography.hazmat.decrepit.ciphers.algorithms import TripleDES # XXX howto decode parameters to CBC mode ? mode = 'cbc' cipher = Cipher( TripleDES(udata), getattr(modes, mode.upper())(param), default_backend() ) else: raise ValueError('Unknown algorithm', algo) decryptor = cipher.decryptor() udata = decryptor.update(edata) + decryptor.finalize() #if keyalgo['algorithm'] != 'rsaes_oaep': nb = ord(udata[-1]) if sys.version[0] < '3' else udata[-1] udata = udata[:-nb] return udata def decrypt(data: str, key: PrivateKeyTypes) -> bytes: """ Decrypt the given data string using the provided private key. :param data: The encrypted data as a string. :param key: The private key used for decryption. :return: The decrypted data as bytes. """ cls = DecryptedData() return cls.decrypt(data, key) endesive-2.19.1/endesive/email/encrypt.py000066400000000000000000000120211504236674500203450ustar00rootroot00000000000000# *-* coding: utf-8 *-* import sys import os from email.mime.application import MIMEApplication from asn1crypto import cms, core, algos from cryptography import x509 from cryptography.hazmat.backends import default_backend from cryptography.hazmat.primitives import hashes from cryptography.hazmat.primitives.ciphers import Cipher, algorithms, modes from cryptography.hazmat.primitives.asymmetric import padding from endesive import signer class EncryptedData(object): def email(self, data: bytes, oaep: bool) -> str: prefix = ['x-', ''][oaep] msg = MIMEApplication(data) del msg['Content-Type'] msg['Content-Disposition'] = 'attachment; filename="smime.p7m"' msg['Content-Type'] = 'application/%spkcs7-mime; smime-type=enveloped-data; name="smime.p7m"' % prefix data = msg.as_string() return data def pad(self, s, block_size): n = block_size - len(s) % block_size if n == 0: n = block_size #return s n = bytes([n] * n) return s + n def recipient_info(self, cert, session_key, oaep): public_key = cert.public_key() cert = signer.cert2asn(cert) tbs_cert = cert['tbs_certificate'] # TODO: use subject_key_identifier when available if oaep: encrypted_key = public_key.encrypt( session_key, padding.OAEP( mgf=padding.MGF1(hashes.SHA512()), algorithm=hashes.SHA512(), label=None ) ) kea = cms.KeyEncryptionAlgorithm({ 'algorithm': cms.KeyEncryptionAlgorithmId('rsaes_oaep'), 'parameters': algos.RSAESOAEPParams({ 'hash_algorithm': algos.DigestAlgorithm({'algorithm': 'sha512'}), 'mask_gen_algorithm': algos.MaskGenAlgorithm({ 'algorithm': algos.MaskGenAlgorithmId('mgf1'), 'parameters': { 'algorithm': algos.DigestAlgorithmId('sha512'), } }), 'p_source_algorithm': algos.PSourceAlgorithm({ 'algorithm': algos.PSourceAlgorithmId('p_specified'), 'parameters': b'', }) }) }) else: kea = {'algorithm': 'rsa'} encrypted_key = public_key.encrypt(session_key, padding.PKCS1v15()) result = cms.RecipientInfo( name='ktri', value={ 'version': 'v0', 'rid': cms.RecipientIdentifier( name='issuer_and_serial_number', value={ 'issuer': tbs_cert['issuer'], 'serial_number': tbs_cert['serial_number'] } ), 'key_encryption_algorithm': kea, 'encrypted_key': core.OctetString(encrypted_key) } ) return result def build(self, data, certs, algo, oaep): key_size = { 'aes128': 16, 'aes192': 24, 'aes256': 32, }[algo.split('_', 1)[0]] block_size = 16 session_key = os.urandom(key_size) iv = os.urandom(block_size) cipher = Cipher( algorithms.AES(session_key), getattr(modes, algo.split('_', 1)[1].upper())(iv), default_backend() ) data = self.pad(data, block_size) encryptor = cipher.encryptor() data = encryptor.update(data) + encryptor.finalize() recipient_infos = [] for cert in certs: recipient_info = self.recipient_info(cert, session_key, oaep) recipient_infos.append(recipient_info) enveloped_data = cms.ContentInfo({ 'content_type': 'enveloped_data', 'content': { 'version': 'v0', 'recipient_infos': recipient_infos, 'encrypted_content_info': { 'content_type': 'data', 'content_encryption_algorithm': { 'algorithm': algo, 'parameters': iv }, 'encrypted_content': data } } }) data = self.email(enveloped_data.dump(), oaep) return data def encrypt(data:bytes, certs:list[x509.Certificate], algo:str='aes256_cbc', oaep:bool=False) -> bytes: """ Encrypt the given data bytes using the provided certificates and algorithm. :param data: The data to encrypt. :param certs: A list of x509.Certificate objects to use for encryption. :param algo: The encryption algorithm to use (allowed are: aes256_cbc, aes256_ofb). :param oaep: Whether to use OAEP padding (default is False). :return: The encrypted data as bytes. """ assert algo[:3] == 'aes' and algo.split('_', 1)[1] in ('cbc', 'ofb') cls = EncryptedData() return cls.build(data, certs, algo, oaep) endesive-2.19.1/endesive/email/sign.py000066400000000000000000000042301504236674500176240ustar00rootroot00000000000000# *-* coding: utf-8 *-* import base64 from cryptography import x509 from cryptography.hazmat.primitives.asymmetric.types import PrivateKeyTypes from endesive import signer class SignedData(object): def email(self, hashalgo, datau, datas, prefix): s = b'''\ MIME-Version: 1.0 Content-Type: multipart/signed; protocol="application/%spkcs7-signature"; micalg="%s"; boundary="----46F1AAD10BE922477643C0A33C40D389" This is an S/MIME signed message ------46F1AAD10BE922477643C0A33C40D389 %s ------46F1AAD10BE922477643C0A33C40D389 Content-Type: application/%spkcs7-signature; name="smime.p7s" Content-Transfer-Encoding: base64 Content-Disposition: attachment; filename="smime.p7s" %s ------46F1AAD10BE922477643C0A33C40D389-- ''' % (prefix, hashalgo, datau, prefix, datas) return s def build(self, datau, key, cert, othercerts, hashalgo, attrs, pss=False): datau = datau.replace(b'\n', b'\r\n') datas = signer.sign(datau, key, cert, othercerts, hashalgo, attrs, pss=pss) datas = base64.encodebytes(datas) if hashalgo == 'sha1': hashalgo = b'sha1' elif hashalgo == 'sha256': hashalgo = b'sha-256' elif hashalgo == 'sha512': hashalgo = b'sha-512' prefix = [b'x-', b''][pss] data = self.email(hashalgo, datau, datas, prefix) return data def sign(datau:bytes, key: PrivateKeyTypes, cert: x509.Certificate, certs: list[x509.Certificate], hashalgo='sha1', attrs=True, pss=False)->bytes: """ Sign data with private key and encapsulate the result (data and signature) as S/MIME message. :param datau: Data to sign (bytes). :param key: Private key to sign with (PrivateKeyTypes). :param cert: Certificate to sign with (x509.Certificate). :param certs: List of additional certificates (list of x509.Certificate). :param hashalgo: Hash algorithm to use (str, default 'sha1'). :param attrs: Whether to include attributes (bool, default True). :param pss: Whether to use PSS padding (bool, default False). :return: Signed data as bytes. """ cls = SignedData() return cls.build(datau, key, cert, certs, hashalgo, attrs, pss) endesive-2.19.1/endesive/email/verify.py000066400000000000000000000025451504236674500201770ustar00rootroot00000000000000# *-* coding: utf-8 *-* from email import message_from_string from cryptography import x509 from endesive import verifier def verify(data:bytes, certs:list[x509.Certificate]=None) -> tuple[bool, bool, bool]: """ Verifiy S/MIME signed email. :param data: Email data as bytes. :param certs: List of additional certificates used to verify signature (system independent). :return: hashok, signatureok, certok hashok: bool True if the hash matches. signatureok: bool True if the signature is valid. certok: bool True if the certificate used for signing is trusted and valid. """ msg = message_from_string(data) sig = None plain = None for part in msg.walk(): ct = part.get_content_type() # multipart/* are just containers if ct.split('/')[0] == 'multipart': continue if ct == 'application/x-pkcs7-signature': sig = part.get_payload(decode=True) elif ct == 'application/pkcs7-signature': sig = part.get_payload(decode=True) elif ct == 'text/plain': plain = part.get_payload(decode=False) if sig is None: raise ValueError('not signed email') plain = plain.encode('utf-8') plain = plain.replace(b'\n', b'\r\n') return verifier.verify(sig, plain, certs) endesive-2.19.1/endesive/hsm.py000066400000000000000000000503541504236674500163740ustar00rootroot00000000000000#!/usr/bin/env vpython3 # coding: utf-8 import os import sys import binascii import datetime import PyKCS11 import base64 import hashlib from cryptography import x509 from cryptography.hazmat.primitives import hashes from cryptography.hazmat.primitives import serialization from asn1crypto import x509 as asn1x509 from asn1crypto import keys as asn1keys from asn1crypto import pem as asn1pem from asn1crypto import util as asn1util import paramiko.agent import cryptography class BaseHSM: def certificate(self): """ callback for HSM used to identfy the ssh agents key exports via fingerprint :return: public-key-fingerprint, certificate-in-pem """ raise NotImplementedError() def sign(self, keyid, data, mech): """ sign :param keyid: the keyid as returned by certificate() :param data: :param mech: hash algo :return: PKCS7 signature blob """ raise NotImplementedError() class HSM(BaseHSM): def __init__(self, dllpath): """ Initialize HSM :param dllpath: dynamic library used to communicate with HSM """ self.pkcs11 = PyKCS11.PyKCS11Lib() self.pkcs11.load(dllpath) self.session = None def getSlot(self, label): """ Find the slot :param label: searched slot name :return: slot """ slots = self.pkcs11.getSlotList(tokenPresent=True) for slot in slots: info = self.pkcs11.getTokenInfo(slot) try: if info.label.split("\0")[0].strip() == label: return slot except AttributeError: continue return None def create(self, label, pin, sopin): """ Initialize a slot :param label: searched slot name :param pin: pin for slot :param sopin: administrative pin """ slot = self.getSlot(label) if slot is not None: return slot = self.pkcs11.getSlotList(tokenPresent=True)[-1] self.pkcs11.initToken(slot, sopin, label) session = self.pkcs11.openSession( slot, PyKCS11.CKF_SERIAL_SESSION | PyKCS11.CKF_RW_SESSION ) session.login(sopin, user_type=PyKCS11.CKU_SO) session.initPin(pin) session.logout() session.closeSession() def login(self, label, pin): """ Start session :param label: slot name :param pin: pin for slot """ slot = self.getSlot(label) if slot is None: return self.session = self.pkcs11.openSession( slot, PyKCS11.CKF_SERIAL_SESSION | PyKCS11.CKF_RW_SESSION ) self.session.login(pin) def logout(self): """ End session """ if self.session is not None: self.session.logout() self.session.closeSession() self.session = None def gen_privkey(self, label, key_id, key_length=2048): """ Create private key :param label: key label :param key_id: key ID :param key_length: key length in bits """ # label - just a label for identifying objects # key_id has to be the same for both objects, it will also be necessary # when importing the certificate, to ensure it is linked with these keys. # key_length - key-length in bits public_template = [ (PyKCS11.CKA_CLASS, PyKCS11.CKO_PUBLIC_KEY), (PyKCS11.CKA_TOKEN, PyKCS11.CK_TRUE), (PyKCS11.CKA_PRIVATE, PyKCS11.CK_FALSE), (PyKCS11.CKA_MODULUS_BITS, key_length), # (PyKCS11.CKA_PUBLIC_EXPONENT, (0x01, 0x00, 0x01)), (PyKCS11.CKA_ENCRYPT, PyKCS11.CK_TRUE), (PyKCS11.CKA_VERIFY, PyKCS11.CK_TRUE), (PyKCS11.CKA_VERIFY_RECOVER, PyKCS11.CK_TRUE), (PyKCS11.CKA_WRAP, PyKCS11.CK_TRUE), (PyKCS11.CKA_LABEL, label), (PyKCS11.CKA_ID, key_id) # (PyKCS11.CKA_KEY_TYPE, PyKCS11.CKK_RSA), # (PyKCS11.CKA_SENSITIVE, PyKCS11.CK_FALSE), ] private_template = [ (PyKCS11.CKA_CLASS, PyKCS11.CKO_PRIVATE_KEY), (PyKCS11.CKA_TOKEN, PyKCS11.CK_TRUE), (PyKCS11.CKA_PRIVATE, PyKCS11.CK_TRUE), (PyKCS11.CKA_DECRYPT, PyKCS11.CK_TRUE), (PyKCS11.CKA_SIGN, PyKCS11.CK_TRUE), (PyKCS11.CKA_SIGN_RECOVER, PyKCS11.CK_TRUE), (PyKCS11.CKA_UNWRAP, PyKCS11.CK_TRUE), (PyKCS11.CKA_LABEL, label), (PyKCS11.CKA_ID, key_id) # (PyKCS11.CKA_SENSITIVE, PyKCS11.CK_TRUE), ] self.session.generateKeyPair(public_template, private_template) def cert_save(self, cert, label, subject, key_id): """ Save certificate :param cert: certificate :param label: certificate label :param subject: certificate subject :param key_id: key ID """ cert_template = [ (PyKCS11.CKA_CLASS, PyKCS11.CKO_CERTIFICATE), (PyKCS11.CKA_CERTIFICATE_TYPE, PyKCS11.CKC_X_509), (PyKCS11.CKA_TOKEN, PyKCS11.CK_TRUE), (PyKCS11.CKA_LABEL, label.encode("utf-8")), ( PyKCS11.CKA_ID, key_id, ), # must be set, and DER see Table 24, X.509 Certificate Object Attributes ( PyKCS11.CKA_SUBJECT, subject.encode("utf-8"), ), # must be set and DER, see Table 24, X.509 Certificate Object Attributes # (PyKCS11.CKA_PRIVATE, PyKCS11.CK_FALSE), # (PyKCS11.CKA_TRUSTED, PyKCS11.CK_TRUE), # (PyKCS11.CKA_SENSITIVE, PyKCS11.CK_FALSE), # (PyKCS11.CKA_ENCRYPT, PyKCS11.CK_TRUE), # (PyKCS11.CKA_VERIFY, PyKCS11.CK_TRUE), # (PyKCS11.CKA_MODIFIABLE, PyKCS11.CK_TRUE), # (PyKCS11.CKA_ISSUER, cert.Issuer); # (PyKCS11.CKA_SERIAL_NUMBER,cert.SerialNumber) (PyKCS11.CKA_VALUE, cert), # must be BER-encoded ] self.session.createObject(cert_template) def cert_load(self, keyID): """ Load certificate :param keyID: key ID """ rec = self.session.findObjects( [(PyKCS11.CKA_CLASS, PyKCS11.CKO_CERTIFICATE), (PyKCS11.CKA_ID, keyID)] ) if len(rec) == 0: return None value = bytes(rec[0].to_dict()["CKA_VALUE"]) return value def certsign(self, sn, pubKey, subject, until, caprivKey, ca): """ Sign certificate :param sn: serial number :param pubKey: public key :param subject: common name for certificate subject :param until: until when is the certificate valid :param caprivKey: signing key :param ca: None: create self signed root CA certificate True: create indirect CA certificate False: create user certificate """ args = { "version": "v3", "serial_number": sn, "issuer": asn1x509.Name.build({ "common_name": "hsm Root CA", }), "subject": asn1x509.Name.build({ "common_name": subject, }), "signature": { "algorithm": "sha256_rsa", "parameters": None, }, "validity": { "not_before": asn1x509.Time({ "utc_time": asn1x509.UTCTime((datetime.datetime.utcnow() - datetime.timedelta(days=1)).strftime('%y%m%d%H%M%SZ')), }), "not_after": asn1x509.Time({ "utc_time": asn1x509.UTCTime(until.strftime('%y%m%d%H%M%SZ')), }), }, "subject_public_key_info": { "algorithm": { "algorithm": "rsa", "parameters": None, }, "public_key": pubKey, }, } if ca is None: args["issuer"] = asn1x509.Name.build({ "common_name": subject, }) args.update({ "extensions": [ { "extn_id": "basic_constraints", "critical": True, "extn_value": {"ca": True, "path_len_constraint": None}, }, { "extn_id": "key_usage", "critical": True, "extn_value": set( [ "crl_sign", "digital_signature", "key_cert_sign", ] ), }, ] }) elif ca: extensions = [ { # 'extn_id': 'crl_distribution_points', # 'critical': False, # 'extn_value': [ # asn1util.OrderedDict([ # ('distribution_point', ['http://ca.trisoft.com.pl/crl']), # ('reasons', None), # ('crl_issuer', None), # ]), # ] #}, { # 'extn_id':'authority_information_access', # 'critical': False, # 'extn_value': [ # { # 'access_method': 'ca_issuers', # 'access_location': asn1x509.URI('http://ca.trisoft.com.pl/cacert'), # }, { # 'access_method': 'ocsp', # 'access_location': asn1x509.URI('http://ca.trisoft.com.pl/ocsp'), # } # ] #}, { 'extn_id': 'authority_key_identifier', 'critical': False, 'extn_value': { 'key_identifier': None, 'authority_cert_issuer': None, 'authority_cert_serial_number': 1, } #}, { # 'extn_id': 'key_identifier', # 'critical': False, # 'extn_value': b'', }, { "extn_id": "basic_constraints", "critical": True, "extn_value": {"ca": True, "path_len_constraint": 0}, }, { "extn_id": "key_usage", "critical": True, "extn_value": set([ "crl_sign", "digital_signature", "key_cert_sign", ]), }, ] args.update({ "extensions": extensions }) else: extensions = [ #asn1util.OrderedDict([ # ('extn_id', 'subject_alt_name'), # ('critical', False), # ('extn_value', ['demo1@trisoft.com.pl']) #]), { # 'extn_id': 'subject_alt_name', # 'critical': False, # 'extn_value': {'rfc822_name' : 'demo1@trisoft.com.pl'}, #}, { 'extn_id': 'authority_key_identifier', 'critical': False, 'extn_value': { 'key_identifier': None, 'authority_cert_issuer': None, 'authority_cert_serial_number': 2, } #}, { # 'extn_id': 'key_identifier', # 'critical': False, # 'extn_value': b'', }, { "extn_id": "basic_constraints", "critical": True, "extn_value": {"ca": False}, }, { "extn_id": "key_usage", "critical": True, "extn_value": set([ "digital_signature", "key_agreement", "key_encipherment", "non_repudiation", ]), }, ] args.update({ "issuer": asn1x509.Name.build({ "common_name": "hsm Indirect CA", }), "extensions": extensions, }) tbs = asn1x509.TbsCertificate(args) # Sign the TBS Certificate data = tbs.dump() value = self.session.sign( caprivKey, data, PyKCS11.Mechanism(PyKCS11.CKM_SHA256_RSA_PKCS, None) ) value = bytes(bytearray(value)) cert = asn1x509.Certificate( { "tbs_certificate": tbs, "signature_algorithm": { "algorithm": "sha256_rsa", "parameters": None, }, "signature_value": value, } ) return cert.dump() def ca_gen(self, label, keyID, subject): """ Initiate root CA certificate :param label: HSM key label :param keyID: HSM key ID :param subject: common name in certificate subject """ privKey = self.session.findObjects( [(PyKCS11.CKA_CLASS, PyKCS11.CKO_PRIVATE_KEY), (PyKCS11.CKA_ID, keyID)] )[0] pubKey = self.session.findObjects( [(PyKCS11.CKA_CLASS, PyKCS11.CKO_PUBLIC_KEY), (PyKCS11.CKA_ID, keyID)] )[0] modulus = self.session.getAttributeValue(pubKey, [PyKCS11.CKA_MODULUS])[0] modulus = binascii.hexlify(bytearray(modulus)).decode("utf-8") exponent = self.session.getAttributeValue( pubKey, [PyKCS11.CKA_PUBLIC_EXPONENT] )[0] exponent = binascii.hexlify(bytearray(exponent)).decode("utf-8") pubKey = asn1keys.RSAPublicKey( { "modulus": int("0x" + modulus, 16), "public_exponent": int("0x" + exponent, 16), } ) # pubKey = asn1keys.RSAPublicKey.load(pubKey.dump()) until = datetime.datetime.utcnow() + datetime.timedelta( days=365 * 40 ) der_bytes = self.certsign(1, pubKey, subject, until, privKey, None) self.cert_save(der_bytes, label, subject, keyID) def ca_sign(self, keyID, label, sn, subject, days, cakeyID): """ Sign certificate :param keyID: HSM key identifier of the signed certificate :param label: HSM label :param sn: certificate serial number :param subject: HSM subject, common name stored in subject fiel of the signed certificate :param days: validity day of certificate :param cakeyID: HSM key identifier of the signing key """ caprivKey = self.session.findObjects( [(PyKCS11.CKA_CLASS, PyKCS11.CKO_PRIVATE_KEY), (PyKCS11.CKA_ID, cakeyID)] )[0] pubKey = self.session.findObjects( [(PyKCS11.CKA_CLASS, PyKCS11.CKO_PUBLIC_KEY), (PyKCS11.CKA_ID, keyID)] )[0] modulus = self.session.getAttributeValue(pubKey, [PyKCS11.CKA_MODULUS])[0] modulus = binascii.hexlify(bytearray(modulus)).decode("utf-8") exponent = self.session.getAttributeValue( pubKey, [PyKCS11.CKA_PUBLIC_EXPONENT] )[0] exponent = binascii.hexlify(bytearray(exponent)).decode("utf-8") pubKey = asn1keys.RSAPublicKey( { "modulus": int("0x" + modulus, 16), "public_exponent": int("0x" + exponent, 16), } ) # pubKey = asn1keys.RSAPublicKey.load(pubKey.dump()) until = datetime.datetime.utcnow() + datetime.timedelta( days=days ) der_bytes = self.certsign(sn, pubKey, subject, until, caprivKey, keyID == b'\x02') self.cert_save(der_bytes, label, subject, keyID) def cert_export(self, fname, keyID): der_bytes = self.cert_load(keyID) pem_bytes = asn1pem.armor("CERTIFICATE", der_bytes) with open(fname + ".der", "wb") as fp: fp.write(der_bytes) with open(fname + ".pem", "wb") as fp: fp.write(pem_bytes) class SSHAgentHSM(BaseHSM): def __init__(self, cert): assert isinstance(cert, cryptography.x509.Certificate) self._a = paramiko.agent.Agent() self._cert = cert def close(self): self._a.close() def certificate(self): """ callback for HSM used to identfy the ssh agents key exports via fingerprint :return: public-key-fingerprint, certificate-in-pem """ # https://superuser.com/questions/421997/what-is-a-ssh-key-fingerprint-and-how-is-it-generated # convert RSA Key to SSH Fingerprint alg, key = ( self._cert.public_key() .public_bytes( encoding=cryptography.hazmat.primitives.serialization.Encoding.OpenSSH, format=cryptography.hazmat.primitives.serialization.PublicFormat.OpenSSH, ) .split(b" ") ) fp = b"SHA256:" + base64.b64encode( hashlib.sha256(base64.b64decode(key)).digest() ) cert = self._cert.public_bytes( cryptography.hazmat.primitives.serialization.Encoding.PEM ) return fp, cert @staticmethod def _decode_fp(keyfp): """ decode a fingerprint :param keyfp: key fingerprint in OpenSSH Format :return: alg, fingerprint-binary """ if not isinstance(keyfp, str): keyfp = keyfp.decode() alg, other = keyfp.split(":", 1) if alg == "SHA256": # pad base64 data data = other.encode() + b"=" * (-len(other) % 4) fp = base64.b64decode(data) elif alg == "MD5": data = other.replace(":", " ") fp = bytes.fromhex(data) else: raise ValueError(alg) return alg.lower(), fp def key(self, fp): """ lookup a ssh-agent-exported key using fingerprint :param fp: the fingerprint :return: the key on success """ alg, fp = self._decode_fp(fp) for key in self._a.get_keys(): kfp = getattr(hashlib, alg)(key.asbytes()).digest() if kfp == fp: break else: raise ValueError("Key not found") return key def sign(self, keyid, data, hashalgo): """ sign using ssh-agent sign_data creates RSA signature with padding=PKCS1v15 alg=SHA1 :param keyid: the keyid as returned by certificate() :param data: :param hashalgo: has to be sha1, sha256 or sha512 :return: PKCS7 signature blob """ assert hashalgo in ("sha1", "sha256", "sha512") if not isinstance(data, bytes): data = data.encode() # defined in # SSH Agent Protocol draft-miller-ssh-agent-00 5.3. Signature flags # https://tools.ietf.org/html/draft-miller-ssh-agent-00#section-5.3 flags = { "sha1": 0, "sha256": 2, # SSH_AGENT_RSA_SHA2_256 "sha512": 4, # SSH_AGENT_RSA_SHA2_512 }[hashalgo] key = self.key(keyid) # AgentKey.sign_ssh_data is padding=PKCS1v15 alg=SHA1 # paramiko does not expose the ssh-agent sign flags to use sha2-256/512 # re-implement sign_ssh_agent .. msg = paramiko.message.Message() msg.add_byte(paramiko.agent.cSSH2_AGENTC_SIGN_REQUEST) msg.add_string(key.blob) msg.add_string(data) msg.add_int(flags) ptype, result = self._a._send_message(msg) if ptype != paramiko.agent.SSH2_AGENT_SIGN_RESPONSE: raise paramiko.SSHException("key cannot be used for signing") d = paramiko.message.Message(result.get_binary()) # parse operation result alg = d.get_text() # interpret if alg in ("ssh-rsa", "rsa-sha2-256", "rsa-sha2-512"): sig = d.get_binary() else: raise ValueError(alg) return sig endesive-2.19.1/endesive/pdf/000077500000000000000000000000001504236674500157755ustar00rootroot00000000000000endesive-2.19.1/endesive/pdf/PyPDF2/000077500000000000000000000000001504236674500170015ustar00rootroot00000000000000endesive-2.19.1/endesive/pdf/PyPDF2/__init__.py000066400000000000000000000003221504236674500211070ustar00rootroot00000000000000from .pdf import PdfFileReader, PdfFileWriter from .merger import PdfFileMerger from .pagerange import PageRange, parse_filename_page_ranges from ._version import __version__ __all__ = ["pdf", "PdfFileMerger"] endesive-2.19.1/endesive/pdf/PyPDF2/_version.py000066400000000000000000000000271504236674500211760ustar00rootroot00000000000000__version__ = '1.26.0' endesive-2.19.1/endesive/pdf/PyPDF2/filters.py000066400000000000000000000373261504236674500210360ustar00rootroot00000000000000# 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" import math from .utils import PdfReadError, ord_, chr_, paethPredictor 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 elif filterByte == 3: for i in range(1, rowlength): left = rowdata[i-1] if i > 1 else 0 floor = math.floor(left + prev_rowdata[i])/2 rowdata[i] = (rowdata[i] + int(floor)) % 256 elif filterByte == 4: for i in range(1, rowlength): left = rowdata[i - 1] if i > 1 else 0 up = prev_rowdata[i] up_left = prev_rowdata[i - 1] if i > 1 else 0 paeth = paethPredictor(left, up, up_left) rowdata[i] = (rowdata[i] + paeth) % 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) class DCTDecode(object): def decode(data, decodeParms=None): return data decode = staticmethod(decode) class JPXDecode(object): def decode(data, decodeParms=None): return data decode = staticmethod(decode) class CCITTFaxDecode(object): def decode(data, decodeParms=None, height=0): if decodeParms: if decodeParms.get("/K", 1) == -1: CCITTgroup = 4 else: CCITTgroup = 3 width = decodeParms["/Columns"] imgSize = len(data) tiff_header_struct = '<' + '2s' + 'h' + 'l' + 'h' + 'hhll' * 8 + 'h' tiffHeader = struct.pack(tiff_header_struct, b'II', # Byte order indication: Little endian 42, # Version number (always 42) 8, # Offset to first IFD 8, # Number of tags in IFD 256, 4, 1, width, # ImageWidth, LONG, 1, width 257, 4, 1, height, # ImageLength, LONG, 1, length 258, 3, 1, 1, # BitsPerSample, SHORT, 1, 1 259, 3, 1, CCITTgroup, # Compression, SHORT, 1, 4 = CCITT Group 4 fax encoding 262, 3, 1, 0, # Thresholding, SHORT, 1, 0 = WhiteIsZero 273, 4, 1, struct.calcsize(tiff_header_struct), # StripOffsets, LONG, 1, length of header 278, 4, 1, height, # RowsPerStrip, LONG, 1, length 279, 4, 1, imgSize, # StripByteCounts, LONG, 1, size of image 0 # last IFD ) return tiffHeader + data 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 == "/DCTDecode": data = DCTDecode.decode(data) elif filterType == "/JPXDecode": data = JPXDecode.decode(data) elif filterType == "/CCITTFaxDecode": height = stream.get("/Height", ()) data = CCITTFaxDecode.decode(data, stream.get("/DecodeParms"), height) 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 endesive-2.19.1/endesive/pdf/PyPDF2/generic.py000066400000000000000000001311251504236674500207720ustar00rootroot00000000000000# 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) # Prevents an infinite loop by raising an error if the stream is at # the EOF if len(tok) <= 0: raise PdfStreamError("File ended unexpectedly.") tok = readNonWhitespace(stream) stream.seek(-1, 1) return readObject(stream, pdf) else: # number object OR indirect reference 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: # Standard formatting adds useless extraneous zeros. o = "%.5f" % self # Remove the zeros. while o and o[-1] == '0': o = o[:-1] return o 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) ESCAPE_DICT = {b_("n") : b_("\n"), b_("r") : b_("\r"), b_("t") : b_("\t"), b_("b") : b_("\b"), b_("f") : b_("\f"), b_("c") : b_(r"\c"), b_("(") : b_("("), b_(")") : b_(")"), b_("/") : b_("/"), b_("\\") : b_("\\"), b_(" ") : b_(" "), b_("/") : b_("/"), b_("%") : b_("%"), b_("<") : b_("<"), b_(">") : b_(">"), b_("[") : b_("["), b_("]") : b_("]"), b_("#") : b_("#"), b_("_") : b_("_"), b_("&") : b_("&"), b_('$') : b_('$'), } try: tok = ESCAPE_DICT[tok] except KeyError: if 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 endesive-2.19.1/endesive/pdf/PyPDF2/merger.py000066400000000000000000000516471504236674500206510ustar00rootroot00000000000000# 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 hasattr(fileobj, "seek") and hasattr(fileobj, "read"): 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() endesive-2.19.1/endesive/pdf/PyPDF2/pagerange.py000066400000000000000000000126361504236674500213140ustar00rootroot00000000000000#!/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 endesive-2.19.1/endesive/pdf/PyPDF2/pdf.py000066400000000000000000003744641504236674500201460ustar00rootroot00000000000000# -*- 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 import uuid 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) }) js_indirect_object = self._addObject(js) # We need a name for parameterized javascript in the pdf file, but it can be anything. js_string_name = str(uuid.uuid4()) js_name_tree = DictionaryObject() js_name_tree.update({ NameObject("/JavaScript"): DictionaryObject({ NameObject("/Names"): ArrayObject([createStringObject(js_string_name), js_indirect_object]) }) }) self._addObject(js_name_tree) self._root_object.update({ NameObject("/OpenAction"): js_indirect_object, NameObject("/Names"): js_name_tree }) 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")) stream.write(b_("%\xE2\xE3\xCF\xD3\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 addURI(self, pagenum, uri, rect, border=None): """ Add an URI from a rectangular area to the specified page. This uses the basic structure of AddLink :param int pagenum: index of the page on which to place the URI action. :param int uri: string -- uri of resource to link to. :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. REMOVED FIT/ZOOM ARG -John Mulligan """ pageLink = self.getObject(self._pages)['/Kids'][pagenum] 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(2)] * 3 if isString(rect): rect = NameObject(rect) elif isinstance(rect, RectangleObject): pass else: rect = RectangleObject(rect) lnk2 = DictionaryObject() lnk2.update({ NameObject('/S'): NameObject('/URI'), NameObject('/URI'): TextStringObject(uri) }); lnk = DictionaryObject() lnk.update({ NameObject('/Type'): NameObject('/Annot'), NameObject('/Subtype'): NameObject('/Link'), NameObject('/P'): pageLink, NameObject('/Rect'): rect, NameObject('/H'): NameObject('/I'), NameObject('/Border'): ArrayObject(borderArr), NameObject('/A'): lnk2 }) lnkRef = self._addObject(lnk) if "/Annots" in pageRef: pageRef['/Annots'].append(lnkRef) else: pageRef[NameObject('/Annots')] = ArrayObject([lnkRef]) 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.xrefstream = False self.startxref = 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 getFormTextFields(self): ''' Retrieves form fields from the document with textual data (inputs, dropdowns) ''' # Retrieve document form fields formfields = self.getFields() return dict( (formfields[field]['/T'], formfields[field].get('/V')) for field in formfields \ if formfields[field].get('/FT') == '/Tx' ) 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 and self.strict: # some other problem raise utils.PdfReadError("Expected object ID (%d %d) does not match actual (%d %d)." \ % (indirectReference.idnum, indirectReference.generation, idnum, generation)) if self.strict: 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") self.startxref = startxref self.xrefstream = False # 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 if self.strict: warnings.warn("Xref table not zero-indexed. ID numbers for objects will be corrected.", 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, only warned and corrected if self.strict=True 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.xrefstream = True 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", "/Size" 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_parts = [] 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_parts.append(x) if debug: print("leaving RNEL") line_parts.reverse() return b"".join(line_parts) 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. This PDF uses code %s" % encrypt['/V']) 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): rotateObj = self.get("/Rotate", 0) currentAngle = rotateObj if isinstance(rotateObj, int) else rotateObj.getObject() 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.raw_get(key) != page2Res.raw_get(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 text += "\n" 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 += b_(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"): # Data can contain EI, so check for the Q operator. tok3 = stream.read(1) info = tok + tok2 # We need to find whitespace between EI and Q. has_q_whitespace = False while tok3 in utils.WHITESPACES: has_q_whitespace = True info += tok3 tok3 = stream.read(1) if tok3 == b_("Q") and has_q_whitespace: 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 == b_("INLINE IMAGE"): newdata.write(b_("BI")) dicttext = BytesIO() operands["settings"].writeToStream(dicttext, None) newdata.write(dicttext.getvalue()[2:-2]) newdata.write(b_("ID ")) newdata.write(operands["data"]) newdata.write(b_("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. if p_entry < 0: 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 endesive-2.19.1/endesive/pdf/PyPDF2/utils.py000066400000000000000000000177551504236674500205320ustar00rootroot00000000000000# 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 = [] 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.append(b_(chr(ord_(plaintext[x]) ^ t))) return b_("").join(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']] def paethPredictor(left, up, up_left): p = left + up - up_left dist_left = abs(p - left) dist_up = abs(p - up) dist_up_left = abs(p - up_left) if dist_left <= dist_up and dist_left <= dist_up_left: return left elif dist_up <= dist_up_left: return up else: return up_left endesive-2.19.1/endesive/pdf/PyPDF2/xmp.py000066400000000000000000000325071504236674500201660ustar00rootroot00000000000000import 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 """ endesive-2.19.1/endesive/pdf/PyPDF2_annotate/000077500000000000000000000000001504236674500206725ustar00rootroot00000000000000endesive-2.19.1/endesive/pdf/PyPDF2_annotate/__init__.py000066400000000000000000000003651504236674500230070ustar00rootroot00000000000000# -*- coding: utf-8 -*- from .annotator import PdfAnnotator from .config.appearance import Appearance from .config.location import Location from .config.metadata import Metadata __all__ = ['PdfAnnotator', 'Appearance', 'Location', 'Metadata'] endesive-2.19.1/endesive/pdf/PyPDF2_annotate/annotations/000077500000000000000000000000001504236674500232275ustar00rootroot00000000000000endesive-2.19.1/endesive/pdf/PyPDF2_annotate/annotations/__init__.py000066400000000000000000000000001504236674500253260ustar00rootroot00000000000000endesive-2.19.1/endesive/pdf/PyPDF2_annotate/annotations/base.py000066400000000000000000000172021504236674500245150ustar00rootroot00000000000000# -*- coding: utf-8 -*- """ Annotation ~~~~~~~~~~~~ Base annotation class. :copyright: Copyright 2019 Autodesk, Inc. :license: MIT, see LICENSE for details. """ from ..pdfrw import PdfDict, PdfArray, PdfName, IndirectPdfDict from ..config.constants import GRAPHICS_STATE_NAME from ..config.metadata import serialize_value from ..util.geometry import transform_rect from ..util.geometry import translate ALL_VERSIONS = ("1.3", "1.4", "1.5", "1.6", "1.7") class Annotation(object): """Base class for all PDF annotation objects. Concrete annotations should define the following: * subtype (e.g. "Square") * make_rect() - bounding box of annotation * add_additional_pdf_object_data [optional] - additional entries to go in the PDF object * add_additional_resources [optional] - additional entries to go in the Resources sub-dict of the annotation There is a lot of nuance and viewer-specific (mostly Acrobat and Bluebeam) details to consider when creating PDF annotations. One big thing that's not immediately clear from the PDF spec is that wherever possible, we fill in the annotations' type-specific details (e.g. BE and IC for squares), but also create and include an Appearance Stream. The latter gives us control over exactly how the annotation appears across different viewers, while the former allows Acrobat or BB to regenerate the appearance stream during editing. """ versions = ALL_VERSIONS def __init__(self, location, appearance, metadata=None): """ :param Location location: :param Appearance appearance: :param Metadata metadata: """ self._location = location self._appearance = appearance self._metadata = metadata def as_pdf_object(self, transform, page): """Return the PdfDict object representing the annotation, that will be inserted as is into the PDF document. :param list transform: Transformation matrix to transform the coords of the annotation from client-specified space to PDF user space. :param PdfDict page: The pdfrw page object from the PDF document :returns PdfDict: the annotation object to be inserted into the PDF """ bounding_box = transform_rect(self.make_rect(), transform) appearance_stream = self._make_appearance_stream_dict(bounding_box, transform) obj = PdfDict( Type=PdfName("Annot"), Subtype=PdfName(self.subtype), Rect=bounding_box, AP=appearance_stream, P=page, ) self._add_metadata(obj, self._metadata) self.add_additional_pdf_object_data(obj) obj.indirect = True return obj @property def page(self): return self._location.page def validate(self, pdf_version): """Validate a new annotation against a given PDF version.""" pass def _add_metadata(self, obj, metadata): if metadata is None: return for name, value in metadata.iter(): obj[PdfName(name)] = serialize_value(value) def _make_ap_resources(self): """Make the Resources entry for the appearance stream dictionary. Implement add_additional_resources to add additional entries - fonts, XObjects, graphics state - to the Resources dictionary. """ resources = IndirectPdfDict(ProcSet=PdfArray([PdfName("PDF")])) self._add_graphics_state_resources(resources, self._appearance) self._add_xobject_resources(resources, self._appearance) self._add_font_resources(resources, self._appearance) self.add_additional_resources(resources) return resources @staticmethod def _add_font_resources(resources, A): if A.fonts: resources.Font = IndirectPdfDict() for font_name, font in A.fonts.items(): resources.Font[PdfName(font_name)] = font @staticmethod def _add_xobject_resources(resources, A): """Adds in provided, explicit XObjects into the appearance stream's Resources dict. This is used when the user is explicitly specifying the appearance stream and they want to include, say, an image. """ if A.xobjects: resources.XObject = IndirectPdfDict() for xobject_name, xobject in A.xobjects.items(): resources.XObject[PdfName(xobject_name)] = xobject @staticmethod def _add_graphics_state_resources(resources, A): """Add in the resources dict for turning on transparency in the graphics state. For example, if both stroke and fill were transparent, this would add: << /ExtGState /PdfAnnotatorGS << /CA 0.5 /ca 0.75 /Type /ExtGState >> >> to the Resources dict. Graphics states can also be specified externally, for use in explicit content streams. This is done by using the `graphics_states` property on the appearance object. """ states = [] internal_state = Annotation._get_internal_graphics_state(resources, A) if internal_state is not None: states.append((GRAPHICS_STATE_NAME, internal_state)) if A.graphics_states: for name, state in A.graphics_states.items(): states.append((name, state.as_pdf_dict())) if states: resources.ExtGState = PdfDict() for name, state in states: resources.ExtGState[PdfName(name)] = state @staticmethod def _get_internal_graphics_state(resources, A): internal_state = A.get_graphics_state() if internal_state.has_content(): return internal_state.as_pdf_dict() return None def _make_appearance_stream_dict(self, bounding_box, transform): # Either use user-specified content stream or generate content stream # based on annotation type. stream = self._appearance.appearance_stream if stream is None: stream = self.make_appearance_stream() resources = self._make_ap_resources() # Transform the appearance stream into PDF space and turn it into a str appearance_stream = stream.transform(transform).resolve() normal_appearance = IndirectPdfDict( stream=appearance_stream, BBox=bounding_box, Resources=resources, Matrix=translate(-bounding_box[0], -bounding_box[1]), Type=PdfName("XObject"), Subtype=PdfName("Form"), FormType=1, ) return PdfDict(N=normal_appearance) def add_additional_pdf_object_data(self, obj): """Add additional keys to the PDF object. Default is a no-op. :param PdfDict obj: the PDF object to be inserted into the PDF """ pass def add_additional_resources(self, resources): """Add additional keys to the Resources PDF dictionary. Default is a no-op. :param PdfDict resources: Resources PDF dictionary """ pass def make_rect(self): """Return a bounding box that encompasses the entire annotation.""" raise NotImplementedError() def make_border_dict(appearance): A = appearance return _make_border_dict(A.stroke_width, A.border_style, A.dash_array) def _make_border_dict(width, style, dash_array=None): border = PdfDict(Type=PdfName("Border"), W=width, S=PdfName(style)) if dash_array: if style != "D": raise ValueError("Dash array only applies to dashed borders!") border.D = dash_array return border class Stamp(object): subtype = "Stamp" endesive-2.19.1/endesive/pdf/PyPDF2_annotate/annotations/image.py000066400000000000000000000215721504236674500246720ustar00rootroot00000000000000# -*- coding: utf-8 -*- """ Image ~~~~~~~~~~~~ Image annotation class. :copyright: Copyright 2019 Autodesk, Inc. :license: MIT, see LICENSE for details. """ import sys import zlib from io import BytesIO from PIL import Image as PILImage from PIL.ImageFile import ImageFile from ..pdfrw import PdfDict, PdfName, IndirectPdfDict from .rect import RectAnnotation from ..config.appearance import set_appearance_state from ..config.constants import CMYK_MODE from ..config.constants import GRAYSCALE_ALPHA_MODE from ..config.constants import GRAYSCALE_MODE from ..config.constants import PALETTE_MODE from ..config.constants import RGB_MODE from ..config.constants import RGBA_MODE from ..config.constants import SINGLE_CHANNEL_MODE from ..graphics import ContentStream from ..graphics import CTM from ..graphics import Rect from ..graphics import Restore from ..graphics import Save from ..graphics import XObject from ..util.geometry import matrix_multiply from ..util.geometry import scale from ..util.geometry import translate class Image(RectAnnotation): """A basic Image annotation class. There is no native image annotation in the PDF spec, but image annotations can be easily approximated by drawing an Image XObject in the appearance stream. Supported formats are PNG, JPEG, and GIF. Only the first frame from multi- frame GIFs is used. This implementation relies on the python Pillow library to retrieve the image's raw sample data, then formats that data as expected by the PDF spec. Additional work needs to be done. For example: - supporting the reading of transparency directly from RGBA images - better compression (e.g. using a Predictor value for FlateDecode) - supporting DeviceCMYK directly """ subtype = "Square" _image_xobject = None # PdfDict of Image XObject def add_additional_resources(self, resources): resources[PdfName("XObject")] = IndirectPdfDict(Image=self.image_xobject) def add_additional_pdf_object_data(self, obj): obj[PdfName("Image")] = self.image_xobject @property def image_xobject(self): if self._image_xobject is None: self._image_xobject = self.make_image_xobject(self._appearance.image) return self._image_xobject @staticmethod def make_image_xobject(image): """Construct a PdfDict representing the Image XObject, for inserting into the AP Resources dict. PNGs and GIFs are treated equally - the raw sample values are included using PDF's FlateDecode compression format. JPEGs can be included in their original form using the DCTDecode filter. PNGs with transparency have the alpha channel split out and included as an SMask, since PDFs don't natively support transparent PNGs. Details about file formats and allowed modes can be found at https://pillow.readthedocs.io/en/5.3.x/handbook/image-file-formats.html :param str|ImageFile image: Either a str representing the path to the image filename, or a PIL.ImageFile.ImageFile object representing the image loaded using the PIL library. :returns PdfDict: Image XObject """ image = Image.resolve_image(image) # PILImage.convert drops the format attribute image_format = image.format width, height = image.size # Normalize images to RGB or grayscale color spaces, and split out the # alpha layer into a PDF smask XObject image, smask_xobj = Image.convert_to_compatible_image(image, image_format) if image_format in ("PNG", "GIF"): content = Image.make_compressed_image_content(image) filter_type = "FlateDecode" # TODO use a predictor elif image_format == "JPEG": content = Image.make_jpeg_image_content(image) filter_type = "DCTDecode" else: raise ValueError( "Unsupported image format: {}. Supported formats are " "PNG, JPEG, and GIF".format(image.format) ) xobj = IndirectPdfDict( stream=content, BitsPerComponent=8, Filter=PdfName(filter_type), ColorSpace=Image._get_color_space_name(image), Width=width, Height=height, Subtype=PdfName("Image"), Type=PdfName("XObject"), ) if smask_xobj is not None: xobj[PdfName("SMask")] = smask_xobj return xobj @staticmethod def convert_to_compatible_image(image, image_format): smask_xobj = None if image_format in ("PNG", "GIF"): if image.mode in (RGBA_MODE, GRAYSCALE_ALPHA_MODE): smask_xobj = Image.get_png_smask(image) # 'P' and 'RGBA' images can just be converted to 'RGB' mode, since # alpha layer is preserved in the smask. if image.mode in (RGBA_MODE, PALETTE_MODE): image = image.convert(RGB_MODE) if image.mode == GRAYSCALE_ALPHA_MODE: image = image.convert(GRAYSCALE_MODE) if image.mode == CMYK_MODE: # The DeviceCMYK PDF color space has some weird properties. In a # future release we can debug these and be smart about it but this # is an easy workaround. image = image.convert(RGB_MODE) return image, smask_xobj @staticmethod def get_png_smask(image): width, height = image.size smask = Image.make_compressed_image_content(image.getchannel("A")) smask_xobj = IndirectPdfDict( stream=smask, Width=width, Height=height, BitsPerComponent=8, Filter=PdfName("FlateDecode"), ColorSpace=PdfName("DeviceGray"), Subtype=PdfName("Image"), Type=PdfName("XObject"), ) return smask_xobj @staticmethod def resolve_image(image_or_filename): if isinstance(image_or_filename, str): return PILImage.open(image_or_filename) elif isinstance(image_or_filename, ImageFile): return image_or_filename raise ValueError( "Invalid image format: {}".format(image_or_filename.__class__.__name__) ) @staticmethod def _get_color_space_name(image): if image.mode == RGB_MODE: return PdfName("DeviceRGB") elif image.mode in (GRAYSCALE_MODE, SINGLE_CHANNEL_MODE): return PdfName("DeviceGray") raise ValueError("Image color space not yet supported") @staticmethod def make_compressed_image_content(image): compressed = zlib.compress(Image.get_raw_image_bytes(image)) return compressed @staticmethod def make_jpeg_image_content(image): file_obj = BytesIO() # This is the only way to preserve the JPEG encoding. It also seems to # recompress the data, so that the raw bytes of this differ from the # raw bytes of the original file. It'll probably be better to provide a # special wrapper around PILImage that preserves the original bytes so # we can just use those for JPEGs. TODO. image.save(file_obj, format="JPEG") return file_obj.getvalue() @staticmethod def get_decoded_bytes(content): # Right now, pdfrw needs strings, not bytes like you'd expect in py3, # for binary stream objects. This might change in future versions. if sys.version_info.major < 3: return content return content.decode("Latin-1") @staticmethod def get_raw_image_bytes(image): if image.mode in (GRAYSCALE_MODE, SINGLE_CHANNEL_MODE): # If this is grayscale or single-channel, we can avoid dealing with # the nested tuples in multi-channel images. This bytes/bytearray # wrapped approach is the only way that works in both py2 and py3. return bytes(bytearray(image.getdata())) elif image.mode == RGB_MODE: raw_image_data = list(image.getdata()) array = bytearray() for rgb in raw_image_data: array.extend(rgb) return bytes(array) raise ValueError("Image color space not yet supported") @staticmethod def get_ctm(x1, y1, x2, y2): """Get the scaled and translated CTM for an image to be placed in the bounding box defined by [x1, y1, x2, y2]. """ return matrix_multiply(translate(x1, y1), scale(x2 - x1, y2 - y1)) def make_appearance_stream(self): A = self._appearance L = self._location stream = ContentStream([Save()]) set_appearance_state(stream, A) stream.extend( [ Rect(L.x1, L.y1, L.x2 - L.x1, L.y2 - L.y1), CTM(self.get_ctm(L.x1, L.y1, L.x2, L.y2)), XObject("Image"), Restore(), ] ) return stream endesive-2.19.1/endesive/pdf/PyPDF2_annotate/annotations/points.py000066400000000000000000000103521504236674500251160ustar00rootroot00000000000000# -*- coding: utf-8 -*- """ Points annotations ~~~~~~~~~~~~~~~~~~~~~~~~~ Annotations that are defined by a series of points: Line, Polygon, Polyline :copyright: Copyright 2019 Autodesk, Inc. :license: MIT, see LICENSE for details. """ from .base import Annotation from .base import make_border_dict from ..pdfrw import PdfArray from ..config.appearance import set_appearance_state from ..config.appearance import stroke_or_fill from ..graphics import Close from ..graphics import ContentStream from ..graphics import Line as CSLine from ..graphics import Move from ..graphics import Restore from ..graphics import Save from ..graphics import Stroke def flatten_points(points): return PdfArray([v for point in points for v in point]) class PointsAnnotation(Annotation): """An abstract annotation that defines its location on the document with an array of points. """ def make_rect(self): L = self._location stroke_width = self._appearance.stroke_width p = L.points[0] min_x, max_x, min_y, max_y = p[0], p[1], p[0], p[1] for x, y in L.points: min_x = min(min_x, x) max_x = max(max_x, x) min_y = min(min_y, y) max_y = max(max_y, y) return [ min_x - stroke_width, min_y - stroke_width, max_x + stroke_width, max_y + stroke_width, ] def base_points_object(self): obj = self.make_base_object() obj.BS = make_border_dict(self._appearance) obj.C = self._appearance.stroke_color # TODO line endings, leader lines, captions return obj class Line(PointsAnnotation): subtype = "Line" def make_appearance_stream(self): A = self._appearance points = self._location.points stream = ContentStream([Save()]) set_appearance_state(stream, A) stream.add(Move(points[0][0], points[0][1])) stream.add(CSLine(points[1][0], points[1][1])) stroke_or_fill(stream, A) stream.add(Restore()) return stream def add_additional_pdf_object_data(self, obj): # TODO line endings, leader lines, captions obj[PdfName("L")] = flatten_points(self._location.points) class Polygon(PointsAnnotation): subtype = "Polygon" versions = ("1.5", "1.6", "1.7") def make_appearance_stream(self): A = self._appearance points = self._location.points stream = ContentStream([Save()]) set_appearance_state(stream, A) stream.add(Move(points[0][0], points[0][1])) for x, y in points[1:]: stream.add(CSLine(x, y)) stream.add(Close()) stroke_or_fill(stream, A) stream.add(Restore()) return stream def add_additional_pdf_object_data(self, obj): if self._appearance.fill: obj[PdfName("IC")] = self._appearance.fill obj[PdfName("Vertices")] = flatten_points(self._location.points) class Polyline(PointsAnnotation): subtype = "PolyLine" versions = ("1.5", "1.6", "1.7") def make_appearance_stream(self): A = self._appearance points = self._location.points stream = ContentStream([Save()]) set_appearance_state(stream, A) stream.add(Move(points[0][0], points[0][1])) for x, y in points[1:]: stream.add(CSLine(x, y)) # TODO add a 'close' attribute? stream.extend([Stroke(), Restore()]) return stream def add_additional_pdf_object_data(self, obj): obj[PdfName("Vertices")] = flatten_points(self._location.points) class Ink(PointsAnnotation): subtype = "Ink" def make_appearance_stream(self): A = self._appearance points = self._location.points stream = ContentStream([Save()]) set_appearance_state(stream, A) stream.add(Move(points[0][0], points[0][1])) # TODO "real" PDF editors do smart smoothing of ink points using # interpolated Bezier curves. for x, y in points[1:]: stream.add(CSLine(x, y)) stream.extend([Stroke(), Restore()]) return stream def add_additional_pdf_object_data(self, obj): obj[PdfName("InkList")] = PdfArray([flatten_points(self._location.points)]) endesive-2.19.1/endesive/pdf/PyPDF2_annotate/annotations/rect.py000066400000000000000000000131031504236674500245340ustar00rootroot00000000000000# -*- coding: utf-8 -*- """ Rectangular Annotations ~~~~~~~~~~~~~~~~~~~~~~~ Annotations defined by a width and a height: Square, Circle :copyright: Copyright 2019 Autodesk, Inc. :license: MIT, see LICENSE for details. """ from .base import Annotation from .base import make_border_dict from ..pdfrw import PdfArray, PdfName from ..config.appearance import set_appearance_state from ..config.appearance import stroke_or_fill from ..graphics import Bezier from ..graphics import Close from ..graphics import ContentStream from ..graphics import Line from ..graphics import Move from ..graphics import quadratic_to_cubic_bezier from ..graphics import Rect from ..graphics import Restore from ..graphics import Save class RectAnnotation(Annotation): """Abstract annotation that defines its location on the document with a width and a height. """ def make_rect(self): stroke_width = self._appearance.stroke_width L = self._location return [ L.x1 - stroke_width, L.y1 - stroke_width, L.x2 + stroke_width, L.y2 + stroke_width, ] def add_additional_pdf_object_data(self, obj): A = self._appearance obj[PdfName("BS")] = make_border_dict(A) obj[PdfName("C")] = A.stroke_color if A.fill: obj[PdfName("IC")] = A.fill padding = A.stroke_width / 2.0 obj[PdfName("RD")] = PdfArray([padding, padding, padding, padding]) class Square(RectAnnotation): subtype = "Square" def make_appearance_stream(self): L = self._location A = self._appearance stream = ContentStream([Save()]) set_appearance_state(stream, A) stream.add(Rect(L.x1, L.y1, L.x2 - L.x1, L.y2 - L.y1)) stroke_or_fill(stream, A) stream.add(Restore()) # TODO dash array return stream def add_rounded_rectangle(stream, x, y, width, height, rx, ry): """Creates a rounded rectangle and adds it to the content stream. :param ContentStream stream: :param float x1: :param float y1: :param float width: :param float height: :param float rx: x radius of the rounded corners :param float ry: y radius of the rounded corners """ stream.add(Move(x + rx, y)) stream.add(Line(x + width - rx, y)) stream.add( quadratic_to_cubic_bezier( start_x=(x + width - rx), start_y=y, control_x=(x + width), control_y=y, end_x=(x + width), end_y=(y + ry), ) ) stream.add(Line(x + width, y + height - ry)) stream.add( quadratic_to_cubic_bezier( start_x=(x + width), start_y=(y + height - ry), control_x=(x + width), control_y=(y + height), end_x=(x + width - rx), end_y=(y + height), ) ) stream.add(Line(x + rx, y + height)) stream.add( quadratic_to_cubic_bezier( start_x=(x + rx), start_y=(y + height), control_x=x, control_y=(y + height), end_x=x, end_y=(y + height - ry), ) ) stream.add(Line(x, y + ry)) stream.add( quadratic_to_cubic_bezier( start_x=x, start_y=(y + ry), control_x=x, control_y=y, end_x=(x + rx), end_y=y, ) ) stream.add(Close()) def add_bezier_circle(stream, x1, y1, x2, y2): """Create a circle from four bezier curves and add it to the content stream, since PDF graphics is missing an ellipse primitive. :param ContentStream stream: :param float x1: :param float y1: :param float x2: :param float y2: """ left_x = x1 right_x = x2 bottom_x = left_x + (right_x - left_x) / 2.0 top_x = bottom_x bottom_y = y1 top_y = y2 left_y = bottom_y + (top_y - bottom_y) / 2.0 right_y = left_y cp_offset = 0.552284749831 # Move to the bottom of the circle, then four curves around. # https://stackoverflow.com/questions/1734745/how-to-create-circle-with-b%C3%A9zier-curves stream.add(Move(bottom_x, bottom_y)) stream.add( Bezier( bottom_x + (right_x - bottom_x) * cp_offset, bottom_y, right_x, right_y - (right_y - bottom_y) * cp_offset, right_x, right_y, ) ) stream.add( Bezier( right_x, right_y + (top_y - right_y) * cp_offset, top_x + (right_x - top_x) * cp_offset, top_y, top_x, top_y, ) ) stream.add( Bezier( top_x - (top_x - left_x) * cp_offset, top_y, left_x, left_y + (top_y - left_y) * cp_offset, left_x, left_y, ) ) stream.add( Bezier( left_x, left_y - (left_y - bottom_y) * cp_offset, bottom_x - (bottom_x - left_x) * cp_offset, bottom_y, bottom_x, bottom_y, ) ) stream.add(Close()) class Circle(RectAnnotation): """Circles and Squares are basically the same PDF annotation but with different content streams. """ subtype = "Circle" def make_appearance_stream(self): L = self._location A = self._appearance stream = ContentStream([Save()]) set_appearance_state(stream, A) add_bezier_circle(stream, L.x1, L.y1, L.x2, L.y2) stroke_or_fill(stream, A) stream.add(Restore()) return stream endesive-2.19.1/endesive/pdf/PyPDF2_annotate/annotations/signature.py000066400000000000000000000455051504236674500256130ustar00rootroot00000000000000# -*- coding: utf-8 -*- """ Signature Annotations ~~~~~~~~~~~~~~~~~~~~~~~ Annotations defined by a width and a height: Square, Circle :copyright: Copyright 2019 Autodesk, Inc. :license: MIT, see LICENSE for details. """ import os.path from ..pdfrw import PdfArray, PdfName, IndirectPdfDict, PdfDict from ..pdfttf import TTFFont from .image import Image from .text import get_text_commands from .base import Annotation from .base import make_border_dict from ..util.geometry import transform_rect from ..util.geometry import identity from ..config.appearance import set_appearance_state from ..config.appearance import stroke_or_fill from ..config.constants import DEFAULT_BASE_FONT from ..config.constants import GRAPHICS_STATE_NAME from ..config.constants import PDF_ANNOTATOR_FONT from ..graphics import BaseCommand, FloatTupleCommand from ..graphics import Bezier from ..graphics import Close from ..graphics import ContentStream from ..graphics import Line from ..graphics import Move from ..graphics import quadratic_to_cubic_bezier from ..graphics import Rect from ..graphics import Restore from ..graphics import Save from ..graphics import BeginText, Text, EndText, TextMatrix from ..graphics import Font from ..graphics import FillColor, StrokeColor, Stroke, StrokeWidth, Fill from ..graphics import CTM, XObject HELVETICA_PATH = os.path.join(os.path.dirname(__file__), "..", "fonts", "Helvetica.ttf") class Signature(Annotation): """Signatur annotation that defines its location on the document with a width and a height. Internal structure follows that which is documented by Adobe, with /frm referencing a blank /n0 layer with all the appearance in the stream of the /n2 layer. """ subtype = 'Widget' def __init__(self, location, appearance, metadata=None): super(Signature, self).__init__(location, appearance, metadata) self._images = {} self._ttf = {} self._type1 = {} def add_additional_resources(self, resources): # TODO: additional resources like: fonts, ... that need to be included in pdf return try: resources.Font except AttributeError: resources.Font = IndirectPdfDict() for font_name, font in self.ttf.items(): resources.Font[PdfName(font_name)] = font def simple_signature(self, signature): """ simple_signature(self, signature) A simple signature annotation whose appearance is inspired by the signatures from Adobe's appearances. The text is output using the default font, and no calls to add_image or add_font are needed to use this. signature = dict( background = Image with alpha / None, icon = Image with alpha / None, labels = bool, CN = str, DN = str, date = str, contact = str, reason = str, location = str, software = str, outline = [R, G, B], border = int, ) """ bbox = self._internal_location() processor = SignatureAppearance(bbox, self._appearance, self._ttf, self._images) height = bbox[3] - bbox[1] width = bbox[2] - bbox[0] t_left = 5 t_top = 5 border = signature.get('border', 0) block = [] if signature.get('text', False): block.append(signature['text']) else: if signature.get('labels', False): labels = dict( DN = 'DN: ', CN = 'Digitally signed by ', date = 'Date: ', contact = 'Contact: ', reason = 'Reason: ', location = 'Location: ', software = 'Signing software: ', ) else: labels = {} for i in ('CN', 'DN', 'date', 'reason', 'contact', 'location', 'software'): if i not in signature: continue block.append('{}{}'.format(labels.get(i, ''), signature[i])) cs = ContentStream([Save()]) if 'background' in signature: if type(signature['background']) == list: cs.extend(processor.fill_colour(*signature['background'])) cs.extend(processor.rect_fill(*bbox)) else: if 'bg' not in self._images: self.add_image(signature['background'], 'Bg') cs.extend(processor.image('Bg', *bbox)) cs.extend(processor.fill_colour(*signature.get('outline', [0, 0, 0]))) cs.extend(processor.stroke_colour(*signature.get('outline', [0, 0, 0]))) if border: cs.extend(processor.border(border)) if 'icon' in signature: if 'icon' not in self._images: self.add_image(signature['icon'], 'Icon') i_w = self._images['Icon']['/Width'] i_h = self._images['Icon']['/Height'] if block: factor = 2.0 else: factor = 1.0 if i_h <= height and i_w <= width/factor: # image smaller than alloted half of box # vertically centre icon and expand text region t_left += i_w + 5 dist = (height - i_h)/2 if block: i_box = [bbox[0], bbox[1]+dist, i_w+bbox[0], bbox[3]-dist] else: dist2 = (width - i_w)/2 i_box = [bbox[0]+dist2, bbox[1]+dist, bbox[2]-dist2, bbox[3]-dist] elif (i_w/i_h) > ((width/factor)/height): # too wide t_left += (width/factor) + 5 scale = (width/factor)/i_w dist = (height - i_h*scale)/2 i_box = [bbox[0], bbox[1]+dist, width/factor, bbox[3]-dist] else: # too tall scale = height/i_h t_left += (i_w*scale) + 5 if block: i_box = [bbox[0], bbox[1], bbox[0]+i_w*scale, bbox[3]] else: # centre if only the icon dist = (width - i_w*scale)/2 i_box = [bbox[0]+dist, bbox[1], bbox[2]-dist, bbox[3]] cs.extend(processor.image('Icon', *i_box)) if block: font = self.get_default_font() cs.extend(processor.text_box('\n'.join(block), font, t_left, 5, (bbox[2]-5)-t_left, height-5)) #cs.extend(processor.text_box('\n'.join(block), font, t_left, t_top, width-2*t_left, height-2*t_top)) cs.add(Restore()) self._n2_layer = cs def set_signature_appearance(self, *directives): """ set_signature_apperance(self, *directives) Use the provided list of lists to compute a signature appearance using calls to the SignatureAppearance processor. Note that the text_box directive can only be used with a TTF font. """ processor = SignatureAppearance(self._internal_location(), self._appearance, self._ttf, self._images) cs = ContentStream([Save()]) for x in directives: if x[0] in processor.template: directives = processor.template[x[0]](processor, *x[1:]) if type(directives) != list: directives = [directives] cs.extend(directives) cs.add(Restore()) self._n2_layer = cs def make_rect(self): stroke_width = self._appearance.stroke_width L = self._location return [ L.x1 - stroke_width, L.y1 - stroke_width, L.x2 + stroke_width, L.y2 + stroke_width, ] def add_default_font(self): self.add_ttf_font(HELVETICA_PATH, PDF_ANNOTATOR_FONT) def get_default_font(self): if PDF_ANNOTATOR_FONT not in self._ttf: self.add_ttf_font(HELVETICA_PATH, PDF_ANNOTATOR_FONT) return self._ttf[PDF_ANNOTATOR_FONT] def add_type1_font(self, base_font, name="Font", encoding='WinAnsiEncoding'): type1 = ( 'Helvetica', 'Helvetica-Bold', 'Helvetica-Oblique', 'Helvetica-BoldOblique', 'Courier', 'Courier-Bold', 'Courier-Oblique', 'Courier-BoldOblique', 'Times-Roman', 'Times-Bold', 'Times-Italic', 'Times-BoldItalic', 'Symbol', 'ZapfDingbats', ) if base_font in ('Symbol', 'ZapfDingbats'): encoding = base_font self._type1[name] = PdfDict( Type = PdfName('Font'), Subtype = PdfName('Type1'), Name = PdfName(name), BaseFont = PdfName(base_font), Encoding = PdfName(encoding), ) def add_ttf_font(self, path, name="Font"): font = TTFFont(path) self._ttf[name] = font def add_image(self, obj, name="Image"): self._images[name] = Image.make_image_xobject(obj) def _make_appearance_stream_dict(self, bounding_box, transform): self._make_n0() self._make_n2() self._make_frm() self._make_apn() return PdfDict(N=self._apn) def as_pdf_object(self, transform, page): """Return the PdfDict object representing the annotation, that will be inserted as is into the PDF document. :param list transform: Transformation matrix to transform the coords of the annotation from client-specified space to PDF user space. :param PdfDict page: The pdfrw page object from the PDF document :returns PdfDict: the annotation object to be inserted into the PDF """ bounding_box = transform_rect(self.make_rect(), transform) appearance_stream = self._make_appearance_stream_dict(bounding_box, transform) obj = PdfDict( Type=PdfName("Annot"), Subtype=PdfName(self.subtype), Rect=bounding_box, AP=appearance_stream, P=page, ) self._add_metadata(obj, self._metadata) self.add_additional_pdf_object_data(obj) obj.indirect = True return obj def _internal_location(self): L = self._location return (0, 0, L.x2 - L.x1, L.y2 - L.y1) def _make_apn(self): self._apn = IndirectPdfDict( BBox = self._internal_location(), Resources = dict( ProcSet = PdfArray([PdfName('PDF')]), XObject = {'FRM': self._frm}, ), Type = PdfName('XObject'), Subtype = PdfName('Form'), FormType = 1, Matrix = identity(), ) self._apn['stream'] = 'q 1 0 0 1 0 0 cm /FRM Do Q' def _make_frm(self): self._frm = IndirectPdfDict( BBox = self._internal_location(), Resources = dict( ProcSet = PdfArray([PdfName('PDF')]), XObject = {'n0': self._n0, 'n2': self._n2}, ), Matrix = identity(), Type = PdfName('XObject'), Subtype = PdfName('Form'), ) self._frm['stream'] = 'q 1 0 0 1 0 0 cm /n0 Do Q q 1 0 0 1 0 0 cm /n2 Do Q' def _make_n0(self): self._n0 = IndirectPdfDict( BBox = self._internal_location(), Type = PdfName('XObject'), Subtype = PdfName('Form'), FormType = 1, Matrix = identity(), Resources = {'ProcSet': PdfArray([PdfName('Text')])}, ) self._n0['stream'] = '% DSBlank' def _make_n2(self): resources = dict( ProcSet = PdfArray([PdfName('PDF'), PdfName('Text'), PdfName('ImageC')]) ) fonts = PdfDict() if self._ttf: for name, font in self._ttf.items(): fonts[name] = font.get_font() if self._type1: for name, font in self._type1.items(): fonts[name] = font if fonts: resources[PdfName('Font')] = fonts if self._images: resources[PdfName('XObject')] = self._images self._n2 = IndirectPdfDict( BBox = self._internal_location(), Matrix = identity(), Type = PdfName('XObject'), Subtype = PdfName('Form'), FormType = 1, Resources = resources, ) self._n2['stream'] = self._n2_layer.resolve() class SignatureAppearance(): def __init__(self, box, appearance, ttf, images): self._in_text = False self._reset_font = True self._reset_tm = False self._cur_font = (PDF_ANNOTATOR_FONT, appearance.font_size) self._cur_tm = [1, 0, 0, 1, 0, 0] self._sc = [0, 0, 0] self._fc = [0, 0, 0] self._bounds = box self._ttf = ttf self._images = images def fill_colour(self, *colour): self._fc = colour return [FillColor(*colour)] def stroke_colour(self, *colour): self._sc = colour return [StrokeColor(*colour)] def border(self, inset): box = self._bounds return [ Rect(inset, inset, box[2]-2*inset, box[3]-2*inset), Stroke() ] def image(self, image_name, x1, y1, x2, y2, distort=True, centred=True): if distort: scale_x = x2-x1 scale_y = y2-y1 else: max_w = x2-x1 max_h = y2-y1 i_w = self._images[image_name]['/Width'] i_h = self._images[image_name]['/Height'] if i_w/i_h >= max_w/max_h: # image proportionally wider than box scale_x = x2-x1 scale_y = scale_x*(i_h/i_w) if centred: # centre vertically dist = (max_h-scale_y)/2.0 y1 += dist elif i_w/i_h < max_w/max_h: # image proportionally narrower than box scale_y = y2-y1 scale_x = scale_y*(i_w/i_h) if centred: # centre horizontally dist = (max_w-scale_x)/2.0 x1 += dist commands = [] if self._in_text: commands.append(EndText()) self._reset_font = True self._reset_tm = True self._in_text = False commands.append(Save()) commands.append(CTM((scale_x, 0, 0, scale_y, x1, y1))) commands.append(XObject(image_name)) commands.append(Restore()) return commands def rect(self, *box): seq = [] if self._in_text: seq.append(EndText()) self._in_text = False seq.extend([ Rect(*box), Stroke() ]) return seq def rect_fill(self, *box): seq = [] if self._in_text: seq.append(EndText()) self._in_text = False seq.extend([ Rect(*box), Fill() ]) return seq def reset(self): return [ StrokeColor(0, 0, 0), FillColor(0, 0, 0), ] def text_position(self, x, y): if x < 0: x = self._bounds[2]+x if y < 0: y = self._bounds[3]+y self._cur_tm[4] = x self._cur_tm[5] = y if self._in_text: return [TextMatrix(self._cur_tm.copy())] self._reset_tm = True return [] def font(self, name, size): if name == 'default': name = PDF_ANNOTATOR_FONT self._cur_font = (name, size) if self._in_text: return [Font(name, size), TextLeading(size*1.2)] self._reset_font = True return [] def text_box(self, text, ttf_font, x, y, width, height, font_size=8, wrap_text=True, align='left', baseline='middle', line_spacing=1.2): if type(ttf_font) == str: font = self._ttf.get(ttf_font, None) if font is None: font = self._ttf[PDF_ANNOTATOR_FONT] fontname = PDF_ANNOTATOR_FONT else: fontname = ttf_font else: font = ttf_font fontname = font.font["name"] if fontname == 'Helvetica': fontname = PDF_ANNOTATOR_FONT font.set_size(font_size) font.set_text(text) commands = [] if not self._in_text: commands.extend([BeginText(), Font(fontname, font_size)]) commands.extend(get_text_commands(x, y, x+width, y+height, text, font_size, wrap_text, align, baseline, line_spacing, font)) if not self._in_text: commands.append(EndText()) return commands def text(self, text): if self._cur_font[0] in self._ttf: ttf_font = self._ttf[self._cur_font[0]] ttf_font.set_size(self._cur_font[1]) ttf_font.set_text(text) text = text.encode("utf-16be").decode("latin1") commands = [] if not self._in_text: commands.append(BeginText()) self._in_text = True if self._reset_tm: commands.append(TextMatrix(self._cur_tm.copy())) self._reset_tm = False if self._reset_font: commands.append(Font(*self._cur_font)) commands.append(TextLeading(self._cur_font[1]*1.2)) self._reset_font = False commands.append(Text(text)) return commands def new_line(self): if self._in_text: return [ NewLine() ] return [] def done(self): if self._in_text: self._in_text = False return [ EndText() ] return [] template = dict( save = Save, reset = reset, image = image, rect = rect, rect_fill = rect_fill, border = border, font = font, text = text, text_box = text_box, text_position = text_position, new_line = new_line, done = done, fill_colour = fill_colour, stroke_colour = stroke_colour, fill_color = fill_colour, stroke_color = stroke_colour, ) class TextPosition(metaclass=FloatTupleCommand): COMMAND = 'Td' ARGS = ['x', 'y'] class TextRender(metaclass=FloatTupleCommand): COMMAND = 'Tr' ARGS = ['render'] class TextScale(metaclass=FloatTupleCommand): COMMAND = 'Tz' ARGS = ['scale'] class TextLeading(metaclass=FloatTupleCommand): COMMAND = 'TL' ARGS = ['leading'] class TextRise(metaclass=FloatTupleCommand): COMMAND = 'Ts' ARGS = ['rise'] class WordSpacing(metaclass=FloatTupleCommand): COMMAND = 'Tw' ARGS = ['wordSpace'] class CharacterSpacing(metaclass=FloatTupleCommand): COMMAND = 'Tc' ARGS = ['charSpace'] class StrokeGray(metaclass=FloatTupleCommand): COMMAND = 'G' ARGS = ['gray'] class FillGray(metaclass=FloatTupleCommand): COMMAND = 'g' ARGS = ['gray'] class NewLine(BaseCommand): COMMAND = 'T*' endesive-2.19.1/endesive/pdf/PyPDF2_annotate/annotations/text.py000066400000000000000000000153121504236674500245670ustar00rootroot00000000000000# -*- coding: utf-8 -*- """ Text Annotations ~~~~~~~~~~~~~~~~ The FreeText annotation :copyright: Copyright 2019 Autodesk, Inc. :license: MIT, see LICENSE for details. """ import os.path import codecs from ..pdfrw import PdfDict, PdfName, PdfString, PdfArray, IndirectPdfDict from ..pdfttf import TTFFont from .base import _make_border_dict from .base import Annotation from ..config.constants import DEFAULT_BASE_FONT from ..config.constants import GRAPHICS_STATE_NAME from ..config.constants import PDF_ANNOTATOR_FONT from ..graphics import BeginText from ..graphics import ContentStream from ..graphics import EndText from ..graphics import FillColor from ..graphics import Font from ..graphics import GraphicsState as CSGraphicsState from ..graphics import Restore from ..graphics import Save from ..graphics import Text from ..graphics import TextMatrix from ..util.geometry import translate from ..util.text import get_wrapped_lines HELVETICA_PATH = os.path.join(os.path.dirname(__file__), "..", "fonts", "Helvetica.ttf") class FreeText(Annotation): """FreeText annotation. Right now, we only support writing text in the Helvetica font. Dealing with fonts is tricky business, so we'll leave that for later. """ subtype = "FreeText" def __init__(self, location, appearance, metadata=None): super(FreeText, self).__init__(location, appearance, metadata) self.ttffont = TTFFont(HELVETICA_PATH) def make_rect(self): L = self._location return [L.x1, L.y1, L.x2, L.y2] def make_default_appearance(self): """Returns a DA string for the text object, e.g. '1 0 0 rg /Helv 12 Tf' """ A = self._appearance stream = ContentStream( [FillColor(*A.fill[:3]), Font(PDF_ANNOTATOR_FONT, A.font_size)] ) return stream.resolve() def add_additional_pdf_object_data(self, obj): obj[PdfName("Contents")] = self._appearance.content obj[PdfName("DA")] = self.make_default_appearance() obj[PdfName("C")] = [] # TODO allow setting border on free text boxes obj[PdfName("BS")] = _make_border_dict(width=0, style="S") # TODO DS is required to have BB not redraw the annotation in their own # style when you edit it. def add_additional_resources(self, resources): font_dict = PdfDict() font_dict[PDF_ANNOTATOR_FONT] = self.ttffont.get_font() resources[PdfName("Font")] = font_dict def make_appearance_stream(self): A = self._appearance L = self._location stream = ContentStream( [ Save(), BeginText(), FillColor(*A.fill[:3]), Font(PDF_ANNOTATOR_FONT, A.font_size), ] ) graphics_state = A.get_graphics_state() if graphics_state.has_content(): stream.add(CSGraphicsState(GRAPHICS_STATE_NAME)) # Actually draw the text inside the rectangle stream.extend( get_text_commands( L.x1, L.y1, L.x2, L.y2, text=A.content, font_size=A.font_size, wrap_text=A.wrap_text, align=A.text_align, baseline=A.text_baseline, line_spacing=A.line_spacing, font=self.ttffont, ) ) stream.extend([EndText(), Restore()]) return stream def get_text_commands( x1, y1, x2, y2, text, font_size, wrap_text, align, baseline, line_spacing, font ): """Return the graphics stream commands necessary to render a free text annotation, given the various parameters. Text is optionally wrapped, then arranged according to align (horizontal alignment), and baseline (vertical alignment). :param number x1: bounding box lower left x :param number y1: bounding box lower left y :param number x2: bounding box upper right x :param number y2: bounding box upper right y :param str text: text to add to annotation :param number font_size: font size :param bool wrap_text: whether to wrap the text :param str align: 'left'|'center'|'right' :param str baseline: 'top'|'middle'|'bottom' :param number line_spacing: multiplier to determine line spacing :param TTFFont font: TTF font helper """ font.set_size(font_size) font.set_text(text) lines = ( get_wrapped_lines(text=text, measure=font.measure_text, max_length=x2 - x1) if wrap_text else [text] ) # Line breaking cares about the whitespace in the string, but for the # purposes of laying out the broken lines, we want to measure the lines # without trailing/leading whitespace. lines = [line.strip() for line in lines] y_coords = _get_vertical_coordinates( lines, y1, y2, font_size, line_spacing, baseline ) xs = _get_horizontal_coordinates(lines, x1, x2, font.measure_text, align) commands = [] for line, x, y in zip(lines, xs, y_coords): line = line.encode("utf-16be").decode("latin1") commands.extend([TextMatrix(translate(x, y)), Text(line)]) return commands def _get_vertical_coordinates(lines, y1, y2, font_size, line_spacing, baseline): """Calculate vertical coordinates for all the lines at once, honoring the text baseline property. """ line_spacing = font_size * line_spacing if baseline == "top": first_y = y2 - line_spacing elif baseline == "middle": midpoint = (y2 + y1) / 2.0 # For the first line of vertically centered text, go up half the # of # lines, then go back down half the font size. first_y = ( midpoint - (line_spacing - font_size) + (((len(lines) - 1) / 2.0) * line_spacing) ) else: # bottom first_y = y1 + (line_spacing - font_size) + (line_spacing * (len(lines) - 1)) return [first_y - (i * line_spacing) for i in range(len(lines))] def _get_horizontal_coordinates(lines, x1, x2, measure, align): # NOTE: this padding is to keep text annotations as they are from cutting # off text at the edges in certain conditions. The annotation rectangle # and how PDFs draw text needs to be revisited, as this padding shouldn't # be necessary. PADDING = 1 if align == "left": return [x1 + PADDING for _ in range(len(lines))] elif align == "center": widths = [measure(line) for line in lines] max_width = x2 - x1 return [x1 + ((max_width - width) / 2.0) - PADDING for width in widths] else: # right widths = [measure(line) for line in lines] max_width = x2 - x1 return [x1 + (max_width - width) - PADDING for width in widths] endesive-2.19.1/endesive/pdf/PyPDF2_annotate/annotator.py000066400000000000000000000271671504236674500232660ustar00rootroot00000000000000# -*- coding: utf-8 -*- """ PdfAnnotator ~~~~~~~~~~~~ The core annotator class. :copyright: Copyright 2019 Autodesk, Inc. :license: MIT, see LICENSE for details. """ import warnings #from pdfrw import PdfReader #from pdfrw import PdfWriter from .annotations.image import Image from .annotations.points import Ink from .annotations.points import Line from .annotations.points import Polygon from .annotations.points import Polyline from .annotations.rect import Circle from .annotations.rect import Square from .annotations.text import FreeText from .config.metadata import Metadata from .config.metadata import UNSET from .graphics import ContentStream from .util.geometry import identity from .util.geometry import matrix_multiply from .util.geometry import normalize_rotation from .util.geometry import rotate from .util.geometry import scale from .util.geometry import translate from .util.validation import NUMERIC_TYPES NAME_TO_ANNOTATION = { 'square': Square, 'circle': Circle, 'line': Line, 'polygon': Polygon, 'polyline': Polyline, 'ink': Ink, 'text': FreeText, 'image': Image, } class PDF(object): def __init__(self, pdf_reader): self._reader = pdf_reader self.pdf_version = self._reader.private.pdfdict.version def get_page(self, page_number): if page_number > len(self._reader.pages) - 1: raise ValueError('Page number {} out of bounds ({} pages)'.format( page_number, len(self._reader.pages), )) return self._reader.pages[page_number] def get_rotation(self, page_number): """Returns the rotation of a specified page.""" page = self.get_page(page_number) rotate = int(page.inheritable.Rotate or 0) return normalize_rotation(rotate) class PdfAnnotator(object): def __init__(self, file_or_reader, scale=None, compress=True): """Draw annotations directly on PDFs. Annotations are always drawn on as if you're drawing them in a viewer, i.e. they take into account page rotation and weird, translated coordinate spaces. :param str|PdfReader file_or_reader: filename of PDF or pdfrw.PdfReader :param number|tuple|None scale: number by which to scale coordinates to get to default user space. Use this if, for example, your points in the coordinate space of the PDF viewed at a dpi. In this case, scale would be 72/dpi. Can also specify a 2-tuple of x and y scale. :param bool compress: whether to output flate-compressed PDFs """ if isinstance(file_or_reader, str): file_or_reader = PdfReader(file_or_reader) self._pdf = PDF(file_or_reader) self._scale = self._expand_scale(scale) self._dimensions = {} self._compress = compress def _expand_scale(self, scale): if scale is None: return 1, 1 elif isinstance(scale, NUMERIC_TYPES): return (scale, scale) return scale def set_page_dimensions(self, dimensions, page_number): """Set dimensions for a given page number. If set, the dimensions for this page override the document-wide rotation and scale settings. :param tuple|None dimensions: As a convenient alternative to scale and you can pass in the dimensions of your sheet when viewed in a certain setting. For example, an 8.5"x11" PDF, rotated at 90° and rastered at 150 dpi, would produce dimensions of (1650, 1275). If you pass this in, you can then specify your coordinates in this coordinate space. :param int page_number: """ self._dimensions[page_number] = dimensions def get_page_bounding_box(self, page_number): page = self._pdf.get_page(page_number) # PDF bounding boxes are complicated. We choose to use the CropBox, if # it's available, because that's what Acrobat uses to display the # actual PDF, and what pdfinfo uses to determine the PDF's dimensions. # If CropBox isn't available, we use MediaBox. We ignore the TrimBox # because Acrobat also ignores this when displaying the PDF. crop_box = page.inheritable.CropBox if crop_box is not None: return [float(n) for n in crop_box] return [float(n) for n in page.inheritable.MediaBox] def get_size(self, page_number): """Returns the size of the specified page's bounding box (pts), accounting for page rotation. :param int page_number: :returns tuple: If page is rotated 90° or 270°, the returned value will be (height, width) in PDF user space. Otherwise the returned value will be (width, height). """ x1, y1, x2, y2 = self.get_page_bounding_box(page_number) rotation = self._pdf.get_rotation(page_number) if rotation in (0, 180): return (x2 - x1, y2 - y1) return (y2 - y1, x2 - x1) def add_annotation( self, annotation_type, location, appearance, metadata=None, ): """Add an annotation of the given type, with the given parameters, to the given location of the PDF. :param str annotation_type: E.g. 'square' :param Location location: Annotation's Location object, specified in the coordinate system of the client. Coordinates will be transformed to PDF user space via get_transform. :param Appearance appearance: :param Metadata|None|UNSET metadata: Metadata object. If UNSET, no metadata is written on the entire annotation. If None, default metadata is used. """ self._before_add(location) metadata = self._resolve_metadata(metadata) self._validate_appearance_stream(appearance) annotation = self.get_annotation( annotation_type, location, appearance, metadata, ) self._add_annotation(annotation) @staticmethod def _resolve_metadata(metadata): if isinstance(metadata, Metadata): return metadata elif metadata is None: return Metadata() elif metadata is UNSET: return None else: raise ValueError('Invalid metadata') @staticmethod def _validate_appearance_stream(appearance): stream = appearance.appearance_stream if stream is not None and not isinstance(stream, ContentStream): raise ValueError( 'Invalid appearance stream format: {}'.format(type(stream))) def _before_add(self, location): # Steps to take before trying to add an annotation to `location` page = self._pdf.get_page(location.page) user_unit = page.inheritable.UserUnit if user_unit not in (1, None): warnings.warn( 'Unsupported UserUnit (value: {})'.format(user_unit) ) def get_annotation(self, annotation_type, location, appearance, metadata): # TODO filter on valid PDF versions, by type annotation_cls = NAME_TO_ANNOTATION.get(annotation_type) if annotation_cls is None: raise ValueError('Invalid/unsupported annotation type: {}'.format( annotation_type )) annotation = annotation_cls(location, appearance, metadata) annotation.validate(self._pdf.pdf_version) return annotation def get_scale(self, page_number): """Public API to get the x and y scales of the given page. :param int page_number: :returns 2-tuple: (x_scale, y_scale) """ rotation = self._pdf.get_rotation(page_number) bounding_box = self.get_page_bounding_box(page_number) return self._get_scale(page_number, bounding_box, rotation) def get_rotation(self, page_number): """Public API to get the rotation of the give page. :param int page_number: :returns int: integer where i % 90 == 0 """ return self._pdf.get_rotation(page_number) def _get_scale(self, page_number, bounding_box, rotation): W = bounding_box[2] - bounding_box[0] H = bounding_box[3] - bounding_box[1] dimensions = self._dimensions.get(page_number) if dimensions is not None: # User-specified dimensions for a particular page just give us the # scaling factor to use for that page. width_d, height_d = dimensions width_pts, height_pts = W, H if rotation in (90, 270): width_pts, height_pts = H, W x_scale = (width_pts / float(width_d)) y_scale = (height_pts / float(height_d)) else: x_scale, y_scale = self._scale return x_scale, y_scale def get_transform(self, page_number, rotation): bounding_box = self.get_page_bounding_box(page_number) _scale = self._get_scale(page_number, bounding_box, rotation) return self._get_transform(bounding_box, rotation, _scale) @staticmethod def _get_transform(bounding_box, rotation, _scale): """Get the transformation required to go from the user's desired coordinate space to PDF user space, taking into account rotation, scaling, translation (for things like weird media boxes). """ # Unrotated width and height, in pts W = bounding_box[2] - bounding_box[0] H = bounding_box[3] - bounding_box[1] scale_matrix = scale(*_scale) x_translate = 0 + bounding_box[0] y_translate = 0 + bounding_box[1] mb_translate = translate(x_translate, y_translate) # Because of how rotation works the point isn't rotated around an axis, # but the axis itself shifts. So we have to represent the rotation as # rotation + translation. rotation_matrix = rotate(rotation) translate_matrix = identity() if rotation == 90: translate_matrix = translate(W, 0) elif rotation == 180: translate_matrix = translate(W, H) elif rotation == 270: translate_matrix = translate(0, H) # Order matters here - the transformation matrices are applied in # reverse order. So first we scale to get the points in PDF user space, # since all other operations are in that space. Then we rotate and # scale to capture page rotation, then finally we translate to account # for offset media boxes. transform = matrix_multiply( mb_translate, translate_matrix, rotation_matrix, scale_matrix, ) return transform def _add_annotation(self, annotation): """Add the annotation to the PDF document, transforming annotation metadata and content stream to PDF user space. """ page = self._pdf.get_page(annotation.page) transform = self.get_transform( annotation.page, self._pdf.get_rotation(annotation.page), ) annotation_obj = annotation.as_pdf_object(transform, page) if page.Annots: page.Annots.append(annotation_obj) else: page.Annots = [annotation_obj] def write(self, filename=None, overwrite=False): if filename is None and not overwrite: raise ValueError( 'Must specify either output filename or overwrite flag' ) if overwrite: filename = self._filename writer = PdfWriter( version=self._pdf.pdf_version, compress=self._compress, ) writer.write(fname=filename, trailer=self._pdf._reader) endesive-2.19.1/endesive/pdf/PyPDF2_annotate/config/000077500000000000000000000000001504236674500221375ustar00rootroot00000000000000endesive-2.19.1/endesive/pdf/PyPDF2_annotate/config/__init__.py000066400000000000000000000000001504236674500242360ustar00rootroot00000000000000endesive-2.19.1/endesive/pdf/PyPDF2_annotate/config/appearance.py000066400000000000000000000121211504236674500246050ustar00rootroot00000000000000# -*- coding: utf-8 -*- """ Appearance Config ~~~~~~~~~~~~~~~~~ Configuration for an annotation's appearance. :copyright: Copyright 2019 Autodesk, Inc. :license: MIT, see LICENSE for details. """ import attr from .constants import ALLOWED_ALIGNS from .constants import ALLOWED_BASELINES from .constants import ALLOWED_LINE_CAPS from .constants import ALLOWED_LINE_JOINS from .constants import BLACK from .constants import DEFAULT_BORDER_STYLE from .constants import DEFAULT_CONTENT from .constants import DEFAULT_FONT_SIZE from .constants import DEFAULT_LINE_SPACING from .constants import DEFAULT_STROKE_WIDTH from .constants import GRAPHICS_STATE_NAME from .constants import TEXT_ALIGN_LEFT from .constants import TEXT_BASELINE_MIDDLE from .graphics_state import GraphicsState from ..graphics import ContentStream from ..graphics import FillColor from ..graphics import GraphicsState as CSGraphicsState from ..graphics import Stroke from ..graphics import StrokeAndFill from ..graphics import StrokeColor from ..graphics import StrokeWidth from ..util.validation import between from ..util.validation import Boolean from ..util.validation import Color from ..util.validation import Enum from ..util.validation import Field from ..util.validation import Number from ..util.validation import positive from ..util.validation import String from ..util.validation import validate_dash_array def is_transparent(color): # E.g. a soothing gray: [0, 0, 0, 0.5] if color is None: return False return len(color) == 4 and color[-1] < 1 @attr.s class Appearance(object): # Stroke attributes stroke_color = Color(default=BLACK) stroke_width = Number(default=DEFAULT_STROKE_WIDTH, validator=positive) border_style = String(default=DEFAULT_BORDER_STYLE) dash_array = Field(list, default=None, validator=validate_dash_array) line_cap = Enum(ALLOWED_LINE_CAPS, default=None) line_join = Enum(ALLOWED_LINE_JOINS, default=None) miter_limit = Number(default=None, validator=positive) stroke_transparency = Number(default=None, validator=between(0, 1)) # Fill attributes fill = Color(default=None) fill_transparency = Number(default=None, validator=between(0, 1)) # Text attributes content = String(default=DEFAULT_CONTENT) font_size = Number(default=DEFAULT_FONT_SIZE, validator=positive) text_align = Enum(ALLOWED_ALIGNS, default=TEXT_ALIGN_LEFT) text_baseline = Enum(ALLOWED_BASELINES, default=TEXT_BASELINE_MIDDLE) line_spacing = Number(default=DEFAULT_LINE_SPACING, validator=positive) wrap_text = Boolean(default=True) # Image attributes image = String(default=None) # Advanced attributes appearance_stream = Field(ContentStream, default=None) xobjects = Field(dict, default=None) graphics_states = Field(dict, default=None) fonts = Field(dict, default=None) def copy(self, **kwargs): A = Appearance(**kwargs) for k, v in self.__dict__.items(): if k not in kwargs: setattr(A, k, v) return A def _get_stroke_transparency(self): stroke_transparency = None if is_transparent(self.stroke_color): stroke_transparency = self.stroke_color[-1] if self.stroke_transparency is not None: stroke_transparency = self.stroke_transparency return stroke_transparency def _get_fill_transparency(self): fill_transparency = None if is_transparent(self.fill): fill_transparency = self.fill[-1] if self.fill_transparency is not None: fill_transparency = self.fill_transparency return fill_transparency def get_graphics_state(self): """Return a GraphicsState config from the appearance's graphics-state- applicable params. :returns GraphicsState: """ return GraphicsState( dash_array=self.dash_array, line_cap=self.line_cap, line_join=self.line_join, miter_limit=self.miter_limit, stroke_transparency=self._get_stroke_transparency(), fill_transparency=self._get_fill_transparency(), ) def set_appearance_state(stream, A): """Update the graphics command stream to reflect appearance properties. :param ContentStream stream: current content stream :param Appearance A: appearance object """ # Add in the `gs` command, which will execute the named graphics state from # the Resources dict, and set CA and/or ca values. The annotations # themselves will need to ensure that the proper ExtGState object is # present in the Resources dict. graphics_state = A.get_graphics_state() if graphics_state.has_content(): stream.add(CSGraphicsState(GRAPHICS_STATE_NAME)) stream.extend([ StrokeColor(*A.stroke_color[:3]), StrokeWidth(A.stroke_width), ]) # TODO support more color spaces - CMYK and GrayScale if A.fill is not None: stream.add(FillColor(*A.fill[:3])) def stroke_or_fill(stream, A): if A.fill is not None: stream.add(StrokeAndFill()) else: stream.add(Stroke()) endesive-2.19.1/endesive/pdf/PyPDF2_annotate/config/constants.py000066400000000000000000000023151504236674500245260ustar00rootroot00000000000000# -*- coding: utf-8 -*- """ Constants ~~~~~~~~~ :copyright: Copyright 2019 Autodesk, Inc. :license: MIT, see LICENSE for details. """ TEXT_ALIGN_LEFT = 'left' TEXT_ALIGN_CENTER = 'center' TEXT_ALIGN_RIGHT = 'right' ALLOWED_ALIGNS = ( TEXT_ALIGN_LEFT, TEXT_ALIGN_RIGHT, TEXT_ALIGN_CENTER, ) TEXT_BASELINE_TOP = 'top' TEXT_BASELINE_MIDDLE = 'middle' TEXT_BASELINE_BOTTOM = 'bottom' ALLOWED_BASELINES = ( TEXT_BASELINE_TOP, TEXT_BASELINE_MIDDLE, TEXT_BASELINE_BOTTOM, ) DEFAULT_CONTENT = '' DEFAULT_FONT_SIZE = 12 DEFAULT_LINE_SPACING = 1.2 DEFAULT_STROKE_WIDTH = 1 DEFAULT_BORDER_STYLE = 'S' LINE_CAP_BUTT = 0 LINE_CAP_ROUND = 1 LINE_CAP_SQUARE = 2 ALLOWED_LINE_CAPS = ( LINE_CAP_BUTT, LINE_CAP_ROUND, LINE_CAP_SQUARE, ) LINE_JOIN_MITER = 0 LINE_JOIN_ROUND = 1 LINE_JOIN_BEVEL = 2 ALLOWED_LINE_JOINS = ( LINE_JOIN_MITER, LINE_JOIN_ROUND, LINE_JOIN_BEVEL, ) BLACK = (0, 0, 0) TRANSPARENT = tuple() GRAPHICS_STATE_NAME = 'PdfAnnotatorGS' DEFAULT_BASE_FONT = 'Helvetica' PDF_ANNOTATOR_FONT = 'PDFANNOTATORFONT1' CMYK_MODE = 'CMYK' RGB_MODE = 'RGB' RGBA_MODE = 'RGBA' PALETTE_MODE = 'P' GRAYSCALE_MODE = 'L' GRAYSCALE_ALPHA_MODE = 'LA' SINGLE_CHANNEL_MODE = '1' endesive-2.19.1/endesive/pdf/PyPDF2_annotate/config/graphics_state.py000066400000000000000000000043711504236674500255160ustar00rootroot00000000000000# -*- coding: utf-8 -*- """ GraphicsState ~~~~~~~~~~~~~ Configuration for an annotation's graphics state. :copyright: Copyright 2019 Autodesk, Inc. :license: MIT, see LICENSE for details. """ import attr from ..pdfrw import PdfDict, PdfName from ..config.constants import ALLOWED_LINE_CAPS from ..config.constants import ALLOWED_LINE_JOINS from ..util.validation import between from ..util.validation import Enum from ..util.validation import Field from ..util.validation import Number from ..util.validation import positive from ..util.validation import validate_dash_array NAME_TO_PDF_ATTR = { "line_width": "LW", "line_cap": "LC", "line_join": "LJ", "miter_limit": "ML", "dash_array": "D", "stroke_transparency": "CA", "fill_transparency": "ca", } @attr.s class GraphicsState(object): """External graphics state config object, that can be used with explicit content streams to control annotation appearance. Some of these values can also be specified by their own operators in the content stream. For example, the line_width property can also be specified by the StrokeWidth (w) content stream operator. See the full PDF spec for constraints on and descriptions of these values. There are a lot more graphics state options, but they are highly technical and beyond the scope of this library. """ line_width = Number(default=None, validator=positive) line_cap = Enum(ALLOWED_LINE_CAPS, default=None) line_join = Enum(ALLOWED_LINE_JOINS, default=None) miter_limit = Number(default=None) dash_array = Field(list, validator=validate_dash_array, default=None) stroke_transparency = Number(default=None, validator=between(0, 1)) fill_transparency = Number(default=None, validator=between(0, 1)) def as_pdf_dict(self): pdf_dict = PdfDict(Type=PdfName("ExtGState")) for attr_name, attr_value in self.__dict__.items(): if attr_value is not None: pdf_name = NAME_TO_PDF_ATTR[attr_name] pdf_dict[PdfName(pdf_name)] = attr_value return pdf_dict def has_content(self): """Returns True if any of the attributes is non-null.""" return any(value is not None for value in self.__dict__.values()) endesive-2.19.1/endesive/pdf/PyPDF2_annotate/config/location.py000066400000000000000000000013431504236674500243220ustar00rootroot00000000000000# -*- coding: utf-8 -*- """ Location ~~~~~~~~~~~~ Configuration for an annotation's location. :copyright: Copyright 2019 Autodesk, Inc. :license: MIT, see LICENSE for details. """ import attr from ..util.validation import Integer from ..util.validation import Number from ..util.validation import Points from ..util.validation import positive @attr.s class Location(object): page = Integer(validator=positive) points = Points(default=None) x1 = Number(default=None) y1 = Number(default=None) x2 = Number(default=None) y2 = Number(default=None) def copy(self): L = Location(page=self.page) for k, v in self.__dict__.items(): setattr(L, k, v) return L endesive-2.19.1/endesive/pdf/PyPDF2_annotate/config/metadata.py000066400000000000000000000064001504236674500242710ustar00rootroot00000000000000# -*- coding: utf-8 -*- """ Metadata ~~~~~~~~ Configuration for an annotation's metadata. :copyright: Copyright 2019 Autodesk, Inc. :license: MIT, see LICENSE for details. """ from datetime import datetime from datetime import timedelta from datetime import tzinfo from uuid import uuid4 UNSET = object() class UTC(tzinfo): def utcoffset(self, dt): return timedelta(0) def dst(self, dt): return timedelta(0) def tzname(self, dt): return 'UTC' class Flags(object): Invisible = 1 Hidden = 2 Print = 4 NoZoom = 8 NoRotate = 16 NoView = 32 ReadOnly = 64 Locked = 128 ToggleNoView = 256 LockedContents = 512 class Metadata(object): """PDF annotation metadata class. By default, new annotations get the following properties: * CreationDate - defaults to UTC now * M (modified date) - defaults to UTC now * NM (unique name) - defaults to uuid4() * F (flags) - defaults to 4, just Flags.Print Datetime objects should be timezone-aware. If they're not, UTC is used. To leave any of these entries off the created annotation, pass kwarg=UNSET. Any additional kwargs will be set on the annotation object as /Name value. So for instance if you use Metadata(Subj='hi'), the annotation object in the PDF will have an attribute of `/Subj (hi)`. Acceptable value types are str, int, float, datetime, and lists of str/int/float. Other values may work, but may appear oddly formatted in the PDF, or break it entirely. """ def __init__( self, creation_date=None, modified_date=None, name=None, flags=None, **kwargs ): """ :param datetime|None|UNSET creation_date: :param datetime|None|UNSET modified_date: :param str|None|UNSET name: :param int|None|UNSET flags: if specified, a bunch of bitwise or-ed `Flags` values. For instance, to specify both Hidden and Invisible, use `Flags.Invisible | Flags.Hidden`. If flags are specified, the default `Print` flag is no longer set; it must be set explicity. """ self.metadata = {} self.set('CreationDate', creation_date, self.now) self.set('M', modified_date, self.now) self.set('NM', name, lambda: str(uuid4())) self.set('F', flags, lambda: Flags.Print) for k, v in kwargs.items(): if v is None: raise ValueError("Can't write Nones to PDF") self.set(k, v, None) def set(self, attr, value, default_func): if value is UNSET: return self.metadata[attr] = default_func() if value is None else value def iter(self): for name, value in self.metadata.items(): yield name, value @staticmethod def now(): return datetime.utcnow().replace(tzinfo=UTC()) def serialize_value(value): if isinstance(value, datetime): return serialize_datetime(value) return value def serialize_datetime(d): if d.tzinfo is None: d = d.replace(tzinfo=UTC()) offset_str = d.strftime('%z') offset_str = "{}'{}".format(offset_str[:3], offset_str[3:]) return d.strftime('D:%Y%m%d%H%M%S{}'.format(offset_str)) endesive-2.19.1/endesive/pdf/PyPDF2_annotate/fonts/000077500000000000000000000000001504236674500220235ustar00rootroot00000000000000endesive-2.19.1/endesive/pdf/PyPDF2_annotate/fonts/Helvetica.ttf000066400000000000000000011436701504236674500244620ustar00rootroot00000000000000FFTM=ǜGDEF. GPOS;H7<^GSUBHIc(OS/2F*-`cmap`Kr$Lcvt >9lfpgm+( glyf#N^head~6hhea "T$hmtx7t "TlocaL<"Xmaxpx nameQM4Td Ipost4^^d[prepn15H_<枰枰e' )) e  k]33fPx[pyrs@= O/ B999Rss@BVYDN\9U99s@ss@s1s4sBsMsKsBsI99\sVVZV9c9#Vs9PV9PVc!V4%V*V*/999/xs&sRsv;s8sH9s=sss;svs<B9s  4*9shs8sKssKR;s\U3od\ L9yW1sZKVVVVVVZVVVV99k99 !9P9P9P9P9Pt9BV*VsRsRsRsRsRsRI;sHsHsHsH99g99%s=ss;s;s;s;s;d\\sssssVsRVsRVsRZ;Z;Z;Z;H8!s8VsHVsHVsHVsHVsH9cs=9cs=9cs=9cs=s5s>iqD3Ye9995999#VsssNs{ssssss9Ps;9Ps;9Ps;IGBVcBVcBVcBVcB!9!!ssssss%V*V*/4/4/49s8VsvY!VsvIVaH\s(>##s%s9PPh;4V`B9! R/4e"e64Es+9 tO8kqXqkSVsR999Ps;ssssssHVsRVsRIS239cs=V9Ps;9Ps;L To89cs=VsVsRI9B\VsRVsRVsHVsH9q599Ps;9Ps;OssVcB!9OOsVsRVsH9Ps;9Ps;9Ps;9Ps;V*r[8EVZ;s!ss0.V4VsHV#" ?/.1sQ99sr:88sHsHA+R+SU>=9=s=ss#A#"s^Ts;GP**66::i99)0g< $sss:9P=<ssr8v`:o Rh2+2:B:AUEUDD]  Ua{a:N:OVVV$V$**x:x:!!V.V.V.UOV:: D!:OKKKKKw;w;NV$V$VVx:339<<hfi<p*p[[[[^ooi[Ivhffhf^IPf[I*1ssc^^Q  e^DJUaUa4Q;;;7"/r9//H////9V)VH9q9VV/b9qVX/V)PX=9d9 V)Zsw;9ZshswJ;9ss%sBqod/sLo;wsm9 om;9q??VsZFZZZmuV'PVb99#%9NVV/m$LV'%V TEV~%9PVPV/AV%6` 6djsVsHb9sP=3bTssHss}H3FN\9W/9wPRsPs9HH)|sbsm"V ]UD&9PsHV%V4 9Ps;s 0Or Gmz2z(N5_c?+:V*V*V*V*m.$rH8zwzwzwH:&H:&9# 9m$Cm$CImuRasPasPOC 0e"$UPRUNLUNL`7mmm^zi|Hm.$`ZOr G&$tkqOJjZULDK; eJVNJ ?PPJM3`G@DKgE>==RDJP9XP-^`V2^U>bTIE+R^T8:9n>s;s;666M2*3):):U( 4)T)()3)3::)+C^[^)^)*))*)*)T)[s7^x) xJ) C^a)[x) xy) 5 0    .OOBBBBDVsRVsvVsvVsvZ;s8s8s8s8s8VsHVsHVsHVsHVsH99cs=sss9ss99'9VVVssssssss9Ps;9Ps;9Ps;9Ps;VsvVsvJVcBVcBVcBVcBVcB!9!9!9!9sssssV4 V4 %%%%%V* V* V*/4/4/4s9sR9VsRVsRVsRVsVsRVsRVsRVsRVsRVsRVsRVsRVsHVsHVsHVsHVsVsHVsHVsH9999Ps;9Ps;9Ps;9Ps9Ps;9Ps;9Ps;Ph;Ph;Ph;Ph;Ph;ssV*V*V*V*ZZZZZZZZ[[lvvooswswswswswswt[h;;;;;;;;33 )o )o999A999=9=9#9#Wl>Koooooooo W l > Khommmmmmmm C X * 7 o oZZswsw;;99oommZZZZZZZZ[ [  o o;;;;;;;; l l  3   bo bommmmmmmm | c p o oZZZZZZZVVf.a/l9l" ";;;;;././1bo99999999C.H/3boV)V)./".mmmmmZ././x^"/l999999999UUUspNNNNsPsPV /e/e%rs$${:UV99LLsLrN9$N$|Lt%t9%[999: B99!:'9%:!9$V.U+V.UGU":B: :b9 999!:'9%:!9$V.U+V.UGU":):$::$q"ZZs(d7NN-5s8`1!R)9cV=zZs/(Xs^==Zo 1::o5V9P2V%^%^ VV9X9cssV*VY)Z9rV44 4 4V** *sZU   U    ;s8Z;/qq(\d*1d-d+dZd\";B8$8sRIV/4KK]%] *gWWK: |K 1I 1<KW" B?;?;S<S<SSSSScScScScScS0E& RhRhs@4s@s1s4sBsM0+sBsIRi   d\j(1ydd\N9cs=V2s *s INd2-1kd4d+VsHVsHLsHsHVsRsRVsHVsHVsH99y9Ps;9Ps;9Ps;VcBs <(s4(s%ZZZZZZZZZZZZZZZZ999999999999999999f.a/[lv[vf.a/[lv[vC.H/H/W>lKC.H/H/W>lK.//hh.//hh)hVV99V)V)NN(( ~ 3>Takmvou~_my? [_hnsuzEMWY[]} c q !! ! !!!"!'!+!2!;!D!K!N!!""""""+"H"`"e#$#%% %%%%%%%&;&j,l,v..!  &7AVemoxtzbp?C]ajquz HPY[]_ j t !! ! !!! !&!)!2!:!A!K!M!_!""""""+"H"`"d#$#%% %%%%%%%&9&j,`,u.. |{zyVTR<:840*&]YTNJHGE"! ~}|vtshgec ^[TMJ>" Lphfdb`F#َْ``) 531&   !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`ardeixpk-vjkhslmgw`ec9il|"cngNjam}b}:yOeqabczfdP@)*)('&%$#"!  ,E#F` &`&#HH-,E#F#a &a&#HH-,E#F` a F`&#HH-,E#F#a ` &a a&#HH-,E#F`@a f`&#HH-,E#F#a@` &a@a&#HH-, <<-, E# D# ZQX# D#Y QX# MD#Y QX# D#Y!!-, EhD ` EFvhE`D-,@ -,@ -, ECa}hC`D-,E#DE#D-, E%EadPQXED!!Y-, %RX#Y!-,i@a d#d@b` d#da\XaY`-,E+#Dz-,E+#D-,E+E#Dz-,%FaeF@`H-,%F`F@aH-,KS \XYXY-, %E#jDE#DEe#E %`j #B#hj`a RX@E#aDYPX@E#aDY-,~;! -,-A-A -,;!~ -,;! -,-A -,~ -,KRXED!!Y-, %#I@` c RX#%8#%e8c8!!!!!Y-,Ei C&`%%IaSX@E#ahD@E#`jD Ee#E`BY C`:-,%# `#-,%# a#-,%-, ` <<-, a <<-,vE %E#ah#h`D-,vE%E#ah#Eh`D-,vE%Eah#E#aD-,Ei2KPX! YaD-+,K PXYD _^-,, EiD`--,,*!-., F%FRX#Y Id F had%F hadRX#eY/ SXi TX!@Yi TX!@eYY:-/, F%FRX#Y F jad%F jadRX#Y/-0,K &PXQXD@DY!! EPXD!YY-1, EiD` E}iD`-2,1*-3,K &SX@Y &SX#!#Y &SX#!#Y &SX#!@#Y &SX%EPX#!#!%E#!#!Y!YD-4,KSXED!!Y-5,K PXYD _^-6, EiD`-7,6*!-8, F%FRX#Y Id F had%F hadRX#eY/ SXi TX!@Yi TX!@eYY:-9, F%FRX#Y F jad%F jadRX#Y/-:,K &PXQXD@DY!! EPXD!YY-;, EiD` E}iD`-<,;*-=,K &SX@Y &SX#!#Y &SX#!#Y &SX#!@#Y &SX%EPX#!#!%E#!#!Y!YD->,KSXED!!Y-?,K PXYD _^-@, EiD`-A,@*!-B, F%FRX#Y Id F had%F hadRX#eY/ SXi TX!@Yi TX!@eYY:-C, F%FRX#Y F jad%F jadRX#Y/-D,K &PXQXD@DY!! EPXD!YY-E, EiD` E}iD`-F,E*-G,K &SX@Y &SX#!#Y &SX#!#Y &SX#!@#Y &SX%EPX#!#!%E#!#!Y!YD-H,KSXED!!Y-I,K PXYD _^-J, EiD`-K,J*!-L, F%FRX#Y Id F had%F hadRX#eY/ SXi TX!@Yi TX!@eYY:-M, F%FRX#Y F jad%F jadRX#Y/-N,K &PXQXD@DY!! EPXD!YY-O, EiD` E}iD`-P,O*-Q,K &SX@Y &SX#!#Y &SX#!#Y &SX#!@#Y &SX%EPX#!#!%E#!#!Y!YD-R,KSXED!!Y-S,K PXYD _^-T, EiD`-U,T*!-V, F%FRX#Y Id F had%F hadRX#eY/ SXi TX!@Yi TX!@eYY:-W, F%FRX#Y F jad%F jadRX#Y/-X,K &PXQXD@DY!! EPXD!YY-Y, EiD` E}iD`-Z,Y*-[,K &SX@Y &SX#!#Y &SX#!#Y &SX#!#Y &SX#!@#Y &SX%EPX#!#!%E#!#!Y!YD-\,KSXED!!Y-S+I+?+5+++Aiy@yJ@ T Ҹ  A d%zH()l`A p2,%&1-1'@gg')lum)d1L9V@ 68!5/'@ -L*1$ %@:LE':E'*%J%zI)8{H(1%z@6H()H'%)L%)F'')H'V[A2+(&!  ????@Jv??>9FD>9FD>9FD>9FD>9FD>9F`D>9F`D>9F`D+++++++++++++++++++++++++++KSXY2KSXY+++++++++++++++++++++++++++++++++++++++++tu+++eB++KRyvpjfEe#E`#Ee`#E`vhb jpEe#E &`bch &aep#eDj#D vfEe#E &`bch &aef#eDv#DfETXf@eDv@vE#aDYbBr]Ee#E`#Ee`#E`vhb rBEe#E &`bch &aeB#eDr#D b]Ee#E &`bch &ae]#eDb#D]ETX]@eDb@bE#aDY++++EiSBst EiK (SIQZX aYD EiDu(/Um;?<(^j\.Lft (mL%z @Lb$89^@RU#QtL,BPQ%h;hvSS}(*R`Ekt@)GGHot5 KLRUevv0CP}*UXwxN\ys [r~%;B^^P +ti>%b;!9BN_aop42MMNOfi Sbm*JZGIm9>NVc~(Lo$2ncDbCatdp(]~G0{b}\lB0*****llll0P$ d (  P h\D,<$(d  !<"0"#$D%@%'`(t* *h*+-L.D///0X01T1|13<455789h::d:;;<=>?@h@BCTDE4FFHHIIJKKKMOLPQR0STdUW$WXXDYZZ[[\\]^`^__`apbcxeDf<fTflffffgixiiiij$jpjk`lPlhlllllmotooooopqqqrrr4rLttv v8vPvhvvvvvxHx`xxxxxxyHz{{ {8{P{h|4|L|d||}~~ 8Ph(@Xp\t4,DtTlD4Ld||@XpTl 8Ph4Ld|  8Ph(@X pPHDXD0XH0¬ì@LlŌŬ $<TlƄƜƴ<\|ǜǼȴ4Ldx 8Ph̠̀ʹθ0H 8PpАШ 8PhрјѰ(@Xp҈ҠҸ0X 8P,Ddۄۤ4LdܴްTx48(pLT4pt($,h,tP0<<h  <   | x@T, 8HXHx$8| !|"\#,$p%&`&' (L)*,8. 0 1 2|34,556x707899: :;>`>?\@@A$AdAAB,BpBBC C<ChCCCDDxDEEFFFGGxGHIJ JTJKKKMDMNNO(O|OPPTPPQ Q0QtQQR8SHStSTTTU$U`UUV<VVVWW\WX X8XXY(YZ[@[[\\h\]<]]^8^^^_0_|_```a,aabb`bbddTe0ef,fg8gxghhxhi(iTijjDjpjjk kklhlmnn<nlno opptpqqTqrXs,sssttu(utuuvpvvwyyhyz0z\z{0{{}P}~DXH$@<`TL4Ld|tL,t(h@0Dd|$Pht\\X,D 8 $@ \,|Ƭ,Ǽ,pˈ8̬ψДѠӬtp,ִhL@ڈܠ ݐ8ެXLH4DHpTd(0TthdL,l\ < (   t  0,p<p L\P0 |!P#@%&0&'`'())*4*+,-.8../X/011282340456,678:8;;;<<=P======>>>0>??@ @$@<@T@lADB B8BPBhBBBC`CD D$D<DTDlDDDDDDEElEEEFG,HIJ8KL(LNP`R4SUVX(Z\P]X^abldeg@hj0kn$prsxu0v wyT{(|@}@ \@L|t@d@X,@pX\TT@H@`0t4X(x0T$|Ƥɬʬ˄ΘϼH҄8ӌPhԀԘ԰(@XpՈՠո0Pp֐ְ0Ph׀טװ(@Xp؈ؠظ(@Xpو٠ٸ(@Xpڈڠڸ0H`xېۨ @`܀ܠ 8Ph݀ݠ 8Ppސް(@Xp߈ߠ߸0H`(@Xp0H`x 8Ph @` @` @`0Pp0Ph0Pp0Ph(@Xp0H`x 8Ph(@Xp0H`x 8Ph(@Xp0H`x 8Ph(@Xp0H`x 8Ph(@Xp @` @` @` @` @` @`0Ph 8Ld $<TlL 8Ph8<Tl  , D \ t      4 L l       l l l l l l l l l l l l l l l l l    ( d  0LH0d(8Td \ ! ""#H#$4$L$d$|$%T%& &'('(**+ +,x,-. .h//0@00000000000022T2355d7H899<9|:0:;<<=>?X@@AACE(EEEFGXHIJKKLN`OPTRSUdWZ[[]4]^_abcddefhk|llmoq4qLrsupvxyz{|~H~~~ XtH dt 4L\t4D\|$4D$0DXhx8,`P@lT|d4h44ltt$L@lp,D<x4h<„|tŤp<ː|ϐTHфҨԬ4@4Ld|ؔجl(@Xxژڸ 8Xxۘ۸(Hh܈ܨ0Ppݐݨ0Ht,Ll ,Ll ,Ll ,Ll ,Ll ,Ll ,Ll $<Tl,D\| $<\t<Tl4Ld|8tBCS+//и/ܸܸ V+V+013!'!BCM 4@O* % d!x|++NM99NEeDM??103#3#1f4|Rq^%@)) !H++NM?<<10###^yyLLq@'W w                    7 7z !G v<?<<<<<<pue?q!)B '3@R % 7X g h F  *0$!$ '-$ 3$ 5*$0$$$$4?R+NMNEeD/735#'#"&54767$;VIo+CNA++Ba?Y4z  fRDwe>*DSA^J&-=pYf?^2Klu~ Dyj>QPOGèY)HpDfqR&@)!H++NMNEeD?M10#R!t!L^a>@   @@L!lR2++NMNEeD??10#.'&'&576^/GQ2yF)8 ];ϐ~lWO(%D^6@ L @ !?{++NMNEeD??1076'&3G.FQ2yA&0)^;^6!!se}qNq@fWw 7 7  77   M ?H+NM73#Ú&Yn@"@N6FWknz*Zk||"!" 5 u!" !8o"'8"$G#v?<^Vj A}L~tU0Z[-(1i dݿnǚK/S@6 8 : 9 J UVb |   :  o8 Gv99??<<99]10]#67!5/EXW-.D艗CcB 2@GVW ZYde kiw% I{v#r%s'|1|2 '.1 G2%%2 5,55, 8!8)o/88/4G3v??9/999910Cy@5*.  -( +( (((.( *(( (+++++++++]]654&#"3654&#"3'&54632#"$5467tf*OD&PY3_|z@\PZer;p+PّS/-)5d1I'@.+(HXh F!''5 !55 <1U@ )$8 )G(v9}KRxz/??9/910Cy@4& %&"$( ((& $(#!(!((% '(++++++++++]326#"543 !"&5654&#"3k7E&gBx=E +9(=887!9 'BF GXUX!f A  & V   -./, 5#J-);GJFC@J -..825&2&8?2/99//9.9?9?<9]q10]]]&#"325&76! #"&5467#"&54327332654! !2$7#SIrVAd̿c^5V{f27#rɬcwBZcbg;XF_C  s_0vSJ3>-) ޽iYZP= @PHXh (     % %   Y@  @   !^++NMNEeDFD? @m~ ":" : ###K@1;%% 1$%g!jp++NMNM9/????9/<<99]99910Cy@,! % &%  2! 22  2 22+++<<++++++]]#.#"!2$!5!#'# '&76!'1$40eNȾ.!Psࡓo+Jrq/ ?@!  %  %  !vp++Nx32%-,5\v?sbl2 0/";gҌ !4@ %^+NM<(E(%%    @    ^+NM99999999NEeD?*4 @p(6GWWggvx ' 778h% %  % %          !^++NMNM9?Pm/ c@6%    i  !++N@   X !<|++N)J'8=>!++NMNM9/????99]9..9910Cy@(67"%6!! !!"7!!!!+++<++++]]$3276=67654&#"#>323267#"'&'#"&5467rN_Y!h2mb1S> z;! vu% *,&]* 7|Z,I /gl,-\SL*SƛHH" B#@Hjv%p@."  ' ..) !]++N32#"'&'#$654&#"3v;`zT29f{&GMQ;#M}辩޶ї^;N@/J  '' '!r}++NMNcX-WHI$% @y@ @)K  ## \!$$9!  %%% '''$.'&'!]++NMNM999999/]???9/<<910Cy@F#& %"$& & & & #!&!& &  &++++<++<+++*+*q]q]]!327673#"3&'&#"86T0O1RyAR (J|#GkUQlJ]6G;.P#B&uFM@+ 9   )!g~++NM]9/<<NEeD??&'/0!rB++NM9NM9/?????9910Cy@,#( $%&#&&(&& ! %"&')& !+++<<+++++]53!"&'33276'#"$3&#"32765|^35#C2vڛH'53#"&'8y1&? 4#\7u:b @dY:Wgyx  9 m      )  !b++N32#4&#"#4'&#"#@4YqN,$32#4'&#"#LhP,0~@)J8-/^RWQbC$F&&HU JGO@&'& 7G  ' .)E!b~++N32.#"#k/6rBK./.@8 *($%'6!F!G$G'V$W'f$g&y y yv#t$t%t&, -.-.( i&%6%%" +.+ / /!/'>(&'(1'>'.01!]++NM9NM99999/999???9q10Cy@L-&%&!! &!,!*!!! "!!" ' !&% -!)!!!++++<<+<<++++++++++]]]32654'&/&'&54632#&'&#"#"&'%Dd='sAt۹kC&>fiE(NwBiPZ0WW[E$$"*IZh=2GN@F*/,E٠ ZR . ?@%9 )!g}++NM]9/<<NEeD/??73!&bB&)/*2/>t/gf !$N4I l@B7HWXWghgw ) 99 > J !r]++NMNM??<<9?<<9999/.+}10]7!5!!!4{>ώI^#r@>!'8 8 @ M M --%# $%!3++NM<<="9%CD% um?srn=rrF|pPS;)@ !we++N=4767C%8\<">?"k%D.PpDzrYp>qru@kʨuR@"K@  @"  $#$b!_++NMM/910]32673#"'&/.#"#>7>3f 953!5(Ift->$G&QT0u(2*aAW sT NA&[SuJ20q/ 5@O* %  d!x++NM99NEeD?M103#3#4e3/{h 1 @r5Jzy6K I,VZX,fhlv 4((())) +*+('  '+%! 1**))*) %1$@1!*% '. '! '.3G22v??9/9.+}999999999+<+ć+<+<+<<+<+<10Cy@"/0$ #&%$ &"! 0 &"& /&+++<<+++]].#"73#&'&'327673#"&'#7&535 > ~U.5S7w #C K, I%.>UE obB-C1;:>^7pbGE8D?@W((((:?34?)  #-:&.9"34);3,/"F! ?$? ,$;/68 ""@A'4\&6C8"AG@v9/???9/<<99999999999910Cy@*   AA  AA++<<++++*]7>54'&'#53&'.54632#4&#"!!>3232767#"$#"Bq ݝC -IH xE@H%/'1S8,IR327'#"&''7.5467 {wwz_8wES|6_.-'4_9|D>{G_*+0%H}}{^*+-*^:~J:<_++$4a6|DU|5{}@^8Wjx         % Gv/9=/??<9/<<<<999.+}.+}10] 33#!!#!5!'!53mo]S}]Cڇ)ׇڈ;3@  !we++N 8P+!=,RWCS+//ܸи/ܸ V+и013#%3#+;@8-8175797 +7#/ A   ';3<??9/10Cy@*;"0[6[$.'[*8'[ 2#[&,#[4+[(:+[++++++++]#"&54632#.#"32673! 76'&!! '&76! CӪkV y lgA*Rny11˕ķ+MKnS`WSV10;; 3@;v1--(0 ")#1#3" 3 *### #,& E"5"/45!?3++NMNM<9?54&#"#>32327#"&'#"&54767.q~33Re9">IH?~=((432:onY1RS)/JS!5290enH0Vj9-;+vLj4  t@&   ) )   @ !w++NM<9<<9 ;c@&  * %%866HGGhv      /<9?910]]67>54&#"#4632!! hYJQQ@{̲4JH)5@ 7   !++/9/?</<10###&5476)#H*@}Ly#tt== * 2 2!c{++NMNEeD/M10#"&5463MJK55KJ6=K55KK55Ky31S+V+A]A )9IYiy ]9 / V+ 901!3632#"'&'7327654&#"'Ba^.F[x|59 6#&)!%45,## QKLnQ 7 / )W; /9?9/10##567673ա~(>;Gk  e1; }@  !<3++NMNM??10Cy@0 &%%  +++++++++++#"'&54763327654&# S78WYcSZp/eH媨ÆXrq\tyrY~_9Mno t@#   ) )   @ !w++NM<9<<9@rrh;Gk  e{‡ XZCZ6 )p@7&) &)!( /9/<9/?9/?9?54&#"#4632!!Q@|)@eYMNZ"c&CaGk !dBJJ;FLA%I}ugCYLKm =Ad '  ,)#=7  2%=9)%,  2"/6=()=/99//<<9<99/?9/9?9/<<9?( eu#  $W*d 11"8!"!we++NMNM9/9?9910Cy@%AAAA+++++]3#>53327673#"$5467!w[,k 0YM=Fk?(M\3_ON/R"8Ct/R"8vt/R"8Ot/"8jt*GR"<vst fA&i iy z  1 % !++NM<:鿨{5!:ET0/#(lrG_- oyx5oFɥt%L`H,Qfp?RG"DCRG"DvRG"DORG"DeRG"DjRGZ"DcIIR4@2=>B=>BIFXFf H8: > 75-%9677D %@10):>KD  $.H-)77ST='>>'5T$)%J'NSTp!]++NMNM9/999?54&#"#67632>32!32673#"'&'#"&54767xx 0=o0OV171 a32p{d$20'>12[!B++NM9NM9??9?9?9.+}9999999++<++<+<++<+10Cy@*+%+&&* &&+++++]]&#"327654'&'7.54327#"&'2|L gr;O0؀26~_8H}4?n5yv;HB%94Q(kZA#/чJ~a.=2\wMMA8"XC"Xv"XO"XjI"\vK) `@@6877EGGGUW9HX   '" ..)!"!]++NMNM????9910]]]$654'&#"37632#"'&'#3Ӝ$Eq%B2Z콃T.$o†[ū[k#>>";dI"\j=&$qh!RG?&Dq=T/?+// B+B+ ܸ01327673#"'&' 3#!#8vm6cM( ڕTA!;;"@w>`wcCHRG L?+M/N/4ܸ%ܸи/MIиI/A&6FVfv ]A]%#и#/4?и?/%CиC/8FB+ B+0(B+ ܸи8и/8;и;/F?и?/01327673#"'&'276=67654&#"#>323267#"'&'#"&5467X8vm6cM( _Y!h2mb1SrB> z;! vu% *,&]* 7|A!;;"@w>`,I /gNZ,-\SL*SƛHH" B#@HjCK&$dBRGUI&DdLZq"&v;"FvZqs&&O;&FOZqY&&b;&FbZqz"&P;"FPcN&'Pp8),S+(V+V+ V+ии/A&6FVfv ]A]!и!/"9 . /%V++V+0167654&'#532654&#"3#5#"5432SEm`v}zK0=?o{O U-* wʬK>cX-W!c |@Q% &2 2222   1"% !"!v++N`mBH-5WS+(V+и/5и5/%V+ V+.V++2V+ ܸ01327673#"'&'!327673#"32&'&#"s8vm6cM( 6T0O1RyARr) (J|A!;;"@w>`QlJ]6G;.P#BkuF&(bzH&HbC&(dH3I&Hd@&(PlbH&HPce&*O=;&JOcx3ɸS+4/ /4.и./A&6FVfv ]A] #ܸ &и&/,и,/0и0/#5*V+ V+2V+# V+ ܸ01327673#"'&'#.#"!2$!5!#'# '&76!2K8vm6cM( 1$40eNȾ.xA!;;"@w>`sࡓo+Jrq=;0>S+?//ܸ&и&/?,и,/5A55&565F5V5f5v555555 ]A55]<и@V+ V+8)V+/1V+ ܸи"01327673#"'&'53!"&'33276'#"$32"327654&@8vm6cM( 35`(#C2vڛH'&Kq)i%Q 3S+V+/ /V+V+и/013#327673#"&/.#"#67632Yɟ.8 iwGD5/;#-b 9p"SC #&` ./O2\D#&weMfYS+V+/V+013#!!9Cve,&}qPsj&,as&a5CS+V+A&6FVfv ]A]9/ܸܺ9/V+и ܺ9013#33267#"&54767:J)53"!24`g:.aC0 3?+B+и/и//B+013#3#CtI0@ )!'++NM9NEeD/???103#\*I7++.+ .+.+//.+013#!"&=33276537fkq1CgiixymCP&LM#60&-ORP&OyN&.^&N/ 1++.+ /// /90133 ##f/9obnK"&/v*D&Ov>K&/^d&OKCS+//и ܸи/ܸ  //V+0167654&'#533!!,Em`vpQ U-* w N:7S+//ܸи/ܸ ///013#3#)CK&/bdv&ObK A7 4     % S!v^++N=##33#"&'y1+&? #\[Zu:bPG%Q++&/'/ܸܸи/&и/ܸи/9"/%/ .+01>=#4'&#"#3>32#"&'y10~@)J8-LhP,&? #\b`J*<y;!)۸S+*//A]A )9IYiy ]*$и$/A&6FVfv ]A]ܸ+!V+ V+'V+ ܸ01327673#"'&'4'&#"327!"532m8vm6cM( ^0LA!;;"@w>`h^+@Pn&2f;!&RfI (@@, ( ;;%$I;* 1$)*w!jf++NMNM9/<??<32!327673#"&'#"%&'&#"654&#"3G o>6@΁wB= )LO,*vSFq4)KYLvðIQ-Ucna_WtGQ[1U^|z^]tH5S ۸xM&5vso&Uvx&5G&Ux5&5PiWB&UPcc&6vB&Vvcc&6ORB&VOc3KTA GG*G&' )))"59 :87$EGJ JHUWVX XY[ZV(VJi(y x w w"783<1C-k*!$ KKK*::H* FGH*+8@770@)I@'K%I%'M%I%KLM!j++NMNM9/9?xe%-,5\v?sbl2 0/";gU QKLnQ 7 / )B3KLaALK)KLG!VV$ff$vvy x z zv# "%894=1B.k+%" LI+ GHI+,9A881A*AJ(L'>'(N'>'LMN!]2++NMNM9999/9?fiE(NwBi@.F[x|59 6#&)!%45,##dPZ0WW[E$$"*IZh=2GN@F*/,EW QKLnQ 7 / )٠cz&6PjB"VP!3&7z..hZ&Wz7!K&7P'm'S+%V+и/и/ и / ܸк%9/ܸиии/#и'ܸ$ / /V+$и&0167654&'#53%33#3267#"&5#53 Em`v&1 C'~Z U-* wՓE8  gœ!&7q0bZ&Wqs/&8ea&Xe/&8q!1&Xq/&K?+'/(/'%и%/ܸ(ܸ!B+ B+ ܸ01327673#"'&'327653! &8vm6cM( @`tj^ 9(e?+)/*/)'и'/ܸи/*ܸܸи/9#B+ B+ ܸ01327673#"'&'327653#7#"'&5i8vm6cM( 50D%#4gS-A!;;"@w>`9R4`Zў=*TR/&8cG&Xc/F&8fh&Xf(/&8dAFI&Xd%q]&:O&ZO*GX&<OszI&\O*G"<jst/4&=vV4&]v /&=b?t4&]b/R"=PMt4"]P3++.+и ///.+01##53567632.#"c#?$ R dp4\U8r %ŸS+&//A]A )9IYiy ]&и/$ܸ и /ܸ$и/и$и'/V+V+V+ и"01%2654&#"632#"&'##5353!!6z-S{o?N=w4XcvvK I+//и/ܸܸA]A )9IYiy ] L+L+L+01!!!2#!%654&#!!22kxtsG:rv%"I+#/$/#и/ܸи/$ ܸи/ A]A )9IYiy ]// L+L+ L+и/ 90135!!>32#"'&'#4&#"326v ;`zT29{&G’MQ;#M#޶ї^Ypm++.+A]A )9IYiy ].+ .+01332#"#676! ! g!Ų s=)嬺1;AY蝽T&!c ++!/"/!и/"ܸ иܸиA]A )9IYiy ] .+.+ .+и 013! )#%!!!27676765#!!2my]L]ceAtJ;a\'oYSG. I+//и/ ܸ ܸиA&6FVfv ]A]L+ L+L+01)"&543!!5!3!!"k2BstȬ rv%"I+#/$/ܸܸи/# и /и/ A&6FVfv ]A]//L+L+ L+и/01!#5#"532!5!3327654&#"%92Tz`;  G&{M#;P QMba^ѶI* ++!/"/!и/"ܺ 99A&6FVfv ]A]A]A )9IYiy ] .+.+ .+01432#!5!&"323>54&I76763 !"$327I`̾A kBnXnxΙ6mdFI`P?l%wM+j\/I+, L+A,,&,6,F,V,f,v,,,,,, ]A,,],ܸ(ܺ(9и# L+ L+'*L+ ܺ*'901%27673#"'&54767&5476324'&#"&# 'XN sݿ~z%,lkoysOU{wYE2LQfk`LJP]:uzhqx:-Y`P;I+L+и/ //L+ L+01>53!!!!#"&'y1/&U #\Bu:b(\@&@PGy& & &&'  /   $&#  $&=& (G'v9/?M<7>32.#"3!#"&'G1f1$2#5V,F ,.SU,ZC@g-8 d?`EUN  > S+ V+///01#"'&53 ?&1yb:uJ\## ?S+V+и //V+и 01333####%v"# ?I+L+и //L+и 01333####%v"%N!I+//L+ 901%'&#5632%;#"'#''TA)=h41,!u!3i7tId 66uRvFgLTP*[I+//и/ ܸܸ ܸи/////9 901>533###"&'y1 &? #\IZC[u:bsG?I+//и/ܸи/ ܸ /L+013>32#4'&#"#LhP,0~@)J8-/^RW0b N}BK.m++.+A]A )9IYiy ]0*.+.+01#"&5476?67654&#"#&763232767iBwN(Eif>&CktAs'=dD%PЏE,/*F@NG2=hZI*"$$E[WW0Z9^ ++ .+.+017 5!! !!9T'=ۤ79ɤ!P'S+ V+//V+01>5!5!!#"&'fy1&U #\Su:b#?++$/%/$"и"/ܸ%ܸ ܸ /.+01327653276?67'7'! &tuvv"/uS+ V+A]A )9IYiy ]  V+V+01 !5!#"$'332654#'iһpzb?ڤywd 6CmS+V+A&6FVfv ]A]V+V+01'"32673#"$57675!!~bzĒpԻʉi'? 렡dwŻy8&4N*uS+V+A&6FVfv ]A]V+V+ ܸ01'"32673#"$57675!!|bzpeһԉi|l' 렡xwy8&ER"&S+V+A]A )9IYiy ]и/(V+V+$#V+01767654&#"#676!2!!6'5!4R}G&Bu(yFb8d) V;oK5Sk}KvzGeL61Wja++.+//01!#3a;++/ /и/ܸ ܸ////01!#3#3a^.+>g++.+и ии//.+.+ и и и01!!!#!5!!5!3>BBVVn /S+V+ии//V+013#3#1f4|t X&''=PzO&'']P8&G']Pk&/-8qPv&/M>XP&OMq&1-!kP&1MSPp&QM8=M&$PoRG&DPsS&,PuT&PPo&2P;!&RP/.&8PP&XP/&8'jDq];&X'jq/G&8'j.vi&X'jv8/7&8'j)PY&X'jP/&8'jC6&X'jCHF$;++.+$и$/&!.+.+.+017&'&5!.#"#>767632#"&32676T0O1RyARr) (J|QlJ]6G;.PkouF=&$'jh=q\(RGq&D'jq=&$'b^:qU(RGv&D'bq&qi:IC&q922,S+%V+A%%&%6%F%V%f%v%%%%%% ]A%%](V+"V+V+V+и 015367!5!3##'# '&76!2#.#"!27674€0eNȾ.ϗ1$ǂ9 v18o+JrqPsࡓs2M3;B#5ոS+6//и/ ܸи6и/&и&/.A..&.6.F.V.f.v...... ]A..]5и5/ 7 V+"*V+1V+V+ ܸ$и%01533#!"&'33276'#"$3253&'&#"3276735542BstȬZז2̢*&1C?&QC=&$'ceTvRGo&D'cv>(&vJI&vSBV&vx\q&v9 =F&$hRG&D=&$"RG&D]F&(hH&H'8&(]H&HqF&,h5&p8&,n]"& P}&2;!&R$P`&2T;!&RfxK&5m&Ufx'&5LO&U/F&8h&X%/8&8$]&Xgc/>׸S+V+;8V+(V+A]A )9IYiy ]A&6FVfv ]A]80и(@>/V++:V++01327654'&/&'&54$32#&'&#"# '&767654&'#534cp\KLQC1[ڰZ;ΕQ7 WM^}N >x32%-,5\v?sbl2 0/";gҌ D$"_BK.=߸S+V+(V+:7V+A]A )9IYiy ]A&6FVfv ]A]7/и(?=/V++9V++ܸ+0132654'&/&'&54632#&'&#"#"&'67654&'#53%Dd='sAt۹kC&>fiE(NwBi_7 WM^PZ0WW[E$$"*IZh=2GN@F*/,E٠ D$"_!CS+V+и/и//V+V+01!#!567654&'#537 WM^g D$"_ Z'S+V+9/ܸи иииܸи#и#/)/'/#V+V+и0133#3267#"&5#536765<'#53&1 C'~Z7 WM^ZՓE8  gœ D#"_'S+ V+A ]A  ) 9 I Y i y ] 9ܸ)#V+V+ V+ 9%#901%2765!"567654&#"'6!2# %7d^>UoΉ7.n`Q-0xՁzuñ:]Pmk$I'S+ V+A ]A  ) 9 I Y i y ] 9ܸ)#V+V+ V+ 9%#9012765!"567654&#"'6!2# %7d^>UoΉ7.`Q-0xՁzuñ:]Pmk/&+P:"&KPDs/IS+/ /и/ܸи/  ܸ /V+901363 #4'&#"#ɌtI53#"&'&y1&? #\7u:b[ />;S+<V+V+ !V+и/и/9A!!]A !!)!9!I!Y!i!y!!!!!! ](и(/4и4/A<<&<6<F<V<f<v<<<<<< ]A<<] @/0V+9V+99и/и/9$и$/0-и-/013>32#"'&'#5#"54324&#"32627675&'&#"0=;`zT18=RVo{{]KG’}PE FSzKMQ;"K[*,-W[KbDk\tSbʬEUI#3CcS+BV+V+ $V+и/и/и/9#9A$$]A $$)$9$I$Y$i$y$$$$$$ ],и,/:и:/ABB&B6BFBVBfBvBBBBBB ]ABB] E///6V+9и/699#9?ܸ(и(/610135367632#"'&'##"324'&#"326327675&'&#"D5>[{tyR0;-wɅ[.+%FE F~EG Iu*F'<_5I&HU JC!?z\?TE6,>SR=ԋ8= +S+ / /V+ 9 901 3#!#3#ڕDZwcCHZ.q&0S+) V+A))&)6)F)V)f)v)))))) ]A))]//V+$/V+$&и&/-9013#&'&'327673!"'#7&'&76!2#"b0_!c3J=Gs=PG.9J@嬺Grx'3#ZS+rY蝽$9E4#f;8!,S+&V+A&&&&6&F&V&f&v&&&&&& ]A&&]&9// V+"V+ 9  и /и/!и!/*9013#&'32673#"'#7&'&532"&̘Hr/ p 7CL9}=6sJ0D XY>w&G: mn#K GS+V+и / V+V+и/01533!%!!BQl!.[S+V+ и /V+ܸ ииии0133!#5#!5!7#J~)p22ү0̯S+//A]A )9IYiy ]ܸ и / ܸ и / /V+012#6?67654&#"#4eW`9DsP$(u@$j] qO"%AFb|ENiS+V+A]A )9IYiy ] /V+012#46?67654&#"#4eW`9DsP$(u@$Nj]rqO"%AFb|E0%0S+!V+*V+A**]A **)*9*I*Y*i*y****** ] *9*9/A]A )9IYiy ]ܸи!$и!/и2V+.V+V+&V+ &9!и#0153! )27654'&#!3#27654'&#!0wm@O)Mq8cYpN1L}uj~FnuBc̚[wY/'+6`scjC_:#729.!S+"//"и/ܸ ܸ ииии #//V+V+и и и01533!33#! &53276=!.IIY[1<<Ďo o4^ 46S+///90133# 4_ZC.wS+V+V+ V+V+ V+иܸ ии иии 01!73!!!!!!#7!!!3#44npf{fo44#no~{ҴBKH8(/5;S+4#V+#494,и,///V+&)V+6 V+и/&(и(/6,и).и./29 3к:9013!327673#"'#7&'&32"3&#&'&'̘Hk86Oq T0O1RyAR1-6F;2(([|d ^S ()T5UQlJ]6G;.P !5B;.'2uF/#_S+//ܸи/ ܸии/ V+V+и01!"&=332765#5333#m7fkq1ŗgiixymCmPWS+V+иии/ /V+V+и013##"&'5>5#5335#538&? y16u:b#\4"5-S+.//. и /иܸ A&6FVfv ]A]&и/V++V+"V+01 '&=! &76! 5332! 7675'&#"f7ħ>1H|o 5g~I0ǟCm%] PN%øS+&//и/ܺ9& и /и/ A&6FVfv ]A]'//"V+ V+ 9"901#"'&=# 325332654&#" ?&w€1y/L0Ub:uaR qMJ\#8䫲^/!+wS++V+V+%ܸܺ 9+и и-//)V+V+ 9и"015!!2#./&'&#!#%2654'&#!/mmbVW .  d9z;r=fv1^3#rT)F!32.#"3##ثkc>6rwcQS+V+9/V+ܸии и и015!3!3!!# !%1P$1I/"%CS+V+V+ܸии и и$01533!33!#"&'53267>7!1bZ[H bB&)/*2/>VHʎf !$8QFH;Ѹ++?67654&327673#"'&54&#"5>32>32_Y!h2mb1Sr> z;! vu% *,&]* 7|,I /gNZ,-\SL*SƛHHi" B#@Hj9H$++.+".+ ܸи/ "9A&6FVfv ]A]&.+ .+и/01%#"543253#"&"32654&q>cRTRf9G$++ .+.+ и/A]A )9IYiy ]"ܸ& .+.+и/01>32#"&'#4&'5>322654&#"I32#"'&'##476324&#"326y1:`zT29&? {&G’F#\LQ;#Mu:bA޶ї^:Mm++.+A]A )9IYiy ].+ .+013327654&#"#>32#"&:r~J0pԵgcm܉wư8P*øI++/,/+и/,ܺ9"ܸи/и/(A((&(6(F(V(f(v(((((( ]A((]/// L+%L+ 9901#"'&5#"54323#2654&#" ?&8HVo{S0=1y}zUb:uK%,-W4K>\#ʬ8'I+(/)/ܸܸи/( и /и/ %A%%&%6%F%V%f%v%%%%%% ]A%%]// L+"L+"901#5#"5432476322654&#"y1?o{S-9&? }zB#\AcX-W4D%u:bʬHG$;++.+и/& .+ .+.+01>32#"'&'.'33267!476.#"8rRAyR1O0T|J( UkP.;G6]ţJlɊFuHF$;++.+$и$/&!.+.+.+017&'&5!.#"#>767632#"&32676T0O1RyARr) (J|QlJ]6G;.PkouFA6=E>7.5&'&'&'%.&676767667677>'4-$  uU9W<*+!" M^nLJ-"*/9!'#;m;OF%%ys )9ixt -  HL!Dc<  ƞ:0D@dC˜'%oAI.;9c: 3ia $$-_T>n9j, نRH(++".+A""&"6"F"V"f"v"""""" ]A""] "9 /%.+.+.+ 901#"&5467.54632#.#";#"3267jZZۦ躪}avgkriwq^JƧj)sf{l^TLCPT[lXVfkSH(׸++".+A]A )9IYiy ]"9/A]A )9IYiy ]"*%.+.+ .+ 90132654&+532654&#"#4632#"&5^qwirkgva}ZZjJkfVXl[TPCLT^lޒ{fs)jƘ>EHJS+4V++A44]A 44)494I4Y4i4y444444 ](!V+>7V+1.V+.19!%01>7.5#"&5332654&+532654&#"#46326767=4-$  uU9W<*V+ZZj^qwirkgva}m.QSys  -  HL!Dc<  fs)jƘkfVXl[TPCLT^lI($$-_T>=H1S+V+-V+A--]A --)-9-I-Y-i-y------ ]&-9&/A&&]A &&)&9&I&Y&i&y&&&&&& ] ܺ  9A&6FVfv ]A]3//V+016?#"'.5%"2654&#'2654'&'B~lnZZjҬJ0D!47?iqrk41mO HI{fs)jUmn6VXl[TPC&$Q#S++.+ܸ и / и/// .+и 01#"&'53265#5333#Z?$ R \Udp=;*8I+9/:/ܸ6ܸи/9и/"9/A//&/6/F/V/f/v////// ]A//]'/*/ L++L+2L+  ܺ"+901!"&'33276'#"$32547632"327654&y6Eu:b_c=;B-I+.///ܸܸи/.и/$A$$&$6$F$V$f$v$$$$$$ ]A$$]+ L+ L+'L+  0153!"&'33276'#"$32"327654&35=#4&#"#4'&#"#367632>32#"&'y1kMj)pf@4YqN,$5353367632#4'&#"##"&'*y1ISUhP,0~@)J8-&? #\Y()WQb32# ?&0~@)J8-LhP,1yUb:uBb32!327673#"&'#"4&'&#"4&#"326Bo>6@΁wB= )LO,*vSFq *)KYLvqKQ-Ucna_WtGQ[1U^|z^ItH5SC۸׾P_w#I+ L+L+L+A]A ]A )9IYiy ]ииA&6FVfv ]A]%//#L+#и01%6765%&'&'76%3#?`^  c^jmp!FL_[!mjF1++.+и////901%#5#"&'532653k6rh1++.+и////901%#5#"&'532653k6rP<F[I+L+и/9и//// L+9 и/01#"'&5#"&'5326533< ?&ERk1yUb:u]0BMrhL\#G1++.+и////9013>32.#"#k/6rePGYI+ L+ и/ и / 9и///L+и/01#"'&533>32.#"# ?&k1yUb:u6r\#* I+L+/01&#47621&? k#\u:b* #I+ L+ ܸ/01>36#4&* ?&1b:u\#/ '9S+ V+%/&/ V+$V+$9012654'&+!2#./&'&+#,fwS-J{OPG?? "  I)YDRj;)$D`z&5SB=3,>M$Q/ '9S+ V+  //&V+ V+ 901327654&#33276?>73#!LJ-SwfWY)I  " ??GPO{);jRDQ$M>,3=BS5&z`D$\@ I+L+ L+01632.#"#"&'732767M+'))3Z!" !LM(<0U+* 4I [[U MLr\@ (/I+#L+L+L+и'01737632.#"3##"&'732767#A3-M+'))3Z!" ! (M(<0U+v_n [[UaSv_ M8~T. #I+L+L+и/013267#"'&'&'&#"'67632-4 *+U0<(ML! "!Z3))'+<p**[abx|22 Y YS++.+ܸи ии//.+и01##534'&#"5>323#x&1 C'~Z+8  g;D ZW++.+ܸи ии//.+и0133#3267#"&5#53&1 C'~ZZՓ8  gp0/#S+$//$и/ܸ ܸ ии/ 9ии!и %//V+V+и и и 01533!33##7#"'&53276=!0ê#4gS-0D%p11ώ=*TRr`ZOR<'0S+V+V+ܸ иܺ9A&6FVfv ]A]! V+V+и014&'5!!#"5467!5!326}Z[~K#״޴#KԎ .++///901 #3h/. 9++/ ////99 901 # #33۴7ӻ5LG/=+++/ /// 99013#67632.#"#&bB&)/*2/>go !$h//S+V+9///90133#/P$N*}S+ V+A]A )9IYiy ]  V+V+и 01!5!#"&'332654#'l|iһepzbڤywx ++//ܸ и / ܸ и /A]A )9IYiy ] /.+012#6?67654&#"#4eW`9DsP$(u@$j] qO"%AFb|E++//и/ A  & 6 F V f v ]A ]ܸܸи//.+012#&'&#"#&'.546O$@u($PsD9`W؂E|bFA%"Oq]j?+//ܸ A ]A  ) 9 I Y i y ]и/ܸи//B+01!"5332654'&/.3e$@u($PsD9`W؂E|bFA%"Oq ]j:\NuS+V+A&6FVfv ]A] V+V+ܸ01#.#"32673#"32ϯr~J0pԵcǠqwJ~P˸I+ L+L+L+A]A )9IYiy ]A&6FVfv ]A]!L+L+L+01! '&7! #"! 3#V­tJ*<yO=H1׸S+# V+-V+ 9A##&#6#F#V#f#v###### ]A##] #9/A--]A --)-9-I-Y-i-y------ ]3//1V+01#"&5467.547673"2>767654'&#8jZZnl~m14krqi?74!D0JUj)sf{IH x$&CPT[lXV6nm0 OI+ / / и/ܸ ܸܸи / ///L+013!3#!#0c r/ 7++.+ / //9901## 3732ONrU9/I+L+/L+013!! /fiE(NwBidC'~Z%Dd='sAt)&11Zo^Zh=2GN@F*/,ElO gœ!Z0WW[E$$"*I]HE8 Vo\ .9QI+/%L+%/9%)и/+L+ L+)&L+),и&801632.#"#"&'732767#"&5#5333632363#hM+'))3Z!" !LM(<0U+!'~Z&1  .I [[U M7xgœ+8 Pr=øI+L+L+6L+и/и#и#/*и*/+и-и-/.96? /#/:/=/1L+ и /и,ܸи/,*и*/.: 901>=#4'&#"####53567632.#"353>32#"&'y10~@)J8-#?$ R LhP,&? #\bfiE(NwBid)%Dd='sA=@0^Zh=2GN@F*/,El $PZ0WW[E$$"*&6m +I+L+ /L+ L+013!!!!ra Y kS+ //// / 9 9 9  9  9 9 9 90133# #33# #z}x|ko}puz}x|ko}p}  }@  }h_I+//ܸܸи/ܸи и и// L+L+01#!##!#ogowogo[$[8$[2UF2$kI+%/&/% и / ܸи/&ܸܸк 9 и////L+901>32332653##"'&=#4&'2 ?&1p@3WS-1y-b:u ]v7X8>$Q!9Y\#2P20)I+////% L+901#"'&5#"'&=#4&'5>32332653# ?&?2WS-1y ?&1pyUb:uO 9Y\#b:u ]v7X8LLBQI+//и/ܸ ܸ ܸ/ //L+ 901367632#4'&#"#BZ +Au)]D8[Z)R,OR;,MkA$uI+%/&/%и/ܸи/ии/&ܺ9//!L+ ܸ!$и$/01367632#4'&#"##547632< +Au)]D8[Z X.0r)R,OR;,Mk:1+I+L+и ///01#53>53#"&'ZZ=ZXQh.[:1EI5I+L+и/////9013>32.#"#EU R5  DIZ]N_X9DI?I+L+и// L+и/и/01#5#"&'532653IV R6 DIZ\N_W94D5I+L+и///901#"'&=#"&'5326531X  ")6 DIZ<1:!'_W94q.] 'ѸS+(//( и / ܸA]A )9IYiy ]и/и/"ܸи/"и/"9") //&V+ V+ 901327654&#33276?>73#!5 ;UHҏ?3 -,29k8X"*K;7,  $+f.;&WD0  9I+/ ////99 90133# #lgheinZ]mj]Z\a !I+/ ///9013#"&'53267>73cA1!N@Nf4WZR J(Lav+++//01#+E[Bav%++////01#!#+E[iE[BBZ 'I+ L+и //013#5467Z79mdrm jF w 'I+ L+и / /01>54&'#5379mjl jE ɀ  'I+L+и//01.=3#ljm97  Ej [Z /I+ L+ ܸи //015265444JJ4V{{SJ44JS{VV{[ZiI+ L+ܸA  & 6 F V f v ]A ]//01"&5463"3[V{{V4JJ4{VV{SJ44JSN I+//ܸ и / ܸ и /A]A )9IYiy ] /L+012#6?67654&#"#463bw,B0Y"9( :DS YzpX5B@.AW9' #1H>"AlO I+//и/ A  & 6 F V f v ]A ]ܸܸи//L+012#&'&#"#4&'.546(jzY TC; (:"Y0B+vƒlA">H1# '9WA.@B5XpWI+//901% %I" Z[WI+//9015-5W"I[Z$BI+///901# #]Z["I$BI+///90133 [ZI"*S+///901#'#̤!*S+///901#373ˣ!x{I+L+//013#xffxI+L+01!!xvVI+//01 #V!:I+//01#3ω!x;rI+L+//013#xff8I+L+01!!v:}I+//01#3ω}!}VI+//01#Vb!! S+/// ///0153#1#1#53131!==כ==;9;;9;! S+////01#53131==;9;[: /I+ L+ ܸи //015265444JJ4V{{SJ44JS{VV{[:iI+ L+ܸA  & 6 F V f v ]A ]//01"&5463"3[V{{V4JJ4{VV{SJ44JS.7 ?I+L+/// /ܸии и /015333#5#.UUTHT.7 ?I+L+/// /ܸии и /01###53357UU THT.7 ?I+L+и / /L+и01753533##5.UUTTUKI+L+01!!U ]S+ V+ ܸ01327673#"'&'8vm6cM( A!;;"@w>`S+V+V+013#%Z ǸS+//A]A )9IYiy ]и/ A  & 6 F V f v ]A ]ܸV+ V+012654&#"2#"&546T4JJ43JJ3V{{VVzz J44JJ44JO{VV{{VV{C S+V+ ܺ 9A&6FVfv ]A]V+ܺ 901!3267#"&54767:J)53"!24`g:.a07.55>724-$  uU9W<*VVV*ss  -  HL!Dc< z$H$-_T>:- I+/// /0177''7:;==;;;<< %GI+L+9/ /// 9 9 901&'&#56723# 5 `\c)J DI+L+//013#DZZ!!.׸I+//0//и/A&6FVfv ]A]и/0(ܸA]A )9IYiy ]и/+L+L+0132654'&/&'&54632#&'&#"#"&'x"T2L9HD!:n\y6!UM34"'H1# '9WA.@B5Xp#S+V+/V+01!!5!e*C/S+V+и //V+01!!5!3eeJC/S+V+и //V+01!!5!3eeC/S+V+и //V+01#!5!eCJ#S+V+/V+01!5!eC*;w/S+V+/V+013!!;U/J;w/'S+V+//V+013!!#;UU/ J}sI+///901#373ˣ}!xI+L+L+01!!!! @@xvpvNt$ BTI+///90133 [Z I"$ BTI+///901%# #]Z[T"I W>I+//901% %I"Z[ W>I+//901 5-5W"I[Zxx øI+//ܸA]A )9IYiy ]и/ A  & 6 F V f v ]A ]L+ L+012654&#"2#"&546H4JJ43JJ3V{{VVzzJ44JJ44JO{VV{{VV{:QrS+//01#3ωQ!3OrS+V+и01#3#3~O##3OrS+V+и013#3# ~r#'S+/V+V+ и /01%327673#"&/.#"#67632x.8 iwGD5/;#-b 9p"S #&` ./O2\7S+V+ии V+V+013#3#S+V+/V+01!##.UJS+V+/V+01##5!U.J2S+V+/V+0133!U2J2S+V+/V+01)533UJ<nCS+//и/ܸܸ V+ܸ013!53`i$S+V+V+013#i;S+//ܸи/V+и013#%3#<QTaS+V+A]A )9IYiy ]/ //01.#"'>32#5>54&)+3V! 3&X`S+ V+ ܸ01&'&#"#>328vm6cM( A!;;"@w>`[1 S+ V+ //013#5467179mdrm jF w[1 S+ V+/ /01>54&'#53[79mjl jE ɀ [1 S+V+//01.=3#1ljm97  Ej [1 S+ V+/ /01>54&'#53[79mjl jE ɀ }S+//01#3}!}S+//01#b!'S+V+//V+01!5!53#vLTTV'S+V+//V+01#3!!TTL VMyS+V+/V+01#5!5TKyT S+ /01767>7'7&'%Y0' )Rml;dTM. '^x/iS+ V+ܸA  & 6 F V f v ]A ]//01"&5463"3/V{{V4JJ4x{VV{SJ44JS#S+V+/V+0133!5VLTT#S+V+/V+015!## VTTL ?S+V+и //V+и0153533##5VVTT8S+V+01!!vo S+V+ / //01>53#"&'o<Z Xa.k;1o S+ V+///01#"'&53X Z<1;t.i$eS+V+V+013#ie;S+//ܸи/V+и013#%3#x øS+//A]A )9IYiy ]и/ A  & 6 F V f v ]A ]V+ V+012654&#"2#"&5464JJ43JJ3V{{VVzzJ44JJ44JO{VV{{VV{[t1} S+ V+ //01>54&'#53[79mjl jE ɀ 3}S+V+A]A )9IYiy ]9/ V+ 901!3632#"'&'7327654&#"'a^.F[x|59 6#&)!%45,## QKLnQ 7 / )CzS+V+ ܺ 9A&6FVfv ]A]V+ܺ 901!3267#"&54767n:J)53"!24`g:.a0`}S+///901#373%ˣ}!}S+///901#'#%̤b!S+ V+ ܸ01327673#"'&'8vm6cM( dA!;;"@w>`S+ V+ ܸ01&'&#"#>328vm6cM( A!;;"@w>`h$}'S+/V+V+ и /01327673#"&/.#"#67632.8 iwGD5/;#-b 9p"S #&` ./O2\8S+V+01!!vf&8S+V+01!!f@vf&8S+V+V+01!!!!f@@vpvh$'S+/V+V+ и /01327673#"&/.#"#67632.8 iwGD5/;#-b 9p"S[ #&` ./O2\XS+V+01!!Xvf&XS+V+01!!f@Xv^=S+//013#c.=!S+//013#c.C^x/ 'S+ V+ ܸ//01526544^4JJ4V{{xSJ44JS{VV{IC?S+//и/ܸV+ܸ013!53IJfJ.;S+//и/ܸV+V+01!!%! Jvj-S+/V+ 9 и01&'&#"632632&#"#8vm6)MN)6mv8jD;;qq;;@vi S+/// /0177''7;==;.;;<<P=S+ V+A  & 6 F V f v ]A ] 9/A]A )9IYiy ]ܸи///01.54767567654&\2O/. `&#FS"p9 b-#;/5DGwi 8.f&xS+V+V+01!!!!f@@xvpvS+//01#3!S+//01 #!S+ V+ ܸ01&'&#"#>328vm6cM( A!;;"@w>`[1 S+ V+/ /01>54&'#53[79mjl jE ɀ  [S+ // и/ܸܺ 9 9 //V+и0153%3##3{}{{eg}}}}Ns#S+V+ V+ и/01!3727#"'&'&'&5N5!-h@''2G IC1;S+//ܸи/V+ܸ01#5!#JJ1.8S+V+V+01!!!!vzv*;br?S+//и/ܸV+и013#3#*ffff71[S+V+/V+01#5#5[JUs=#7.#"#>32732673#"&'WJ/24^2I2&D @HB,57b2K4)@F 1)(E3 9-&J9#si='32673#".#"#>32'4632#"&4632#"&i57b2K44MDC(24^2I2+KGEF1!!//!!11!!//!!19-&J9#$1)(E3$#//##--#//##--:7-S+/ /#*V+#3и3/7*#901>3232767#"&'&'&'&#">323267#"&'&'&'&#"'9'0#1.-, ( E"+#!'9'0#-G!B%& C",$#J ` #w#J-` "c ) )S+/ ///V+901%!55!%cI4I嫫嫫+S+V+//9901##5#vgS+//9015-5"I[Z^/Z iS+ V+ܸA  & 6 F V f v ]A ]//01"&5463"3/V{{V4JJ4{VV{SJ44J+S+V+V+ V+ܸ0167632#&'&#"73# (Mc6mv8{v`>w@";;!A!6) S+/ ///0177''7;==;;;<< >S+//901% %I"Z[ >S+//901 5-5"I[Z T ;S+/ //999 901 5-5%# #"I"Z[[Z"I^/Z 'S+ V+ ܸ//01526544^4JJ4V{{SJ44JS{VV{PS+V+V+013#WS+ V+ 9///999 9 9017''7'75(ڇcf(LoGGGGoNQx<,>׸S+?//A]A )9IYiy ]ܸ?и/VVzz>  =V4JJ43%%4%%43JJ{VV{> >{VV{= =J44J%$ $%%$  #%J44Je S+//V+01 '7%=959s=949 S+//V+01! 76%# '&% 6!!se}q*.FQ2yA&0)^; FS+//V+01! 76%# '&% 6!!se}q.FQ2yA&0)^;xS+V+01!!xv8S+V+01!!v lw"3S+/V+и/!ܸи/ 0132673!"'&'%.#"#>7>32rjfBjP$2Z|HhL4`8:"PdT‚:QW sT NA&[SuJ20 FS+//V+01$'&! 5>7>3 ʎse}q("I.FQ2yA&0)^;eS+//V+01%5!5!5eIv ;ɸS+323267#"'&'#"&54670,K471*9 B=FT|Q_;:  / g>J_]L#$SI 3'-  .*&*cN$$LC" $5[DJR  $3S+V+$и$/V+!V+V+01!327673#"&54632&'&#" xHLF* Y')T)6%QQc/#I(6:#AYE'S+V+и//013#3#\\\\f øS+//A]A )9IYiy ]и/A&6FVfv ]A] V+V+014'&#"3267#"&54632b&]SKKRYC^~nshK/J~YVrU~US+/ /и/ܸи/  ܸ  и / 9/ /V+01327653#7#"'&5K B^"ZU4Is))0T-OO+M)EleS+V+A&6FVfv ]A] V+V+01#.#"32673#"&54632W9?V%DI8A Wx]i}jZrL1BT7PPnDQS=DUIWQ V7Zxo=$keebheVt%K2,}uMS+/ /и/ܸ  ܸ/ //V+ 901367632#4'&#"#Z +Au)]D8[Z)R,OR;,Mk^/ &iS+$V+V+V+$и/ 9//%/!V+и/ и!и/01367632>32#4&#"#4'&#"#^Y -8@'Q3l'^5'5L\ 83TZL' #+*N*Gt6(GS^6&OhDH 5S+V+и/////9013>32.#"#DU R5  DIZ]N_X9JC[S+V+ܸи ии///V+и0133#3:7#"&5#53[VV  !?-HHJ GA4bJS+///9013#7b`L +S+/// /9901373#'#u{|nsrav+++//01#+E[Ba+@++//013aE[BQx++ .+///01#"&53;H6>b"~9,];NuS+V+A]A )9IYiy ] V+V+01>32#"&'332654'&#"#;һp0J~rװwܡmc;NS+//и/A&6FVfv ]A] V+V+V+01#.#"32673#"5323#Яr~J0pԵ cm܉w3:;NS+//A]A )9IYiy ]ܸи/ܸ  V+V+V+01>32#"&'332654'&#"##53;һp0J~r װwܡmc! ?++ .+ и/  и и/ .+01%5>5#53# D:C{ ^w?L/sI+//013#no aI+ / /ܸܸ и/ܺ 9 9/L+ик 9013#%3#3#ꕕ0ntor&zC: j5+/ /0147672#"'&)$65''#'56&)}9%#''53'))%//&zZ/p&zZ/&zZ/#&zZ/&z/D&z.Z0&2n; %5+/// 8+ 9013#!#!#H ןʣZ@`u;)5+)8+"8+A""]A "")"9"I"Y"i"y"""""" ]"и/"9/A]A )9IYiy ] ܸ)и +8+(8+8+901!2#!7!767&'&!5!7674'&'&!fuKNwPL\_j{ZX%OsbNRRQRed987661?++)5+8+/8+01!!#)5+/8+01%!'3!'pBdTMZ /5+8+ 8+8+8+01!!!!!!LEH 5+8+8+01!!!5!qVB O5+ / / и/ܸ ܸܸи / ///8+013!3#!##ZZ`q-߸5+.///.и//ܸA&6FVfv ]A]и/&A&&]A &&)&9&I&Y&i&y&&&&&& ]"8+*8+8+01!!%76%2#$'&67656'&%m\RV nywhkuy?+R:9ff7<X78953/0+綻5+8+//013#Z= 15+8+ /// /90133 ##Z A/'5+///9013###?\bZD^s5+//и/ܺ9ܸ и / /// //9 9 901!3!#####CP+ZDD S5+ / / и/ ܸܸ /// /9 901333###uZub 5+8+8+ 8+017!!!!!!bMgRq)׸5+*/+/*и/+ ܸA&6FVfv ]A]и/ "A""]A "")"9"I"Y"i"y"""""" ]8+&8+0176%2#$'&67656'&%q\RV nywhkuyR:9ff7<X78953/0+綻?5+/ /и/ ܸܸ//8+01!#!#f#Z5+// ܸA]A )9IYiy ] и /ܸ/ 8+8+01!7654!'!$'!#BXVnj;:ZcdX 5+ 8+8+017 5!! !!X;#=ͬ5ˬ/#5+8+/8+01!5!!#!!)-/5+8+9///901#3 3dVPdPw#5+ 8+8+8+A]A )9IYiy ]ииA&6FVfv ]A]A]%//#8+8+#иии016765%&'&'76%53#?`^  c^Fjmp!F`!mj= +5+/// /9 901 3 3 # #1+\\+{{%HL)۸5+/ и /A]A]A]A]A0]A`]A]A]A]A]A`]A0]ܸܸ ܸии ////8+и01#$'&3367673)ۦvuurV{}}{7PMP  PMed5+//и/и/ܸ и / 9A]A )9IYiy ]A&6FVfv ]A] 8+8+ и 017!5$%!!5$4'&'!dZZj{{{}kȬ_fߓ\ɬ / W5+ 8+ и/ ܸи/и//8+и 013#3#%3#ŽZ)- Q5+ 8+ 8+ܸи/9/ 8+  и 01#3 33#%3#ٸdVPd=Z4&*zw4&.zh;o+6&0zb  &2z+&>n%Z=/5+,8+$8+$ܸ$и/ и /$9A,,&,6,F,V,f,v,,,,,, ]A,,]8+(8+и/и/ 01%727#&'&5##&'&5476723532767654'&'/=%%'H)-}suqp{P97%HBCHHHHX 31F⣦V%#;y{}{y}oq55+8+ "8+и/A""]A "")"9"I"Y"i"y"""""" ]" 9/  99/A//]A //)/9/I/Y/i/y////// ] 7/18+8++&8+ &+9&(и(/+)и)/01#%2"'&'32765&'&#5276767&#j϶yy9mquPRP!#?>`HE\\45-)sPN??o| Z]L1ûyz"#XeHB?54!TP@;=<RToJ=?5+8+9 // 9 9 901%&'&#5672 3# !1 #/i/;`HR!-#%1'h{)5+*/+/*и/+ ܺ 9 9A]A )9IYiy ]&A&&&&6&F&V&f&v&&&&&& ]A&&] 8+8+$8+01!!&'&'%5 67654'&'&'&'&# 'eLF닌KL)H}XX퇄՜'m}wP;:'& %tfkw=A5+<)8+A<<&<6<F<V<f<v<<<<<< ]A<<]<$и$/8+/88+@8+и/%@901#"727673#"'&'&'&567675&'&54767632#&'&#"73m///%%%PZsRO TPPFC)+EBXT57&#<{}} PP^LAHHETq%$:3#!)/1sXZ#%?Bdg?B98ZM87!CGNj)%#Z\!Jo05+(8+A&6FVfv ]A]/0-8+#8+ и /и/01327632#6767674'&+"'&57675!5!w (+F+)+5y@?#  =or<+:57-+)/XZ]K"%%)RT/be ;o+=G5+ 8+8+ ܸܸ/8+ и016#"5676363#6'#G!P{bۜHG'w=cbV(1S5+2/3/ܸ1ܸи2 и /)ܸии/-!8+8+)8+014'&'47676767&'&'&'&7676';@>?87^^^^67 1/bc`a11;:;93ᐑXjk=<<=kjolDEEDloH )15+8+и/// / 9013727#"'&'&'&5N5!-h@'')o #%/-8N) 15+8+ /// /9013! ##X)J{\#^%N!5+// // 901632;#"'#'&#)=h43-!3i7J'TA 67{do)5+ /!/ и/ܸ! ܸ ܸ и/ и/и/// /8+ии/9к9013327653327&'&'"'##9776JVT%'`l)NRTNsw"!FB1)5+///9013 3#B>+k)LqoB5+38+A&6FVfv ]A]:39:/ܺ?:9&/B8+/8+ 8+и/6 9?01#"73!"72#67656'&&'&5%5&'&'47675#5!V9:%Ghc+32--jeN=;++#"/2z{ChFG3-E"F`34 13J35./ONXXTMPPH?qnB1;9sVDC+ou=˸5+ /!/ܸ  и /A]A )9IYiy ] A&6FVfv ]A]8+8+01$'&56764'&'676q+FIHJVRNL=풓ז}{{pu{w/)[5+//ܸ и /ܸи/и/ / /8+и01!#727#"'&'&'&5!##/M6 -h@&' )oo #%/-8wou=#5+$/%/ܸA]A )9IYiy ]$и/ܸ и /""/ 8+8+ и /!901%676'4'&'&#%"'&'##DAA!;:VEFDC{{wwVRR/}wu9!uuw}}-ᢣ$%NLo=)5+*/+/*и/+ܺ9ܸA&6FVfv ]A]/8+016767674'&'&'&4767#% %5:`ߔzJLP%#!"o%%)RP5+yups qoVV>-/\N\_Io="ո5+#/$/ܸA]A )9IYiy ]9# и /A&6FVfv ]A]8+8+8+01#$'&56767!4'&'676d9FIHJVRNL풓}{{pu{w;)35+8+и/ / /8+01!!727#"'&'&'&5!;N5!-i?'')oo #%/-8+);5+//ܸи/ܸ// 8+01! 33276'3+JG9776[NRRNuwoP/#5+ 8+8+ 8+A]A )9IYiy ]A & 6 F V f v ]A ]A ] и ии!и%/"/8+8+и ии!01%67654'&'#&'&'%53#9]Z^_^`\\   pslkklsp""ood=S5+////99 9999016723 367&'&'# &'&#!J;9\-#@119V36)// vT7H --J)o7/#?5+8+ 8+8+ и и% //0133676767653#&'&'++;8AD;:+-ᇎ)jBA%#d#%ABj>be o ebm)55+)"8+38+ 8+A ]A  ) 9 I Y i y ] "939'"9A))&)6)F)V)f)v)))))) ]A))]7 /&/8+и/013276765'3&'&'#&'&747673327673j4/E@++-s?@X_eILLLf^_A>r3+&>J/-;V+/%#5ofX􁋊’53XX35¶fo5#%/+V /Y5+8+8+и/ܺ9/ /8+и013727#"'&'&'&53#%3#N5!-h@''Ǹ)o #%/-8+[5+8+8+9/ܺ9/ 8+8+и01! 33276'33#%3#+JG9776[NRRNuhou4&8z+ &>zm &Bz6;Ne++.+A&6FVfv ]A] .+.+01#.#"32673#"532Яr~J0pԵcm܉w3:m7++.+и//.+.+013#"'532>53#yji/%1!33=Rj+%9q"+;S+ V+ *и*/ -V+%V+* V+0176%2#$'&76767!&%!&q\RV nyj 5dku_R:9ff7<953/0+?R"'S+V+V+V+01!!323#"'&547632#&'&#"` 9O1~wZmvl=G~VCmh n[ϛ՝rhlDFwd?R#'S+V+ V+ V+ 01&'&#"#67632#"'&'332767!5!CV~G=lvmZw~1ߖO9 `mwdwFDlhr[nh S+//и/A]A )9IYiy ]ܸ ии/ / V+V+013!2#!#654'&#!!6?u!>:鿨{V:E>";dLZqmS+V+A&6FVfv ]A] V+V+01#.#"327673! '&76! c!Ųs=嬺G4Y蝽ES+//и/ܺ9 и /ܸ и //// //9 9 901! !#465##]Z&Cc-w)-64oO){S+//и/ܺ9 и /ܸ и ////9 9 901! !#465##B?)F-wC-64Fo==+۸S+,//,и/A]A )9IYiy ]ܸܸи/ии(и-/V+$V+ V+ии/ 901!%"'&'#!!#5!676'4'&'&#F,{{wwVRR/}DAA!;:VEFDCV`-ᢣ$%N٬}wu9!uuw}ZquS+V+A]A )9IYiy ] V+V+016! ! '&'332#"#h4Gׯ=sٲ!&T͛YA;1Zq!S+"//"и/A&6FVfv ]A] V+V+ V+01#.#"327673! '&76! 3#c!Ųs=嬺G4PY蝽EZq"S+"//A]A )9IYiy ]ܸ"и/ܸ# V+V+!V+016! ! '&'332#"##53h4Gׯ=sٲ!&T͛YA;1u\&k~ WS+V+ V+V+ V+ V+V+V+ и01!!!!!!3#%3#1){H: ^6S+7/&/72и2/1ܸA&&]A &&)&9&I&Y&i&y&&&&&& ]&ܺ298/6V++V++9301!>325>7>54.#"#!5!}CWi9,\ZT$0=# <]A@~ug'ITZ-1E,-V|O-PKG$ab/"-nrq0T53:  +$(er|?\f6  F )S+V+//V+ 901!!#3#`dFPb87S+,V+,)3V+"V+*+V+01#".54>32#.#"!!32>7b+IfaCj@9cQdbC%JiKSiN4J,H]gk1^lB @}oR0Bo嘕zL")G^in4GpM)*H`mt8ewT4DoHb@S+! V+@V+6 !96/ܺ+@9+/A++]A ++)+9+I+Y+i+y++++++ ]ܸB&V+;V+;01.#"#".=332>54.'%.54>32-X[!@]<$e`/0TrH؎F?kPOl?DmNb\+AÃ{̓Q=mP/y(>1%HG`|MXcD)OcTW,<]A3N:-AD\tHZxE;vtS+V+//013#B MS+V+ V+9/ܸ  /V+и 013#3#%3#ŝGB#h?S+//ܸ и /ܸ/V+013#".=332>5J{VKnC4U<5W>"d&,_iuf9X<>gM% 3S+'V+V+V+A]A )9IYiy ] и3ܸ5*#V+ V+ V+*и/*ܺ'*901%!2>54.#!!2#!! #"&'532>7+>wo?4Z_' !.C0 =cJId= e Cxh #S+ V+V+V+A]A )9IYiy ]и!и% //V+ V+и  и"01%!2>54.+3!332#!!#wnĬ=cJId= ^LNWS+//и/ܸܸи//V+ V+01!5!!>36#4.##?#[df/vm3@iKX\ 4e\9:[?"LFAS+V+ / // 9 9 9013#3! ##yuFa4-\&n~/H9*'S+'V+ V+ ܸ0132673#".732>73 3#"&' ePQd7cSXa3- $*--A/ p20Sa{W-V9QDJKAhJ'+Kg=  )52nb-/ CS+V+ V+V+ //V+ܸ 013!3!#!B;$O S+///V+01  3#!Z'ڛ^r+>S+//и/A]A )9IYiy ] ܸи V+V+V+01!!!2#!7!2>54.#!~=>woy=cJId=(5S+4V+ .V+A..]A ..).9.I.Y.i.y...... ]!. 9!/A!!]A !!)!9!I!Y!i!y!!!!!! ]ܺ94'и7V+3V+)&V+&)901!2#!%2>54.#!2>54.#!W96_H).K7-^M23Pr_O`Q$$Q`uoawAHtT 9WsH&XUI6UyT0g`V@%%C^::^C%%?V14Q8:S+V+/V+01!!#`d%eS+V+V+9/ܸ!V+ V+ииܸи013>7>7!3#!!%$  / 0c}ouƠ3;Mr{g8f /S+V+ V+V+V+01!!!!!!1){:  OS+ V+ и //// / /V+ и013! !###! 333ZPĄ\HvD^^vEAS+10V+V+A]A )9IYiy ]019/ܸ и /;ܸ&ܸC6+V+ V+@V+ܺ!@9+101!2>54.#"#4>32#".'332>54.+ ?\<6^L_a/-PlHvÌNYm9_E'bv~ڥd1ai_m;%LrNV'AQ*E`=5YvA^nL03edr(=[|Ppr9/l?jM+ FoN:`F'/ gS+ // и/ܸи/ܸ и / /// /9 901333###[BT/9cS+//и/ܸи/ܸи/// V+ ܸ0132673#".7333### ePQd7cSXa39QDJKAhJ'+Kg=[BTL 1S+V+ /// /9013! ##u4%7S+ V+V+ܸV+V+01! #"&'532>7!#!4Z_' !.C0 e CxhB{S+//и/ܺ9 и / ܸ/// //9 9 901!3!#####bb+B++/ WS+ // и/ܸܸи и / ///V+013!3#!#^BLP+ǸS+,//A]A )9IYiy ]ܸ,и/"A""&"6"F"V"f"v"""""" ]A""]-'V+V+01#".546$324.#"32>&NuzzʟvN&a  aF{|…F@Äā@_m==m_qq䫃ݟYY݃ݞWW/CS+//и/ܸܸ //V+01!#!#BS+//A]A )9IYiy ] и /ܸܸи/ V+V+012654&#!!2#!#njyt99tyZ~~>qaaq>Pb1mS+V+A&6FVfv ]A]V+ -V+ (0132>73#".54>32#.#"Fl^lB +IfaCj@9cQdbC%JiKqFߜUDoH@}oR0Bo嘕zL")G^in4GpM)T#S+V+/V+01!!#! /HS+ //V+01%32>73 3#"&'+ $*--A/ p20Sa{W-V  )52nb-A $/S+%V+V+" V+A]A )9IYiy ]"и и"A%&%6%F%V%f%v%%%%%% ]A%]A%%] *и1/#/* V+V+*ии "и+014.#2>"$.54>$3532##3">ą>5bbŦcc>Æ>fp;;o MᓓMMᓓMfo;c;p%/ +S+////9 9013 3 3 # % uu oo34\ US+V+V+ 9 /ܸ //V+ии 013!33#!ŗ;`QS+// и / ܸиܸ/ //V+901#".5332>73#O`l9iT1]V0cYI^ )g.[tB B CS+V+V+ V+  /// V+013!3!3!BqS+V+V+ V+  9 / ܸ/// V+ и и и и 013!3!33#!ŗ;ZS+//и/A]A )9IYiy ] ܸи V+V+V+01!5!!2#!7!2>54.#! ~>>wo=cJId=qS+V+V+V+A]A )9IYiy ]и!// V+V+ 013!2#!%2>54.#!3#~>>woc=cJId=BS+//и/A]A )9IYiy ]ܸи/ V+V+013!2#!%2>54.#!~>>woc=cJId=dw4WS+5/3/и5 и /3ܸ 'ܸ6,!V+V+3V+ 01!6.#"#4>32#".'332>7!p66s|KmH !CedX~Z3@kEU?r^1lh_H*L]S"JrO6pi]E(#MxދuG^nOk?3Rwg2S+V+)V+ V+иA]A )9IYiy ] 4.V+$V+V+0133>32#".'##4.#"32> eZ#IqzqpO-TEttEHqz:ybq_m=5^Yu߃ݟYY݃ݞWWj/FS+G//ܸG$и$/$9;A;;&;6;F;V;f;v;;;;;; ]A;;])и)/0иH///0V+FV+F901!#!"#>?>7.54>7>3!!"27!=S;)"  *QF VO7 4C#%ad]#a>662* $5+2\P@ (NbFrY?  2<@375 VLP3JS+K/4/ ܸ4и/K$и$/4-и-/$>A>>&>6>F>V>f>v>>>>>> ]A>>] LCV+0V+Cи/Cи/301>323267#".'#".54>7%>54&#"32>5Dt^NrE-0E/"L^tI>u]88Zt<-+1wzxANX,2T>"3H+FJG8"bT% GqQ% %;+%?/(NsLSyQ,%9?aUgg *;(.F0 ):J.H+;SS+T/J/AJJ]A JJ)J9JIJYJiJyJJJJJJ ]и/T+и+/32#".'.54>7>?>732>54.#"#(>4LN}_>>\|R]}J $Coo.gga('  2'*\hxFA -*EfGOlF%!IuUSxN&+01  ;i[(M=%BĂ)ud?(H8Iha@;@P. 9RYXE+3Qb]MIlBAo /(S+(V+"V+A""]A "")"9"I"Y"i"y"""""" ]"9"9/A]A )9IYiy ] ܸ(и *V+'V+V+901!2#!7!2>54.#!5!2654.#!H;Ud2fkIa::aI]l2?!/Jf' x_KxT-,>''?+JN,;$ /S+V+/V+01!!#/q/sS+V+ V+ V+ 9/ ܺ 9V+ V+ иܸии 01)#3>5!3#!Ĭ,4여|)!luqZ[WP#P"-gS+./#/ܸи/. и /ܸ#"и"/-и/V+(V+#V+"01#".54>32!32>7.#" JxclL+I`kp4nI*NoFGbB)+MlB?jP0VFjAGؒb}[;Bˉ\NZ1(>L%NzS+1WwG'/OS+ V+ и //// / /V+ и0133 ##### 333}]_[]^][^y3J3PES+V+ܸ;ܸ"и"/#9;(ܸG8-V+ V+@V+ܺ#@9-3ܸ@EиE/0132>54.#"#>32#".'332654.#"]%PB+5P5LI9,BSYZ)HoD-8D:'M|OfxG6L]06YB !! k'>, ;-+O?HmP6 %KrL1K8' 9Y@ZW+4`Q;N.fV%:)$/ gS+ // и/ܸи/ܸ и / /// /9 901333###ӹ/55$cS+//и/ܸи/ܸи/// V+ ܸ0132673#".'333### RPQR 2[MM~Z3wӹ@KIB7!#Xf0SvL) ''# B (Ivt/{S+//и/ܺ9 и / ܸ/// //9 9 901!33##### /n^^/ WS+ // и/ܸܸи и /// /V+013!3#!# /P!H+P'ǸS+(//A]A )9IYiy ](и/ A  & 6 F V f v ]A ]ܸ)V+#V+014.#"32>7#".54>32s(PuMMtP((PtMMuP(DuuDDuuDYl==lYZl==lZӔOOӄҔOO/;S+//и/ܸܸ //V+01!#!#3 eq/}Z+P.ǸS+//%//и/ܸи/A%%]A %%)%9%I%Y%i%y%%%%%% ]% ܸи/и/ 0/*V+ V+*ܸ и/ 90133>32#".'##32>54.#"}7MeAVzHC{k5\I4 "GkILoH""HoLIkG"/%B1BDŽB-7Wl==lW[n==nHP-uS+#V+A##&#6#F#V#f#v###### ]A##](V+V+ܸ-01#".54>32#.#"32>7,EcV/hcYC(L]T`B){oLqK%(JkD0VD0 y'\[TA'6U~lՔP$o^jc/#Cb>3/#S+V+/V+01!5!!#qN/S+// V+01333#"&'5326?g423=K1(-: 3?</hT|W6  1-FZbJ_KS+`/ и /AO]A]A]A]  ܸк 9,и,/.и\ܸ/и\1и1/RAR]AOR]AR]AR]=ܸ\GиG/HR9\Iи=a./I/V+'V+и/,к-I.90к1I.9'6иBиGиG/KиW014.#"3265##".54>32333>32#".'##2>54.#"&@T.JhB (73# <>иBlO;>;N54.+j^c43`W0S<"#?Y6m/W{MN{W.-G32F-?/S+V+ V+V+A]A )9IYiy ]!//V+V+013#3!2#!7!2>54.#!BW`33`W0S<"#?Y6//m/W{MN{W.-G32F-/S+//и/A]A )9IYiy ]ܸи/ V+V+013!2#!7!2>54.+)X`33`X0S<"#?Y7/m/W{MN{W.-G32F-/P*GS+V+)и,$V+V+)V+ ܸ01!.#"#>32#".'332>7!q 33>32#".'##9(OuMMuO((OuMMuO(N NkuDDumLϸYl==lYZl==lp;q~CO҂ӔOEu)P/'9S+1V+V+A11&161F1V1f1v111111 ]A11]19(//'(V+9V+9901!##"#>?>7&54>7>3!!"3!@_B%   2&'1JKHܹ$4' #%+574 D?s). "6*6D->0Q@1  N,+;& R%&SP#"-15oS+ V+/.V+32V+#V+-и7"V+/0V+#V+(V+ܸ/2и0401#".54>32!32>7.#"3#%3# JxclL+I`kp4nI*NoFGbB)+MlB?jP0%HVFjAGؒb}[;Bˉ\NZ1(>L%NzS+1WwGHZ1qS+ V+V+и и#ܸ /и3//V+*V+ик *901#533!!>325>54.#"#ƹ+5BP/Z}R/ #?fdTj<2J4*I;*  ?d}|o$FmFXh1d\R<#   )S+V+//V+901!!# #t/q!HP*?S+ V+ %V+V+V+ܸ*01#".54>32#.#"!!32>7RsTsy??ysHyV %=Y< q#FlI3YC*^b^.T|ЖS+[`'L:$8u`=!;R1HP7SS+7V+ V+ܸ$ܸ -ܸ92V+!V+2ܸ0132>54.54>32#.#"#".'*If>>_@!:_y~y_:>lTci7{yjo:^yy^:4kldvCR;U6/@&,9')A`GTW,4Z{G[aWH/:'&@_GIc;+Zb?+S+V+и/V+013#3#Ѳ) MS+V+ V+9/ܸ  /V+и 013#3#%3#| /Z??S+ V+ ܸи V+V+и/0132>53#"'3###-6?pW"" /";;dH)R}/ 0S+&V+V+V+A]A )9IYiy ] и/ܸ2("V+V+ V+ V+(01%32>54.+32#!!#"&'532>70S="#?Z6^c33`XBt0SvL) ''# -G32F-'m/W{MN{W.B (IvtZ/#S+V+#V+V+ии# A]A )9IYiy ]%//V+V+и и"01!#3!332#!732>54.+1^c33`XL0S<"#?Y7/mm/W{MN{W.-G32F-"S+#//# и / ܸ и и и ܺ 9$/ /!/ V+V+и к9014&'.#"##533!!>32#NL 6Kƹ+8JY5KzU."="5<$ %MwSUAS+V+ / // 9 9 9013#33 ##| ^و'q$&SN*'S+ V+%V+%ܸ01333#"&'5326?32673#".'g423=K1(-: 3?54.#!N.~>>wo=cJId=#S+$//$и/и ܸA]A )9IYiy ]ܸ и%/V+ V+V+и01!5!3!!!2#!!2>54.#jOP)W`33`W+M9""9M+q/W{MN{W.-G32F--gS+./)/.,и,/+ܸи)и/)ܸи/%V+V+V+и)01!67!2#!"!!327673# &!#qQh=Cˁ~^)hu]'8=hک 6+9xD իwg9+5 BR)GS+V+V+&V+V+ии"01!!323#"'&'##3367632#&'&#"` 9O1~wM خYvl=G~VCmh n[τ!3:rhlDFwd= 9S+V+ 9/// / V+013##### GڕϢԟpCW / 9S+V+9 //// V+01!####3 !fhoj hh/ ^S+//ܸи/ 9 9ܸк99/// //V+и и013#####!#3) ڕϢԟ̥CW3S+//ܸ и / 9 9 ܸии/ 99 ///// /V+и и01!####!#3!3 !fhojň֮g hhh3% ^)S+/и/A`]A]A]A]A0]A]99 A0 ]A ]A ]A ]A` ]A ] ܺ 9 9ܸܺ 9 99  ///V+V+и01776%!#5&'&'## ! @7vuur7{tGr{MP [ PM]/ǸS+/и/A]A]A0]и/9 A ]A ]A0 ] ܺ 9ܸи/ܺ 9 99  ///V+0176767!#5&'&#&#7!]vqepzVBx{BSÓZUTZ㓣8; \ ;8D #˸S+V+V+V+V+к999 9 9!9"9#9%/////"V+V+ ии/и/01#3!!#5&'&'##57 !@7vuurVb/Gr{MP [ PM!&3!$ӸS+V+V+V+V+к999 9!9"9#9$9&//////#V+V+и/ ии01#3!!#5&'&###5677!Ԯ_epzVBxOC+SIˢ\3TZ㓣8; \&8^)۸S+/ и /A]A]A]A]A0]A`]A]A]A]A]A`]A0]ܸܸ ܸии ////V+и01#$'&3367673)ۦvuurV{}}{7PMP  PMeo7/#?S+V+ V+V+ и и% //0133676767653#&'&'++;8AD;:+-ᇎ)jBA%#d#%ABj>be o ebP"-[S+./"/ܸ.и/ܸ"#и#/-и-//V+(V+-V+01#".546$3232>7'.#"&NuzzʟvN&a  a+H{{H RooQ _m==m_qqzƌMMzmHHmH+P )S+V+%V+V+0132>75.#"#".54>32 /NkDEkN/ /NmEElN/'DuuDDuuDJyW00WyJL}Z11Z}LCӔOOӄҔOO%S+/ V+ 90133>32.#"#%}M4FbE%?1$3)&DkJ' ;`E-PS+/V+90133>32.#"##uS(<'2=߾/na L?4n5S+/V+ V+ 9и01 7632.#"#%#3#3z>@&)/*2/~~HWZ !## AS+/V+ V+и/ 9и017632.#"#%#3#3=@&)/*2/>Zu~/VZ !$5/##PI !&2\9;I[N&R\sLGS+//и/ܸܸ /V+01!3!#;GS+//и/ܸܸ /V+01!53!#ӠE/pq  CI+ L+и /L+L+ и 013#53!!3#5hn3 CI+L+ и /L+L+и 013!!3###s/^s[؃6wS+//ܸи/ܸик9////V+ к 901!###### 33333:ċfVĎUfZBB=03wS+//ܸи/ܸик9////V+ к 901!###### 33333>HkkIFNPGZD@@r3MS+-=V+ V+A ]A  ) 9 I Y i y ] 9#A==]A ==)=9=I=Y=i=y====== ]O*0V+V+EV+ V+ܺ 9E'и'/(0*9*@01%2765!"567654&#"'476!2632#"'&'7327654&#"'7&'&'3d^>Uojb7.;.F[x|59 6#&)!%45,##_amn`Q-0xqhuԈzuñ:]P|Q QKLnQ 7 / ) ljXkG3RIS+>?V+ V+/V+?9A]A )9IYiy ]"?9A//]A //)/9/I/Y/i/y////// ]8 98/A 88)898I8Y8i8y8]A88]A88]A888]DܺH 9 V+A<V++V+61V+ 9ܸ"и13и3/64и4/A>ܺH16901632#"'&'7327654&#"'7&'&53327654"5354'&#"#!2όq<.F[x|59 6#&)!%45,##`cCASD.%)>9YխA/AZG S QKLnQ 7 / ) _pFKTG6D F 'L]>-cOS+/ /и/ܸи  ܺ 9// / 901!#33 ###it~?5qr>Zz3ES+/ /и/ܸи  ܺ 9// /01!#333 ###'NG>Ik3@Z+aS+/ /ܸи и / ܸи /// /99901 ####33~?sxx>pBUz3QS+//и/ܸииܸ / /// 901%##33533 ##hhGI3@(AS+V+ и / / V+к 90133 ###!.47675t~?qr>B5 %05C3?S+V+ и / /V+и015!333 ###5qNGIk@US+V+V+к 9 / ܸи // /V+01#3!33##p ywLZQ3US+ V+V+9/ܸи и/ // V+0133##!#3F\\wPk3DC sS+//и/ܸиܸ и ии// / V+V+ и 01#3!3#!.4767p L+! %0f3 OS+//ܸи/ܸ и //V+ V+ 01!#!#3!f3Z3DcC9S+-V+V+A&6FVfv ]A]9%"V+1V+01"327673#"'&'532654&/$'&7!2#^^~w[%0P*oG3/S+V+9///9013 3#*3xo*GQS+V+9///V+и к9901!#!.4767!3 3ePP %0m>*oG3GS+ V+ 9 ///V+ 9и 0135!3 3!!#ǍxZo.HKS+V+ 9 / // 9 9  901!## # 3 3H.l\Z`;)$3KS+ V+ 9 // / 9 9 9013 3 3 ## $x' {oHEYS+V+ V+ 9/ ܸ V+V+ иܸи 01!!5!!!33#<  y5k5Z8}3uS+ V+V+ 9 /ܸ  и /V+V+иии ܸ01!!33#!5#!5!\|UPk IS+V+ V+ к 9/ܸ/// V+012733### '&3ϦyxvP)Zc)nw?wE3aS+V+V+ 9 / ܸ к 9 // /V+90132733###"'&5'\\Q:3ZPkeuT/ kS+V+ V+V+ ии и/// V+  и /и/01673##$'&3.ÀdP2 +c nw?*w3gS+ V+V+V+ и ик9/// V+ 901%5#"'&533673#Q:bVY_uT/F25 CS+//и/ܸиܸ/// V+01"#363 #Ϧæ]vP)-)n;w3WS+//и/ܸ иܺ 9/// V+  901!4#"#36329Q:JZL3euT:+3OS+#V+#и/3и3/V+0V+,V+,и#017376!2!327673# '&#"'&5467&'&#"#\x2!LI̾A kBnXn u:b6yc#ڑsmdI`P?l%ķ>&? ٞ&FF+3OS+#V+#и/3и3/V+0V+,V+,и#017367632!327673#"'&'#"'&5467&'&#"#\0nr86T0O1RyARȋ >u:bb (J|;yc kUQlJ]6G;.P&? uF:CAIS+9V+#1V+9и/A11]A 11)191I1Y1i1y111111 ]1)ܺ51#9IиI/&.V+FV+BV+Bи9017376!2!3276733267#"&54767&'&#"'&5467&'&#"#\x2!LI̾A kBn8B J)53"!24`g: 7ܠ u:b6yc#ڑsmdI`P?l%&? ٞ&CFFAIS+9V+#1V+9и/A11]A 11)191I1Y1i1y111111 ]1)ܺ51#9IиI/&.V+FV+BV+Bи9017367632!3276733267#"&54767&'&'#"'&5467&'&#"#\0nr86T0O1Ry J)53"!24`g:!u:bb (J|;yc kUQlJ]6G;.P76763 !"$327I`̾A kBnXnxΙ6mdFI`P?l%wM+jP#P"-kS+.//.и/и/ ܸ#ܸ"и"/-и /(V+V+#V+"01>32#".=!.#"32>7\ JxclL+Iakp4nI)NoFGcB),NlB?jP/FjAFْb}[;Bˉ\NZ1(>L%NzS+1WwGa&*`P#&f &lKf"u&]C*&m0&8"/uS+ V+A]A )9IYiy ]  V+V+01 !5!#"$'332654#'iһpzb?ڤywd $N*}S+ V+A]A )9IYiy ]  V+V+и 01!5!#"&'332654#'l|iһepzbڤywx -&nH9$&n- &n)f$u&P$&tgR5& mN!/S+V+ V+ V+ V+01! '&7! ! 767!&! !&ʯojȪbd&07*͓͔L%R!S+V+V+ V+01 ! '&547632767!&#"!&9 ~cc~~cdXX< YR- mRe틙XrwN$'bL%'w`s$&'7&>)&y9N&5) &yfNu&4)^&yBN&^ &}fiu& V -S+V+9//V+013!!3#yՠkZF3 -S+V+9// V+01!3##!F\\k3q &fEu&K.HMS+// // V+к 9 9 9 01!3 3!!# #!fSHnl\_v;Z`$3MS+////V+9 и к 99013#533 33## $>8ʹ{P6o  I+//и/A&6FVfv ]A]ܸ ܸ/ L+L+01"3!"'&54763!3'5HR?Da^ys]q>TQ>19Tlyay+Zo!I+"/#/ܸܸ"и/A&6FVfv ]A]9 / L+L+014'&#"3276#5#"'&5476323-A>-0BtE9{(TiZQfTyqy{K[ӛâ4r/S+, V+A,,&,6,F,V,f,v,,,,,, ]A,,],ܸ#ܺ#9 V+ V+'*V+ ܺ*'901%27673!"'&54767&54763 4'&#"&# ma읗.7bjoU>^dnkXLJP]:uzuhqx0-Q`GR+˸S+V+ V+A&6FVfv ]A]9/ܺ9 -(V+ V+V+9  ܸи/и/(#017&'&5463 #4#"727&#$327653!"'&GA/AձY9>)%.DSACnȁ->]' F D6GTKFp_RZ&POCS+// и /ܸܸ// V+V+01!"'53276!#"&'5>/q>LB]#7#? i15-)AgGy+6b#$$P3KS+//и/ ܸܸ // V+V+01"'5325!#"&'56767!SE71#? i"[8G#!6b}x[s$(,5iS+,V+V+ /V+A//]A //)/9/I/Y/i/y////// ] / 9/ 9/A]A )9IYiy ]ܸии#и,%и&и*и3и7//V++V+*'V+к '*9и'#и%и+3и3/*4и4/01!33 !##5!%27654'&'!3#53#654'&'6#m@O)Mq8cYUpN1Jyo.nu6`b[wY/'+6`sjC_:\72;k92S+V+2V+ (V+и/и/A&6FVfv ]A]и/A((]A (()(9(I(Y(i(y(((((( ] 4/V+#01#".5476732>54.'.5)!;U81]UN_4.D--D/-?%2@$/SH=.OT`@Dz[6(PxP4  +>2 0@$;R>1$IZrLq!+CS+3V+V+"=V+A]A )9IYiy ]A33&363F3V3f3v333333 ]A33]3ܸܺ,9A==]A ==)=9=I=Y=i=y====== ]"E8'V+014>5<./#4>#".32>54.q;ZgZ;-7"7S`S7D{ii~F 4EL?)/Qm>DmL)&:F?/YjTMK-*"Ph"-/G61PMShZaxC:r9,B<V+ܺ-94A>>]A >>)>9>I>Y>i>y>>>>>> ]#F9(V+ V+0174>=4&#"#54>32#".32>54.9VeV9KL!6'Fx\;XfX;V+U V+]V+A&6FVfv ]A]6>9AUU&U6UFUVUfUvUUUUUU ]AUU]H U9A]]]A ]])]9]I]Y]i]y]]]]]] ]&/30V+MRV+XV+Rи/36и6/MCиC/01#".=.#"3&'.'.#!532.'.54>32>32"32>54.R5wu4 -HfF:nW5Ii.fge-jj:3A8`1QF?+U(kw?A|tR_CLgP}<VzM$*RxoĒUZ` D[eU8;ma{uT(&%#%"*  ^ŀrП^)CT*4W>#R4d]\f6jS+QS+V+V+'9'/&ܸ- V+!V+ ܸ&012#".5332>54.#"#4>Aa[+DuWgi5"?X6C_=0Q=0jxKoI$.Ok<LV++ܸܺ"9A>>]A >>)>9>I>Y>i>y>>>>>> ]L#V+CV+90V+0ܸ&ܸ03и3/97и7/J014>32#".5332>54.#"'32>54.#" !:]ZPz[<%)CW.5q\;Bzwn4BuV27[w@%  7*XH.$AX4/H4"~SZXF+"8JPR#@v\=-SzR_s?>}}!BcAKhA=gN3U<"*698Lf2HTyS+RV+.DV+:V+A::&:6:F:V:f:v:::::: ]A::] :9:к.9:!и!/:$и$/:8и8/ADD]A DD)D9DIDYDiDyDDDDDD ]LиL/ARR&R6RFRVRfRvRRRRRR ]ARR].V?V+OV+I V+)3V+ I9$3)901".54&>7#".54>32>?>32"32>54.%267.#"sb, S?MjA'LoH(ep6FW6in81mj9aF(:dOBfD##CdAEC<=KD#NlTiZ/'91Qh6AqS0>-l&N+2&DuZ^N)LjA;r\8-QqDCqS/UZ@ITGITDe1CS+5 V+?V+$V+A&6FVfv ]A]?9)A55&565F5V5f5v555555 ]A55]E:V+2V+и#и#/:$и$/2,и,/01#".54>32>32#52>54&#""32>54.(5wu24uNkSLeOqEMd:pX6W{O&*RyNOxQ)-SwoĒUSmnșZ"=U3-T@&G{ΐL:k[JrB\f64d]\f6K~)S+$V+V+A$$&$6$F$V$f$v$$$$$$ ]A$$])ܸ+// V+)ܸ01".54>32#52>54.#"3cr>H˃DžD=o^!UJ36`OO`58PZ"$IvyΗVVucZ+]gbe45f`i\*;S;ոS+V+V+A]A )9IYiy ]ии/ 96ܸ"и"/=V+;V+1'V+ '19ܸ',и,/1/и//012#".5332654.#"'32>54.#x`('CX0@_>3nzoc.@gI{}.J^/%   7*XH.$@X4CkBHuY; ;Wn=Zp@>|}R[0{C`<aD#JMxS+WV+(3V+?V+KV+A33]A 33)393I3Y3i3y333333 ]AAWW&W6WFWVWfWvWWWWWW ]AWW](zf/ TV+spV+.-V+ и #иT8и8/TFиF/01'.54>323>323>32#52>54.#"#54.#"#4.'&3&'.'.#!532kw?*bxEfK2 $TfcM!*RZm\(AmQ0R="6Q7=Q4  32#".54>.#"3267Xy)9\BDZ5=mZmb- :]Ztk3JzW">^@;bF&v7(gDqQ-%?R-Y`2:nf+?{nQ0Hnx7S?hJ)+WWN4HٸS+I/D/ADD]A DD)D9DIDYDiDyDDDDDD ] и /D(ܺ D(9I4и4/:ܸи/:и/(J?-V+V+#5V+ܺ 995#9014632326767#"&'&'>32#".5%"32>54.N13(VctFFw+2)$0*yNO{+2'>Oa:]q@9txZa?%9cJ- DlMGjG#*MlQB 6614'/nrM+OnS/UuFIi?4aTT{P'JXS+ANV+45V+ %V+4ܺ% 9 *ܸAAA&A6AFAVAfAvAAAAAA ]AAA]NHܸ Z!/$/I/-V+!%ܸ-<иS01>32>767&35152>54&#"#4.#"3".54>32V+T]m\(#&L# (+%].BB=.0^K/kn9O5#7M48ZA#0>B>[N*bxgL#nTsEPWKt\D  ,^g-Mgt|;;{tgN-+_jRzW7! 0x͝rȕVEtS?EɸS+V+1V+ܸ ܺ 9A11]A 11)191I1Y1i1y111111 ];и;/;/V+,"V+",9ܸ"%и%/"'и'/,*и*/01#"&5332>54.#"'32>54.'.53&GhB@wZ65"&##".532>54&'&'77>7>328szڪ DlKOoD R98Z@$+3)9Q33P9 .!)i/3,k66^O@ `uAK^5.Ng9Y  32#52>54&#"#4.'"3".=4>7>5632T,W_m[(BoO0R="kn=S7"8O68V:,9<<[K 54.53>sf~c(>aD?eG%(454(+@J@+exBAxjMSV,'KkE6TG<aVQ\o`S'Ocw˸S+FV+s<V+2iV+(V+Ass&s6sFsVsfsvssssss ]Ass]<s9< и /2и/Aii]A ii)i9iIiYiiiyiiiiii ]i29A((]A (()(9(I(Y(i(y(((((( ]-i29A<s9AFF&F6FFFVFfFvFFFFFF ]AFF]P9sUиU/i_и_/d9yK#V+nV+Z7V+014>7.54>32#"$&%4.'#".54>732>32>54.'>54.#"`K~) (Hb;:_C%(ΑO^^6aO")F^4;bH('V]2KvvËM +)#,-$)) ))$--#)+!$-:&3O46P5$8-#ml\r !*4 5Q65O3$9,$q`uϚZZ2?/(#$).=|1=-*$#(.?GSlaS+UKV+V+5V+&V+3ܸKMиM/KOиO/AUU&U6UFUVUfUvUUUUUU ]AUU]UPиP/URиR/cV+:V+OFV+FO9 и!ܸ:,и,/FX0123>32#".5332>54.#"#54.#"#".5476?32>7>Xh9!GuYiI`슊ٗO;m_^~J(F72B(#:,(6$ &7M59S6'" )Gk7bRTb5;nbws84vfQ!$TeRyP(#>Ver;CnN+0=B@*J8 8N.F$"3>"=V46`H*DSSgiS+T V+LV+/.V+^V+A&6FVfv ]A]^99ܸ&ܺ! &9ALL]A LL)L9LILYLiLyLLLLLL ]ATT&T6TFTVTfTvTTTTTT ]ATT]i/+V+cV+YV+и!ܸ+4ܸAиA/cOиO/01#".54>32>32# $5332>54.#"'32>54&#"32>54.#"F3c^[a3/ben/)kOxZ<$"?X75kU5I*]jz^&+QrG%  62ZC(mw6S:3S<6O42N44R9Zl;5.#"#>321kzpo7"EiGDeB!3ZHplñZz*ZxF5r}LxS,DlNKwR,pb.$EM%aS+@V+24V+#V+2ܸ(A@@&@6@F@V@f@v@@@@@@ ]A@@]@[ܸcO/-V+\YV+#"V+ и-;01.'.54>323>32#52>54.#"#4.'"3&'.'.#!5!2*Jkw?*bxg}G #Nao](AmQ0S=" =W75R74M68Y> Ii.fge-ji93A8`1QF?*O$!_֐pĐS?mTLqEHguJ2[QU{P'1]U;{tgM-3c]|U(&%#%"*  >Sq+sS+,/ /,)и)/ܸи/  ܸ "к#) 9 - /*/V+&V+ܺ#&90132>753#".5332>5#"&'3!,]³BY7*PuKZxF5r}LxS,#IqO+;=@SS+O V+56V++V+ и/ 659AOO&O6OFOVOfOvOOOOOO ]AOO]O@и@/+FиUAV+;V+'JV+@ܺ @9к*J'9;0и0/@5014>323>32#".54>3254.#"#4.#"2>=.#"F!?Z89K-1P3p}xt8'CZfm5m- & ( ' !&;@iJ) JnI$$Js8^O",CS'&RE,"N|ZqʘXPgbrP1F1

32>32#67>54&#"4.#">%WjaN ,Miw@7GX5\[. #rt7[A%f*<%6K/Ia9 Lh=8R]&>bM:+ /"8dSL~-6**3,tDy)MnDT2%)Ib9Q 2GDSCVS+ V+A,V+A  & 6 F V f v ]A ]AA,,]A ,,),9,I,Y,i,y,,,,,, ]KܺFK9AX6/PV+%V+%"и"/F%9014676732>54.#"#532>54.'.53#".D*& $1_\KoJ$Cds/  AAA2H?h1Qj9Si<(7$$5) &9P8!#7DO*2>7.#"c/&Ab[rl4KzkB`?@dGDgD"&HiE1*?{nQ0Kru632#.'&>32>32#4.#"#4&'">54.#" 7HZ7Fd=3A"OeVG=5& !C_3U23l:5&+[dIK-vM`U(#8F" E9%,H2YhiVdG'1X|9SYUiS+V+<=V+V+ܺ&9&/0и1к6=<9DкE9JкP9V9&`ܸk V+?6V+e!V++[V+ ܸ?<01%".'#".5332>5#".54>324.##32>3"3%.#"32>Y-C3&.izo\(4]HGb>/=Q9B_?#B^;9Q=/"DfEDjA(3B, ,2C57E2+8G51"!) (/6I)2ZxF5r}LxS,.Ng9?7$/RrDCnN*#5=Qa5 o%Vhx1)!+- /- 44'.88.'47Xt"8ǸS+9/-/9 и /#ܸи#и/# и /# и /A--]A --)-9-I-Y-i-y------ ]-ܸ#7и7/:!/(V+2V+ 2901>?>32#".5332>54.#"(em6FW6ii4-isa+:dOBcB Aa@9aF($E".k62&DuZ^NNl<;w`<2X{I=lQ.)LjA-CAKS+)4V+V+VEV+4и/A))&)6)F)V)f)v)))))) ]A))])и/AEE]A EE)E9EIEYEiEyEEEEEE ]A&6FVfv ]A]9V9/Q/yV+y ܸQHܸ$и$/yd01".532654.#"'.'.#"&'.54>32>54&#"'>3232>54&'&'7#".'.'IV- !3(  4`J.#"#  |  >[;No+8Wl;&$*,>Q;}N8W; +W|QQ) (Hc<6$)!BcS!3> &$ bRwK"7'  W@##K>(3232>76.'.'&'77>.'.'&'7676.'.67'&'">54.ѓOQm8eM.RUIpL-E4$ ?T"$I)\l 8-.=-IR 1'(  *"/ *9G)M<&=N]20T4 Pev+A/:jQ/*%qj#GjG]rUx̔S&0;_J5  +0-++  #2! ABD"J! 49B*/ )xQ') Vju8;P3323"$'#>54.#"2IU>fH'KgeL,PmAXRA:-QmADvW27Yq:7nX7i'`sMfp;4loNs`',-! EtaMN`sBFnK('KlUS(ŸS+)//) и /A]A )9IYiy ]ܺ 9 ܺ$ 9* V+'$V+V+ ܸ и /"и"/012#"&5332>54.#"'!5!=o2A}t HtTJrM(/UwI45cCoKa{FK^5+MkA@cD"~ᓃ>RRS+10V+&NV+019/ ܸܸ&и/!0&9ANN]A NN)N9NINYNiNyNNNNNN ]N9и9/&T4+V+ V+I>V+!>I9+1ܸ>AиA/>CиC/IFиF/01.54>;#"#".5332>54.#"'32>54.LjB$MxTkZ1?$6R_)SrF;[>@_>3nzoc.y9cI*/K]/%    '*XH.+Lj}.Zq=ZxF>|}.Ng9Cc?6U<1QA1T):IոS+J//ܸиJи/и(и*A**&*6*F*V*f*v****** ]A**]4и;и*C/ V+#@V+V+V+ии5иH01#3##".54>;5#".54>3232>=#"4.#";&\sM_5@jJJj@:fPqS 3A!=V60ZE*5O4^g%?U0FQ|L(PyR`K M~^UzN%QJF4F+&HhBR 'Fz?iK)[X2E*ISy=JW'S+>&V+<5V+PV+<и<ܸܸ.A>>&>6>F>V>f>v>>>>>> ]A>>]DAPP]A PP)P9PIPYPiPyPPPPPP ]<VиWиYV+74V+KV+.EV+.ииKCиEU012+;#".=#".54>;54.+532;#2>54.'# QtT/-QnKq9Q3X_j[(LnO-3YxH_.A(bjO~W/=HzWaT`yEjq;AwgF)GpkkrJ*$9[A"6f\"+JrjkpG)C^;"Zx kT#O&#TkjP.s SS+ // и/ܸии ܸ V+V+ V+0173#3#3#1SS+ V+ и V+V+V+ V+и/01!'!!!!!!!#XTux}y?RH(S+ V+A]A )9IYiy ]" 9"/A""]A "")"9"I"Y"i"y"""""" ]ܸ*V+%V+V+ 9ܸ(014632#"&5332654&+532654&#"RjZZۦ躪}avgkriwq^Ƨj)sf{l^TLCPT[lXVfk;+S+V+и/V+01#3#53;*CT / OS+ //ܸ и/ܸ ////9901!##33 ߽/8! ǸS+/ /и/A&6FVfv ]A]A ]A  ) 9 I Y i y ] ܸV+ V+01"32654$' # 54^^RK0L:LS+ V+V+A  & 6 F V f v ]A ]ܸ//V+01%5>54'&#".54$3  cm܉w3:Lr~J0pԵ9  0S+1/ /1и/A&6FVfv ]A]#и#/A ]A  ) 9 I Y i y ] ,ܸ0и0/#09#09,2$//V+)V+$9$901327674'&#">'#"$54767'76763 HB%9+;=kZA#/49(pJ~.=2\wMMOA8 |TO01r526~_8H}4?n5y>.K&/;S+$6V+A66]A 66)696I6Y6i6y666666 ]$=///!/'V+9!9ܸи/93ܸ+и+/01"'&'#"&'&'&'!&'&#"#6$32>323276?32654&#"2o>6@΁wB= )LO,*vSFq)KYLvq+Q-Ucna_WtGQ[1U^|z^tH5SC۸׾;!NyS+//и/ A  & 6 F V f v ]A ]ܸ V+01*&74'&#"".732"0L7*" ^ @;!2S+//A]A )9IYiy ]ܸи/ A  & 6 F V f v ]A ]V+01!">325>3!9#(3"(.+*/ S+//A]A )9IYiy ]и/ܸиܸ/V+ V+012654'&+'##!2,fwS-Ja{OPDRj;)@\Q/$D`z/ 'AS+'V+ и') //'V+ V+ 901#"3##"#5676?>7.54763!4J-SwfY)I  " ??GPO{D6);jR$M>,3=BS5&z`D$/ 'AS+ V+%и )/&/ V+$V+$901";!"'&5467./&'&'53;3TfwS-J{OPG?? "  I)YRj;)6$D`z&5SB=3,>M$MZS+V+A]A )9IYiy ]V+ V+  и / 901!27654'&#!5!'#!MR4`Z/=*TR(0D%#4gS-*sS+ //A]A )9IYiy ] и/ܺ9и/ܸии!V+ V+  и / и/и/ܸи/01!27654'&#!5!'#!5353R4`Z/=*TR(0D%#4gS-3Sz&S+!V+ A!!]A !!)!9!I!Y!i!y!!!!!! ]!и/(V+$V+V+$и/ 901##!5!2654&#!5!27654&#!5bO$=?$FVST7kPm2K@4YqN,$323267#"'&'#"&5467HC@jJ$MF";Q, ]Wd*xtTS  B'Xjk4vg "I7@z  A;6;n33lJ_/.3Laiu : ;ŸS+?67654&327673#"'&54&#"5>32>32D?jJ#NE#;Q,]Wd*wsTS B'Xjkc4vg "I7@ B;6;n43l_/.4K`jt(3$S+%/"/и/%и/" и /"ܸA&6FVfv ]A]&/V+ V+и/01#"&5463253#"&"32654&r+~VT~+t< G7fzzffzz2=F⮮F:q< \:j4RS+S//S7и7/и/7ܸи/A]A )9IYiy ]и/+и+/-79H79NܸT )V+D:V+6V+ и/696 и /:и/)0иDKиRиR/01.#"32676767'>54&#"#67632>32!32673#"'&'#"&54767HvUV{x"+mN"9[="]'# E%#OXG*G{vEw^D9*~OS/*mc\aS-2g6iPJ;WzV6\~osso6  !E<@$% "2)&=@*O;!#16<;E9kuQJ9x!675VL{`>( TS+//и/ܸи/A]A )9IYiy ]ܸи/ / V+V+9013>32#"'&'#4&#"326T|*tEW;$(vgdX2hg79þ*6axkC}( S+//и/и/ A  & 6 F V f v ]A ]ܸи/9/V+V+012654&#"3#5#"&54632XsvW`xg",{s-zOWz6jF?ֱ3$3S+V+$и$/V+!V+V+01!327673#"&54632&'&#"& fkd<"~8#:V.:ǠQ5zXxF9M5ssB&3*g!9 ϺLS2\b3$;S+V+$и$/&!V+V+V+01&'&5!.#"#>767632#"&3267r' -fld;"}8#:V.:ǡQ4{Xw2:M4stB'2*g 9 κLT1]b:(S+"V+A""&"6"F"V"f"v"""""" ]A""]" ܸ%V+V+V+ 901#"&5467.54632#.#";#"3267|ZL@@vy YETILQJTPbkC^glveKgRHXgMC;6/9=HL:(S+ V+ "ܸA]A )9IYiy ] *V+%V+V+ 9014632#"&5332654&+532654&#":|ZK@?vy YDTILQJTQakB_glveKgRHXgMC;6/9=HL+-S+.//ܸи/.и/$A$$&$6$F$V$f$v$$$$$$ ]A$$]+и/ V+ V+'V+  0153#"&'33276'#"&54632"327654&%%v+O{ +]-&lY{ZB2hX8t0`MTnv4+h=:9ʿq~Dm|G]^+S+V+и/V+01#3#53[ 7S+V+ // /990133 ##[{H3k{C$b^]&eS+$V+V+V+$и/ 9(//%/!V+ и!и/01367632>32#4&#"#4'&#"#^~.$@P[7+sG7L7KlOIvl9+,2>:n=#4'&#"#3>32#"&'V#"Z-5' y6yJ8 -} BcF*G /&PKrlC:p>sS)F* ǸS+//A]A )9IYiy ]и/A&6FVfv ]A] ܸ V+V+014'&#"3267#"&54632i"6ukks^¤NjCi~zyճ)}S+V+A]A )9IYiy ]V+ V+ܸ013327654&#"#>32#"&)| QYz5"agP]|—F]wMrraTڤ}*-+S+//////ܸ 01".74'&#"&74632&  "6uk''¤1Ci~*TS+ V+A  & 6 F V f v ]A ] V+ и  и /ܸ и/01#"&5>3265>($ks^)QyT"S+#//A]A )9IYiy ]#"и"/ ܸи/ и/" 9ܸи$!/V+ V+  9014'&#"326367632#"'&'#o112Yw|&.@XRmV:#)F[A~GmX>v e4+ƸjD&4|r[S+V+ܸи ии///V+и0133#3:7#"&5#53wyy# 0Z@ggh( e\Ih[US+/ /и/ܸ  ܸ  и / 9 / /V+01327653#7#"'&5"]0y%Ii; ;%Dx?pup+3/-&%<9Zk-*m,*_:;f  GS+V+9/ /// 9 9 901&'&#56723#b"!K! ؂:j  #J,?J.)S+*//*и/A]A )9IYiy ] ܺ 9 9и/&A&&&&6&F&V&f&v&&&&&& ]A&&] + V+V+$V+01!!&'&'%5%67654'&'&'&'&# =i62^abdZ-s66  3>?i_^_fnqieWXUd9*)kHL [S+//////99 9999016723367&'&' #&'&#4]*ޓ-##(=$':! Su3r 4*n ` ^DW+S+V+и/V+0173#3#^9 aDM7S+V+и//// V+0173>32.#"#aztL  `h<&n}QK[/<US+/ /и/ܸ  ܸ  и / 9 / /V+017327653#7#"'&5"]0y%Ii; <;%Dx?pup+3/-&%<9Zk-*m,*_:;f ' FGS+V+9// // 9 9 901&'&#56723#b"!K! ؂w:j  #J,?y'*F#S+$//A]A )9IYiy ]$и/ܸܸ и /"и%"/ V+V+!901676'4'&'&#%"'&'##y0..*)=t1200WXWTU=::"YTniT(STinTYmlss7 'F[S+//////99 99990176723367&'&' #&'&#4]*ޓ-##(=$':!< Su3r 4*n ` 5G9AS+B/2/AܸиAи2и/2A9B#и#/&ܸ2.и./A4//7>V+:V+*ܸ и /*95>7901!327673#"'#7#"'&5332767&5473632&'&#"G69HT0O1RyARx#4gS-0D ~r) (J|QlJCuNb]6G;.P\6=*TR9R4`+97>]PPhkuF.;S+32#"'&'#&#"#676324&#"326 8 iwG";`zT29#-b 9p{&G’©#&`MQ;#M./O2\ҩ޶ї^0<S+=/4/и/4и/4$ܸи$"и"/4&и&/=,и,/:A::&:6:F:V:f:v:::::: ]A::]$>/1)V+V+ V+/7V+  и /и/01&'&#"#6763253327673#"/#5#"54322654&#"0=#-b 9p 8 iwG"?o{W}zK" ./O2\s#&`scX-W5ʬ 5S+1V+к"19"/!ܸ и /!ии/0ܸ#и"/и"3и04и7//!/(V+-%V+ V+(и/-/и//0и 201632.#"3#327673#"'&'#&#"#67632#5356?$ R 8 iwG" #-b 9p v\U #&`*./O2\pUI1@S+A/2/Aи/:ܸи/A22]A 22)292I2Y2i2y222222 ]2 ܸ2 и /:и/: и /"и B!/*V+6V+/'V+> V+ >9*и//1и1/01367632#"'&'327673#"'#5&'&#"#676324'&#"326 6@[{tyR0;8 iwG #-b 9p%FE%%F~*I(<_5I#&`./O2\\d|W G.uS+.V+и/.9и./ V+'V+,$V+и/'и/,.и./013>32.#"327673#"'#&'&#"#67632k 8 iwG #-b 9p/6r #&`( ./O2\  +SS+V+ܸи#/V+!V+и/!#и#/01&327673#"'#&'&#"#676325476218 iwG #-b 9p&? k#\#&`' ./O2\|u:b Z6ɸS+4V+49/ܸии/иии#и6ܸ$и4+и+/2и63и8/ /V+ +V+0(V++и/02и2/3и50133#327673#"'3267#"&5&'&#"#676325#53 8 iwG"&1 C'~Z#-b 9pZՓ#&`8  g? ./O2\.<S+92V+V+V+ 29ик299$к02990/.и./04и0;ܸ6и>//(/41V+149(9 (91и/1и/(9-(947и19к;(901367673#4'&#"#3267#"/#7&5#5333#@3D_nA-1 1 C'~-9_Q!- wYQv7X9I  @5œ+ՓL(1{S+2/1/и2 и /)ܸи  и /1ܸи/и/ 'и'/3-!V+V+)V+014'&'47676767&'&'&'&7676'- "XX""i 23KL23  65VW34 i \\ gxMNNMx1QHH89!!!!98HHQEGF<:%%%%:S+//A]A )9IYiy ] ܺ 9и/A&6FVfv ]A]9V+ V+901#3"&54632"&54632,L3JJ34JJ3JJ34JJ!#J44JJ44JpJ44JJ44JO+>S+//и/ A  & 6 F V f v ]A ] 9A]A )9IYiy ]ܺ9V+ V+9 9013#"&54632"&546324JJ43JJ4JJ43JJ!#J44JJ44JpJ44JJ44JBIJS+/V+01!!B);:):BIJS+/V+01!57!:;*IB:BIJS+/V+01!!BB;\;*BIJS+/V+01!'1!];Bs;BJ S+////01 775I;;;:;B:J S+/// /01 /A;;;A::;DH5S+V+и/////9013>32.#"#DU R5  DIZ@]N_X9=&$cUPRGI&Dc?&%bAv%&Eb$&%b<v%&Eb/&%q--v%&EqZ3qu&v;3&vc*&'b8&Gb4c&'bG8&Gbc&'qD8&Gqc&'8u&G2yc&'O`8i&GO&('qzCH&H'qC*&('q!vxH&H'qv&(OkHbI&HO&(eHI&He38&('a\zH&H'az.&)b[#&Ib~c&*q]=;M&Jq/&+b4&Kb//&+b&Kb/&+jJ&Kj39=/&+z =&Kz /&+a&Ka&,eZ&Le';h&,'j9v,&&jv  N&.vV?&Nv N&.bN&NbN&.qe/&Nq-K&/b7Q&ObK&/'b7q.!&O'bq!K&/q./5&Oq-{K&/O&OO'&0vI%&Pv&0b/%&Pb&0b %G&Pb*&1b*&Qb*&1bI&Qb*&1q/I&Qq-*&1OvI&QOP&2'e|v;!&R'evP&2'eQjp;!&R'ejP&2'q)C$8;!&R'qC$P&2'q7v0;!&R'qv1&3vgSvU%&Sv&3bGyvU%&Sb x)&5bz&Ubx&5bG&Ubx&5'q%bJ.&U&q5bx&5q/G&Uq-c&6b_mB&Vb c&6bXBK&Vbc&6'v]bB&V'vb:c&6'P_mbeB&V'Pb-c&6'boberB&V'bb!&7b5T &Wb!&7b Z&Wb!/&7q0-bZ&Wq!u&7O`<Z&WO/&8jI&Xj/&8eI&Xe]/&8OgI&XO/b&8'eRv&X'ev/&8'qjo&X'qj46&9eq9 &Ye46&9b\ /&Yb%qH&:Cj&ZC %qf&:v&Zv %q&:jv8&Zj%q&:br<&Zb%q&:b|/&Zb|*4&;bk. &[b*4&;j_# &[j*G&<bd4I&\b/C&=Oe4&]O/&=b54I&]b//&=q,-4/I&]q-/&Kq-&Wj1J&ZcI$&\cRGZ;IS+ 8V+#V+G@V+и/A  & 6 F V f v ]A ]2и2/A@@]A @@)@9@I@Y@i@y@@@@@@ ]#KD/'5V+V+'и/'*и*/5.и./01%276=67654&#"#>323267#"'&'#"&5467526544_Y!h2mb1SrB> z;! vu% *,&]* 7|E4JJ4V{{u,I /gNZ,-\SL*SƛHH" B#@HjSSJ44JS{VV{ &Abh=&$bYRGI&Db=J&$RG&D}=&$'Of4vRG&D'Ov!=&$'OK.CGy&D'OC=&$'Oh?RG&D'O}_=,&$'OPDesoRG&D'Oe="&$'OPDbqRG&D'Ob=+&$'a{1vMRG&D'avn=R&$'af\CgtRG&D'aC#=i&$'af6RGK&D'a=\&$'af\eRG&D'ae&=8&$'af\bqRG&D'ab&(bHI&Hbu&(!H &Hv!&(edH&He&('Orov7HL&H'Ov-&('OtCfy&H'OC&('OT-H&H'O?f&('OaNeH&H'Oe-&('OaObH&H'Obu&,r! &]&,bC&LbP&2b;!N&RbP&2aI;!&RsP&2'O|vC4;p&R'OvQP.&2'OCP!&R'OCP;&2'Ol;!&R'OoPb&2'OWe;!&R'Oe%P:&2'O\b;!&R'ObP^&Vv;;&WvPq&VC;;&WCP&VaS;;&WP\&Ve;;&WeP&Vb;;p&Wb/&8bI&Xb/u&81! &Xt-&]vOh&^v <&]C^h&^C.g&]Wh&^}o+&]enh&^e&]bhp&^b*G&<C9I&\C*G&<b_I&\bI*GO&<I&\Cg*G &<ePI&\eZD&*CZD&*{ZD&*PZD&*]ZD&*QZD&*^Z&*RZ&*_[{&C @[{&{ @-&P B&] &Q !&^ oq5&R 6oq5&_ 6wD&.C\wD&.{\wD&.PwD&.]wD&.QwD&.^A&ClA&{l&P&]3&Q&^;o+F&0CV;o+F&0{V;o+F&0P;o+F&0];o+F&0Q;o+F&0^;o+&0R;o+&0_&Cl&{l4&PI&]3&Q(&^ox5&Rbox5&_b 0&2C 0&2{A0&2P90&2]=0&2Q=0&2^#&2R#&2_&Cl&{l&P&]3&Q&^o5&Rbo5&_bouD&8CouD&8{ouD&8PouD&8]ouD&8QouD&8^5&Cl5&{l&P&]3&Q&^+0&>C+0&>{+0&>P+0&>]+0&>Q+0&>^+&>R+&>_&{l`&]3?&^o5&_bm0&BC*m0&B{*m0&BP^m0&B]Vm0&BQZm0&B^Zm&BRYm&B_YV&C.lV&{.l &P. &].3&Q.&^.o L5&R.bo L5&_.bZ4&*oZ4&*zw4&.oiw4&.zh;o+6&0oc;o+6&0zb  &2o  &2zou4&8oou4&8z+ &>o+ &>zm &Bo7m &Bz6ZD&*'CB ZD&*'{B ZD&*'PB ZD&*']B ZD&*'QB ZD&*'^B Z&*'RB Z&*'_B [&C& @2[&{& @2 R&P' 2H g&]' 2] 9&Q' 2/ F&^' 2<o 5&R' 62o 5&_' 62;+F&0'CVB;+F&0'{VB;+F&0'PB;+F&0']B;+F&0'QB;+F&0'^B;+&0'RB;+&0'_B =&C'l23 =&{'l23 &P'2 &]'32 &Q'2 &^'2o 35&R'b2 )o 35&_'b2 )m0&B'C*Bm0&B'{*Bm0&B'P^Bm0&B']VBm0&B'QZBm0&B'^ZBm&B'RYBm&B'_YB &C'.l2 &{'.l2 M&P'.2 C b&]'.32 X 4&Q'.2 * A&^'.2 7o 5&R'.b2 o 5&_'.b2 Z&*Z&*q8Z4&*'oB Z=&*B Z4&*'zB Z&*D5Z&*'D5B ;!& E;& qf .1&o /1&z `& 2V3 'I+ L+и / /01>54&'#53,.WUV2U7 f  5+8+// / /01;727#"'&'&'&5N5!-h@''2G 3 'I+ L+и / /01>54&'#53,.WUV2U7 f  I+ L+ ܸ01&'&#"#>328vm6cM( A!;;"@w>`=_I+//ܸܸи/ܸи/L+ L+ииܸ013#%3#%&'&#"#>32F8vm6cM( HA!;;"@w>`;+6&0'ocB;+=&0B;+6&0'zbB;o+&0DU;+&0'DLB./&oZ//&zZ.p&oZ/p&zZ&2 -I+ L+// / 901>54&'#53%#3,.WUVBm׳2U7 f  -I+ L+// / 901>54&'#53%3#,.WUVnֲ2U7 f o5 'I+ L+ /L+ܸ01>4&'#53&'&#"#>32P,.CUW18vm6cM( 4U  8A!;;"@w>`G&2EN0&2q1&2m?&2nT&2D=&2EY!&WEn&q .&oZ/&zZ -I+L+///901.=3##33VUW-,m׳ f 7U< -I+L+///901.=3#3#3VUW-,n f 7UUoo5 1I+L+ 9/L+ܸ01.=3#47&'&#"#>32 WUC.,t8vm6cM(   UA!;;"@w>`+&>+ &>q,+&>m%+&>n%ouD&:CouD&:{+&>D)+&>Ee)-!&E)-&qf .&oZ/&z\&{l qI+ / / и/ܸ ܸܺ9 9L+иик9 01#3%#3'#3Еnֲt aI+ / /ܸܸ и/ܺ 9 9/L+ик 9013#%3#3#ꕕ0nto.rI+//01#3rm׳m &B'o7Bm)&BBm &B'z6Bm&BDm&B'DB.#&oZ/#&zZ.D&o.Z/D&z.Z^/&.2%/sI+//013#no3 'I+L+и//01.=3#3VUW-, f 7UUK++.+01!!U UK++.+01!!U UK++.+01!!U v@!_++N/M10!!{ @ !x++N/M10!!++.+01!!;++/ /и/ܸ ܸ////01!#3#3aJ.8++.+.+01!!!! @@vpvZ -@ d# d4 lH+NM54&'#5379mjl jE ɀ 'S+ V+и  //0167654&'#53Em`v U-* w 'S+V+и//01.=3#ljm97  Ej NtC@$ d##d4 d4 !?3++NM<'#53Em]y=8mY| U-* t_ yLsNt WS+//и/ܸиܸ и/ /V+и01.=3#.=3#$tbmKPsbmKw*9`^w*9`P +@  zy / y G v<<?M<@<:D<+'"- %  ++++++++++++++++++++++++]$32654&#"&632#"&532654&#"#"&54633#32654&#"&632#"&5qOPppPOqpPOqqOPpD6opqOPppPOqqqOPppPPpqOOqpP@ZaqqOPppP   #/3?KWc?+=IB+C7B+$B+ B+B+UaB+[OB+A]A )9IYiy ]A]A )9IYiy ]ACC&C6CFCVCfCvCCCCCC ]ACC]C!A$$&$6$F$V$f$v$$$$$$ ]A$$]C*и*/1I[93I[9A==&=6=F=V=f=v====== ]A==]AOO]A OO)O9OIOYOiOyOOOOOO ]Aaa]A aa)a9aIaYaiayaaaaaa ][e2/0/B+@:B+ B+4FB+ии'и -иLиRи Xи^01%2654&#"2#"&5462654&#"%#"&546323#2654&#"2#"&5462654&#"2#"&546PppPOqqOOqqOPppopPppPOqqOPppPOqqOqOPppPOqqOOqpPPpqOPppPOqqOPppPOqV++//01 #VM++////01 #!#V<MM ++///// /01 #!#!#V<<MMMW++//01#M++////01###MM ++///// /01#####\MMM}sI+///901#'#̤b!J@))@ !ce++N7>3 ʎse}q("I.FQ2yA&0)^;I+///901 # #Ûv:>,I++L+ L+L++9 9 +99+9"+9%+9.///$/&/999 9 9999999"9%9(9+9017''7'757''7'75!7''7'75p(ڇcf(@(ڇcf((ڇcf(LoGGGGoN|LoGGGGoNLoGGGGoNUK++.+01!!U C@!(H7!H7++/3/3/ %I+/L+к901##"'5W߆>8"")G++//и/ ܸ ܸ //.+ 01#5! ###r}@*HՓIttLs'* '++ .+  .+ .+01!&5476)#3*H*Ó'#tt9r') ++ .+ .+ .+01! !73#r*HttN9WI+ L+ 9///999 9 9017''7'75(ڇcf(9LoGGGGoN!CI+ L+ܸи и/и/L+01&'&=3##534mFvHk 2*P $'I+#L+L+01$'&! 5>7>3 ! 76%# '&%ʎse}q("6!!se}qI.FQ2yA&0)^;؟.FQ2yA&0)^;NI+ L+ 9к 9 ///999 9 999999017''7'757''7'75(ڇcf(t(ڇcf(9LoGGGGoNLoGGGGoNB߸I+//ܸA]A )9IYiy ]9 и /A&6FVfv ]A] 9//L+ L+013#4&#"3264&#"326ooyVUyyUVyyUVyyVUyH6UyxVUyyUyyUUyy@"3I+/L+и/!ܸи/ 0132673#"'&'%.#"#>7>32JUPML2O7>3 ʎse}q("џ.FQ2yA&0)^;L&oS+ V+ и / /V+ 9 9и/и/ 9 901!'5!75v_&v٩y$cy'vy'`y%'vat OS+ //ܸии  и / ܸ V+V+ V+01%#53#53#5fڃ> 'I+/// /// / /01 #!#!#!#V<<dMMMM%S _S+V+ V+V+ и  и V+ V+V+и01#5!#53#3#//t<Y 'S+V+////V+01%'7'7%''3#Y}ϓ7S+V+ии V+V+013#3#% _S+V+ V+V+ и  и V+ V+V+и01#5!#53#3#/B{[6 GS+V+и //V+и/и/01!5%'7'7%''6{S! OS+V+иии и V+V+ V+013#3#3#!} gS+V+иии и и иV+ V+ V+V+013#3#3#3#!}"  ˸I+//ܸ и /A]A )9IYiy ] A&6FVfv ]A]L+L+01#"'&5476324&#"3260+??5 ; KR$ W afcf''۸I+(/)/ܸA]A )9IYiy ]и/(и/A&6FVfv ]A]"и"/%L+L+ L+01#&'&#"67632#"&5476324&#"326Y!BKY/+5Zvd ?x^O?S:XPFGG1*--srb]|7dMND\_% I+/ L+01#6767!5"s,+d"tEKtN"`]M2nwWZ!   2KI+.L+ L+A]A )9IYiy ] 9 /A ]A  ) 9 I Y i y ]A&6FVfv ]A]ܺ$ 9 (ܺ1.(94+L+L+ L+$ 91 9014&#"3264&#"326&54632#"&5467&@AA:K3;CUBAQJN?R(tkgu"(,/th>=%0(CC-29BEHIA8RD"(@PsmHC*2P^rl?]$ 'I+(/)/( и /"A""&"6"F"V"f"v"""""" ]A""]и/)ܸA]A )9IYiy ]9 и/L+L+% L+013267#"&54632#"&54&#"3265"A[Y3gywt;!'BimqO>BMDJ6XKk0&ebNtenS1ONYJFRF. 7+ ?I+L+и / /L+и0153533##5.UUTT+&lI+L+013#+l].7I+L+L+01!5!57 TTVVGO0 iI+L+A&6FVfv ]A]и///01#.'&'&54767/O$)Iz9tJB CWI+//и/ܸи/ ܸ ܸи/ //L+и/013>32#4'&#"#BV&U4r(\? %Z7L/)O,QQ12 !85 1˸I+//ܸ и /A]A )9IYiy ] A&6FVfv ]A]L+L+01#"'&5476324&#"3260+??5 ; 73#bbMG`E -S7 D";I+ L+ܸи/$L+L+01767654&#"#67632!!>`@)K>]#\!:{r=#ZE12 Bb7&*5?IF%C^;hRV=#3&,5U]0 1I+%L+%9/A]A )9IYiy ]%ܺ)%9,ܸ3/L+"L+" ܸи/)" 901332654&#*5327654&#"#47632#"&^#\GV[P   2!9L3Z"Y 7mx##8@|s F9LKR$ W afcf'2'۸I+(/)/ܸA]A )9IYiy ]и/(и/A&6FVfv ]A]"и"/%L+L+ L+01#&'&#"67632#"&5476324&#"326Y!BKY/+5Zvd ?x^O?S:XPFGG*--srb]|7dMND\_%DI+/ L+01%#6767!5"s,+d"tEKtN"`]M2nwWZ!/  2KI+.L+ L+A]A )9IYiy ] 9 /A ]A  ) 9 I Y i y ]A&6FVfv ]A]ܺ$ 9 (ܺ1.(94+L+L+ L+$ 91 9014&#"3264&#"326&54632#"&5467&@AA:K3;CUBAQJN?R(tkgu"(,/th>=%(CC-29BEHIA8RD"(@PsmHC*2P^rl?]$0'I+(/)/( и /"A""&"6"F"V"f"v"""""" ]A""]и/)ܸA]A )9IYiy ]9 и/L+L+% L+013267#"&54632#"&54&#"3265"A[Y3gywt;!'BimqO>BMDJ6XKk0&ebNtenS1ONYJFRF.D7O ?I+L+и //L+и0153533##5.UUTT+3&I+L+013#+].7I+L+L+01!5!57 TTVVGs0.iI+L+A&6FVfv ]A]и///01%#.'&'&54767/O$)Iz9tJ)2$i;ѸS+323267#"'&'#"&54670,K471*9 B=FT|Q_;:  / g>J_]L$SI 3'-  .*&*cN$$LC" $5[DJR $1 h$3S+V+$и$/V+!V+V+01!327673#"&54632&'&#" xHLF* Y')T)6%QQc/#I(6:#AYE0k ǸS+//A]A )9IYiy ]и/A&6FVfv ]A] ܸ V+V+014'&#"3267#"&54632&]SKKRYC^~nshYK/J~YVrU~D\ 5S+/// /9990137#'#u{|nsr$1 h$;S+V+$и$/&!V+V+V+01&'&5!.#"#>767632#"&73267P HLF* Y')T)6%QQc/#I(6:#AYE"_A'ոS+(/'/ܸи' и(и/и/ 9 A  & 6 F V f v ]A ]и/'и/ V+V+V+#V+V+ #901!!!!!!#"'&547632#.#"32767@IjTWsV] abYmxxn9aZUXGNf֣hq^GST(Z8q'-4S+0#V+A00&060F0V0f0v000000 ]A00] #09//// V+9и/ 9293901373#&'327673!"'#7&'#&76%&:bPn!s=:Bu_f[O{W'5~ 0̓G9Y蝽H^E_!_9Ŕtc"Zq/S+0///ܸи//90и/+A++&+6+F+V+f+v++++++ ]A++]/!(V+ V+и/!%013>32.#"67673! '&76! #.#"k_=嬺G4!Ųx\g6rY蝽EڻzKzA*    !++N3232767#"$#"'>54'!5!&'&'#53&54632#4&#"An0HxE@H%/'1S8,IR32<"*6h0)pf@4YqN,$V+V5V+A&6FVfv ]A]к+9/ܸи"и#и)и-ܸ*A55]A 55)595I5Y5i5y555555 ]A>>]A >>)>9>I>Y>i>y>>>>>> ]5FиF/V^2YV+ V+JV+V+,иJA01!2+#&+32654733#3267#"&5#5332654'&/&'&54632#&'&#"#"&'NJbxkoc!:CT[VV  !?-HH@"T2L:GE :m]y5"UL35#';a!5mowdȬrՓE8  gœ!Z0WW[E$$"*IZh=2GN@F*/,E٠N 'VS+ V+V+G8V+P/V+и/и/и/%A//]A //)/9/I/Y/i/y////// ]A88]A 88)898I8Y8i8y888888 ]/@и@/PX,SV+ V+;DV+$V+012654'&+!2#./&'&+#32654'&/&'&54632#&'&#"#"&'FQ93dTT7g61++ z2=d"T2L:GE :m]y5"UL35#';a!5mowdp9 1^3#rT)F!.*D*=eɹa3{ג' )+%%ڻT39`Y蝽1aS+V+и////V+и и к 9015333!!!!##1Ys&dss#X!CS+V+и ии/V+01%#5%55%!5!!Kqttb3)D%,3S+#V+и#ии#)и#2/(V+V+V+-V+ ииии!и#и*и101535#535!23#3##!#%4'!!6'&+!&2767!)x<)kxBsֆSXVXo7M82VXH39Ac%.S+(V+V+V+ и ииܺ!9A((&(6(F(V(f(v(((((( ]A((],и0 //V+! 901#&'&76753#&'&'676!5!#'UآȚ嫨1$qZn0eNaesYrqک DsI; Uato+7=S+///V+V+ и к 9 ик9иик9к9901537#5!3!#3##!#%'!3N<+:hڕ̥79tq#ݢHH@Iz_GS+V+IV+Iи/@и@/BиB/FиF/01>7>%%67>7&'.'.'.'&67'5>7%57>'.'.'.! #=9EY' !!Z cP- &8$L#KG9[aIG0U&&44* (oyx1   #dxC,)R9<@   $0"33:f/-3:A%  "#  Zq )S+*//ܸ*и/ и ии#A##&#6#F#V#f#v###### ]A##]'/ /01#&'&76%53#&'&'67673Uԗ嬞߄!cL|]=Uxa E~S@[Y蝚/B 5!!#5!/OPZFX63S+4/V+V+!и%и'012>7!>767!4.+>3!01#3##/eaXF-2GJA  S QuL"<[@-"5* 0/$% $I']W/   ^S+V+V+ ܺ9к9и иик9ик9 / V+012>53+575573%%cg5N6ooBxeRdddea䜁=X?ZS+<V+'V+HUV+<H9и/A&6FVfv ]A]6и6/AUU]A UU)U9UIUYUiUyUUUUUU ]/KRV+#V+XDV++9V+#9+и/92и2/013276=67654&#"#>323267#"'&'#"&5467#.#"32673#"&54632tQ=9`C E?5I( TNZ&lixLK ;#O_yw`Dp IPm0X\HTpxt&Cs.k\  B29T;515c..avV*).DtW_i =?SkFffYK~ēq=?nyS+<V+'V+_PV+hGV+<h9<h9и/A&6FVfv ]A]6и6/AGG]A GG)G9GIGYGiGyGGGGGG ]APP]A PP)P9PIPYPiPyPPPPPP ]hp/k/#V+S\V++9V+kи/+и/92и2/kD013276=67654&#"#>323267#"'&'#"&546732654'&/&'&54632#&'&#"#"&'tQ=9`C E?5I( TNZ&lixLK ;#O_yw`;+k@a&I[X)KvE*m'bAD,2L|*D&Cs.k\  B29T;515c..avV*).DtW_i M988:,.Sax[9B' -2)- ,_[fZq%I+&/'/ܸ&и/A&6FVfv ]A]# L+L+ܸи/ и/$901#.#"327673! '&76! c!Ų2-+0s=嬺G4Xx&_Y蝽E (o&r&31"+S+,//ܸ иии,и/%A%%&%6%F%V%f%v%%%%%% ]A%%])к*9/V+013#&'&'67673!!&'&54767QT=\ .!6a:LQqJeoKf^'70</GP5 8`P/˯u\}VXY0k":+7AS+ V+&2V+,V+,9,9A  & 6 F V f v ]A ]A]A )9IYiy ]A22]A 22)292I2Y2i2y222222 ],9///V+5#V+V+/и//)013#.#"32673#"&546324'&#"3267#"&54632tQp IPm0X\HTpxt1wi``hsTx&C?SkFffYK~ēq%_<_rmḻ:a6S+ V+ 5V+*)V+*9*9A  & 6 F V f v ]A ]),и,/-)*9*8/$1V+V+V+9013#.#"32673#"&54632327653#7#"'&5tQp IPm0X\HTpxt;Sy+sm!B^5&C?SkFffYK~ēqo:5!=l9dPTe'6b4Yo&r)3/wI+L+L+L+и и ии//// //L+ и013!3#!###33ɳɳ_CQQ !+I+#$L+*'L+L+L+A]A )9IYiy ]и/A]A )9IYiy ]и/-%/(/L+ L+L+#и*014'&#"3276!5!2#"'&5476%#33#T&P(KM(yG:=II=:G잺g[AWUDYXCxbezzfbyTH+*4)S+V+. V+$3V+ V+A&6FVfv ]A]A ]A  ) 9 I Y i y ].(A33]A 33)393I3Y3i3y333333 ]6V+V+!-V+0'V+01! 76'&! ! '&76! !2+#&+326545 11?Jbxkoc!:CT~10odVz9HQI+L+ L+L+ и A]A )9IYiy ] и / /L+L+ ии01!2+###&+326543#hɝBs&&GȬmr\P&/ݸI+) L+L+"-L+ 9A]A )9IYiy ]A))&)6)F)V)f)v)))))) ]A))]1/$L+ L+!и!/01%'# '&7! %'765#"326dRq«t#5~d[A@8lԋ"y-6H*Ў~~{hv< i !2 /C+I+L+(L+A0L+56L+A&6FVfv ]A]A((&(6(F(V(f(v(((((( ]A((]2596:и:/A=и=/5E/+/CL+0L+2+903иC5к:+9C;к=+901327654'&/&'&54632#&'&#"#"'&733#465##1}8.Y%&Qda)F~s^-mXM-hgK(FvMNŎҍ_c_ ?'IP<.\cpz;:J164bziFFwm"h;koO BI+L+ L+L+ иL+ L+ L+ и и/и и/ ии01###5)!!!!!3!!eeIjct)XyXZUXyX @HXhx@  @       9999?<<<<9+}+}10]3###5!##΅tʅj+IIyyy\^#@M 7 G W zv fu) : : %  11#$R+NM9999NEeD?<32#4&'  ?&1y%b:u\#N.="$cf3 +S+V+/V+V+01!5!!5!34/I'ѸI+(/)/ܸ( и / 9A&6FVfv ]A]%A%%]A %%)%9%I%Y%i%y%%%%%% ]" L+L+01! '$76!2'7&$# ! 4&y-60~~{hv/; :xdRq«t#5~d[A >lX   [I+L+/////L+ L+L+ ии01!!!!# 3#'!#!#33#XficpvBq mJOf)x}w|ZX-E!yf.c"I+#/$/ܸ A ]A  ) 9 I Y i y ]#и/ܸи/ и/ и/!L+ L+L+01%&332!"!!36763 !"1${0eNȾ)s 2/Io+JKI+L+/L+01!#!5!KKI+L+/L+01)5!3KQǯ*G/I+L+9///901!# #3GZZ+>mPY( ;ٸI+L+ L+A&6FVfv ]A]A ]A  ) 9 I Y i y ]и/5ܸ=L+2L+,2901327654&'67654&#"#"&54767#6367632;VIo+CN_L+Bao!Y4z fRDwe>]?DSA^J&-=pYCk^2Klu~fpyj>Q@POG=Y)HpDfk)l :>S+?//?и/*A**&*6*F*V*f*v****** ]A**] и /A]A )9IYiy ]3ܺ=39@/;/6V+V+'V+'9 '9=;901 3#'!#327654'&/&'&54632#&'&#"#"'&7 3owCp mKPfW1}8.Y%&Qda)F~s^-mXM-hgK(FvMNkQ E!>'IP<.[co{; 9J163bzjGEwCf. +S+V+/V+V+01!5!!5!3f ('Z I+L+/ //013##567673Q@|)@&CaGk !d,&,,9&,',9,ro&,994694&9,V4 !&9',V,4 Z&9',V',, m&,;9*4;*&;,V* !&;',V,K/Zq&c'0;L&LL&L'LL&LY /Y ;&YL &Y'LL &Y'L'LL&L[ /[ ;&[L &['LL=O;NF8G%GPZquI+L+A]A )9IYiy ] L+L+016! ! '&'332#"#h4Gׯ=sٲ!&T͛YA;1;NuS+V+A]A )9IYiy ] V+V+01>32#"&'332654'&#"#;һp0J~rװwܡmc/qWa@487HGH// /9=/9999?(Zm( m@a\o( v@?IY         \!<3++N?(-"$3S+ V+ // V+ 9 901#! !265!ɏFd"֋XF;CS+//и/ܸܸ V+ܸ013!53;L(+S+V+01!5+lSS+V+01!5S K6S+V+//01#3K * s6S+V+//01#3s * +S+V+/V+01#!Kb5  SS+V+/V+01#!s] G K+S+V+/V+01%5!#5b sSS+V+/V+01%5!#]kS+V+/V+01!3K,lS+V+/V+01!3svTGKS+V+/V+013!5%lsS+V+/V+013!5%vS+//01!!B@c  ?R+NM<NEeD??9=/<9999M.+}.+}.+}.+}10q] BE#$  !S+//014>32#".Ex[[xEEx[[xEE[xEEx[[xEEx.:F=S+)V+8>V+DV+!V+2V+A]A )9IYiy ]A&6FVfv ]A]A>>]A >>)>9>I>Y>i>y>>>>>> ]!H%V+-V+/ V+ ܸ-Aܸ5и/;0146324'&#"! 76'&! ! '&76! 2654&#"!2654&#">ķrS`01g4DD43CC4DD43CCjӪA*A 11D34DD43DD34DD43D.:F9S+)V+8>V+DV+!V+2V+A]A )9IYiy ]A&6FVfv ]A]A>>]A >>)>9>I>Y>i>y>>>>>> ]!H%V+-V+ V+;ܸ/и-Aܸ501#"&573265! 76'&! ! '&76! 2654&#"!2654&#"ķrS`01g4DD43CC4DD43CCӪA*) 11D34DD43DD34DD43D*6S+V+(.V+"V+A""]A "")"9"I"Y"i"y"""""" ]"и/4ܸи/A..]A ..).9.I.Y.i.y...... ]8 V+1V++V++и1%01#"'&53265! '&76! 2654&#"!2654&#")`Sr^01g4DD43CC4DD43CC*A11D34DD43DD34DD43D>S+V+V+A]A )9IYiy ] и //V+901'654'&'# 546327v/xzH{zng=7M^);*A)(03+0OZ8kS+ V+и и и/V+V+V+ и и и01535#5333#3#!!8Qvr9v$gS+ V+и и и//V+V+ и и и01535#5333#3##$vrv+_S+V+и/V+ V+ и/*ܸи/*9 901332673#"'&'!!'.#"#>7>32953!5(Ift->2Q!&QT0u(2*aA sT A&[SuJ208*S+//и/A]A )9IYiy ]ܸܸ и ии /V+V+ V+и0153!2#!#&#!!!!265482BstΓ\Ȭ%rPx'1_S+$V+V++ܸ ܺ9$0и3// /V+("V+"(901#"'&5!2#./&'&#!2654'&#! ?&mmbVW .  d9z;y5r=fUb:u\1^3#rT)F!A>>&>6>F>V>f>v>>>>>> ]A>>] >9I4и4/: 9C 9IGиG/K 9L 9N// V+/'V+  и /9и/'%и%//1и1/59 :и:/C9K9L90133267#"'&'#7&'&546?&#"#>326=6%67654'̘Du% *,&]* 7gYh49K8^\e";! 83 !4.,vIS9hF:> 4O H" B#@H5-5[ >L*Sƛ_I 5/gN- I ,-R)!S+V+9/ܸк9иии#/V+ܸии 0133#3267#"&=##5333hDg&1 C'~Zt 38  g4i3+YS+V+V+ 9 /ܸ и и//V+ V+013!33##!#Ɇċ_ZQCSS+V+ V+ 9/ ܸи  //V+ 9013676323##4'&#"#@3WS-Vn1pQ!9YZv7XNWS+//и/ܸܺ9 и///9013! ###t?4Z]S+//и/ܸܺ9 и//990133 ###fEobZn/ 3S+ V+и /V+ V+017!5!!#!/Cv?iZ4/ /S+ V+ V+V+ 017!5!!#!4{>!Zf'S+V+//V+01!#3f^QN0'S+V+//V+01!#3N 0cKS+V+/V+01!!#KUJK yS+ V+ V+A ]A  ) 9 I Y i y ]/ V+V+012654&#"!!#b%55%$44U:5$%55%$5J%SS+V+//01%#%.Uh 8S+V+//01#'58U.>h*uS+V+ V+A]A )9IYiy ] // V+01%#%2654&#"*.U%55%$44hi5$%55%$5owS+ V+V+A&6FVfv ]A] 9// V+01#'5"&54632oU.%55%$44>h5$%55%$5#S+V+/V+01!!#!WJS+V+ V+A]A )9IYiy ] /V+V+01!!#!2654&#"WC%55%$44J5$%55%$5L,8eS+06V+A66]A 66)696I6Y6i6y666666 ]0:3-V+0167>&'&'&67>.#&'&676%2654&#"PJ2>  /0 !/,][W I2>  01 ".,][W %55%$44: K3NM).c.,)C9 L3NM)-d.,(D5$%55%$5D,67>&'&'&67>.#&'&676OJ2>  /0 !/,][W I2>  01 ".,][W : K3NM).c.,)C9 L3NM)-d.,(DD,&'.767#>&'.&'.7>6 W[],/! 1/  >2J W[],." 00  >2D(,.d-)MN3L 9C),.c.)MN3K K}CS+//и/ܸܸ V+V+01!!%!K2xJbS+//017<<< <S+//01'C<<<<:aS+V+A&6FVfv ]A]/ V+013>54.'!!:QQ@bX|{JOK 1eS+V+015!KeeI /eS+/V+01'!5!!<&<)eeeS+/V+01!5!!D&<ee<K /S+ V+ ܸи //013526544K4JJ4V{{SJ44JS{VV{"5S+V+V+V+01!5#55t^|#S+/ / 9 901.'&'&'&'&'15"*L7GW]F+F4HC$i1%ΤDSS}GO.#.+ 4isH #S+/ / 9 901'676776767%1i$CH4F+F]WG7L*"5Hsi4 +.#.O}GSSD/S+ V+A ]A  ) 9 I Y i y ] иV+ V+9 901 5 5 "&54632"&54632oE93JJ34JJ43JJ34JJ7ji6J44JJ44J73#4Ú&Yn@"yS+V+A]A )9IYiy ]и/$V+V+01767654&#"#676!2!!64R}G&Bu(yFb8d) ;oK5Sk}KvzGeL61Wj11S+%V+A]A )9IYiy ]%9/A]A )9IYiy ])%9,ܸ3/V+"V+ V+/ܸ и/и/"ܺ) 901332654&#"5327654&#"#476!2#"1 (F%&eAreE&@nG,Fq?qxv 8ktxBzpùR34/ KS+ V+и/  и //V+ и 01 !533#5w^_B S+V+A]A )9IYiy ]"V+V+ V+ 90132654&#"'!!67632!"$'}@T]/m=2-Pim;|H@ r&!M#'׸S+(//(и/A&6FVfv ]A]A]A )9IYiy ]ܸ)%V+V+ V+01#&'&#"67632#"7!24&#"326#A >^Vj A}L~t!U0Z[-(1i dnǚ+S+/ V+01#67!5EXW-.D艗CcB 2QS+.V+ V+A]A )9IYiy ]A&6FVfv ]A].9/ܺ 9 /A ]A  ) 9 I Y i y ]$ 9(ܺ1.(94+V+V+ V+$ 91 9014&#"3264&#"326&54632#"$5467&*tfw0}iOD&PY3_|zK!PZerËpDPّS/-)5d1 I'S+(//( и /"A""&"6"F"V"f"v"""""" ]A""]и/A]A )9IYiy ]ܺ9)V+V+% V+01326#"543 !"&54&#"326k7E&7C-K{`65P%C[&X4??4K\@A7 ) xa@6 9  !) ) !!gB++NM]9/<<< S+V+/V+01!!z S+V+V+V+013!!! $ª\o(@_Xh           \ <3+N54'&#"'67632!"&543.WjVs[/5$49#:Bre مz|fb)L~ ?( @\ww77w ))   X  NMNM9v//9?999=/<.+}Ň.+}10q]] 5!! !!(CjH)y\ S+V+ V+01632.#"#"&'732767M+'))3Z!" !LM(<0U+* 4I [[U MLr1q}@AGw7   /9/39999/3232767#"&'&'&'&#">323267#"&'&'&'&#"\OrMaIGa\7 (6ZYQ!D#71WF+COrMaIGZ-CJMD#71XH,?F2A&*%0 < -GF2[67; : /E-@# d 4 dcR+NM@# d 4 d4d?3+NM<'#53Em]y=8mY| U-* t_ yLsc&*z=zI&JzG2=N&.z 3&Nzx3K&/z? 3&Oz*=*&1z 3I&QzI3x&5z3G&UzNt W++//и/ܸиܸ и/ /.+и01.=3#.=3#$tbmKPsbmKw*9`^w*9` '++.+и//01.=3#ljm97  Ej 2E(G@-G0 @G @k\ G'@3uqGd @+>xG@&('OgjqgzHu&H'Oq&('OWiPXH&H'OP:&0C*>%&PC:x8&5a\L&Ua3H&H'Oq/H0&H'OPR=&$'!RG&D'RKJ&D'c&((H=I&H`q5&('6WH=&H'xcD&('(EfH=&H'`p&,'j! 3[&'UyM&L}oP;&2K;<!N&R]P;q&2'K;<!&R'] P;l&2'K;<!&R']c;&6B;K&V+/&8'#!8&X'f /&[15j&]$h&^p; w"<\j I+:#L+-.L+aXL+A@L+:%и%/@RиR/AXX]A XX)X9XIXYXiXyXXXXXX ]@hиAlJFL+!L+dUL+[]L+!и/и/ܸ ܸ[(и(/U-и-/]3и3/U;и;/FN0132673!"'&'%.#"#>7>323>32#4'&#"#53!"&'33276'#"$32"327654&rjfBjP$2Z|HhL4`8:"PdT‚:LhP,0~@)J8-35'ou+&>'e+&>'n%+ &>'A+ &>'P+ &>'Q+ &>'{+ &>']+ &>'^+&>'o++&>'eM+)&>'n%<+&>'A$+&>'P$+&>'Q$+&>'{$+&>']$+&>'^$.1&o/1&z[{&C@-&P&Q[{&{@B&]!&^.1!&o/1!&z[{!&C@-!&P!&Q[{!&{@B!&]!!&^.&oZ/&zZ/&z'Z0&Cl}&Pd&Q&{l&]3q&^.!&oZ/!&zZ/9&z'Z!&Clw!&P^!&Q!&{l!&]3k!&^.&oZ/&z/&z'X&Al`&P3?&Q&{l`&]3?&^.!&oZ/!&z/a&z'!&Al`!&P3?!&Q!&{l`!&]3?!&^x!+/I+/L+L+ L+ %ܸܺ 9/и*и-и 1// /)L+"L+"9и",и).01!2#./&'&+###2654'&+!3#mmbVW .  d9znɎr=f1^3#rT)F!y&Al`&P3?&Q; S+// V+ V+013#!#!#!!H ןʣZ@`uv;! /S+// V+ V+ܸ 013#!#!#327673#"'&'H ןʣ8vm6cM( Z@`uLA!;;"@w>`_S+V+/V+013#!!ZvY!+S+V+/V+ܸ 013#327673#"'&'s8vm6cM( Z!A!;;"@w>`)- %S+V+9/ V+01#3 3%!!AdVPdv)-!5S+V+9/ V+ ܸ 01#3 3327673#"'&'8vm6cM( dVPd{A!;;"@w>`>S+V+V+A]A )9IYiy ] и //V+901'654'&'# 546327v/xzH{zng=7M^);*A)(03+0OZ'S+V+и//01.=3#v`mEw *-U NtWS+//и/ܸиܸи//V+и01.=3#.=3#$y]mEP|Ym8=t *-U _sLy  'S+ V+и / /01>54&'#5379mjl jE ɀ Nt [S+//иܸи/ иܸ //V+и01676'#53%676'#53KmbtKmbs`9*w^`9*w;P !i  2F   ixw x    >)    d y ` !  ^ 3 =` KWt _m }  l !"* 9 #> 1= EU e o 1990-2006 Apple Computer Inc. 1981 Linotype AG 1990-91 Type Solutions Inc. 1990-2006 Apple Computer Inc. 1981 Linotype AG 1990-91 Type Solutions Inc.HelveticaHelveticaRegularRegularHelvetica; 13.0d1e1; 2017-06-14Helvetica; 13.0d1e1; 2017-06-14HelveticaHelvetica13.0d1e113.0d1e1HelveticaHelveticaHelvetica is a registered trademark of Linotype AGHelvetica is a registered trademark of Linotype AGHelveticaHelveticaCourantHelvetica est une marque dpose de Linotype AGNormalHelvetica ist ein eingetragenes Warenzeichen der Linotype AGRegolareHelvetica un marchio registrato di Linotype AGRegulierHelvetica is een geregistreerd handelsmerk van Linotype AGNormalHelvetica r ett registrerat varumrke fr Linotype AGHelvetica es una marca registrada de Linotype AGNormalHelvetica er et registreret varemrke tilhrende Linotype AGNormaljnRegularNormaaliNorml00000|̴NormalRegularNormalNormal1KG=K9RegularniRegular4NormalReguler28G09=89Thng thng ( ? / . ? $Biasa^8OSRegularRegular9'/JRegularee  !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghjikmlnoqprsutvwxzy{}|~      !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~      !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~      !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~      !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~      !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~      !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~      !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~      !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~ softhyphenAmacronamacronAbreveabreveAogonekaogonek Ccircumflex ccircumflex Cdotaccent cdotaccentDcarondcaronDcroatEmacronemacronEbreveebreve Edotaccent edotaccentEogonekeogonekEcaronecaron Gcircumflex gcircumflex Gdotaccent gdotaccent Gcommaaccent gcommaaccent Hcircumflex hcircumflexHbarhbarItildeitildeImacronimacronIbreveibreveIogonekiogonekIJij Jcircumflex jcircumflex Kcommaaccent kcommaaccent kgreenlandicLacutelacute Lcommaaccent lcommaaccentLcaronlcaron Ldotaccent ldotaccentNacutenacute Ncommaaccent ncommaaccentNcaronncaron napostropheEngengOmacronomacronObreveobreve Ohungarumlaut ohungarumlautRacuteracute Rcommaaccent rcommaaccentRcaronrcaronSacutesacute Scircumflex scircumflexTcedillatcedillaTcarontcaronTbartbarUtildeutildeUmacronumacronUbreveubreveUringuring Uhungarumlaut uhungarumlautUogonekuogonek Wcircumflex wcircumflex Ycircumflex ycircumflexZacutezacute Zdotaccent zdotaccentslongbstrokeBtopbarbtopbarOopenDafricanDtopbardtopbar deltaturned EreversedSchwaEopenFhook IotaafricanIstrokelbaruni019B Nhookleft nlegrightlongOcenteredtildeOhornohornyrTonetwotonetwoEshTretroflexhookUhornuhornUpsilonafricanuni01B5uni01B6Ezh Ezhreversed ezhreversed twostroke clickdental clicklateral clickalveolarclickretroflexDZcaronDzcarondzcaronLJLjljNJNjnjAcaronacaronIcaronicaronOcaronocaronUcaronucaronUdieresismacronudieresismacronUdieresisacuteudieresisacuteUdieresiscaronudieresiscaronUdieresisgraveudieresisgraveeturnedAdieresismacronadieresismacron Adotmacron adotmacronAEmacronaemacronGstrokegstrokeGcarongcaronKcaronkcaronOogonekoogonek Oogonekmacron oogonekmacronEzhcaronezhcaronjcaronDZDzdzGacutegacuteWynnNgravengrave Aringacute aringacuteAEacuteaeacute Ostrokeacute ostrokeacute Adblgrave adblgraveAinvertedbreveainvertedbreve Edblgrave edblgraveEinvertedbreveeinvertedbreve Idblgrave idblgraveIinvertedbreveiinvertedbreve Odblgrave odblgraveOinvertedbreveoinvertedbreve Rdblgrave rdblgraveRinvertedbreverinvertedbreve Udblgrave udblgraveUinvertedbreveuinvertedbreve Scommaaccent scommaaccent Tcommaaccent tcommaaccentYoghyoghHcaronhcaronuni0220uni0226uni0227uni0228uni0229uni022Auni022Buni022Cuni022Duni022Euni022Funi0230uni0231uni0232uni0233dotlessjuni0238uni0239uni023Auni023Buni023Cuni023Duni023Euni0241uni0242uni0243uni0244uni0245uni0246uni0247uni0248uni0249uni024Auni024Buni024Cuni024Duni024Euni024Faturnedascript ascriptturneduni0253oopenuni0256uni0257 ereversedschwa schwahookeopen eopenreversedeopenreversedhookeopenreversedclosedjdotlessstrokeuni0260gscripthturneduni0266uni0267istroke iotalatin Ismallipa lmiddletildeuni026Dmturnedmlonglegturnedmhook nhookleftuni0273 Nsmallipauni0275uni0276philatinrturnedrlonglegturneduni027Brlongleguni027D rfishhookrfishhookreversed RsmallipaRsmallinvertedeshdotlessjstrokehookeshsquatreversedtturnedtretroflexhookubar upsilonlatinvturnedwturnedyturned Ysmallipaezh glottalstopglottalstopreversedglottalstopinverted cstretched bilabialclick eopenclosed Hsmallipakturned Lsmallipauni02A0glottalstopstrokeglottalstopstrokereverseduni02A3dezhuni02A6uni02A7uni02A9uni02AAuni02ABuni02ACuni02ADuni02AEuni02AFuni02B0uni02B1uni02B2uni02B3uni02B4uni02B5Rsmallinvertedsuperioruni02B7uni02B8primemod dblprimemodcommaturnedmod apostrophemod afii64937uni02BEuni02BFuni02C0uni02C1uni02C2uni02C3uni02C4uni02C5uni02C8uni02C9uni02CAuni02CBuni02CCuni02CDuni02CEuni02CFcolontriangularmodcolontriangularhalfmoduni02D2uni02D3uni02D4uni02D5uni02D6uni02D7 rhotichookmoduni02DFuni02E0uni02E1uni02E2uni02E3uni02E4tonebarextrahighmodtonebarhighmod tonebarmidmod tonebarlowmodtonebarextralowmoduni02EAuni02EBuni02ECuni02EDuni02EEuni02EFuni02F0uni02F1uni02F2uni02F3uni02F4uni02F5uni02F6uni02F7uni02F8uni02F9uni02FAuni02FBuni02FCuni02FDuni02FEuni02FFgravecmbacutecmb circumflexcmbtildecmb macroncmb overlinecmbbrevecmb dotaccentcmb dieresiscmbhookcmbringcmbhungarumlautcmbcaroncmbverticallineabovecmbdblverticallineabovecmb dblgravecmbcandrabinducmbbreveinvertedcmbcommaturnedabovecmb commaabovecmbcommareversedabovecmbcommaaboverightcmb gravebelowcmb acutebelowcmblefttackbelowcmbrighttackbelowcmbuni031Ahorncmbringhalfleftbelowcmbuptackbelowcmbdowntackbelowcmb plusbelowcmb minusbelowcmbuni0321uni0322 dotbelowcmbdieresisbelowcmb ringbelowcmb commaaccent cedillacmb ogonekcmbverticallinebelowcmbuni032Adblarchinvertedbelowcmb caronbelowcmbcircumflexbelowcmb brevebelowcmbbreveinvertedbelowcmb tildebelowcmbmacronbelowcmb lowlinecmb dbllowlinecmbtildeoverlaycmbstrokeshortoverlaycmbstrokelongoverlaycmbsolidusshortoverlaycmbsoliduslongoverlaycmbringhalfrightbelowcmbuni033Asquarebelowcmbseagullbelowcmbuni033Dtildeverticalcmbdbloverlinecmb gravetonecmb acutetonecmbperispomenigreekcmb koroniscmbdialytikatonoscmbypogegrammenigreekcmbuni0346uni0347uni0348uni0349uni034Auni034Buni034Cuni034Duni034Ecombininggraphemejoineruni0350uni0351uni0352uni0353uni0354uni0355uni0356uni0357uni0358uni0359uni035Auni035Buni035Cuni035Duni035Euni035Ftildedoublecmbbreveinverteddoublecmbuni0362uni0363uni0364uni0365uni0366uni0367uni0368uni0369uni036Auni036Buni036Cuni036Duni036Euni036Fnumeralsigngreeknumeralsignlowergreek ypogegrammeniuni037Buni037Cuni037D questiongreektonosuni0385 Alphatonos anoteleia EpsilontonosEtatonos Iotatonos Omicrontonos Upsilontonos OmegatonosiotadieresistonosAlphaBetaGamma DeltagreekEpsilonZetaEtaThetaIotaKappaLambdaMuNuXiOmicronPiRhoSigmaTauUpsilonPhiChiPsi Omegagreek IotadieresisUpsilondieresis alphatonos epsilontonosetatonos iotatonosupsilondieresistonosalphabetagammadeltaepsilonzetaetathetaiotakappalambdamugreeknuxiomicronrho sigmafinalsigmatauupsilonphichipsiomega iotadieresisupsilondieresis omicrontonos upsilontonos omegatonossigmalunatesymbolgreekyotgreekuni03F4uni03F5uni03F6uni03F7uni03F8uni03F9uni03FAuni03FBuni03FCuni03FDuni03FEuni03FFuni0400 Iocyrillic Djecyrillic Gjecyrillic Ecyrillic Dzecyrillic Icyrillic Yicyrillic Jecyrillic Ljecyrillic Njecyrillic Tshecyrillic Kjecyrillicuni040DUshortcyrillic Dzhecyrillic Acyrillic Becyrillic Vecyrillic Gecyrillic Decyrillic Iecyrillic Zhecyrillic Zecyrillic IicyrillicIishortcyrillic Kacyrillic Elcyrillic Emcyrillic Encyrillic Ocyrillic Pecyrillic Ercyrillic Escyrillic Tecyrillic Ucyrillic Efcyrillic Khacyrillic Tsecyrillic Checyrillic Shacyrillic ShchacyrillicHardsigncyrillic YericyrillicSoftsigncyrillicEreversedcyrillic IUcyrillic IAcyrillic acyrillic becyrillic vecyrillic gecyrillic decyrillic iecyrillic zhecyrillic zecyrillic iicyrilliciishortcyrillic kacyrillic elcyrillic emcyrillic encyrillic ocyrillic pecyrillic ercyrillic escyrillic tecyrillic ucyrillic efcyrillic khacyrillic tsecyrillic checyrillic shacyrillic shchacyrillichardsigncyrillic yericyrillicsoftsigncyrillicereversedcyrillic iucyrillic iacyrillicuni0450 iocyrillic djecyrillic gjecyrillic ecyrillic dzecyrillic icyrillic yicyrillic jecyrillic ljecyrillic njecyrillic tshecyrillic kjecyrillicuni045Dushortcyrillic dzhecyrillic Yatcyrillic yatcyrillicEiotifiedcyrilliceiotifiedcyrillicYuslittlecyrillicyuslittlecyrillicYuslittleiotifiedcyrillicyuslittleiotifiedcyrillicYusbigcyrillicyusbigcyrillicYusbigiotifiedcyrillicyusbigiotifiedcyrillic Psicyrillic psicyrillic Fitacyrillic fitacyrillicIzhitsacyrillicizhitsacyrillicIzhitsadblgravecyrillicizhitsadblgravecyrillicuni0478uni0479GheupturncyrillicgheupturncyrillicGhestrokecyrillicghestrokecyrillicZhedescendercyrilliczhedescendercyrillicZedescendercyrilliczedescendercyrillicKadescendercyrillickadescendercyrillicKaverticalstrokecyrillickaverticalstrokecyrillicKabashkircyrillickabashkircyrillicEndescendercyrillicendescendercyrillic Enghecyrillic enghecyrillicEsdescendercyrillicesdescendercyrillicTedescendercyrillictedescendercyrillicUstraightcyrillicustraightcyrillicUstraightstrokecyrillicustraightstrokecyrillicHadescendercyrillichadescendercyrillic Tetsecyrillic tetsecyrillicChedescendercyrillicchedescendercyrillicCheverticalstrokecyrilliccheverticalstrokecyrillic Shhacyrillic shhacyrillicCheabkhasiancyrilliccheabkhasiancyrillicChedescenderabkhasiancyrillicchedescenderabkhasiancyrillicpalochkacyrillicZhebrevecyrilliczhebrevecyrillicEnhookcyrillicenhookcyrillicuni04CFAbrevecyrillicabrevecyrillicAdieresiscyrillicadieresiscyrillic Aiecyrillic aiecyrillicIebrevecyrilliciebrevecyrillic Schwacyrillic schwacyrillicSchwadieresiscyrillicschwadieresiscyrillicZhedieresiscyrilliczhedieresiscyrillicZedieresiscyrilliczedieresiscyrillicDzeabkhasiancyrillicdzeabkhasiancyrillicImacroncyrillicimacroncyrillicIdieresiscyrillicidieresiscyrillicOdieresiscyrillicodieresiscyrillicObarredcyrillicobarredcyrillicObarreddieresiscyrillicobarreddieresiscyrillicuni04ECuni04EDUmacroncyrillicumacroncyrillicUdieresiscyrillicudieresiscyrillicUhungarumlautcyrillicuhungarumlautcyrillicChedieresiscyrillicchedieresiscyrillicuni04F6uni04F7Yerudieresiscyrillicyerudieresiscyrillicuni04FEuni04FFuni0500uni0501uni0510uni0511uni0512uni0513uni0E3F.bahtthaiu10D0u10D1u10D2u10D3u10D4u10D5u10D6u10D7u10D8u10D9u10DAu10DBu10DCu10DDu10DEu10DFu10E0u10E1u10E2u10E3u10E4u10E5u10E6u10E7u10E8u10E9u10EAu10EBu10ECu10EDu10EEu10EFu10F0u10F1u10F2u10F3u10F4u10F5u10F6u10FBuni1D01uni1D08uni1D09uni1D0Euni1D11uni1D12uni1D13uni1D14uni1D16uni1D17uni1D18uni1D19uni1D1Auni1D1Duni1D1Euni1D1Funi1D43uni1D44uni1D45uni1D46uni1D47uni1D48uni1D49uni1D4Auni1D4Buni1D4Cuni1D4Duni1D4Euni1D4Funi1D50uni1D51uni1D52uni1D53uni1D54uni1D55uni1D56uni1D57uni1D58uni1D59uni1D5Auni1D5Buni1D5Duni1D5Euni1D5Funi1D61uni1D62uni1D63uni1D64uni1D65uni1D66uni1D67uni1D68uni1D6Auni1D6Buni1D6Cuni1D6Duni1D6Euni1D71uni1D72uni1D73uni1D75uni1D7Auni1DBF.smallthetauni1DC0uni1DC1uni1DC4uni1DC5uni1DC6uni1DC7uni1DC8uni1DC9uni1DCA Aringbelow aringbelow Bdotaccent bdotaccent Bdotbelow bdotbelow Blinebelow blinebelow Ccedillaacute ccedillaacute Ddotaccent ddotaccent Ddotbelow ddotbelow Dlinebelow dlinebelowDcedilladcedillaDcircumflexbelowdcircumflexbelow Emacrongrave emacrongrave Emacronacute emacronacuteEcircumflexbelowecircumflexbelow Etildebelow etildebelow Ecedillabreve ecedillabreve Fdotaccent fdotaccentGmacrongmacron Hdotaccent hdotaccent Hdotbelow hdotbelow Hdieresis hdieresisHcedillahcedilla Hbrevebelow hbrevebelow Itildebelow itildebelowIdieresisacuteidieresisacuteKacutekacute Kdotbelow kdotbelow Klinebelow klinebelow Ldotbelow ldotbelowLdotbelowmacronldotbelowmacron Llinebelow llinebelowLcircumflexbelowlcircumflexbelowMacutemacute Mdotaccent mdotaccent Mdotbelow mdotbelow Ndotaccent ndotaccent Ndotbelow ndotbelow Nlinebelow nlinebelowNcircumflexbelowncircumflexbelow Otildeacute otildeacuteOtildedieresisotildedieresis Omacrongrave omacrongrave Omacronacute omacronacutePacutepacute Pdotaccent pdotaccent Rdotaccent rdotaccent Rdotbelow rdotbelowRdotbelowmacronrdotbelowmacron Rlinebelow rlinebelow Sdotaccent sdotaccent Sdotbelow sdotbelowSacutedotaccentsacutedotaccentScarondotaccentscarondotaccentSdotbelowdotaccentsdotbelowdotaccent Tdotaccent tdotaccent Tdotbelow tdotbelow Tlinebelow tlinebelowTcircumflexbelowtcircumflexbelowUdieresisbelowudieresisbelow Utildebelow utildebelowUcircumflexbelowucircumflexbelow Utildeacute utildeacuteUmacrondieresisumacrondieresisVtildevtilde Vdotbelow vdotbelowWgravewgraveWacutewacute Wdieresis wdieresis Wdotaccent wdotaccent Wdotbelow wdotbelow Xdotaccent xdotaccent Xdieresis xdieresis Ydotaccent ydotaccent Zcircumflex zcircumflex Zdotbelow zdotbelow Zlinebelow zlinebelow hlinebelow tdieresiswringyringarighthalfringslongdotaccent Adotbelow adotbelow Ahookabove ahookaboveAcircumflexacuteacircumflexacuteAcircumflexgraveacircumflexgraveAcircumflexhookaboveacircumflexhookaboveAcircumflextildeacircumflextildeAcircumflexdotbelowacircumflexdotbelow Abreveacute abreveacute Abrevegrave abrevegraveAbrevehookaboveabrevehookabove Abrevetilde abrevetildeAbrevedotbelowabrevedotbelow Edotbelow edotbelow Ehookabove ehookaboveEtildeetildeEcircumflexacuteecircumflexacuteEcircumflexgraveecircumflexgraveEcircumflexhookaboveecircumflexhookaboveEcircumflextildeecircumflextildeEcircumflexdotbelowecircumflexdotbelow Ihookabove ihookabove Idotbelow idotbelow Odotbelow odotbelow Ohookabove ohookaboveOcircumflexacuteocircumflexacuteOcircumflexgraveocircumflexgraveOcircumflexhookaboveocircumflexhookaboveOcircumflextildeocircumflextildeOcircumflexdotbelowocircumflexdotbelow Ohornacute ohornacute Ohorngrave ohorngraveOhornhookaboveohornhookabove Ohorntilde ohorntilde Ohorndotbelow ohorndotbelow Udotbelow udotbelow Uhookabove uhookabove Uhornacute uhornacute Uhorngrave uhorngraveUhornhookaboveuhornhookabove Uhorntilde uhorntilde Uhorndotbelow uhorndotbelowYgraveygrave Ydotbelow ydotbelow Yhookabove yhookaboveYtildeytildeuni1F00uni1F01uni1F02uni1F03uni1F04uni1F05uni1F06uni1F07uni1F08uni1F09uni1F0Auni1F0Buni1F0Cuni1F0Duni1F0Euni1F0Funi1F10uni1F11uni1F12uni1F13uni1F14uni1F15uni1F18uni1F19uni1F1Auni1F1Buni1F1Cuni1F1Duni1F20uni1F21uni1F22uni1F23uni1F24uni1F25uni1F26uni1F27uni1F28uni1F29uni1F2Auni1F2Buni1F2Cuni1F2Duni1F2Euni1F2Funi1F30uni1F31uni1F32uni1F33uni1F34uni1F35uni1F36uni1F37uni1F38uni1F39uni1F3Auni1F3Buni1F3Cuni1F3Duni1F3Euni1F3Funi1F40uni1F41uni1F42uni1F43uni1F44uni1F45uni1F48uni1F49uni1F4Auni1F4Buni1F4Cuni1F4Duni1F50uni1F51uni1F52uni1F53uni1F54uni1F55uni1F56uni1F57uni1F59uni1F5Buni1F5Duni1F5Funi1F60uni1F61uni1F62uni1F63uni1F64uni1F65uni1F66uni1F67uni1F68uni1F69uni1F6Auni1F6Buni1F6Cuni1F6Duni1F6Euni1F6Funi1F70uni1F71uni1F72uni1F73uni1F74uni1F75uni1F76uni1F77uni1F78uni1F79uni1F7Auni1F7Buni1F7Cuni1F7Duni1F80uni1F81uni1F82uni1F83uni1F84uni1F85uni1F86uni1F87uni1F88uni1F89uni1F8Auni1F8Buni1F8Cuni1F8Duni1F8Euni1F8Funi1F90uni1F91uni1F92uni1F93uni1F94uni1F95uni1F96uni1F97uni1F98uni1F99uni1F9Auni1F9Buni1F9Cuni1F9Duni1F9Euni1F9Funi1FA0uni1FA1uni1FA2uni1FA3uni1FA4uni1FA5uni1FA6uni1FA7uni1FA8uni1FA9uni1FAAuni1FABuni1FACuni1FADuni1FAEuni1FAFuni1FB0uni1FB1uni1FB2uni1FB3uni1FB4uni1FB6uni1FB7uni1FB8uni1FB9uni1FBAuni1FBBuni1FBCuni1FBDuni1FBEuni1FBFuni1FC0uni1FC1uni1FC2uni1FC3uni1FC4uni1FC6uni1FC7uni1FC8uni1FC9uni1FCAuni1FCBuni1FCCuni1FCDuni1FCEuni1FCFuni1FD0uni1FD1uni1FD2uni1FD3uni1FD6uni1FD7uni1FD8uni1FD9uni1FDAuni1FDBuni1FDDuni1FDEuni1FDFuni1FE0uni1FE1uni1FE2uni1FE3uni1FE4uni1FE5uni1FE6uni1FE7uni1FE8uni1FE9uni1FEAuni1FEBuni1FECuni1FEDuni1FEEuni1FEFuni1FF2uni1FF3uni1FF4uni1FF6uni1FF7uni1FF8uni1FF9uni1FFAuni1FFBuni1FFCuni1FFDuni1FFEuni2000uni2001enspaceemspaceuni2004uni2005uni2006uni2007uni2008uni2009uni200Azerowidthspacezerowidthnonjoinerzerowidthjoinerlefttorightmarkrighttoleftmark hyphentwononbreakinghyphen figuredash horizontalbardblverticalbar dbllowlinequoteleftreversedquotedblleftaltoneuni2023 onedotleader twodotleaderuni2027uni2028uni2029uni202Auni202B afii61573 afii61574 afii61575uni202Funi2031minutesecond primetriple primereversedsecondreverseduni2037uni2038 referencemark exclamdbl interrobangoverlineuni203Funi2040 caretinsertuni2042uni2043uni2045uni2046uni2047uni2048uni2049 tironianetreversedpilcrowuni204Cuni204Duni204Euni204Funi2050uni2051uni2052uni2053uni2054uni2055uni2056uni2057uni2058uni2059uni205Auni205Buni205Cuni205Duni205Euni205Funi2060uni2061uni2062uni2063uni206Auni206Buni206Cuni206Duni206Euni206Funi2070uni2071uni2074uni2075uni2076uni2077uni2078uni2079uni207Auni207Buni207Cuni207Duni207Euni207Funi2080uni2081uni2082uni2083uni2084uni2085uni2086uni2087uni2088uni2089uni208Auni208Buni208Cuni208Duni208Euni2090uni2091uni2092uni2093uni2094uni20A0 colonsigncruzeirolirauni20A5uni20A6uni20A7uni20A8wondongEurouni20ADuni20AEuni20B1uni20B2uni20B3Hryvniauni20B5u20B8uni20B9.INDIAN_RUPEE_SIGNu20BAuni2100uni2101uni2102 centigradeuni2104careofuni2106 fahrenheituni210Dnumerouni2117uni2119uni211Auni2120uni2121 ohminverteduni2129kelvinangstromFturneduni213Auni213Buni2141uni2142uni2143uni2144uni214Buni214Duni214Euni215FOneromanTworoman Threeroman Fourroman FiveromanSixroman Sevenroman Eightroman NineromanTenroman Elevenroman Twelveromanuni216Cuni216Duni216Euni216Foneromantworoman threeroman fourroman fiveromansixroman sevenroman eightroman nineromantenroman elevenroman twelveromanuni217Cuni217Duni217E thousandromanuni2183uni2184gradientuni2210uni23CE.Return-Symboluni2423.spaceopenboxuni2500uni2501uni2502uni2503uni250Cuni250Funi2510uni2513uni2514uni2517uni2518uni251Bblocku25CFuni2639whitesmilingfaceblacksmilingfaceuni266Auni2C60uni2C61uni2C62uni2C63uni2C64uni2C65uni2C66uni2C67uni2C68uni2C69uni2C6Auni2C6Buni2C6Cuni2C75uni2C76uni2E00uni2E01uni2E02uni2E03uni2E04uni2E05uni2E06uni2E07uni2E08uni2E09uni2E0Auni2E0Buni2E0Cuni2E0Duni2E0Euni2E0Funi2E10uni2E11uni2E12uni2E13uni2E14uni2E15uni2E16uni2E17uni2E1Cuni2E1DuniA700uniA701uniA702uniA703uniA704uniA705uniA706uniA707uniA708uniA709uniA70AuniA70BuniA70CuniA70DuniA70EuniA70FuniA710uniA711uniA712uniA713uniA714uniA715uniA716uniA717uniA718uniA719uniA71AuniA720uniA721zero.001one.001two.001 three.001four.001five.001six.001 seven.001 eight.001nine.001uniFFA1.halfwidthhangulkiyeokuniFFA4.halfwidthhangulnieununiFFA7.halfwidthhangultikeut old_notequalold_partialdiff old_summation old_integral old_radicalold_approxequalquotesinglbase.oldquotedblbase.oldGcedillagcedillaKcedillakcedillaLcedillalcedillaNcedillancedillaRcedillarcedillaquotedblleftaltone.oldquoteleftreversed.oldnotequal.mirrorpartialdiff.mirrorsummation.mirrorintegral.mirrorradical.mirrorapproxequal.mirrorE_circumflex_macrone_circumflex_macronE_circumflex_carone_circumflex_caronMgravemgraveRbreverbreveecircumflexmacronecircumflexcaron Amacrongrave amacrongrave aacuteogonekEverticallinebeloweverticallinebelowEverticallinebelowgraveeverticallinebelowgraveEverticallinebelowacuteeverticallinebelowacute Imacrongrave imacrongraveidotaboveacuteOverticallinebelowoverticallinebelowOverticallinebelowgraveoverticallinebelowgraveOverticallinebelowacuteoverticallinebelowacuteSverticallinebelowsverticallinebelow Umacrongrave umacrongrave xdotbelow Uhornbreve uhornbreve ngtildeaboveuni2124 old_uni2140uni2134uni2140.mirroruni2140lambdastrokedotabovealphamacronvariaalphamacronoxiaalphamacronpsilialphamacronpsilivariaalphamacronpsilioxiaalphamacrondasiaalphamacrondasiavariaalphamacrondasiaoxiaalphabrevevariaalphabreveoxiaalphabrevepsilialphabrevepsilivariaalphabrevepsilioxiaalphabrevedasiaalphabrevedasiavariaalphabrevedasiaoxiaiotamacronvariaiotamacronoxiaiotamacrondialytikaoxiaiotamacronpsiliiotamacronpsilivariaiotamacronpsilioxiaiotamacrondasiaiotamacrondasiavariaiotamacrondasiaoxiaiotabrevevaria iotabreveoxiaiotabrevedialytikaoxiaiotabrevepsiliiotabrevepsilivariaiotabrevepsilioxiaiotabrevedasiaiotabrevedasiavariaiotabrevedasiaoxiaupsilonmacronvariaupsilonmacronoxiaupsilonmacrondialytikaoxiaupsilonmacronpsiliupsilonmacronpsilivariaupsilonmacronpsilioxiaupsilonmacrondasiaupsilonmacrondasiavariaupsilonmacrondasiaoxiaupsilonbrevevariaupsilonbreveoxiaupsilonbrevedialytikaoxiaupsilonbrevepsiliupsilonbrevepsilivariaupsilonbrevepsilioxiaupsilonbrevedasiaupsilonbrevedasiavariaupsilonbrevedasiaoxiaAlphamacronvariaAlphamacronoxiaAlphamacronpsiliAlphamacronpsilivariaAlphamacronpsilioxiaAlphamacrondasiaAlphamacrondasiavariaAlphamacrondasiaoxiaAlphabrevevariaAlphabreveoxiaAlphabrevepsiliAlphabrevepsilivariaAlphabrevepsilioxiaAlphabrevedasiaAlphabrevedasiavariaAlphabrevedasiaoxiaIotamacronvariaIotamacronoxiaIotamacrondialytikaoxiaIotamacronpsiliIotamacronpsilivariaIotamacronpsilioxiaIotamacrondasiaIotamacrondasiavariaIotamacrondasiaoxiaIotabrevevaria IotabreveoxiaIotabrevedialytikaoxiaIotabrevepsiliIotabrevepsilivariaIotabrevepsilioxiaIotabrevedasiaIotabrevedasiavariaIotabrevedasiaoxiaUpsilonmacronvariaUpsilonmacronoxiaUpsilonmacrondialytikaoxiaUpsilonmacronpsiliUpsilonmacronpsilivariaUpsilonmacronpsilioxiaUpsilonmacrondasiaUpsilonmacrondasiavariaUpsilonmacrondasiaoxiaUpsilonbrevevariaUpsilonbreveoxiaUpsilonbrevedialytikaoxiaUpsilonbrevepsiliUpsilonbrevepsilivariaUpsilonbrevepsilioxiaUpsilonbrevedasiaUpsilonbrevedasiavariaUpsilonbrevedasiaoxiauni211Duni2115 UpsilonpsiliUpsilonpsilivariaUpsilonpsilioxia Alphamacron Alphabreve Iotamacron Iotabreve Upsilonmacron Upsilonbreveu1D160quotesinglbase.mirrorquotedblbase.mirrorquoteleftreversed.mirrorquotedblleftaltone.mirror+uvvwabbccdde 2LDFLTlatnligartlaJ" !@>`^}mmlk`eigjC" !>@^`m}C`egijklm LOI 0>DFLTlatnkern.<Bhv8n$7<i 7i9i: 0, but it # doesn't declare constraints on it. Unclear if/how we should validate. font, font_size = cls._get_tokens(idx, tokens) return cls(font, float(font_size)) class Text(metaclass=TupleCommand): COMMAND = 'Tj' ARGS = ['text'] def resolve(self): return '({}) {}'.format(self.text, self.COMMAND) class XObject(metaclass=TupleCommand): COMMAND = 'Do' ARGS = ['name'] def resolve(self): return '/{} {}'.format(self.name, self.COMMAND) class GraphicsState(metaclass=TupleCommand): COMMAND = 'gs' ARGS = ['name'] def resolve(self): return '/{} {}'.format(self.name, self.COMMAND) class Rect(metaclass=FloatTupleCommand): COMMAND = 're' ARGS = ['x', 'y', 'width', 'height'] def transform(self, t): x, y = transform_point((self.x, self.y), t) width, height = transform_vector((self.width, self.height), t) return Rect(x, y, width, height) class Move(metaclass=FloatTupleCommand): COMMAND = 'm' ARGS = ['x', 'y'] def transform(self, t): x, y = transform_point((self.x, self.y), t) return Move(x, y) class Line(metaclass=FloatTupleCommand): COMMAND = 'l' ARGS = ['x', 'y'] def transform(self, t): x, y = transform_point((self.x, self.y), t) return Line(x, y) class Bezier(metaclass=FloatTupleCommand): """Cubic bezier curve, from the current point to (x3, y3), using (x1, y1) and (x2, y2) as control points. """ COMMAND = 'c' ARGS = ['x1', 'y1', 'x2', 'y2', 'x3', 'y3'] def transform(self, t): x1, y1 = transform_point((self.x1, self.y1), t) x2, y2 = transform_point((self.x2, self.y2), t) x3, y3 = transform_point((self.x3, self.y3), t) return Bezier(x1, y1, x2, y2, x3, y3) class BezierV(metaclass=FloatTupleCommand): """Cubic bezier curve, from the current point to (x3, y3), using (x2, y2) and (x3, y3) as control points. """ COMMAND = 'v' ARGS = ['x2', 'y2', 'x3', 'y3'] def transform(self, t): x2, y2 = transform_point((self.x2, self.y2), t) x3, y3 = transform_point((self.x3, self.y3), t) return BezierV(x2, y2, x3, y3) class BezierY(metaclass=FloatTupleCommand): """Cubic bezier curve, from the current point to (x3, y3), using (x1, y1) and (x3, y3) as control points. """ COMMAND = 'y' ARGS = ['x1', 'y1', 'x3', 'y3'] def transform(self, t): x1, y1 = transform_point((self.x1, self.y1), t) x3, y3 = transform_point((self.x3, self.y3), t) return BezierY(x1, y1, x3, y3) class MatrixCommand(TupleCommand): def __new__(cls, name, parents, attrs): attrs['ARGS'] = ['matrix'] attrs['NUM_ARGS'] = 6 return super(MatrixCommand, cls).__new__(cls, name, parents, attrs) def __init__(cls, name, parents, attrs): def transform(self, t): return cls(matrix_multiply(t, self.matrix)) def resolve(self): return ' '.join([format_number(n) for n in self.matrix] + [self.COMMAND]) @classmethod def from_tokens(cls, idx, tokens): return cls([float(tok) for tok in cls._get_tokens(idx, tokens)]) def __init__(self, matrix): if len(matrix) != 6: raise ValueError('go away you bad dude') setattr(cls, 'transform', transform) setattr(cls, 'resolve', resolve) setattr(cls, 'from_tokens', from_tokens) setattr(cls, '__init__', __init__) class TextMatrix(metaclass=MatrixCommand): COMMAND = 'Tm' class CTM(metaclass=MatrixCommand): COMMAND = 'cm' def format_number(n): # Really small numbers should just be rounded to 0 if -ZERO_TOLERANCE <= n <= ZERO_TOLERANCE: return '0' # Cut off unnecessary decimals if n % 1 == 0: return str(int(n)) # Otherwise return 10 decimal places, but remove trailing zeros. I wish I # could use 'g' for this, but that switches to scientific notation at # certain thresholds. string = '{:.10f}'.format(n) i = len(string) - 1 while string[i] == '0': i -= 1 return string[:i + 1] def quadratic_to_cubic_bezier( start_x, start_y, control_x, control_y, end_x, end_y ): """Make a cubic bezier curve from the parameters of a quadratic bezier. This is necessary because PDF doesn't have quadratic beziers. """ cp1x = start_x + 2 / 3 * (control_x - start_x) cp1y = start_y + 2 / 3 * (control_y - start_y) cp2x = end_x + 2 / 3 * (control_x - end_x) cp2y = end_y + 2 / 3 * (control_y - end_y) return Bezier(cp1x, cp1y, cp2x, cp2y, end_x, end_y) endesive-2.19.1/endesive/pdf/PyPDF2_annotate/pdfrw.py000066400000000000000000000030671504236674500223740ustar00rootroot00000000000000from endesive.pdf.PyPDF2 import generic as pdf def makeObject(obj): if isinstance(obj, pdf.PdfObject): return obj if isinstance(obj, int): return pdf.NumberObject(obj) if isinstance(obj, float): return pdf.NumberObject(obj) if isinstance(obj, str): return pdf.createStringObject(obj) if isinstance(obj, (list, tuple)): result = pdf.ArrayObject() for v in obj: v = makeObject(v) result.append(v) return result if isinstance(obj, dict): result = PdfDict() for k, v in obj.items(): v = makeObject(v) result[k] = v return result raise ValueError("can`t convert to PdfObject", obj) class PdfDict(pdf.DictionaryObject): indirect = False stream = None def __init__(self, *args, **kwargs): super(PdfDict, self).__init__({}) for k, v in kwargs.items(): self[k] = v def __setitem__(self, k, v): if k == "stream": if isinstance(v, str): v = v.encode("latin1") self.stream = v return if not isinstance(k, pdf.NameObject): k = PdfName(k) v = makeObject(v) super(PdfDict, self).__setitem__(k, v) class IndirectPdfDict(PdfDict): indirect = True def PdfName(name): return pdf.NameObject("/" + name) def PdfString(s): return pdf.createStringObject(s) def PdfArray(l): result = pdf.ArrayObject([]) for v in l: v = makeObject(v) result.append(v) return result endesive-2.19.1/endesive/pdf/PyPDF2_annotate/pdfttf.py000066400000000000000000000206351504236674500225410ustar00rootroot00000000000000import os import re import zlib from ..fpdf.ttfonts import TTFontFile from .pdfrw import PdfDict, PdfName, PdfString, PdfArray, IndirectPdfDict class TTFFont: def __init__(self, ttffilename): self.size = 12 self.font = None ttf = TTFontFile() ttf.getMetrics(ttffilename) desc = { "Ascent": int(round(ttf.ascent, 0)), "Descent": int(round(ttf.descent, 0)), "CapHeight": int(round(ttf.capHeight, 0)), "Flags": ttf.flags, "FontBBox": ( int(round(ttf.bbox[0], 0)), int(round(ttf.bbox[1], 0)), int(round(ttf.bbox[2], 0)), int(round(ttf.bbox[3], 0)), ), "ItalicAngle": int(ttf.italicAngle), "StemV": int(round(ttf.stemV, 0)), "MissingWidth": int(round(ttf.defaultWidth, 0)), } font_dict = { "type": "TTF", "name": re.sub("[ ()]", "", ttf.fullName), "desc": desc, "up": round(ttf.underlinePosition), "ut": round(ttf.underlineThickness), "cw": ttf.charWidths, "ttffile": ttffilename, # "fontkey": fontkey, "originalsize": os.stat(ttffilename).st_size, "subset": set(range(0, 32)), } self.font = font_dict def font_widths(self, font, maxUni): rangeid = 0 range_ = {} range_interval = {} prevcid = -2 prevwidth = -1 interval = False startcid = 1 cwlen = maxUni + 1 # for each character for cid in range(startcid, cwlen): if font["cw"][cid] == 0: continue width = font["cw"][cid] if width == 65535: width = 0 if cid > 255 and (cid not in font["subset"]) or not cid: # continue if "dw" not in font or (font["dw"] and width != font["dw"]): if cid == (prevcid + 1): if width == prevwidth: if width == range_[rangeid][0]: range_.setdefault(rangeid, []).append(width) else: range_[rangeid].pop() # new range rangeid = prevcid range_[rangeid] = [prevwidth, width] interval = True range_interval[rangeid] = True else: if interval: # new range rangeid = cid range_[rangeid] = [width] else: range_[rangeid].append(width) interval = False else: rangeid = cid range_[rangeid] = [width] interval = False prevcid = cid prevwidth = width prevk = -1 nextk = -1 prevint = False for k, ws in sorted(range_.items()): cws = len(ws) if k == nextk and not prevint and (not k in range_interval or cws < 3): if k in range_interval: del range_interval[k] range_[prevk] = range_[prevk] + range_[k] del range_[k] else: prevk = k nextk = k + cws if k in range_interval: prevint = cws > 3 del range_interval[k] nextk -= 1 else: prevint = False w = [] for k, ws in sorted(range_.items()): if len(set(ws)) == 1: w.extend((k, k + len(ws) - 1, ws[0])) else: w.extend((k, ws)) return w def get_font(self): font = self.font # Font objects ttf = TTFontFile() fontname = "MPDFAA" + "+" + font["name"] subset = font["subset"].difference(set([0])) ttfontstream = ttf.makeSubset(font["ttffile"], subset) ttfontstream = zlib.compress(ttfontstream) codeToGlyph = ttf.codeToGlyph ##del codeToGlyph[0] # Font file FontFile2 = IndirectPdfDict(stream=ttfontstream, Filter=PdfName("FlateDecode")) # CIDSystemInfo dictionary CIDSystemInfo = IndirectPdfDict( Registry=PdfString("Adobe"), Ordering=PdfString("UCS"), Supplement=0 ) # Font descriptor FontDescriptor = IndirectPdfDict( Type=PdfName("FontDescriptor"), FontName=PdfName(fontname), Flags=(font["desc"]["Flags"] | 4) & ~32, FontBBox=font["desc"]["FontBBox"], ItalicAngle=font["desc"]["ItalicAngle"], Ascent=font["desc"]["Ascent"], Descent=font["desc"]["Descent"], CapHeight=font["desc"]["CapHeight"], StemV=font["desc"]["StemV"], MissingWidth=font["desc"]["MissingWidth"], FontFile2=FontFile2, ) # Embed CIDToGIDMap # A specification of the mapping from CIDs to glyph indices cidtogidmap = ["\x00"] * 256 * 256 * 2 for cc, glyph in codeToGlyph.items(): cidtogidmap[cc * 2] = chr(glyph >> 8) cidtogidmap[cc * 2 + 1] = chr(glyph & 0xFF) cidtogidmap = "".join(cidtogidmap) # manage binary data as latin1 until PEP461-like function is implemented cidtogidmap = cidtogidmap.encode("latin1") cidtogidmap = zlib.compress(cidtogidmap) CIDToGIDMap = IndirectPdfDict(stream=cidtogidmap, Filter=PdfName("FlateDecode")) # CIDFontType2 # A CIDFont whose glyph descriptions are based on TrueType font technology CIDFontType2 = IndirectPdfDict( Type=PdfName("Font"), Subtype=PdfName("CIDFontType2"), BaseFont=PdfName(fontname), CIDSystemInfo=CIDSystemInfo, FontDescriptor=FontDescriptor, W=PdfArray(self.font_widths(font, ttf.maxUni)), CIDToGIDMap=CIDToGIDMap, ) if font["desc"].get("MissingWidth"): CIDFontType2[PdfName("DW")] = font["desc"]["MissingWidth"] # ToUnicode ToUnicode = IndirectPdfDict( stream="\n".join( ( "/CIDInit /ProcSet findresource begin", "12 dict begin", "begincmap", "/CIDSystemInfo", "<> def", "/CMapName /Adobe-Identity-UCS def", "/CMapType 2 def", "1 begincodespacerange", "<0000> ", "endcodespacerange", "1 beginbfrange", "<0000> <0000>", "endbfrange", "endcmap", "CMapName currentdict /CMap defineresource pop", "end", "end", ) ) ) # Type0 Font # A composite font - a font composed of other fonts, organized hierarchically Type0 = IndirectPdfDict( Type=PdfName("Font"), Subtype=PdfName("Type0"), BaseFont=PdfName(fontname), Encoding=PdfName("Identity-H"), DescendantFonts=PdfArray([CIDFontType2]), ToUnicode=ToUnicode, ) return Type0 def set_size(self, pt): self.size = pt def set_text(self, text): uni = set([ord(c) for c in text]) self.font["subset"] = self.font["subset"].union(uni) def measure_text(self, text): "Get width of a string in the current font" cw = self.font["cw"] w = 0 l = len(text) for char in text: char = ord(char) if len(cw) > char: w += cw[char] # ord(cw[2*char])<<8 + ord(cw[2*char+1]) # elif (char>0 and char<128 and isset($cw[chr($char)])) { $w += $cw[chr($char)]; } elif self.font["desc"]["MissingWidth"]: w += self.font["desc"]["MissingWidth"] # elif (isset($this->CurrentFont['MissingWidth'])) { $w += $this->CurrentFont['MissingWidth']; } else: w += 500 return w * self.size / 1000.0 endesive-2.19.1/endesive/pdf/PyPDF2_annotate/util/000077500000000000000000000000001504236674500216475ustar00rootroot00000000000000endesive-2.19.1/endesive/pdf/PyPDF2_annotate/util/__init__.py000066400000000000000000000000001504236674500237460ustar00rootroot00000000000000endesive-2.19.1/endesive/pdf/PyPDF2_annotate/util/font_metrics.py000066400000000000000000000025331504236674500247200ustar00rootroot00000000000000# -*- coding: utf-8 -*- """ Font Metrics Utils ~~~~~~~~~~ :copyright: Copyright 2019 Autodesk, Inc. :license: MIT, see LICENSE for details. """ import attr from .validation import Number, List, Dict @attr.s class FontMetrics: """ Class to hold our font metric calculations. """ italicAngle = Number(default=0) usWeightClass = Number(default=500) isFixedPitch = Number(default=0) unitsPerEm = Number(default=1000) scale = Number(default=float(1)) bbox = List(default=[]) ascent = Number(default=None) descent = Number(default=None) capHeight = Number(default=None) stemV = Number(default=None) defaultWidth = Number(default=None) widths = List(default=[]) cmap = Dict(default={}) @property def flags(self): """ See Section 9.8.2 - Font Descriptor Flags of PDF 1.7 Spec Bit 1 - FixedPitch Bit 2 - Serif Bit 3 - Symbolic Bit 4 - Script Bit 6 - Nonsymbolic Bit 7 - Italic Bit 17 - AllCap Bit 18 - SmallCap Bit 19 - ForceBold :return: """ flags = 4 if self.italicAngle != 0: flags = flags | 64 if self.usWeightClass >= 600: flags = flags | 262144 if self.isFixedPitch: flags = flags | 1 return flags endesive-2.19.1/endesive/pdf/PyPDF2_annotate/util/geometry.py000066400000000000000000000105361504236674500240610ustar00rootroot00000000000000# -*- coding: utf-8 -*- """ Geometry ~~~~~~~~ Geometry utility functions :copyright: Copyright 2019 Autodesk, Inc. :license: MIT, see LICENSE for details. """ import math def normalize_rotation(rotate): if rotate % 90: raise ValueError('Invalid Rotate value: {}'.format(rotate)) while rotate < 0: rotate += 360 while rotate >= 360: rotate -= 360 return rotate def to_radians(degrees): return degrees * math.pi / 180 def rotate(degrees): """Return a homogenous rotation matrix by degrees :params int degrees: integer degrees :returns list: matrix rotated by degrees, 6-item list """ radians = to_radians(degrees) return [ math.cos(radians), math.sin(radians), -math.sin(radians), math.cos(radians), 0, 0, ] def translate(x, y): return [1, 0, 0, 1, x, y] def scale(x_scale, y_scale): return [x_scale, 0, 0, y_scale, 0, 0] def identity(): return [1, 0, 0, 1, 0, 0] def matrix_multiply(*args): """Multiply a series of matrices. len(args) must be at least two. If more than two matrices are specified, the multiplications are chained, with the left-most matrices being multiplied first. E.g. matrix_multiply(A, B, C) => (A*B)*C What this means for combining affine transformations is that they are applied in reverse order. For instance, to perform rotation R, scale S, and translation T, in that order, you would use: matrix_multiply(T, S, R) Each matrix is a 6-item homogenous matrix. """ if len(args) < 2: raise ValueError('Cannot multiply fewer than two matrices') r = _matrix_multiply(args[0], args[1]) for m in args[2:]: r = _matrix_multiply(r, m) return r def matrix_inverse(matrix): """Invert a 6-item homogenous transform matrix. A transform matrix [a, b, c, d, e, f] is part of a 3x3 matrix: a b 0 c d 0 e f 1 Invert it using the formula for the inverse of a 3x3 matrix from http://mathworld.wolfram.com/MatrixInverse.html """ a, b, c, d, e, f = matrix determinant = float(a * d - b * c) unscaled = [d, -b, -c, a, c * f - d * e, b * e - a * f] return [x / determinant for x in unscaled] def _matrix_multiply(A, B): a00, a01, a10, a11, a20, a21 = A b00, b01, b10, b11, b20, b21 = B b02, b12, b22 = 0, 0, 1 # We don't have to compute all entries of the new matrix during # multiplication, since any multiple of affine transformations is an affine # transformation, and therefore homogenous coordinates. c00 = b00 * a00 + b01 * a10 + b02 * a20 c01 = b00 * a01 + b01 * a11 + b02 * a21 c10 = b10 * a00 + b11 * a10 + b12 * a20 c11 = b10 * a01 + b11 * a11 + b12 * a21 c20 = b20 * a00 + b21 * a10 + b22 * a20 c21 = b20 * a01 + b21 * a11 + b22 * a21 return [c00, c01, c10, c11, c20, c21] def transform_point(point, matrix): """Transform point by matrix. :param list point: 2-item list :param list matrix: 6-item list representing transformation matrix :returns list: 2-item transformed point """ x, y = point a, b, c, d, e, f = matrix # This leaves out some unnecessary stuff from the fact that the matrix is # homogenous coordinates. new_x = x * a + y * c + e new_y = x * b + y * d + f return [new_x, new_y] def transform_vector(vector, matrix): """Transform a vector by a matrix. This is similar to transform_point, except that translation isn't honored. Think of a vector as displacement in space, and a point as, well, a point in space. :param list vector: 2-item list :param list matrix: 6-item list representing transformation matrix :returns list: 2-item transformed point """ x, y = vector a, b, c, d, _, _ = matrix new_x = x * a + y * c new_y = x * b + y * d return [new_x, new_y] def transform_rect(rect, matrix): """Transform a rectangle specified by two points (lower left and upper right) by a transformation matrix. :param list rect: [x1, y1, x2, y2] :param list matrix: transformation matrix :returns list: [x1, y1, x2, y2] with transformed points """ x1, y1 = transform_point(rect[:2], matrix) x2, y2 = transform_point(rect[2:], matrix) x1, x2 = sorted([x1, x2]) y1, y2 = sorted([y1, y2]) return [x1, y1, x2, y2] endesive-2.19.1/endesive/pdf/PyPDF2_annotate/util/text.py000066400000000000000000000071451504236674500232140ustar00rootroot00000000000000# -*- coding: utf-8 -*- """ Text Utils ~~~~~~~~~~ :copyright: Copyright 2019 Autodesk, Inc. :license: MIT, see LICENSE for details. """ def unshift_token(text): """Remove a token from the front of a string. :param str text: :returns: {'text': str, 'separator': str, 'remainder': str} """ if len(text) == 0: return {'text': text, 'separator': '', 'remainder': ''} token = '' for i in range(0, len(text)): char = text[i] if (char == ' ' and (len(token) >= 1 and token[i - 1] == ' ')): token += char elif (char == ' ' and len(token) == 0): token += char elif char == ' ': return {'text': token, 'separator': ' ', 'remainder': text[i + 1:]} elif char == '\n': return { 'text': token, 'separator': '\n', 'remainder': text[i + 1:], } elif (len(token) >= 1 and token[i - 1] == ' '): return { 'text': token, 'separator': '', 'remainder': text[len(token):], } else: token += char return {'text': token, 'separator': '', 'remainder': ''} def unshift_line(text, measure, max_length): """Remove a line of text from a string. :param str text: text to be broken :param func measure: function that takes a string and returns its width :param int max_length: max width of each line :returns: {'text': str, 'remainder': str} """ line = '' token = {'text': '', 'separator': '', 'remainder': text} while True: token = unshift_token(token['remainder']) token_text = token['text'] remainder = token['remainder'] separator = token['separator'] if len(line) == 0: if len(token_text) > 0: # This allows us to add partial tokens for the first token for char in token_text: if measure(line + char) > max_length: line = char if len(line) == 0 else line return { 'text': line, 'remainder': text[len(line):], } else: line += char if separator == '\n': return {'text': line, 'remainder': remainder} line += separator else: return { 'text': line, 'remainder': text[len(line) + len(separator):], } else: if measure(line + token_text) <= max_length: line += token_text if separator == '\n' or remainder == '': return {'text': line, 'remainder': remainder} else: line += separator else: return {'text': line, 'remainder': text[len(line):]} def get_wrapped_lines(text, measure, max_length): """Break a string of text into lines wrapped to max_length. The algorithm is the same one used in the PGBS TextElement in web-viewer, to maintain consistency in line breaks. :param str text: text to be broken :param func measure: function that takes a string and returns its width :param int max_length: max width of each line :returns: list of strings """ line = unshift_line(text, measure, max_length) lines = [line['text']] while (len(line['remainder']) > 0): line = unshift_line(line['remainder'], measure, max_length) lines.append(line['text']) return lines endesive-2.19.1/endesive/pdf/PyPDF2_annotate/util/true_type_font.py000066400000000000000000000166351504236674500253020ustar00rootroot00000000000000# -*- coding: utf-8 -*- """ True Type Fonts Utility Class ~~~~~~~~~~ :copyright: Copyright 2019 Autodesk, Inc. :license: MIT, see LICENSE for details. """ from fontTools.ttLib import TTFont from .font_metrics import FontMetrics _FONT_CACHE = {} def get_true_type_font(path, font_name, font_size=None): """Helper to avoid having to reload font from disk multiple times in a session :param str path: path to .ttf font file :param str font_name: name of the font to be included in the PDF file :param int|None font_size: :returns TrueTypeFont: """ key = (path, font_name, font_size) font = _FONT_CACHE.get(key) if font is not None: return font font = TrueTypeFont(path, font_name, font_size) _FONT_CACHE[key] = font return font class TrueTypeFont: """ Used to load a true type font and calculate font metrics from it that are needed to embed the font program in a PDF. """ def __init__(self, path, font_name, font_size=None): self.ttfPath = path self._ttfFont = TTFont(self.ttfPath) # Subsetted fonts have 6 random letters prepended to their names # See section 9.6.4 - Font Subsets of the PDF 1.7 Spec self.fontName = 'RXMLFT+' + font_name self.metrics = self._calculate(self._ttfFont) self._glyph_set = self._ttfFont.getGlyphSet() self._font_size = font_size def get_glyph_id(self, glyph_name): """ Wrapper for getting a glyph name via font tools. :param glyph_name: The name of the glyph we're retrieving. :return: The corresponding glyph ID. """ return self._ttfFont['glyf'].getGlyphID(glyph_name) def measure_text(self, text, font_size=None): """Measure a block of text using the font's metrics. If the text contains characters the font does not define, the .notdef character's width is used. :param str text: The text to measure :param int|None font_size: Font size (in em units) to scale measurements. If missing, self._font_size is used. :returns int: width of text """ font_size = font_size if font_size is not None else self._font_size if font_size is None: raise ValueError('Font size must be specified') total_width = 0 notdef_width = self._glyph_set['.notdef'].width for character in text: # If the cmap doesn't contain the character, this'll just return # None for the glyph and use .notdef glyph = self._glyph_set.get(self.metrics.cmap.get(ord(character))) total_width += glyph.width if glyph is not None else notdef_width # Scale total width by font size return total_width * font_size / self.metrics.unitsPerEm @staticmethod def _calculate(font): """ Calculates metrics about our true type font. These calculations are taken from previous work done in the mpdf/fpdf projects. :param font: The fonttools font object. :return: A FontMetrics object containing the calculated metrics. """ # Font Header Table units_per_em = font['head'].unitsPerEm scale = 1000 / float(units_per_em) x_min = font['head'].xMin y_min = font['head'].yMin x_max = font['head'].xMax y_max = font['head'].yMax bbox = [ (x_min * scale), (y_min * scale), (x_max * scale), (y_max * scale) ] # hhead metrics table, these seem to be used instead of OS/2 for compatibility reasons if 'hhea' in font: ascent = font['hhea'].ascent * scale descent = font['hhea'].descent * scale # OS/2 and Windows metrics table if 'OS/2' in font: us_weight_class = font['OS/2'].usWeightClass if not ascent: ascent = font['OS/2'].sTypoAscender * scale if not descent: descent = font['OS/2'].sTypoDescender * scale if font['OS/2'].version > 1: cap_height = font['OS/2'].sCapHeight * scale else: cap_height = ascent else: us_weight_class = 500 if not ascent: ascent = y_max * scale if not descent: descent = y_min * scale cap_height = ascent stem_v = 50 + int(pow((us_weight_class / 65.0), 2)) # Post table is_fixed_pitch = font['post'].isFixedPitch italic_angle = font['post'].italicAngle # hmtx - contains advance width and left side bearing for each glyph default_width = font['hmtx'].metrics['.notdef'][0] # Character map cmap = font['cmap'].getBestCmap() # Widths glyph_set = font.getGlyphSet() cids = [cid for cid in cmap] if len(cids) <= 0: raise MetricsParsingError("Couldn't find any characters in font") widths = TrueTypeFont._format_widths(glyph_set, cmap, cids) return FontMetrics( italicAngle=italic_angle, usWeightClass=us_weight_class, isFixedPitch=is_fixed_pitch, unitsPerEm=units_per_em, scale=scale, bbox=bbox, ascent=ascent, descent=descent, capHeight=cap_height, stemV=stem_v, defaultWidth=default_width, widths=widths, cmap=cmap, ) @staticmethod def _format_widths(glyph_set, cmap, cids): """ See Section 9.7.4.3 Glyph Metrics in CIDFonts This function will take a uniform list of widths and format it to the PDF compacted format. The widths use one of two formats for each segment. For varying widths: c [w1 w2 .. wn] For constant widths: cfirst clast w ie. [ 120 [ 400 325 500 ] 7080 8032 1000 ] Would have 120 be 400, 121 be 325, 122 be 500 and 7080 to 8032 all be 1000 width :return: A list of lists conforming to the PDF compacted format for widths. """ cids_length = len(cids) if cids_length == 0: return [] cids.sort() start = 0 i = 1 # See Section 9.7.4.3 Glyph Metrics in CIDFonts # The widths use one of two formats for each segment. # For varying widths: c [w1 w2 .. wn] # For constant widths: cfirst clast w # ie. [ 120 [ 400 325 500 ] 7080 8032 1000 ] # Would have 120 be 400, 121 be 325, 122 be 500 and 7080 to 8032 all be 1000 width widths = [] while True: if i >= cids_length or (cids[i] - cids[i - 1] > 1): indices = [x for x in range(cids[start], cids[i - 1] + 1)] w = [glyph_set[cmap[index]].width for index in indices] if len(set(w)) == 1: # Append a 'cfirst clast w' style width to our width segments widths.append(cids[start]) widths.append(cids[i - 1]) widths.append(w[0]) else: # Append a 'c [w1 w2 .. wn]' style width to our width segments widths.append(cids[start]) widths.append(w) # No more ranges if i >= cids_length: break start = i i = i + 1 return widths class MetricsParsingError(Exception): pass endesive-2.19.1/endesive/pdf/PyPDF2_annotate/util/validation.py000066400000000000000000000117371504236674500243640ustar00rootroot00000000000000# -*- coding: utf-8 -*- """ Validation Utils ~~~~~~~~~~~~~~~~ :copyright: Copyright 2019 Autodesk, Inc. :license: MIT, see LICENSE for details. """ import attr NUMERIC_TYPES = (int, float) def Boolean(**kwargs): _add_validator_to_kwargs(kwargs, instance_of(bool)) return attr.ib(**kwargs) def Integer(**kwargs): _add_validator_to_kwargs(kwargs, instance_of(int)) return attr.ib(**kwargs) def Number(**kwargs): _add_validator_to_kwargs(kwargs, is_number()) return attr.ib(**kwargs) def Enum(values, **kwargs): _add_validator_to_kwargs(kwargs, one_of(values)) return attr.ib(**kwargs) def String(**kwargs): _add_validator_to_kwargs(kwargs, instance_of(str)) return attr.ib(**kwargs) def List(**kwargs): _add_validator_to_kwargs(kwargs, instance_of(list)) return attr.ib(**kwargs) def Dict(**kwargs): _add_validator_to_kwargs(kwargs, instance_of(dict)) return attr.ib(**kwargs) def Color(**kwargs): """Color value. Can be specified as three-item list/tuple (RGB) or four- item list/tuple (RGBA). """ _add_validator_to_kwargs(kwargs, is_color()) return attr.ib(**kwargs) def Points(**kwargs): _add_validator_to_kwargs(kwargs, is_points_list()) return attr.ib(**kwargs) def Field(allowed_type, **kwargs): """Generic field, e.g. Field(ContentStream).""" _add_validator_to_kwargs(kwargs, instance_of(allowed_type)) return attr.ib(**kwargs) def is_points_list(): def validate(obj, attr, value): if isinstance(value, (list, tuple)): for point in value: if len(point) != 2 or not ( isinstance(point[0], NUMERIC_TYPES) and isinstance(point[1], NUMERIC_TYPES) ): raise ValueError( 'Value ({}) must be a list of points'.format(value) ) elif value is not None: raise ValueError( 'Value ({}) must be a list of points'.format(value) ) return validate def greater_than_eq(i): def validate(obj, attr, value): if value is not None and not value >= i: raise ValueError('Value ({}) must be >= than {}'.format(value, i)) return validate positive = greater_than_eq(0) def between(a, b): def validate(obj, attr, value): if value is not None and not (a <= value <= b): raise ValueError( 'Value ({}) must be between {} and {}'.format(value, a, b) ) return validate def instance_of(types): def validate(obj, attr, value): if value is not None and not isinstance(value, _tupleize(types)): raise ValueError( 'Value ({}) must be of type ({})'.format(value, types) ) return validate def is_number(): def validate(obj, attr, value): if value is not None and not isinstance(value, NUMERIC_TYPES): raise ValueError('Value ({}) must be numeric'.format(value)) return validate def one_of(values): def validate(obj, attr, value): if value is not None and value not in values: raise ValueError( 'Value ({}) must be in ({})'.format(value, values) ) return validate def is_color(): def validate(obj, attr, value): if isinstance(value, (list, tuple)): if len(value) not in (3, 4): raise ValueError( 'Value ({}) is not a RGB(A) color'.format(value) ) for component in value: if not ( isinstance(component, NUMERIC_TYPES) and component >= 0 and component <= 1 ): raise ValueError( 'Value ({}) is not a RGB(A) color'.format(value) ) elif value is not None: raise ValueError('Value ({}) is not a RGB(A) color'.format(value)) return validate def validate_dash_array(obj, attr, value): msg = ( 'Value ({}) must be a dash array of the form ' '[dash_array, dash_phase], where dash_array is a list of integers,' ' and dash_phase is an integer' ) if isinstance(value, list): if ( len(value) != 2 or not isinstance(value[0], list) or any(not isinstance(x, int) for x in value[0]) or not isinstance(value[1], int) ): raise ValueError(msg.format(value)) elif value is not None: raise ValueError(msg.format(value)) def _listify(v): if isinstance(v, tuple): return list(v) elif not isinstance(v, list): return [v] return v def _tupleize(v): if isinstance(v, list): return tuple(v) elif not isinstance(v, tuple): return (v,) return v def _add_validator_to_kwargs(kwargs, validator): existing = _listify(kwargs.pop('validator', [])) existing.append(validator) kwargs['validator'] = existing endesive-2.19.1/endesive/pdf/__init__.py000066400000000000000000000001141504236674500201020ustar00rootroot00000000000000from . import cms from . import pdf from .verify import PDFVerifier, verify endesive-2.19.1/endesive/pdf/cms.py000066400000000000000000001241721504236674500171400ustar00rootroot00000000000000#!/usr/bin/env vpython3 import sys import time import random import io import struct import datetime import hashlib import codecs import struct from cryptography.hazmat import backends from cryptography.hazmat.primitives import serialization from cryptography.hazmat.primitives.serialization import pkcs12 from cryptography.hazmat.primitives.asymmetric import ec from cryptography.x509 import ObjectIdentifier from endesive import signer from endesive.pdf.PyPDF2 import pdf, generic as po def EncodedString(s): return po.createStringObject(codecs.BOM_UTF16_BE + s.encode("utf-16be")) class UnencryptedBytes(po.utils.bytes_type, po.PdfObject): original_bytes = property(lambda self: self) def writeToStream(self, stream, encryption_key): stream.write(b"<") stream.write(self) stream.write(b">") class WNumberObject(po.NumberObject): Format = b"%08d" def writeToStream(self, stream, encryption_key): stream.write(self.Format % self) class SignedData(pdf.PdfFileWriter): def encrypt(self, prev, password, rc): encrypt = prev.trailer["/Encrypt"].getObject() if encrypt["/V"] == 2: rev = 3 keylen = 128 // 8 else: rev = 2 keylen = 40 // 8 P = encrypt["/P"].getObject() O = encrypt["/O"].getObject() ID_1 = prev.trailer["/ID"].getObject()[0] real_U = encrypt["/U"].getObject().original_bytes if rev == 2: U, key = pdf._alg34(password, O, P, ID_1) else: assert rev == 3 U, key = pdf._alg35( password, rev, keylen, O, P, ID_1, encrypt.get("/EncryptMetadata", pdf.BooleanObject(False)).getObject(), ) U, real_U = U[:16], real_U[:16] assert U == real_U self._encrypt_key = key def write(self, stream, prev, startdata): stream.write(pdf.b_("\r\n")) positions = {} for i in range(len(self._objects)): idnum = i + 1 obj = self._objects[i] if obj is None: positions[idnum] = 0 continue positions[idnum] = startdata + stream.tell() stream.write(pdf.b_(str(idnum) + " 0 obj\n")) key = None if self._encrypt_key is not None: pack1 = struct.pack("q", offset) dataindex = ["0 1"] dataxref = [b"\x00" + pack(0)] keys = sorted(positions.keys()) i = 0 while i < len(keys): off = positions[keys[i]] if off != 0: start = i while i < len(keys) and positions[keys[i]] != 0: dataxref.append(b"\x01" + pack(positions[keys[i]])) i += 1 dataindex.append("%d %d" % (keys[start], i - start)) else: i += 1 dataindex = " ".join(dataindex) dataxref = b"".join(dataxref) trailer[po.NameObject("/Type")] = po.NameObject("/XRef") trailer[po.NameObject("/W")] = po.NameObject("[1 8 0]") trailer[po.NameObject("/Index")] = po.NameObject("[%s]" % dataindex) trailer._data = dataxref retval = trailer.flateEncode() trailer.update(retval) trailer._data = retval._data stream.write(pdf.b_("%d 0 obj\n" % (len(self._objects)))) trailer.writeToStream(stream, None) stream.write(pdf.b_("\nendobj")) # eof stream.write(pdf.b_("\nstartxref\n%s\n%%%%EOF\n" % (xref_location))) def _extend(self, obj): stream = getattr(obj, "stream", None) if stream is not None: # stream = stream.encode("utf-16be") d = {"__streamdata__": stream, "/Length": len(stream)} d.update(obj) dct = pdf.StreamObject.initializeFromDictionary(d) if "/Filter" in obj and obj["/Filter"] == "/FlatDecode": del dct["/Filter"] dct = dct.flateEncode() else: dct = pdf.DictionaryObject() for k, v in obj.items(): if isinstance(v, pdf.DictionaryObject): if v.indirect: v = self._extend(v) v = self._addObject(v) else: v = self._extend(v) elif isinstance(v, list): result = pdf.ArrayObject() for va in v: if isinstance(va, pdf.DictionaryObject): if va.indirect: va = self._extend(va) va = self._addObject(va) else: va = self._extend(va) result.append(va) v = result dct[k] = v return dct def _make_signature(self, Contents=None, Type=None, SubFilter=None): sig = po.DictionaryObject() sig_ref = self._addObject(sig) sig.update( { po.NameObject("/Type"): Type, po.NameObject("/Filter"): po.NameObject("/Adobe.PPKLite"), po.NameObject("/SubFilter"): SubFilter, po.NameObject("/ByteRange"): po.ArrayObject( [ WNumberObject(0), WNumberObject(0), WNumberObject(0), WNumberObject(0), ] ), po.NameObject("/Contents"): Contents, } ) return sig, sig_ref def _make_sig_annotation(self, F=None, Vref=None, T=None, Pref=None): annot = po.DictionaryObject() annot_ref = self._addObject(annot) annot.update( { po.NameObject("/FT"): po.NameObject("/Sig"), po.NameObject("/Type"): po.NameObject("/Annot"), po.NameObject("/Subtype"): po.NameObject("/Widget"), po.NameObject("/F"): F, po.NameObject("/T"): T, po.NameObject("/V"): Vref, po.NameObject("/P"): Pref, # For an invisible signature, /Rect should be a size 0 box # Defaulting to that po.NameObject("/Rect"): po.ArrayObject( [ po.FloatObject(0.0), po.FloatObject(0.0), po.FloatObject(0.0), po.FloatObject(0.0), ] ), } ) return annot, annot_ref def addAnnotation(self, cert, udct, box, page0ref, obj13, obj13ref, new_13): from endesive.pdf.PyPDF2_annotate.annotations.signature import Signature from endesive.pdf.PyPDF2_annotate.config.appearance import Appearance from endesive.pdf.PyPDF2_annotate.config.location import Location from endesive.pdf.PyPDF2_annotate.util.geometry import identity x1, y1, x2, y2 = box annotation = Signature( Location(x1=x1, y1=y1, x2=x2, y2=y2, page=0), Appearance() ) if "signature" in udct: # Plain text signature with the default font # text to render is contained in udct['signature'] # font parameters are in udct['signature']['text'] annotationtext = udct["signature"] wrap_text = udct.get("text", {}).get("wraptext", True) font_size = udct.get("text", {}).get("fontsize", 12) text_align = udct.get("text", {}).get("textalign", "left") line_spacing = udct.get("text", {}).get("linespacing", 1.2) annotation.add_default_font() annotation.set_signature_appearance( ["fill_colour", 0, 0, 0], ["font", "default", font_size], [ "text_box", annotationtext, "default", 0, 0, x2 - x1, y2 - y1, font_size, wrap_text, text_align, "middle", line_spacing, ], ) elif "signature_img" in udct: # Simple image signature, stretches to fit the box # image to render is contained in udct['signature_image'] annotation.add_image(udct["signature_img"], "Image") annotation.set_signature_appearance( [ "image", "Image", 0, 0, x2 - x1, y2 - y1, udct.get("signature_img_distort", True), udct.get("signature_img_centred", False), ] ) elif "signature_appearance" in udct: # Adobe-inspired signature with text and images # Parameters are contained in udct['signature_appearance'] # If a field is included in the display list, that field # will be contained in the annotation. # # Text and border are the colour specified by outline, # and border is the the inset distance from the outer # edge of the annotation. The R G B values range between # 0 and 1. # # Icon is an image to display above the background and # border at the left-hand side of the anntoation. If # there is no text, it is centred. # # The text block is left-aligned to the right of the icon # image. If there is no image, the text is left-aliged # with the left-hand border of the annotation # # display fields: # CN, DN, date, contact, reason, location # # Dict format: # appearance = dict( # background = Image with alpha / None, # icon = Image with alpha / None, # labels = bool, # display = list, # software = str, # outline = [R, G, B], # border = int, # ) sig = {} for f in ("background", "icon", "labels", "border", "outline"): if f in udct["signature_appearance"]: sig[f] = udct["signature_appearance"][f] toggles = udct["signature_appearance"].get("display", []) if(isinstance(toggles, str)): sig["text"] = toggles else: for f in ("contact", "reason", "location", "contact", "signingdate"): if f in toggles: sig[f] = udct.get(f, "{} unknown".format(f)) if "date" in toggles: sig["date"] = udct["signingdate"] if "CN" in toggles: sig["CN"] = cert.subject.get_attributes_for_oid( ObjectIdentifier("2.5.4.3") )[0].value if "DN" in toggles: sig["DN"] = cert.subject.rfc4514_string() annotation.simple_signature(sig) else: # Manual signature annotation creation # # Make your own appearance with an arbitrary number of # images and fonts if "manual_images" in udct: for name, img in udct["manual_images"].items(): annotation.add_image(img, name=name) if "manual_fonts" in udct: for name, path in udct["manual_fonts"].items(): annotation.add_ttf_font(path, name=name) annotation.add_default_font() annotation.set_signature_appearance(*udct["signature_manual"]) pdfa = annotation.as_pdf_object(identity(), page=page0ref) objapn = self._extend(pdfa["/AP"]["/N"]) objapnref = self._addObject(objapn) objap = po.DictionaryObject() objap[po.NameObject("/N")] = objapnref obj13.update( { po.NameObject("/Rect"): po.ArrayObject( [ po.FloatObject(x1), po.FloatObject(y1), po.FloatObject(x2), po.FloatObject(y2), ] ), po.NameObject("/AP"): objap, # po.NameObject("/SM"): po.createStringObject("TabletPOSinline"), } ) page0 = page0ref.getObject() if new_13: annots = po.ArrayObject([obj13ref]) if "/Annots" in page0: page0annots = page0["/Annots"] if isinstance(page0annots, po.IndirectObject): annots.insert(0, page0annots) elif isinstance(page0annots, po.ArrayObject): annots = page0annots annots.append(obj13ref) else: annots = page0["/Annots"] page0.update({po.NameObject("/Annots"): annots}) self._objects[page0ref.idnum - 1] = page0 def makepdf(self, prev, udct, algomd, zeros, cert, othercerts, ocspurl, ocspissuer, **params): catalog = prev.trailer["/Root"] size = prev.trailer["/Size"] pages = catalog["/Pages"].getObject() page0ref = prev.getPage(udct.get("sigpage", 0)).indirectRef self._objects = [] while len(self._objects) < size - 1: self._objects.append(None) if params['mode'] == 'timestamp': # deal with extensions if "/Extensions" not in catalog: extensions = po.DictionaryObject() else: extensions = catalog["/Extensions"] if "/ESIC" not in extensions: extensions.update( { po.NameObject("/ESIC"): po.DictionaryObject( { po.NameObject("/BaseVersion"): po.NameObject("/1.7"), po.NameObject("/ExtensionLevel"): po.NumberObject(1), } ) } ) catalog.update({po.NameObject("/Extensions"): extensions}) else: esic = extensions["/ESIC"] major, minor = esic["/BaseVersion"].lstrip("/").split(".") if int(major) < 1 or int(minor) < 7: esic.update( { po.NameObject("/BaseVersion"): po.NameObject("/1.7"), po.NameObject("/ExtensionLevel"): po.NumberObject(1), } ) SubFilter=po.NameObject("/ETSI.CAdES.detached") else: SubFilter=po.NameObject("/adbe.pkcs7.detached") # obj12 is the digital signature obj12, obj12ref = self._make_signature( Type=po.NameObject("/Sig"), SubFilter=SubFilter, Contents=UnencryptedBytes(zeros), ) obj12.update( { po.NameObject("/Prop_Build"): pdf.DictionaryObject( { po.NameObject("/App"): pdf.DictionaryObject( { po.NameObject("/Name"): po.NameObject( "/" + udct.get("application", "endesive") ) } ), } ), } ) if params["mode"] == "timestamp": # obj12 is a timestamp this time obj12.update( { po.NameObject("/Type"): po.NameObject("/DocTimeStamp"), po.NameObject("/SubFilter"): po.NameObject("/ETSI.RFC3161"), po.NameObject("/V"): po.NumberObject(0), } ) d12 = {} for k, v in ( ('/Name', 'name'), ('/Contact', 'contact'), ('/Location', 'location'), ('/Reason', 'reason'), ): v = udct.get(v, None) if v is not None: d12[po.NameObject(k)] = po.createStringObject(v) if 1 or params.get("use_signingdate"): d12[po.NameObject("/M")] = po.createStringObject(udct["signingdate"]) if d12: obj12.update(d12) # obj13 is a combined AcroForm Sig field with Widget annotation new_13 = True # obj13 = po.DictionaryObject() if udct.get("signform", False): # Attaching signature to existing field in AcroForm if "/AcroForm" in catalog: form = catalog["/AcroForm"].getObject() if "/Fields" in form: fields = form["/Fields"].getObject() obj13ref = [ f for f in fields if f.getObject()["/T"] == udct.get("sigfield", "Signature1") ][0] obj13 = obj13ref.getObject() self._objects[obj13ref.idnum - 1] = obj13 new_13 = False # box is coordinates of the annotation to fill box = udct.get("signaturebox", None) if new_13: obj13, obj13ref = self._make_sig_annotation( F=po.NumberObject(udct.get("sigflagsft", 132)), T=EncodedString(udct.get("sigfield", "Signature1")), Vref=obj12ref, Pref=page0ref, ) else: # original obj13 is a merged SigField/SigAnnot # Setting /V on the AcroForm field sets the signature # for the field obj13.update({po.NameObject("/V"): obj12ref}) # fill the existing signature field annotation, # ignore any other location if "/Rect" in obj13: box = [float(f) for f in obj13["/Rect"]] # add an annotation if there is a field to fill if box is not None: self.addAnnotation(cert, udct, box, page0ref, obj13, obj13ref, new_13) else: # invisible signature objap = po.DictionaryObject() objapref = self._addObject(objap) objform = po.DictionaryObject({ po.NameObject("/Length"): po.NumberObject(0), po.NameObject("/Type"): po.NameObject("/XObject"), po.NameObject("/Subtype"): po.NameObject("/Form"), po.NameObject("/Bbox"): po.ArrayObject([ po.FloatObject(0.0), po.FloatObject(0.0), po.FloatObject(0.0), po.FloatObject(0.0), ]), }) objformref = self._addObject(objform) objap.update({po.NameObject("/N"): objformref}) obj13.update({po.NameObject("/AP"): objapref}) if udct.get("sigandcertify", False) and "/Perms" not in catalog: obj10 = po.DictionaryObject() obj10ref = self._addObject(obj10) obj11 = po.DictionaryObject() obj11ref = self._addObject(obj11) obj14 = po.DictionaryObject() obj14ref = self._addObject(obj14) obj14.update({po.NameObject("/DocMDP"): obj12ref}) obj10.update( { po.NameObject("/Type"): po.NameObject("/TransformParams"), po.NameObject("/P"): po.NumberObject(udct.get("sigflags", 3)), po.NameObject("/V"): po.NameObject("/1.2"), } ) obj11.update( { po.NameObject("/Type"): po.NameObject("/SigRef"), po.NameObject("/TransformMethod"): po.NameObject("/DocMDP"), po.NameObject("/DigestMethod"): po.NameObject("/" + algomd.upper()), po.NameObject("/TransformParams"): obj10ref, } ) obj12[po.NameObject("/Reference")] = po.ArrayObject([obj11ref]) catalog[po.NameObject("/Perms")] = obj14ref if "/AcroForm" in catalog: form = catalog["/AcroForm"].getObject() if "/Fields" in form: fields = form["/Fields"] old_field_names = [f.getObject()["/T"] for f in fields] else: fields = po.ArrayObject() old_field_names = [] if udct.get("auto_sigfield", False) and obj13["/T"] in old_field_names: name_base = udct.get("sigfield", "Signature1") checklist = [ f[len(name_base) :] for f in old_field_names if f.startswith(name_base) ] for i in range(1, len(checklist) + 1): suffix = "_{}".format(i) if suffix in checklist: continue new_name = "{}{}".format(name_base, suffix) obj13.update({po.NameObject("/T"): EncodedString(new_name)}) break old_flags = int(form.get("/SigFlags", 0)) new_flags = int(form.get("/SigFlags", 0)) | udct.get("sigflags", 3) if new_13: fields.append(obj13ref) form.update( { po.NameObject("/Fields"): fields, po.NameObject("/SigFlags"): po.NumberObject(new_flags), } ) elif new_flags > old_flags: form.update({po.NameObject("/SigFlags"): po.NumberObject(new_flags)}) formref = catalog.raw_get("/AcroForm") if isinstance(formref, po.IndirectObject): self._objects[formref.idnum - 1] = form form = formref else: form = po.DictionaryObject() form.update( { po.NameObject("/Fields"): po.ArrayObject([obj13ref]), po.NameObject("/SigFlags"): po.NumberObject( udct.get("sigflags", 3) ), } ) catalog[po.NameObject("/AcroForm")] = form if "/Metadata" in catalog: catalog[po.NameObject("/Metadata")] = catalog.raw_get("/Metadata") if udct.get("ltv", False): dss = po.DictionaryObject() vri = po.DictionaryObject() certs = po.ArrayObject() ocsps = po.ArrayObject() crls = po.ArrayObject() dss.update({ po.NameObject("/Type"): po.NameObject("/DSS"), po.NameObject("/VRI"): vri, po.NameObject("/Certs"): certs, po.NameObject("/OCSPs"): ocsps, po.NameObject("/CRLs"): crls, }) catalog[po.NameObject("/DSS")] = self._addObject(dss) if ocspurl is None: ocspurl = signer.extract_ocsp_url_from_cert(cert) if ocspurl is not None: if ocspissuer is None: for othercert in othercerts: if othercert.subject == cert.issuer: ocspissuer = othercert break certissuer = ocspissuer ocspresp = signer.fetch_ocsp_response(cert, certissuer, ocspurl) if ocspresp is not None: obj = po.StreamObject() obj._data = ocspresp ocsps.append(self._addObject(obj)) obj = po.StreamObject() obj._data = cert.public_bytes(serialization.Encoding.DER) certs.append(self._addObject(obj)) for cert in othercerts: obj = po.StreamObject() obj._data = cert.public_bytes(serialization.Encoding.DER) certs.append(self._addObject(obj)) x_root = prev.trailer.raw_get("/Root") self._objects[x_root.idnum - 1] = catalog self.x_root = po.IndirectObject(x_root.idnum, 0, self) self.x_info = prev.trailer.get("/Info") def sign( self, datau, udct, key, cert, othercerts, algomd, hsm, timestampurl=None, timestampcredentials=None, timestamp_req_options=None, mode="sign", ocspurl=None, ocspissuer=None, use_signingdate=True, ): startdata = len(datau) fi = io.BytesIO(datau) # read end decrypt prev = pdf.PdfFileReader(fi) if prev.isEncrypted: rc = prev.decrypt(udct["password"]) else: rc = 0 # digest method must remain unchanged from prevoius signatures obj = prev.trailer for k in ("/Root", "/Perms", "/DocMDP", "/Reference"): if k in obj: obj = obj[k] if isinstance(obj, po.ArrayObject): obj = obj[0] obj = obj.getObject() else: obj = None break if obj is not None: algomd = obj["/DigestMethod"][1:].lower() # produce smaller signatures, but must be signed twice aligned = udct.get("aligned", 4096 if isinstance(key, ec.EllipticCurvePrivateKey) else 0) if aligned: zeros = b"00" * aligned else: md = getattr(hashlib, algomd)().digest() if mode == "timestamp": contents = signer.timestamp( None, algomd, timestampurl, timestampcredentials, timestamp_req_options, prehashed=md, )[0]["values"][0].dump() else: attrs = udct.get("attrs", True) pss = udct.get("pss", False) contents = signer.sign( None, key, cert, othercerts, algomd, attrs, md, hsm, pss, timestampurl, timestampcredentials, timestamp_req_options, ocspurl, ocspissuer, ) zeros = contents.hex().encode("utf-8") params = {"mode": mode, "use_signingdate": use_signingdate} if not timestampurl: params["use_signingdate"] = True self.makepdf(prev, udct, algomd, zeros, cert, othercerts, ocspurl, ocspissuer, **params) # if document was encrypted, encrypt this version too if prev.isEncrypted: self.encrypt(prev, udct["password"], rc) else: self._encrypt_key = None # ID[0] is used in password protection, must be unchanged ID = prev.trailer.get("/ID", None) if ID is None: ID = udct.get("id") or hashlib.md5(repr(time.time()).encode()).digest() else: ID = ID.getObject()[0].original_bytes newID = udct.get("newid", repr(random.random())) self._ID = po.ArrayObject( [ po.ByteStringObject(ID), po.ByteStringObject(hashlib.md5(newID.encode()).digest()), ] ) fo = io.BytesIO() self.write(fo, prev, startdata) datas = fo.getvalue() br = [0, 0, 0, 0] bfrom = (b"[ " + b" ".join([WNumberObject.Format] * 4) + b" ]") % tuple(br) pdfbr1 = datas.find(zeros) pdfbr2 = pdfbr1 + len(zeros) br = [ 0, startdata + pdfbr1 - 1, startdata + pdfbr2 + 1, len(datas) - pdfbr2 - 1, ] bto = b"[%d %d %d %d]" % tuple(br) bto += b" " * (len(bfrom) - len(bto)) assert len(bfrom) == len(bto) datas = datas.replace(bfrom, bto, 1) md = getattr(hashlib, algomd)() md.update(datau) b1 = datas[: br[1] - startdata] b2 = datas[br[2] - startdata :] md.update(b1) md.update(b2) md = md.digest() if mode == "timestamp": contents = signer.timestamp( None, algomd, timestampurl, timestampcredentials, timestamp_req_options, prehashed=md, )[0]["values"][0].dump() else: attrs = udct.get("attrs", True) pss = udct.get("pss", False) contents = signer.sign( None, key, cert, othercerts, algomd, attrs, md, hsm, pss, timestampurl, timestampcredentials, timestamp_req_options, ocspurl, ocspissuer, ) contents = contents.hex().encode("utf-8") if aligned: nb = len(zeros) - len(contents) contents += b"0" * nb assert len(zeros) == len(contents) datas = datas.replace(zeros, contents, 1) return datas def timestamp( datau, udct, algomd="sha1", timestampurl=None, timestampcredentials=None, timestamp_req_options=None, ): """ parameters: datau: pdf bytes being timestamped udct: dictionary with signing parameters Same paramaters as the sign method. The following parameters should not be used as they are either unused or conflict with normal timestamping: - signform - sigandcertify - contact - location - signingdate - reason Timestamping also does not typically use signature appearances. The following appearance options should probably be omitted, but do not conflict with the normal timestamping operations. - signaturebox - signature - signature_img - signature_img_distort - signature_img_centred - signature_appearance - signature_manual - manual_fonts - manual_images algomd:string default: sha1 - name of the hashing algorithm used to calculate the hash of the document being signed e.g.: sha1, sha256, sha384, sha512, ripemd160 hsm: an instance of endesive.hsm.HSM class used to sign using a hardware token or None timestampurl: timestamp server URL or None timestampcredentials:Dict username and password for authentication against timestamp server. Default: None timestamp_req_options: Dict to set options to the POST http call against the timestamp server. Default: None returns: bytes ready for writing after unsigned pdf document containing its electronic timestamp """ cls = SignedData() return cls.sign( datau, udct, None, # key, None, # cert, None, # othercerts, algomd, None, # hsm, timestampurl, timestampcredentials, timestamp_req_options, mode="timestamp", ) def sign( datau, udct, key, cert, othercerts, algomd="sha1", hsm=None, timestampurl=None, timestampcredentials=None, timestamp_req_options=None, ocspurl=None, ocspissuer=None, ): """ parameters: datau: pdf bytes being signed udct: dictionary with signing parameters aligned: int if 0 then precompute size of signature, but first fake data will be signed !=0 number of hexbytes (00) reserved for signature, must be equal or greather than hex representation of signature probably 16384 will be sufficient .... sigflags: int default:3 1,2,3 - flags for acroform sigflagsft: int default:132 - flags for annotation widget from pdf 12.5.3 sigpage: int default:0 - page on which signature should appear sigfield: string default:Signature1 auto_sigfield: bool default:False False - do not check for sigfield name conflicts True - append and increment suffix to sigfield when a field by the name of sigfield already exists in AcroForm signform: bool default:False False - do not fill in an existing form's signature field True - attach signature to the pre-existing Sig field by the the name provided by sigfield in AcroForm. Use with signature or signature_img, will fill the signature field's widget, ignoring signaturebox. sigandcertify: bool default:False False - sign only document True - sign and certify document signaturebox: box|None default:None - where to put signature image/string on selected page signature: string if box is not None then it should be latin1 encodable string signature_img: string|pil_image if box is not None and string is None then it should be pil image instance or image file name or byte array of image signature_img_distort: bool default:True True - do not maintain image aspect ratio, fill the entire bounding box, distorting the image. This is set to True to match the behaviour of previous versions of endesive False - maintain image aspect ratio when fitting image into the bounding box signature_img_centred: bool default:True True - centre images within the bounding box when image aspect ratio does not match that of the bounding box False - do not centre image, position it at the lower-left of the bounding box signature_appearance: dict if box is not None then render a signature appearance that is configured by the dict. See below for configuration signature_manual: list if box is not None then render a manually-created signature apperance using the directives contained in this list manual_fonts: dict fonts required by the manual signature appearance manual_images: dict images required by the manual signature appearance contact: string required info about the person signing the document location:string required info about location of the person signing the document signingdate: string required info about signing time eg: now.strftime('D:%Y%m%d%H%M%S+00\'00\'') reason: string required info about reason for signing the document password: string required if the document is password protected, signing it also requires that password text: dict text attributes wraptext=True, fontsize:12, textalign:'left', linespacing:1.2 application: string optional application name in advanced signature properties dialog in Acrobat Reader pss: boolen optional choosen signature scheme RSASSA-PSS (true) vs. PKCS1-v1_5 (false/default) key: cryptography.hazmat.backends.openssl.rsa._RSAPrivateKey - private key used to sign the document cert: cryptography.x509.Certificate - certificate associated with the key othercerts: list of cryptography.x509.Certificate to be saved with the signed document, e.g.: a list of intermediate certificates used to confirm the authenticity of the certificate used in the signature algomd:string default: sha1 - name of the hashing algorithm used to calculate the hash of the document being signed e.g.: sha1, sha256, sha384, sha512, ripemd160 hsm: an instance of endesive.hsm.HSM class used to sign using a hardware token or None timestampurl: timestamp server URL or None timestampcredentials:Dict username and password for authentication against timestamp server. Default: None timestamp_req_options: Dict to set options to the POST http call against the timestamp server. Default: None ocsppurl: ocsp server URL or None ocspissuer: certificate of issuer or None ltv: boolean enable LTV signature returns: bytes ready for writing after unsigned pdf document containing its electronic signature Signature appearance: Adobe-inspired signature with text and images Parameters are contained in udct['signature_appearance'] If a field is included in the display list, that field will be included in the annotation. Its value is based upon what is in udct and the cert. Text and border are the colour specified by outline, and border is the the inset distance from the outer edge of the annotation. The R G B values range between 0 and 1. Icon is an image to display above the background and border at the left-hand side of the anntoation. If there is no text, it is centred. The text block is left-aligned to the right of the icon image. If there is no image, the text is left-aliged with the left-hand border of the annotation display fields: CN, DN, date, contact, reason, location Dict format: appearance = dict( background = Image with alpha / None, icon = Image with alpha / None, labels = bool, display = list, software = str, outline = [R, G, B], border = int, ) Signature manual: Manually set up your own signature appearance with arbitrary fonts and images. The full list of directives can be seen in the template dict in endesive.pdf.PyPDF2_annotate.annotations.signatureaSignatureAppearance Coordinates are based off of the lower-left corner of the annotation manual_images is a dict of images that will be included in the annotation The keys are strings, and are the names to use when referring to the them in 'image' directives. manual_fonts is a dict of TrueType fonts that will be included in the annotation. The keys are strings, and are the names to use when referring to the them in 'image' directives. The values are the paths to the font files. Do not use the name 'default' in this dict; it is treated specially. """ cls = SignedData() return cls.sign( datau, udct, key, cert, othercerts, algomd, hsm, timestampurl, timestampcredentials, timestamp_req_options, "sign", ocspurl, ocspissuer, ) endesive-2.19.1/endesive/pdf/fpdf/000077500000000000000000000000001504236674500167145ustar00rootroot00000000000000endesive-2.19.1/endesive/pdf/fpdf/__init__.py000066400000000000000000000006371504236674500210330ustar00rootroot00000000000000#!/usr/bin/env python # -*- coding: utf-8 -*- "FPDF for python" __license__ = "LGPL 3.0" __version__ = "1.7.2" from .fpdf import FPDF, FPDF_FONT_DIR, FPDF_VERSION, SYSTEM_TTFONTS, set_global, FPDF_CACHE_MODE, FPDF_CACHE_DIR try: from .html import HTMLMixin except ImportError: import warnings warnings.warn("web2py gluon package not installed, required for html2pdf") from .template import Template endesive-2.19.1/endesive/pdf/fpdf/fonts.py000066400000000000000000000634611504236674500204310ustar00rootroot00000000000000#!/usr/bin/env python # -*- coding: latin-1 -*- # Fonts: fpdf_charwidths = {} fpdf_charwidths['courier']={} for i in range(0,256): fpdf_charwidths['courier'][chr(i)]=600 fpdf_charwidths['courierB']=fpdf_charwidths['courier'] fpdf_charwidths['courierI']=fpdf_charwidths['courier'] fpdf_charwidths['courierBI']=fpdf_charwidths['courier'] fpdf_charwidths['helvetica']={ '\x00':278,'\x01':278,'\x02':278,'\x03':278,'\x04':278,'\x05':278,'\x06':278,'\x07':278,'\x08':278,'\t':278,'\n':278,'\x0b':278,'\x0c':278,'\r':278,'\x0e':278,'\x0f':278,'\x10':278,'\x11':278,'\x12':278,'\x13':278,'\x14':278,'\x15':278, '\x16':278,'\x17':278,'\x18':278,'\x19':278,'\x1a':278,'\x1b':278,'\x1c':278,'\x1d':278,'\x1e':278,'\x1f':278,' ':278,'!':278,'"':355,'#':556,'$':556,'%':889,'&':667,'\'':191,'(':333,')':333,'*':389,'+':584, ',':278,'-':333,'.':278,'/':278,'0':556,'1':556,'2':556,'3':556,'4':556,'5':556,'6':556,'7':556,'8':556,'9':556,':':278,';':278,'<':584,'=':584,'>':584,'?':556,'@':1015,'A':667, 'B':667,'C':722,'D':722,'E':667,'F':611,'G':778,'H':722,'I':278,'J':500,'K':667,'L':556,'M':833,'N':722,'O':778,'P':667,'Q':778,'R':722,'S':667,'T':611,'U':722,'V':667,'W':944, 'X':667,'Y':667,'Z':611,'[':278,'\\':278,']':278,'^':469,'_':556,'`':333,'a':556,'b':556,'c':500,'d':556,'e':556,'f':278,'g':556,'h':556,'i':222,'j':222,'k':500,'l':222,'m':833, 'n':556,'o':556,'p':556,'q':556,'r':333,'s':500,'t':278,'u':556,'v':500,'w':722,'x':500,'y':500,'z':500,'{':334,'|':260,'}':334,'~':584,'\x7f':350,'\x80':556,'\x81':350,'\x82':222,'\x83':556, '\x84':333,'\x85':1000,'\x86':556,'\x87':556,'\x88':333,'\x89':1000,'\x8a':667,'\x8b':333,'\x8c':1000,'\x8d':350,'\x8e':611,'\x8f':350,'\x90':350,'\x91':222,'\x92':222,'\x93':333,'\x94':333,'\x95':350,'\x96':556,'\x97':1000,'\x98':333,'\x99':1000, '\x9a':500,'\x9b':333,'\x9c':944,'\x9d':350,'\x9e':500,'\x9f':667,'\xa0':278,'\xa1':333,'\xa2':556,'\xa3':556,'\xa4':556,'\xa5':556,'\xa6':260,'\xa7':556,'\xa8':333,'\xa9':737,'\xaa':370,'\xab':556,'\xac':584,'\xad':333,'\xae':737,'\xaf':333, '\xb0':400,'\xb1':584,'\xb2':333,'\xb3':333,'\xb4':333,'\xb5':556,'\xb6':537,'\xb7':278,'\xb8':333,'\xb9':333,'\xba':365,'\xbb':556,'\xbc':834,'\xbd':834,'\xbe':834,'\xbf':611,'\xc0':667,'\xc1':667,'\xc2':667,'\xc3':667,'\xc4':667,'\xc5':667, '\xc6':1000,'\xc7':722,'\xc8':667,'\xc9':667,'\xca':667,'\xcb':667,'\xcc':278,'\xcd':278,'\xce':278,'\xcf':278,'\xd0':722,'\xd1':722,'\xd2':778,'\xd3':778,'\xd4':778,'\xd5':778,'\xd6':778,'\xd7':584,'\xd8':778,'\xd9':722,'\xda':722,'\xdb':722, '\xdc':722,'\xdd':667,'\xde':667,'\xdf':611,'\xe0':556,'\xe1':556,'\xe2':556,'\xe3':556,'\xe4':556,'\xe5':556,'\xe6':889,'\xe7':500,'\xe8':556,'\xe9':556,'\xea':556,'\xeb':556,'\xec':278,'\xed':278,'\xee':278,'\xef':278,'\xf0':556,'\xf1':556, '\xf2':556,'\xf3':556,'\xf4':556,'\xf5':556,'\xf6':556,'\xf7':584,'\xf8':611,'\xf9':556,'\xfa':556,'\xfb':556,'\xfc':556,'\xfd':500,'\xfe':556,'\xff':500} fpdf_charwidths['helveticaB']={ '\x00':278,'\x01':278,'\x02':278,'\x03':278,'\x04':278,'\x05':278,'\x06':278,'\x07':278,'\x08':278,'\t':278,'\n':278,'\x0b':278,'\x0c':278,'\r':278,'\x0e':278,'\x0f':278,'\x10':278,'\x11':278,'\x12':278,'\x13':278,'\x14':278,'\x15':278, '\x16':278,'\x17':278,'\x18':278,'\x19':278,'\x1a':278,'\x1b':278,'\x1c':278,'\x1d':278,'\x1e':278,'\x1f':278,' ':278,'!':333,'"':474,'#':556,'$':556,'%':889,'&':722,'\'':238,'(':333,')':333,'*':389,'+':584, ',':278,'-':333,'.':278,'/':278,'0':556,'1':556,'2':556,'3':556,'4':556,'5':556,'6':556,'7':556,'8':556,'9':556,':':333,';':333,'<':584,'=':584,'>':584,'?':611,'@':975,'A':722, 'B':722,'C':722,'D':722,'E':667,'F':611,'G':778,'H':722,'I':278,'J':556,'K':722,'L':611,'M':833,'N':722,'O':778,'P':667,'Q':778,'R':722,'S':667,'T':611,'U':722,'V':667,'W':944, 'X':667,'Y':667,'Z':611,'[':333,'\\':278,']':333,'^':584,'_':556,'`':333,'a':556,'b':611,'c':556,'d':611,'e':556,'f':333,'g':611,'h':611,'i':278,'j':278,'k':556,'l':278,'m':889, 'n':611,'o':611,'p':611,'q':611,'r':389,'s':556,'t':333,'u':611,'v':556,'w':778,'x':556,'y':556,'z':500,'{':389,'|':280,'}':389,'~':584,'\x7f':350,'\x80':556,'\x81':350,'\x82':278,'\x83':556, '\x84':500,'\x85':1000,'\x86':556,'\x87':556,'\x88':333,'\x89':1000,'\x8a':667,'\x8b':333,'\x8c':1000,'\x8d':350,'\x8e':611,'\x8f':350,'\x90':350,'\x91':278,'\x92':278,'\x93':500,'\x94':500,'\x95':350,'\x96':556,'\x97':1000,'\x98':333,'\x99':1000, '\x9a':556,'\x9b':333,'\x9c':944,'\x9d':350,'\x9e':500,'\x9f':667,'\xa0':278,'\xa1':333,'\xa2':556,'\xa3':556,'\xa4':556,'\xa5':556,'\xa6':280,'\xa7':556,'\xa8':333,'\xa9':737,'\xaa':370,'\xab':556,'\xac':584,'\xad':333,'\xae':737,'\xaf':333, '\xb0':400,'\xb1':584,'\xb2':333,'\xb3':333,'\xb4':333,'\xb5':611,'\xb6':556,'\xb7':278,'\xb8':333,'\xb9':333,'\xba':365,'\xbb':556,'\xbc':834,'\xbd':834,'\xbe':834,'\xbf':611,'\xc0':722,'\xc1':722,'\xc2':722,'\xc3':722,'\xc4':722,'\xc5':722, '\xc6':1000,'\xc7':722,'\xc8':667,'\xc9':667,'\xca':667,'\xcb':667,'\xcc':278,'\xcd':278,'\xce':278,'\xcf':278,'\xd0':722,'\xd1':722,'\xd2':778,'\xd3':778,'\xd4':778,'\xd5':778,'\xd6':778,'\xd7':584,'\xd8':778,'\xd9':722,'\xda':722,'\xdb':722, '\xdc':722,'\xdd':667,'\xde':667,'\xdf':611,'\xe0':556,'\xe1':556,'\xe2':556,'\xe3':556,'\xe4':556,'\xe5':556,'\xe6':889,'\xe7':556,'\xe8':556,'\xe9':556,'\xea':556,'\xeb':556,'\xec':278,'\xed':278,'\xee':278,'\xef':278,'\xf0':611,'\xf1':611, '\xf2':611,'\xf3':611,'\xf4':611,'\xf5':611,'\xf6':611,'\xf7':584,'\xf8':611,'\xf9':611,'\xfa':611,'\xfb':611,'\xfc':611,'\xfd':556,'\xfe':611,'\xff':556 } fpdf_charwidths['helveticaBI']={ '\x00':278,'\x01':278,'\x02':278,'\x03':278,'\x04':278,'\x05':278,'\x06':278,'\x07':278,'\x08':278,'\t':278,'\n':278,'\x0b':278,'\x0c':278,'\r':278,'\x0e':278,'\x0f':278,'\x10':278,'\x11':278,'\x12':278,'\x13':278,'\x14':278,'\x15':278, '\x16':278,'\x17':278,'\x18':278,'\x19':278,'\x1a':278,'\x1b':278,'\x1c':278,'\x1d':278,'\x1e':278,'\x1f':278,' ':278,'!':333,'"':474,'#':556,'$':556,'%':889,'&':722,'\'':238,'(':333,')':333,'*':389,'+':584, ',':278,'-':333,'.':278,'/':278,'0':556,'1':556,'2':556,'3':556,'4':556,'5':556,'6':556,'7':556,'8':556,'9':556,':':333,';':333,'<':584,'=':584,'>':584,'?':611,'@':975,'A':722, 'B':722,'C':722,'D':722,'E':667,'F':611,'G':778,'H':722,'I':278,'J':556,'K':722,'L':611,'M':833,'N':722,'O':778,'P':667,'Q':778,'R':722,'S':667,'T':611,'U':722,'V':667,'W':944, 'X':667,'Y':667,'Z':611,'[':333,'\\':278,']':333,'^':584,'_':556,'`':333,'a':556,'b':611,'c':556,'d':611,'e':556,'f':333,'g':611,'h':611,'i':278,'j':278,'k':556,'l':278,'m':889, 'n':611,'o':611,'p':611,'q':611,'r':389,'s':556,'t':333,'u':611,'v':556,'w':778,'x':556,'y':556,'z':500,'{':389,'|':280,'}':389,'~':584,'\x7f':350,'\x80':556,'\x81':350,'\x82':278,'\x83':556, '\x84':500,'\x85':1000,'\x86':556,'\x87':556,'\x88':333,'\x89':1000,'\x8a':667,'\x8b':333,'\x8c':1000,'\x8d':350,'\x8e':611,'\x8f':350,'\x90':350,'\x91':278,'\x92':278,'\x93':500,'\x94':500,'\x95':350,'\x96':556,'\x97':1000,'\x98':333,'\x99':1000, '\x9a':556,'\x9b':333,'\x9c':944,'\x9d':350,'\x9e':500,'\x9f':667,'\xa0':278,'\xa1':333,'\xa2':556,'\xa3':556,'\xa4':556,'\xa5':556,'\xa6':280,'\xa7':556,'\xa8':333,'\xa9':737,'\xaa':370,'\xab':556,'\xac':584,'\xad':333,'\xae':737,'\xaf':333, '\xb0':400,'\xb1':584,'\xb2':333,'\xb3':333,'\xb4':333,'\xb5':611,'\xb6':556,'\xb7':278,'\xb8':333,'\xb9':333,'\xba':365,'\xbb':556,'\xbc':834,'\xbd':834,'\xbe':834,'\xbf':611,'\xc0':722,'\xc1':722,'\xc2':722,'\xc3':722,'\xc4':722,'\xc5':722, '\xc6':1000,'\xc7':722,'\xc8':667,'\xc9':667,'\xca':667,'\xcb':667,'\xcc':278,'\xcd':278,'\xce':278,'\xcf':278,'\xd0':722,'\xd1':722,'\xd2':778,'\xd3':778,'\xd4':778,'\xd5':778,'\xd6':778,'\xd7':584,'\xd8':778,'\xd9':722,'\xda':722,'\xdb':722, '\xdc':722,'\xdd':667,'\xde':667,'\xdf':611,'\xe0':556,'\xe1':556,'\xe2':556,'\xe3':556,'\xe4':556,'\xe5':556,'\xe6':889,'\xe7':556,'\xe8':556,'\xe9':556,'\xea':556,'\xeb':556,'\xec':278,'\xed':278,'\xee':278,'\xef':278,'\xf0':611,'\xf1':611, '\xf2':611,'\xf3':611,'\xf4':611,'\xf5':611,'\xf6':611,'\xf7':584,'\xf8':611,'\xf9':611,'\xfa':611,'\xfb':611,'\xfc':611,'\xfd':556,'\xfe':611,'\xff':556} fpdf_charwidths['helveticaI']={ '\x00':278,'\x01':278,'\x02':278,'\x03':278,'\x04':278,'\x05':278,'\x06':278,'\x07':278,'\x08':278,'\t':278,'\n':278,'\x0b':278,'\x0c':278,'\r':278,'\x0e':278,'\x0f':278,'\x10':278,'\x11':278,'\x12':278,'\x13':278,'\x14':278,'\x15':278, '\x16':278,'\x17':278,'\x18':278,'\x19':278,'\x1a':278,'\x1b':278,'\x1c':278,'\x1d':278,'\x1e':278,'\x1f':278,' ':278,'!':278,'"':355,'#':556,'$':556,'%':889,'&':667,'\'':191,'(':333,')':333,'*':389,'+':584, ',':278,'-':333,'.':278,'/':278,'0':556,'1':556,'2':556,'3':556,'4':556,'5':556,'6':556,'7':556,'8':556,'9':556,':':278,';':278,'<':584,'=':584,'>':584,'?':556,'@':1015,'A':667, 'B':667,'C':722,'D':722,'E':667,'F':611,'G':778,'H':722,'I':278,'J':500,'K':667,'L':556,'M':833,'N':722,'O':778,'P':667,'Q':778,'R':722,'S':667,'T':611,'U':722,'V':667,'W':944, 'X':667,'Y':667,'Z':611,'[':278,'\\':278,']':278,'^':469,'_':556,'`':333,'a':556,'b':556,'c':500,'d':556,'e':556,'f':278,'g':556,'h':556,'i':222,'j':222,'k':500,'l':222,'m':833, 'n':556,'o':556,'p':556,'q':556,'r':333,'s':500,'t':278,'u':556,'v':500,'w':722,'x':500,'y':500,'z':500,'{':334,'|':260,'}':334,'~':584,'\x7f':350,'\x80':556,'\x81':350,'\x82':222,'\x83':556, '\x84':333,'\x85':1000,'\x86':556,'\x87':556,'\x88':333,'\x89':1000,'\x8a':667,'\x8b':333,'\x8c':1000,'\x8d':350,'\x8e':611,'\x8f':350,'\x90':350,'\x91':222,'\x92':222,'\x93':333,'\x94':333,'\x95':350,'\x96':556,'\x97':1000,'\x98':333,'\x99':1000, '\x9a':500,'\x9b':333,'\x9c':944,'\x9d':350,'\x9e':500,'\x9f':667,'\xa0':278,'\xa1':333,'\xa2':556,'\xa3':556,'\xa4':556,'\xa5':556,'\xa6':260,'\xa7':556,'\xa8':333,'\xa9':737,'\xaa':370,'\xab':556,'\xac':584,'\xad':333,'\xae':737,'\xaf':333, '\xb0':400,'\xb1':584,'\xb2':333,'\xb3':333,'\xb4':333,'\xb5':556,'\xb6':537,'\xb7':278,'\xb8':333,'\xb9':333,'\xba':365,'\xbb':556,'\xbc':834,'\xbd':834,'\xbe':834,'\xbf':611,'\xc0':667,'\xc1':667,'\xc2':667,'\xc3':667,'\xc4':667,'\xc5':667, '\xc6':1000,'\xc7':722,'\xc8':667,'\xc9':667,'\xca':667,'\xcb':667,'\xcc':278,'\xcd':278,'\xce':278,'\xcf':278,'\xd0':722,'\xd1':722,'\xd2':778,'\xd3':778,'\xd4':778,'\xd5':778,'\xd6':778,'\xd7':584,'\xd8':778,'\xd9':722,'\xda':722,'\xdb':722, '\xdc':722,'\xdd':667,'\xde':667,'\xdf':611,'\xe0':556,'\xe1':556,'\xe2':556,'\xe3':556,'\xe4':556,'\xe5':556,'\xe6':889,'\xe7':500,'\xe8':556,'\xe9':556,'\xea':556,'\xeb':556,'\xec':278,'\xed':278,'\xee':278,'\xef':278,'\xf0':556,'\xf1':556, '\xf2':556,'\xf3':556,'\xf4':556,'\xf5':556,'\xf6':556,'\xf7':584,'\xf8':611,'\xf9':556,'\xfa':556,'\xfb':556,'\xfc':556,'\xfd':500,'\xfe':556,'\xff':500} fpdf_charwidths['symbol']={ '\x00':250,'\x01':250,'\x02':250,'\x03':250,'\x04':250,'\x05':250,'\x06':250,'\x07':250,'\x08':250,'\t':250,'\n':250,'\x0b':250,'\x0c':250,'\r':250,'\x0e':250,'\x0f':250,'\x10':250,'\x11':250,'\x12':250,'\x13':250,'\x14':250,'\x15':250, '\x16':250,'\x17':250,'\x18':250,'\x19':250,'\x1a':250,'\x1b':250,'\x1c':250,'\x1d':250,'\x1e':250,'\x1f':250,' ':250,'!':333,'"':713,'#':500,'$':549,'%':833,'&':778,'\'':439,'(':333,')':333,'*':500,'+':549, ',':250,'-':549,'.':250,'/':278,'0':500,'1':500,'2':500,'3':500,'4':500,'5':500,'6':500,'7':500,'8':500,'9':500,':':278,';':278,'<':549,'=':549,'>':549,'?':444,'@':549,'A':722, 'B':667,'C':722,'D':612,'E':611,'F':763,'G':603,'H':722,'I':333,'J':631,'K':722,'L':686,'M':889,'N':722,'O':722,'P':768,'Q':741,'R':556,'S':592,'T':611,'U':690,'V':439,'W':768, 'X':645,'Y':795,'Z':611,'[':333,'\\':863,']':333,'^':658,'_':500,'`':500,'a':631,'b':549,'c':549,'d':494,'e':439,'f':521,'g':411,'h':603,'i':329,'j':603,'k':549,'l':549,'m':576, 'n':521,'o':549,'p':549,'q':521,'r':549,'s':603,'t':439,'u':576,'v':713,'w':686,'x':493,'y':686,'z':494,'{':480,'|':200,'}':480,'~':549,'\x7f':0,'\x80':0,'\x81':0,'\x82':0,'\x83':0, '\x84':0,'\x85':0,'\x86':0,'\x87':0,'\x88':0,'\x89':0,'\x8a':0,'\x8b':0,'\x8c':0,'\x8d':0,'\x8e':0,'\x8f':0,'\x90':0,'\x91':0,'\x92':0,'\x93':0,'\x94':0,'\x95':0,'\x96':0,'\x97':0,'\x98':0,'\x99':0, '\x9a':0,'\x9b':0,'\x9c':0,'\x9d':0,'\x9e':0,'\x9f':0,'\xa0':750,'\xa1':620,'\xa2':247,'\xa3':549,'\xa4':167,'\xa5':713,'\xa6':500,'\xa7':753,'\xa8':753,'\xa9':753,'\xaa':753,'\xab':1042,'\xac':987,'\xad':603,'\xae':987,'\xaf':603, '\xb0':400,'\xb1':549,'\xb2':411,'\xb3':549,'\xb4':549,'\xb5':713,'\xb6':494,'\xb7':460,'\xb8':549,'\xb9':549,'\xba':549,'\xbb':549,'\xbc':1000,'\xbd':603,'\xbe':1000,'\xbf':658,'\xc0':823,'\xc1':686,'\xc2':795,'\xc3':987,'\xc4':768,'\xc5':768, '\xc6':823,'\xc7':768,'\xc8':768,'\xc9':713,'\xca':713,'\xcb':713,'\xcc':713,'\xcd':713,'\xce':713,'\xcf':713,'\xd0':768,'\xd1':713,'\xd2':790,'\xd3':790,'\xd4':890,'\xd5':823,'\xd6':549,'\xd7':250,'\xd8':713,'\xd9':603,'\xda':603,'\xdb':1042, '\xdc':987,'\xdd':603,'\xde':987,'\xdf':603,'\xe0':494,'\xe1':329,'\xe2':790,'\xe3':790,'\xe4':786,'\xe5':713,'\xe6':384,'\xe7':384,'\xe8':384,'\xe9':384,'\xea':384,'\xeb':384,'\xec':494,'\xed':494,'\xee':494,'\xef':494,'\xf0':0,'\xf1':329, '\xf2':274,'\xf3':686,'\xf4':686,'\xf5':686,'\xf6':384,'\xf7':384,'\xf8':384,'\xf9':384,'\xfa':384,'\xfb':384,'\xfc':494,'\xfd':494,'\xfe':494,'\xff':0} fpdf_charwidths['times']={ '\x00':250,'\x01':250,'\x02':250,'\x03':250,'\x04':250,'\x05':250,'\x06':250,'\x07':250,'\x08':250,'\t':250,'\n':250,'\x0b':250,'\x0c':250,'\r':250,'\x0e':250,'\x0f':250,'\x10':250,'\x11':250,'\x12':250,'\x13':250,'\x14':250,'\x15':250, '\x16':250,'\x17':250,'\x18':250,'\x19':250,'\x1a':250,'\x1b':250,'\x1c':250,'\x1d':250,'\x1e':250,'\x1f':250,' ':250,'!':333,'"':408,'#':500,'$':500,'%':833,'&':778,'\'':180,'(':333,')':333,'*':500,'+':564, ',':250,'-':333,'.':250,'/':278,'0':500,'1':500,'2':500,'3':500,'4':500,'5':500,'6':500,'7':500,'8':500,'9':500,':':278,';':278,'<':564,'=':564,'>':564,'?':444,'@':921,'A':722, 'B':667,'C':667,'D':722,'E':611,'F':556,'G':722,'H':722,'I':333,'J':389,'K':722,'L':611,'M':889,'N':722,'O':722,'P':556,'Q':722,'R':667,'S':556,'T':611,'U':722,'V':722,'W':944, 'X':722,'Y':722,'Z':611,'[':333,'\\':278,']':333,'^':469,'_':500,'`':333,'a':444,'b':500,'c':444,'d':500,'e':444,'f':333,'g':500,'h':500,'i':278,'j':278,'k':500,'l':278,'m':778, 'n':500,'o':500,'p':500,'q':500,'r':333,'s':389,'t':278,'u':500,'v':500,'w':722,'x':500,'y':500,'z':444,'{':480,'|':200,'}':480,'~':541,'\x7f':350,'\x80':500,'\x81':350,'\x82':333,'\x83':500, '\x84':444,'\x85':1000,'\x86':500,'\x87':500,'\x88':333,'\x89':1000,'\x8a':556,'\x8b':333,'\x8c':889,'\x8d':350,'\x8e':611,'\x8f':350,'\x90':350,'\x91':333,'\x92':333,'\x93':444,'\x94':444,'\x95':350,'\x96':500,'\x97':1000,'\x98':333,'\x99':980, '\x9a':389,'\x9b':333,'\x9c':722,'\x9d':350,'\x9e':444,'\x9f':722,'\xa0':250,'\xa1':333,'\xa2':500,'\xa3':500,'\xa4':500,'\xa5':500,'\xa6':200,'\xa7':500,'\xa8':333,'\xa9':760,'\xaa':276,'\xab':500,'\xac':564,'\xad':333,'\xae':760,'\xaf':333, '\xb0':400,'\xb1':564,'\xb2':300,'\xb3':300,'\xb4':333,'\xb5':500,'\xb6':453,'\xb7':250,'\xb8':333,'\xb9':300,'\xba':310,'\xbb':500,'\xbc':750,'\xbd':750,'\xbe':750,'\xbf':444,'\xc0':722,'\xc1':722,'\xc2':722,'\xc3':722,'\xc4':722,'\xc5':722, '\xc6':889,'\xc7':667,'\xc8':611,'\xc9':611,'\xca':611,'\xcb':611,'\xcc':333,'\xcd':333,'\xce':333,'\xcf':333,'\xd0':722,'\xd1':722,'\xd2':722,'\xd3':722,'\xd4':722,'\xd5':722,'\xd6':722,'\xd7':564,'\xd8':722,'\xd9':722,'\xda':722,'\xdb':722, '\xdc':722,'\xdd':722,'\xde':556,'\xdf':500,'\xe0':444,'\xe1':444,'\xe2':444,'\xe3':444,'\xe4':444,'\xe5':444,'\xe6':667,'\xe7':444,'\xe8':444,'\xe9':444,'\xea':444,'\xeb':444,'\xec':278,'\xed':278,'\xee':278,'\xef':278,'\xf0':500,'\xf1':500, '\xf2':500,'\xf3':500,'\xf4':500,'\xf5':500,'\xf6':500,'\xf7':564,'\xf8':500,'\xf9':500,'\xfa':500,'\xfb':500,'\xfc':500,'\xfd':500,'\xfe':500,'\xff':500} fpdf_charwidths['timesB']={ '\x00':250,'\x01':250,'\x02':250,'\x03':250,'\x04':250,'\x05':250,'\x06':250,'\x07':250,'\x08':250,'\t':250,'\n':250,'\x0b':250,'\x0c':250,'\r':250,'\x0e':250,'\x0f':250,'\x10':250,'\x11':250,'\x12':250,'\x13':250,'\x14':250,'\x15':250, '\x16':250,'\x17':250,'\x18':250,'\x19':250,'\x1a':250,'\x1b':250,'\x1c':250,'\x1d':250,'\x1e':250,'\x1f':250,' ':250,'!':333,'"':555,'#':500,'$':500,'%':1000,'&':833,'\'':278,'(':333,')':333,'*':500,'+':570, ',':250,'-':333,'.':250,'/':278,'0':500,'1':500,'2':500,'3':500,'4':500,'5':500,'6':500,'7':500,'8':500,'9':500,':':333,';':333,'<':570,'=':570,'>':570,'?':500,'@':930,'A':722, 'B':667,'C':722,'D':722,'E':667,'F':611,'G':778,'H':778,'I':389,'J':500,'K':778,'L':667,'M':944,'N':722,'O':778,'P':611,'Q':778,'R':722,'S':556,'T':667,'U':722,'V':722,'W':1000, 'X':722,'Y':722,'Z':667,'[':333,'\\':278,']':333,'^':581,'_':500,'`':333,'a':500,'b':556,'c':444,'d':556,'e':444,'f':333,'g':500,'h':556,'i':278,'j':333,'k':556,'l':278,'m':833, 'n':556,'o':500,'p':556,'q':556,'r':444,'s':389,'t':333,'u':556,'v':500,'w':722,'x':500,'y':500,'z':444,'{':394,'|':220,'}':394,'~':520,'\x7f':350,'\x80':500,'\x81':350,'\x82':333,'\x83':500, '\x84':500,'\x85':1000,'\x86':500,'\x87':500,'\x88':333,'\x89':1000,'\x8a':556,'\x8b':333,'\x8c':1000,'\x8d':350,'\x8e':667,'\x8f':350,'\x90':350,'\x91':333,'\x92':333,'\x93':500,'\x94':500,'\x95':350,'\x96':500,'\x97':1000,'\x98':333,'\x99':1000, '\x9a':389,'\x9b':333,'\x9c':722,'\x9d':350,'\x9e':444,'\x9f':722,'\xa0':250,'\xa1':333,'\xa2':500,'\xa3':500,'\xa4':500,'\xa5':500,'\xa6':220,'\xa7':500,'\xa8':333,'\xa9':747,'\xaa':300,'\xab':500,'\xac':570,'\xad':333,'\xae':747,'\xaf':333, '\xb0':400,'\xb1':570,'\xb2':300,'\xb3':300,'\xb4':333,'\xb5':556,'\xb6':540,'\xb7':250,'\xb8':333,'\xb9':300,'\xba':330,'\xbb':500,'\xbc':750,'\xbd':750,'\xbe':750,'\xbf':500,'\xc0':722,'\xc1':722,'\xc2':722,'\xc3':722,'\xc4':722,'\xc5':722, '\xc6':1000,'\xc7':722,'\xc8':667,'\xc9':667,'\xca':667,'\xcb':667,'\xcc':389,'\xcd':389,'\xce':389,'\xcf':389,'\xd0':722,'\xd1':722,'\xd2':778,'\xd3':778,'\xd4':778,'\xd5':778,'\xd6':778,'\xd7':570,'\xd8':778,'\xd9':722,'\xda':722,'\xdb':722, '\xdc':722,'\xdd':722,'\xde':611,'\xdf':556,'\xe0':500,'\xe1':500,'\xe2':500,'\xe3':500,'\xe4':500,'\xe5':500,'\xe6':722,'\xe7':444,'\xe8':444,'\xe9':444,'\xea':444,'\xeb':444,'\xec':278,'\xed':278,'\xee':278,'\xef':278,'\xf0':500,'\xf1':556, '\xf2':500,'\xf3':500,'\xf4':500,'\xf5':500,'\xf6':500,'\xf7':570,'\xf8':500,'\xf9':556,'\xfa':556,'\xfb':556,'\xfc':556,'\xfd':500,'\xfe':556,'\xff':500} fpdf_charwidths['timesBI']={ '\x00':250,'\x01':250,'\x02':250,'\x03':250,'\x04':250,'\x05':250,'\x06':250,'\x07':250,'\x08':250,'\t':250,'\n':250,'\x0b':250,'\x0c':250,'\r':250,'\x0e':250,'\x0f':250,'\x10':250,'\x11':250,'\x12':250,'\x13':250,'\x14':250,'\x15':250, '\x16':250,'\x17':250,'\x18':250,'\x19':250,'\x1a':250,'\x1b':250,'\x1c':250,'\x1d':250,'\x1e':250,'\x1f':250,' ':250,'!':389,'"':555,'#':500,'$':500,'%':833,'&':778,'\'':278,'(':333,')':333,'*':500,'+':570, ',':250,'-':333,'.':250,'/':278,'0':500,'1':500,'2':500,'3':500,'4':500,'5':500,'6':500,'7':500,'8':500,'9':500,':':333,';':333,'<':570,'=':570,'>':570,'?':500,'@':832,'A':667, 'B':667,'C':667,'D':722,'E':667,'F':667,'G':722,'H':778,'I':389,'J':500,'K':667,'L':611,'M':889,'N':722,'O':722,'P':611,'Q':722,'R':667,'S':556,'T':611,'U':722,'V':667,'W':889, 'X':667,'Y':611,'Z':611,'[':333,'\\':278,']':333,'^':570,'_':500,'`':333,'a':500,'b':500,'c':444,'d':500,'e':444,'f':333,'g':500,'h':556,'i':278,'j':278,'k':500,'l':278,'m':778, 'n':556,'o':500,'p':500,'q':500,'r':389,'s':389,'t':278,'u':556,'v':444,'w':667,'x':500,'y':444,'z':389,'{':348,'|':220,'}':348,'~':570,'\x7f':350,'\x80':500,'\x81':350,'\x82':333,'\x83':500, '\x84':500,'\x85':1000,'\x86':500,'\x87':500,'\x88':333,'\x89':1000,'\x8a':556,'\x8b':333,'\x8c':944,'\x8d':350,'\x8e':611,'\x8f':350,'\x90':350,'\x91':333,'\x92':333,'\x93':500,'\x94':500,'\x95':350,'\x96':500,'\x97':1000,'\x98':333,'\x99':1000, '\x9a':389,'\x9b':333,'\x9c':722,'\x9d':350,'\x9e':389,'\x9f':611,'\xa0':250,'\xa1':389,'\xa2':500,'\xa3':500,'\xa4':500,'\xa5':500,'\xa6':220,'\xa7':500,'\xa8':333,'\xa9':747,'\xaa':266,'\xab':500,'\xac':606,'\xad':333,'\xae':747,'\xaf':333, '\xb0':400,'\xb1':570,'\xb2':300,'\xb3':300,'\xb4':333,'\xb5':576,'\xb6':500,'\xb7':250,'\xb8':333,'\xb9':300,'\xba':300,'\xbb':500,'\xbc':750,'\xbd':750,'\xbe':750,'\xbf':500,'\xc0':667,'\xc1':667,'\xc2':667,'\xc3':667,'\xc4':667,'\xc5':667, '\xc6':944,'\xc7':667,'\xc8':667,'\xc9':667,'\xca':667,'\xcb':667,'\xcc':389,'\xcd':389,'\xce':389,'\xcf':389,'\xd0':722,'\xd1':722,'\xd2':722,'\xd3':722,'\xd4':722,'\xd5':722,'\xd6':722,'\xd7':570,'\xd8':722,'\xd9':722,'\xda':722,'\xdb':722, '\xdc':722,'\xdd':611,'\xde':611,'\xdf':500,'\xe0':500,'\xe1':500,'\xe2':500,'\xe3':500,'\xe4':500,'\xe5':500,'\xe6':722,'\xe7':444,'\xe8':444,'\xe9':444,'\xea':444,'\xeb':444,'\xec':278,'\xed':278,'\xee':278,'\xef':278,'\xf0':500,'\xf1':556, '\xf2':500,'\xf3':500,'\xf4':500,'\xf5':500,'\xf6':500,'\xf7':570,'\xf8':500,'\xf9':556,'\xfa':556,'\xfb':556,'\xfc':556,'\xfd':444,'\xfe':500,'\xff':444} fpdf_charwidths['timesI']={ '\x00':250,'\x01':250,'\x02':250,'\x03':250,'\x04':250,'\x05':250,'\x06':250,'\x07':250,'\x08':250,'\t':250,'\n':250,'\x0b':250,'\x0c':250,'\r':250,'\x0e':250,'\x0f':250,'\x10':250,'\x11':250,'\x12':250,'\x13':250,'\x14':250,'\x15':250, '\x16':250,'\x17':250,'\x18':250,'\x19':250,'\x1a':250,'\x1b':250,'\x1c':250,'\x1d':250,'\x1e':250,'\x1f':250,' ':250,'!':333,'"':420,'#':500,'$':500,'%':833,'&':778,'\'':214,'(':333,')':333,'*':500,'+':675, ',':250,'-':333,'.':250,'/':278,'0':500,'1':500,'2':500,'3':500,'4':500,'5':500,'6':500,'7':500,'8':500,'9':500,':':333,';':333,'<':675,'=':675,'>':675,'?':500,'@':920,'A':611, 'B':611,'C':667,'D':722,'E':611,'F':611,'G':722,'H':722,'I':333,'J':444,'K':667,'L':556,'M':833,'N':667,'O':722,'P':611,'Q':722,'R':611,'S':500,'T':556,'U':722,'V':611,'W':833, 'X':611,'Y':556,'Z':556,'[':389,'\\':278,']':389,'^':422,'_':500,'`':333,'a':500,'b':500,'c':444,'d':500,'e':444,'f':278,'g':500,'h':500,'i':278,'j':278,'k':444,'l':278,'m':722, 'n':500,'o':500,'p':500,'q':500,'r':389,'s':389,'t':278,'u':500,'v':444,'w':667,'x':444,'y':444,'z':389,'{':400,'|':275,'}':400,'~':541,'\x7f':350,'\x80':500,'\x81':350,'\x82':333,'\x83':500, '\x84':556,'\x85':889,'\x86':500,'\x87':500,'\x88':333,'\x89':1000,'\x8a':500,'\x8b':333,'\x8c':944,'\x8d':350,'\x8e':556,'\x8f':350,'\x90':350,'\x91':333,'\x92':333,'\x93':556,'\x94':556,'\x95':350,'\x96':500,'\x97':889,'\x98':333,'\x99':980, '\x9a':389,'\x9b':333,'\x9c':667,'\x9d':350,'\x9e':389,'\x9f':556,'\xa0':250,'\xa1':389,'\xa2':500,'\xa3':500,'\xa4':500,'\xa5':500,'\xa6':275,'\xa7':500,'\xa8':333,'\xa9':760,'\xaa':276,'\xab':500,'\xac':675,'\xad':333,'\xae':760,'\xaf':333, '\xb0':400,'\xb1':675,'\xb2':300,'\xb3':300,'\xb4':333,'\xb5':500,'\xb6':523,'\xb7':250,'\xb8':333,'\xb9':300,'\xba':310,'\xbb':500,'\xbc':750,'\xbd':750,'\xbe':750,'\xbf':500,'\xc0':611,'\xc1':611,'\xc2':611,'\xc3':611,'\xc4':611,'\xc5':611, '\xc6':889,'\xc7':667,'\xc8':611,'\xc9':611,'\xca':611,'\xcb':611,'\xcc':333,'\xcd':333,'\xce':333,'\xcf':333,'\xd0':722,'\xd1':667,'\xd2':722,'\xd3':722,'\xd4':722,'\xd5':722,'\xd6':722,'\xd7':675,'\xd8':722,'\xd9':722,'\xda':722,'\xdb':722, '\xdc':722,'\xdd':556,'\xde':611,'\xdf':500,'\xe0':500,'\xe1':500,'\xe2':500,'\xe3':500,'\xe4':500,'\xe5':500,'\xe6':667,'\xe7':444,'\xe8':444,'\xe9':444,'\xea':444,'\xeb':444,'\xec':278,'\xed':278,'\xee':278,'\xef':278,'\xf0':500,'\xf1':500, '\xf2':500,'\xf3':500,'\xf4':500,'\xf5':500,'\xf6':500,'\xf7':675,'\xf8':500,'\xf9':500,'\xfa':500,'\xfb':500,'\xfc':500,'\xfd':444,'\xfe':500,'\xff':444} fpdf_charwidths['zapfdingbats']={ '\x00':0,'\x01':0,'\x02':0,'\x03':0,'\x04':0,'\x05':0,'\x06':0,'\x07':0,'\x08':0,'\t':0,'\n':0,'\x0b':0,'\x0c':0,'\r':0,'\x0e':0,'\x0f':0,'\x10':0,'\x11':0,'\x12':0,'\x13':0,'\x14':0,'\x15':0, '\x16':0,'\x17':0,'\x18':0,'\x19':0,'\x1a':0,'\x1b':0,'\x1c':0,'\x1d':0,'\x1e':0,'\x1f':0,' ':278,'!':974,'"':961,'#':974,'$':980,'%':719,'&':789,'\'':790,'(':791,')':690,'*':960,'+':939, ',':549,'-':855,'.':911,'/':933,'0':911,'1':945,'2':974,'3':755,'4':846,'5':762,'6':761,'7':571,'8':677,'9':763,':':760,';':759,'<':754,'=':494,'>':552,'?':537,'@':577,'A':692, 'B':786,'C':788,'D':788,'E':790,'F':793,'G':794,'H':816,'I':823,'J':789,'K':841,'L':823,'M':833,'N':816,'O':831,'P':923,'Q':744,'R':723,'S':749,'T':790,'U':792,'V':695,'W':776, 'X':768,'Y':792,'Z':759,'[':707,'\\':708,']':682,'^':701,'_':826,'`':815,'a':789,'b':789,'c':707,'d':687,'e':696,'f':689,'g':786,'h':787,'i':713,'j':791,'k':785,'l':791,'m':873, 'n':761,'o':762,'p':762,'q':759,'r':759,'s':892,'t':892,'u':788,'v':784,'w':438,'x':138,'y':277,'z':415,'{':392,'|':392,'}':668,'~':668,'\x7f':0,'\x80':390,'\x81':390,'\x82':317,'\x83':317, '\x84':276,'\x85':276,'\x86':509,'\x87':509,'\x88':410,'\x89':410,'\x8a':234,'\x8b':234,'\x8c':334,'\x8d':334,'\x8e':0,'\x8f':0,'\x90':0,'\x91':0,'\x92':0,'\x93':0,'\x94':0,'\x95':0,'\x96':0,'\x97':0,'\x98':0,'\x99':0, '\x9a':0,'\x9b':0,'\x9c':0,'\x9d':0,'\x9e':0,'\x9f':0,'\xa0':0,'\xa1':732,'\xa2':544,'\xa3':544,'\xa4':910,'\xa5':667,'\xa6':760,'\xa7':760,'\xa8':776,'\xa9':595,'\xaa':694,'\xab':626,'\xac':788,'\xad':788,'\xae':788,'\xaf':788, '\xb0':788,'\xb1':788,'\xb2':788,'\xb3':788,'\xb4':788,'\xb5':788,'\xb6':788,'\xb7':788,'\xb8':788,'\xb9':788,'\xba':788,'\xbb':788,'\xbc':788,'\xbd':788,'\xbe':788,'\xbf':788,'\xc0':788,'\xc1':788,'\xc2':788,'\xc3':788,'\xc4':788,'\xc5':788, '\xc6':788,'\xc7':788,'\xc8':788,'\xc9':788,'\xca':788,'\xcb':788,'\xcc':788,'\xcd':788,'\xce':788,'\xcf':788,'\xd0':788,'\xd1':788,'\xd2':788,'\xd3':788,'\xd4':894,'\xd5':838,'\xd6':1016,'\xd7':458,'\xd8':748,'\xd9':924,'\xda':748,'\xdb':918, '\xdc':927,'\xdd':928,'\xde':928,'\xdf':834,'\xe0':873,'\xe1':828,'\xe2':924,'\xe3':924,'\xe4':917,'\xe5':930,'\xe6':931,'\xe7':463,'\xe8':883,'\xe9':836,'\xea':836,'\xeb':867,'\xec':867,'\xed':696,'\xee':696,'\xef':874,'\xf0':0,'\xf1':874, '\xf2':760,'\xf3':946,'\xf4':771,'\xf5':865,'\xf6':771,'\xf7':888,'\xf8':967,'\xf9':888,'\xfa':831,'\xfb':873,'\xfc':927,'\xfd':970,'\xfe':918,'\xff':0} endesive-2.19.1/endesive/pdf/fpdf/fpdf.py000066400000000000000000002251261504236674500202150ustar00rootroot00000000000000#!/usr/bin/env python # -*- coding: latin-1 -*- # **************************************************************************** # * Software: FPDF for python * # * Version: 1.7.1 * # * Date: 2010-09-10 * # * Last update: 2012-08-16 * # * License: LGPL v3.0 * # * * # * Original Author (PHP): Olivier PLATHEY 2004-12-31 * # * Ported to Python 2.4 by Max (maxpat78@yahoo.it) on 2006-05 * # * Maintainer: Mariano Reingart (reingart@gmail.com) et al since 2008 est. * # * NOTE: 'I' and 'D' destinations are disabled, and simply print to STDOUT * # **************************************************************************** from __future__ import division import hashlib from datetime import datetime from functools import wraps import math import errno import os, sys, zlib, struct, re, tempfile, struct from .ttfonts import TTFontFile from .fonts import fpdf_charwidths from .php import substr, sprintf, print_r, UTF8ToUTF16BE, UTF8StringToArray from .py3k import PY3K, pickle, urlopen, Image, basestring, unicode, exception, b, hashpath # Global variables FPDF_VERSION = '1.7.2' FPDF_FONT_DIR = os.path.join(os.path.dirname(__file__),'font') FPDF_CACHE_MODE = 0 # 0 - in same foder, 1 - none, 2 - hash FPDF_CACHE_DIR = None SYSTEM_TTFONTS = None def set_global(var, val): globals()[var] = val class FPDF(object): "PDF Generation class" def __init__(self, orientation='P',unit='mm',format='A4'): # Some checks self._dochecks() # Initialization of properties self.offsets={} # array of object offsets self.page=0 # current page number self.n=2 # current object number self.buffer='' # buffer holding in-memory PDF self.pages={} # array containing pages self.orientation_changes={} # array indicating orientation changes self.state=0 # current document state self.fonts={} # array of used fonts self.font_files={} # array of font files self.diffs={} # array of encoding differences self.images={} # array of used images self.page_links={} # array of links in pages self.links={} # array of internal links self.in_footer=0 # flag set when processing footer self.lastw=0 self.lasth=0 # height of last cell printed self.font_family='' # current font family self.font_style='' # current font style self.font_size_pt=12 # current font size in points self.underline=0 # underlining flag self.draw_color='0 G' self.fill_color='0 g' self.text_color='0 g' self.color_flag=0 # indicates whether fill and text colors are different self.ws=0 # word spacing self.angle=0 # Standard fonts self.core_fonts={'courier':'Courier','courierB':'Courier-Bold','courierI':'Courier-Oblique','courierBI':'Courier-BoldOblique', 'helvetica':'Helvetica','helveticaB':'Helvetica-Bold','helveticaI':'Helvetica-Oblique','helveticaBI':'Helvetica-BoldOblique', 'times':'Times-Roman','timesB':'Times-Bold','timesI':'Times-Italic','timesBI':'Times-BoldItalic', 'symbol':'Symbol','zapfdingbats':'ZapfDingbats'} # Scale factor if(unit=='pt'): self.k=1 elif(unit=='mm'): self.k=72/25.4 elif(unit=='cm'): self.k=72/2.54 elif(unit=='in'): self.k=72. else: self.error('Incorrect unit: '+unit) # Page format if(isinstance(format,basestring)): format=format.lower() if(format=='a3'): format=(841.89,1190.55) elif(format=='a4'): format=(595.28,841.89) elif(format=='a5'): format=(420.94,595.28) elif(format=='letter'): format=(612,792) elif(format=='legal'): format=(612,1008) else: self.error('Unknown page format: '+format) self.fw_pt=format[0] self.fh_pt=format[1] else: self.fw_pt=format[0]*self.k self.fh_pt=format[1]*self.k self.fw=self.fw_pt/self.k self.fh=self.fh_pt/self.k # Page orientation orientation=orientation.lower() if(orientation=='p' or orientation=='portrait'): self.def_orientation='P' self.w_pt=self.fw_pt self.h_pt=self.fh_pt elif(orientation=='l' or orientation=='landscape'): self.def_orientation='L' self.w_pt=self.fh_pt self.h_pt=self.fw_pt else: self.error('Incorrect orientation: '+orientation) self.cur_orientation=self.def_orientation self.w=self.w_pt/self.k self.h=self.h_pt/self.k # Page margins (1 cm) margin=28.35/self.k self.set_margins(margin,margin) # Interior cell margin (1 mm) self.c_margin=margin/10.0 # line width (0.2 mm) self.line_width=.567/self.k # Automatic page break self.set_auto_page_break(1,2*margin) # Full width display mode self.set_display_mode('fullwidth') # Enable compression self.set_compression(1) # Set default PDF version number self.pdf_version='1.3' def check_page(fn): "Decorator to protect drawing methods" @wraps(fn) def wrapper(self, *args, **kwargs): if not self.page and not kwargs.get('split_only'): self.error("No page open, you need to call add_page() first") else: return fn(self, *args, **kwargs) return wrapper def set_margins(self, left,top,right=-1): "Set left, top and right margins" self.l_margin=left self.t_margin=top if(right==-1): right=left self.r_margin=right def set_left_margin(self, margin): "Set left margin" self.l_margin=margin if(self.page>0 and self.x0): #Page footer self.in_footer=1 self.footer() self.in_footer=0 #close page self._endpage() #Start new page self._beginpage(orientation) #Set line cap style to square self._out('2 J') #Set line width self.line_width=lw self._out(sprintf('%.2f w',lw*self.k)) #Set font if(family): self.set_font(family,style,size) #Set colors self.draw_color=dc if(dc!='0 G'): self._out(dc) self.fill_color=fc if(fc!='0 g'): self._out(fc) self.text_color=tc self.color_flag=cf #Page header self.header() #Restore line width if(self.line_width!=lw): self.line_width=lw self._out(sprintf('%.2f w',lw*self.k)) #Restore font if(family): self.set_font(family,style,size) #Restore colors if(self.draw_color!=dc): self.draw_color=dc self._out(dc) if(self.fill_color!=fc): self.fill_color=fc self._out(fc) self.text_color=tc self.color_flag=cf def header(self): "Header to be implemented in your own inherited class" pass def footer(self): "Footer to be implemented in your own inherited class" pass def page_no(self): "Get current page number" return self.page def set_draw_color(self, r,g=-1,b=-1): "Set color for all stroking operations" if((r==0 and g==0 and b==0) or g==-1): self.draw_color=sprintf('%.3f G',r/255.0) else: self.draw_color=sprintf('%.3f %.3f %.3f RG',r/255.0,g/255.0,b/255.0) if(self.page>0): self._out(self.draw_color) def set_fill_color(self,r,g=-1,b=-1): "Set color for all filling operations" if((r==0 and g==0 and b==0) or g==-1): self.fill_color=sprintf('%.3f g',r/255.0) else: self.fill_color=sprintf('%.3f %.3f %.3f rg',r/255.0,g/255.0,b/255.0) self.color_flag=(self.fill_color!=self.text_color) if(self.page>0): self._out(self.fill_color) def set_text_color(self, r,g=-1,b=-1): "Set color for text" if((r==0 and g==0 and b==0) or g==-1): self.text_color=sprintf('%.3f g',r/255.0) else: self.text_color=sprintf('%.3f %.3f %.3f rg',r/255.0,g/255.0,b/255.0) self.color_flag=(self.fill_color!=self.text_color) def get_string_width(self, s): "Get width of a string in the current font" s = self.normalize_text(s) cw=self.current_font['cw'] w=0 l=len(s) if self.unifontsubset: for char in s: char = ord(char) if len(cw) > char: w += cw[char] # ord(cw[2*char])<<8 + ord(cw[2*char+1]) #elif (char>0 and char<128 and isset($cw[chr($char)])) { $w += $cw[chr($char)]; } elif (self.current_font['desc']['MissingWidth']) : w += self.current_font['desc']['MissingWidth'] #elif (isset($this->CurrentFont['MissingWidth'])) { $w += $this->CurrentFont['MissingWidth']; } else: w += 500 else: for i in range(0, l): w += cw.get(s[i],0) return w*self.font_size/1000.0 def set_line_width(self, width): "Set line width" self.line_width=width if(self.page>0): self._out(sprintf('%.2f w',width*self.k)) @check_page def line(self, x1,y1,x2,y2): "Draw a line" self._out(sprintf('%.2f %.2f m %.2f %.2f l S',x1*self.k,(self.h-y1)*self.k,x2*self.k,(self.h-y2)*self.k)) def _set_dash(self, dash_length=False, space_length=False): if(dash_length and space_length): s = sprintf('[%.3f %.3f] 0 d', dash_length*self.k, space_length*self.k) else: s = '[] 0 d' self._out(s) @check_page def dashed_line(self, x1,y1,x2,y2, dash_length=1, space_length=1): """Draw a dashed line. Same interface as line() except: - dash_length: Length of the dash - space_length: Length of the space between dashes""" self._set_dash(dash_length, space_length) self.line(x1, y1, x2, y2) self._set_dash() @check_page def rect(self, x,y,w,h,style=''): "Draw a rectangle" if(style=='F'): op='f' elif(style=='FD' or style=='DF'): op='B' else: op='S' self._out(sprintf('%.2f %.2f %.2f %.2f re %s',x*self.k,(self.h-y)*self.k,w*self.k,-h*self.k,op)) @check_page def ellipse(self, x,y,w,h,style=''): "Draw a ellipse" if(style=='F'): op='f' elif(style=='FD' or style=='DF'): op='B' else: op='S' cx = x + w/2.0 cy = y + h/2.0 rx = w/2.0 ry = h/2.0 lx = 4.0/3.0*(math.sqrt(2)-1)*rx ly = 4.0/3.0*(math.sqrt(2)-1)*ry self._out(sprintf('%.2f %.2f m %.2f %.2f %.2f %.2f %.2f %.2f c', (cx+rx)*self.k, (self.h-cy)*self.k, (cx+rx)*self.k, (self.h-(cy-ly))*self.k, (cx+lx)*self.k, (self.h-(cy-ry))*self.k, cx*self.k, (self.h-(cy-ry))*self.k)) self._out(sprintf('%.2f %.2f %.2f %.2f %.2f %.2f c', (cx-lx)*self.k, (self.h-(cy-ry))*self.k, (cx-rx)*self.k, (self.h-(cy-ly))*self.k, (cx-rx)*self.k, (self.h-cy)*self.k)) self._out(sprintf('%.2f %.2f %.2f %.2f %.2f %.2f c', (cx-rx)*self.k, (self.h-(cy+ly))*self.k, (cx-lx)*self.k, (self.h-(cy+ry))*self.k, cx*self.k, (self.h-(cy+ry))*self.k)) self._out(sprintf('%.2f %.2f %.2f %.2f %.2f %.2f c %s', (cx+lx)*self.k, (self.h-(cy+ry))*self.k, (cx+rx)*self.k, (self.h-(cy+ly))*self.k, (cx+rx)*self.k, (self.h-cy)*self.k, op)) def add_font(self, family, style='', fname='', uni=False): "Add a TrueType or Type1 font" family = family.lower() if (fname == ''): fname = family.replace(' ','') + style.lower() + '.pkl' if (family == 'arial'): family = 'helvetica' style = style.upper() if (style == 'IB'): style = 'BI' fontkey = family+style if fontkey in self.fonts: # Font already added! return if (uni): global SYSTEM_TTFONTS, FPDF_CACHE_MODE, FPDF_CACHE_DIR if os.path.exists(fname): ttffilename = fname elif (FPDF_FONT_DIR and os.path.exists(os.path.join(FPDF_FONT_DIR, fname))): ttffilename = os.path.join(FPDF_FONT_DIR, fname) elif (SYSTEM_TTFONTS and os.path.exists(os.path.join(SYSTEM_TTFONTS, fname))): ttffilename = os.path.join(SYSTEM_TTFONTS, fname) else: raise RuntimeError("TTF Font file not found: %s" % fname) name = '' if FPDF_CACHE_MODE == 0: unifilename = os.path.splitext(ttffilename)[0] + '.pkl' elif FPDF_CACHE_MODE == 2: unifilename = os.path.join(FPDF_CACHE_DIR, \ hashpath(ttffilename) + ".pkl") else: unifilename = None if unifilename and os.path.exists(unifilename): fh = open(unifilename, "rb") try: font_dict = pickle.load(fh) finally: fh.close() else: ttf = TTFontFile() ttf.getMetrics(ttffilename) desc = { 'Ascent': int(round(ttf.ascent, 0)), 'Descent': int(round(ttf.descent, 0)), 'CapHeight': int(round(ttf.capHeight, 0)), 'Flags': ttf.flags, 'FontBBox': "[%s %s %s %s]" % ( int(round(ttf.bbox[0], 0)), int(round(ttf.bbox[1], 0)), int(round(ttf.bbox[2], 0)), int(round(ttf.bbox[3], 0))), 'ItalicAngle': int(ttf.italicAngle), 'StemV': int(round(ttf.stemV, 0)), 'MissingWidth': int(round(ttf.defaultWidth, 0)), } # Generate metrics .pkl file font_dict = { 'name': re.sub('[ ()]', '', ttf.fullName), 'type': 'TTF', 'desc': desc, 'up': round(ttf.underlinePosition), 'ut': round(ttf.underlineThickness), 'ttffile': ttffilename, 'fontkey': fontkey, 'originalsize': os.stat(ttffilename).st_size, 'cw': ttf.charWidths, } if unifilename: try: fh = open(unifilename, "wb") pickle.dump(font_dict, fh) fh.close() except IOError: if not exception().errno == errno.EACCES: raise # Not a permission error. del ttf if hasattr(self,'str_alias_nb_pages'): sbarr = list(range(0,57)) # include numbers in the subset! else: sbarr = list(range(0,32)) self.fonts[fontkey] = { 'i': len(self.fonts)+1, 'type': font_dict['type'], 'name': font_dict['name'], 'desc': font_dict['desc'], 'up': font_dict['up'], 'ut': font_dict['ut'], 'cw': font_dict['cw'], 'ttffile': font_dict['ttffile'], 'fontkey': fontkey, 'subset': sbarr, 'unifilename': unifilename, } self.font_files[fontkey] = {'length1': font_dict['originalsize'], 'type': "TTF", 'ttffile': ttffilename} self.font_files[fname] = {'type': "TTF"} else: fontfile = open(fname) try: font_dict = pickle.load(fontfile) finally: fontfile.close() self.fonts[fontkey] = {'i': len(self.fonts)+1} self.fonts[fontkey].update(font_dict) if (diff): #Search existing encodings d = 0 nb = len(self.diffs) for i in range(1, nb+1): if(self.diffs[i] == diff): d = i break if (d == 0): d = nb + 1 self.diffs[d] = diff self.fonts[fontkey]['diff'] = d filename = font_dict.get('filename') if (filename): if (type == 'TrueType'): self.font_files[filename]={'length1': originalsize} else: self.font_files[filename]={'length1': size1, 'length2': size2} def set_font(self, family,style='',size=0): "Select a font; size given in points" family=family.lower() if(family==''): family=self.font_family if(family=='arial'): family='helvetica' elif(family=='symbol' or family=='zapfdingbats'): style='' style=style.upper() if('U' in style): self.underline=1 style=style.replace('U','') else: self.underline=0 if(style=='IB'): style='BI' if(size==0): size=self.font_size_pt #Test if font is already selected if(self.font_family==family and self.font_style==style and self.font_size_pt==size): return #Test if used for the first time fontkey=family+style if fontkey not in self.fonts: #Check if one of the standard fonts if fontkey in self.core_fonts: if fontkey not in fpdf_charwidths: #Load metric file name=os.path.join(FPDF_FONT_DIR,family) if(family=='times' or family=='helvetica'): name+=style.lower() exec(compile(open(name+'.font').read(), name+'.font', 'exec')) if fontkey not in fpdf_charwidths: self.error('Could not include font metric file for'+fontkey) i=len(self.fonts)+1 self.fonts[fontkey]={'i':i,'type':'core','name':self.core_fonts[fontkey],'up':-100,'ut':50,'cw':fpdf_charwidths[fontkey]} else: self.error('Undefined font: '+family+' '+style) #Select it self.font_family=family self.font_style=style self.font_size_pt=size self.font_size=size/self.k self.current_font=self.fonts[fontkey] self.unifontsubset = (self.fonts[fontkey]['type'] == 'TTF') if(self.page>0): self._out(sprintf('BT /F%d %.2f Tf ET',self.current_font['i'],self.font_size_pt)) def set_font_size(self, size): "Set font size in points" if(self.font_size_pt==size): return self.font_size_pt=size self.font_size=size/self.k if(self.page>0): self._out(sprintf('BT /F%d %.2f Tf ET',self.current_font['i'],self.font_size_pt)) def add_link(self): "Create a new internal link" n=len(self.links)+1 self.links[n]=(0,0) return n def set_link(self, link,y=0,page=-1): "Set destination of internal link" if(y==-1): y=self.y if(page==-1): page=self.page self.links[link]=[page,y] def link(self, x,y,w,h,link): "Put a link on the page" if not self.page in self.page_links: self.page_links[self.page] = [] self.page_links[self.page] += [(x*self.k,self.h_pt-y*self.k,w*self.k,h*self.k,link),] @check_page def text(self, x, y, txt=''): "Output a string" txt = self.normalize_text(txt) if (self.unifontsubset): txt2 = self._escape(UTF8ToUTF16BE(txt, False)) for uni in UTF8StringToArray(txt): self.current_font['subset'].append(uni) else: txt2 = self._escape(txt) s=sprintf('BT %.2f %.2f Td (%s) Tj ET',x*self.k,(self.h-y)*self.k, txt2) if(self.underline and txt!=''): s+=' '+self._dounderline(x,y,txt) if(self.color_flag): s='q '+self.text_color+' '+s+' Q' self._out(s) @check_page def rotate(self, angle, x=None, y=None): if x is None: x = self.x if y is None: y = self.y; if self.angle!=0: self._out('Q') self.angle = angle if angle!=0: angle *= math.pi/180; c = math.cos(angle); s = math.sin(angle); cx = x*self.k; cy = (self.h-y)*self.k s = sprintf('q %.5F %.5F %.5F %.5F %.2F %.2F cm 1 0 0 1 %.2F %.2F cm',c,s,-s,c,cx,cy,-cx,-cy) self._out(s) def accept_page_break(self): "Accept automatic page break or not" return self.auto_page_break @check_page def cell(self, w,h=0,txt='',border=0,ln=0,align='',fill=0,link=''): "Output a cell" txt = self.normalize_text(txt) k=self.k if(self.y+h>self.page_break_trigger and not self.in_footer and self.accept_page_break()): #Automatic page break x=self.x ws=self.ws if(ws>0): self.ws=0 self._out('0 Tw') self.add_page(self.cur_orientation) self.x=x if(ws>0): self.ws=ws self._out(sprintf('%.3f Tw',ws*k)) if(w==0): w=self.w-self.r_margin-self.x s='' if(fill==1 or border==1): if(fill==1): if border==1: op='B' else: op='f' else: op='S' s=sprintf('%.2f %.2f %.2f %.2f re %s ',self.x*k,(self.h-self.y)*k,w*k,-h*k,op) if(isinstance(border,basestring)): x=self.x y=self.y if('L' in border): s+=sprintf('%.2f %.2f m %.2f %.2f l S ',x*k,(self.h-y)*k,x*k,(self.h-(y+h))*k) if('T' in border): s+=sprintf('%.2f %.2f m %.2f %.2f l S ',x*k,(self.h-y)*k,(x+w)*k,(self.h-y)*k) if('R' in border): s+=sprintf('%.2f %.2f m %.2f %.2f l S ',(x+w)*k,(self.h-y)*k,(x+w)*k,(self.h-(y+h))*k) if('B' in border): s+=sprintf('%.2f %.2f m %.2f %.2f l S ',x*k,(self.h-(y+h))*k,(x+w)*k,(self.h-(y+h))*k) if(txt!=''): if(align=='R'): dx=w-self.c_margin-self.get_string_width(txt) elif(align=='C'): dx=(w-self.get_string_width(txt))/2.0 else: dx=self.c_margin if(self.color_flag): s+='q '+self.text_color+' ' # If multibyte, Tw has no effect - do word spacing using an adjustment before each space if (self.ws and self.unifontsubset): for uni in UTF8StringToArray(txt): self.current_font['subset'].append(uni) space = self._escape(UTF8ToUTF16BE(' ', False)) s += sprintf('BT 0 Tw %.2F %.2F Td [',(self.x + dx) * k,(self.h - (self.y + 0.5*h+ 0.3 * self.font_size)) * k) t = txt.split(' ') numt = len(t) for i in range(numt): tx = t[i] tx = '(' + self._escape(UTF8ToUTF16BE(tx, False)) + ')' s += sprintf('%s ', tx); if ((i+1)0): #Go to next line self.y+=h if(ln==1): self.x=self.l_margin else: self.x+=w @check_page def multi_cell(self, w, h, txt='', border=0, align='J', fill=0, split_only=False): "Output text with automatic or explicit line breaks" txt = self.normalize_text(txt) ret = [] # if split_only = True, returns splited text cells cw=self.current_font['cw'] if(w==0): w=self.w-self.r_margin-self.x wmax=(w-2*self.c_margin)*1000.0/self.font_size s=txt.replace("\r",'') nb=len(s) if(nb>0 and s[nb-1]=="\n"): nb-=1 b=0 if(border): if(border==1): border='LTRB' b='LRT' b2='LR' else: b2='' if('L' in border): b2+='L' if('R' in border): b2+='R' if ('T' in border): b=b2+'T' else: b=b2 sep=-1 i=0 j=0 l=0 ns=0 nl=1 while(i0): self.ws=0 if not split_only: self._out('0 Tw') if not split_only: self.cell(w,h,substr(s,j,i-j),b,2,align,fill) else: ret.append(substr(s,j,i-j)) i+=1 sep=-1 j=i l=0 ns=0 nl+=1 if(border and nl==2): b=b2 continue if(c==' '): sep=i ls=l ns+=1 if self.unifontsubset: l += self.get_string_width(c) / self.font_size*1000.0 else: l += cw.get(c,0) if(l>wmax): #Automatic line break if(sep==-1): if(i==j): i+=1 if(self.ws>0): self.ws=0 if not split_only: self._out('0 Tw') if not split_only: self.cell(w,h,substr(s,j,i-j),b,2,align,fill) else: ret.append(substr(s,j,i-j)) else: if(align=='J'): if ns>1: self.ws=(wmax-ls)/1000.0*self.font_size/(ns-1) else: self.ws=0 if not split_only: self._out(sprintf('%.3f Tw',self.ws*self.k)) if not split_only: self.cell(w,h,substr(s,j,sep-j),b,2,align,fill) else: ret.append(substr(s,j,sep-j)) i=sep+1 sep=-1 j=i l=0 ns=0 nl+=1 if(border and nl==2): b=b2 else: i+=1 #Last chunk if(self.ws>0): self.ws=0 if not split_only: self._out('0 Tw') if(border and 'B' in border): b+='B' if not split_only: self.cell(w,h,substr(s,j,i-j),b,2,align,fill) self.x=self.l_margin else: ret.append(substr(s,j,i-j)) return ret @check_page def write(self, h, txt='', link=''): "Output text in flowing mode" txt = self.normalize_text(txt) cw=self.current_font['cw'] w=self.w-self.r_margin-self.x wmax=(w-2*self.c_margin)*1000.0/self.font_size s=txt.replace("\r",'') nb=len(s) sep=-1 i=0 j=0 l=0 nl=1 while(iwmax): #Automatic line break if(sep==-1): if(self.x>self.l_margin): #Move to next line self.x=self.l_margin self.y+=h w=self.w-self.r_margin-self.x wmax=(w-2*self.c_margin)*1000.0/self.font_size i+=1 nl+=1 continue if(i==j): i+=1 self.cell(w,h,substr(s,j,i-j),0,2,'',0,link) else: self.cell(w,h,substr(s,j,sep-j),0,2,'',0,link) i=sep+1 sep=-1 j=i l=0 if(nl==1): self.x=self.l_margin w=self.w-self.r_margin-self.x wmax=(w-2*self.c_margin)*1000.0/self.font_size nl+=1 else: i+=1 #Last chunk if(i!=j): self.cell(l/1000.0*self.font_size,h,substr(s,j),0,0,'',0,link) @check_page def image(self, name, x=None, y=None, w=0,h=0,type='',link=''): "Put an image on the page" if not name in self.images: #First use of image, get info if(type==''): pos=name.rfind('.') if(not pos): self.error('image file has no extension and no type was specified: '+name) type=substr(name,pos+1) type=type.lower() if(type=='jpg' or type=='jpeg'): info=self._parsejpg(name) elif(type=='png'): info=self._parsepng(name) else: #Allow for additional formats #maybe the image is not showing the correct extension, #but the header is OK, succeed_parsing = False #try all the parsing functions parsing_functions = [self._parsejpg,self._parsepng,self._parsegif] for pf in parsing_functions: try: info = pf(name) succeed_parsing = True break; except: pass #last resource if not succeed_parsing: mtd='_parse'+type if not hasattr(self,mtd): self.error('Unsupported image type: '+type) info=getattr(self, mtd)(name) mtd='_parse'+type if not hasattr(self,mtd): self.error('Unsupported image type: '+type) info=getattr(self, mtd)(name) info['i']=len(self.images)+1 self.images[name]=info else: info=self.images[name] #Automatic width and height calculation if needed if(w==0 and h==0): #Put image at 72 dpi w=info['w']/self.k h=info['h']/self.k elif(w==0): w=h*info['w']/info['h'] elif(h==0): h=w*info['h']/info['w'] # Flowing mode if y is None: if (self.y + h > self.page_break_trigger and not self.in_footer and self.accept_page_break()): #Automatic page break x = self.x self.add_page(self.cur_orientation) self.x = x y = self.y self.y += h if x is None: x = self.x self._out(sprintf('q %.2f 0 0 %.2f %.2f %.2f cm /I%d Do Q',w*self.k,h*self.k,x*self.k,(self.h-(y+h))*self.k,info['i'])) if(link): self.link(x,y,w,h,link) @check_page def ln(self, h=''): "Line Feed; default value is last cell height" self.x=self.l_margin if(isinstance(h, basestring)): self.y+=self.lasth else: self.y+=h def get_x(self): "Get x position" return self.x def set_x(self, x): "Set x position" if(x>=0): self.x=x else: self.x=self.w+x def get_y(self): "Get y position" return self.y def set_y(self, y): "Set y position and reset x" self.x=self.l_margin if(y>=0): self.y=y else: self.y=self.h+y def set_xy(self, x,y): "Set x and y positions" self.set_y(y) self.set_x(x) def output(self, name='',dest=''): "Output PDF to some destination" #Finish document if necessary if(self.state<3): self.close() dest=dest.upper() if(dest==''): if(name==''): name='doc.pdf' dest='I' else: dest='F' if dest=='I': print(self.buffer) elif dest=='D': print(self.buffer) elif dest=='F': #Save to local file f=open(name,'wb') if(not f): self.error('Unable to create output file: '+name) if PY3K: # manage binary data as latin1 until PEP461 or similar is implemented f.write(self.buffer.encode("latin1")) else: f.write(self.buffer) f.close() elif dest=='S': #Return as a string return self.buffer else: self.error('Incorrect output destination: '+dest) return '' def normalize_text(self, txt): "Check that text input is in the correct format/encoding" # - for TTF unicode fonts: unicode object (utf8 encoding) # - for built-in fonts: string instances (latin 1 encoding) if self.unifontsubset and isinstance(txt, str) and not PY3K: txt = txt.decode('utf8') elif not self.unifontsubset and isinstance(txt, unicode) and not PY3K: txt = txt.encode('latin1') return txt def _dochecks(self): #Check for locale-related bug # if(1.1==1): # self.error("Don\'t alter the locale before including class file"); #Check for decimal separator if(sprintf('%.1f',1.0)!='1.0'): import locale locale.setlocale(locale.LC_NUMERIC,'C') def _getfontpath(self): return FPDF_FONT_DIR+'/' def _putpages(self): nb=self.page if hasattr(self,'str_alias_nb_pages'): # Replace number of pages in fonts using subsets (unicode) alias = UTF8ToUTF16BE(self.str_alias_nb_pages, False) r = UTF8ToUTF16BE(str(nb), False) for n in range(1, nb+1): self.pages[n] = self.pages[n].replace(alias, r) # Now repeat for no pages in non-subset fonts for n in range(1,nb+1): self.pages[n]=self.pages[n].replace(self.str_alias_nb_pages,str(nb)) if(self.def_orientation=='P'): w_pt=self.fw_pt h_pt=self.fh_pt else: w_pt=self.fh_pt h_pt=self.fw_pt if self.compress: filter='/Filter /FlateDecode ' else: filter='' for n in range(1,nb+1): #Page self._newobj() self._out('<>>>' else: l=self.links[pl[4]] if l[0] in self.orientation_changes: h=w_pt else: h=h_pt annots+=sprintf('/Dest [%d 0 R /XYZ 0 %.2f null]>>',1+2*l[0],h-l[1]*self.k) self._out(annots+']') elif n == 1 and self.signer: self._out('/Annots [SIGNER 0 R]') if(self.pdf_version>'1.3'): self._out('/Group <>') self._out('/Contents '+str(self.n+1)+' 0 R>>') self._out('endobj') #Page content if self.compress: # manage binary data as latin1 until PEP461 or similar is implemented p = self.pages[n].encode("latin1") if PY3K else self.pages[n] p = zlib.compress(p) else: p = self.pages[n] self._newobj() self._out('<<'+filter+'/Length '+str(len(p))+'>>') self._putstream(p) self._out('endobj') #Pages root self.offsets[1]=len(self.buffer) self._out('1 0 obj') self._out('<>') self._out('endobj') def _putfonts(self): nf=self.n for diff in self.diffs: #Encodings self._newobj() self._out('<>') self._out('endobj') for name,info in self.font_files.items(): if 'type' in info and info['type'] != 'TTF': #Font file embedding self._newobj() self.font_files[name]['n']=self.n font='' f=open(self._getfontpath()+name,'rb',1) if(not f): self.error('Font file not found') font=f.read() f.close() compressed=(substr(name,-2)=='.z') if(not compressed and 'length2' in info): header=(ord(font[0])==128) if(header): #Strip first binary header font=substr(font,6) if(header and ord(font[info['length1']])==128): #Strip second binary header font=substr(font,0,info['length1'])+substr(font,info['length1']+6) self._out('<>') self._putstream(font) self._out('endobj') flist = [(x[1]["i"],x[0],x[1]) for x in self.fonts.items()] flist.sort() for idx,k,font in flist: #Font objects self.fonts[k]['n']=self.n+1 type=font['type'] name=font['name'] if(type=='core'): #Standard font self._newobj() self._out('<>') self._out('endobj') elif(type=='Type1' or type=='TrueType'): #Additional Type1 or TrueType font self._newobj() self._out('<>') self._out('endobj') #Widths self._newobj() cw=font['cw'] s='[' for i in range(32,256): # Get doesn't rise exception; returns 0 instead of None if not set s+=str(cw.get(chr(i)) or 0)+' ' self._out(s+']') self._out('endobj') #Descriptor self._newobj() s='<>') self._out('endobj') elif (type == 'TTF'): self.fonts[k]['n'] = self.n + 1 ttf = TTFontFile() fontname = 'MPDFAA' + '+' + font['name'] subset = font['subset'] del subset[0] ttfontstream = ttf.makeSubset(font['ttffile'], subset) ttfontsize = len(ttfontstream) fontstream = zlib.compress(ttfontstream) codeToGlyph = ttf.codeToGlyph ##del codeToGlyph[0] # Type0 Font # A composite font - a font composed of other fonts, organized hierarchically self._newobj() self._out('<>') self._out('endobj') # CIDFontType2 # A CIDFont whose glyph descriptions are based on TrueType font technology self._newobj() self._out('<>') self._out('endobj') # ToUnicode self._newobj() toUni = "/CIDInit /ProcSet findresource begin\n" \ "12 dict begin\n" \ "begincmap\n" \ "/CIDSystemInfo\n" \ "<> def\n" \ "/CMapName /Adobe-Identity-UCS def\n" \ "/CMapType 2 def\n" \ "1 begincodespacerange\n" \ "<0000> \n" \ "endcodespacerange\n" \ "1 beginbfrange\n" \ "<0000> <0000>\n" \ "endbfrange\n" \ "endcmap\n" \ "CMapName currentdict /CMap defineresource pop\n" \ "end\n" \ "end" self._out('<>') self._putstream(toUni) self._out('endobj') # CIDSystemInfo dictionary self._newobj() self._out('<>') self._out('endobj') # Font descriptor self._newobj() self._out('<>') self._out('endobj') # Embed CIDToGIDMap # A specification of the mapping from CIDs to glyph indices cidtogidmap = ''; cidtogidmap = ["\x00"] * 256*256*2 for cc, glyph in codeToGlyph.items(): cidtogidmap[cc*2] = chr(glyph >> 8) cidtogidmap[cc*2 + 1] = chr(glyph & 0xFF) cidtogidmap = ''.join(cidtogidmap) if PY3K: # manage binary data as latin1 until PEP461-like function is implemented cidtogidmap = cidtogidmap.encode("latin1") cidtogidmap = zlib.compress(cidtogidmap); self._newobj() self._out('<>') self._putstream(cidtogidmap) self._out('endobj') #Font file self._newobj() self._out('<>') self._putstream(fontstream) self._out('endobj') del ttf else: #Allow for additional types mtd='_put'+type.lower() if(not method_exists(self,mtd)): self.error('Unsupported font type: '+type) self.mtd(font) def _putTTfontwidths(self, font, maxUni): if font['unifilename']: cw127fname = os.path.splitext(font['unifilename'])[0] + '.cw127.pkl' else: cw127fname = None if cw127fname and os.path.exists(cw127fname): fh = open(cw127fname, "rb"); try: font_dict = pickle.load(fh) finally: fh.close() rangeid = font_dict['rangeid'] range_ = font_dict['range'] prevcid = font_dict['prevcid'] prevwidth = font_dict['prevwidth'] interval = font_dict['interval'] range_interval = font_dict['range_interval'] startcid = 128 else: rangeid = 0 range_ = {} range_interval = {} prevcid = -2 prevwidth = -1 interval = False startcid = 1 cwlen = maxUni + 1 # for each character for cid in range(startcid, cwlen): if cid == 128 and cw127fname and not os.path.exists(cw127fname): try: fh = open(cw127fname, "wb") font_dict = {} font_dict['rangeid'] = rangeid font_dict['prevcid'] = prevcid font_dict['prevwidth'] = prevwidth font_dict['interval'] = interval font_dict['range_interval'] = range_interval font_dict['range'] = range_ pickle.dump(font_dict, fh) fh.close() except IOError: if not exception().errno == errno.EACCES: raise # Not a permission error. if (font['cw'][cid] == 0): continue width = font['cw'][cid] if (width == 65535): width = 0 if (cid > 255 and (cid not in font['subset']) or not cid): # continue if ('dw' not in font or (font['dw'] and width != font['dw'])): if (cid == (prevcid + 1)): if (width == prevwidth): if (width == range_[rangeid][0]): range_.setdefault(rangeid, []).append(width) else: range_[rangeid].pop() # new range rangeid = prevcid range_[rangeid] = [prevwidth, width] interval = True range_interval[rangeid] = True else: if (interval): # new range rangeid = cid range_[rangeid] = [width] else: range_[rangeid].append(width) interval = False else: rangeid = cid range_[rangeid] = [width] interval = False prevcid = cid prevwidth = width prevk = -1 nextk = -1 prevint = False for k, ws in sorted(range_.items()): cws = len(ws) if (k == nextk and not prevint and (not k in range_interval or cws < 3)): if (k in range_interval): del range_interval[k] range_[prevk] = range_[prevk] + range_[k] del range_[k] else: prevk = k nextk = k + cws if (k in range_interval): prevint = (cws > 3) del range_interval[k] nextk -= 1 else: prevint = False w = [] for k, ws in sorted(range_.items()): if (len(set(ws)) == 1): w.append(' %s %s %s' % (k, k + len(ws) - 1, ws[0])) else: w.append(' %s [ %s ]\n' % (k, ' '.join([str(int(h)) for h in ws]))) ## self._out('/W [%s]' % ''.join(w)) def _putimages(self): filter='' if self.compress: filter='/Filter /FlateDecode ' i = [(x[1]["i"],x[1]) for x in self.images.items()] i.sort() for idx,info in i: self._putimage(info) del info['data'] if 'smask' in info: del info['smask'] def _putimage(self, info): if 'data' in info: self._newobj() info['n']=self.n self._out('<>') if('trns' in info and isinstance(info['trns'], list)): trns='' for i in range(0,len(info['trns'])): trns+=str(info['trns'][i])+' '+str(info['trns'][i])+' ' self._out('/Mask ['+trns+']') if('smask' in info): self._out('/SMask ' + str(self.n+1) + ' 0 R'); self._out('/Length '+str(len(info['data']))+'>>') self._putstream(info['data']) self._out('endobj') # Soft mask if('smask' in info): dp = '/Predictor 15 /Colors 1 /BitsPerComponent 8 /Columns ' + str(info['w']) smask = {'w': info['w'], 'h': info['h'], 'cs': 'DeviceGray', 'bpc': 8, 'f': info['f'], 'dp': dp, 'data': info['smask']} self._putimage(smask) #Palette if(info['cs']=='Indexed'): self._newobj() filter = self.compress and '/Filter /FlateDecode ' or '' if self.compress: pal=zlib.compress(info['pal']) else: pal=info['pal'] self._out('<<'+filter+'/Length '+str(len(pal))+'>>') self._putstream(pal) self._out('endobj') def _putxobjectdict(self): i = [(x["i"],x["n"]) for x in self.images.values()] i.sort() for idx,n in i: self._out('/I'+str(idx)+' '+str(n)+' 0 R') def _putresourcedict(self): self._out('/ProcSet [/PDF /Text /ImageB /ImageC /ImageI]') self._out('/Font <<') f = [(x["i"],x["n"]) for x in self.fonts.values()] f.sort() for idx,n in f: self._out('/F'+str(idx)+' '+str(n)+' 0 R') self._out('>>') self._out('/XObject <<') self._putxobjectdict() self._out('>>') def _putresources(self): self._putfonts() self._putimages() #Resource dictionary self.offsets[2]=len(self.buffer) self._out('2 0 obj') self._out('<<') self._putresourcedict() self._out('>>') self._out('endobj') def _putinfo(self): self._out('/Producer '+self._textstring('PyFPDF '+FPDF_VERSION+' http://pyfpdf.googlecode.com/')) if hasattr(self,'title'): self._out('/Title '+self._textstring(self.title)) if hasattr(self,'subject'): self._out('/Subject '+self._textstring(self.subject)) if hasattr(self,'author'): self._out('/Author '+self._textstring(self.author)) if hasattr (self,'keywords'): self._out('/Keywords '+self._textstring(self.keywords)) if hasattr(self,'creator'): self._out('/Creator '+self._textstring(self.creator)) self._out('/CreationDate '+self._textstring('D:'+datetime.now().strftime('%Y%m%d%H%M%S'))) def _putcatalog(self): if self.signer: self._out('/AcroForm <>') self._out('/Type /Catalog') self._out('/Pages 1 0 R') if(self.zoom_mode=='fullpage'): self._out('/OpenAction [3 0 R /Fit]') elif(self.zoom_mode=='fullwidth'): self._out('/OpenAction [3 0 R /FitH null]') elif(self.zoom_mode=='real'): self._out('/OpenAction [3 0 R /XYZ null null 1]') elif(not isinstance(self.zoom_mode,basestring)): self._out(sprintf('/OpenAction [3 0 R /XYZ null null %s]',self.zoom_mode/100)) if(self.layout_mode=='single'): self._out('/PageLayout /SinglePage') elif(self.layout_mode=='continuous'): self._out('/PageLayout /OneColumn') elif(self.layout_mode=='two'): self._out('/PageLayout /TwoColumnLeft') def _putheader(self): self._out('%PDF-'+self.pdf_version) self._out('%\xba\xba\xfe\xda') def _puttrailer(self): h1 = hashlib.md5(self.buffer.encode('utf8')).hexdigest().upper() h2 = hashlib.md5(datetime.now().strftime('%Y-%m-%d %H:%M:%S').encode('utf8')).hexdigest().upper() self._out('/Size '+str(self.n+1)) self._out('/Root '+str(self.root)+' 0 R') self._out('/Info '+str(self.root-1)+' 0 R') self._out('/ID [<'+h1+'><'+h2+'>]') def _enddoc(self): self._putheader() self._putpages() self._putresources() #Info self._newobj() self._out('<<') self._putinfo() self._out('>>') self._out('endobj') #Catalog self._newobj() self._out('<<') self._putcatalog() self._out('>>') self._out('endobj') self.root = self.n self.pkcs11_signature() #Cross-ref o=len(self.buffer) self._out('xref') self._out('0 '+(str(self.n+1))) self._out('0000000000 65535 f ') for i in range(1,self.n+1): self._out(sprintf('%010d 00000 n ',self.offsets[i])) #Trailer self._out('trailer') self._out('<<') self._puttrailer() self._out('>>') self._out('startxref') self._out(o) self._out('%%EOF') self.pkcs11_sign() self.state=3 signer = False def pkcs11_signature(self): pass def pkcs11_sign(self): pass def _beginpage(self, orientation): self.page+=1 self.pages[self.page]='' self.state=2 self.x=self.l_margin self.y=self.t_margin self.font_family='' #Page orientation if(not orientation): orientation=self.def_orientation else: orientation=orientation[0].upper() if(orientation!=self.def_orientation): self.orientation_changes[self.page]=1 if(orientation!=self.cur_orientation): #Change orientation if(orientation=='P'): self.w_pt=self.fw_pt self.h_pt=self.fh_pt self.w=self.fw self.h=self.fh else: self.w_pt=self.fh_pt self.h_pt=self.fw_pt self.w=self.fh self.h=self.fw self.page_break_trigger=self.h-self.b_margin self.cur_orientation=orientation def _endpage(self): #End of page contents self.state=1 def _newobj(self): #Begin a new object self.n+=1 self.offsets[self.n]=len(self.buffer) self._out(str(self.n)+' 0 obj') def _dounderline(self, x,y,txt): #Underline text up=self.current_font['up'] ut=self.current_font['ut'] w=self.get_string_width(txt)+self.ws*txt.count(' ') return sprintf('%.2f %.2f %.2f %.2f re f',x*self.k,(self.h-(y-up/1000.0*self.font_size))*self.k,w*self.k,-ut/1000.0*self.font_size_pt) def _parsejpg(self, filename): # Extract info from a JPEG file try: f = open(filename, 'rb') while True: markerHigh, markerLow = struct.unpack('BB', f.read(2)) if markerHigh != 0xFF or markerLow < 0xC0: raise SyntaxError('No JPEG marker found') elif markerLow == 0xDA: # SOS raise SyntaxError('No JPEG SOF marker found') elif (markerLow == 0xC8 or # JPG (markerLow >= 0xD0 and markerLow <= 0xD9) or # RSTx (markerLow >= 0xF0 and markerLow <= 0xFD)): # JPGx pass else: dataSize, = struct.unpack('>H', f.read(2)) data = f.read(dataSize - 2) if dataSize > 2 else '' if ((markerLow >= 0xC0 and markerLow <= 0xC3) or # SOF0 - SOF3 (markerLow >= 0xC5 and markerLow <= 0xC7) or # SOF4 - SOF7 (markerLow >= 0xC9 and markerLow <= 0xCB) or # SOF9 - SOF11 (markerLow >= 0xCD and markerLow <= 0xCF)): # SOF13 - SOF15 bpc, height, width, layers = struct.unpack_from('>BHHB', data) colspace = 'DeviceRGB' if layers == 3 else ('DeviceCMYK' if layers == 4 else 'DeviceGray') break except Exception: self.error('Missing or incorrect image file: %s. error: %s' % (filename, str(exception()))) # Read whole file from the start f.seek(0) data = f.read() f.close() return {'w':width,'h':height,'cs':colspace,'bpc':bpc,'f':'DCTDecode','data':data} def _parsegif(self, filename): # Extract info from a GIF file (via PNG conversion) if Image is None: self.error('PIL is required for GIF support') try: im = Image.open(filename) except Exception: self.error('Missing or incorrect image file: %s. error: %s' % (filename, str(exception()))) else: # Use temporary file f = tempfile.NamedTemporaryFile(delete=False, suffix=".png") tmp = f.name f.close() if "transparency" in im.info: im.save(tmp, transparency = im.info['transparency']) else: im.save(tmp) info = self._parsepng(tmp) os.unlink(tmp) return info def _parsepng(self, name): #Extract info from a PNG file if name.startswith("http://") or name.startswith("https://"): f = urlopen(name) else: f=open(name,'rb') if(not f): self.error("Can't open image file: "+name) #Check signature magic = f.read(8).decode("latin1") signature = '\x89'+'PNG'+'\r'+'\n'+'\x1a'+'\n' if not PY3K: signature = signature.decode("latin1") if(magic!=signature): self.error('Not a PNG file: '+name) #Read header chunk f.read(4) chunk = f.read(4).decode("latin1") if(chunk!='IHDR'): self.error('Incorrect PNG file: '+name) w=self._freadint(f) h=self._freadint(f) bpc=ord(f.read(1)) if(bpc>8): self.error('16-bit depth not supported: '+name) ct=ord(f.read(1)) if(ct==0 or ct==4): colspace='DeviceGray' elif(ct==2 or ct==6): colspace='DeviceRGB' elif(ct==3): colspace='Indexed' else: self.error('Unknown color type: '+name) if(ord(f.read(1))!=0): self.error('Unknown compression method: '+name) if(ord(f.read(1))!=0): self.error('Unknown filter method: '+name) if(ord(f.read(1))!=0): self.error('Interlacing not supported: '+name) f.read(4) dp='/Predictor 15 /Colors ' if colspace == 'DeviceRGB': dp+='3' else: dp+='1' dp+=' /BitsPerComponent '+str(bpc)+' /Columns '+str(w)+'' #Scan chunks looking for palette, transparency and image data pal='' trns='' data=bytes() if PY3K else str() n=1 while n != None: n=self._freadint(f) type=f.read(4).decode("latin1") if(type=='PLTE'): #Read palette pal=f.read(n) f.read(4) elif(type=='tRNS'): #Read transparency info t=f.read(n) if(ct==0): trns=[ord(substr(t,1,1)),] elif(ct==2): trns=[ord(substr(t,1,1)),ord(substr(t,3,1)),ord(substr(t,5,1))] else: pos=t.find('\x00'.encode("latin1")) if(pos!=-1): trns=[pos,] f.read(4) elif(type=='IDAT'): #Read image data block data+=f.read(n) f.read(4) elif(type=='IEND'): break else: f.read(n+4) if(colspace=='Indexed' and not pal): self.error('Missing palette in '+name) f.close() info = {'w':w,'h':h,'cs':colspace,'bpc':bpc,'f':'FlateDecode','dp':dp,'pal':pal,'trns':trns,} if(ct>=4): # Extract alpha channel data = zlib.decompress(data) color = b('') alpha = b('') if(ct==4): # Gray image length = 2*w for i in range(h): pos = (1+length)*i color += b(data[pos]) alpha += b(data[pos]) line = substr(data, pos+1, length) re_c = re.compile('(.).'.encode("ascii"), flags=re.DOTALL) re_a = re.compile('.(.)'.encode("ascii"), flags=re.DOTALL) color += re_c.sub(lambda m: m.group(1), line) alpha += re_a.sub(lambda m: m.group(1), line) else: # RGB image length = 4*w for i in range(h): pos = (1+length)*i color += b(data[pos]) alpha += b(data[pos]) line = substr(data, pos+1, length) re_c = re.compile('(...).'.encode("ascii"), flags=re.DOTALL) re_a = re.compile('...(.)'.encode("ascii"), flags=re.DOTALL) color += re_c.sub(lambda m: m.group(1), line) alpha += re_a.sub(lambda m: m.group(1), line) del data data = zlib.compress(color) info['smask'] = zlib.compress(alpha) if (self.pdf_version < '1.4'): self.pdf_version = '1.4' info['data'] = data return info def _freadint(self, f): #Read a 4-byte integer from file try: return struct.unpack('>I', f.read(4))[0] except: return None def _textstring(self, s): #Format a text string return '('+self._escape(s)+')' def _escape(self, s): #Add \ before \, ( and ) return s.replace('\\','\\\\').replace(')','\\)').replace('(','\\(').replace('\r','\\r') def _putstream(self, s): self._out('stream') self._out(s) self._out('endstream') def _out(self, s): #Add a line to the document if PY3K and isinstance(s, bytes): # manage binary data as latin1 until PEP461-like function is implemented s = s.decode("latin1") elif not PY3K and isinstance(s, unicode): s = s.encode("latin1") # default encoding (font name and similar) elif not isinstance(s, basestring): s = str(s) if(self.state==2): self.pages[self.page]+=s+"\n" else: self.buffer+=s+"\n" @check_page def interleaved2of5(self, txt, x, y, w=1.0, h=10.0): "Barcode I2of5 (numeric), adds a 0 if odd lenght" narrow = w / 3.0 wide = w # wide/narrow codes for the digits bar_char={'0': 'nnwwn', '1': 'wnnnw', '2': 'nwnnw', '3': 'wwnnn', '4': 'nnwnw', '5': 'wnwnn', '6': 'nwwnn', '7': 'nnnww', '8': 'wnnwn', '9': 'nwnwn', 'A': 'nn', 'Z': 'wn'} self.set_fill_color(0) code = txt # add leading zero if code-length is odd if len(code) % 2 != 0: code = '0' + code # add start and stop codes code = 'AA' + code.lower() + 'ZA' for i in range(0, len(code), 2): # choose next pair of digits char_bar = code[i] char_space = code[i+1] # check whether it is a valid digit if not char_bar in bar_char.keys(): raise RuntimeError ('Char "%s" invalid for I25: ' % char_bar) if not char_space in bar_char.keys(): raise RuntimeError ('Char "%s" invalid for I25: ' % char_space) # create a wide/narrow-seq (first digit=bars, second digit=spaces) seq = '' for s in range(0, len(bar_char[char_bar])): seq += bar_char[char_bar][s] + bar_char[char_space][s] for bar in range(0, len(seq)): # set line_width depending on value if seq[bar] == 'n': line_width = narrow else: line_width = wide # draw every second value, the other is represented by space if bar % 2 == 0: self.rect(x, y, line_width, h, 'F') x += line_width @check_page def code39(self, txt, x, y, w=1.5, h=5.0): """Barcode 3of9""" dim = {'w': w, 'n': w/3.} chars = { '0': 'nnnwwnwnn', '1': 'wnnwnnnnw', '2': 'nnwwnnnnw', '3': 'wnwwnnnnn', '4': 'nnnwwnnnw', '5': 'wnnwwnnnn', '6': 'nnwwwnnnn', '7': 'nnnwnnwnw', '8': 'wnnwnnwnn', '9': 'nnwwnnwnn', 'A': 'wnnnnwnnw', 'B': 'nnwnnwnnw', 'C': 'wnwnnwnnn', 'D': 'nnnnwwnnw', 'E': 'wnnnwwnnn', 'F': 'nnwnwwnnn', 'G': 'nnnnnwwnw', 'H': 'wnnnnwwnn', 'I': 'nnwnnwwnn', 'J': 'nnnnwwwnn', 'K': 'wnnnnnnww', 'L': 'nnwnnnnww', 'M': 'wnwnnnnwn', 'N': 'nnnnwnnww', 'O': 'wnnnwnnwn', 'P': 'nnwnwnnwn', 'Q': 'nnnnnnwww', 'R': 'wnnnnnwwn', 'S': 'nnwnnnwwn', 'T': 'nnnnwnwwn', 'U': 'wwnnnnnnw', 'V': 'nwwnnnnnw', 'W': 'wwwnnnnnn', 'X': 'nwnnwnnnw', 'Y': 'wwnnwnnnn', 'Z': 'nwwnwnnnn', '-': 'nwnnnnwnw', '.': 'wwnnnnwnn', ' ': 'nwwnnnwnn', '*': 'nwnnwnwnn', '$': 'nwnwnwnnn', '/': 'nwnwnnnwn', '+': 'nwnnnwnwn', '%': 'nnnwnwnwn', } self.set_fill_color(0) for c in txt.upper(): if c not in chars: raise RuntimeError('Invalid char "%s" for Code39' % c) for i, d in enumerate(chars[c]): if i % 2 == 0: self.rect(x, y, dim[d], h, 'F') x += dim[d] x += dim['n'] endesive-2.19.1/endesive/pdf/fpdf/html.py000066400000000000000000000346151504236674500202430ustar00rootroot00000000000000# -*- coding: latin-1 -*- "HTML Renderer for FPDF.py" __author__ = "Mariano Reingart " __copyright__ = "Copyright (C) 2010 Mariano Reingart" __license__ = "LGPL 3.0" # Inspired by tuto5.py and several examples from fpdf.org, html2fpdf, etc. from .fpdf import FPDF from .py3k import PY3K, basestring, unicode, HTMLParser DEBUG = False def px2mm(px): return int(px)*25.4/72.0 def hex2dec(color = "#000000"): if color: r = int(color[1:3], 16) g = int(color[3:5], 16) b = int(color[5:7], 16) return r, g, b class HTML2FPDF(HTMLParser): "Render basic HTML to FPDF" def __init__(self, pdf, image_map=None): HTMLParser.__init__(self) self.style = {} self.pre = False self.href = '' self.align = '' self.page_links = {} self.font = None self.font_stack = [] self.pdf = pdf self.image_map = image_map or (lambda src: src) self.r = self.g = self.b = 0 self.indent = 0 self.bullet = [] self.set_font("times", 12) self.font_face = "times" # initialize font self.color = 0 #initialize font color self.table = None # table attributes self.table_col_width = None # column (header) widths self.table_col_index = None # current column index self.td = None # cell attributes self.th = False # header enabled self.tr = None self.theader = None # table header cells self.tfooter = None # table footer cells self.thead = None self.tfoot = None self.theader_out = self.tfooter_out = False self.hsize = dict(h1=2, h2=1.5, h3=1.17, h4=1, h5=0.83, h6=0.67) def width2mm(self, length): if length[-1]=='%': total = self.pdf.w - self.pdf.r_margin - self.pdf.l_margin if self.table['width'][-1]=='%': total *= int(self.table['width'][:-1])/100.0 return int(length[:-1]) * total / 101.0 else: return int(length) / 6.0 def handle_data(self, txt): if self.td is not None: # drawing a table? if 'width' not in self.td and 'colspan' not in self.td: try: l = [self.table_col_width[self.table_col_index]] except IndexError: raise RuntimeError("Table column/cell width not specified, unable to continue") elif 'colspan' in self.td: i = self.table_col_index colspan = int(self.td['colspan']) l = self.table_col_width[i:i+colspan] else: l = [self.td.get('width','240')] w = sum([self.width2mm(lenght) for lenght in l]) h = int(self.td.get('height', 0)) / 4 or self.h*1.30 self.table_h = h border = int(self.table.get('border', 0)) if not self.th: align = self.td.get('align', 'L')[0].upper() border = border and 'LR' else: self.set_style('B',True) border = border or 'B' align = self.td.get('align', 'C')[0].upper() bgcolor = hex2dec(self.td.get('bgcolor', self.tr.get('bgcolor', ''))) # parsing table header/footer (drawn later): if self.thead is not None: self.theader.append(((w,h,txt,border,0,align), bgcolor)) if self.tfoot is not None: self.tfooter.append(((w,h,txt,border,0,align), bgcolor)) # check if reached end of page, add table footer and header: height = h + (self.tfooter and self.tfooter[0][0][1] or 0) if self.pdf.y+height>self.pdf.page_break_trigger and not self.th: self.output_table_footer() self.pdf.add_page() self.theader_out = self.tfooter_out = False if self.tfoot is None and self.thead is None: if not self.theader_out: self.output_table_header() self.box_shadow(w, h, bgcolor) if DEBUG: print("td cell", self.pdf.x, w, txt, "*") self.pdf.cell(w,h,txt,border,0,align) elif self.table is not None: # ignore anything else than td inside a table pass elif self.align: if DEBUG: print("cell", txt, "*") self.pdf.cell(0,self.h,txt,0,1,self.align[0].upper(), self.href) else: txt = txt.replace("\n"," ") if self.href: self.put_link(self.href,txt) else: if DEBUG: print("write", txt, "*") self.pdf.write(self.h,txt) def box_shadow(self, w, h, bgcolor): if DEBUG: print("box_shadow", w, h, bgcolor) if bgcolor: fill_color = self.pdf.fill_color self.pdf.set_fill_color(*bgcolor) self.pdf.rect(self.pdf.x, self.pdf.y, w, h, 'F') self.pdf.fill_color = fill_color def output_table_header(self): if self.theader: b = self.b x = self.pdf.x self.pdf.set_x(self.table_offset) self.set_style('B',True) for cell, bgcolor in self.theader: self.box_shadow(cell[0], cell[1], bgcolor) self.pdf.cell(*cell) self.set_style('B',b) self.pdf.ln(self.theader[0][0][1]) self.pdf.set_x(self.table_offset) #self.pdf.set_x(x) self.theader_out = True def output_table_footer(self): if self.tfooter: x = self.pdf.x self.pdf.set_x(self.table_offset) #TODO: self.output_table_sep() for cell, bgcolor in self.tfooter: self.box_shadow(cell[0], cell[1], bgcolor) self.pdf.cell(*cell) self.pdf.ln(self.tfooter[0][0][1]) self.pdf.set_x(x) if int(self.table.get('border', 0)): self.output_table_sep() self.tfooter_out = True def output_table_sep(self): self.pdf.set_x(self.table_offset) x1 = self.pdf.x y1 = self.pdf.y w = sum([self.width2mm(lenght) for lenght in self.table_col_width]) self.pdf.line(x1,y1,x1+w,y1) def handle_starttag(self, tag, attrs): attrs = dict(attrs) if DEBUG: print("STARTTAG", tag, attrs) if tag=='b' or tag=='i' or tag=='u': self.set_style(tag,1) if tag=='a': self.href=attrs['href'] if tag=='br': self.pdf.ln(5) if tag=='p': self.pdf.ln(5) if attrs: if attrs: self.align = attrs.get('align') if tag in self.hsize: k = self.hsize[tag] self.pdf.ln(5*k) self.pdf.set_text_color(150,0,0) self.pdf.set_font_size(12 * k) if attrs: self.align = attrs.get('align') if tag=='hr': self.put_line() if tag=='pre': self.pdf.set_font('Courier','',11) self.pdf.set_font_size(11) self.set_style('B',False) self.set_style('I',False) self.pre = True if tag=='blockquote': self.set_text_color(100,0,45) self.pdf.ln(3) if tag=='ul': self.indent+=1 self.bullet.append('\x95') if tag=='ol': self.indent+=1 self.bullet.append(0) if tag=='li': self.pdf.ln(self.h+2) self.pdf.set_text_color(190,0,0) bullet = self.bullet[self.indent-1] if not isinstance(bullet, basestring): bullet += 1 self.bullet[self.indent-1] = bullet bullet = "%s. " % bullet self.pdf.write(self.h,'%s%s ' % (' '*5*self.indent, bullet)) self.set_text_color() if tag=='font': # save previous font state: self.font_stack.append((self.font_face, self.font_size, self.color)) if 'color' in attrs: self.color = hex2dec(attrs['color']) self.set_text_color(*color) self.color = color if 'face' in attrs: face = attrs.get('face').lower() try: self.pdf.set_font(face) self.font_face = face except RuntimeError: pass # font not found, ignore if 'size' in attrs: size = int(attrs.get('size')) self.pdf.set_font(self.font_face, size=int(size)) self.font_size = size if tag=='table': self.table = dict([(k.lower(), v) for k,v in attrs.items()]) if not 'width' in self.table: self.table['width'] = '100%' if self.table['width'][-1]=='%': w = self.pdf.w - self.pdf.r_margin - self.pdf.l_margin w *= int(self.table['width'][:-1])/100.0 self.table_offset = (self.pdf.w-w)/2.0 self.table_col_width = [] self.theader_out = self.tfooter_out = False self.theader = [] self.tfooter = [] self.thead = None self.tfoot = None self.table_h = 0 self.pdf.ln() if tag=='tr': self.tr = dict([(k.lower(), v) for k,v in attrs.items()]) self.table_col_index = 0 self.pdf.set_x(self.table_offset) if tag=='td': self.td = dict([(k.lower(), v) for k,v in attrs.items()]) if tag=='th': self.td = dict([(k.lower(), v) for k,v in attrs.items()]) self.th = True if 'width' in self.td: self.table_col_width.append(self.td['width']) if tag=='thead': self.thead = {} if tag=='tfoot': self.tfoot = {} if tag=='img': if 'src' in attrs: x = self.pdf.get_x() y = self.pdf.get_y() w = px2mm(attrs.get('width', 0)) h = px2mm(attrs.get('height',0)) if self.align and self.align[0].upper() == 'C': x = (self.pdf.w-x)/2.0 - w/2.0 self.pdf.image(self.image_map(attrs['src']), x, y, w, h, link=self.href) self.pdf.set_x(x+w) self.pdf.set_y(y+h) if tag=='b' or tag=='i' or tag=='u': self.set_style(tag, True) if tag=='center': self.align = 'Center' def handle_endtag(self, tag): #Closing tag if DEBUG: print("ENDTAG", tag) if tag=='h1' or tag=='h2' or tag=='h3' or tag=='h4': self.pdf.ln(6) self.set_font() self.set_style() self.align = None if tag=='pre': self.pdf.set_font(self.font or 'Times','',12) self.pdf.set_font_size(12) self.pre=False if tag=='blockquote': self.set_text_color(0,0,0) self.pdf.ln(3) if tag=='strong': tag='b' if tag=='em': tag='i' if tag=='b' or tag=='i' or tag=='u': self.set_style(tag, False) if tag=='a': self.href='' if tag=='p': self.align='' if tag in ('ul', 'ol'): self.indent-=1 self.bullet.pop() if tag=='table': if not self.tfooter_out: self.output_table_footer() self.table = None self.th = False self.theader = None self.tfooter = None self.pdf.ln() if tag=='thead': self.thead = None if tag=='tfoot': self.tfoot = None if tag=='tbody': # draw a line separator between table bodies self.pdf.set_x(self.table_offset) self.output_table_sep() if tag=='tr': h = self.table_h if self.tfoot is None: self.pdf.ln(h) self.tr = None if tag=='td' or tag=='th': if self.th: if DEBUG: print("revert style") self.set_style('B', False) # revert style self.table_col_index += int(self.td.get('colspan','1')) self.td = None self.th = False if tag=='font': # recover last font state face, size, color = self.font_stack.pop() if face: self.pdf.set_text_color(0,0,0) self.color = None self.set_font(face, size) self.font = None if tag=='center': self.align = None def set_font(self, face=None, size=None): if face: self.font_face = face if size: self.font_size = size self.h = size / 72.0*25.4 if DEBUG: print("H", self.h) self.pdf.set_font(self.font_face or 'times','',12) self.pdf.set_font_size(self.font_size or 12) self.set_style('u', False) self.set_style('b', False) self.set_style('i', False) self.set_text_color() def set_style(self, tag=None, enable=None): #Modify style and select corresponding font if tag: t = self.style.get(tag.lower()) self.style[tag.lower()] = enable style='' for s in ('b','i','u'): if self.style.get(s): style+=s if DEBUG: print("SET_FONT_STYLE", style) self.pdf.set_font('',style) def set_text_color(self, r=None, g=0, b=0): if r is None: self.pdf.set_text_color(self.r,self.g,self.b) else: self.pdf.set_text_color(r, g, b) self.r = r self.g = g self.b = b def put_link(self, url, txt): #Put a hyperlink self.set_text_color(0,0,255) self.set_style('u', True) self.pdf.write(5,txt,url) self.set_style('u', False) self.set_text_color(0) def put_line(self): self.pdf.ln(2) self.pdf.line(self.pdf.get_x(),self.pdf.get_y(),self.pdf.get_x()+187,self.pdf.get_y()) self.pdf.ln(3) class HTMLMixin(object): def write_html(self, text, image_map=None): "Parse HTML and convert it to PDF" h2p = HTML2FPDF(self, image_map) text = h2p.unescape(text) # To deal with HTML entities h2p.feed(text) endesive-2.19.1/endesive/pdf/fpdf/php.py000066400000000000000000000026661504236674500200670ustar00rootroot00000000000000#!/usr/bin/env python # -*- coding: latin-1 -*- from .py3k import PY3K, basestring, unicode # fpdf php helpers: def substr(s, start, length=-1): if length < 0: length=len(s)-start return s[start:start+length] def sprintf(fmt, *args): return fmt % args def print_r(array): if not isinstance(array, dict): array = dict([(k, k) for k in array]) for k, v in array.items(): print("[%s] => %s " % (k, v)) def UTF8ToUTF16BE(instr, setbom=True): "Converts UTF-8 strings to UTF16-BE." outstr = "".encode() if (setbom): outstr += "\xFE\xFF".encode("latin1") if not isinstance(instr, unicode): instr = instr.decode('UTF-8') outstr += instr.encode('UTF-16BE') # convert bytes back to fake unicode string until PEP461-like is implemented if PY3K: outstr = outstr.decode("latin1") return outstr def UTF8StringToArray(instr): "Converts UTF-8 strings to codepoints array" return [ord(c) for c in instr] # ttfints php helpers: def die(msg): raise RuntimeError(msg) def str_repeat(s, count): return s * count def str_pad(s, pad_length=0, pad_char= " ", pad_type= +1 ): if pad_type<0: # pad left return s.rjust(pad_length, pad_char) elif pad_type>0: # pad right return s.ljust(pad_length, pad_char) else: # pad both return s.center(pad_length, pad_char) strlen = count = lambda s: len(s) endesive-2.19.1/endesive/pdf/fpdf/py3k.py000066400000000000000000000031021504236674500201500ustar00rootroot00000000000000#!/usr/bin/env python # -*- coding: utf-8 -*- "Special module to handle differences between Python 2 and 3 versions" import sys PY3K = sys.version_info >= (3, 0) try: import cPickle as pickle except ImportError: import pickle try: from urllib import urlopen except ImportError: from urllib.request import urlopen try: from hashlib import md5 except ImportError: try: from md5 import md5 except ImportError: md5 = None def hashpath(fn): h = md5() if PY3K: h.update(fn.encode("UTF-8")) else: h.update(fn) return h.hexdigest() # Check if PIL is available (tries importing both pypi version and corrected or manually installed versions). # Necessary for JPEG and GIF support. # TODO: Pillow support try: from PIL import Image except ImportError: try: import Image except ImportError: Image = None try: from HTMLParser import HTMLParser except ImportError: from html.parser import HTMLParser if PY3K: basestring = str unicode = str ord = lambda x: x else: basestring = basestring unicode = unicode ord = ord # shortcut to bytes conversion (b prefix) def b(s): if isinstance(s, basestring): return s.encode("latin1") elif isinstance(s, int): if PY3K: return bytes([s]) # http://bugs.python.org/issue4588 else: return chr(s) def exception(): "Return the current the exception instance currently being handled" # this is needed to support Python 2.5 that lacks "as" syntax return sys.exc_info()[1] endesive-2.19.1/endesive/pdf/fpdf/template.py000066400000000000000000000221021504236674500210760ustar00rootroot00000000000000# -*- coding: iso-8859-1 -*- "PDF Template Helper for FPDF.py" __author__ = "Mariano Reingart " __copyright__ = "Copyright (C) 2010 Mariano Reingart" __license__ = "LGPL 3.0" import sys,os,csv from .fpdf import FPDF from .py3k import PY3K, basestring, unicode def rgb(col): return (col // 65536), (col // 256 % 256), (col% 256) class Template: def __init__(self, infile=None, elements=None, format='A4', orientation='portrait', title='', author='', subject='', creator='', keywords=''): if elements: self.load_elements(elements) self.handlers = {'T': self.text, 'L': self.line, 'I': self.image, 'B': self.rect, 'BC': self.barcode, 'W': self.write, } self.texts = {} pdf = self.pdf = FPDF(format=format,orientation=orientation, unit="mm") pdf.set_title(title) pdf.set_author(author) pdf.set_creator(creator) pdf.set_subject(subject) pdf.set_keywords(keywords) def load_elements(self, elements): "Initialize the internal element structures" self.pg_no = 0 self.elements = elements self.keys = [v['name'].lower() for v in self.elements] def parse_csv(self, infile, delimiter=",", decimal_sep="."): "Parse template format csv file and create elements dict" keys = ('name','type','x1','y1','x2','y2','font','size', 'bold','italic','underline','foreground','background', 'align','text','priority', 'multiline') self.elements = [] self.pg_no = 0 if not PY3K: f = open(infile, 'rb') else: f = open(infile) for row in csv.reader(f, delimiter=delimiter): kargs = {} for i,v in enumerate(row): if not v.startswith("'") and decimal_sep!=".": v = v.replace(decimal_sep,".") else: v = v if v=='': v = None else: v = eval(v.strip()) kargs[keys[i]] = v self.elements.append(kargs) self.keys = [v['name'].lower() for v in self.elements] def add_page(self): self.pg_no += 1 self.texts[self.pg_no] = {} def __setitem__(self, name, value): if name.lower() in self.keys: if not PY3K and isinstance(value, unicode): value = value.encode("latin1","ignore") elif value is None: value = "" else: value = str(value) self.texts[self.pg_no][name.lower()] = value # setitem shortcut (may be further extended) set = __setitem__ def has_key(self, name): return name.lower() in self.keys def __getitem__(self, name): if name in self.keys: key = name.lower() if key in self.texts: # text for this page: return self.texts[self.pg_no][key] else: # find first element for default text: elements = [element for element in self.elements if element['name'].lower() == key] if elements: return elements[0]['text'] def split_multicell(self, text, element_name): "Divide (\n) a string using a given element width" pdf = self.pdf element = [element for element in self.elements if element['name'].lower() == element_name.lower()][0] style = "" if element['bold']: style += "B" if element['italic']: style += "I" if element['underline']: style += "U" pdf.set_font(element['font'],style,element['size']) align = {'L':'L','R':'R','I':'L','D':'R','C':'C','':''}.get(element['align']) # D/I in spanish if isinstance(text, unicode) and not PY3K: text = text.encode("latin1","ignore") else: text = str(text) return pdf.multi_cell(w=element['x2']-element['x1'], h=element['y2']-element['y1'], txt=text,align=align,split_only=True) def render(self, outfile, dest="F"): pdf = self.pdf for pg in range(1, self.pg_no+1): pdf.add_page() pdf.set_font('Arial','B',16) pdf.set_auto_page_break(False,margin=0) for element in sorted(self.elements,key=lambda x: x['priority']): #print "dib",element['type'], element['name'], element['x1'], element['y1'], element['x2'], element['y2'] element = element.copy() element['text'] = self.texts[pg].get(element['name'].lower(), element['text']) if 'rotate' in element: pdf.rotate(element['rotate'], element['x1'], element['y1']) self.handlers[element['type'].upper()](pdf, **element) if 'rotate' in element: pdf.rotate(0) if dest: return pdf.output(outfile, dest) def text(self, pdf, x1=0, y1=0, x2=0, y2=0, text='', font="arial", size=10, bold=False, italic=False, underline=False, align="", foreground=0, backgroud=65535, multiline=None, *args, **kwargs): if text: if pdf.text_color!=rgb(foreground): pdf.set_text_color(*rgb(foreground)) if pdf.fill_color!=rgb(backgroud): pdf.set_fill_color(*rgb(backgroud)) font = font.strip().lower() if font == 'arial black': font = 'arial' style = "" for tag in 'B', 'I', 'U': if (text.startswith("<%s>" % tag) and text.endswith("" %tag)): text = text[3:-4] style += tag if bold: style += "B" if italic: style += "I" if underline: style += "U" align = {'L':'L','R':'R','I':'L','D':'R','C':'C','':''}.get(align) # D/I in spanish pdf.set_font(font,style,size) ##m_k = 72 / 2.54 ##h = (size/m_k) pdf.set_xy(x1,y1) if multiline is None: # multiline==None: write without wrapping/trimming (default) pdf.cell(w=x2-x1,h=y2-y1,txt=text,border=0,ln=0,align=align) elif multiline: # multiline==True: automatic word - warp pdf.multi_cell(w=x2-x1,h=y2-y1,txt=text,border=0,align=align) else: # multiline==False: trim to fit exactly the space defined text = pdf.multi_cell(w=x2-x1, h=y2-y1, txt=text, align=align, split_only=True)[0] print("trimming: *%s*" % text) pdf.cell(w=x2-x1,h=y2-y1,txt=text,border=0,ln=0,align=align) #pdf.Text(x=x1,y=y1,txt=text) def line(self, pdf, x1=0, y1=0, x2=0, y2=0, size=0, foreground=0, *args, **kwargs): if pdf.draw_color!=rgb(foreground): #print "SetDrawColor", hex(foreground) pdf.set_draw_color(*rgb(foreground)) #print "SetLineWidth", size pdf.set_line_width(size) pdf.line(x1, y1, x2, y2) def rect(self, pdf, x1=0, y1=0, x2=0, y2=0, size=0, foreground=0, backgroud=65535, *args, **kwargs): if pdf.draw_color!=rgb(foreground): pdf.set_draw_color(*rgb(foreground)) if pdf.fill_color!=rgb(backgroud): pdf.set_fill_color(*rgb(backgroud)) pdf.set_line_width(size) pdf.rect(x1, y1, x2-x1, y2-y1) def image(self, pdf, x1=0, y1=0, x2=0, y2=0, text='', *args,**kwargs): if text: pdf.image(text,x1,y1,w=x2-x1,h=y2-y1,type='',link='') def barcode(self, pdf, x1=0, y1=0, x2=0, y2=0, text='', font="arial", size=1, foreground=0, *args, **kwargs): if pdf.draw_color!=rgb(foreground): pdf.set_draw_color(*rgb(foreground)) font = font.lower().strip() if font == 'interleaved 2of5 nt': pdf.interleaved2of5(text,x1,y1,w=size,h=y2-y1) # Added by Derek Schwalenberg Schwalenberg1013@gmail.com to allow (url) links in templates (using write method) 2014-02-22 def write(self, pdf, x1=0, y1=0, x2=0, y2=0, text='', font="arial", size=1, bold=False, italic=False, underline=False, align="", link='http://example.com', foreground=0, *args, **kwargs): if pdf.text_color!=rgb(foreground): pdf.set_text_color(*rgb(foreground)) font = font.strip().lower() if font == 'arial black': font = 'arial' style = "" for tag in 'B', 'I', 'U': if (text.startswith("<%s>" % tag) and text.endswith("" %tag)): text = text[3:-4] style += tag if bold: style += "B" if italic: style += "I" if underline: style += "U" align = {'L':'L','R':'R','I':'L','D':'R','C':'C','':''}.get(align) # D/I in spanish pdf.set_font(font,style,size) ##m_k = 72 / 2.54 ##h = (size/m_k) pdf.set_xy(x1,y1) pdf.write(5,text,link) endesive-2.19.1/endesive/pdf/fpdf/ttfonts.py000066400000000000000000001146611504236674500210000ustar00rootroot00000000000000#****************************************************************************** # TTFontFile class # # This class is based on The ReportLab Open Source PDF library # written in Python - http://www.reportlab.com/software/opensource/ # together with ideas from the OpenOffice source code and others. # # Version: 1.04 # Date: 2011-09-18 # Author: Ian Back # License: LGPL # Copyright (c) Ian Back, 2010 # Ported to Python 2.7 by Mariano Reingart (reingart@gmail.com) on 2012 # This header must be retained in any redistribution or # modification of the file. # #****************************************************************************** from struct import pack, unpack, unpack_from import re import warnings from .php import die, substr, str_repeat, str_pad, strlen, count from .py3k import b, ord # Define the value used in the "head" table of a created TTF file # 0x74727565 "true" for Mac # 0x00010000 for Windows # Either seems to work for a font embedded in a PDF file # when read by Adobe Reader on a Windows PC(!) _TTF_MAC_HEADER = False # TrueType Font Glyph operators GF_WORDS = (1 << 0) GF_SCALE = (1 << 3) GF_MORE = (1 << 5) GF_XYSCALE = (1 << 6) GF_TWOBYTWO = (1 << 7) def sub32(x, y): xlo = x[1] xhi = x[0] ylo = y[1] yhi = y[0] if (ylo > xlo): xlo += 1 << 16 yhi += 1 reslo = xlo-ylo if (yhi > xhi): xhi += 1 << 16 reshi = xhi-yhi reshi = reshi & 0xFFFF return (reshi, reslo) def calcChecksum(data): if (strlen(data) % 4): data += str_repeat(b("\0"), (4-(len(data) % 4))) hi=0x0000 lo=0x0000 for i in range(0, len(data), 4): hi += (ord(data[i])<<8) + ord(data[i+1]) lo += (ord(data[i+2])<<8) + ord(data[i+3]) hi += lo >> 16 lo = lo & 0xFFFF hi = hi & 0xFFFF return (hi, lo) class TTFontFile: def __init__(self): self.maxStrLenRead = 200000 # Maximum size of glyf table to read in as string (otherwise reads each glyph from file) def getMetrics(self, file): self.filename = file self.fh = open(file,'rb') self._pos = 0 self.charWidths = [] self.glyphPos = {} self.charToGlyph = {} self.tables = {} self.otables = {} self.ascent = 0 self.descent = 0 self.TTCFonts = {} self.version = version = self.read_ulong() if (version==0x4F54544F): die("Postscript outlines are not supported") if (version==0x74746366): die("ERROR - TrueType Fonts Collections not supported") if (version not in (0x00010000,0x74727565)): die("Not a TrueType font: version=" + version) self.readTableDirectory() self.extractInfo() self.fh.close() def readTableDirectory(self, ): self.numTables = self.read_ushort() self.searchRange = self.read_ushort() self.entrySelector = self.read_ushort() self.rangeShift = self.read_ushort() self.tables = {} for i in range(self.numTables): record = {} record['tag'] = self.read_tag() record['checksum'] = (self.read_ushort(),self.read_ushort()) record['offset'] = self.read_ulong() record['length'] = self.read_ulong() self.tables[record['tag']] = record def get_table_pos(self, tag): offset = self.tables[tag]['offset'] length = self.tables[tag]['length'] return (offset, length) def seek(self, pos): self._pos = pos self.fh.seek(self._pos) def skip(self, delta): self._pos = self._pos + delta self.fh.seek(self._pos) def seek_table(self, tag, offset_in_table = 0): tpos = self.get_table_pos(tag) self._pos = tpos[0] + offset_in_table self.fh.seek(self._pos) return self._pos def read_tag(self): self._pos += 4 return self.fh.read(4).decode("latin1") def read_short(self): self._pos += 2 s = self.fh.read(2) a = (ord(s[0])<<8) + ord(s[1]) if (a & (1 << 15) ): a = (a - (1 << 16)) return a def unpack_short(self, s): a = (ord(s[0])<<8) + ord(s[1]) if (a & (1 << 15) ): a = (a - (1 << 16)) return a def read_ushort(self): self._pos += 2 s = self.fh.read(2) return (ord(s[0])<<8) + ord(s[1]) def read_ulong(self): self._pos += 4 s = self.fh.read(4) # if large uInt32 as an integer, PHP converts it to -ve return (ord(s[0])*16777216) + (ord(s[1])<<16) + (ord(s[2])<<8) + ord(s[3]) # 16777216 = 1<<24 def get_ushort(self, pos): self.fh.seek(pos) s = self.fh.read(2) return (ord(s[0])<<8) + ord(s[1]) def get_ulong(self, pos): self.fh.seek(pos) s = self.fh.read(4) # iF large uInt32 as an integer, PHP converts it to -ve return (ord(s[0])*16777216) + (ord(s[1])<<16) + (ord(s[2])<<8) + ord(s[3]) # 16777216 = 1<<24 def pack_short(self, val): if (val<0): val = abs(val) val = ~val val += 1 return pack(">H",val) def splice(self, stream, offset, value): return substr(stream,0,offset) + value + substr(stream,offset+strlen(value)) def _set_ushort(self, stream, offset, value): up = pack(">H", value) return self.splice(stream, offset, up) def _set_short(self, stream, offset, val): if (val<0): val = abs(val) val = ~val val += 1 up = pack(">H",val) return self.splice(stream, offset, up) def get_chunk(self, pos, length): self.fh.seek(pos) if (length <1): return '' return (self.fh.read(length)) def get_table(self, tag): (pos, length) = self.get_table_pos(tag) if (length == 0): die('Truetype font (' + self.filename + '): error reading table: ' + tag) self.fh.seek(pos) return (self.fh.read(length)) def add(self, tag, data): if (tag == 'head') : data = self.splice(data, 8, b("\0\0\0\0")) self.otables[tag] = data ############################################/ ############################################/ ############################################/ def extractInfo(self): #################/ # name - Naming table #################/ self.sFamilyClass = 0 self.sFamilySubClass = 0 name_offset = self.seek_table("name") format = self.read_ushort() if (format != 0): die("Unknown name table format " + format) numRecords = self.read_ushort() string_data_offset = name_offset + self.read_ushort() names = {1:'',2:'',3:'',4:'',6:''} K = list(names.keys()) nameCount = len(names) for i in range(numRecords): platformId = self.read_ushort() encodingId = self.read_ushort() languageId = self.read_ushort() nameId = self.read_ushort() length = self.read_ushort() offset = self.read_ushort() if (nameId not in K): continue N = '' if (platformId == 3 and encodingId == 1 and languageId == 0x409): # Microsoft, Unicode, US English, PS Name opos = self._pos self.seek(string_data_offset + offset) if (length % 2 != 0): die("PostScript name is UTF-16BE string of odd length") length /= 2 N = '' while (length > 0): char = self.read_ushort() N += (chr(char)) length -= 1 self._pos = opos self.seek(opos) elif (platformId == 1 and encodingId == 0 and languageId == 0): # Macintosh, Roman, English, PS Name opos = self._pos N = self.get_chunk(string_data_offset + offset, length).decode("latin1") self._pos = opos self.seek(opos) if (N and names[nameId]==''): names[nameId] = N nameCount -= 1 if (nameCount==0): break if (names[6]): psName = names[6] elif (names[4]): psName = re.sub(' ','-',names[4]) elif (names[1]): psName = re.sub(' ','-',names[1]) else: psName = '' if (not psName): die("Could not find PostScript font name") self.name = psName if (names[1]): self.familyName = names[1] else: self.familyName = psName if (names[2]): self.styleName = names[2] else: self.styleName = 'Regular' if (names[4]): self.fullName = names[4] else: self.fullName = psName if (names[3]): self.uniqueFontID = names[3] else: self.uniqueFontID = psName if (names[6]): self.fullName = names[6] #################/ # head - Font header table #################/ self.seek_table("head") self.skip(18) self.unitsPerEm = unitsPerEm = self.read_ushort() scale = 1000 / float(unitsPerEm) self.skip(16) xMin = self.read_short() yMin = self.read_short() xMax = self.read_short() yMax = self.read_short() self.bbox = [(xMin*scale), (yMin*scale), (xMax*scale), (yMax*scale)] self.skip(3*2) indexToLocFormat = self.read_ushort() glyphDataFormat = self.read_ushort() if (glyphDataFormat != 0): die('Unknown glyph data format ' + glyphDataFormat) #################/ # hhea metrics table #################/ # ttf2t1 seems to use this value rather than the one in OS/2 - so put in for compatibility if ("hhea" in self.tables): self.seek_table("hhea") self.skip(4) hheaAscender = self.read_short() hheaDescender = self.read_short() self.ascent = (hheaAscender *scale) self.descent = (hheaDescender *scale) #################/ # OS/2 - OS/2 and Windows metrics table #################/ if ("OS/2" in self.tables): self.seek_table("OS/2") version = self.read_ushort() self.skip(2) usWeightClass = self.read_ushort() self.skip(2) fsType = self.read_ushort() if (fsType == 0x0002 or (fsType & 0x0300) != 0): die('ERROR - Font file ' + self.filename + ' cannot be embedded due to copyright restrictions.') self.restrictedUse = True self.skip(20) sF = self.read_short() self.sFamilyClass = (sF >> 8) self.sFamilySubClass = (sF & 0xFF) self._pos += 10 #PANOSE = 10 byte length panose = self.fh.read(10) self.skip(26) sTypoAscender = self.read_short() sTypoDescender = self.read_short() if (not self.ascent): self.ascent = (sTypoAscender*scale) if (not self.descent): self.descent = (sTypoDescender*scale) if (version > 1): self.skip(16) sCapHeight = self.read_short() self.capHeight = (sCapHeight*scale) else: self.capHeight = self.ascent else: usWeightClass = 500 if (not self.ascent): self.ascent = (yMax*scale) if (not self.descent): self.descent = (yMin*scale) self.capHeight = self.ascent self.stemV = 50 + int(pow((usWeightClass / 65.0),2)) #################/ # post - PostScript table #################/ self.seek_table("post") self.skip(4) self.italicAngle = self.read_short() + self.read_ushort() / 65536.0 self.underlinePosition = self.read_short() * scale self.underlineThickness = self.read_short() * scale isFixedPitch = self.read_ulong() self.flags = 4 if (self.italicAngle!= 0): self.flags = self.flags | 64 if (usWeightClass >= 600): self.flags = self.flags | 262144 if (isFixedPitch): self.flags = self.flags | 1 #################/ # hhea - Horizontal header table #################/ self.seek_table("hhea") self.skip(32) metricDataFormat = self.read_ushort() if (metricDataFormat != 0): die('Unknown horizontal metric data format '.metricDataFormat) numberOfHMetrics = self.read_ushort() if (numberOfHMetrics == 0): die('Number of horizontal metrics is 0') #################/ # maxp - Maximum profile table #################/ self.seek_table("maxp") self.skip(4) numGlyphs = self.read_ushort() #################/ # cmap - Character to glyph index mapping table #################/ cmap_offset = self.seek_table("cmap") self.skip(2) cmapTableCount = self.read_ushort() unicode_cmap_offset = 0 unicode_cmap_offset12 = 0 for i in range(cmapTableCount): platformID = self.read_ushort() encodingID = self.read_ushort() offset = self.read_ulong() save_pos = self._pos if platformID == 3 and encodingID == 10: # Microsoft, UCS-4 format = self.get_ushort(cmap_offset + offset) if (format == 12): if not unicode_cmap_offset12: unicode_cmap_offset12 = cmap_offset + offset break if ((platformID == 3 and encodingID == 1) or platformID == 0): # Microsoft, Unicode format = self.get_ushort(cmap_offset + offset) if (format == 4): if (not unicode_cmap_offset): unicode_cmap_offset = cmap_offset + offset break self.seek(save_pos) if not unicode_cmap_offset and not unicode_cmap_offset12: die('Font (' + self.filename + ') does not have cmap for Unicode (platform 3, encoding 1, format 4, or platform 3, encoding 10, format 12, or platform 0, any encoding, format 4)') glyphToChar = {} charToGlyph = {} if unicode_cmap_offset12: self.getCMAP12(unicode_cmap_offset12, glyphToChar, charToGlyph) else: self.getCMAP4(unicode_cmap_offset, glyphToChar, charToGlyph) #################/ # hmtx - Horizontal metrics table #################/ self.getHMTX(numberOfHMetrics, numGlyphs, glyphToChar, scale) ############################################/ ############################################/ def makeSubset(self, file, subset): self.filename = file self.fh = open(file ,'rb') self._pos = 0 self.charWidths = [] self.glyphPos = {} self.charToGlyph = {} self.tables = {} self.otables = {} self.ascent = 0 self.descent = 0 self.skip(4) self.maxUni = 0 self.readTableDirectory() #################/ # head - Font header table #################/ self.seek_table("head") self.skip(50) indexToLocFormat = self.read_ushort() glyphDataFormat = self.read_ushort() #################/ # hhea - Horizontal header table #################/ self.seek_table("hhea") self.skip(32) metricDataFormat = self.read_ushort() orignHmetrics = numberOfHMetrics = self.read_ushort() #################/ # maxp - Maximum profile table #################/ self.seek_table("maxp") self.skip(4) numGlyphs = self.read_ushort() #################/ # cmap - Character to glyph index mapping table #################/ cmap_offset = self.seek_table("cmap") self.skip(2) cmapTableCount = self.read_ushort() unicode_cmap_offset = 0 unicode_cmap_offset12 = 0 for i in range(cmapTableCount): platformID = self.read_ushort() encodingID = self.read_ushort() offset = self.read_ulong() save_pos = self._pos if platformID == 3 and encodingID == 10: # Microsoft, UCS-4 format = self.get_ushort(cmap_offset + offset) if (format == 12): if not unicode_cmap_offset12: unicode_cmap_offset12 = cmap_offset + offset break if ((platformID == 3 and encodingID == 1) or platformID == 0): # Microsoft, Unicode format = self.get_ushort(cmap_offset + offset) if (format == 4): unicode_cmap_offset = cmap_offset + offset break self.seek(save_pos ) if not unicode_cmap_offset and not unicode_cmap_offset12: die('Font (' + self.filename + ') does not have cmap for Unicode (platform 3, encoding 1, format 4, or platform 3, encoding 10, format 12, or platform 0, any encoding, format 4)') glyphToChar = {} charToGlyph = {} if unicode_cmap_offset12: self.getCMAP12(unicode_cmap_offset12, glyphToChar, charToGlyph) else: self.getCMAP4(unicode_cmap_offset, glyphToChar, charToGlyph) self.charToGlyph = charToGlyph #################/ # hmtx - Horizontal metrics table #################/ scale = 1 # not used self.getHMTX(numberOfHMetrics, numGlyphs, glyphToChar, scale) #################/ # loca - Index to location #################/ self.getLOCA(indexToLocFormat, numGlyphs) subsetglyphs = [(0, 0)] # special "sorted dict"! subsetCharToGlyph = {} for code in subset: if (code in self.charToGlyph): if (self.charToGlyph[code], code) not in subsetglyphs: subsetglyphs.append((self.charToGlyph[code], code)) # Old Glyph ID => Unicode subsetCharToGlyph[code] = self.charToGlyph[code] # Unicode to old GlyphID self.maxUni = max(self.maxUni, code) (start,dummy) = self.get_table_pos('glyf') subsetglyphs.sort() glyphSet = {} n = 0 fsLastCharIndex = 0 # maximum Unicode index (character code) in this font, according to the cmap subtable for platform ID 3 and platform- specific encoding ID 0 or 1. for originalGlyphIdx, uni in subsetglyphs: fsLastCharIndex = max(fsLastCharIndex , uni) glyphSet[originalGlyphIdx] = n # old glyphID to new glyphID n += 1 codeToGlyph = {} for uni, originalGlyphIdx in sorted(subsetCharToGlyph.items()): codeToGlyph[uni] = glyphSet[originalGlyphIdx] self.codeToGlyph = codeToGlyph for originalGlyphIdx, uni in subsetglyphs: nonlocals = {'start': start, 'glyphSet': glyphSet, 'subsetglyphs': subsetglyphs} self.getGlyphs(originalGlyphIdx, nonlocals) numGlyphs = numberOfHMetrics = len(subsetglyphs) #tables copied from the original tags = ['name'] for tag in tags: self.add(tag, self.get_table(tag)) tags = ['cvt ', 'fpgm', 'prep', 'gasp'] for tag in tags: if (tag in self.tables): self.add(tag, self.get_table(tag)) # post - PostScript opost = self.get_table('post') post = b("\x00\x03\x00\x00") + substr(opost,4,12) + b("\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00") self.add('post', post) # Sort CID2GID map into segments of contiguous codes if 0 in codeToGlyph: del codeToGlyph[0] #unset(codeToGlyph[65535]) rangeid = 0 range_ = {} prevcid = -2 prevglidx = -1 # for each character for cid, glidx in sorted(codeToGlyph.items()): if (cid == (prevcid + 1) and glidx == (prevglidx + 1)): range_[rangeid].append(glidx) else: # new range rangeid = cid range_[rangeid] = [] range_[rangeid].append(glidx) prevcid = cid prevglidx = glidx # cmap - Character to glyph mapping - Format 4 (MS / ) segCount = len(range_) + 1 # + 1 Last segment has missing character 0xFFFF searchRange = 1 entrySelector = 0 while (searchRange * 2 <= segCount ): searchRange = searchRange * 2 entrySelector = entrySelector + 1 searchRange = searchRange * 2 rangeShift = segCount * 2 - searchRange length = 16 + (8*segCount ) + (numGlyphs+1) cmap = [0, 1, # Index : version, number of encoding subtables 3, 1, # Encoding Subtable : platform (MS=3), encoding (Unicode) 0, 12, # Encoding Subtable : offset (hi,lo) 4, length, 0, # Format 4 Mapping subtable: format, length, language segCount*2, searchRange, entrySelector, rangeShift] range_ = sorted(range_.items()) # endCode(s) for start, subrange in range_: endCode = start + (len(subrange)-1) cmap.append(endCode) # endCode(s) cmap.append(0xFFFF) # endCode of last Segment cmap.append(0) # reservedPad # startCode(s) for start, subrange in range_: cmap.append(start) # startCode(s) cmap.append(0xFFFF) # startCode of last Segment # idDelta(s) for start, subrange in range_: idDelta = -(start-subrange[0]) n += count(subrange) cmap.append(idDelta) # idDelta(s) cmap.append(1) # idDelta of last Segment # idRangeOffset(s) for subrange in range_: cmap.append(0) # idRangeOffset[segCount] Offset in bytes to glyph indexArray, or 0 cmap.append(0) # idRangeOffset of last Segment for subrange, glidx in range_: cmap.extend(glidx) cmap.append(0) # Mapping for last character cmapstr = b('') for cm in cmap: if cm >= 0: cmapstr += pack(">H", cm) else: try: cmapstr += pack(">h", cm) except: warnings.warn("cmap value too big/small: %s" % cm) cmapstr += pack(">H", -cm) self.add('cmap', cmapstr) # glyf - Glyph data (glyfOffset,glyfLength) = self.get_table_pos('glyf') if (glyfLength < self.maxStrLenRead): glyphData = self.get_table('glyf') offsets = [] glyf = b('') pos = 0 hmtxstr = b('') xMinT = 0 yMinT = 0 xMaxT = 0 yMaxT = 0 advanceWidthMax = 0 minLeftSideBearing = 0 minRightSideBearing = 0 xMaxExtent = 0 maxPoints = 0 # points in non-compound glyph maxContours = 0 # contours in non-compound glyph maxComponentPoints = 0 # points in compound glyph maxComponentContours = 0 # contours in compound glyph maxComponentElements = 0 # number of glyphs referenced at top level maxComponentDepth = 0 # levels of recursion, set to 0 if font has only simple glyphs self.glyphdata = {} for originalGlyphIdx, uni in subsetglyphs: # hmtx - Horizontal Metrics hm = self.getHMetric(orignHmetrics, originalGlyphIdx) hmtxstr += hm offsets.append(pos) try: glyphPos = self.glyphPos[originalGlyphIdx] glyphLen = self.glyphPos[originalGlyphIdx + 1] - glyphPos except IndexError: warnings.warn("missing glyph %s" % (originalGlyphIdx)) glyphLen = 0 if (glyfLength < self.maxStrLenRead): data = substr(glyphData,glyphPos,glyphLen) else: if (glyphLen > 0): data = self.get_chunk(glyfOffset+glyphPos,glyphLen) else: data = b('') if (glyphLen > 0): up = unpack(">H", substr(data,0,2))[0] if (glyphLen > 2 and (up & (1 << 15)) ): # If number of contours <= -1 i.e. composiste glyph pos_in_glyph = 10 flags = GF_MORE nComponentElements = 0 while (flags & GF_MORE): nComponentElements += 1 # number of glyphs referenced at top level up = unpack(">H", substr(data,pos_in_glyph,2)) flags = up[0] up = unpack(">H", substr(data,pos_in_glyph+2,2)) glyphIdx = up[0] self.glyphdata.setdefault(originalGlyphIdx, {}).setdefault('compGlyphs', []).append(glyphIdx) try: data = self._set_ushort(data, pos_in_glyph + 2, glyphSet[glyphIdx]) except KeyError: data = 0 warnings.warn("missing glyph data %s" % glyphIdx) pos_in_glyph += 4 if (flags & GF_WORDS): pos_in_glyph += 4 else: pos_in_glyph += 2 if (flags & GF_SCALE): pos_in_glyph += 2 elif (flags & GF_XYSCALE): pos_in_glyph += 4 elif (flags & GF_TWOBYTWO): pos_in_glyph += 8 maxComponentElements = max(maxComponentElements, nComponentElements) glyf += data pos += glyphLen if (pos % 4 != 0): padding = 4 - (pos % 4) glyf += str_repeat(b("\0"),padding) pos += padding offsets.append(pos) self.add('glyf', glyf) # hmtx - Horizontal Metrics self.add('hmtx', hmtxstr) # loca - Index to location locastr = b('') if (((pos + 1) >> 1) > 0xFFFF): indexToLocFormat = 1 # long format for offset in offsets: locastr += pack(">L",offset) else: indexToLocFormat = 0 # short format for offset in offsets: locastr += pack(">H",int(offset/2)) self.add('loca', locastr) # head - Font header head = self.get_table('head') head = self._set_ushort(head, 50, indexToLocFormat) self.add('head', head) # hhea - Horizontal Header hhea = self.get_table('hhea') hhea = self._set_ushort(hhea, 34, numberOfHMetrics) self.add('hhea', hhea) # maxp - Maximum Profile maxp = self.get_table('maxp') maxp = self._set_ushort(maxp, 4, numGlyphs) self.add('maxp', maxp) # OS/2 - OS/2 os2 = self.get_table('OS/2') self.add('OS/2', os2 ) self.fh.close() # Put the TTF file together stm = self.endTTFile('') return stm ######################################### # Recursively get composite glyph data def getGlyphData(self, originalGlyphIdx, nonlocals): # &maxdepth, &depth, &points, &contours nonlocals['depth'] += 1 nonlocals['maxdepth'] = max(nonlocals['maxdepth'], nonlocals['depth']) if (len(self.glyphdata[originalGlyphIdx]['compGlyphs'])): for glyphIdx in self.glyphdata[originalGlyphIdx]['compGlyphs']: self.getGlyphData(glyphIdx, nonlocals) elif ((self.glyphdata[originalGlyphIdx]['nContours'] > 0) and nonlocals['depth'] > 0): # simple contours += self.glyphdata[originalGlyphIdx]['nContours'] points += self.glyphdata[originalGlyphIdx]['nPoints'] nonlocals['depth'] -= 1 ######################################### # Recursively get composite glyphs def getGlyphs(self, originalGlyphIdx, nonlocals): # &start, &glyphSet, &subsetglyphs) try: glyphPos = self.glyphPos[originalGlyphIdx] glyphLen = self.glyphPos[originalGlyphIdx + 1] - glyphPos except IndexError: warnings.warn("missing glyph %s" % (originalGlyphIdx)) return if (not glyphLen): return self.seek(nonlocals['start'] + glyphPos) numberOfContours = self.read_short() if (numberOfContours < 0): self.skip(8) flags = GF_MORE while (flags & GF_MORE): flags = self.read_ushort() glyphIdx = self.read_ushort() if (glyphIdx not in nonlocals['glyphSet']): nonlocals['glyphSet'][glyphIdx] = len(nonlocals['subsetglyphs']) # old glyphID to new glyphID nonlocals['subsetglyphs'].append((glyphIdx, 1)) savepos = self.fh.tell() self.getGlyphs(glyphIdx, nonlocals) self.seek(savepos) if (flags & GF_WORDS): self.skip(4) else: self.skip(2) if (flags & GF_SCALE): self.skip(2) elif (flags & GF_XYSCALE): self.skip(4) elif (flags & GF_TWOBYTWO): self.skip(8) ######################################### def getHMTX(self, numberOfHMetrics, numGlyphs, glyphToChar, scale): start = self.seek_table("hmtx") aw = 0 self.charWidths = [0] * 256*256 nCharWidths = 0 if ((numberOfHMetrics*4) < self.maxStrLenRead): data = self.get_chunk(start,(numberOfHMetrics*4)) arr = unpack(">%dH" % (int(len(data)/2)), data) else: self.seek(start) for glyph in range(numberOfHMetrics): if ((numberOfHMetrics*4) < self.maxStrLenRead): aw = arr[(glyph*2)] # PHP starts arrays from index 0!? +1 else: aw = self.read_ushort() lsb = self.read_ushort() if (glyph in glyphToChar or glyph == 0): if (aw >= (1 << 15) ): aw = 0 # 1.03 Some (arabic) fonts have -ve values for width # although should be unsigned value - comes out as e.g. 65108 (intended -50) if (glyph == 0): self.defaultWidth = scale*aw continue for char in glyphToChar[glyph]: if (char != 0 and char != 65535): w = int(round(scale*aw+0.001)) # ROUND_HALF_UP in PY3K (like php) if (w == 0): w = 65535 if (char < 196608): self.charWidths[char] = w nCharWidths += 1 data = self.get_chunk((start+numberOfHMetrics*4),(numGlyphs*2)) arr = unpack(">%dH" % (int(len(data)/2)), data) diff = numGlyphs-numberOfHMetrics for pos in range(diff): glyph = pos + numberOfHMetrics if (glyph in glyphToChar): for char in glyphToChar[glyph]: if (char != 0 and char != 65535): w = int(round(scale*aw+0.001)) # ROUND_HALF_UP in PY3K (like php) if (w == 0): w = 65535 if (char < 196608): self.charWidths[char] = w nCharWidths += 1 # NB 65535 is a set width of 0 # First bytes define number of chars in font self.charWidths[0] = nCharWidths def getHMetric(self, numberOfHMetrics, gid): start = self.seek_table("hmtx") if (gid < numberOfHMetrics): self.seek(start+(gid*4)) hm = self.fh.read(4) else: self.seek(start+((numberOfHMetrics-1)*4)) hm = self.fh.read(2) self.seek(start+(numberOfHMetrics*2)+(gid*2)) hm += self.fh.read(2) return hm def getLOCA(self, indexToLocFormat, numGlyphs): start = self.seek_table('loca') self.glyphPos = [] if (indexToLocFormat == 0): data = self.get_chunk(start,(numGlyphs*2)+2) arr = unpack(">%dH" % (int(len(data)/2)), data) for n in range(numGlyphs): self.glyphPos.append((arr[n] * 2)) # n+1 !? elif (indexToLocFormat == 1): data = self.get_chunk(start,(numGlyphs*4)+4) arr = unpack(">%dL" % (int(len(data)/4)), data) for n in range(numGlyphs): self.glyphPos.append((arr[n])) # n+1 !? else: die('Unknown location table format ' + indexToLocFormat) # CMAP Format 4 def getCMAP4(self, unicode_cmap_offset, glyphToChar, charToGlyph): self.maxUniChar = 0 self.seek(unicode_cmap_offset + 2) length = self.read_ushort() limit = unicode_cmap_offset + length self.skip(2) segCount = int(self.read_ushort() / 2) self.skip(6) endCount = [] for i in range(segCount): endCount.append(self.read_ushort()) self.skip(2) startCount = [] for i in range(segCount): startCount.append(self.read_ushort()) idDelta = [] for i in range(segCount): idDelta.append(self.read_short()) # ???? was unsigned short idRangeOffset_start = self._pos idRangeOffset = [] for i in range(segCount): idRangeOffset.append(self.read_ushort()) for n in range(segCount): endpoint = (endCount[n] + 1) for unichar in range(startCount[n], endpoint, 1): if (idRangeOffset[n] == 0): glyph = (unichar + idDelta[n]) & 0xFFFF else: offset = (unichar - startCount[n]) * 2 + idRangeOffset[n] offset = idRangeOffset_start + 2 * n + offset if (offset >= limit): glyph = 0 else: glyph = self.get_ushort(offset) if (glyph != 0): glyph = (glyph + idDelta[n]) & 0xFFFF charToGlyph[unichar] = glyph if (unichar < 196608): self.maxUniChar = max(unichar,self.maxUniChar) glyphToChar.setdefault(glyph, []).append(unichar) # CMAP Format 12 def getCMAP12(self, unicode_cmap_offset, glyphToChar, charToGlyph): self.maxUniChar = 0 # table (skip format version, should be 12) self.seek(unicode_cmap_offset + 2) # reserved self.skip(2) # table length length = self.read_ulong() # language (should be 0) self.skip(4) # groups count grpCount = self.read_ulong() if 2 + 2 + 4 + 4 + 4 + grpCount * 3 * 4 > length: die("TTF format 12 cmap table too small") for n in range(grpCount): startCharCode = self.read_ulong() endCharCode = self.read_ulong() glyph = self.read_ulong() for unichar in range(startCharCode, endCharCode + 1): charToGlyph[unichar] = glyph if (unichar < 196608): self.maxUniChar = max(unichar, self.maxUniChar) glyphToChar.setdefault(glyph, []).append(unichar) glyph += 1 # Put the TTF file together def endTTFile(self, stm): stm = b('') numTables = count(self.otables) searchRange = 1 entrySelector = 0 while (searchRange * 2 <= numTables): searchRange = searchRange * 2 entrySelector = entrySelector + 1 searchRange = searchRange * 16 rangeShift = numTables * 16 - searchRange # Header if (_TTF_MAC_HEADER): stm += (pack(">LHHHH", 0x74727565, numTables, searchRange, entrySelector, rangeShift)) # Mac else: stm += (pack(">LHHHH", 0x00010000 , numTables, searchRange, entrySelector, rangeShift)) # Windows # Table directory tables = self.otables offset = 12 + numTables * 16 sorted_tables = sorted(tables.items()) for tag, data in sorted_tables: if (tag == 'head'): head_start = offset stm += tag.encode("latin1") checksum = calcChecksum(data) stm += pack(">HH", checksum[0],checksum[1]) stm += pack(">LL", offset, strlen(data)) paddedLength = (strlen(data)+3)&~3 offset = offset + paddedLength # Table data for tag, data in sorted_tables: data += b("\0\0\0") stm += substr(data,0,(strlen(data)&~3)) checksum = calcChecksum(stm) checksum = sub32((0xB1B0,0xAFBA), checksum) chk = pack(">HH", checksum[0],checksum[1]) stm = self.splice(stm,(head_start + 8),chk) return stm endesive-2.19.1/endesive/pdf/pdf.py000066400000000000000000000046011504236674500171210ustar00rootroot00000000000000# *-* coding: utf-8 *-* import hashlib from endesive import signer from . import fpdf class FPDF(fpdf.FPDF): signer = True def pkcs11_aligned(self, data): data = ''.join(['%02x' % i for i in data]) nb = 0x4000 - len(data) data = data + '0' * (0x4000 - len(data)) return data def pkcs11_setup(self, config, key, cert, othercerts, algomd): self.pkcs11config = config self.pkcs11zeros = self.pkcs11_aligned([0]) self.pkcs11annot = 0 self.pkcs11key = key self.pkcs11cert = cert self.pkcs11certs = othercerts self.pkcs11algomd = algomd def pkcs11_signature(self): self._newobj() self.pkcs11annot = self.n self._out('<>/T(signature%d)/V %d 0 R>>' % ( self.pkcs11annot, self.pkcs11annot + 1)) self._out('endobj') self._newobj() self._out('< bool: validator = CertificateValidator( cert, othercerts, validation_context=self.context ) try: path = validator.validate_usage(set(["digital_signature"])) certok = True except Exception as ex: logger.exception(ex) certok = False return certok def is_valid_pdf(self) -> bool: return b"%PDF-" in self.pdf_data[:1024] def is_signed(self) -> bool: n = 0 while True: n = self.pdf_data.find(b"/ByteRange", n) if n == -1: break start = self.pdf_data.find(b"[", n) stop = self.pdf_data.find(b"]", start) if start == -1 or stop == -1: self.modified = True return False n = stop + 1 try: br = [int(i, 10) for i in self.pdf_data[start + 1 : stop].split()] assert self.pdf_data[br[1]] == 60 and self.pdf_data[br[2]-1] == 62 except: self.modified = True return False self.byte_ranges.append(br) if len(self.byte_ranges) == 0: return False byte_range = self.byte_ranges[-1] # last signature if byte_range[0]!=0 or byte_range[2]+byte_range[3] != len(self.pdf_data): self.wholefile = False return False self.wholefile = True return True def decompose_signed_data(self, datau: bytes, signed_data: cms.SignedData) -> tuple: signature = signed_data["signer_infos"][0]["signature"].native algo = signed_data["digest_algorithms"][0]["algorithm"].native attrs = signed_data["signer_infos"][0]["signed_attrs"] mdData = getattr(hashlib, algo)(datau).digest() if attrs is not None and not isinstance(attrs, core.Void): mdSigned = None for attr in attrs: if attr["type"].native == "message_digest": mdSigned = attr["values"].native[0] signedData = attrs.dump() signedData = b"\x31" + signedData[1:] else: mdSigned = mdData signedData = datau hashok = mdData == mdSigned cert = None othercerts = [] serial = signed_data["signer_infos"][0]["sid"].native["serial_number"] for pdfcert in signed_data["certificates"]: if serial != pdfcert.native["tbs_certificate"]["serial_number"]: othercerts.append(pdfcert.chosen) else: cert = pdfcert.chosen public_key = cx509.load_pem_x509_certificate( pem.armor("CERTIFICATE", cert.dump()), default_backend() ).public_key() sigalgo = signed_data["signer_infos"][0]["signature_algorithm"] sigalgoname = sigalgo.signature_algo if isinstance(public_key, ec.EllipticCurvePublicKey): try: public_key.verify( signature, signedData, ec.ECDSA(getattr(hashes, algo.upper())()), ) signatureok = True except Exception as e: signatureok = False elif sigalgoname == "rsassa_pss": parameters = sigalgo["parameters"] # parameters.debug() # print(parameters.native) salgo = parameters["hash_algorithm"].native["algorithm"].upper() mgf = getattr( padding, parameters["mask_gen_algorithm"].native["algorithm"].upper() )(getattr(hashes, salgo)()) salt_length = parameters["salt_length"].native try: public_key.verify( signature, signedData, padding.PSS(mgf, salt_length), getattr(hashes, salgo)(), ) signatureok = True except: signatureok = False elif sigalgoname == "rsassa_pkcs1v15": try: public_key.verify( signature, signedData, padding.PKCS1v15(), getattr(hashes, algo.upper())(), ) signatureok = True except: signatureok = False else: raise ValueError("Unknown signature algorithm") tspdata = None for attr in signed_data["signer_infos"][0]["unsigned_attrs"]: if attr["type"].native == "signature_time_stamp_token": for v in attr["values"]: if v["content_type"].native == "signed_data": tspdata = v["content"] crls = signed_data["crls"] return (signed_data, tspdata, crls, cert, othercerts, hashok, signatureok) def decompose_signature(self) -> tuple: byte_range = self.byte_ranges[-1] # last signature contents = self.pdf_data[byte_range[0] + byte_range[1] + 1 : byte_range[2] - 1] try: signaturebytes = bytes.fromhex(contents.decode("utf8")) except: return False data1 = self.pdf_data[byte_range[0] : byte_range[0] + byte_range[1]] data2 = self.pdf_data[byte_range[2] : byte_range[2] + byte_range[3]] datau = data1 + data2 signed_data = cms.ContentInfo.load(signaturebytes)["content"] return self.decompose_signed_data(datau, signed_data) def verify_ocsp_data(self, cert, othercerts, crldata): for crl1 in crldata: # clr1: cms.RevocationInfoChoice if crl1.native["other_rev_info_format"] != "ocsp_response": logger.debug("bad ocsp data") return False, None elif crl1.native["other_rev_info"]["response_status"] != "successful": logger.debug(f"ocsp response status failure: {crl1.native['other_rev_info']['response_status']}") return False, None elif crl1.native["other_rev_info"]["response_bytes"]["response_type"] == "basic_ocsp_response": crlresp : ocsp.BasicOCSPResponse = crl1.chosen[1][1][1].parsed #crlresp = crl1.native["other_rev_info"]["response_bytes"]["response"] produced_at = crlresp["tbs_response_data"]["produced_at"].native cert_was_checked = False next_check_at = None for ccert in crlresp["tbs_response_data"]["responses"]: v = ccert["cert_id"]["serial_number"].native == cert.serial_number if v: cert_was_checked = True next_check_at = ccert["next_update"].native break sigalgo = crlresp["signature_algorithm"]["algorithm"].native sig = crlresp["signature"].native sigok = False ocspcert = None for othercert in crlresp["certs"]: for ext in othercert["tbs_certificate"]["extensions"]: if ext["extn_id"].native == "extended_key_usage" and "ocsp_signing" in ext["extn_value"].native: ocspcert = othercert if ocspcert: bcert = x509.Certificate.load(ocspcert.dump()) if self.validate_certificate(bcert, othercerts) and not sigok: try: public_key = cx509.load_pem_x509_certificate( pem.armor("CERTIFICATE", ocspcert.dump()), default_backend() ).public_key() signedData = crlresp["tbs_response_data"].dump() # only sha256_rsa public_key.verify( sig, signedData, padding.PKCS1v15(), getattr(hashes, "SHA256")(), ) sigok = True except: logger.debug(f"ocsp signing certificate is invalid") pass if sigok and cert_was_checked: return True, (produced_at, next_check_at) logger.debug(f"ocsp cannot be verified") else: logger.debug(f"ocsp unknown response type: {crl1.native['other_rev_info']['response_bytes']['response_type']}") return False, None def verify_tsp_data(self, signed_data, tspdata, othercerts): if tspdata['encap_content_info']['content_type'].native == 'tst_info': (_, _, tcrldata, tcert, tothercerts, _, tsignatureok) = self.decompose_signed_data(b'', tspdata) if tsignatureok and self.validate_certificate(tcert, othercerts): tst = tspdata['encap_content_info']['content'].parsed signature_bytes = signed_data['signer_infos'][0]['signature'].native md = hashlib.sha256(signature_bytes).digest() if md == tst['message_imprint']['hashed_message'].native: return True, tst['gen_time'].native return False, None def verify(pdfdata:bytes, certs:list[cx509.Certificate]=None) -> list[tuple[bool, bool, bool]] : """ Verify PDF signature. :param pdfdata: PDF document as bytes. :param certs: List of additional certificates used to verify signature (system independent). :return: List of tuples containing three boolean values for each signature: (hashok, signatureok, certok): hashok: bool - True if the hash matches. signatureok: bool - True if the signature is valid. certok: bool - True if the certificate used for signing is trusted and valid.""" results = [] n = pdfdata.find(b"/ByteRange") while n != -1: start = pdfdata.find(b"[", n) stop = pdfdata.find(b"]", start) assert n != -1 and start != -1 and stop != -1 br = [int(i, 10) for i in pdfdata[start + 1 : stop].split()] assert pdfdata[br[1]] == 60 and pdfdata[br[2]-1] == 62 contents = pdfdata[br[0] + br[1] + 1 : br[2] - 1] bcontents = bytes.fromhex(contents.decode("utf8")) data1 = pdfdata[br[0] : br[0] + br[1]] data2 = pdfdata[br[2] : br[2] + br[3]] signedData = data1 + data2 result = verifier.verify(bcontents, signedData, certs) results.append(result) n = pdfdata.find(b"/ByteRange", br[2] + br[3]) return results endesive-2.19.1/endesive/plain/000077500000000000000000000000001504236674500163275ustar00rootroot00000000000000endesive-2.19.1/endesive/plain/__init__.py000066400000000000000000000000621504236674500204360ustar00rootroot00000000000000from .sign import sign from .verify import verify endesive-2.19.1/endesive/plain/sign.py000066400000000000000000000016541504236674500176470ustar00rootroot00000000000000# *-* coding: utf-8 *-* from cryptography import x509 from cryptography.hazmat.primitives.asymmetric.types import PrivateKeyTypes from endesive import signer def sign(datau:bytes, key: PrivateKeyTypes, cert: x509.Certificate, certs: list[x509.Certificate], hashalgo='sha1', attrs=True, pss=False) -> bytes: """ Sign data with private key without any encapsulation. Parameters: datau: Data to sign (bytes). key: Private key to sign with (PrivateKeyTypes). cert: Certificate to sign with (x509.Certificate). certs: List of additional certificates (list of x509.Certificate). hashalgo: Hash algorithm to use (str, default 'sha1'). attrs: Whether to include attributes (bool, default True). pss: Whether to use PSS padding (bool, default False). Returns: Signed data as bytes. """ return signer.sign(datau, key, cert, certs, hashalgo, attrs, pss=pss) endesive-2.19.1/endesive/plain/verify.py000066400000000000000000000013571504236674500202130ustar00rootroot00000000000000# *-* coding: utf-8 *-* from cryptography import x509 from endesive import verifier def verify(datas:bytes, datau:bytes, certs:list[x509.Certificate]=None) -> tuple[bool, bool, bool]: """ Verifies signed bytes. Parameters: datas: Signed data as bytes. datau: Original data as bytes. certs: List of additional certificates used to verify signature (system independent). Returns: hashok, signatureok, certok hashok : bool True if the hash matches. signatureok : bool True if the signature is valid. certok : bool True if the certificate used for signing is trusted and valid. """ return verifier.verify(datas, datau, certs) endesive-2.19.1/endesive/signer.py000066400000000000000000000356131504236674500170750ustar00rootroot00000000000000# *-* coding: utf-8 *-* from __future__ import unicode_literals import sys import types import hashlib import time import requests from base64 import b64encode from datetime import datetime from asn1crypto import cms, algos, core, keys, pem, tsp, x509, ocsp, util from cryptography.hazmat.primitives import hashes, serialization from cryptography.hazmat.primitives.asymmetric import padding, utils, ec from cryptography.hazmat import backends from cryptography import x509 as cryptography_x509 from cryptography.x509 import ocsp as cryptography_ocsp def cert2asn(cert, cert_bytes=True): if isinstance(cert, x509.Certificate): return cert if cert_bytes: cert_bytes = cert.public_bytes(serialization.Encoding.PEM) else: cert_bytes = cert if pem.detect(cert_bytes): _, _, cert_bytes = pem.unarmor(cert_bytes) return x509.Certificate.load(cert_bytes) def extract_ocsp_url_from_cert(cert): """Extract OCSP URL from certificate's Authority Information Access extension""" if hasattr(cert, 'public_bytes'): crypto_cert = cert else: if hasattr(cert, 'dump'): cert_bytes = cert.dump() else: cert_bytes = cert crypto_cert = cryptography_x509.load_der_x509_certificate( cert_bytes, backends.default_backend()) try: aia = crypto_cert.extensions.get_extension_for_oid( cryptography_x509.oid.ExtensionOID.AUTHORITY_INFORMATION_ACCESS) for access_description in aia.value: if access_description.access_method == cryptography_x509.oid.AuthorityInformationAccessOID.OCSP: return access_description.access_location.value except cryptography_x509.ExtensionNotFound: return None return None def fetch_ocsp_response(cert, issuer, url): if hasattr(cert, 'dump'): cert_bytes = cert.dump() cert = cryptography_x509.load_der_x509_certificate( cert_bytes, backends.default_backend()) if hasattr(issuer, 'dump'): issuer_bytes = issuer.dump() issuer = cryptography_x509.load_der_x509_certificate( issuer_bytes, backends.default_backend()) builder = cryptography_ocsp.OCSPRequestBuilder() builder = builder.add_certificate(cert, issuer, hashes.SHA1()) req = builder.build() data = req.public_bytes(serialization.Encoding.DER) try: response = requests.post( url, headers={"Content-Type": "application/ocsp-request"}, data=data, ) if response.status_code != 200: return None return response.content except requests.exceptions.ConnectionError: return None def timestamp(unhashed, hashalgo, url, credentials, req_options, prehashed=None): if prehashed: hashed_value = prehashed else: hashed_value = getattr(hashlib, hashalgo)(unhashed).digest() tspreq = tsp.TimeStampReq( { "version": 1, "message_imprint": tsp.MessageImprint( { "hash_algorithm": algos.DigestAlgorithm({"algorithm": hashalgo}), "hashed_message": hashed_value, } ), #'req_policy', ObjectIdentifier, {'optional': True}), "nonce": int(time.time() * 1000), "cert_req": True, #'extensions': tsp.Extensions() } ) tspreq = tspreq.dump() tspheaders = {"Content-Type": "application/timestamp-query"} if credentials is not None: username = credentials.get("username", None) password = credentials.get("password", None) if username and password: auth_header_value = b64encode( bytes(username + ":" + password, "utf-8") ).decode("ascii") tspheaders["Authorization"] = f"Basic {auth_header_value}" if req_options is None: req_options = {} tspresp = requests.post(url, data=tspreq, headers=tspheaders, **req_options) if tspresp.headers.get("Content-Type", None) == "application/timestamp-reply": tspresp = tsp.TimeStampResp.load(tspresp.content) if tspresp["status"]["status"].native == "granted": attrs = [ cms.CMSAttribute( { "type": cms.CMSAttributeType("signature_time_stamp_token"), "values": cms.SetOfContentInfo( [ cms.ContentInfo( { "content_type": cms.ContentType("signed_data"), "content": tspresp["time_stamp_token"][ "content" ], } ) ] ), } ) ] return attrs else: raise ValueError("TimeStampResponse status is not granted") else: raise ValueError("TimeStampResponse has invalid content type") def sign( datau, key, cert, othercerts, hashalgo, attrs=True, signed_value=None, hsm=None, pss=False, timestampurl=None, timestampcredentials=None, timestamp_req_options=None, ocspurl=None, ocspissuer=None, ): if signed_value is None: signed_value = getattr(hashlib, hashalgo)(datau).digest() signed_time = datetime.now(tz=util.timezone.utc) if hsm is not None: keyid, cert = hsm.certificate() cert = cert2asn(cert, False) else: cert = cert2asn(cert) certissuer = None certificates = [] certificates.append(cert) for i in range(len(othercerts)): certo = cert2asn(othercerts[i]) if certo.subject == cert.issuer: certissuer = certo certificates.append(certo) hashalgo = unicode(hashalgo) if sys.version[0] < "3" else hashalgo signer = { "version": "v1", "sid": cms.SignerIdentifier( { "issuer_and_serial_number": cms.IssuerAndSerialNumber( { "issuer": cert.issuer, "serial_number": cert.serial_number, } ), } ), "digest_algorithm": algos.DigestAlgorithm({"algorithm": hashalgo}), "signature": signed_value, } if not pss: signer["signature_algorithm"] = algos.SignedDigestAlgorithm( {"algorithm": "rsassa_pkcs1v15"} ) else: md = getattr(hashes, hashalgo.upper()) if isinstance(key, keys.PrivateKeyInfo): salt_length = key.byte_size - md.digest_size - 2 salt_length = md.digest_size else: if key is None: salt_length = md.digest_size else: salt_length = padding.calculate_max_pss_salt_length(key, md) signer["signature_algorithm"] = algos.SignedDigestAlgorithm( { "algorithm": "rsassa_pss", "parameters": algos.RSASSAPSSParams( { "hash_algorithm": algos.DigestAlgorithm( {"algorithm": hashalgo.lower()} ), "mask_gen_algorithm": algos.MaskGenAlgorithm( { "algorithm": algos.MaskGenAlgorithmId("mgf1"), "parameters": { "algorithm": algos.DigestAlgorithmId(hashalgo.lower()), }, } ), "salt_length": algos.Integer(salt_length), "trailer_field": algos.TrailerField(1), } ), } ) if attrs: if attrs is True: signing_certificate1 = cms.CMSAttribute( { "type": cms.CMSAttributeType("signing_certificate"), "values": ( tsp.SigningCertificate( { "certs": [ tsp.ESSCertID( { "cert_hash": hashlib.sha1( cert.dump() ).digest(), "issuer_serial": tsp.IssuerSerial( { "issuer": ( x509.GeneralName( { "directory_name": cert.issuer, } ), ), "serial_number": cert.serial_number, } ), } ), ] } ), ), } ) signing_certificate2 = cms.CMSAttribute( { "type": cms.CMSAttributeType("signing_certificate_v2"), "values": [ tsp.SigningCertificateV2( { "certs": [ tsp.ESSCertIDv2( { "hash_algorithm": algos.DigestAlgorithm( {"algorithm": "sha256"} ), "cert_hash": hashlib.sha256( cert.dump() ).digest(), "issuer_serial": tsp.IssuerSerial( { "issuer": ( x509.GeneralName( { "directory_name": cert.issuer, } ), ), "serial_number": cert.serial_number, } ), } ), ] } ), ], } ) signer["signed_attrs"] = [ cms.CMSAttribute( { "type": cms.CMSAttributeType("content_type"), "values": ("data",), } ), cms.CMSAttribute( { "type": cms.CMSAttributeType("message_digest"), "values": (signed_value,), } ), # cms.CMSAttribute( # { # "type": cms.CMSAttributeType("signing_time"), # "values": (cms.Time({"utc_time": core.UTCTime(signed_time)}),), # } # ), signing_certificate2, ] else: if isinstance(attrs, types.FunctionType): attrs = attrs(signed_value) signer["signed_attrs"] = attrs config = { "version": "v1", "digest_algorithms": cms.DigestAlgorithms( (algos.DigestAlgorithm({"algorithm": hashalgo}),) ), "encap_content_info": { "content_type": "data", }, "certificates": certificates, "signer_infos": [ signer, ], } if ocspurl and ocspissuer: ocsp_response = fetch_ocsp_response(cert, ocspissuer, ocspurl) if ocsp_response: ocsp_response = ocsp.OCSPResponse.load(ocsp_response) other = cms.RevocationInfoChoice( { "other": cms.OtherRevocationInfoFormat( { "other_rev_info_format": cms.OtherRevInfoFormatId( "ocsp_response" ), "other_rev_info": ocsp_response, } ) } ) config["crls"] = cms.RevocationInfoChoices([other]) datas = cms.ContentInfo( { "content_type": cms.ContentType("signed_data"), "content": cms.SignedData(config), } ) if attrs: tosign = datas["content"]["signer_infos"][0]["signed_attrs"].dump() tosign = b"\x31" + tosign[1:] else: tosign = datau if hsm is not None: signed_value_signature = hsm.sign(keyid, tosign, hashalgo) else: if pss: md = getattr(hashes, hashalgo.upper()) hasher = hashes.Hash(md(), backend=backends.default_backend()) hasher.update(tosign) digest = hasher.finalize() signed_value_signature = key.sign( digest, padding.PSS(mgf=padding.MGF1(md()), salt_length=salt_length), utils.Prehashed(md()), ) else: if isinstance(key, ec.EllipticCurvePrivateKey): signed_value_signature = key.sign( tosign, ec.ECDSA(getattr(hashes, hashalgo.upper())()) ) else: signed_value_signature = key.sign( tosign, padding.PKCS1v15(), getattr(hashes, hashalgo.upper())() ) if timestampurl is not None: datas["content"]["signer_infos"][0]["unsigned_attrs"] = timestamp( signed_value_signature, hashalgo, timestampurl, timestampcredentials, timestamp_req_options, ) # signed_value_signature = core.OctetString(signed_value_signature) datas["content"]["signer_infos"][0]["signature"] = signed_value_signature # open('signed-content-info', 'wb').write(datas.dump()) return datas.dump() endesive-2.19.1/endesive/verifier.py000066400000000000000000000121661504236674500174170ustar00rootroot00000000000000# *-* coding: utf-8 *-* import os import glob import hashlib import datetime from asn1crypto import x509, core, pem, cms import certifi from cryptography.hazmat.primitives import serialization, hashes from cryptography.hazmat.primitives.asymmetric import padding, ec from cryptography.x509.verification import PolicyBuilder, Store from cryptography import x509 as cx509 from cryptography.hazmat.backends import default_backend class VerifyData(object): def __init__(self, trustedCerts=None): with open(certifi.where(), "rb") as pems: certs = cx509.load_pem_x509_certificates(pems.read()) if trustedCerts is not None: for cert_bytes in trustedCerts: certs.append(cx509.load_pem_x509_certificate(cert_bytes)) #self.trustedCerts = trustedCerts store = Store(certs) self.verifier = PolicyBuilder( ).store(store ).time(datetime.datetime.utcnow() ).max_chain_depth(4 ).build_client_verifier() def verify(self, datas, datau): signed_data = cms.ContentInfo.load(datas)["content"] # signed_data.debug() signature = signed_data["signer_infos"][0]["signature"].native algo = signed_data["digest_algorithms"][0]["algorithm"].native attrs = signed_data["signer_infos"][0]["signed_attrs"] mdData = getattr(hashlib, algo)(datau).digest() if attrs is not None and not isinstance(attrs, core.Void): mdSigned = None for attr in attrs: if attr["type"].native == "message_digest": mdSigned = attr["values"].native[0] signedData = attrs.dump() signedData = b"\x31" + signedData[1:] else: mdSigned = mdData signedData = datau hashok = mdData == mdSigned cert = None othercerts = [] serial = signed_data["signer_infos"][0]["sid"].native["serial_number"] for pdfcert in signed_data["certificates"]: if serial != pdfcert.native["tbs_certificate"]["serial_number"]: othercerts.append( cx509.load_pem_x509_certificate( pem.armor("CERTIFICATE", pdfcert.chosen.dump()) ) ) else: assert cert is None cert = cx509.load_pem_x509_certificate( pem.armor("CERTIFICATE", pdfcert.chosen.dump()) ) public_key = cert.public_key() sigalgo = signed_data["signer_infos"][0]["signature_algorithm"] # sigalgo.debug() sigalgoname = sigalgo.signature_algo if isinstance(public_key, ec.EllipticCurvePublicKey): try: public_key.verify( signature, signedData, ec.ECDSA(getattr(hashes, algo.upper())()), ) signatureok = True except Exception as e: signatureok = False elif sigalgoname == "rsassa_pss": parameters = sigalgo["parameters"] # parameters.debug() # print(parameters.native) salgo = parameters["hash_algorithm"].native["algorithm"].upper() mgf = getattr( padding, parameters["mask_gen_algorithm"].native["algorithm"].upper() )(getattr(hashes, salgo)()) salt_length = parameters["salt_length"].native try: public_key.verify( signature, signedData, padding.PSS(mgf, salt_length), getattr(hashes, salgo)(), ) signatureok = True except: signatureok = False elif sigalgoname == "rsassa_pkcs1v15": try: public_key.verify( signature, signedData, padding.PKCS1v15(), getattr(hashes, algo.upper())(), ) signatureok = True except: signatureok = False else: raise ValueError("Unknown signature algorithm") try: self.verifier.verify(cert, othercerts) certok = True except Exception as ex: print("*" * 10, "failed certificate verification:", ex) print("cert.issuer:", cert.issuer) print("cert.subject:", cert.subject) certok = False return (hashok, signatureok, certok) def verify(datas:bytes, datau:bytes, certs:list[x509.Certificate]=None) -> tuple[bool, bool, bool]: """ Verify signed data. :param data: Email data as bytes. :param certs: List of additional certificates used to verify signature (system independent). :return: hashok, signatureok, certok hashok : bool True if the hash matches. signatureok : bool True if the signature is valid. certok : bool True if the certificate used for signing is trusted and valid. """ cls = VerifyData(certs) return cls.verify(datas, datau) endesive-2.19.1/endesive/xades/000077500000000000000000000000001504236674500163305ustar00rootroot00000000000000endesive-2.19.1/endesive/xades/__init__.py000066400000000000000000000000251504236674500204360ustar00rootroot00000000000000from .bes import BES endesive-2.19.1/endesive/xades/bes.py000066400000000000000000000474701504236674500174670ustar00rootroot00000000000000# -*- coding: utf-8 -*- # https://dss.nowina.lu/validation # https://signatures-conformance-checker.etsi.org/pub/index.php # import base64 import time import datetime import hashlib import io import uuid from cryptography.x509.oid import NameOID from lxml import etree, builder import requests from asn1crypto import cms, algos, core, keys, pem, tsp, x509, util DS = builder.ElementMaker( namespace="http://www.w3.org/2000/09/xmldsig#", nsmap={"ds": "http://www.w3.org/2000/09/xmldsig#"}, ) CanonicalizationMethod = DS.CanonicalizationMethod DigestMethod = DS.DigestMethod DigestValue = DS.DigestValue KeyInfo = DS.KeyInfo Object = DS.Object Reference = DS.Reference Signature = DS.Signature SignatureMethod = DS.SignatureMethod SignatureValue = DS.SignatureValue SignedInfo = DS.SignedInfo Transform = DS.Transform Transforms = DS.Transforms X509Certificate = DS.X509Certificate X509Data = DS.X509Data X509IssuerName = DS.X509IssuerName X509SerialNumber = DS.X509SerialNumber XPath = DS.XPath XADES = builder.ElementMaker( namespace="http://uri.etsi.org/01903/v1.3.2#", nsmap={ "xades": "http://uri.etsi.org/01903/v1.3.2#", "ds": "http://www.w3.org/2000/09/xmldsig#", }, ) Cert = XADES.Cert CertDigest = XADES.CertDigest DataObjectFormat = XADES.DataObjectFormat Description = XADES.Description DocumentationReference = XADES.DocumentationReference DocumentationReferences = XADES.DocumentationReferences Identifier = XADES.Identifier IssuerSerial = XADES.IssuerSerial MimeType = XADES.MimeType ObjectIdentifier = XADES.ObjectIdentifier QualifyingProperties = XADES.QualifyingProperties SignedDataObjectProperties = XADES.SignedDataObjectProperties SignedProperties = XADES.SignedProperties SignedSignatureProperties = XADES.SignedSignatureProperties SigningCertificate = XADES.SigningCertificate SigningTime = XADES.SigningTime UnsignedProperties = XADES.UnsignedProperties UnsignedSignatureProperties = XADES.UnsignedSignatureProperties SignatureTimeStamp = XADES.SignatureTimeStamp EncapsulatedTimeStamp = XADES.EncapsulatedTimeStamp OID_NAMES = { NameOID.COMMON_NAME: "CN", NameOID.COUNTRY_NAME: "C", NameOID.DOMAIN_COMPONENT: "DC", NameOID.EMAIL_ADDRESS: "E", NameOID.GIVEN_NAME: "G", NameOID.LOCALITY_NAME: "L", NameOID.ORGANIZATION_NAME: "O", NameOID.ORGANIZATIONAL_UNIT_NAME: "OU", NameOID.SURNAME: "SN", } class BES: debug = False def __init__(self): self.guid = str(uuid.uuid1()) self.time = datetime.datetime.utcnow().strftime("%Y-%m-%dT%H:%M:%SZ") def sha256(self, data): h = hashlib.sha256(data).digest() return base64.b64encode(h).decode() def base64(self, data): b64 = b"".join(base64.encodebytes(data).split()) data = [] for i in range(0, len(b64), 64): data.append(b64[i : i + 64]) data = b"\n".join(data).decode() return data def get_rdns_name(self, rdns): name = "" for rdn in rdns: for attr in rdn._attributes: if len(name) > 0: name = name + "," if attr.oid in OID_NAMES: name = name + OID_NAMES[attr.oid] else: name = name + attr.oid.dotted_string s = "".join(["%02x" % int(b) for b in attr.value.encode()]) s = "#0C%02X%s" % (len(attr.value), s) name = name + "=" + s continue name = name + "=" + attr.value return name def _c14n(self, nodes, algorithm, inclusive_ns_prefixes=None): exclusive, with_comments = False, False if algorithm.startswith("http://www.w3.org/2001/10/xml-exc-c14n#"): exclusive = True if algorithm.endswith("#WithComments"): with_comments = True data = etree.tostring( nodes, encoding="UTF-8", xml_declaration=True, standalone=False ) data = io.BytesIO(data) tree = etree.parse(data) data = io.BytesIO() tree.write_c14n( data, exclusive=exclusive, with_comments=with_comments, compression=0, inclusive_ns_prefixes=inclusive_ns_prefixes, ) c14n = data.getvalue() return c14n def unsignedpropertied(self, signed_value, tspurl, tspcred, hashalgo="sha256"): if tspurl is None: unsignedproperties = UnsignedProperties( Id="UnsignedProperties_" + self.guid + self.mapa["_5d"] ) else: tspreq = tsp.TimeStampReq( { "version": 1, "message_imprint": tsp.MessageImprint( { "hash_algorithm": algos.DigestAlgorithm( {"algorithm": hashalgo} ), "hashed_message": signed_value.encode(), } ), #'req_policy', ObjectIdentifier, {'optional': True}), "nonce": int(time.time() * 1000), "cert_req": True, #'extensions': tsp.Extensions() } ) tspreq = tspreq.dump() tspheaders = {"Content-Type": "application/timestamp-query"} if tspcred is not None: username = tspcred.get("username", None) password = tspcred.get("password", None) if username and password: auth_header_value = base64.b64encode( bytes(username + ":" + password, "utf-8") ).decode("ascii") tspheaders["Authorization"] = f"Basic {auth_header_value}" tspresp = requests.post(tspurl, data=tspreq, headers=tspheaders) if ( tspresp.headers.get("Content-Type", None) == "application/timestamp-reply" ): tspresp = tsp.TimeStampResp.load(tspresp.content) if tspresp["status"]["status"].native == "granted": attr = self.base64(tspresp["time_stamp_token"].dump()) else: raise ValueError("TimeStampResponse status is not granted") else: raise ValueError("TimeStampResponse has invalid content type") unsignedproperties = UnsignedProperties( UnsignedSignatureProperties( SignatureTimeStamp( CanonicalizationMethod( Algorithm="http://www.w3.org/TR/2001/REC-xml-c14n-20010315" ), EncapsulatedTimeStamp( attr, Encoding="http://uri.etsi.org/01903/v1.2.2#DER" ), Id="SignatureTimeStamp_" + self.guid, ) ), Id="UnsignedProperties_" + self.guid + self.mapa["_5d"], ) return unsignedproperties mapa = { "_02": "_5d", "_2f": "_70", "_43": "_1c", "_20": "_7f", "_46": "_19", "_49": "_16", "_5a": "_05", "_2c": "_73", "_4b": "_14", "_11": "_4e", "_5d": "_02", } def enveloped(self, data, cert, certcontent, signproc, tspurl, tspcred): tree = etree.parse(io.BytesIO(data)) signedobj = tree.getroot() canonicalizedxml = self._c14n(signedobj, "") digestvalue1 = self.sha256(canonicalizedxml) nsmap = signedobj.nsmap.copy() nsmap.update( { "xades": "http://uri.etsi.org/01903/v1.3.2#", "ds": "http://www.w3.org/2000/09/xmldsig#", } ) siXADES = builder.ElementMaker( namespace="http://uri.etsi.org/01903/v1.3.2#", nsmap=nsmap ) SignedProperties = siXADES.SignedProperties nsmap = signedobj.nsmap.copy() nsmap.update({"ds": "http://www.w3.org/2000/09/xmldsig#"}) siDS = builder.ElementMaker( namespace="http://www.w3.org/2000/09/xmldsig#", nsmap=nsmap ) SignedInfo = siDS.SignedInfo certdigest = self.sha256(certcontent) certcontent = self.base64(certcontent) certserialnumber = "%d" % cert.serial_number certissuer = self.get_rdns_name(cert.issuer.rdns) if self.debug: self.guid = "279d6285-779c-4449-9c92-6bf3f7edacc2" self.time = "2020-11-24T00:32:43Z" certissuer = "2.5.4.97=#0C10564154504C2D35313730333539343538,CN=Certum QCA 2017,O=Asseco Data Systems S.A.,C=PL" signedproperties = SignedProperties( SignedSignatureProperties( SigningTime(self.time), SigningCertificate( Cert( CertDigest( DigestMethod( Algorithm="http://www.w3.org/2001/04/xmlenc#sha256" ), DigestValue(certdigest), ), IssuerSerial( X509IssuerName(certissuer), X509SerialNumber(certserialnumber), ), ) ), Id="SignedSignatureProperties_" + self.guid + self.mapa["_02"], ), SignedDataObjectProperties( DataObjectFormat( Description( """\ MIME-Version: 1.0 Content-Type: text/xml Content-Transfer-Encoding: binary Content-Disposition: filename="document.xml"\ """ ), ObjectIdentifier( Identifier( "http://www.certum.pl/OIDAsURI/signedFile/1.2.616.1.113527.3.1.1.3.1", Qualifier="OIDAsURI", ), Description("Opis formatu dokumentu oraz jego pełna nazwa"), DocumentationReferences( DocumentationReference( "http://www.certum.pl/OIDAsURI/signedFile.pdf" ) ), ), MimeType("text/xml"), ObjectReference="#Reference1_" + self.guid + self.mapa["_2f"], ), Id="SignedDataObjectProperties_" + self.guid + self.mapa["_43"], ), Id="SignedProperties_" + self.guid + self.mapa["_46"], ) canonicalizedxml = self._c14n(signedproperties, "") digestvalue2 = self.sha256(canonicalizedxml) if self.debug: print("*" * 20, "enveloped signedproperties") print(canonicalizedxml) print("digest:", digestvalue2) unsignedproperties = self.unsignedpropertied( digestvalue2, tspurl, tspcred, "sha256" ) signedinfo = SignedInfo( CanonicalizationMethod( Algorithm="http://www.w3.org/TR/2001/REC-xml-c14n-20010315" ), SignatureMethod( Algorithm="http://www.w3.org/2001/04/xmldsig-more#rsa-sha256" ), Reference( Transforms( Transform( XPath("not(ancestor-or-self::ds:Signature)"), Algorithm="http://www.w3.org/TR/1999/REC-xpath-19991116", ) ), DigestMethod(Algorithm="http://www.w3.org/2001/04/xmlenc#sha256"), DigestValue(digestvalue1), Id="Reference1_" + self.guid + self.mapa["_2f"], URI="", ), Reference( DigestMethod(Algorithm="http://www.w3.org/2001/04/xmlenc#sha256"), DigestValue(digestvalue2), Id="SignedProperties-Reference_" + self.guid + self.mapa["_20"], Type="http://uri.etsi.org/01903#SignedProperties", URI="#SignedProperties_" + self.guid + self.mapa["_46"], ), Id="SignedInfo_" + self.guid + self.mapa["_49"], ) canonicalizedxml = self._c14n(signedinfo, "") if self.debug: print("*" * 20, "enveloped signedinfo") print(canonicalizedxml) signature = signproc(canonicalizedxml, "sha256") actualdigestencoded = base64.b64encode(signature).decode() digestvalue3 = [] for i in range(0, len(actualdigestencoded), 64): digestvalue3.append(actualdigestencoded[i : i + 64]) digestvalue3 = "\n".join(digestvalue3) DOC = Signature( signedinfo, SignatureValue( digestvalue3, Id="SignatureValue_" + self.guid + self.mapa["_5a"] ), KeyInfo( X509Data(X509Certificate(certcontent)), Id="KeyInfo_" + self.guid + self.mapa["_2c"], ), Object( QualifyingProperties( signedproperties, unsignedproperties, Id="QualifyingProperties_" + self.guid + self.mapa["_4b"], Target="#Signature_" + self.guid + self.mapa["_11"], ) ), Id="Signature_" + self.guid + self.mapa["_11"], ) signedobj.append(DOC) return tree def enveloping( self, fname, data, smime, cert, certcontent, signproc, base64encode=True, withcomments=False, detached=False, tspurl=None, tspcred=None, ): swithcomments = "" if withcomments: swithcomments = "#WithComments" if detached: tree = etree.parse(io.BytesIO(data)) signedobj = tree.getroot() canonicalizedxml = self._c14n(signedobj, "") digestvalue1 = self.sha256(canonicalizedxml) URI = fname signedobj = None else: if base64encode: data = base64.b64encode(data).decode() signedobj = Object( data, Encoding="http://www.w3.org/2000/09/xmldsig#base64", MimeType=smime, Id="Object1_" + self.guid, ) URI = "#Object1_" + self.guid elif 0: signedobj = Object(data, MimeType="text/xml", Id="Object1_" + self.guid) URI = "#Object1_" + self.guid else: signedobj = Object(MimeType="text/xml", Id="Object1_" + self.guid) tree = etree.parse(io.BytesIO(data)) signedobj.append(tree.getroot()) URI = "#Object1_" + self.guid canonicalizedxml = self._c14n(signedobj, "") digestvalue1 = self.sha256(canonicalizedxml) certdigest = self.sha256(certcontent) certcontent = self.base64(certcontent) certserialnumber = "%d" % cert.serial_number certissuer = self.get_rdns_name(cert.issuer.rdns) signedprop = SignedProperties( SignedSignatureProperties( SigningTime(self.time), SigningCertificate( Cert( CertDigest( DigestMethod( Algorithm="http://www.w3.org/2001/04/xmlenc#sha256" ), DigestValue(certdigest), ), IssuerSerial( X509IssuerName(certissuer), X509SerialNumber(certserialnumber), ), ) ), Id="SignedSignatureProperties_" + self.guid + self.mapa["_02"], ), SignedDataObjectProperties( DataObjectFormat( Description( """\ MIME-Version: 1.0 Content-Type: %s Content-Transfer-Encoding: binary Content-Disposition: filename="%s"\ """ % (smime, fname) ), ObjectIdentifier( Identifier( "http://www.certum.pl/OIDAsURI/signedFile/1.2.616.1.113527.3.1.1.3.1", Qualifier="OIDAsURI", ), Description("Opis formatu dokumentu oraz jego pełna nazwa"), DocumentationReferences( DocumentationReference( "http://www.certum.pl/OIDAsURI/signedFile.pdf" ) ), ), MimeType(smime), ObjectReference="#Reference1_" + self.guid + self.mapa["_2f"], ), Id="SignedDataObjectProperties_" + self.guid + self.mapa["_43"], ), Id="SignedProperties_" + self.guid + self.mapa["_46"], ) canonicalizedxml = self._c14n(signedprop, "") digestvalue2 = self.sha256(canonicalizedxml) if self.debug: print("*" * 20, "build signedprop") print(canonicalizedxml) print("digest:", digestvalue2) signedinfo = SignedInfo( CanonicalizationMethod( Algorithm="http://www.w3.org/TR/2001/REC-xml-c14n-20010315" ), SignatureMethod( Algorithm="http://www.w3.org/2001/04/xmldsig-more#rsa-sha256" ), Reference( Transforms( Transform( Algorithm="http://www.w3.org/TR/2001/REC-xml-c14n-20010315" + swithcomments ) ), DigestMethod(Algorithm="http://www.w3.org/2001/04/xmlenc#sha256"), DigestValue(digestvalue1), URI=URI, Id="Reference1_" + self.guid + self.mapa["_2f"], ), Reference( DigestMethod(Algorithm="http://www.w3.org/2001/04/xmlenc#sha256"), DigestValue(digestvalue2), Id="SignedProperties-Reference_" + self.guid + self.mapa["_20"], Type="http://uri.etsi.org/01903#SignedProperties", URI="#SignedProperties_" + self.guid + self.mapa["_46"], ), Id="SignedInfo_" + self.guid + self.mapa["_49"], ) canonicalizedxml = self._c14n(signedinfo, "") if self.debug: print("*" * 20, "build signedinfo") print(canonicalizedxml) signature = signproc(canonicalizedxml, "sha256") actualdigestencoded = base64.b64encode(signature).decode() digestvalue3 = [] for i in range(0, len(actualdigestencoded), 64): digestvalue3.append(actualdigestencoded[i : i + 64]) digestvalue3 = "\n".join(digestvalue3) unsignedproperties = self.unsignedpropertied( digestvalue2, tspurl, tspcred, "sha256" ) DOC = Signature( signedinfo, SignatureValue( digestvalue3, Id="SignatureValue_" + self.guid + self.mapa["_5a"] ), KeyInfo( X509Data(X509Certificate(certcontent)), Id="KeyInfo_" + self.guid + self.mapa["_2c"], ), Object( QualifyingProperties( signedprop, unsignedproperties, Id="QualifyingProperties_" + self.guid + self.mapa["_4b"], Target="#Signature_" + self.guid + self.mapa["_11"], ) ), Id="Signature_" + self.guid + self.mapa["_11"], ) if signedobj is not None: DOC.append(signedobj) return DOC endesive-2.19.1/examples/000077500000000000000000000000001504236674500152405ustar00rootroot00000000000000endesive-2.19.1/examples/.gitignore000066400000000000000000000002631504236674500172310ustar00rootroot00000000000000*.pem *.crt *.der *.p7s *.json softhsm2/ softhsm2.conf signature_appearances/endesive/ t-ocsp-crl.der t-ocsp-issuer.der t-ocsp-req.bin t-ocsp-resp.bin t-ts-req.bin t-ts-resp.bin endesive-2.19.1/examples/DejaVuSans.ttf000066400000000000000000027065241504236674500200020ustar00rootroot00000000000000@FFTMsLGDEFώhGPOSV5GSUB@YMATH28}h>OS/2Y-v-VcmapI&cvt i9fpgmq4vjgasp glyfa {head  T6hhea  T$hmtx%߭ Uakern ; ?loca`( amaxpq X` nameoM X=postHȖT dprep; h=))(0Y         !%&&'KLLMOPTUst?@@ABCJKQRWX    ) * , -            ghhiijjkmnnoyz!",-l \DFLTzarabarmnbraicanschercyrlgeorgrekhanihebrkana*lao 6latnFmathnko ogamrunrtfngthaiKUR SND URD MKD SRB 4ISM 4KSM 4LSM 4MOL 4NSM 4ROM 4SKS 4SSM 4 kern8kern>markFmarkTmark\markdmkmkjmkmkrmkmkx    "*2:BLT\dlt|fF  f!<":#89;=4CCG Xr s^ 0&:  vy~vy~ *06<BHNTZ`flrx~:::::r: 4 4 `Ltuwxz{|}Ltuwxz{|}RX^djpv|$ lJGH N>X  &,lwlwlwfn@CDEFIRW &,28l`l~l~l`l~l`Z& #HNTZ`flrx~tt;888  !"    ! "(.4:@FB :v| $*06<BHNTZ`flrx~hhh=DhhhVDhh=DDnnnnhh   !# )""0$$1&,29  %",,78 $*06<BHNTZ`flrx~ &,{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{ $6HZl~ cj cj cj cj c c cj cj&vy~>DJPV\bhntz< w &,28>DJPV\bhntz "(.4:@FLRX^djpv| $*06<BHNTZ`flrx~ &,28>DJPV\bhntz     " ( . 4 : @ F L R X ^ d j p v |     $ * 0 6 < B H N T Z ` f l r x ~      & , 2 8 > D J P V \ b h n t z     " ( . 4 : @ F L R X ^ d j p v |     $ * 0 6 < B H N T Z ` f l r x ~  &,28>DJPV\bhntz "(.4:@FLRX^djpv| $*06<BHNTZ`flrx~ &,28>DJPV\bhntz "(.4:@FLRX^djpv| $*06<BHNTZ`flrx~U,!8|Q'n ppjjj,v,,vjj  XXXXD[j[j, 8 8>>j pjjj^jj,,,,,,,j^ppjjjj         XXXXX[j 8pp 8v 8 j j j 8 8 v j j j p D j>>>D>>> j,    ppjI^`k/#eYYY++++++jj++jj++jj++ 8 8jj 8 8jj,,X X ,,XX,,X X ,,X X jjjjjj     j j,j,j j j,j,j D Dvv j j,j,j>>++ jRj 8 8,j,j        ++++pp++,,,, ,,,,,,,,,,2  pp++pp++jjjj++jj++,,XX,,XX,,XXjjjj    XXjjXXjjXX&j&jXX&j&j[j[jSjSj[j[jSjSjXX 8 8jjjj 8 8,j,j>>SS&j&j>++jjj  pp++j++ 8jjjj++^++j++,XX,XX,XX,X X   >SSp++ jIII^^^```kkk///###eeeYYYYYYYYY^ppjj     XppXXX p pX&j&j[jSjSjXppvjjjj jjj j,j,j 8,j,j v j,j,j p j,j,j>SS>SS+I++c++++ 'DPsBDVk3=?PltvvD"&vy~BHNTZ`flrx~ 06<BHNTZ`flrx~c00008000q=i000010f00j=0P'-/355 78 :;=A0 $6HZl~ cr cr cr cr cr cr cr cr Ltuwxz{|}Z`flrx~``L \ &,28>DJPV\bhntz "(.4:@FLRX^djpv| $*06<BHNTZ`flrx~ &,28>DJPV\bhntz     " ( . 4 : @ F L R X ^ d j p v |     $ * 0 6 < B H N T Z ` f l r x ~      & , 2 8 > D J P V \ b h n t z     " ( . 4 : @ F L R X ^ d j p v |     $ * 0 6 < B H N T Z ` f l r x ~  &,28>DJPV\bhntz "(.4:@FLRX^djpv| $*06<BHNTZ`flrx~ &,28>DJPV\bhntz "(.4:@FLRX^djpv|R``S`4rrLRLX X X X [r[r~x,LLRLLRL@@xX X X X X [rrLLLLLLLLxxx99xxxxxx44f_RLFRI^`n#YYY++++++LL++LL++++LL@LL@XXXXXXXX@@xxxxxxxxxxll_e++RLR L 99FFX++++XV++,,,:,,,,:,:,,,,,:,:LrrX+F+Frr++L&LRR++LL++XXXXX~X~X X X X RRX X & & X X &&[r[rSrSr[r[rSrSr~~x~x~LLFLRFSrSrR&R&R++R&RL XVX++++LLRL++R++++XXXxXxXxXxX~X~4S4S4++&RIII^^^```nnn###YYYYYYYYY@X RRX X RRX & & X XX[rSrSrxrxLLLFLLRFR@xxxxxx9xxxff4S4S4fSfSfSrSr++++++((22;;Ps')xVk3=?PltvvD Ltuwxz{|}z "(`{{{{{{{{` <BHNTZ`flrx~]xx@[")@>E"~~x2x::#=bcGHJ"> @FLRX^djpv|]kxyyyxyz[f"w)h>yEy`P["~[~t`zxy2{`uxJJ::#=QQ``bc @CDEFIRSTUVW 28>DJPV\bhnttbbbbt`~~`~` Z R   !"# $*06<BHNTZ 28>DJPV\bhntz "(.4:@FLRX^djpv| $*06<BHNTZ`flrx~ &,28>DJPV\bhntz%$=D]4568:();AA=HH>QR?YYAaaBy{CFGHI**J77KTTLMN  OY\^_a cg'r)-|25<HLPSShj bNj $*06<Jms}P-   {{ Y &,28>DJPV\bhntz "(.4:@FLRX^djpv|L-./++'fs.}////'s////s}\'/'R///RJsR//'s{y5D;+./}RY$&'(+,01268=DFGHKLPQRVX]-HQRYayz{*7T , - $%BCFGHOS L rx~ &,28>DJPV\bhntz "(.4:@FLRX^djpv| $*06<BHNTZ`flrx~ &,28>DJPV\bhntz "(.4:@FLRX^djpv|     $ * 0 6 < B H N T Z ` f l r x ~      & , 2 8 > D J P V \ b h n t z     " ( . 4 : @ F L R X ^ d j p v |     $ * 0 6 < B H N T Z ` f l r x ~      & , 2 8 > D J P V \ b h n t z L\/.Rs''}srJf;RRsRR%}^Gb`R////'}sJf////Rss};\f'7R/'z`RR///.RR'}r`RTTRTcRRJ@@RjRjRbRb}RRRRRRRRsR555RRaRt;Q'RRRRRRR}}^G^dRRR::R'aHRR_R:RGR R.R~RJ}'/'}'}^TTT@X}Tg^GX^Rffftftf//LBRRf,4$R'_zRf4L}`ReT'sR^G^5sRR/nRRwRRJV1vvvR;nRR'RR RRR\R}%fOL5s/<\R&Rx9\wR}R`$= D]$>BCDIJKMOPXZ  [\]()^--`AAaEEbHHcNNdQReTTgYYhaailljvvky{loqu xJLgikmmGGJJMM##4477}~hikps{   , -      ! " ( ) * , / 0 5 9:;=OR@@TU W []-i25y;P}wSTkkuu   !"# $*06<BHNTZl l "(.4:@FLRX^djpv|  &,2:@FLRX^djpx~ $*06<BHNTZ`flrx~ (.4:@FLTZ`flrx~     " ( . 4 : @ F L R X ^ d j p v |     $ * 0 6 < B J P V \ b h n t z     " ( . 4 : @ F L R X ^ d j p v |     $ * 0 6 < B H N T Z ` f l r x ~      & , 2 8 > D J P V \ b h n t z  "(.4:@FLRX^djpv|  &,28>DJPV^djpv| $*06<BHNTZ`flrx~ &.4:@FLRX^djpv| "(.4:@FLRX^djpv| $*06<BHNTZ`flrx~L\/.*s''}srJ{#{{j{//{{s{ {o{{'{}{^{G{b{`{{'{{}s{J{#Q{{{{s}{\LX';\//''{ssr`{{{'{{{./'}{r`{{T{{{{c{R{R{J|@{@{{{jj{{b{b{}{/{{{{{{{{s{{{3{33{^{a{p{{;{Q{'{{{}{}{^{G{^d{{{{{::'a{H{{/{{j:G{ .J{~^{}J|E{}{{{{E}{p{{t{}{j{{{b{{^{~~{}{t{^{{{{/'{{{H/rtOs}s'LsoqGGYNsT{a{E{{{{@{{t{{{{}{{{{T{`{kb{{K{{{{{{{{t{{'{///{{4{^{c{s{"{O{,s{O{%'}{{{O{t{t{e{sK{{{{'}{E{b{{t{{{^{{{T{{TT{{@{{{{{}{{{{{{{{{T{g{b{^{G{{{{^{{{LBRf,4${' _zf4DL}1{`{e**}T{{'s^{G{^{{{3s{{/ {0{{{{'l{n{T{T{n{wJ{{{1{{v{vqv{*\;{n{{{'o{{{{\j{{}{'{fO{L5s/<\&Rx9{\{w{{{{{}{y$= D]$>?ABCDFGIJ  KL()M55OABPEERHISNNUPVVXY][]___baacffdijelpgt{ltu yJLgikmmF^efjjllnnppxx  6LT c#$i+,k/7mAAvNNwYYx__yccz}~{}~hps|               &&::@@   -//&15':P,wCVWXRTbkkeuufyyg|}hjk  "#( .",5@A$*06>FLRX`flrx~ &,28>FNTZ`flrx~{{{{{{{{{{{{{{{{{{orr{r{{{{{{{{{{{{{{A{{{{{{{{{{{{{{ {{{{{{{{{{{{{{>D >DJPV\bhntzX(l>tV(t>\X(RDtR<D$(,28<=DHLRX\]HYayz{*7TS&!0# 5PKr9KD &&K9a}au9aauaau/&DaDDkkDDDDkDD)ak}/DDa9}D}&&9}k}k}&D aDY}aaauNaaau}}k}ka aakkAk&k}}DHVaD)kkDN9a}au9aau/9a}au9aau/9a}au9aau/&kD&9a}au9aau/9a}a9aa/D?}DVD aDKr9KD &&Kk}k&/<&R$$%%&&''))**++-- .. // 22 33 445566778899::;;<<==HHIINNQQRRUUYYZZ[[ \\!mm"}}#$%&%'( )*+!!,,-((. /  0  ""&&100::?? 2 3  4 $$%%&&''))** ++-- ./22 3344 5566 778899::;;<<==DDFFGGHHIIJKLLOOPPQQRRTTUUVV WW!XX"YY#ZZ$[[%\\&mm'}}()* ++,,-../"/&&010101234352678888393:;;  3<3<=<;    !! "" ## $$>%%5&&''!((?++@--@//@0011"33@55@66A77B88C99D::??4EFEF G43H4IJ ~ ~A  K L B A B C D M N  Oa$%&')*+-./23456789:;<=HINQRUYZ[\m}  "&0:? `$XRjRVX\^b dh JDFLTzarabarmnbraicanschercyrlgeorgrek$hani4hebr@kanaRlao ^latnjmathnko ogamrunrtfng(thai4 KUR SND (URD (   MKD SRB F CAT ZESP ZGAL ZISM bKSM bLSM bMOL vNSM bROM vSKS bSSM b     RQDaaltaaltaaltcaseccmpccmpccmpccmpdligdligdligfinafinahlig hliginitinitliga$liga,locl2locl8medi>mediDrligJrligTsalt\saltbsalth     (RZbjr $,4<DLT\dlt|R `  DLf      >    d F z     \ HXPTXvHPX`hp EFGcX,,,H!!  !! &   B9&&99 D9LM *_ + j$=EEGGIIKKLMNOWW      ""$$&&((**,,..0022446688:;==??AAHHRRTTVVyz  **__ + +   &!!!&   $$4F""$$4F##$$4F$$$$4F%%$$4F&&(0RU'.6VVXZ'.6[\^_'.6`bdd'(0eh' 0DF Bt|~39?BEH K" &tl$  6(!$B',*4-00n369<8:?B>NHFJLTqNvPhjs#%BRR5;ADGJM 8 * #&D).,6/22p58;>=<AD@PVsP TTVVX\ahjprs)OBRQ4:@CFI L  7 )"%C(-+5.11o47:=<;@C?OUrO TTVVX\ahjprs)O2  zz yvvyz~&8Jlzz }z }z xwut xwtuwxz} > $~|~|6 "(IOILOLIIRl$*06<x{vztyrxpwovmuktS~Q}P| &,y{wzuysxqwltR}T}Uiqs3'B 8  WVWA(:FPZfr ,"  + *" $; V 0 (/ F X R")567DF  hgiefkj$:@GMU[hgiefkj$:@GMU[kuR,-DO *"&kuR,-DO\ 9 %#&$)*"+',(  y!ST|}z{ LM *_ + jjjjj P< ```h`UvZZZZZZZZrZZ8<(:0 &2>JVbfjnr~&2>JVbfjnr~PpN KI P KJ P KK P@ L  M  N  O  P  Q  R  S  T  KKU P LKV P MKW P NKX P oY pZ q[ r\ s] t^ u_ v` wa xb yc zd {e |f }g ~h i j k Dl E0F\r Q  R  S  /W  1X  [T  ]U  _V  ( u ((  (  ( u ((  (  ( u ((  ( q ( f (( ~ ( q ( r ((  (( ((  ( _(_( ( r ((  (( ((  (  ( ( ( o (( ( l (  ( q ( ~ ( q ( u (  ( f ( ~ ( (B((B((q(Vq(Vq(Vq(V >>@@^`   K N o Bq !    / 1 [ ] _33f n $`) PfEd@ m`, , ~OSXZbw%V_  :UWZpt?5JR>PjGv#.[jx{}EMWY[]} d q ! !I!K!N!!###!#(#,#u#z#}#######$#$i&&&&'' '''K'M'R'V'^''''''()) )A))))***/*k***++$+T,w,-%-e-o...%..MGMQWn+AKSWg&A6<>ADO#t QWZ\pz1Ya  !@WZ`ty? 7LT@RtFn&0]w{} HPY[]_ j t !! !K!N!P!!###$#+#s#z#}#######$"$`%&&&''' ')'M'O'V'X'a'''''')) )@))))** */*j*}**+++S,`,y--0-o..."..MЦDLPTb"0FNVd(8>@CFR pva_WRA@?72/.)(&! ,)'`^hgedcWUTM84953*n~e`\VT sofT |{@:80ğmlllllyl^lXlVkkkkkkkkkkkkkQ$Q#konnmiWWG < ~bOQSWXZZ\bpwz#$%81VY_a%'BG  I  KLMN!:O@UiWWZZ`ptty??"#%&()*.589:<ILQRXbd 57JLRTo>@PRjt!.>?FG@nvBKh#}&.0[]jwx{{}}   E HM <PW BYY J[[ K]] L_} M l      d j q H t P k x !! ! !I !K!K !N!N !P! !! !# ## ##! #$#( #+#, #s#u #z#z #}#} ## ## ## ## ## ## ## $"$# $`$i %& &&u&&&&'''' ' ''')'K'M'M'O'R'V'V'X'^'a'''''5''C''E''F'(L))\) ) ^)@)A`))b))d))l))m**o* *r*/*/*j*k*}*****++++$+S+T,`,w,y,--%-0-e!-o-oW..X..Y.".%Z....^MM_DGLMPQTWbn"+0AFK NS&VW,dg.26<>IQk&o(A68<>>@ACDFOR=AKMSW #gptkvp #V 89w;>y@D}FFJPRkՠ!" $$ '')24799;;abdd!gj"lr&tw-y|1~~506-.1155#%+-@ CC    !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`a rdei xpk vj s gw U l|>cn T m} b : '   y  qz5fqu-J3T99NR7s`s3VV9s3D{o{RoHT3fs +b-{T#\q#H99`#fy```{w``b{{Rffw;{J/}oo5jo{-{T7fD)fs, %Id@QX Y!-,%Id@QX Y!-,  P y PXY%%# P y PXY%-,KPX EDY!-,%E`D-,KSX%%EDY!!-,ED-,%%I%%I` ch #:e:-ff@ /10!%!!fsr)5 5@ K TX8Y<2991/0 P ]%3#3#5qeB@KTKT[X8Y1<20@0 @ P ` p ]#!#o$++`@1      91/<<<<<<<2220@   ]!! !3!!!!#!#!5!!5!T%Dh$ig8R>hggh`TifaabbNm!(/@U" '&( /)/))/B" ) *!#*- ) " & 0K TX8YK TKT[KT[X@8Y<<<1/299990KSX99Y"#.'5.546753.'>54&dijfod]SS\dtzq{---@A$*.U# jXV`OnZXhq) #'3@6$%&%&'$'B .$ &($4'!%   ! + 1 4K TK T[K T[KT[KT[K T[X18Y9912<0KSXY""32654&'2#"&546"32654&%3#2#"&546WccWUccUVcbWWcd1Zܻۻa ۻۼ 0@      !         B  (('+'$ .  .'.'!!199999991/9990KSX99999999Y"2]@ " ) **&:4D ^YZ UZZY0g{ "-  ' (   2'') #**(/2; 49?2J LKFO2VZ Y UY\_2j i`2uy z 2229]]3267 >73#'#"5467.54632.#"[UԠ_I{;B h]hΆ02޸SUWDi;#QX?@Yr~YW׀c?}<$$/1oX3go7@ KTKT[X8Y10@ @P`p]#o+{ 7@  KTX 8YKTX @8Y29910#&547{>;o @ <99103#654<:=JN@,       <2<2991<22990 %#'-73%g:r:g:PrPbybcy #@   <<1/<<0!!#!5!-Ө-Ӫ--@ 1073#ӤR@d10!!d1/073#B-@B/9910KSXY"3#m #@  10"32'2#"  P3343ssyzZ @@B  KTX@8Y1/20KSXY"]7!5%3!!JeJsHHժJ@'B   KTKT[KT[X8Y91/20KSX9Y"@2UVVzzvtvust]]%!!567>54&#"5>32Ls3aM_xzXE[w:mIwBC12\ps(p@.    #)&  )KTKT[X 8Y99190@ daa d!]!"&'532654&+532654&#"5>32?^jTmǹSrsY %Đ%%12wps{$& Ѳ|d @   B    K TK T[X 8Y<291/<290KSXY"@* *HYiw+&+6NO O Vfuz ]] !33##!55^%3`d^@#    KTKT[X8YKTX@8Y190!!>32!"&'532654&#",X,$^hZkʭQTժ 10$& $X@$  "% " !%190@]]"32654&.#">32# !2 LL;kPL;y$&W]ybhc@B991/0KSXY"KTX@878Y@X9Hg]]!#!3V+ #/C@% '-'0 $*$ !0991990"32654&%.54$32#"$54632654&#"HŚV г "Əُattt$X@# %!"" %190@]]7532#"543 !"&2654&#"LK:lL>$& V\s[#@<21/073#3### %@  <2103#3#ӤR#٬@^M@*B$#29190KSXY" 5Ѧ`@ #<210!!!!^O@+B$#<9190KSXY"55//m$e@+$     &%K TX8Y99991/9990y z z ]%3##546?>54&#"5>32ſ8ZZ93lOa^gHZX/'eVY5^1YnFC98ŸLVV/5<4q L@2  L4307$7CM34( (+(I+*(I,=M<9912990K TK T[KT[KT[KT[XMMM@878Y@ NN/N?N]32654&#"#"&5463253>54&'&$#"3267#"$'&5476$32|{zy!orqp ˘s'6@   0210].# !267# !2'ffjzSb_^^_HHghG.@   2 99991/0`]3 !%! )5BhPa/w.,~ .@   21/0 ]!!!!!!9>ժF# )@ 21/0 ]!!!!#ZpPժH7s9@ 43 1990%!5!# !2.# !26uu^opkSUmnHF_`%; ,@ 8  221/<20P ]3!3#!#"d+9.KTX@8Y1/0@ 0@P`]3#+f B@  9 KTX@8Y991990@ 0 @ P ` ]3+53265M?nj @(B  291/<290KSXY"]@ ((764GFCUgvw    (+*66650 A@E@@@ b`hgwp  ,]q]q3! !#3wH1j%@ :1/0@ 0P]3!!_ժ @4  B    >  91/<290KSXY"p]@V   && & 45 i|{y   #,'( 4<VY ej vy ]]! !###-}-+3 y@B6 991/<2990KSXY" ]@068HGif FIWXeiy ]]!3!#j+s #@  310"32' ! ':xyLHH[[bb:@   ? 291/0@ ?_]32654&#%!2+#8/ϒs R@*  B     39991990KSX9Y""32#'# ! '? !#y;:xLHHab[T@5  B    ?  299991/<9990KSX9Y"@]@Bz%%%&'&&& 66FFhuuw]]#.+#! 32654&#A{>ٿJx~hb؍O'~@<    B %( "-"(9999190KSX99Y")])/)O)].#"!"&'532654&/.54$32Hs_wzj{r{i76vce+ٶ0/EF~n|-&J@@@1/20K TX@878Y@  @ p ]!!#!ժ+)@@   8AKTX8Y1299990]332653! ˮ®u\*$h@'B91/290KSXY"P]@b*GGZ} *&&))% 833<<7HEEIIGYVfiizvvyyu)]]!3 3J+D {@I      B     91/<2290KSXY"]@  ($ >>4 0 LMB @ Yjkg ` {|      !   # $ %  <:5306 9 ? 0FFJ@E@BBB@@ D M @@XVY Pfgab```d d d wv{xwtyywpx   []]3 3 3# #D:9:9+=; f@  1 ]@ /<20KBPX@   @    Y3 3 # #su \Y+3{@(B@@ 91/290KSXY" ]@<5000F@@@QQQe &)78@ ghxp ]]3 3#f9\ @BB K TK T[X8Y991/0KSXY"@@ )&8HGH    / 59? GJO UYfio wx ]]!!!5!sP=g՚oX;@CK TX@8YKTKT[X8Y210!#3!XB-@B/9910KSXY"#mo0@CKTKT[X@8Y<10!53#5oXޏ@ 91290 # #HHu-10!5f1@ D10K TKT[X@878Y #ofv{-{ %@'   #   E&22991/9990@n0000 0!0"?'@@@@ @!@"PPPP P!P"P'p' !"'''000 0!@@@ @!PPP P!``` `!ppp p! !]]"326=7#5#"&5463!54&#"5>32߬o?`TeZ3f{bsٴ)Lfa..'' 8@  G F221/0`]4&#"326>32#"&'#3姒:{{:/Rdaadq{?@  HE210@ ].#"3267#"!2NPƳPNM]-U5++++$$>:#qZ8@G E221/0`]3#5#"3232654&#":||ǧ^daDDaq{p@$   KE9190@)?p?????,// , ooooo ]q]!3267# 32.#" ͷjbck)^Z44*,8 Cė/Y@     LK TX @8YKTX 8Y<<991/22990@P]#"!!##535463cM/ѹPhc/яNqVZ{ (J@#  &#' & G E)221/990`***]4&#"326!"&'5326=#"3253aQQR9||9=,*[cb::bcd4@  N  F21/<90`]#4&#"#3>32d||Bu\edy+@F<21/0@  @ P ` p ]3#3#`Vy D@   O  F<2991990@ @P`p]3+532653#F1iL`a( @)B F 291/<90KSXY" ]@_ ')+Vfgsw    ('(++@ h` ]q]33 ##%kǹi#y"F1/0@ @P`p]3#{"Z@&   PPF#291/<<<290@0$P$p$$$$$$$ ]>32#4&#"#4&#"#3>32)Erurw?yz|v\`gb|d{6@  N  F21/<90`]#4&#"#3>32d||Bu\`edqu{ J@  QE10@#?{{   {  {]"32654&'2#"s98V{>@ GF2210@ `]%#3>32#"&4&#"326s:{{8 daaqVZ{ >@   GE2210@ `]32654&#"#"3253#/s:||:/daDDadJ{0@    F21/90P].#"#3>32JI,:.˾`fco{'@<  S  SB %( R"E(9999190KSX99Y"']@m   . , , , ; ; ; ; $( ( *//*(() )!$'      '/)?)_))))))]]q.#"#"&'532654&/.54632NZb?ĥZlfae@f?((TT@I!*##55YQKP%$78@  F<<2991/<2990]!!;#"&5#53w{KsբN`>X{;@    NF921/290o]332653#5#"&||Cua{fc=`@'BK TX@8YKTKT[X8Y91/290KSXY"@Hj{  &&)) 55::0FFIIFH@VVYYPffiigh`ut{{uz>]]3 3#=^^\`TV5` @IU U U U   B     K TKT[KT[KT[K T[X@8YK TK T[KT[X8Y91/<2290KSXY"@" 5 IIF @ [[U P nnf yy          %%#'!%""%' $ ! # 9669 0FHF@B@@@D D D @@VVVPQRRPS T U cdejejjjn a g ouuy}x}zzxy  { v } @/   y]]333# #V`jjj;y` C@F      B   K TKT[KT[KT[X@8YKTX8Y91/<290KSXY"@   & =1 UWX f vzvt        )&% * :9746 9 0 IFE J @ YVYYWVYVV Y P o x  /]] # # 3 dkr))`HJq=V`@C        B     K TKT[X @8YKTX 8Y9129990KSX2Y"@     # 5 I O N Z Z j        '$$  )( % $ $ ' ** 755008 6 6 8 990A@@@@@@@@B E G II@TQQUPPVUVW W U U YYPffh ii`{xx   e]]+5326?3 3N|lLT3!;^^hzHTNlX` @B K TK T[X8YKTX@8Y2991/0KSXY"@B&GI  + 690 @@E@@CWY_ ``f``b ]]!!!5!qjL}e`ۓ%$w@4 %   !  % $  C %K TX@8Y<<29999999199999990&]#"&=4&+5326=46;#"3>l==k>DV[noZVtsݓXX10#$@6%   #%#C %K TX8YKTX@8Y<2<9999999199999990&]326=467.=4&+532;#"+FUZooZUF?l>>l?VWstݔ1#@  1990#"'&'&'&#"5>32326ian ^Xbian ^V1OD;>MSOE<>L5` e@  <29910K TX @ 878YKTKT[KT[X  @878Y P ]#53#3b+e#!Q@+     "  "<<<221<9990%.'>7#&73JDFHAMf fIX⸹)**'# 32!b`@!    <<1/2<2990K TX@878Y66].#"!!!!53#535632NL=ty-=))׏/я^R#/@I -'! - -'!0 *$0* $ $(st*(s099999999919999999907'#"&''7.5467'7>324&#"326{r%$&(r;t=:x=q%%&&s7t@?s9q(&%%s>v:@t8s'%$|pprR@F  B     fe f e<2299991/2<2<290KSXY"K TX@878Y@(' ' ')((79  ]]!#!5!5'!5!3 3!!!c`Tþ{yT9{3{JD{3@ <210##  \= >@54&.#"#"&'532654/.5467.54632{?>?>S8alӃ\]>9̭IXW:fqր][;;ȦI.Z.L-[.K''PGZsweZ54m@''TLf{xf[1,pEF)@dd1<20K TK T[X@878YK TK T[KT[KT[X@878YKTKT[X@878Y@````pppp]3#%3#^y/IC@&=>:A$104G$ 7aD=0^* D^ J21/02#"$'&5476$"3267>54&'..#"3267#"&54632mmllmmmmllmm^^``^^⃄^]]^\^BB@zBCFInmmmmnnmmmmng^^^傁^^__^]⃅]^^! "s;)_@3(%%  * "(kl"k *22999199990!!#5#"&546;54&#"5>32"326=P,]uu>DIE~bRhP{@p?Dq[[""CO@Mr%# @I    B   o o n<2991<2990KSXY" 5 5%-+#-+#RR^@ 10!#!^d10!!d/8L`@6EBC?2H09JC 9 $HE301B54&'.'2#"$'&5476$#32654&'2#'.+#^^``^^⃄^]]^\^ㄘmmllmmmmllmm}{{nWXfi`C.;I6Bf^^^傁^^__^]⃅]^^gnmmmmnnmmmmnb>KL?gwyVpMI`3Db+/10K TKT[X@878Y!!Vu=  @  Z[Z10"32654&'2#"&546PnnPPnoO@v+..ooPOmmOOp1.-rB .@     <2<21/<<0!!#!5!!!-Ө-}}^J@$}}B ~9190KSX2Y"!!56754&#"5>32 "?XhU4zHM98rn81^BQ##{l0b(H@'    #)~&~ )999190#"&'532654&+532654&#"5>32 \e9}F4wCmxolV^^ad_(fQI7Z`mR|yOFJLl?<:=svcE`sRf1@ D10K TKT[X@878Y3#fV` M@%  !   NF!2912<990"`""]3326533267#"&'#"&'#% )I#ER2bf*V H<9 NPOONN;9 %@]] 91290!###.54$yfNݸHF103#F#u@  ' 1/90!#"&'532654&'T76xv.W+"J/;<+->i0Y[ 0.W= ,@   |]|| 12035733! c)t'+n`d.@  klk 9910!!2#"&546"32654&PXγгi~hi}|P{ݿܾsH# @I  B   o op<<991<2990KSXY"5 %5 +-+-#^R^  ^R^  &{' Pd '5?&{'td '5b&u' Pd '5n` $@/  !# #%" " "!& %999919990KTKT[KT[X%%%@878Y@ ttttv]33267#"&546?>7>5#537ZZ:3mN`^gIYX0&ϜeWX5^1YnFC98ŸLVV/5<6hk&$%uhk&$#uhm&$&u  +@ ]1h^&$$u #+@ @O# /#]1hN&$"u  +@ 0?  ]1hm !@T   !!  ! !!!B     !  VV!"2299999991/<9990KSXY" #]@  s P#f iu {yyv v!# ]]4&#"326!.54632#!#TY?@WX??Y!X=>sr?<҈_Z?YWA?XXN)sIsrFv)H@9  B     <291/<0KSXY"]@gww  ]!!!!!!#!59=qժF՞su'&&z-k&(%uk&(#um&(&u@@ ]1N&("u @@ @]1;k&,%/uk&,#/u`m&,&/u +1XN&,"/u +1  g@    2  y<291/220@(   ]]! )#53!!3 !iP`P5~.,3^&1$u"+@ 0?""]1sk&2%'usk&2#'usm&2&'u+@]1s^&2$'u!0 +@ 0!?0 !/0!0]1sN&2"'u +@ @O]1? @M    B   <291<290KSXY"  ' 7 7w55v8vL57y5yy5f +@< +,  )&  *&& &,+,* # )#3,99999999199999990@*WZWU!je!{vu! FYVjddj(|svz( ]] 324&'.#"&5!27!"&''3>_'y=_''NOy;WfNPƀ[gX@CHp@CpDfbMKYg[KKX)k&8%u)k&8#u)m&8&u +@ / ]1)N&8"u +@P_@O /]1k&<#su =@   ? 2291/0@ ?_]332+#32654&#'ђ/@0-'!  **.  !' $'$-F099991/990@@'(     ! "&  : :!MM I!I"jj  ]]4632#"&'532654&/.5467.#"#:A9`@IPAtx;e\`Wqqs`/Q*%jd_[?T>7;[gp{-f&DCR @?&/&&]1{-f&DvR @?&/&&]1{-f&DR (,+1{-7&DR.< +@ ./<.<]1{-&DjR -( +@(o(P-_(@-O(0-?(-( ]1{-&DR%@&,,& 2882 ++1@ ?5?/5/]0{o{3>@C'-%= 4%:.-*1 %?47&%7& =&-7"E?<9999912<<29990@0+0,0-0.0/00@+@,@-@.@/@0P+P,P-P.P/P0+0@@@@@@@@@??? ??0,0-0.0/@,@-@.@/P,P-P.P/ooo oo`,`-`.`/p,p-p.p/,-./]q].#">32!3267#"&'#"&5463!54&#"5>32"326=DJԄ ̷hddjMI؏`TeZ߬o0Z^Z55*,ywxx..''`f{bsٴ)qu{&Fzqf&HCqf&Hvqf&H"+1q&Hj@@ ]1f'Cof'v\f& +1F&j +1qu('@^%{&%#${##{#({'(#&'('%$%(('"#" ! B('&%"! ## #)&' ! (%#" QE)999999919990KSXY"?*]@v%+("/#/$)%-&-'*(6%F%X X!` `!f"u u!u"%#%$&&&''(6$6%F$E%Z Z!b b!z{     {zzv v!x"**']].#"32654&#"432''%'3%F2X)6 ~r4*!M!ü޼z&77kc\̑oabd7&Qquf&RCsquf&Rvsquf&Rs+1qu7&Rs .+@ /. .]1qu&Rjs +@ @O0?]1o )@ r <<103#3#!!oAH +@<+,&  )&  *&& &,+,* # #Q)E,22999999199999990@p(?-YVUV jf!{    { z{ {!"#$%{&%--&YVUZ(ifej(ztvz($$]] 32654&'.#".5327#"&'')gA\*g>}66]C_56`?`!*(Ou))Hn.Mw834OMx43NXf&XC{Xf&Xv{Xf&X{ +1X&Xj{ +@ @O0?]1=Vf&\v^V>@ GF2210@ `]%#3>32#"&4&#"326s:{{8daa=V&\j^+@ 0? /]1h1'q;$ +@@O]1{-&qJD+@o]1h'J$+1@oo]0{-&OD"+1u&${u{&Ds'k&&#-uqf&Fvs'm'&Lu& <=/1qf&Fs'P'*Lu&q'Fs'm&&'-u@]1qf&Fm''u'q&G! @_?]1 q$J@$ "    GE%<<1/<20`&&&]!5!533##5#"3232654&#"F:||ǧN}}daDDa3&(q=q'qH@p]1m')u(@@]1qH'H@p]1P'*u(q'Hu&(qu{&Hxg&('o@@ ]1qa&H!+@!]1sm'&\u* <=/1qVZf&hJ  <=/1sm&*)uqVZH&JsP'*\u*@?]0qVZ'jJs'^*qVZ4' J;m'&u+ +@ / ]1dm'&uK*+1KQX88Y@ @@]:@    8 22221/<2222203!533##!##53!5qʨ"ʨ9Qx>@!   N  2221/<2290#4&#"##5353!!>32||}}`Bu\zzedx^'$.u, +1g7'+1Y1'q.;,+1H'q+1gm').u,+1VH'+1u%'d,u 'JLP&,*/u<<1??]0y{,@ F91/0@4D@P`p]3#\`{f'-\,@1V'M8L@F1f_m'&.u-+1V\f'+1j' .' N` @(B F 291/<290KSXY" ]@_ ')+Vfgsw    ('(++@ h` ]q]33 ##%kǹ`!jl'#nv/Jl'#ZvO<1KQX@8Y@O]0j' /' O@@]1j'!/'!9O @]1j'y1w/'ysOK QKSKQZ[X@8Y1u ?@   : y<<991/900P]3%!!'79Pw^Mo;jnH ^@  z z <<991/90KTX @ 878Y@ @ P ` sz p ]37#'7Ǹ}Lɸ{JZjXj3l'#v1@O]1dm&vBQ @?O]13' 1d{' Q3_&1'g +@ /  ]1df&Q +@]1'QU~V;@  AKTX8Y21@ /0!"#367632+53265PͳNijQRW1fOCCoa`ZVd{;@  NF 21/90`!!]+5327654&#"#367632dRQi&&||BYZuccH``01`e22wxs1'q';2 +@]1qu&qsR+1sm')'u2+@]1quH&sR#+1sk'+'u2quf'Rs ;@   299991/220!!!!! !# !39OAg@AժF|pm|q{'3@1 . ("%4"1 K1 Q+E499912<2290@%?5_5p55555????? ooooo ]q].#"!3267#"&'#"32>32%"32654& H ̷jbdjQGьBN5Z44*,nmnm98olkp݇Tl'#v5m&vBUT' 5J{' UT_&5'}g@_]0Zf&U +@]1l'#v6om&vBVm'&u6  ))Ic:1of&%V  ))Ic:1u&6zou{&Vzm&6'u + ""Ic:1of&V' + ""Ic:1u&zP77u&zW_&7'sg +1@_]07&W!7p@]1F@   @ @ <<1/2<20@@p ]!!!!#!5!!  ժA@7C@  F<<2<<2991/<<<20]!!!!;#"'&=#535#53w{{%&sQQ''PO>)^'$u8 '+@ ]1X7'X&+1)1'q;8 +@ / ]1X'qX+1)m')u8+@]1XH'X+1)o&8iX&X| @@@!]1)k'+u8^f'Xu)&8u{&X'Dt'&|:+1V5m'EZ+1t'&r|< +1=Vm&^\+1N&<"su +1\l'#v=Xm&vB]\P'*u=X']@ O _ ]1\m&='uXf&] +@ ]1/#@  L<1/0!##53546;#"c'&яN()g ,D@% ")%,$'".EG* ,(%#'F-<2221/<204'&#"327667632#"'&'##5353!!STTSSTTS:YX{{XY:E/tssttsstRd0110d}}P)C@#   . *29991/90"]!2654&#!2654&#%!2#!"#546D+ |v݇f>orqp ˘0_i1F&8@# (EGF'221/067632#"'&'#!%4'&#"3276s:YX{{XY:NkrSTTSSTTSd0110dtssttsst 3@  . /21@  / 9/04'&#!!276!2#!#ONDNO|N8DCDCD>@  G /221@  /ij9/0>32#"&'##34&#"326s:{{:"QrdaadDs'0@  0 <10>3 !"&'53 !"shSzjffbGGaaHH_^9'(9^_sZd$D@"! %  %  0%210&&].# !267# !2676;#"'ffjzS` SfM?nb_^^_HHgh$bzq"N@$ ## HE#210@ $$$$$].#"3267#"!2546;#"NPƳPNM]-GFE0iL~++++$$>: a .@   2 99991/0`]3 !%! )"#5465BhPav/w.,~0_i1F.@  .21@   /0)!"!!"$54$3!!@DNN|#+qZ?@G E221/0` ]5!#5#"3232654&#" M:||:ndaDDadqVtc'T@ )E Q E(]99@   (99@%S 910%!"'53254%&'&326&#">kGxfu'~@3cnBOFFu\0%p9 *E +@    21@ /0!5!!5!!5E>9+uD@& 39190!!"56$3 ! 7327upo^   2`_FHg[{(@@$ )) #)* &)190.54$32.#";#"3267# $546؃ YsrSǾmTj^У%!| &${spw21%%ݐf#A@  2991990 ]!!!!+53265ZpPM?nժHVe@#   LK TX@8YKTX8Y<<9912299990@P]#"!!+53265#535463cM/ѮcMPhc뻫Ph*Nsd&I@43! F'1@'$$'990%!5!# !246;#".# !26uu^[DM?npkSUmnꪖ_`%Rv%@ 'P $&]ĵ 91@ %$&222990@ #%$$<<$#$%#@$"! #9927654'&'3#"'&5476736,3,,3,6hC.KddK.Ch B9Iy\\yI9B z^ȮwBAWWABw1G*O@, *&NF+291@ '&&  #/<<9990%27654'&'5+"&54&#"#3>323LTWJ>ymoF||BuLibep_!edg .@  KTX@8Y991/9903;#"&n?M-– R E@   >f3@)B 6  999991/299990KSXY" ]@068HGif FIWXeiy]]!3!+53265jG?n+Vd{Ls 1@ 3221@   0! ! "!&32sy:;x Vb[[z=g&24v'X Rs3@ !  <1/0!4&#! !2!2"327&nzy;pa'Xܯ–bb-LgFqVY{!:@ """# E"9104'&##"3232"327&&&idRصRQ@TVt1098``:6:@   ? 291/0@ ?_]32654&#%!2+#"#5468ʄv/ϒ0_i1FV$O@$#% %G  F%22991990@ `&&&&]%#46;#">32#"&4&#"326siL:{{8(adaaTV@  ?  2299991@  /9990@ @u|]#.+#33 326&#A{>ٿJx~hb؍Oђ r!d@ -" "99991@B!  "90KSX@ Y6 327# '&546?6764'& {璑z<;YZL-|숋_ppٶ+23@@md{'@  !! RE(99991@ '$$(90@S !S BKSX99Y"]@/)?)_))))))]@% '$&((*//*( ( ))$]@.,,,;;;; q>323267#"&546?>54&#"Lf@eaflZ?bZN?$%PKQY55##*!I@TT((8V6@   O 221@   <20;#"&5# 54!23%&'&#"3wMc/R5!n|wj=hP`@o,0A37V?@ F<<291@/<2990!!;+53276="&5#53w{KsF0j&&էN01`>X@ @  991/2990K TX@878Y@@p ]!!##"#546;^vժ+Zi1F7I@  F<<2291@  /<299990]!!;#"&5#53546;#"w{KsբcMcN`NQfT@ @@ 120K TX@878Y@@p ]!!;#"&!n?Nժ=–_&84i' XN:@!3   1@   <2220!! 47!5!3254'5!X ƱXw>*a"Lav-@   /<91@ 0%254'&'5!'&'&33cAnMagn"ʦmWDtz–d@  @ @99/1@  /9990@        BKSXY""#3 632#54&9%NZUUIG9\[ny6P=V{j@  K TKT[X @8YKTX 8Y9991@:        B    9990KSX2Y"@      '$$  )( % $ $ ' 755008 6 6 8 A@@@@@@@@B E G TQQUPPVUVW W U U ffh { F]@%     # 5 I O N Z Z j ]+5326?3 67632#54&#"N|lLT3!;^0XQ99) hzHTN43`rr:T*\@5    B  B K TK T[X 8Y9991/<20KSX<<<323#L:s_%'ST_ijxzX"Jh0@umHLIwKK!!C12\RI`1]5@ F1@  0 4&#!!!%$ $5& )sQ;-%,%hV)$yhL?`3@  F1@ 203 4&#!!!32!"'hi;-ԧc%,&cV)$yJX$!"'&'5327674'&+#5333!plnUQQLITNPc9:V>}ws}#(rAbLrV{@@  F221@ B 0KSXY#36763254'&#"s4QҸMNr98xܭz BR1pqWBAV&@ F10@ @P`p]3#V''V:@    <<2<<219/<2<203!!!!#!5!5!5!s____,Ԫ m'?' f'@'qf'@Gf$'-/V'Me/V'MvOf'-_1V'M>1V'MeQhm&$'u<1{-f&DZ +'+1`m&,'/u  Ic:1^f&  Ic:1sm&2''uquf&Rv <1)m&8'u<1Xf&Xv  Ic:1)3&U08X1'q{;)Z&8X6X"&XX)Z&8]0X"&X])`&8Y0X"&XYq{h3&$U{-1&qR;h3&$W{-&DWH4'q>{o'qs%T@!$"43 &<1@"#%&99ܰ KTX"@8Y<203## !2.# !2675#535!5yyuu^opkC XSUmnHF_`%'XqV{ 4X@"2% G,E5221@ #% ) 2/3 &)/99<20`666]4&#"3263#!"&'532767!5!6=#"3253:aQQRZ9||9=nXF]@,*_EG^[cb::bcsm&*'Ju!<@!T!$!]1qVZc&JJjm''u.m&N'u* +1KQX88Y@ @@]su'42quu{'Rsu1'q';quu&qsm''uyXL/f&TVdf'%  Ic:1 '=' ']'q']Gsl'#v*qVZc&Jv-5@8221@ /203!327653! '&5!#>=B>d`gd"dPNOKZ߀xxv 9V@@  221@ B 0KSXY%#3676324'&#"8WST=<HW5xz7 GF3k'%u1dd&QChs&#\}{s&#}Hl'#\v{oc&vefl'#vHc&vhp&$,z{-d'Dh6&$(>{-H'eDp&(,zqc'H6&((>qH'Hsp&,,Yzc'fw6&,(>>UH'$sp&2,Azqud'Rs6&2(>quH'RTp&5,yzJc'%UT6&5(>^H'-U)p&8,zXd'X)6&8(>XH'X'v6o{',V'S77'WRs. 56$>54&#"57>54.#"5632?4o1\}p_s54&#"57>54.#"5$32Fp>!BlJc(v];?"AW?-1CA#E ptgDZX%KlaF='.`[b[3XpVU 2#PQ̝qpD(4%3254'"632!"'#67&5#"'&76323 76'& %44nI5"C0:XY|ˀ|YX:ST$TTTTT- H:E<$d0110d^jtssttssq% ;W@$3=E (B!8;7B/E<̲ ;]91@$3< ;<,<990" 7654&327654'&'52 '&54767&'&5476!˸jkkjpkk_;̨_`Lm䖋_``aCUtMMMMMN'|OEH-AA+Mdha "ccttttُcc"FYXSJqq 4C@6E B42()+&BE5221@4)".559920" 7654'& '&5467&'&5473327654'qSRRS SSSR:4HRQ;4?+IHIJ,MMMMMNMMJ@b@Y "ccttttُ"#VKYIAAAAAtw>\V@ B  K TK T[X 8Y991@ B  /0KSX@ Y@@ )&8HGH  /59?GJOUYfiowx]]+53276=!5!5!!Hri&&gPP%01oXV`@   K TK T[X 8YKTX @8YĴ@`]99Դ@`]1@ B  /0KSX@ Y@2&GI + 690EIWY_fh]]+53276=!5!5!!۞Hri&&5ejLP%01%hP'*u${-'JDu&(zqu{&Hz{s3&2Ubqu1&qs;s3&2\iqu&R\sP'*'u2qu'sRs3&2Wjqu1&qs;1'qr;<=V&q^\p\%3254'"632!"'#67&73%44nI5"C1- H:EVy` 8@   OF 991990@  @ P ` p ]3+53265F1iL`aq #/A@1E%G +G!E0<<<<1@( . /22220 6& 23632#"'#5#"'&76'&  7/ST$Trrrrˀ]STTSST$Tjtss ^ŨŢtsstjtssqV{ %/D@1E$G+G'E0<<<<1@ *.! 02<220'&  7"'##"'&763253632 6& STTSST$TrrˀrrST$TdtsstjtssRŢŪjtss|3 #!#'#7'7 3!Jafp|҈2F;R/o]jY'FF8O ",'&76!27&'!2767# '#&# rfuSv=:efc.1 tsfjwv9tFXh$xYv+!f //_H$$\/ح ]"+'7&576!27&'32767#"'&#"i`UUQ.-Y_vcPNONMRS]7GGcc^N lOU ^q+$Vqrg j ;@   : <<1/<20@ 0P]33#!!#53ʿ_w1##'!5!7 !4" gZ8f,i> XRBY bo{=4'&/&'&54632.#"3#"'&/&'&'&'53276 23@LLfLNZDE11?PS{W*L'TrGY$alfccaFF'K((%$JK((**T@%$!,KL[@~$=&[#5-,X3`!;#"'&/&+=!qjN\1*LlTrGY=Z^e`1~$=&[? %P6@ 9991@  /0##32654&+"56;2'񍚚EOZ*,FP{7@   991@  /032654'&#"5632##/dLUIVVN}AH+Fnt  (\@ #  . &%)<229991@(% #/99/<20*]!!!2654&#!2654&#%!2#!#53[D+ |迿ɐʇf>orqp ˘p _@ 8AKTX8Y<2<21@   29/<<2299990]3!33#! 5#53!3265˥ߦ®j*$}h1B33#!!!!#7#!#!AX .AA<VF㪾FqB&-1&'&'!3267#"'#&'&3273&#"#So+Jajbck{cPm!)81G\9/Zo Z 6Z44*,!  C "2JcfRY@    9 KTX@8Y<2991<2990@ 0@P`]#+53265#5333RM?nʿwHVS@$   OF<<22991<2990@ @P`p]33#+53265#533#F1iL`(aؤsf$C@$  %" %  %2299199053;#"&5# !232#"nEMMT–\\xEEqV@{$H@"%"%G E%229910`&&&]#"&=#"3253;32654&#"@F:||:Li1戮VּdaDDada= T @  ?  !<299991@!  B  /<229990KSX9Y"@"]@Bz%%%&'&&& "66FFhuuw]]#.+##53! 32654&#A{>ٿJxʿ~hbw؍OJ{=@ F<<<1@  /<20P]###533>32.#":.I,h<ĤfcΡ3!733!#!53!ٗ ٗwјv9 V`+5326?!533!33!+N|lLT3!øLùmhzHT33`{ %@ '  F&22991@ & # &  9990@1??? ?!OOO O!___ _!ooo o! ! !]@%???? ?!?"OOOO O!O"____ _!_"]2654&#"3>32#!3267#"&߬o?`TeZ+f{bsٴ)Lfa..''qZ{8@G E221/0`]53#5#"3232654&#":||ǧdaDDa{ 8@  G F221/0`]4&#"326>32#"&'#3姒:||:/Rdaad` $C@  !G! F%22991/0`&&&]4&#"326>32#"&'#46;#"姒:{{:Z[/Rdaad~Ӝ}}{0@  EH <10>32!"&'532654&#"M]*ULNPƳPN3$$##++++qs{'/O@( ,,H"E02991@.*%00@ 11111].#"67632#"'#47&'&!23254#"NPc'>IjJ?_SPI 9/-U:Me5++rQ,3H=Y}/)9DhQ#3 :#:9KqV@$K@$%"%OG E%221990`]#"&=#"323;32654&#"@F:||:Li1戮VּdaDDad^ؙa=q$=@" %%  GE%2210`]546;#"#5#"3232654&#"iL:||ǧadaDDaq{"r@ KE#91@  #90@)?$p$$$$?????,//,ooooo ]q]47632!"&'532767!7&'&#"qkcbdcjfg ]\RS^,*4cdWWZZq{A@$  KE91905!.#"5>3 #"73267qN ͷjbck 9Z44*,#ė|{ 4w@6.('4 KE5<Ķ&  91@/.'""5 5@  &"90@ 4 &'<<<<<%6'6'32#"'&'&'&5>3 73;#"'&5Nf  R`\Lladbck $˸&&i+@WR֊>8E#Z`vg'#d4*,#)u10`Z|J|*|>i@@603273;#"'&5|PUTZGUU]UTNHtCDFEwGQPabLq_&&i+@WR@\l%88ZX83,-F@.. NBj10`ZȦFq|/;@ 1 &,E01@00)0#90"327654'&+5327654'&'2# 76`cchҗUTNHtCDFEhqr<V`K@   OF<<22991<2990@ @P`p]33#+53265#53F1iL`(aؤqV 0U@)  &#-* *-+& G E122991/990`222]4&#"326!"&'5326=#"32546;#"aQQR9||9iL=,*[cb::bcaqVZ` #C@ # GE$21/990`%%%]!"326!"&'5326=#"43!aQQR9|=ͻ,*[cb:*qO{8@4 E1990%#5!#"!2.#"326Ae{-h]_cƳO|$$>:77>>`Rd`#y@ %  $ĵ 91@  $222  990<<<<< 3#"&54767327654'&'bB_j&;;&j_BC(::(xܱSccS$-EIdccdIE-`d`#y@ %  $ĵ 91@  $222  990<<<<< 3#"&54767327654'&'b)rG,EE,Gr)C'88'bLx>>xLb-!@2FF2@!-VX`9@     NF21290`]332653##"&||Cua{VfcdC@!   N  F2991/<9990`]#4&#"#46;#">32d||iMBu\~aedVd!J@%  " NF"2991/9990`#]+53265#"#46;#"632diLiMHa=~a >@    F<<<2221/<20@ @P`p]33###533#¸`<Ĥn`Nt` '@   221@   /2205!#3!53t褤K#<@ % V V$<<1@#! !//2<903327673#"'#&'&#"#67632= &}33[ &}33[ %$RIJ %$RIJMT5@  <2<1@ /9/<2033##4'# 7632&#"3=5*7M\TK9V_ (@  F 1@   990;#"&5y=x1F|t(L6$@#&#" F%<̲#91@B""  " /9/ 990@$#@  **8;ILT[q ]@$$%$$5$7E$FT$\ ]@    ]2!"'&'5327654'&+5!#3!CicUQ^cdjTmcd\[je8+lh%12KKKJ3Lb&^@PP F'<91@  #''<<<290@0(P(p((((((( ]%#"&5332765332653#5#"'&Cb`ruSSrw=ZXyzVUy=<b`^zbze32>>Vb&a@PP F'<91@  #''<<<290@0(P(p((((((( ]%#"&5332765332653##"'&Cb`ruSSrw=ZXyzVUy=<b`^zbzZe32>>V{0c@PP)%'F1291@ %*!*-(&/<<290@02P2p2222222 ]>32+5327654&#"#4'&#"#3>32)E__RQi&&ru99wSS?yzUV|v{zH``01NM_``gb>>Vk{Q@N O F2991@ /9@   990`]#4&#"+532653>32k||F1iLBu\satedVJ{;@ N  F21@   /  90&54&#"#3>32;#"R||Bu&&i1F``edH10d` y@BNF 991/<2990KSXY" ]@068HGif FIWXeiy ]]!3!##`ylqu{ ,@  Q E2210"!.265!2#"qt蔔98q$`I@  E2ij 991@   /<<@ 9/0!!!!! '&76!#";:E*%xxxx%`ݛlklm>|$2@ &E E%1@ #%<202765 26= "&'"&H`k&InI&k`B"F:.aע ģ0[1[0T\l6puypVj`/@   /2991@  /90%!"/32653#r%832JI,:.˾ fcVJ{:@  F2190P].#";#"&53>32JI,Li:.˾atfc~{%@ 21@  /29903!5346;#"iLAat~{%@ 1@  /29903!534&+532ʴLiAa`@4  B      F299991/<9990KSX9Y"@]@Bz%%%&'&&& 66FFhuuw]]#.+#!232654&#0s2âJ{Qpwu t]:'`iVNM``E@  F299991@  /29990332673#!32654&#Q{Jî2s0jp|Ɓuw`':]t i`MNVoV{0@C  S('  S'('B1 '(!.1' ($R$+E19999190KSX99Y"0].#"#"/;#"&=32654&/.54632NZb?ĥdXLie@f?((TT@I!* ajYQKP%$V4@ O F<22991@  99046;#"+5326cMF1iK»Ph)aV O@ !O F!<<229921@! ! !99<20546;#"3#+53265#53#5cMF1iK`NPh(aؤi7V5e"O 1@ 04&+532;#"&McKi1F(hPaV2@   O 221@  /<20!3## 54!346;#"#"3276w5RcMów|n!o@`Ph3A07^3@   /<<2991@  /<2990]!5!4&+5323#{Ksբ>`N7V=@   F<<2991<2990]!!;#"&5#53w{Liൣa>`C@     NF2221/222220` ]3!33##5#"&=#5!326:CuȮ||h=$#^lfk`8@   91/20@ 3 3#f%.]`8XV`@"B  OK TK T[X8YKTX@8Y2991/0KSXY"@B&GI + 690@@E@@CWY_``f``b]]!!;#"&=!5!qjLLi/F7e`ۧa%X`!@  "KTK T[X8YKTX@8Y299<21@  /<0@ BKSXY"@:&GI #+ #690#@@ECWY_#``fb###]]!367632+#47!5!3254qjL"TA`:&>R~ie8FX`ۢG7W9W`/=3<;4%6]XL/` @ "!̲91@B!  !9/ 990@ @  **8;ILT[q ]@  %$ 5 7E FT \ ]@    ]2!"'&'5327654'&+5!5!`q|/=@1 %,%E01@0 0"0( 90";#"327654'&% !"$5467&'&5476EwEFDCtHNTUhcc`a|p<:!a>>`V.9@ F<<991@   /<203#33## 54!3#"32767Ku_+xG`͋BA0 L` ## 33R9L T#`@ F1/03!!`3qV $C@  #%% "GE%2210@ `&&&&]32654&#"#"32546;#"#/s:||:iM/daDDadaX$L@ & %<<ij#1@  $! /<2KPXY032765&'&#"56763 3###53T?V:9cPONNLQQUmlprLbAr+#}swԤX$M@ &"#E%<<ij "#1@ $!# ##/<2KPXY0535&'&5476!2&'&#";3##plnUQQLNONPc9:V>ws}#+rAbLrq &) 76'& %3!!!+5#"'&7632/ST$TTTTT iL:XY|ˀ|YXjtssttssH^Lۓd0110MqL4@#5#"'&76323!2!"'&'5327654'&+5 76'& Z:XY|ˀ|YX:jejbVQ^cdjTmcd\]:ST$TTTTT3d0110d^L$8*mh%12KKKJjtssttssq 3: 76'& %%!332!##47!#5#"'&763233254#/ST$TTTTTghL<):XY|ˀ|YX:FXjtssttss_ 3<;4d0110d^6[7@7!!3!27654&/.54632.#")"'&5#53w{%&s@FF^@fLNZb?ƣ|LQQ''-,4IM*$((TT@I!,e>PO`>7V&/!05476;#"+53276=#"'&5#53!3wxWQîc&'QRF1i&&QQ3%&sN[V((h)``01PO`>''7p-9D!6!2&'&#"63 #"'47!"'&5#533276'&#"&57!3w{UQQLNONPcccO+eKTIQQ;BS_r(ր%&sz#+qrfr v)2LOAPO`> 'KV ''/Vo5+5327654&#"#!##535476;#"!;67632oRQi&&||ӹWWc'&-BYZuccH``01/яNUV((hce22wxA'3!27654&/.54632.#")FF^@fLNZb?ƣ|LO-,4IM*$((TT@I!,e> @   F<2991@ B /0KSX@  Y@B &GI   + 09 @@@@@C EWY `````b f]]3!!!+iLLۓ6 333# #333# #6ttttU=63@    <2<21@  220!#!#!#!#6kkUXrXJ3@ NF 21@ 0%#"&54&+53232653#׃Li1FęaBþyVv!:@ #NF "21@" ""0%#"&54&+53232653;#"&'׃Li1FPh2FęaBþyfu0@ 32tNN^luu)qJy}wYYk\g88u:KSX@ 32tNN^lugrB0)qJy}wYYk\xkW6Vr88 #@<<1@03+5327653#zt43r,Bttx66XVru@ 1@ /0.#"#3>32.biuu$uT  qksa97H <1 /032653#5#"&'H.bitt$uT  qkJa97Hu' <1@  /<032653;#"&=#"&'H.bit0B,rg$uT  qkJ V6Xlx a97 !+33276?3327654'&+CFCDtk=%%(f{n!!"}K'))'K}N;[--s?5/.6 333# #6tt&+53276?331/.N]D0 {{bp"#WK/itftf&t  @ 10#5Rڬ@u1 ܴ? O ]ܶ ]<1ܲ]90526544u@XX@sPOOP{X@?X{POPPu1 @    ]<1 Բ]90"'&4763"3sPOOPs@XX@PPOP{X?@Xu+@ 91@   032765&'&#"567632#'y7$#?q22110335WDDFk[@*7K$@ ` XFh_@Cu-@ 91@   0#&'&547632&'&#"3kGDEW53301212q>$%6y[AmC@_hFX ` @$K7*@ 2% % g 25-5g'|?f=u912]90K TKT[X@878Y3# #fg|?fLu91<Բ]90K TKT[X@878Y@ 5:5:3]]33|g?f7@ u91290K TKT[X@878Y3#'#f?f7@ u91<90K TKT[X@878Y373x^@1@/0#^+b+qsRf3#ff #ofv^@1@/0%#^++Tq^#onvsR3#lo#E@ j,5!##–,dU 533##5#5Dud&u!5!&>ߖ)9H W@ VV1<0K TX@878YKTKT[KT[X@878Y332673#"&v aWV` v HKKJLDfN@ d10K TK T[X@878Y KTKT[X@878Y3#  @ V xV104&#"3267#"&54632X@AWWA@Xzssss?XW@AWX@sssLu @   '1/90!33267#"&546w-+76 >&Dzs5=X.. W]0iJ7c@$   VwVv99991<<99990K TK T[X@878Y'.#"#>3232673#"&9! &$}f[&@%9! &$}f[&@Z7IR!7IRfB@991<20K TKT[X@878Y3#3#߉fx%3;#"'&5&&i+@WRd10`ZȢf '#7'373\\]]\aa``u # 5473733254/MMz /1/03#zttu/2&'&#"#"'&'532654'&/&'&547632j1549W++](}24NM9>=D@?>=RX o(l00GF@99 a /$*+MW33 k2-*)*IX01 u! #'#37 ͉H+uX@ 1/0!!5!AGЈX'@??//21/]0!!5!3A4X@ 21/0!!5!3AhhX'@pp0021/]0!!5!3A4X@ 1/0%3!5?p+v'qqm 93vJ!_@ Vw V v"99991@   "<<99990K TX@878Y'&'&#"#67632327673#"&9 &}33[&@%9 &}33[&@7 %$RIJ!7 %$RIJ{f6@ D910K TKT[X@878Y # mXfvq{Pf6@ D910K TKT[X@878Y3#fs{?f<@u991290K TKT[X@878Y3#'#?fsH7b/q|  !)1H{Z%@ 910@4D]3#^{)I@ dd 91<20@#4D`````````ppppp]3#%3#^y)7{"@ V@ V /1@@ /0632#546?654&#"7pihX,#w3-.>GZdH3UC=A   (6%""($4f{Cf<@u991<90K TKT[X@878Y373NxsD/1/0#DD'4]fB@991<20K TKT[X@878Y#!#͇fxx)1V'B)1H VV/1 /<0#.#"#> v aWV` v ")KKJLD( @0#3Ӥ?#55#53pp{53#7"op{y3#@uUCqPUv$<#5353#ĠxxxF33##xx2xU?p!5!#Ik{1@V/K TK T[KT[X@8Y21@ /0532654&'3#"&=X.. W]0iw-+76 >&Dzs5V @  V21@ /0"&5463"3VZ||Z(55(}ZY|x5'(5 M3!5353D M#5!##걈ň$ #53533##Ġxxxx 5! zV '+53276=0RQi&&``01wV %3;#"'&5w&&iQR10``Zs3#'SjC( @V xV1@ /04&#"3267#"&54632[6'(55('6y|ZZ||ZZ|&65'(56&Z}}ZY||jT @03#Ӥ#uzLuD/1/0#D`tP#5!#fJc9X#"4533273273" v aWV` v "6KKJL9HS/TB  #"'&'.#"5>32326SKOZq Mg3OINS5dJ t]F ;73 !;?<6 7=xh!5xhh5!Ĥh'`_^NO'ygfFXY @  V21@ /02#52654&#Z||Z(55(B}ZY|x5'(5[3!53[J!!5#>J*>c9X632#&#"#&'"#72;tv gfv ifvtR+ '7'77}`}}`}}`}}`p}`}}`}}`}}` .54675>54'&'C!RI 7!RI 0PQn +0PQn : ' ! !fCqPfvH7FbV+I#5!#!Ֆ֖V,2!5!5!5!>>2xx3#3#@`tt!#!–*>,Jf'73327673#"'&'#7&'&#"#67632Bmk  &}33[& !Bnk  &}33[& g  $%RJI g $%RJI J!%'.#"#4632326=3#"&3#3#9 $(}gV$=09" (}gT";薖Җh! 2-ev 3)dw.CJ"$$c( 7!#'73!'3p~(͛3#557'2d͛~~x&'&4767@*,,*@rNPPNr*,@A++{OPPN`1'+!x050567654'&xrNPPNr@*,,*{NPPO{++A@,*.Do2>&"762"'"&46264&" 5O57O5>||=>||66O5555M75m?|}A@}|6M65O5p "pk "Ppk!!p kpT!!p ଔ* '#'&'&#"#67632327673#"'&O,$e5Fqp[?9ZO,$a9Gqp[?9J7  $0GJI "7  $,KJI pn #w(5!'3#7ws~~d͛q` !#!#!#Sb+e !#####b+tf@103AntVH@10%#AnH3y`V #"'&=3; #V!. {q{'yOF{'y#f-sRf1@ D10K TKT[X@878Y3#fFR&jl@_]@_q0hf''HFyuf't+f'-}f'z/f'5(f'n:f'h>6'.Nh$%j@ 1/03!!)ժh=@ B1/0KSX@Y !3f5:9+(\=;+s!2@"" "#3"10!!"3276'&' ! '&76>b܁܁:xżp[bb,j.h<@ B1/<0KSX@Y3#3#:9&+031b *@    <<1/0!!!!!!29iggqs2;3 F@B   <<1/220KSX@   Y%!!5 5!!>!8ߪp7<s'<@) !%(<<<<1@' %'/<<<<0367654'&'&'&76753#–bbʖbbWssWWssW=;;s.@ <<1/22<20!6'"'&336763#ּՂnʊnhg椌gHN&3@ &("3'1/<2220%!567654'&#"!5!&'&576! cccd?IH1/GGaʦa>”XN'"/u/ +1N'"qu: +1qf&Fnf&PJVdf'Lf&NF*&Zqy *@ ,%E+99@ ?/]q@ ) !/99@<<10@  ]@IIIJN LNIK ]@:9:88? <>]@ + +*))]@  ]@++]'&#"3273;#"'&'#"'&763 N,-=MKLyHc( #) Xn^T).^,ru7 nik%1)0T*XoW)&V!7@E F21@  90%#! !"3 5 4# yYo 0kEdZ&J:@ V`@@ 1@ /<20@ 993#&+532i^;,_1FLdVD~qu-T@(/E( Q!E. ]99@%%.99@S910&#"#"'&4767&5!232654'&'&fu5KxD7VUV[a~@Fu\0%p̥@$OF(Iqrs`g |2=@" 33'(#,34 '0E310&'&547632&'&#";#"32767#"'&546p<@ KQX@8Y1@ 20%#457654'&# !5!ʄOTJPE* :;f,KOxsPWKL,#%5,*3Y'iVd{1@  FN  F21/0@]#4&#"#367632d||BYZuccH`e22wxqu$!O@ """#E QE"2]21@?]0@ w##]!3276'&#"2#"'&76EVSI 6VQ@=񈉉d~uvn` @ F1@ /0;#"'&5c"$lYoRR`+.0`b` I@   F 21@ /<20@    <<33 ##Gb`/ZFB?= F@ 1@ /<0@  # #'&+5z~J/k`ue<2~V`wJ`B@1@ /20@ 99!367676'&'31!xdLjE.*{`T|p5dwY|rNįtkR&@@ (" %'1@ '#"'<90%#457654'&# %$47#5! $ڄOTJPE* :MKOxsPWKL,#%5,*,X$Rݿ qu{RJ`/@  1@ /220!#3267#"&5!##J117,#J%x\c`PH? XV{1@ EQ F]1067632#"&'#44&#"326=;{:+fZ#adqR{$6@ !& HE%1@% %0 !2.#"32#457654'&-ULNPƯPTJPE* >:##++LOxsPWKL,#%5,*q` 1@  QE]1@ 0"32654'&'!##"'&76sRVVOcm񈉉qnsȷzn휝dm`#@  1@ /20%;#"'&5!5!!$lYoRR\ W0`b*`+@ E F@?? ?]1@ /<0327676'&'31'"'&5R27ki;jF-*eb`+@EvfwZ{sxvpVh )=@+E(#E*<<1@ *'*<2<20"27654'&'2##"'&7673=A__UVF6˷džfB:VVMpˑRh]p[nmNssg.;Uda@    <<91@  <<90%KSX@   99  9 9Y#&+53;'$ܕ11FA3N11F~0)~pV`6@   <<1@  <2<<0&'&53367653#EkUJ|CUvܷ%aw~LB,BTxnc#n'`8@E  E1@  /<2<0 433233243! &aƏ˪ޏƛa!)R@O@+}&Nj.*&jZquf&}T*f&"Z'f&^YVj 3! # # wHV1M$ 'G@)E& F(2Բ?]1@ ("((Զ?]990267656#" '&76#327>&iPDyz]6;~oxҤ]Y:PWp=l޺lǧ_ը,嶖ꀰ-ўqu$ 7@ !EE <1@  04'&#" '&4632  1BSxyJ̃Я#/p~ZZ7Ai6deBWQ I@ "!9Ĵ?@]1@ /<99@ o]0#4''&"562%62#"FR**RMw(oUCHk&_*SKHv H# 0r{C @[)/Bf'ngPWQN'"ugpV'A@)   $E(<<<<1@ (  (<<<<02##"'&76327676'&#"DžǷdžǷqMTVMqqLWULc휙owgsugHgusgAm`E@ EE91@ <22205!#%$! 47)323764A,Ma")aM:GϤ*RѧOp[g9&'&47#"54654'&#"563277632327"'532! `7"7$>9[@[`7"7>9[&F]_I I5l|"O z:6hl0'[Ml |"Oz:6hlf$11sXD@!  ܶ0]9ܶ0]1@   <0#&'&76!   76';:{HpҳI椤qVu{ <@!E E ܲ0]9991@   <0"32654'&#&'&7632sVVUVVV9kjstntstu n}{R$.@ & #%1@ %"%0 32#457654'&# '&76)F`{[mzYTJPE* :xe+wTOxsPWKL,#%5,*eNqRQ` 4@ " E!IJ]1@ ! !0")!"32#457654'&g-[oPTJPE* >LOxsPWKL,#%5,*#)@VF'6  (<1@ ( $(0347632&'&#"!!#"'&'53276`1213$)),x:KAb933.1220W@Rd >Qoɏ?s K_7"'&76'&526n 'BQ_'BQ_[~,`*l#FR`*l#FRB@ 91B/0KSX@Y #!3&pM]rV`!#56! #'#64?!"QhRR_@0:IKiXL}/M4!wx#&'#&' #'nd2Fb.-t`4#M!P^sK=W@< 9:?5 +,">99KSX +9> &1>29<90'6767&'&'#"'&46733276=332764''3=D۴vayͤgDd''dey{d;]TCHI}rHGFFtAGCT_8d榈d*0QA^^^Fkmihhimw'AFU'`%S@!'E  E&99KSX"Pe^Ґ8*7D ! ! 12԰.#AL.#^Yq4+& "H4B;;=/?"+VhPOV !! 7654'&#"#676! 3 7llc^#,V)ۄe]6?fضdVj{ # 7654'&#"#67632327\B\\TP%I/yYk}oSKu,2R¤ຐs5%! &'&#"567632 67632'&#" ;!53276n"?E! rK,/ 4'Kr !D<&tEGGH h=" C(FK#C "&E !!6{5%! &'&#"56763267632'&#";!53276[96:@%((%@:6-:IkI:8=3553gs%+$67632! '&76!2767&#"327*W8QU{2Τ|sK^lȺhiieb-sJV"1Pһ '$Astxssq[/&67632#"'&76!27674'&#"3276I,)e[xtgO_\SG]EZSTVXXTRS7xJF61𢢜Pһ ''rsstxsst,V4@  <<1@   <220#5!#!#!3`d`du7U3@  <<1@   <220#5####!3_pzpppg3#"54654'&#"563277632327#"'$47(`7"7$>9[@[`7"7>9[@[|"O z:6hl0%[Ml |"Oz:6hl0%?[MV{$:@&E QF% ]1@%" %04767632#"'&')! $'&  7Z6;x[Y: +STTSST$T%Уb^#10dX4tsstjtssq{FVyMsaq{!&'&#"!!32?# '&76!2%%cjf_[_fMJOhk en(' c\\c( +{!56763 !"/532767!5!&'&#"'(ne khOJMf_[_fjc% ؜c\\c Vs'& @  >  91@ B  /<290KSX@  Yp]@ 6II YY @  &)5:EJ ]]! !###-}-!+V` O@ F  1@ B   /290KSX@   Y!!###`{`UV{'4767632#"'&'!!#5#5'&  7Z=;{XY:eSTTSST$TfZ#10dȪpptsstjtsss'Hs'&y3s''yk&%uN&"uBBBB|#I#IabhFaF`C`#BC`CUXC`C85YBB#Ih;5#I@PX@855Yf4@  <1@/20%+532654&#!#!5!!!2L>o||Rh"9+Fjk&#us'N@  2<1@  IIPX@8Y0! ! &! !!! 'zOFӐhgս6,XNf-T/3@   <1@  /<20!565!32#!% 4&+pٕxL@+8/Xڦ5@ 2<21@   /<2<20!!#3!332#4&+326 z6࡟9d݇,@   <1@    /<202#4&#!#!5!!||Rqf9+Fk&#u3k&%u#m')ru; )@   1  /<20)3!3!#++h$.@  . 21@  /04&#!!26!!2)DlN݇@%j@ 1/03!!)ժe4@ <1@  /2220%!!67!3#!#p&axު D+?x4&A((v@   <2991@B   /<<2290KSX@    <<Y@ I:I:I:I:I:I:@  <<<<33 # # # 3DDxM(?@ * %)21@  %&" )02#"$'532654&+532654&#"5>I8z,|йԳƆ\qѲ|!ĐBY+wps{M("3 y@ B  6 991/<2990KSXY" ]@068HGif  FI WX ei y   ]]#!33j+3m&)u# + KT KT[KT[X@ 88Y1 Y@   2991@ B  /<290KSX@    <<Y3! # #_yT:%@   1@  /<035675!#!T>Wxfb/X++0;+s2;@ 1/<0#!#;"++3s'&7#> 1B /20KSX@   Y%+53276?3 3 OM?w.-!suٵ2&]*jklyj =@!   <<<<1@ /<2<203>54&'$%53# W==U+  -=;; )@  <1@ /2<0)3!33#;ʪ+$@  21 /20!!"&533!3_||xdv+ *@    1@ /2<<0%!3!3!3OOʪ+++o2@  <1@   /22<<0)3!3!33#OOʪ++< *@  21/0!!5!!2#4'&#!!276GN6ONDPO+DCDCF&, $@   21/04'&#!!2763!2#!ONDNONDCDCo#N@ <21@   IIPX@8Y0! 7!5!&! 56! ! 'oOzFՎaa0&8@''!&$#(  !%$'2<1/0"3276'&76! ! '&!#3~܂܀s;:ŴL椤kj@@  21@ B  /<0KSX  Y3!!" &$54$)#!:ƒdv'V+w{-{Dp7):@+E'Q! E*21@*$ *9902#"'&5476$%676"32654&}:[;z631-~LӔ{0w)v ,u8w>` /@ " F!21@  /0!2654&#32654&#%!2#!r~~hhVlj9_ZZ^SJJOgyr`F1/03!!`3k`4@  <1@  /2220%!!6765!3#!#}v[(bt:d6(U3Rq{HF`@   <2991@B   /<<2290KSX@    <<Y@ I:I:I:I:I:I:@  <<<<33 ##'# 3?nn`QO6m|(N@ &* )1@ #)) ) KQXY KQXY0#"&'532654&+532654&#"5>32|PZG]twGabLx\l%%pZXkYF@\]y` ?@B  F F 991/<2990KSX@  Y##3y`}`y&# +KTKT[KT[X@ 88Y1` Y@  F 2991@ B  /<290KSX@    <<Y33 ##Tsŷ`OQ5Ls`$@ F  1  /<0356765!#!L8D{X^~ŷoPO` M@B   F F 1/<290KSX@   Y! !### >? ˸ʹ`'P` '@  F F 221/<203!3#!#U`7qu{R`@ FF1/<0#!#`3`V{Sq{F<m` 1/20!!#!<1BB`3=V`\pVg (3B@5E)! '.E4<<<<1@,41$ 4<2<20327&#"#"323>32#"&'4&#"326/{brrb{9SS99SS9{brrb{/Ǩ<9^N5=L^^LN^Ǩ;y`[` (@ F <1 /2<0)3!33#9U`33R`;@ F21/2#I #IRX 8Y0!!"'&533!3Hf\45h)_Vu;;` )@ F  F 1 /2<<0%!3!3!3ڹ"ٹ`3+`2@  F<1@   /22<<0)3!3!33#"ٹڹ`333R>.` ,@ E  21@   /02#!!5!!!2654&q8$~͓7_ZZ^{'">`%@ E  F21 /04&#!!263!2#!z~~@9LZ^_n7q{M@ H<21@   IIPX@8Y073267!5!.#"563 !"'q2 ǚ-VړiVFHL{ :@ E  F2<1@/0"32654&632#"'##3Jq и¾.`At"`<@  21@ B  /<0KSX  Y;#" .5463!##zwwVtS^a\'qk&CZq&jBBBB|#I##Iabh#FaF`C`#BC`CUXC`C85YBB##Ih;#5##I@PX#@8#55Y/V?@N F <221@ /<20#533!!>325654&#"#߰Bvz||яLmedY).ПĞm&vq{N@ HE221@  I IPX @8Y02&#"!!327# ǟ 2ғ-{FViګVH>=o{VyLFVyML`6@!E  <1@ /<0356765!32#!!%2654&+L8DثX^x~~~ŷ7oPv_ZZ^`8@E   F2<21@    /<2<2032#!!#3!2654&+N޹"\~~`7`73_ZZ^/:@N F<221@ /<<20#533!!>32#4&#"#߰Buʸ||яLmed*m&voyk&C]=V&^` )@ F F 1  /<20)3!3!#TfUf`3s48@$%6 )  51@ $-/<2<0"'&46733276=332764''3#"'&':y{d;]TCHI}rHGFFtAGCT_8d{{ђed''deFkmihhimw'AFf^^^^'`^:@  <<<1@    /<20!2#!!5!53!4'&#!!276XNpqONDNOQQfDCDC:@E  <<<1@    /<20$4&#!!2!5!3!!!2##~~EW^͓Lʣ+#3376!2&'&# !!!2767# '&SvwhfstgFtsfjwvú 9$#G_//wƪ//_H$$O{#2&#"!!327# '&'##33676>\" , Ux{ z{FVAW^3VH`3ʀ !#!#!#3 73` !#####3 Ñkk`_ !#!#!#!#3!3  o_<9d7`!#####!#3!3 kÑkk`_s@   9ܴO]9ܶ@@]9991@B  /<<9<20KSX@  Y@]##767!#'&'!ʓdսxQPtՀ`>YY~b҆12z(k{`~@   9ܲ]9ܲ0]9991@B  /<<9<20KSX@Yp]! #4'&'##767E]kKV:VS8V‰Jl&VtO\KtU'4! !#'&'##767!#3!PtՀ`ʓdսUn>qd2z Y~b_49n(.`! !#4'&'##767!#3!7kKV:VS8V‰]w&VtO\Kt`?sVszS#"&#"3276&#"#"'&54763!27654'4327654!"567376767632'&#"ssD#`At bTDt;<}J5?u_hFAXVRuťޠsj#B#' "2ZbrRUgr %',azQ^XRj7&6J- @' WoWdE\`[tO#"&#"32632&#"#"'&53!2654'&'"#5223 54'&#"5673767632&#"vmDPb!',-cX;b12i?,ZnN .rr. >._- > ^ >‘  tӪ ҫ q{&P%327654'&+"&'&'#";67>2# '&5476!36767623 !#"'&'&r-HVV?- ,4, -GVUH- ,4 .xt. 4 .wt. 4 `ta  _tp_   颈   袉   vt&'0'&'s3'cS'&sV'9@  0Դ/?]1@   /0]!# '&76!2&'&# 3!#SvwhfstkSh$#G_//ӂqV{9@  HE1@ /0@ ]! '&576!2&'&#";#UQQLNONPccccɖ#+qr͹rq;'''7'77'77did}}didii}}}d}}}}dBz/!"'&'&'&547676763!476767623 8  8 g    ) M #&#"56763 v][Jw}$)/K'*Ca"53#7 a#55#53g M !2%$'$'&ʇrE2 _fݘL{t\q F` &3@MZg#.#"#> #.#"#> #.#"#> #.#"#> #.#"#> #.#"#> #.#"#> #.#"#> v aWV` v "8v aWV` v "v aWV` v "fv aWV` v "v aWV` v "v aWV` v " v aWV` v "v aWV` v "AKKJLQKKJLKKJLKKJLKKJL)KKJLKKJLKKJLX- #)/'7'7'7%'%53-#%5#53 3#kyo\wyo\zV\Ly[`@¬@_ӤRӤRZy\yW\zn[wyo\ԤRԤR߬@¬@Vm&)uV8&!:@  <<<1@    /<20!2#!#535334'&#!!276N訨ʨONDNOQQfDCDC&E 9@ E <<<1@  /<204'&#!!276!2#!#5333>CB>ytts9L^*..+URRRя>'+#!2'674&+327'7Uj~ rGj#u~{Sqrے-,9/~V{)%'7654'& 32'#"'&'#367632*nOSTTSSTFoWl{XY::YX{ ]ststsjts].01d d01j@ 1/03!3!)2$ F1/03!3!`:33G )@  <<1/<20!!5!!!!!N)#l8U` +@  <<1@  /<20!!5!!!!!?`۪ f3@  <1@/0#!!!2+5327654&#)qmL>87||9ժFwrKK"V `3@  F<1@/0#!!3 +5327654'&#rFRRQn!&&1`GQ``07 )(33 3## # # 3׈)D"AMF`33 3###'# 3?nfz!n`QL6mu&z9u|&z3! 3## #E#A`33 3###Tw8sŷ`OL5373! ###ʭd_dTy%u`37533 ##5#`eBTse``avFOQ5a!33#! # ##53ʨ_ʨye=3!!3 ###53dTsŷ}}z}5OQ5}2 _@   2991@B   /<290KSX@    <<Y!! # #!2_=y+*` _@   2991@B   /<290KSX@    <<Y!3 ##!*8Tsŷ`OQ56@    8 22<1/<20P]3!33##!#"dA9@`1@  F   F2<21/<203!33##!#W`39L -@   8 221/<203!!!#!#)"d9` +@    F221/<203!!!#!#W`3ͪJft8@<1@ /<0#!#!!2+5327654&#;"rqmL>87||9+wrKK"V!`3@!F <1@  /<0#!#!3 +5327654'&FRRQn!&&1:`GQ``07&.sAY%.54>323267#".'#"$&54>73267>54.#"+9lR2*DaSN}aF-?jQ&h;>e3.x=&QUW+Byc[sp8<{R?S0 $0>&1H3!(BT1kBtW22Tp{:SJ#&4t}f|}ާbm:E/fcYC(+G[`_&bnqxz?P4>73267.54>3232>7#"&'#".>54.#"qKц][-2`X'V$?/(PtMBpP-\_#D-)*%-8%7CFIGԑLV"- !(,!(؜XFrXbr> %gx@]sA9hY^    , Tָ&^dc+KiB&HiCsu''z-qu{'z ,@ @ @ <1@  /20%3##!5!!A+<m` (@   <1@ /20%3##!5!!B1BL<=V`o@  K TKT[X @8YKTX 8YI:9120@BKSXY"%#3 3;^^DNl!#!5!53 3!ssf=V` !!#5!5!53 F;^^`XXNl=;%3## # 3 3p\Y/su A{+3;y`%3## # 3 3q!r))kLHJqG5@ @ @ <1@    /2<20%!33#!!5!!+A+B`3@  <1@    /2<20%!33#!!5!!xZ9B1B9L|.@   <221@  /20%3##!"'&533!3_qm||x˪Awr7ٟd`F@ F  <221@  /2#I#IRX8Y0%3##!"'&=33!3f\45h)L _Vu;;#"'&53;333###;qm||֐wr7ٟ9d+`5333###5#"'&=3f\4+ _Vu;0$@  21 /<0!2#4&#!#z||f9dK"*I@#$ $3 +291@ $ (+<2076! !!267# '&'&=3%!&'& ":Cppoż vzKB@bHam `_F$$UgkL>A9||f{%.i@.&&K /2@ p000]91@& &"*"/o]2</]90"'&=33676!2!32767# '&&'&#"XY`09Jt⃄ fgjdcbhcneNRS]\RZF1!&łZdc4,ZZWW-!&'& 76! !!267#$'&'&=3bHa":Cppomw vzKBm|| `_F$c TgkL>A9f{1&'&#""'&=33676!2!32767#&'&RS]\ƐY`09Jt⃄ fgjdcbhcOJ{ZZWWRZF1!&łZdc4,3{,(vm')[uFH'f532+5327654&#!#3!qmL>87||qwrKK"9wV`3 +5327654'&#!#33^HRRQn!&&,%wGQ``07$)`6V!#!567!3#:bCux+8.%5ժV.V+`%3##!56765!s{{v^̳;bVdžf;1@ 82<1@  /20%!#3!3+53276q"L>87h_9dKKV`/@ F F2<1@  /<0!#3!3+53276WRQn!&`3``07V!#!#3!33#;"9dժVV@`!#!#3!33#W{`39V/@ 221@  /20%!"'&533!3##_qm||xɪwr7ٟd+`G@ F221@  /2#I #IRX 8Y0%!"'&=33!3##Hf\45h)p_Vu;;V%3####! !+-}-VV`%3####! !H{˸ʲ>?V'P`yOh'J+1@oo]0{-&O"+1hN&"u  +@ 0?  ]1{-&jR -( +@(o(P-_(@-O(0-?(-( ]1H{o{m')u@@]1qH'@p]1uQq{uN'" umq&jTn(vN'"QuF'jN'"u&j:yXL/`T31'q;y'q3N'"uy'jsN&"'u +@ @O]1qu&js +@ @O0?]1saqu{7sN&}"'uqu&~jso#N'"guq&j#1'qr;=V&q^#N'"ru=V&j^#k'+ru=Vf&^N'"u&j^j #@   <1/03!!3#)ժA` #@  F <1/03!!3#`LFN&"u&jGV9@  <<<1@ /<20!!5!!!!!!+53265N)#iGRiL`na8VU`;@  <<1@ /<<0!!5!!!!!!+53265?`nFRjK۪`na=f*%+532767 # 3 3*SfL>7( ^Y/su bzK5sx+3;Vd` +527>5 # 3 dkkCQO5r))`&9as mHJq=;3 3!!# #!5!suNt\Y+wD{;y` 3 3!!# #!5)) ~q4H &@  21@   /03!!"!"$54$3!fONDNONNCD#CD+fq` %@ F E21  /03!!"!"'&763!5>BC>9sttyLZ+.i.*RRPRUC 09@2&)  1291@"-(1220!"32765#"'&54$3!3327653#"'&NOO_KV! 3j^nN?4pi;?nhf1CDP_m}`61f[JJOZxx9qs` 08@2F&) E1291@" 1-(1220!"32765#"'&54763!3327653#"'&=C>A@j\-1C]^fety>dhd.*^\:9m4l01a`RUaPOORAsxx%7@@9., ,#81@'2-28904'&+5327654'&#"567632327653#"'&'&\]OOQRSrsdeY憆GGRQ?4pi;?nhf0!JK;$& hi|UV!bb[JJOZxx8PaF|5G@7., ,#61@66'2,6 KQXY04'&+5327654'&#"5>32327653#"'&NHtCDFEwGQPabLqr<=ih<>dhpb8f83,-F@.. NO]@AHOHXDEORAsxueV<):@  '+%*1@!'(/90!#4'&+5327654'&#"5676323#s\]OOQRSrsdeY憆GGRQJK;$& hi|UV!baV|)?@ !+) *1@ / KQXY0%3##4'&+5327654'&#"5>32ȻNHtCDFEwGQPabLqr<dhpb{v^̳;b`WORAsxue{-`6@F  F221@  /20327653#"'&=!#3!zgh<>dhpbW`WORAsxue{`3s0@  1@ 0# '&76! &! !2653d-|e'%{9!Ҏ׿qF{0@ E E1@ 076!2&#"3253# '&q кĽbZZb/n||r|r|>禞f/@  @@1@  20327653#"'&5!5!?4oi;?nhin+[JJOZxx}q`2@  1@  2 ]0327653#"'&5!5!x>=ih<>dhpbB1VFEORAsxue{~{R|JTf:/@ 1@ 20356765!+532765!T:WxM?77fb0dKLøLVs`/@ F1@ 20356765!+532765!L3DF1a.&{X^}з0)oPT 35675! 3 # # !T>Wysu \Yfb/X+3{L` # # !56765! k0X^̶8D')`HJoP~ŷt32654&#!##!23 #h /ϒ0*3V{ ##"&'#3>32&  k\{::{T%+ܧ$`tad dakj3&$54$)!!!!!!3!!"d;>v78ȒFwtw{&/!3267# '&'##.5463!632.#"%;#"w ͷjbckVteVgKww^Z44*,'ėS^a\s4qVZ{TD:V5`Z37!#'# #3'jȎ_Ȁy`373#'##35Av擎LsŷK)@wLQ5`PTfs%9@' !&<1@!/<035675!!2+5327654&#!#!T>WxqmL>87||fb/XwrKK"9+LV `'9@)"#(<1@#!/<0356765!3 +5327654'&#!#!L8DFRRQn!&&,{X^~ŷGQa`07$)oPft!?@ #8"2<21@ /<2<203!3!2+5327654&#!#!#qmL>87||"dwrKK"99V`#@@ % !F$2<21@!#/<203!33 +5327654'&#!#!#UFRRQn!&&,`7GQa`07$) !!#!3#q"r+A9` 3##!#`9L3`p#653&'# 33267.''U.,aOYFqlEk*Yb?f)6^&4Z)e\3'4H./)%uxm3-`433! #54.#"!!"$+Z`bZ*J%)9 ym22my=]#3##!".4>3 4.#"3ؔMM،"*Z`iV%,[_r=PŏQym2:d_5Z!4.#"#5! 3#*Za`Z+$"ym22my 9''ί=3!!32>=3! }J*Zb`Z+ym22my 9)%)!!332>54."#54> 3Tmqn,dV=uG0fܜc.L2Rg|]= L+S{ugyC@pVGKyҚXZ %!!3!!Zf33! #54.#"!"$+Z`bZ*%)9 ym22my$)8"#4> 3##".4>;54.2>5#"q6[6[Bt^_tADu[5o%AXhV>"9Z>N2myuݔJJݓ4kn9:sl3zmpBAkP#?]##".4>3!33#!"3265IՋؔMM؋o_[,%ViWW]О\uBnsEA33>32#54."#?vԒK+Z[+ MIHݖK2ym22lyD!!xگ2>53".5!#36Tf`bQ3HҳK`1Kf>>fKIwo55owO+>33>32.#"#".5467#32>54.$+ NBR=3)EvԒK+Z[+?CHݖ&ym22lzF%.>76$73>g? ;w8q`g_ 8/@9L`uPhG/+Xam@E\>&5C4>32>54."#54> .'#".%"3267.;eHxv(A//db,N,T"?W68m86o8n~Gf=l!?1XXVQ^ IrN(`P2s|Fg}F@pVGKyҚXXV?-_34e0Yd$Kq$3 AOH@BPd%3!4.#"#5! ;+ZabY) !ym24mw 9''i$"!".>7>73>33!&-p|CtBnK#QMCYP8PDYMG)#@[9r El~mXBkJ(~`#J#! 332>5!)*YbaY*& ''uxm33mxY7 .5332>54&#!5!2>54& #4>2YML+`qp^*PQwM%ʠJL%@T.DuW2g~GJeArW22Vp>'C\5vqr{_g65f];hS<?[vq32>=3! #5)ZcbY)uxm33nx 9-!y..+532%.#"32>=3#".54>7d8UjGk@*oKie2R䑒XNoԔ Hy54&#"#54> MJ*rIhf2R$WKUEg Vq32#4.gVb4fc8fGl IpX*9ٜWWق\OvO}";".5&>32!!332676&%4.#"32>VxP.O哠MLldNQ_(0eoke.+K;ym'+H5#9GG@k”X^yݼ1L?=d{E9dM&7%@r[-jx#!4.#"#! 3#^*Za`Z+$"ym22myu''ί=)8d)#".=32>533;AvԒK+Z[+HJHݖym22lz =332>54.'.'&>2#.#" .5`RPd86aTCq_F(IÍN'NzVOxO$&KqPՔNRҕPDtT0 DiI:U=( -?XsKZr@=lT,TB)'F_72I5% Binfs=K)3! #54.#""(,\`bX)%)9 ym22myug1@ .5332>54&#!53.54>22>54& gML+`qp^* 7(JL%@T.DuW2QwM%ʠD|g~GJeArW22Vp>2?J)_g65f];hS<?[vg'C\5vst{&UJ0M!!#:Ox'3>4.'.>753#]h88h]ˇXXˇZZv;kęl;T ֘TT՘T2n+".'!!#5#53!22>4."*>n^Kh˾"ٔMM$VҎU%&WЌV%4毚e$ NMZ\22[a67as2n)3 $.=3".546;2%"4.#>db7>53o:Z=z3^SB[9z.Z$9H(@{b?%9H(G{^;fCU5)#&>32#".'332>54.'&umG~f?z`< =[<'OC1& 0B&Je;yD"FnL0R>#+G3 %'<*.cZ3!Z#z`*%#".5332>5332>53#5#"&EW]1:V;GrQ+qxFrP+?y|~t?xqNQqH 1\Rzb2]QziazVd{5#"!!#3>32Bv='V fcqV/{(2>54."##".>32533#/+QtuQ+,QttQ:}fyCCyf}:ʡp<323eBvVH=`fcb3!!3276=3#5#"'&>=}TVCvddZLPO_b0gbxwqV/{-3!#".>325332>54.#"Zs:}fyCCyf}:!IxW<]F0 !KwW<]E0 RdaUٛUadN{M%AUaf0N|M&@V`f )3!!!#z%LVd{!#"!!3>32VBv=} fc\V{,<!4.#"#3>323##".4>!"32>f1HvORg;*cmv=D~mQ.`FH`87Zsf2(+@)QQD/dp=)Ze 5".54>3!33ItQ++QtIQvM&BB@{<5faep<32dBv\=fcVl`3!3rN V*32>53#5#".5#"#3>32HqxFrP+?y=kDKnH$AWh;⣛2]Qzia)e=2\Q'I7"qt-3!#".54>732>54.'#"ԤB7}C=DD>o[(QwPOxP(+G4NxQ)  ҠNׄzΗUUzxƔ^SoAAoSMwcV,EuVX3327653##"&VWCvZ_^{VgbdKj0-B#5#".7>7.54?37>32>=4.'<4H\pCbj7>m^D];"$*.GW(9 !CeDMxR+EpQ=lR0, d-J6Bxi`K 4GS)D59?;-?""EsS-7]{DV5wuh&2uV9{!#"#3>329sBvH=`fcRZ$(>53>32&#"32#5#".'&732>=4.+7k-42Grb*wќZF\tEff568V-Ia8FsS.*buG* `zE*Kh=Lw,J6ArZXuF3[|Ih@mEA~-332>5!##5#"&KwS-ոCva2\Q/gbVr` 3+53265F1iL`aX!32>53#5#"&5#'KwS-Cv2\Q{gbV{{13!!".54>54.#"5>32 Pt*D07.54>737>7$F7!#0D(YȸE  V`*%#".5332>5332>53##"&EW]1:V;GrQ+qxFrP+?y|~t?xqNQqH 1\Rzb2]QzXiaznV|,D3!!".5467>'.54>32%">54.32!!5>54.O|V-?yct?!=V5)?`B"#Gl4ZzFs`afF}gS{q94myPIa8X{XV-332>533!#"&KwS-sCva2\Q/Vgb{'3>32##"#5#"&5332>!OW[,ĸ32dKwS,Bv\=2\Q gboVX{J`%!!3r&"`V'3>32##"##"&5332>!OW[,ĸ9jQ1CdƸ?oS0/3K2\=/ZUVgba/[)V{,%!!#5#533>32#"&4."2>s빑:|fzCCzf|8+QttQ++QtuP+__daV؛Vadp=;2%"4.#2>!gWxV0PZbo;;ob}t{ E}jj}֗RV'IgS]VWrB+OnCHpM'LF&OHBM_/9k~%!!5#"&5332>73X&"CvƸIuT.gbZ/X}MR73#3#Rd%$'d ZZ-,DC <21I:03#3#D-dC'KRX@8<1YC %  <<1@  <73>53`#8!2-A,#8"2.@,eX5AnEQ`Q2,  6AnE RaQ1,XH`6ܴt o]1K QX8Y /0%4.#!5!23!5 &EyWJ{tEKcf:%.UrUX`?! ̴t\]KQK SZX}/Y1  //0#&'#"'532>54.+532EM:!FPP7.3"$,EV8(3e\Z`^pQg6 4[u;X`( 1K QX 8Y/0##!5!ƺ/я`<F Fp j ]K QX8Y1 //0##4&#!5! .T`&`ؙt`!FFK QX8Y1/0#t``Xm` E 1KSKQZX|/jZj Z ]1YK QX8Y /0#"#467#5mPWAM8`y'` 7F Fp ]K QX8Y1 //t]0#4&#!#! ^yƒ/`k[! F ܷtp / ]1K QX!8Y /l nn\ ^^D D4 4 ]02>54.#"5632 r-YttY-0ZCB]rWfT%`t[(([tq}=Qҍ ,DB`#1K QX8Y/0B`LXV`8F a _ ]K QX8Y1 _O?]0#4.#!5!22X]ֆ5hruB=X`5ܷOO??]1K QX8Y /0!2#!5!2>4.#!XXuxP""PxuXdN""Nd`@kk@>uu>X6  Բ]1K QX 8Y/0!!3CWn`4F F1K QX8Y  /o ~ ]0)!2!4&#%w4g`:sƒXp%d'F &Բp]J#:#*##h#Z#Jhs #]K QX'8Y1 //Xl\v]03>3 !5!4&#"#>54XBMLbL3xzaV0*bP]` NFd6û[I3'@Vt`$FFK QX8Y10#t` Xx` 1F  K QX8Y1 / ]0%4&+532!5dj~~ͻX{o.` ]  Fܲ]ܶJ < `]1YTid]K QX8Y /44 && BB Rd]0!  ! 4.-_`'0kIuX$XBH`KF >   ]1K QX8Y ]0g G ]35%3>1X‚$FDvj/h 29Vd`^F F1K QX8Y ܷJ  / ]KPKSZX @8Yj\J]0#4&+327#"&5! dGJ)CRC^ СIE d`j Fܴ_ ? ]ܷ== KK ]1K QX8Y /}ܲ_qpPJ]KPKSZX@8Y0! )5!2654&+327#"&5(V^HJ)CRC`܎ۺIE XVcGܲ]ܷ6DT]1K QX8YIJ7]0>=3#4.'%f:uh=hH9=1c䒙.×o~S&PjI9X`lF  ܰ KQKSZX @8 /Y<;?HlY_Ji|= ]1K QX8Y /ķT8Tt]0%367>53!5d,.&=$S47Z7 J}XM./GV_ R  F ԷO_o]1K QX 8Y/IJ]@ P q0#7 !5!WWV LTюnX`@F 1KTKT[X /1YK QX8Y /0KPX//0Y#4.#!5!2ʺ3P~RO~zM::IviF)5]XS`(* )ܴ]ܷH;+P`p]K PX881/}/Y 0WW]1fgwv]K QX*8Y/ܷ/]CC"H%]0!#3>732>73I0K8( )l_+bkcE8" *=Ki`!#@5]Ey+gE=(Ci䣉W=`I F 1]K QX 8Y /j[]0#4.+#"'53265#5!2 $@pP{5NA&G.]l,^`Jce:%r3C `',,`',40`'0=0`@ D103#`n`@DD1<203#3#`|"%0#4'&'37676537653#"'% '##5 rb{ .q & q-aT !}Bs12j{@E#$]} q!<"ibP-F`)*5"2767#"'&54767&'&5&76 '##5M@V:118UF%/>7P6.N@?^G?D)7-#F}Bs)^ &# \*$@.") n F>]KH*!#TH#bP-F`z %3#%3#3#%3#ƴ>^< %3#%3#%3#3#%3#>>^!#53ӤR@ 327654'&+5336767N5G4pQf$h?FA@6b ! eI(R[2* #53 3#ӤR%@-$%#5754&'./.54632.#"'/XZH߸g^aOl39ZZ8{4<5/VVL89CFnY1^5YVeU"756767&'&54767632&767/SD435gcbnZdF31`9:H:ZU!LOTAKv?=0ps2#ql '~U'}>ry3#&-9&p. &.&/ (f&[- (f$3  !27# '&5767"$JKԖ^`e~h'?6`vc–e4- (&[-?}R%67654'&'3#"'532# b&_-q  ?%#&'$473327676'&/3327653323#"'&'TPxmil_Qb_y^@@$;sR,%@n\Kf% I01_2F,k>GHܳ&%0l}=J"5^.327654'&'&#"&#4763&547632#bzL,5;(.;Dn2KxAZM\MObxX'*9:X DD(NOf7*(?$S-8APH&-? "327654'&'2#"'&5476B!799[]KB{ƶ`Q%T*WE{R,,9.UMAx|KU#JN @ &"34'&!5 767"'&'&547632?,3/V%._]g>v-(tYhYH9!$3/,;̠X*VL_ !"bWg3ZfJ6%#"'$47376767654'&'&'&'4762#&'&'&VfxH?Ba=~T;~BrC:@_` B(EN><}9M I&huqc- !P85J.39sJ%*==!'&"7*S@UYD J&r. $5%5%HHnnnn$&567&'&54763233"/#"'&5332767654&#" %!lE?I(7 /4KU^r8Z #08 " -d$* 9^W4'6O'&n=NV)qaK" %$5%%5%HHnnnnn$5%Hnn$-&'&5476323"'&'#5276767654&#") lE?I(7$# +EȓV " - 8_W4'6O -n=*{nmp" %$5%Hnn8(#"'&54737676533254'3'&!9EO)"a 2=`YG g -SGL(E?4mmb}8T"RY$6îs9It6Y ! 4&#"32>"&462X@AWWA@Xz柟?XW@AWX栠h732767#"'&'gC*6:)kXZZC5"LMD6{S )L}@FOwO $/-#"'&547.#526763"327654'& lE?I(7$# +EȓV " -. 8_W4'6O -n=*{nmp" % 4373ËF3# !#'3%1yI !nR#'337673#" %1BR{6)coajr!nUPymL%#'37676537653#"' %1/(/H/; 'G 44.5WY9!nr|> @2%,*;l>3  *"2767#"'&54767&'&'&76#zf\MOYp0;JcX~VI|eepdkAXH,7p 4C@#90L@rRiUZhsBBsǮuu5aU#'#"'532N%bU`DK*22<!&'3673b~ĚZ00ZĥxU:Ũ ;6I<3#&'#6̴UxĚZ00Z~bI6; :d#"'&'&547632#54'&#"=:i_{\ %Z[,,G\O98<SGU37e{a}UwnWl42@B^!x$%-`+-!d! M fM&L&19 &19 &'.>&0 &0&2 &2 (&[}8 (&[1? (f&[. (f&[1 (&[/ (f&[0 (f&[2}&]L}R&]>}R&]-}'-&]L}&].}R&].+}&]/}x&]0}&]2 /'L>_ r'>_ &&_>X &&_-4H &'_ &'-4H&_-( &_. &_/ &_2 &a'-_ - &a0x &a'/ 0x &c.x &c/~ &e/Ru @&g/,:654'&32! '$&73! 76767#"'&54767632)B,4((7(*Hnق@AZAd#?zKbNLZB`.+M;3*)3P&ڴF=)d \^tL"9;l&NKCW4,E$2Hf6&-k&'-~-k&/x~&0&2xxkH&-~kH&/R~)-%2767654'&54767#"'$473$62 #dGf>5?AhXPA7.EB|=Q#!w*6(  %{{qeVUI&b \^~B".54767!#!"'$4733!2$6=4'%$ `h_ >5 ?Ahm/yYk>ba7# #5&qeV&b \^~B"jj7)&>F&l-F&l/qF&l0X)+&Q)+&>F):&.)+&.X)+&1)4&/&m&m-jx4&m/&m0&vH&'-? -vH#"'$47332767654'3HdnaPm/1]]LGL"fh8D%jdQ45b`ޜH&L%]H&'-? >&]H&/  2?4#">#"'&54733267&'&547632&'5#"32764&__A-D$Iln9e|8-H,-C,QN(Jb41}>XA%v3hO =J6>(E& !BQHJQS'Bg=q?%'i!.C] ('0&[-? @r'>q @'xq @4'q @'/, qJrr&r>J'1rpRLR%'&547632&767#"'#'3X\lTX\D8/0E= %1Bx:=$!"4'Qjr!n8j$(327654'&#"327#"'&5732#"-2!WZWXZV%2-Z(.5__52ZJkV0B7,g`p5oU%mao3/AbM3))I<<d (@  1@  0"32$  h P3343ssyzZ (@  1@  /20%!5!3%=Je+HH=  21 /203!#3ulh=   221 /0)5!!5!3=lȪ=   21/0%!!!3!l =21 /0!#3!=l*=1/0!#!3!=lcr8A'91/0#3ASuNA (  < /<10%!3!#N{ 2@ EEܲ@]91@   /<02>4."#&'.4>329[ZZ_PGr䆇䄄rEMp`77`p_88 1ŧbbŧ1 y@ 1/03#+q!/@ E  EԶ 0 ]1@  0 6&    z>z='+@  2291@ /2903#36Q*=q33# =qCq @ 1/<0)3!39Uq"q @ <1/0!5!!59qKqO!>@#E E"ܲ@]ܲ@]1@  /2<0%!!5!&'.4> 2>4.":RJr 惃sKRQ[ZZ{ 1ũbbŨ1 p`88`p`88 %@    21 /03"3#!5!p9 fq2@ E<21@  /<20!#!##"&6 54'&"3qvCf^]8mr^:<UfɃ]8ƃD '@   <<1@  /0#!!!y5!Փ/= '@   <<1@ /0!5!!5!#55ߒѓ+ %@ <1 /0!!27654'&'2#!3,R4,,=iXXXlι]Oz}I__ҭ$;@   ܲ_]9@   /999@ 10#4'&'5!4B 5McAq_9V= 491@ /̲]촍]0 53#T9+!-@ #"1@  !/203432>324&#"!4&#"!}x5%^ZHZlK--Xh&|ŕnc= &@   <<1  /<<0!5!3!!#KK?=9@  <<<<1@    /<<<<<<0!!5!3!3!!#!KøL=??q!@ 1/0!!9UqqK==1B/0KSX@Y! #tFC00B~+n 4@ <<1@    /<20327654'&+!!2/!!m]%i ;@ED\TqQE=4."XErrJSRJrCEoJ[ZZO{ 2Ʀ1 { 1SV/p_88_p`88} @ 1/0#!#}+B} #@   <1/0#!#3}Om +@   <<1@   /0!%!!5!!z;  TKѓ+qO $=@&E "E%ܲ@]<<ܲ@]1@  "#/<<02>4."%#&'.4767673 [ZZTXErrJSRJrCEoJR"p_88_p`88 2Ʀ1 { 1SV/ qO(#&'.4767675!5!!2>4."XErrJSRJrCEoJRNQ[ZZP 2Ʀ1 { 1SV/ p_88_p`88b/1/0!!VBf#"&/#332?E=9Qct2 %xf" %/x $Dp/1/03#=f7u91290K TKT[X@878Y3#'#f[fE9190@ Ueu@ )9IUe]]!5'3{Bf3326?3#'#"&'Bx% 2tcQ9=Ef$ /% "[fC9190@Ueu&6FZj]]5%3%[{fS/1/03#̭F'/1/<<03#%3#\yu  <1/0#527#53gu  <1/03"3#  gd 1/03#!!Mdd '@  <<1@ /03#3#!!Mޒ1/0'!! ''/33!!3'#67654'&67654&nudruxtddx>DD>xIIv! RTx`aw,0dc1-!:;z{t{*L@$% E+<<<<@!#91@$+<@ (+0%"3254"3254#"54!#"543263 #4#"h??AA??A'+,LW@@@@@@@@pطQQ9/@@1(. #E0<<1@!0%* 00"3254"54$3  !2632&#"# 54-654!"`@@@CvBըiUv˫:knL?o@@@@N;Ejfae:.88U8327&'"254"%47&5476! #4'&# 63 #"'632# i60IKhh*)7!o^RX;*:9u`/'"6OfqAtqLI $\9.ȶmQ!6@   E"1@"  "0463 #"&'7325#'&&7'6met "xCBCquЍ h! ACBB )2@  #&E*<1@  *%/0"32654& 4''&5432#5476$ % U%|{e6Lj` %"%:yx~)RhKK>  65@$- 3 (E7<<<1@ 5/7&7"32654&4763  !27632! 54-654!"#"`$ % 琺By#xJi:OknLIo %"%0yKpjNdfDQcwiC|85ss *;@&%   E+<1@")+&+02654&'&47&7'73%$$!% l݁6ZA| $! $Vm-G4 p?{1@ F1@ <@0%"32544!  #"54$32@@@)@@@@Pvv .<@- " 'E/<1@ $/-)/<20%"32654&672#4#"#"'&#" #"53232l$ % L 7*>(z*M#6&8"$ %"%3|0ۯqiPWu{+?@-$'+ ,<1@ )!,&,<0%"3254"3254 #"5#&767663 #4!" @@@@@@!Ӣ7y-^@@@@@@@@edm%W ,9@. $  )E-<1@ '-+"<0"32654&4323254#4#"%$7"@$ % 쐋'(uj %"%@կ̰Xsgh\_"9@ $ E#1@# #<0254#"53265$54767653!"'#W@@>z]U]iTrs@@@@pegu/ssIs|2@  E<1@  0"325447&763! 3%$5@@@ԶMg@@@@R&Ѩ'LBIs2@  E<1@  0"325447&76! 3%$5@@@ԶMg@@@@<%Ҩ'hBY E"32654&!"32654&&''"&5623253765$7465&'7$ % $ % Kfg饤IJ %"% %"%IKbv4ˋ42@7-]fn9h%A@'$ F&1@&<<@" &0!"'# 432!32533253"3254hfg襤>@@@ JJ=|\@@@@@h} -?@, (,$ E.<1@"&. .<<0"32654&2533253!"'# 47&5432d$ % AfgB %"%4˩/JJ=%܉Mh -?@, (,$ E.<1@"&. .<<0"32654&2533253!"'# 47&5432d$ % AfgB %"%4˩JJ=%܋L@`$@1@  <<03!23! '#"543225O)3Ɯ)`,88{s *;@&%   E+<1@")+&+02654&'&47&7'73%$$!% l݁6ZA| $! $Vm-G4 p& ,7@  '#E-<1@+.%.0"32654&4! ! &# ! ! '&54323 c$ $ 6buUKX $ $8${nE{N%O 0@@2, %&E1<1@%/1!*<0%"32654&&'&'&5! 765! '676%&4% $  ,D )@ ' 1#-E5<<1@ )6/%!60"32654& 4%$54!232#"'&#"! '&5432h$ % ${ajjh@MqKy)LJm_ %"%1EYl0xP^b8Rsu_|]F'"2''&'$!32'&547"32?6AS2;9’hhNU~ +;9jq!Bao'@u@` +@   /991@ /0! &7623$'4'74"Y#!A[VB8?<kP$U.FM?>={{+@  E1@   <0 ##"2#"53254#"n=;C>@{jVR777r&WA@ji  /1  /<20! ! !5 74! %&?%~?>~@i$@  /1 /<220! ! 3!5 76! %&>%~?>wJ~~@ji*@   /1@   /<20! ! !5 74! #5%&?%~?>~N@i.@  /1@  /<220! ! 3!5 76! #5%&>%~?>wJ~~T3"36654'#"5432AA\(DeN[̼o[$N[u%@ /1@ /0"3254"547&54323253r>Juum@s> [yu?{EBXF` '656%"'&76! 4"3YVA!. {x9322674&#"CCjFPH OQ$!%!p'(FnJv-O!3] $ $z{&LL00, ("32654&&3 #"4/&5432N$ % s $ˌeqɘzm %"%82y,v\#"6@ E#@! 1@ ##04$54%&&5! $#"57"3254ix@@@X4|`Pٳ ?@@@@ ""32654&5&'7!$#"47#$ % dt.; %"%Ȉ_p 8>u%t/;4#"#"'&#"$#&532327632! '&57"32654&"3C2z7J,"/IN\=0BWTO3H$ % Xt\DD\t] 5<\UCfwpv  gH %"%V@/1/03#V '@ /1@  /<0'6"%)56574 65+*+UGm++),}݅.p\(>.4"!27676327673!#5654#"'&'&#";&543.%2~*&IHHܝBOg(LBC]i%>e>.`h>3A?~= h\$kb8:;-F_Zkf2)N !@ /<<1@ /<<053533##5N؎؎؎ JP>r@ /1@ /0432#"73254#"ЄLTPPHHH` " 7654&' ! '&476^L:NbX1coqoh`WĒcg&24764'&#"676'&'&5476  pHgc/5pIu upHECle\gUܚsuϨcy\$24"27#&5432# '&5?$5+r%3]f́|pHFPfouTapH/%24'$5432327#"'&#"%$'#"54322533]L/|tkZ1AQf(3Ɯ)DjR:jTh8KOpt$68{cW%24"$'&5?$532&'&32!r|T9lc ~x?LvTamY<KcW-224"7&5&326532&'&32$'&324!B}b$|T9lc ~xr=Ch(筭 ?fXmY<KLvttY4@'&''"&54323253765'$543227#"$#""32654&fg饤u ^|uISL\>$ % ,IKbv4ˋjEaTW8ҋ %"%{ &%"324"324#"54!#"543263 #4#"h??AA??A'+,LWpطQQ%Rpt MU"32654&254"#&76767%4#"#"'&#"$#&3232763276'767$ % nnvp+-"2D2z7J,"0IN\=0J%.3?5xv'Q %"%933hk//3wt\DD\t 5<\UCrTF-2bG;"b,i $5354#" #"524"m~ŶejsX\|9 I"327$"3273653%"'%5254%$7&76%$5#0#&7626A?A? Tcb*@RX6&$Hu Ӣ5r@@@@@@@mo6J,/7'- /ԋu cd LX"327$"3273253!"''&76324%$7&76%$5#0#&76262654&'&A?A?fxԅ$8$+Rb,7Hu Ӣ5r$!% @@@@@@@mӔJce$3- /ԋu cd $! $x! !5!!%64'7;OtJu4SSv;X"]| Kn#"57!3273!q-JLX1o2!6&#"&5&632!~po~ds.xsgd{1n? #"327%%5!5!!I4&#"!5!! > F+ W5y%# !!!)!YF^e.*zMjO<%!3!kѳ/Cx} 4&#"36#&3632ʴtÑl}9^DoUD!#!63 䂍w8 =10<x "3265!%"3!!5!!5LiA-*'=Xx%4&#"#463!!&632ʽtwaf ɪXPdr !#"3 3!  ! 36_J ?89biVGej4T2#"5!5!3>53{9ˉ= RծP%#"547#5!3273ԢV-ؠv湯V4bn%!#"5732653!!Iݼsrǀiy8/quŚl# 533>54'7п _*jiю6&#!!>7)!!! ۜ ٽ3+dr !#"32!527&'! ! aUm}EI=a]Mv8"`_؀d"#327&%#;!###) 7bb6eeabe^tN4 LNhBZp!#!3!3!ѽr4fQJA#4&"#&32˲(۬TAnu%#"533273ҐM=űU5ax~&$=3326=#"533273~ս˶θ$!S98ȗX2%6&#"#3632χ/050y5#$!&# %73gu6wfranXx{ "3265!# !33!Ǜ G$P ;w4&#!!>7#!!#5!#!2p]9P~ҹ9{m{(d # 5332654%$432#6&#"ѿͬ]`yDeȪƋv#"'!!33263ϴ< ! ## #5!zk{TO_<G# 5!#!32653Gó Z^ѫ54&+#3!23X׾7bo!#"&7326554632#&#"}}5:#ÃL}<B%#&=#5!;3Ѿv ZtmfanR#&$3;>53RL[a^}#ǩP 3#"32654&#"3267+!!.546;!5!5>32EHPw=xXcahxZ֔յ~9]~}_h` dYZydDz¼d! 7332&53[]&"z~8<kԤd! %76'&53'!2YK/0>!<ACijAI{2HPZLi$%#"5%674#"'! 4&'326LҫES}*6w1(Wd(a'! 47&#"#&%'67$!26! # !2^NWue+ htzkof P(B Ԟclq/쬱zbd`! 7332#"#'! tX!71n?\od`"! 73!54'#53654#"#'! oI% ݪy=Z\ϿT҅h)! 7&%&326#"6\Z[FxL *qaqEtD'\ad`!263 ##"! #"32dh~eos` U@J(6dd`# #  \D #m8ZV! 73!54+53$54'3mF2( g)y>[Fa[d( j0#5#"#'#"#'#"#&%'67$!263263   C1Cm\`X^+ >fTo'd! !4#"#5! &' !2oIeٷzD&?! 1N//T-, jNY! )!"67 #32RfN0v{t{\n@  ;kd`##"#5#"#!263 /8WaV@~Y$3 d! 7332+53274$53[]Ǯ-mdȨHdi! 73325 '6%5%cWd9)*@]OruGvd###"#5#"#%7263 OާPvĶ[`KBbw+ IH@Q)M! 3!26573fRT|u]Zp %3! 32%#Zܸ:_\2)K[60~  ! 73!2&#"#4+'73263 nG{ RmWPOC0@]g[x(2d!`2:! 63 ! $=46326=4+5326'#"! #"32d]xcd렷PSԟa ]YeRj\wCD4soX7<\"qd! 7332&'"#'!3wU!#g2*>|?\K | Pd)_%67!263 #5#"#'#"#4'&PQ`[n³<5)5A)q+dN! 7332 4733673gQ|zӑkB_v?  ><(! !4#"&=6#53263 .'"325zGN~ZXR86zH9!? ,V5''5X4ʸMk74#"63 ##"#! ZtvNA%tG4SD9S`Z8A ! 53! +532'6&'3t{>@׭ `W(;Ƙnl=Wd ! !63&#"32[]\x4+G.BaX'!26;'"&=4#"63 ! 3 #&9RXZ~NG}+y4X5'(4V`G$>d%3!!! 733245#";#!3  ^[ V//UQK_ K+; ! 363 #"32bV`(/?;L#%#5265&/%77654&+532Q sQfV?LEDOR#\ՀxЖsp2Eš"%-4.-UAd'! 73324'#53256+53274$53aW((qegZa mV=EHqx'! 3324+53256+53274&53[]woqdaH x{mQY>EHqd`27$! 3&'6#"FRᑞߋTs_0sIKSzydd_! 73325#53$=#%Y_'ݵo#B&=ZZyu?d%! 733254+53$#$! 727_Z CM\WA^!)vTwd'! %!! ! 3#3!"3253!54#"Y^ arrr6fwwid9`$!"'!525#"!$!263 #"729Y`^H]Y'zSe"8Z`! %$54#"#'! ! 4'3676 bO4`V69"S+\PBh$43 32/7! 47$3254&#"PŽH=Few1(W~d dca54'&#"'67$% #7#";;_CC B|MKOm0T$,n' 3#3#3#nʺd\(2"4;!"4#"32JA{ntv2c`Lзh=@ B1/0KSX@Y %##.d+hK'Eh*hO'*t@1B/990KSX@Y sNO'*)tN'")u'ew^?1B/990KSX@Y 5](&xyw^O'*1t'56'&56'O'56O&E'E'EO'EO&O'*0'wE&O'wEO&w^O'*?0 3#!38Ygg`nC^^n7]^7nn7]]0d"&533265453zWA@XzCss!AWX@+!U#454&#"#462zX@AWzB+@XWA!s0U!5!2654&#!5!2@XX@s0{X@?X{0U 4&#"32>"&4623X@AWWA@Xz柟C?XW@AWX栠H> %'111 ]]1<203!3CC~K3#K!5!${1V #5#53533zz{{1##5!z$ %{{:'U'"'=wq'h9hK'Eh1hO'*tw^:<1B/0KSX@Y7 5wM40w^O'*)tw^N'")uw^'w^:21B/0KSX@Y%5^xyw^O'*1t'56&9'56&O'56O&'wE&O'wEO&'wE&O'wEO&w^N'"1u<291B0KSX@}}}}Y5`sbbs]103C)8)K'E)*@ 8AKTX8Y1  /<03! #4&#"!!ˮî$*\u)O'*tw^ 2 <1 /07! )5! )w5BhPa.,~w^O'*tw^N'"uw^'y` 2<1 /0%! )! !`aPhB5jiy`O'*"t&''&O'O&'w'(O'wO&('y'(O'yO&('~ ~21@  0# $54$!3#"3nn͙ nn{'|'|w}'dy'F> %@ 21@  /90"32654&"$54$32#Bz_̀#R3IK'E %@  21@  /90"32654&#4$32#&f̲_ȭT#R3{O'*tF> (@  21@  90%2654&#"3#"$54$3Bf̲_ȭ벃F>O'*t FN'"u  (@  21@  90%2654&#"672#"$53z_̀ʃIO'*5t#'F'?'~'|?O&~O&|' F& O'!FO&!?'#~&#|?O'$~O&$|?&~#~  $~ ]21@ 02654&#"632#"&53XP^J\TaaQ_VFTHUGQK})~J8 2654&#"03#"&54632xOaT\J^P_KQGUHTFV}i~F'x'F'x '#F> 1 /0#4$32#4&#"#fK'E< 1 /04&#"#4$32f#O'*t<F> 1 032653#"$5fF>O'*t>FN'"u> 1 03#"$53326f餗O'*5tA':F&:?'<~&<|?O'=~O&=|'>F&>O'?FO&??'A~&A|?O'B~O&B|?&~A~ ] ]1 03#"&53326yaO\T~JPML 32653#"&5T\OaQLMPJ~w:1/0!#!5!)+jK'EVj@ :1/03!!)ժjO'*tVw:1/0!5!_++wO'*tXwN'"uXj/jO'*5t[5&Tw'T&V'VO'WO&W5'Xw&X6O'YwO&Y'[&[O'\O&\&~[]10!!3 nC ~21@  0! $54$)!"3͙ nn{3!5 nw} (@  91@  20"32654&'2#"$547!5__ȘLӦnjFY 'iqFY} )@  91@  20"32654&'!!#"$54$C`^ȋMӑnj '*i<qw "@  91 /20%2654&#"!5!&54$32__ȋfLnjw'*<sw'"<sFY #@  91 /20%2654&#""$54$32!C^`șMgnjFY'*T<vH}'ow}';o3'vFY'yv3'wFY&wyFY'"T<v\ 2654&#""&546 !j>_IEcI_(0MJBSKFXCIn~|Q;n."&5332653ܨabaaJPMMPJ\ 2654&#"0!5!&546 _IcEI_>jm0(MICXFKSBJnn;Q|~w 1 /0%2654&#!5!2#bŘ쥒FY 'FY 1 /0%"$54$3!!"Cꏙƥ᪑FY'*<w  1 /052#!5!2654&᪑w'*<w'"<FY 1 /0"3!!"$54$3CbƙFY'*<H'w&;3'F&13'F&1H'w&;H'w&;3'F&13'F&1\"3!!"&5463RiPYnvDZHCn~}w^ %5-5 ^j22F  ? 1 /0!3#$53TCc Xon2K' E @ ? 1 /053#3  cCT-ncCO'* tF   ? 1 /0%#5%3# c--noXF O'*tFN'"u @  ? 1 /0%!#3#c-gCcnO'*3t'F'''O'O&'F&O'FO&'&O'O&&~  ] ] 1  04&+3#XHǜV+.#"#"&'532654'&/&'&54632Cw7Bh#-8GC>=JGBAm'./G?;=~ÇH)@@V\`RʺªV\`RʺªhZ·%XhZ·Fl632#4&#"#"&3326tҪºR`\VҪºR`\VX%Zh۷ZhFlO'*tF'32654 !"/.#"3"54!2!rz|K٬42 swUҤ'4X˧|`í~pX˧|`J3~F'*<F'763 #52654&#"# '4!"326(24׬'Uvr!24֭٣K|zsp~ȕ`|Xp~8=`|F'*<&F&'F&O'FO&'FU''FU&'FU&'FU&'>72#52654&#"#"&'463"326[*'sobI=J>",BR\*$jt_UV) '2654&"#"'&54632! 33265,B:d:B0<~JIjˮîB,">>",BVU_tjN*$u) '"2654&'632#"&5! #4&#",B:d:B0<~JIj!!ˮîUB,">>",BVU_tj$*\) '"2654&74&#"#! #"&547632(B:d:BB®!!jIJ~<UB,">>",Bu$*Njt_UV)O'*t)O'*tS^$264&"&546; )5! '&Vhf# fw_:@ 91@ B /90KSXY%4$32#4&#"!7g#ʲfhXdfF.=@ 1@ B 90KSXY#"$533265!>ʲf"fw_?@  91@ B 90KSXY '!32653#"$5g"ffd餗 K'; , '< , O'= ,;'>,;O'?, 'A , O'B ,( (2654&""&546323326=3#"&=bFntnPX/Q,CEmaZT:KMMKFHn|ppX;oBGj9$ 3>2654&"!&546323326=3#"&=!"&54632!2654&"bFntnP?+/Q,CEmaʔ/bFntnPZT:KMMKFH;XppX;oBGj9|ppX;T:KMMKFHFY<@   91B /0KSX@ Y!"3"$54$3!7YꏙbXhUFY'*<.w8  91B /0KSX@ Y!26544#!wb gXw'*\<0FY:@  91B /0KSX@ Y'!"$54$3"3!YhbƙXiU𥒥FY'*i<2\'%!"&5463"3!\=.̞RiPYB~}nDZHCw%#535!53!3##q=ԭ-!%#5#53!3!3=~0Ԥ!O'*t6w533#!#5!5#5q=-ЭԤwO'*t8!3#!#!#5353=ԭ0~!O'*Vt: 33#!#!5#53m unfy~n ,@  221@  /990%2654&#"672#"'"#3z_̀ٷ{O{ʃIH+'sZ@  21  /0# !3! !5aPh//+jiN !!!5!;VnVN#5!5!5!53!!75$i2$i*mւVxnVnՆu!s #'#37 ͉sH+'Y &,:s &-< O&-= 7&-> 7O&-? &-A O&-B!!!!#!YX  !!###!YX  !!#####!YX    H!!#######! \YX     !!#########! YX     !3!!  !333!!&  !33333!!e    G!3333333!!     !333333333!!      !3!!#!?r !333!!###!?r   !33333!!#####!?r      Y#!3333333!!#######!?r        +!333333333!!#########!?r         SC !3!!#!YX\\SC!333!!###!XX\\\\SC!33333!!#####!\X\\\\\\S FC#!3333333!!#######!ZX\\\\\\\\S C+!333333333!!#########!YX\\\\\\\\\\!33!!# #!՚rՙr %!3!!#!!2^DD^ Wc !!!5!5!!!wsX #5!! !!'!%'! !7%!77'7!  ww u||||||||||||u  G7+/37;?CGKO!5#535#535#53533533533533#3#3#!!#3%#3%#3#3%#3%#3#3%#3%#3??????𨨨!!!!aOq:#[!' 7#}CrarCrrD:[! !rarC}rbar=` !#!#3!ff`G [`3!!!!!!!! j /t`Ӕ&{o{4=J%#"'&=!.#"5>32>32#!3267#"'&32767%2654'&#"JԄ℄N ̷hddddj||MI؏ii~ST`Te__ZjkSR\]i߬A@o\]Z^Z5*,=>` #% 54)3#4+327#!5#53!2x9||ԙf_ڪrĐq{Fg`32654&#%! )s7F0Ǔ$g` ! )#53!#32654&+7F0ɖzٍ`` !!!!!! /`Ӕ|1#"&'5327654'&+5327654'&#"567632p<54& #.54! ì++f++$$>:#tNPƳPNM]*U3MY + 3267>54&#"'>3 '# 5467'7*(Ou))Hn.Mw834OMx43N)gA\*g>}66]C_56`?`q{&/=5!&'&#"5>3267632#"'&'#"'&732767276'&#"qN ffjbdjQGhi񈉉ijBN℄RR\]VVUVVVZdc44*,nmn67윜78lkpĘZYWWsttstuq/u{ 4&#"#32/8qu/ 32653#"4/8`!264&#%!2#!#N[cc[H^^>2`!.54763!##"#676#";jpkla;;?î545w?@@?w iQP%$q2^66**TS++2`!&'&'3;3!"'&546#"37545â?;;a|lkp w?@@?wS66^2q$%PQicQ++ST**<m``$ 653 &53sXٹ};ML+%!5!2654&#!5!#TZ`fcL||BtN5353!5!2654&#!5!#Z`fcxzʤ||Dv/{&#!5!2654&#!5!27654'&#!5!#|vz{\MN`_`gb>> E__ru99wSS?yzVU=`YV5`ZX`]x`73264&+5%5!2 'Ӏ{n Fo}ɽBdd>Jm7{3!!I{/=`N`#!#`I``Z^`367653#5&'&3U9VˆmmV9S`1Ms,}},uMLs` h !3#'!#ZgVXVq`!!!!!5!#!.AeW"___DXI &327654'&#327654'&#%!2#!g1221g̼^-..-^EOO)(N^h+&&MO%%X@? ]65dL.- rUpz 327654'&#%! )[ZZ[vNONN]eefe !!!!!!R-@___S !5!!5!5!5@-_/__H~$5#5!#"'&547632&'&#"326NJYXe|}}|\SRFFPOWWVVWCj]/rssr'y5UVVUL 3!3#!#΀2Wr3# 3+53265A@1(TFDE`Tli 33 ##-<azBm3!!_ 33###|{9="G 33##|_{EEG ##3G|_{EDEH"327654'&$  '&RQQRQQQQwvvwtww[\\[[\\[\vvvvuvG>@"327654'&327654'&'52#"&54767&'&54763sCDDCstDCCBR65<%j<=0ER^X65`l<=ca==ll*6RI)++LK,++,KL++5##,&)$%LY+8:6iG2278PyAAyP87'21I.* 32764'&#%!2+#Y0110YQQQQ))))]?@@?[ #'&'&+#!232654&#=)&''y.,,LPO)*s\^^\$ )(GTD<32#"&'#3t4554455$pMPPPPMp$uuc@AA@@AA86Z[[Z68^gG3#5#"'&76322764'&"Jtt%78NPQQPN874555555S^8Z[([Z@AA@@AAG#!32767#"'&547632&'&#"@AsC?>>>BADbc^]SSt44Va:: 2j88a WW[ZQRmT3210XGMK SX@ 2KSKQZKT[X888Y1@   /0Y5!.#"5>32#"&73267GsC}>?CŻthVau2koamTebXTb2&'&547632.#";#"32767#"&5476G&%HG{065>=f,K,,+*Ib]W-155_;65-9553+,$$4O,, ^$'U13 `fa<))R`1#"'&'532654'&+5327654'&#"5>32FLHG{065>=23-KX+*Ib]V.156_:65-9j2RQ,+ H4O-+]4$'U 12  `33a<))G 14'&#"327#"'&'53276=#"'&763253J44^]4444]^4PP=7633223r99$88NOPPON88$tm=>>==>>FNO e 45k37XX"XX7_z3#53ztttu 33 ##uuZu2u{"4@ $ #32>32#4&#"tHKYhuu'oMLl+yRowtHJZiw[Wk\sa97EBEB~wZXku4@ zx66X6VYYk\sa8BDG 6@ KSKQZKT[X 88Y1@ /0"32654&'2#"&546]ml^]ll]ǁqqpoWGu 67632#"'&'532764'&#"G0336^_]^:5311213p?>>?p3121 XXYY _ ?@@? G4'&"#46320T6667zWVoBAA@qWWG27653#"'&506667zVWoBAA@qWWu#3>32#"&$4'&"27uu$pMPPPPMpf4554455b_86Z[[Z6@AA@@AA#3#;#"'&5#5350Hww33UUPM,V-,vTPn3327653#5#"&nt''N^67tt+78Jy~{Y,-65\c`9nA!5!27654'&#!5!#Ue22<KLg#"FS10gg%dAl88u{(#"&53327653327653#5#"&Q+<=Rnxu$$IZ54t$$KY45tt(78LMlE!"z[+,64\c[+,66Zcb;F&33#&{{y #! !&'3254554#"t nυ9F}攥^ؙ83a _{3#5&+532{t<,||GXG+&#" '&54767&54!232654'&'&yAJZVWVWW!/bL+"766^]l9=P(r(B4?KWXXWr]$,O'(@?Ajp69G  )"27654'&'2##5"'&5476734 )=;67-!XQVVQs~SVV@h)%661FQ:5}t?3XJOZUUXR=\ ,Ajq@:%'#&+53;'&^sa,(^ra,GX]:DFYzg Oduudnsd&sdyodsdy67632#"&'#44&#"326&_%sNo%ti\[jj[\i92ض78"{qqrG xd%tdV{(!2.#">32#"&'#32654&#"aQQR9||9F,*[cbbc#Lt`5!#3#3!53#53t𰰰त T2V${"+%##533>323##"&!3276!&'&#"s:{ˀf t{7JTTJf>TT>̪daÐꕢafttf>VttVV/%+53276'7#3/F0j&*06G#367632#"'&$4'&"27tt%87NPQQPN78f5455554_s^8Z[[ZA@@AA@@Gu&'&#"32767#"&54632u1122q>??>q22110h;533` @??@ _ GKu+325&#"47&'&54632&'&#"632#"Z%0\R@5`$^4412/412q>??5{3 * &;/Z ` ?@@biG.&'&#"32654'&7#"&54632''7'37 i:;n\[nO$$ZY drP =67Tb1#"'&'5327654'&+532654'&#"5>32N+,QR2658-56:_651.V]aIV-+K-32==l/|GHL ))unn77wU:8P#P,i/0\+53276=#533343r,Brrtn x66XU P#PG ,5#"3276#"'&'53276=#"'&54763J]4444]^44tPP=7633223r99$88NOPPO>==>>=۠NO e 45k37XXXXn3327653##"&nt''N^67tt+87Jy~{Y,-65\cO9I 5333##53#Irtggttt\\jz~ ;#"&5C,rfpUWlwI 5!#3!53IMjjo\\E\\I5!#3#3!535#535IMjjjjooo\\\\\\V`3#"54;33#'#"3276ztteztry "3rKNB ,|ssW?#5$ z~3;#"&5ztC,rfSVXlx[`+53276'7#3`34r,Bttax66XS gq3!!q_u{467632+53265&7454&#"#4'&#"#367632+=32#4'&#"43r,B0t*pJz>?t'(N^66x66X6V~a88BDwY,-56\uU 4'&#"#367632;#"'&5P''N^66uu)89Jy?>0B,r34Y,-56\sa8BDzV6X66xq 33##q-{{~G 2#"'&5476"!&'!3276WVVWUWWU6//1w &6^]6&WWWXXWWWW@9\[8E-AA.G&.#5!#3!535&'&5476767654'&OpFVVFp^nCWWCnt6%66%4#76$\\FWWG\\FWWE[*,ApoA-9*A@+Fa:.#"#"/;#"'&=32654'&/.547632;1j8W*,]({44MN9> 0Br34@?>=RX l)k`GF@rb/$+*MW33 V6X66x"j2-*TIX00476;#"+5326z73zno>43r,B0]Me30U:Jx66X6#3#;+5326=#"'&5#5350Hw43r,B033UUPM,ax66X6V -,vTP^!533!33##5#"&=)3276^ntgtuut+87Jy~''N^61\\`9Y,-6/G&5!327654'&'5!# '&54767GE()78Z[78*,?G$"ZYYZ!"J\{':?KY7667YR8>#{\8?>LRRQRR<=:u2653#"'&53QHuDEEDuHPZs{>??>{}ZPz3+"&53?27654'&'&gH#"YZ,rftA Z87)2:08?>LRRlwpU67YQ8C&# #3{{ s7n !!!5!G'L\^=R^7!!#;#"&=!5!G'LC,rf>\^=R VXlx ^7^n#47#5!5!3632#'3254#|`\'Ln& m,7!!^R^=jR37!2#"'&'5327654'&+5!5!hCQ>63``;??C5~Ex>?::hn\& =;M|CD m**PJ*)]R^G !32767&'&"2#"&76So/6^]6/ +66,ǗWVVWVV*MWXMmGYXFovw^wwwv[f!5!73[f3!Px[f#'!5f[f!!#PU騋fBf 3#'#35fxBf 73#'#˴fxh'${-{'TDP'*u%R'>E&%&E&%&Esu'l'#Lvquf&vCP'*u'qZ'uG''qZ'fG''qZ'fGw&'z[quZ&Gz''qZ'fGZ&([q^'[HZ&(Zq^&HZK&(7qK{&H7v&(qv{&Hum')u&(zquH&H'zK#O'*vt)/'uIs&*2"qVZ&JI;N'*s+dR'>K;'+d'K;P&+j@dN'>Kt;&+ztd&Kz9;&+ 9d&Kv&,Jvg'LYZ&,XtF&Xajl'#v.l'#ZvNj&.&Nj&. &Nvj'/''O jk'*u'/S1'q(; 5j&/J'Oj'&/\'&Ol'#sv0f&PvO'*wt0'P't0{'P3P'*u1d'Q3'1d{'Q3&1d{&Q3'&1d{'&QsZ&2`fqu &R`sV&2^lqu&R'jo$rsZ&2[jqu^&R[sZ&2Zhqu^'ZRl'#v3Vf&Sv2O'*t3V'STN'*s5J'UT'}5J{' UT1'q}; XJ&q YT&5TJ{&UO'*t6o''V'6o{'%Vm'#v'*6of&V&VvW&_6o'-#O'*t `o'' aO'*rt77'uW'q77'W&7b7&W'r&77''&W)'8X{'{Xv)&8vX{&XK)&87KX{&Xu7)Z&`.8X&+v)4&V28X'VXh}&9F=7&Ymh&9=`&Y^Dr'%|:V5k'C ZDr'#|:V5m'vZDN'j>:V5'jEZDN'*s:V5'GZD&:V5`&ZJ=;O'*s;;y'b[=;N&;j>;y&[jfP'*ru<=V'`\\m'&u=Xf&]\&=X`&]1\&=X`&]d&KfN&Wj->V5&ZB=V&\{a&D/'uA!#'7#53546;#"7Jݰd&&KhjN()gti/!##535#53676;#"3# GWd&EFV( D7&#"#4>32"#"'532654.546m@f_@&9dc07CjjCӴmob)F[dd[F)Z@hoϋ\(Ž}_-C-->T\_EFvX5P3) $2BgCquIh'${-{'!Dh&$u{-{&DTh:&$a{'aDh:&$b{-&Dbh[&$h{'hDhu&$c{-'cDhm&{-f&"hZ&$e{-'eDhZ&$f{-'fDh&$g{-5'gDhY&$d{-&Ddh&{-&3&(q{&H&(uq{&H^'$u(q7'H:&(aq'aH:&(bq'bH[&(hq&Hhu&(cq'cHm&qf'& Z&,#uD|& &,.y&Ls&2'qu{&Rss&2'uqu{&R}s:&2alq'aRs:&2bjqu'bRs[&2hjq'hRsu&2cequ'cRsm&'quf's& sgk'#'ubvf&vscgk'%'ubvf&Cscg&b'uv{&c}g^'$'ubv7&scg&b'v&cs)&8X{&X{)&8uX{&X}_k'#uqif&v{r_k'%uqif&C{r_&qui{&r}_^'$uqi7'r_&qi&r{r&<%r|=Vk&\C!'v<=V`'t\&<r|=V&\`^'$ru<=V7&w\ 333!!+ժ 33533#####53มม}}qa&F pqa&F Hqf&F qf&F qf&F qf&F qm&F vqm&F Dha&' #ha&' f'' |f'' Ĉf'' SXf'' om&'1 Qm&'x Na&J Da&J 9f&J f&J %f&J Of&J R-a'+ -a'+ 7f'+ |If'+ Ĉf'+" Sf'+^ oVda&L Vda&L Vdf&L Vdf&L pVdf&L Vdf&L Vdm&L Vdm&L a'- a'- f'- |f'- Ĉnf'-3 Sf'-d om'-t Qm'- Nna&N na&N f&N 'f&N <f&N Qf&N =nm&N nm&N Aa'/ 5a'/ Kf'/ |Kf'/ Ĉf'/4 Sf'/p o"m'/ Q)m'/ Nqua&T xqua&T nquf&T equf&T Tquf&T quf&T a&5# Va&5} Of'5v |Yf'5 Ĉf'56 SPf'5w o*a&Z =*a&Z *f&Z '*f&Z !*f&Z `*f&Z W*m&Z 8*m&Z Ia':b f': Ĉf':6 o3m':L N'a&^ ^'a&^ T'f&^ Y'f&^ ^'f&^ 'f&^ 'm&^ c'm&^ ^a&>N qa'> if'> |uf'> ĈCf'>t Syf'> om'>B QPm'> Nqf&F tqfAf&J TfBVdf&L VdfCnf&N fDquf&T {qufa*f&Z 0*fb'f&^ M'fcqVa& HqVa& HqVf& HqVf& HqVf& HqVf& HqVm& HqVm& HVha&  Vha&  Vf&  FVf&  FVf&  hVXf&  Vm&  Vm&  2Vda& 8Vda& 8Vdf& 8Vdf& 8Vdf& 8Vdf& 8Vdm& 8Vdm& 8Va&  Va&  Vf&  Vf& ! Vnf& " #Vf& # TVm& $ dVm& % V'a& NYV'a& OYV'f& PYV'f& QYV'f& RYV'f& SYV'm& TYV'm& UYVa& V \Vqa& W Vif& X Vuf& Y VCf& Z Vyf& [ Vm& \ PVPm& ] qH&Fzq&FqyqVf& ^HqVy&FHqVf&AHq7&F nqV7& Hhm&')uh1&'q;f&'B RhfVh&' xa VxaH <ܲ?]1 Դ?_]KPXY̲?]90IIPX@@88Y#55#53xgJ7FJm'$jVdf& b8Vd{&L8Vdf&C8Vd7&L Vd7& 8f'+b Ruf f'-n Rf!V;&- f'   f' . BJm'$ nH&N$n&Nqn&N .&x7&N .zm&N 0gm&/).uY1&/q.;f'/q R}f"~f'  f'  _Jm'$ *H&Z'*&Zq$*&Z *EVa&V Va&V *7&Z '*m&Z m&:)vu1&:q;f': Rf$5a'7 F)&j lFRfCV'f& jYV'`&^YV'f&cY'7&^ OV'7& Yf'5; Rf#f'>D Rf%NV&> sRfvxaH ܲ?]<1 Դ?_]KPXY̲?]90IIPX@@88Y53#7"͔gd10!!dd dy/10!!dOydy/10!!d8ydy/10!!d8yy/10!!y&__J&BBB@ 10#53ӤR?@ 103#ӤR՘?@ 10%3#ӤR@#5R՘?m '@   1<20#53#53ӤRӤR??m '@   1<203#%3#ӤRӤRլ@@m '@    1<20%3#%3#ӤRfӤR@@m #5!#5RmRխ??9; '@  YW Y <<1<203!!#!5!oo\]9;>@   Y W Y <<2<<2122220%!#!5!!5!3!!!oooo\\3!   \ 104632#"&3~|}}||}3q31/073#k1/<20%3#%3#V #@   1/<<220%3#%3#%3#ki3#iq L #'3?K@D$%&%&'$'B@ .(F4 :&$L%IC'1+C =  1 =I 7+ ! L9912<<2220KSXY"KTK T[K T[K T[K T[KT[XL@LL878Y"32654&'2#"&5462#"&546!3#"32654&2#"&546"32654&WddWUccUt%ZVcbWWcdWccWUccܻۻۻۼܻۻ q r "-7;EP\"32654&'2#"&546"32654&'2#"&546  &54%3#"26542#"&546"32654& WddWUccUyWddWUccU<¹ߠZucbcNWccWUccۻۻۻۼ5ۻ(`3(`u(`&  ,(`' ,&  X(`#3W`u(`&  ,(`& ' X , #'#Rs#G@%Bon29190KSXY" 5s-+#R#I@&Bop<9190KSXY"5 +-#^R^  &K'N''=NO'^O$#5>323#7>54'&L Za^gHZX/'-93A% #C98ŸLVV/5<4BR-5^1Y7| B_ % ij991@  <202$7#"$'56:<hh~vvuw~ign % ij991@  <202&$#"56$6;>nvv~hhgi~wuI3 # #bbc$$v=' {' { 3_!!V_+@B10KSXY"3#-\X 3!!#3hX^#"#JX 53#5!!53X^JݏޏJ&""gJ&"JJ'^"d] 7 91@ B  <20KSXY327# 'du](; 2###׎辸( 3+"&5463yv}~}|( ';2+v~}O|}=k {B# #5#5R#۬@n& " #=o'  BC''Hd1#"'&'&'&#"5>32326撔 錄ܔ撰 錂1OD;>MSOE<>L~ #8| #'7!5!'737!!qaqqaq)`rrbqr2 535353,(`$' ,& '  XfN 53!535353fXp fN 5353535353,p  3#3#'d 3#%3#3#3#dipD %53535353#!5!3!,|f  feP> 3#3#3#>w 3#3#3#3#W "27654/2#"&5462332233VVVVVVVz@ <<1@03#3#zttttg? @   ] <291<290KTKT[KT[KT[K T[K T[X@878YKTKT[X@878Y@T /9IFYi       "5GK S[ e]] !33##5!55bf]myf !!67632#"&'53264&#"y^^a`<~B9>>Eoo4h6_ MLKJq ff\/"327654'&&'&#"67632#"&547632X3333XW33331221DD &9:DTTXWll122m45[Z4554Z[54bg KL1LMONuv l!#!liH30Y *:"32764'%&'&546 #"'&54767327654'&#"55j]\655T./RQ./SZ85UVUV56-/.UQ100/SS0/*,+KLV,++]12Hdt::dJ01:7PyAAAAyN98?&%%$A?&%%$S.532767#"&547632#"'&2654'&#"1220DC #<9EWXWXkl122Xf33XU5443g KK/MNoouv rh\Z4554Z\44k !!#!5!Q_i_k_8_83!!'3_a!!!!''^_o #&'&4767TRRTe^///._~g3#676'&ge_/../_eT)**)~~~u0@ 32tNN^luu)qJy}wYYk\sa88WT NdC{d^TtdbTud?C PdfC Qd\T RdlC SdYT TdST Ud Vd8 Wd  Xdoif Ydgif ZdMdGdGdu!sdGdugrdugdzgdu{du [dudud#%dV##"32.#"3267!!!!!!Oc%eNLbbL:/667756GFDFG ks9'.473&'3267#"'#7&'#7&'&76%73&'hA>/(%:@w]ayA9&AX}R4>C5Ai<)^_HH?WghйKp(`,%6767# !2.#"3>32.#".aXj]aye6{_]w|^0n&<$'/_HGghGG_^ٜu]\Y!!!!3###5qZpP~WHE9Eb#!!53#535#535632.#"!!!5-쿿=OL=tyB_))HB+#&'&#"#3676323632#4&#"#̪m49wSS>YXyzU6%X\xruxGM_a`f21>&>E3\""&)''#!333#3#!###535#53355P8ĢĢ8PP4&{{&&{{{ P32654&#+#!233!!;532654&/.54632.#"#"&'5#"&5qzzWQeGl`[z_<`HJU];Ufɘ/ϒjqqR>N#55YQKP%$((TT@I!*##`3E326&##.+#! 32654&/.54632.#"#"'&ٿJx}A{>[b`cae@fLNZb?ĥZa,/b؍$~3YQKP%$((TT@I!*;"&)-1'#53'3!73!733#3#####5!73'!!7]:1000019]zu }Luuguuguuuu_ % #4&#!#)"33!3_SV*$oNq&1@: "+ /) 2+"!)#&  , & &*!/<29999999999122<20K TK T[K T[KT[KT[KT[X222@878Y@z  1Ti lnooooiko o!o"o#n$l%i'i-  !"#$%&'()*+,-2   USjg ]].#"!!!!3267#"#734&5465#7332[f A78 ʝf[Y`(77(6bbiZȻ{.# .{ZiHH"{/ #/{"G(33!!###5uX_Tws1s!5!!77#'%5'&PPM4Mo؈onوn9 -bw'67>32#"'&'"326767654'&'&67'>7632#"'.'&/#"'&54632326767654'&'&&#"32">1aJ{%A01Q[W7>/W1   >$<  . #dCw-^URB$`>DL_K>.3b @N\uLMiI(S395l9,8G(/&  -9)ЗiRm:3Xwdg7? 2j7#=5(6$ 629T/ (2M !:5S}$@{mbq~Es/4 -& "TAB`]|@8nRkcd]aC".)5'632327&547632#527654'#"'&#"%654'&#"o|@X"07PYtaTk~j[IwmqJ2530D#24!`NkBX``S㫣†qJ323!!!3267# $547#5\J5 ;_srigCS1r{jJ,{ +kv67&&UB{\* {;^~FE/0K?{r*.#267#&'&576753r\ee\Z\X[dtye]X\[CvlCiZZiH$"v9Bt"$CuflC !!!!#!ժx j&7!!!##&'&+532767!7!&'&#j77O57=A}A=;AٿKDFxJD7-JZ{{N{~U]$HDh01C>r{C4X !#'%5'%3772hN4L4PP~n؉noوo.C!2+!!##535#5;2654&+ *⦦ 3!~d=!5!'3 G~d=z!#'73!5~~͛=z5!'3#7=~~d͛{ 3#%3#%3#yfP{ 3#%3#%3#%3#ky)=z #'73!'3#7~~<~~͛͛C $(B"326=7#5#"&54634&#"5>32%3#.#"3267#"&54632pSHfmƩogDc\GD^o8yy8o^IICBRCI M >OW\ 7$44"C +EI.46'&#"#&'53254&'"326=7#5#"&54634&#"5>32%3#VNz$p;i0ʪ%={pSHfmƩogDc\GD}|49d$, !5Lf,1BRCI M >OW\ 7$s'!.#"3267# !2'Y藣yyYjzS #bvAZ4-4ZBuHHghG[!!m&r&F+,/-/ܸܸ,(и(/A&6FVfv ]A] и ии# /!"+!0153&'&'6767!!5&'&76wI3cc3I86QLNN7887NNMR48_ki:rq;zn #++$ * rn<(2.#"3267#"&54632%3#"326&$  &54^o8yy8o^IICDkavva`ww~44"K <M-1332653#5#"&.#"3267#"&54632%3#\QPcu`^o8yy8o^IICDLriuD P44"K{Ro#&&r)Io!6767632#"'&#"32767#"'&'&547!#"'&54632327676"#"'&'&54767632l(9BKc{=&%%03!((!,739%7`lG;7 25]hB4,'5  'B[QF$%]c'G  %! }Kr~,1ьIg)*!&!(D;w},75;!_']7:y}[Ϟ\@4>#,!, 'QFj(JG4$$,*)/9yK#%P73276767654'&'&#"&'&"'632654'&'&54767767#"'&'672#"*i(X%# 1FSE/ O.55FuPU[QF[00rl~"KI}!;IFs;n;_T^͌Q79}w^l.Gyr\[4O9%#i#^MX;yv@c}e.ID\7I;>2V秉uӰ3!3%!!!!!!nnq  dx+%H#>54&#"#3>32u j_ y/wFx \/HT^Ȧ^m$RZ3%632##"#'7-P4-> {|a\=BcL;t9#"'&5476323276765"#"'&54767632thn<7# ;KQ>!|Za,4(XM!},‚<7D9#7.M=.1?@ '(MXI(' jF!2?632327654'&54?#"'&#"632327#"&#"jou9!ydG>PPPP5ʺ68^nm{z}}ȋo֏zZ'PVaK~pmdykb^OP681/::b:DnJ327654'7#"'&'$#5"'47676766767632#"'&'&'&#"32nZS_n0VBRny#HB?X!$9BMw>7l. ;7%,;(ӧuy,D0&3273#"'#67&5477632654#0)W:K32#"&'####53&  O:{{:ܧ$}daad}j %# !3!# dX0dd q+6+/BB/,/<-ݰ.<-ް#? < # 9 FhH)##Ii;BB=#IbiF`FaC`#BC`CUXC`C8Y& <BB00<İ< 6< <9 FhH #Ih; < ְ ݰ,9, FhH &ְ& #Ii;/,#Ih:1#IC`#BC`CPX& ,/C`C8K RX #IC`#BC`C@PXC`C@aC`#B C`C8YYYBB=#IbiF`FaC`#BC`CUXC`C8Y#)<BB1#IRX   <  < Y3525!463"!4632#"&732654&#"5!6jgggg92299229k̀k@4nNggNNggD{{ "-! ! ! ! '32654&#%!2+# JR12)uyӲckkc?L00ey wXQPXdn;C0<67632#"'67327654'&#"#"'&57&547276545[ۄFIyeL )qz]E& JEYq:?.蔁0.A ƂMkeLPק<+(h|H=y|n=B {u.F/4_NT 33!27&#%!2+!67654'&,d.@nX<-]\,q jdZ)VV)s!)%#'# ! % 7& 676'&B 3y;:x+lllli$ #ab[ 2222jT%%5$c$B2 _327654'&'&'#"'&5476323276765""'&5476!6?232767#"'&B=]iS\ZV30Fn7;#FfS9!!< #5,h";<2XngZR{,##9>;K!QIag£S D5@7*'S:y}*7H0 5#!,Il @3Xnh0{(2r:=OSlIX&54'&#"#"'&527654'&#"3"'&547632763227767654'&#"R(O*\xggfg-.@@?@@?\QA@@@S6fggfeӻp/$~AB}:1$ -*MJJ@f[+8vuuv zVWWWXWWVVW\uvuuu# bW1W{|^1$h{vC[SK\GChfy /2 &.2&'&+3!.+!! !27&#676'&%3LDEx-Me5q>HJxnu1EA+ZY*01/O~hbb)j)V>U)-  /!/ и/ ܸи!ܸA]A)9IYiy ] и /9 ///+ +0132654&#+#!273 # #s sNCI/ϒ_6۬kk%T$+.3&##&'&''7#!27%7 67654#?\A>:AٿKE6ToF^~_ ,8~|T3Jۏ/HDh0& ,ok؍]-Dbg('4.#"#"&'532654&/.54632733###UW'AG/E8pi4sG[d/EK7?8pc|3iиY"*/( VAO[`*,2,* M=H\T(l0`!!#!!!!!!!3!!rso+` `ffff'F >@!    b b cbc91<<2<<903#######5Jq7rqr/B^^"h %73# ' 3,o-MoF+,\ %#!!!5!8kO8d qddd XL/ 654&#!5!5!5!!2!"'X $''ߦԧc̆eeaԊfJN>NsDU767654'&#"#"'&5733272632632!"'4'&'&#"'6763232767654'&'&#"_}yj#1Q\$####,TGG\n#?QY>kDM4giMqE#"'&'&5476?&'&547632#"'&547654'&#"3"32767'_ilE_ml=Oc{T3-2") %+fa@aP/Z_|{w:maZu> IhA"%@_l$=PczS2VN-2!$+%$+@e}N069na[u>_T M#"'&'!#!"'&547632327676=!7!&#"#"'&5476!27327#X':'7?<=**M_4. B^l{>!'Ba>nG#&#w4$B00!K=DcK_4B( 03B{>ceDInFT=I,Fw7K. 0# )5!!5!3#Pʪ9Bk32767"'&'&47'&'&'#"'&547632326765&#"6767632377632#"'&'&'&#",5(.'*'E`97y{7a;f7;>F3.^PeMD*#7@,j!HhH<=.%_yipp3 T}B',$ *5܀/,,@!;Da97TVM;nwF^O?/,%!;>jytX<;}f?E'_n H''#  .hJ) 4&#"322#"&54WOmVPm˜ݢt}t{أأg4 4'+5654/&4?'&547 '&5474/c2>Bd=VE/b5c2ltc2c2uc1LS2?Bd,>8?]/c6c1LS2tc1LS2c1LS2903#!".54?>3!4'.#!".54>323!2O,""$%@;5H *Y[#$"x2 1[G(  WA,!2#"&/#!"54?>3!!"&5462TPl 0%= -d,mF"$mG- .7#*(/ $"Sae(!q~B;V&!"&54>323!2#"&'&5 mG * 5G 0%9 . q~( 0 (/ &Js!S'DQIF 4632#"&3!53#5!pQOooOQpoTQooQOonuyy5yZR; ! ! ! ! HH#[[breH !#y;:x L`  !!!!#!3#'!#33 # #DjwZDZ֏R``C5MR.}$z`-1%5"'&'&5#2327#"'&5#!#"#463!#3#, 9Yl(Ht*=Z2dr!Z4@'!8 ֦zEB bLs{dYsZ{3#"#4763 3׮UEEl4FũdGQnCF\xB*WbOZ=0 3%!!,:*nq dd3!3!!!! nn8q  qwS ! ! !!5 5Y*dccS!!6$3 !"$'53 !"kJu^uopkoSUggHF_`2/.2%:1/0!#!5!)+:1/0!5!_++!# #3bef9WJ " )327&#!3676654'&|tK"P"coAfյ|cv~dAA xPfUmZ #2!7#"547632!3 32767654'&#"* 6B8wx!Nbb|˞"#>|OO'vN 2wx87tKsO=  =d01 PD10d^dTd6Jthi[{ (232767# '&5477632!7!654'&#" N&#G_yZ\klmk}Z5fF 9NJC0<7h:J(u*oDMcFPZd82vRsO 3#3#!!ɸ.Ԇ$N9`V 3##676#732767!ɸ.fʆ#5H2K1i0/N)deеT0Hd01``;&0 #473>32#"&'532654&7>54&#";Ht]h202޸SUWDi;2[UԠ_I@Yr~YW׀c?}<$$/1oX3gQX?@Q` $@   F 21@/0!5!!5!`o`' '5&{ Sdt' '5&{ Ud ' '5&{'{d NdX&{' '5ud^X&t' '5ud^&{' '5 Qd^^&t' '5 Qdb^&u' '5 Qd?^& P' '5 Qd~&{' '5 Rdf~& Q' '5 Rdw&{' '5 Tdbw&u' '5 Tdfw& Q' '5 Tdlw& S' '5 Td&{ '5,'&,,&,',,(Q&,9h9&9,,&9',, &9',',,-&,;=;;=&;,=B&;',,j/s'&'0yL&LLpY&L'LpLA&LY=`Y=&YLD=-&Y'LDL=&Y'LD'LL$J&L[;y`[;&[L[;D&['L[LyOq{FqZG{Py }  ) !3 !## !5hPPh55~ji.,w# + ++ A]A)9IYiy ] A]A)9IYiy ]%"+++ + 013 !#3 #32654&#! )5HHNhPaY.,职~y }(1C3 +3 !32654&+! ) #"35# !35#"&546!`HH5NNPhthNN5H/ó., ji~s'H{sV'.# !267## !2'ff vzSb_^^_$ghGWX' '5'ud Nd?8   2@ @@ 00 ]1@   990@   <<@ <<KSX << Y5!!dx=xUZxx @   991  2@ OO ?? ]0@   <<@ <<KSX << Y3'#'-Zxxvx<xuP8   2@ OO __ ]1@  990@   <<@ <<KSX << Y'7!5!'7Pwx=xZwxx @  991  2@ @@ PP ]0@   <<@ <<KSX << Y#737Zvxxx76767632&'&'&#"#"'&/#7!#/)85,0F"<;NJX[GR7<"#!2)85,/$#?2WG[XJN;?,!F0O<:" %7xxUZxaxxaxuP8 '7!' 7!'7Pwxx>xaxUwxx>>xxwd?8 !5!3#xwx-xZxY %'3'!!5xZxZxvx檪uP8 22@ O O _ _ ]1@   990@   <<@ <<KSX  <<  Y!#3!'7'8窪xwx-\xwZwx !5!!7#7\xxZxx+xvx7!!5!7'3'xxxxxZxxvxxvxd>%52#!5! 767>54&'&'&>42/+-+-':1 Hxwxܪ-)o=  xwZwx(.46<=69)-d>>3276767654'&'&'&"5476767632+#5!5 6 +/24>A1:'-+/24>xwx  =69)-(.46=<69)-xZxvP>54'&'&'&"3)'7'7!#5#"'&'&'&5476767632# 6 +lxwx>42/+-':1A>42/+ׂ  xwZwx-)96<=64.(-)96=dP8X#532267676767632267676;'7'7#""'&'&'&'&'&""'&'&'& xwx 0$#$   "%'-0$' !  ' '- xwx  ('Z&("  "(&Z'( -xZx$ -#%"&* 'xwZwx ""&*  *&"" dPF%'!5!!'7'7!pxwxpdxwx^:5xZxo:xwZwx* %'7 !^ b9YXxbZ  #!5 xwxoxZx[ !'7'7!#xwxxwZwxZ  !5!3 ixwxDxZx[ 3!'7'7xwxDxwZwx 7#7!5xwZwx=xwxd? !5!3?=xwx-xZx,-eX&7#754767676 #4&'&'&"9xxZvx.-\ZnllnZ\-.BB54'&/#7!!#"'&'&'&54767D !BB54'&x\-..0YXplgtTY0../Z#,@#B"!BB@RNJV]xwx]TQ>]xwx]xLii `iiT4]xZx]4]xwZwx]JiiiiuP8!7'!7!5!7!'7'7!'7!5giiyYuI0]xwx]uIiixK]xwZwx]Kxd?8!!5!!]xwx]7Qix]xZx]xi#'3'#'x\xZx^xhP8^xvx^huP87'!5!'7'7!5$iiQ7]xwx]iix]xwZwx]x737#73jhx^xvZxx\x%hh^xvx^8dP8!7'!!5!'7'iili\]xwx]]xwxiii]xZx]]xwZwx7''3'7#7iii]xZx]]xwZwxliii{]xwx]\]xwx  #7!##PU?,UvU,?UP5#'#5!#5'U,?UvU?ԄU4 753!5373U?ԃUPqPU?U 433!'3ɕPU?UqPU?,Ud?8!!!!5!!c$R&xwxxxxZxxuP8!5!'!5!7'!5!Q$܊xwx&RFxxxwZwxxd?8#''''#53777?(FncxwxFn-FnxZxFnuP8577773'7'7#'''unFxwxcnF-nFxwZwxnF3'!!!!#!5!5!5!'-Zx((ت&&xvxTrx#7!5!5!5!3!!!!7Zxx((&&xxrTxd?8 5!!5!35!dxqxUZxxa 3'#'3#3#-ZxxbvxrxVuP8  '7!5!'7%!#'#5PwxqxUwxxw( 737533-vxxvxrxv4k?9 !#3?xvxתx~\xuI9 !'73#'7!uxvxxvvx7?~ 5!! !!  d }*^V 3! !!d}*p  d HP~ !! !!    ^V #!# !!!d e n ^V !! !3 3!!!E*dr*r$| \d^V )3! !3#!5#3 3 ȃ\Pdx @t %#!5#3'!3!3! !33'ȡdxd:tZdd\nt^V%#!3!3! !3!5#3ĹtIt\Px^V%3 3!!! !!3 37r*kd d| ^V %#!5#3 3!3!! !!33 37ȃ:͊` \h u}~ 7!! !5#35! u\Pdx f:bȃ  zM!#7!!#Mc"?,^xc?x^zM35!3!5!73zpc?Jx^cr+a?^xJ^V 3 3# '! !! !  e   dCuP8)5A '7!"'&'&'&'#5367676762!'7$"!&'&'!27676Pwx 21@=:C.2  21@=:C.2 _x_R#)l$h$#R#$Uwx@21.2@@21.2@xw#w;' , utP'7!5!'7!5!'7!5!'7Pwx===xUZwxתתxwZd?D5!3!!#!dx3xUZxmmxuPD '7!#!5!3!'7Pwxͪ3xUwxmmxwdPD3!'7'7!#!5xwxwwxwxmxwZwxmxZxd?D5!333!!###!dx⪪YxUZxmmmmxuPD '7!###!5!333!'7PwxYxUwxmmmmxwdPD333!'7'7!###!5d xwxdxwxmmxwZwxmmxZx7?@  !JBJAu}@ 7'!5! PJBł}BB7}@7'! ! 6BB A}BBh %!3!3۠ՈR+nm+A&6FVfv ]A]+ +0132#&'&#"327673#" B!OO!BzcI7͙7Ic_L 0"'&547632654'&#"563 3276767&#"\m`cu\6% GGnth r5?,/H@3H5,Y:$UeI+HQ\N,tqzSd69->eSY׮l !5!!5!!5>+5!#7#53!5!!5!733!Kcd04+^^``k](673#"'&'#7&'&$32 '&#" 32$767&'&YjiEd80~i?/c`RQQ$g'-"SRR:;nSz_'BTc_ N@DROg`8@91/90@cmpxyvn]] !3!^DC?`%! !3f<?I!!"$54$3!!!W?JGcGK@ sJxNL``ȟMOx]I&/!!!!3!!"''&'&54$;7#"ؖI$$$GA?d`,,cFU;}YI7ʟ 7c``JxH NGx]g% $54$)!!3!+*(FiNv%FrO:0QI&'&'&'!5!2#!5!676767!5?JGcGK@ 'JxNLȟMOx]I&/'7!5!!5!&#!5!2+4'&'&'3276765 I^Q$$GA?d`,,#FT;}YI7ʟ 7c;JxH HNGx]g )5%2767!5&'&!5(*FiNv%FtFgP:1R, //01!!,wq@gg120!#!# }wq@gg1<03!3wJ}w; ]@    91990@0QVPZ spvupz  Z pp{ t  ]]!! !!5 7AJI3!-10!!ת !#!5!3!!5!--+}ת W+и и и / + +и 01!!#!5!3#-Ө-5B<%?P%73% %#'TUUTUTTUDGrXY %=} *@    91903##'%\sB}}`s-Pb;=v& us=e&  Ps 127#"#"'&'&'#"'&547632676;#"3cd3668+MI6641C;ItY^^SI6?+((C;ItK@tkHMfpEF?$Tx5@ejre!93Ex5@#/;&'#"'&54763267632#"'&%27#""327654'&1C;JsY^^TI6?+((C;JsY^^TI666cd3778s~d3778]$Tx5@ejre!93Ex5@ejreMHMfpEFHMfpEFI%!3!~,I%!3IfIA//+к99к901%&'&'3!!#4'!&'7`'JAW`LqR]+X* Pʋs^(Rs57756u5 +  // 9 9 901 7&'7%%'6 676r{EG%y44RW!L!$Ҿ &!L {JP+3#+fJ+ 7+и//9 90137#'PMVo)gnJ+3#3#@+fJ+{//и/ܸи ܸܸ и и// // 9 9 9 9013737##'[P]ME+qd @oxpAn!3# ih^T3 3##"T^32#4&#"#P(*7332653#"RP7*uM>2&#""&'7327~9GA~9G⧅}}uM&  %uM& ' % JuM-6?67632&#"#"'&'7327&'&5476767654'&'SOJMG79GcBnnVsSOJMG79G]InoSu=,EG%,=,HK%DAF7K|oUDAF71IosV/HgjG$4.JhgH$uMMQZc67632&#"!67632&#"#"'&'7327!#"'&'7327&'&54767!!67654'&SOJMG79G~SOJMG79GcBnnVsSOJMG79GSOJMG79G]InoSu~=,HK% =,EG%DAF77DAF7K|oUDAF7$çDAF70IosV!.JhgH$+/HgjG$uMmqu~67632&#"!67632&#"!67632&#"#"'&'7327!#"'&'7327!#"'&'7327&'&54767!)!67654'&SOJMG79G~SOJMG79G~SOJMG79GcBnnVsSOJMG79GSOJMG79GSOJMG79G]InoSu,~=,HK%2=,EG%DAF77DAF77DAF7K|oUDAF7$çDAF7$çDAF70IosV!.JhgH$+/HgjG$uL.3&#"7#'754'&'#"&'7327#4767>32";EY?w^H6H\O3,,HO;E+@/VfmVmHO?u]HH]sM3 gz.VrmV_zuM<%4'>7'7&#"7"&'7327&'&54767>2=,HK%=Q Hl;EYLmHH7'&#"'"&'7327&'&54767>2=,HK%m#6,=iSH;EcHKs;E]InoSuJ.JghH$6B0+@TH?HK|z1IosV32326ian ^Xbian ^V2NE;=LTNE;=K23276767632.#"#"&'gV^ naibX^ nai2UK=;ENTL=;EN1).#"3".54>323265.#72#"&:QHRdhNi\dnx>@HRdhNi\dnx.ttlH=YOHL\}X[lH=YOHL\}W#"'"#322{dfftX{dfftX#*$0!#.5476767654&'30ND:323267#"''cDXbia]yeEVgia`yS LTNE+~F KUNE,F #"/&'&#"5>32326!!ian^Xbian ^VeoNE;=LTNE;=K`#"/&'&#"5>32326!!ian^Xbian^VeOE;=LSNE; =Kkb%&32767#"'!!'7!5!7&#"5>32%H\ iaBP﹉lZXbian3}o -X"OEd8LSNE;I"#"/&'&#"5>32326!!!!ian^Xbian^VeOE;=LSNE;?Kk˪.#"/&'&#"5>32326#5!7!5!7!!!!'ian^Xbian^VLoKɦoOE;=LSNE;?KL˪s˪sB.32767#"'!!!!'7#5!7!5!7'&#"5>327b K`Jqia'+\+zlh>Tm?u2^Xbianc"%]OE˪Nt˪=LSNE;%N;?@.9*-" *19" <-<<219999990#"'&'&'&#"5>32326#"'&'&'&#"5>32326ian ^Xbian ^Vgian ^Xbian ^VoNE;=LTNE;=KڲOE;=LSNE;=K43267#"'3267#"/'&#"5>327&#"5>29+Vgia@LJZVgia}9+Xbia@MHZXbi a KUOE8KUNE; @^ LTNE8LSNE;f@59#"/&'&#"5>32326#"/&'&#"5>32326!!ian^Xbian^Vgiaq^Xbian3VeLOE;=LSNE;?KҲOE;=LSNE;?Ky5P#"/&'&#"5>32326#"/&'&#"5>32326#"/&'&#"5>32326ian^Xbian^Vgian^Xbian^Vgiaq^Xbian3VײOE;=LSNE;?KҲOE;=LSNE;?KҲOE;=LSNE;?K"32?632.#"#"&'!5!5gV^naibX^naiUK?;ENSL=;EOȪ+  %5 % $%5$[g&Y%ZhӦ69%676767!!"'&'&'!5!!5!676762!!&'&'&[C-87VYYW6 8.CC.8d 6WYYV7 e8-,CE[<0[2332[39\DD+N+DD\93[2332[0<[EC,` !5!676762!!&'&'&!![C.8d 6WYYV7 e8-;++DD\93[2332[0<[EC,`' P ' P&  P' P&  P0' P&  P.62' P' P W63& ' P P` 3654'!!5!&547!5!!4434w~0IG00GG2?8>;_8` !!!!"264&'2#"&546HdddeH;k'**z{DbFE``bq+((d:svv`K!!!! &!56뗲`!!!! 3# $c'`!!!!33#$'c`!!!!!!'+]^*^]N䰰` !!!!!3!Np!NNf`07GO!!!!#"3###535463!3267#"&546324&#"'53#5#"&4632264&"?$mmC???DNB&H#$J'`qk[Q_C<17HBB@,I\\I,@p`ctiG6B?9i=$#tu#gSSS`*!!!!>32#4&#"#4&#"#3>32!]?U\Z79EPZ7:DPZZV:;S==:xoHOM]QHPL^P%U20=` ,!!!!3#7#546?>54&#"5>324eeb_--B6'Z0/`4\o$-,N2A+,/-7#!^aO&E++ '>@"     <291<2<<990!!!!!'7!5!7!}/H{};fըfӪL !@  <<<<10!!!!!!ת4!5!7!!!!!!'7!5!7!5!DQ"rn遙RoLT˪˪T˪  )@    <<10!!!!!!!!K T@.B $# <2291/90KSXY" 5 !!@po V@/B$ # <<291/90KSXY"55 !5AǪV 3!! 5 !!@poV !!555 !5BkǪ!5!7!5!7!!!!' 5'`ȉ)P"_=6@ss1stFpo!5!7!5!7!!!!'55'`ȉ)P"_=6ss1stF. 5 5:6:6pr pr . 55556:86:'!67&'&54767&'676'&'{)#Y4JJ4Y#))#Y4JJ4Y#)AAAAGF㞢GGGG➣FG2;;;<<;2;5$?$%5%67$'W eĔd?NĔ])]o& bR)`q% Rd%'%5% >zmzF<˶@6 o@hGp%5'75%7-孈m%˶C@ʴ@hGp/V !5!%5%%%!!'/xvH-rf5LOlUrC@=Vlь=/V%'!5!75%7%5!!' GWb[mmNL>ߪwe=ت=$%#"'&'&'&#"5>32326 5jbn ^Xbh`n ^Vg@ND:3232655jbn ^Xbh`n ^VfNF<>LTNF<>L>)P14%&#"5>32%5%%%3267#"'&'&/' k Xbh`'+kuE%sk ^Vhjbn "Pv1-LTND9ATj͊LTNF<= &TN#wf=J;N} 55 58@'poN} 5 55@'pom`!-%5%%%'5%%5 MM`ZDOA@FZDt@m*_TW&o}䎲w&-r~bUm`!7/%5%%'%5%75%Jvad",,V`bL"_D2,/*/&O{¸[&}P %5$r osaa^~||P 55%$so a||^a)W!%5%5$gV$}]]x|)W3%55%$Vg}$BW|]]RW(%#"'&'&'&#"5>32326%5$ian ^Xbian ^Vg$}NE;=LTNE;=K$]]x|RW(%#"'&'&'&#"5>3232655%$ian ^Xbian ^Ve}$NE;=LTNE;=K$|]]&%5$%67%'Et֋$k}uU)?eKtuu" K 9''567$'567&'%=⃹t֋~}uRU)?Kuu,ަK9'_%!"54763!!"3!슊@^`@ƍ^`_75!27654&#!5!2#@`^@Ȋʣ`^; #";3!!!!#"54763^`0rrndflppꊊ^`&pphƍ3 32654'&+ #!5!!5!32#^`0rrpp9^`phƍ7!!!"'&54763!!"3!Ɋ@_`@,ƍ^`7!!5!27654&#!5!2#@`_@Ȋɖ,`^ȋ '!";!!!!'7!5!7&'&54763!7!!ʉ_`'}E=aLT>scL0R^`5ƍ7 '327654'&/!5!7+!!'7!5!7!5!^`__BV 5cTpX?bLm>U`^`C 7 Xȋ5j )5!7!!'!"'&54763!!"3!.Bqx-qxDɊ@_`@Z54&'&'$  &'&'&547676!!#!5!]\LMLLML\]]\LMLLML\bc1111cbbc1111cbdd''LMmjML''''LMjmML'dbcwvwvcbddbcvwvwcbee$7!!"2767>54&'&'$  &'&'&547676r$]\LMLLML\]]\LMLLML\bc1111cbbc1111cbתa''LMmjML''''LMjmML'dbcwvwvcbddbcvwvwcb$3?"2767>54&'&'$  &'&'&547676''7'77]\LMLLML\]]\LMLLML\bc1111cbbc1111cbxyx''LMmjML''''LMjmML'dbcwvwvcbddbcvwvwcbxyx$7 "2767>54&'&'$  &'&'&547676pxg]\LMLLML\]]\LMLLML\bc1111cbbc1111cbpx''LMmjML''''LMjmML'dbcwvwvcbddbcvwvwcb$73#"2767>54&'&'$  &'&'&547676]\LMLLML\]]\LMLLML\bc1111cbbc1111cb''LMmjML''''LMjmML'dbcwvwvcbddbcvwvwcb$ 2L"264&'2#"&54>"2767>54&'&'$  &'&'&547676ZPnnnoO@v+..]\LMLLML\]]\LMLLML\bc1111cbbc1111cbAoPOmmp1.-rB''LMmjML''''LMjmML'dbcwvwvcbddbcvwvwcb$+E %#'-73%"2767>54&'&'$  &'&'&547676C4f4C4/f/]\LMLLML\]]\LMLLML\bc1111cbbc1111cb1XSXYS''LMmjML''''LMjmML'dbcwvwvcbddbcvwvwcb$!;!!!!"2767>54&'&'$  &'&'&547676]\LMLLML\]]\LMLLML\bc1111cbbc1111cbj''LMmjML''''LMjmML'dbcwvwvcbddbcvwvwcb$37"2767>54&'&'$  &'&'&547676!!]\LMLLML\]]\LMLLML\bc1111cbbc1111cb8''LMmjML''''LMjmML'dbcwvwvcbddbcvwvwcb$!%!!!!#!5!QX>ddYee$ !!!%!!rPX>ת\$   ' 7 %!%!!=kyykyjjX>xjyjjyk$$ 3#!%!!aX>J@ <1<033!!upJ!#!5!3JI!#!5IssI35!3!|33!!Nup| !#3!!!!.NN$J !#3!!!!.$J !3!!!#3GupJ !#33!!!#3.GVfupJ!#3#3!!!!.cGGf$J33!!!'!'Ssj\s=u5Y6pJ!!!!'!#3!7!sjshxj56$$J!!'!#3!#3s6s=5Y6puJ!#3!!!!!'!#37!s:jsjG$-56$]*5$%67654&#"'632#"'732654'&'$@e=M>P7sZw㔰Zs7P>M=e.(Y7O0<0:>~jy[<<[yj~>:0<0O7Y]*327#"&5476%$'&54632&#"ee=M>P7sZw㔰Zs7P>M=e@.(Y7O0<0:>~jy[<<[yj~>:0<0O7Y( 51  ^ bb:d 5! 5bd 5! ^bbb:yg62"'&'!"&462!6"264S몧Q3Q3TW4drOOsOOSQ3CB3RU4CDPrOOqyg"&462!6762"'&'!$264&"aS몧Q33TW4QrOOsOSQ3CB3RU4CDPrOOqbgR 7!6762"'&'$&"26b1[륢S4OsPOtO.D/YR3BPQqOOy;d 3#!!#3%!5!( 󀨨 ds <!##5!#T~N 35!3 3#K#"T^ !!3# K@ih^T !!3 3#K@#"쪠T^~ )3!!&'.'&ZVF%,E=Ώ?~%FVZDA?=~ !53*,Ԫ֪w # #}}wJw 3 3!#wJww@ 1@ 0"# #4$H̭9B( w@ 1@ 02$53 3H4CC1 (B9 rHF103#F1  !!'+]^*^]䰰3#3#!5!7 !! 'RLxxLux66x<ux6xx6x'B  ' ''ٛ>PNq^D^'B %  !'''tNP^D'B 5  5!''6bNP'B5 5tN>]P'B 5 'Nt>P`32?632.#"#"&'!5gV^naibX^naiUK= ;ENSL=;EOȪcy 33#cu?Ik8ff%q#cy 33#cffI?#q% )!"3!!"'&5463!! '&76)!"3!k:((P:jZYk񼽽jȊ ()9:PZXD  ȋ )5!2#!5!2654'&#5!27654'&#!5! !YZj:P((:kɊj XZP:9)(ƍN$!4&"#47632! #4'& PtPZXD|p:PP::ȀZX8x8Ȋ:1$2653#"&5! '&3 765PtPZX1::PP:8ZX:8Ȋ|84'&'##47673#Z:KK:ZllY:::ZaȌlala4###!5!5!5!333!!!!'5#Y~~~~,,33ͨ^ 3# 57Ѧ^ 3#55=d//m.   5 5 5 :6:6:6pr pr pr .  5555556:86::6:.  5 !5! 5?@Npo. 5 5!55?ްop9 %5 5!@op9 7 5 !5!?)W5$%5$Ti}$_|x]])W5$%$5iT$}B!]]|!&!%'&'57&%5$%67&%7*?;i@]0qw^%KA6#(AF+3273267#"'' 5cCXbh`^xnieEVhjb_zl]@LTND*F JVND+Fpo"%&#"5>3273267#"''55cCXbh`^xnieEVhjb_zl[LTND*F JVND+FͰW&&#"5>3273267#"''%5$cDXbia]ymieEVgia`yl]$}. LTNE+F KUNE,F]]x|W&&#"5>3273267#"''55%$cDXbia]ymieEVgia`yl[}$3 LTNE+F KUNE,F|]] 7%'%5 '瞃۞L О  @Y8@\9@a ' 7%͞G۞О@?Y@<9@}5!%57%!!'71|Iv\' :qߦ[@Z8@_}7!!'7#5!7%%%9Jpv\]FGjq8@ǹ@  &vvrn66\]]\6666\]]\65kk\SS]\6666\]]\6666\!YZ  "27654/2#"&5465732332233VVVVVVVV)t'>32#"&'#'%53%&  s:{{:!8#!rܧ$daad]chaam@j.!3!3:^ &ۺ+#+#+A&6FVfv ]A]A]A)9IYiy ]+ + $%+$01! 4$32! 4$#"35%33!??qqW|A?rpG~+/ 8?+3&+3+A&6FVfv ]A]A]A)9IYiy ]3и/A&&]A&)&9&I&Y&i&y&&&&&&& ],9+ + +0)+001! 4$32! 4$#"!!56$7>54&#"5>32??qqWO\R!>/_N;sa=0>A?rpGM"?U(?N&:$}:iF D+B5+B+A&6FVfv ]A]A]A)9IYiy ]A55]A5)595I5Y5i5y5555555 ]5B9,5B9,/A,,]A,),9,I,Y,i,y,,,,,,, ]ܺ&9;9+ + )"+)?8+?2/+2/2901! 4$32! 4$#"#"&'532654&+532654&#"5>32??qqW v@X[}DuskcZX\[4yk_=hA?rpG]0OLGN<:,+>2+201! 4$32! 4$#""32654&.#"632#"&5432??qqWN\\NN\\Ta/w N 5jA?rpGb[ZbbZ[b#P =  "#/$/ܸ#и/A&6FVfv ]A]A]A)9IYiy ] 9!9+ + !+01! 4$32! 4$#"!#!??qqWkQ1A?rpGK '?K +=+1F+1+A&6FVfv ]A]A]A)9IYiy ]A&6FVfv ]A]AFF]AF)F9FIFYFiFyFFFFFFF ]%F19%/A%%]A%)%9%I%Y%i%y%%%%%%% ]+=9+/4F19%7ܸ+@+ + ":+".I+.C+C4C901! 4$32! 4$#""32654&%.54632#"&546732654&#"??qqWT__TT__jivvWQMKRRKMQA?rpGPIIPQHIPIvSttSv\\=BB=>BB 4@+>)+>+/8+/A&6FVfv ]A]A]A)9IYiy ]A>&>6>F>V>f>v>>>>>>> ]A>>])>9A88]A8)898I8Y8i8y8888888 ]+ +  2+ ,;+,5&+501! 4$32! 4$#"532676#"&54632#"&2654&#"??qqWUa.w O 5kN[[NN\\A?rpG$O <b[[bb[[b &2>+#+#*<+*60+6+A&6FVfv ]A]A]A)9IYiy ]A00]A0)090I0Y0i0y0000000 ]A<<]A<)<9<I<Y<i<y<<<<<<< ]+ + -9+-$%+$3'+3$01! 4$32! 4$#"35733!"32654&'2#"&546??qqW͞u>@EE@?FF?A?rpG>>'*6ޗ{j5!jl!X3 !@ <j 5!!5!!5!r#B#B#j<l !!!!!r#B#B#XXXm 333mjjjm !!!@@@mjjj<j 53353353353X 5!###ljjjX !5!!!5!4l t,> 3!!!--Axj 333!xjkx 3!3!kA 5!5!5!3,,=jX 5!333jkkX 5!35!3̠= 3!!!!-- ABx 333!!xs  x 3!33!!-skA jB !5!5!5!3,,X !5!333xtjk X 5!3!5!33t,  !5!!5!4B 5!!###sjjj 5!!5!3!!t,-sjB 5!5!3!,-XAj 5!333!jkk 5!5!333!XkA!5!5!5!3!!!!,,--AB5!333!!###sjkkjj !!!!5!5!333!-s t,jBkA 43!!"yY[p~| 4&#!5!2[Yxp~|j 5!2653#xY[j~|qj !"&533![Yyjq|~*m3YѲ/ Y*m#3*/ Y*m # # 3 3*iSjh5!|j3?hj5!h}j3@hl|X!@?hl!h}X!@@l5!5!!5ijVV333PP?@l!!!iXVV#!#P@P?@;\;?!O?;j!Oj;!Ok;!O@;!O;!O;B!OB;!O q! ! ! !' I!] ! 3 :d'bm #'+/37;?53!5353!5353!5353!5353!5353!5353!5353!53('O'('('(67576('l #'+/37;?CGKOSW[_cgkosw{#5353353353!3#%3#%3#%3#3#5#53#53#1#53#1#53#75353535313#3#3#3#75353535313#3#3#3#75353535313#3#3#3#bb~! 'm 59=A35#%35#35#%35#%35#35#35#35#35#35!35!#5#!5#35735#35#wNOŶZXYI6ZB;YBq:g!(@;n'n;!!!;(' @;'nn';!!;@@ ;!!!O;n';&nn';!!'($! $!!!,7r+uv ))xxp) )$7632#"'327$%&#"%632#"'~~~~eMM>yJJJJJ6````qq|qq#u"@91990  9%-p) 327$%&#"%632#"'MM>y````qq|qqr' '/7?G%&'&'6767&'&'7%'676727"'64'7&"'62&47\+;.81F9K58.42d;E9G,:.80G9J6&8.;+d1O9FLL&_`JnLL'`_n<1& j(0=Ju &,A=N:0('<1& j(0=Ju &1<>EB0(n_II'[[JnII'[[p) %/36%632#"'327&#"6767&'&6py AAAA,+-,,-+A@@Rqq|qq%%mܱ[0$ %@%|"p) )73276'&#"7632#"'327$%&#"%632#"'r99:9rr9:99XWXXXXWXMM>yB!!BB!!oe33eje33````qq|qqp @ 104767632#"'&'&pihѵhiihҵhiѶiiiiѶiiiip $32#"$27$%&#pkk<MAk^a``p $32#"$"3pkk<MAk^``p $32#"$%&#"pkkAk^>``p $32#"$327$pkk\MMAk^>``p $  $"327$!pkk]<MMgAk^```p $  $"!pkk]<Ak^`p})6%63"'pRqq)#2y|q*q( 2654&#"!|~}}|v< ( $%632#"'327$%&#"!IMM>y_O````|qqqqH( ( !#%&#")%632OyyMMqq>~``  3327$3!#"'$@1>qq``) %63"æqv`) 2#%&#u)q>` 527$3Muyv`>q "'$33yuMq`p)%632#%&#"puqq>``p03327$3#"'$puMMuyy``>qq!$ !$ !$! !$!$3! 2654&#"4632"&nȊce;~|ddcc||}$!%!!d r<$!%!!We r<$!%!W7 r<$!%!W7 r<$ !%!!!!+c,b r<<!$ 462"! W|VV} ,|VV|V !$! c  !$! b  p(  7& $  %;<*X֖$ !!!!!!,7,rWb<)) Ie$ !!!!%!!,crWbM)MM^??@7`d?\gOOOOy>*<?v^h"3263#!5276;'4?'4?26u'6"gP39.4! '*C0.xV#m14He '1l1 Z+dd?33 #&'&+"'&#"/573;2?"#'57#&'#"#5676!5:+#9,p!j[%+ > 7VCCc":8}V .e3B=Se` e9*=9 3@=}k %C`:d;emu}'S3273&'3327&'67&'67&'67'32654'&'2327654&#"3672 $54767&'&47'&327632#"/#"57#"54?'&5432'&27632#"/#"57#"54?'&5432'&327632#"/#"57#"54?'&5432'&27632#"/#"57#"54?'&5432'&327632#"/#"57#"54?'&5432'&27632#"/"57#"54?'&5432'4327632#"/#"57#"54?'&5432'&27632#"/#"57#"54?'&5432'&27632#"/#"57#"54?'&5432'&27632#"/#"57#"4?'&54327'4327632#"/#"57#"54?'&54327'&27632#"/"57#"54?'&5432&'67&'67&'67'&327632#"/#"57#"54?'&5432'&27632#"/"57#"54?'&5432'&27632#"/"57#"54?'&5432'&27632#"/"57#"54?'&5432'&327632#"/#"57#"54?'&5432B~ %<z*+')+(@&'$||e<-A}]\B-71SLoWj\vLL)(0/ (( .1(%%,* # $ )*f$% +) $ #*+f%%,* $ $ )*  \o  [ %)#&'%&)#`#$ *) $ #+,U  Q  0 E%% +) $ $*+&EC&V*,)-)-*,%&%&fБfU 3HhfeefhH2pu^QFs棥sKQGh!99!  !77!  4 4 22 K44 22 22  11                   7        %&%&%'%&%'%&22  //  g               44 22  ->O`q +&'&54?632332?654/&#"2#"/54762#"/54762#"/54762#"/54762#"/54762#"/54762#"/547672#"/54762#"/54762#"/5476%2#"/5476%2#"/5476%2#"/5476D.2`{4&/<) e>O ,4H3R 07K $   $   #  #  #  $   #  $   $  U $   # " $   #  7Q=KG<s-8PZy9z _e""#/2dt0&2j ,: . 4 . = ,  ,   -  -  -  -   .  .   ,   -   !! WV9`8 !! 7 ! !WVDu9`8N I 7%7&54769 }V&7A 6$ 8'^4? !2 7%7&547!&'6I@Y%14HFS"="l-2DC[9 &! 4$32 4$ #"&54>2JJhhq0^mNMn2Z^Z2K7iwBNmmN1Z00Z} C"32654%"32654&%#"&54767654$ #"&767&54! ggJIhIhhIJgg[ZQoy y}WZ[zADgJIggIJggJIhhIJgU\\Q srW\\^} A4&#"26%4&#"326! 547&'&632 $54'&'&632hIJgggMgJIhhIJg#@@z[ZW}yOOyoQZ[sIhhIJggJJggJIgg ][[Xrq Q\\} "32654&7#"32ɏǾ/`T_ȐɎ;P12Y}1"264&"3264#"54327&5432#"'&'3xyx& کZTdIU  k#5AMYer3#"'%&547654'!#"'4%$53!76=332654&#"#"&54632'#"&54632#"&54632&'&67632#"&'&676'.547>'.76$6&'&54%6&'&6>#"'.54>32#"'.54 [$gi< D""D =if%LW쥨驧r^]]^ !! !! . . *)X,),*))+. } +G  G+vKK9__9KKݧꧦ]]_""""s!!""W&. - . - a)," "  ))    !) /     p%-5AMYdp|5#!4'&'5#2#"&546"264"264"2647>'.7>'.676&'&>&'&7>'.%7>'.676&'&676&'&53!76=3%#"'676%27+%&547654'7327&'$%'#327%654'&54718楣. . . .  - -Y - -))G))))U*)>- - ~- - VK; yA C0B Ax ;K'6FJ> $06# >JF6&@@1AeA1@@H磤椣筁 . . . .E - -- ,1))),(9)())u- , - - G77W6 W77G D&& ee˥ &&D "(=pp=("u !!'!Pn8hv "!!'!##+572367676MoL)>u eI3?ba8hA:F;/Itxv !!'!  ##' Mo_h[ei[i8hi[ef[l[@36273 ##'5) U.WW1@ US Vdv#,5>~3+&=43+&=4%3+&=43+&=43+&=43+&=43+&=4%33 #&'&+"'&#"/573;2?"#'57#&'#"#5676!5\:V\9\:\:]:&]9[\::+#9,p!j[%+ > 7VCCc":8 #8d#7$6$8;$7i$7 #9pPL  )Z. ;6ZV Z3%Y63 .87p  3DMy!674#!!6?676545&#'323276767654#3#&'&'454632767!672!&=75$/563&43!32+'!67#>54&53# ? I :W0 96;E,Q 2:&l6x0 bm! o۸"\>%Ef~e2U6g!6V#p5C+ C ? P9 @7H4XmM7RV /M(=H: ,qLUD)8Wqke-Pex NW =$ U  /0c)H?2@[nDF8T$.J? !' !T4XKGwL5_K !'7W4Z~wDS&5476322632%632#"'&'#64'#"'&'&54654&'&54767632xJX%&XA,B:\8 [EMH95##Fl% !9@!#jL p_Mi#"?8" %lF##58HN4hok@RRr*%te BB9'7*$%) "fXS5EIf" )%#,7'9CB >E3#"'4332327$'#"$4727%672567654&5&oJ7.b9M D ,B3 qY 5**]d=HN9% sW$,J ]T-MMm@ed: ,'Z M'cM&T)$$ < I2%!"&54676737#&'&54>;7!"&546767!7!"&54>3!6763!26P+=6/2D>R+>2,+v*>>+2  ,2 =,2  =,3>,2463!2!2#!!#!32#3#!>*v+,1>+R=D206=+P#,>3,=  2,= 2,  2+>{"D%4&#!"!0#"3!!"3!#";#"3&'6737#&'6737!"'67!7!&'63!67!2I0!6OS SS: SS>SS]]J]]]]h\\, Bv*>K%39LKIOKHLKIhghghghgE?-L!D72654'6#"'4#"'54#"'54#"'675674767#%$4:JILLHOKHLKIhghgighgD>-sJ1 b6'SS cRR SS?SS\\K\\;\\]]!A*>K{!C%254+'3254+'!254#!'!24+!&#!"463!!2!!#!3#3SS?SS *vA!,]]j\\\\K\\IKLHKOIKL93%N-?EghghghgiL!C32=732=7325732'654&#'%2&'&5&'5&'IKLHKOHLLIJ:4$N->DghgighghSS=SS SSb SS'6a!0J)K>*B \\]]:]]J]]}O &*.26:> 3656;2#'7+"/#"'+"5&54775%"'5476;25'7&56%635&56;374765'75'76=4'&+ +"'4!#"'4543$365&5&#%#754'&5&&547'5367&547+&'&'735&2?"5%75537'7'3533553535'32767&5%2?&#%55'5757757751:e,$?F?Y>F_LA3ELH3,8LYLlEF'!0< k#gF  EeY!! Gp&iq.8ZN$%`BCf F4"4._?ee3&{E(1-+$Kt8 -  $Gs sM rEF"2 >_plTErf^5.>=9|5"-l)d ,&>vv]cccWpC-+ d8 Bpp>W]oaxvuPp82,D ^8, ^B$K+ "1R[+e*; 2 W QP I&? gpo% w ^SA$ 2 9i-5n02 Ai&IY^P]D%\??\OWC ,,1 /211/=;7777=321811{908hN%b\Dh,)h?17I21!122223 21&2%2#"'&=477654'#"'5473Bq4|l anN ilm b 9 b؍MOb>YaYƮ58l7P P@ $0<FX + &=6&# 3 6=%&#"';27!5%67%!&'&'2+"'&=476r cR~UY082.ԍ_W_V"+}IR8D).P9H'S]ٱZYHYoX(I_ ;.2lOP%.G6R%&I8d)Nl>54'67&54&#"&'632.547#"'&'#"'3267654'7327323.#'654'567654&&5476;'&'%&+"#"8DH$$yU ?L[>!WtJ([Fho*m.2\=w\`|UP7:/E" @7?EP]Eix pF@T5ym,"&eB@q(A _% #+B7!N &".OS$XE/K(Aa]dLP*'FCaYr=C44mo C (FKWYFvbph'UD'R< $d#+?Vm#327&"#"'7'632&'$54#&73254'&#"'5&567#&''5$'67'654'6'5$'67'654$'67&'654'''5$56732#"'&#"&'$'63&47"7&'7&'7&'7&'54'6546767675477&545?&''5&#" '6%35&'.54>23#67!&#"W  OB7[l#> F_Vh " "@.,=6tJ4Vp1EQJqMi vhpHI!:JJJ =4m\8B*?o v!"t,`s&*_~P1>5='g=>24<+-s[,*&sd1PT>3J@='h<42J-H#*YT_Y)*)X^TY*$D  ?>}>  *0t"J.  &b54CUE ''!`9 !,(MTE *! }q~=/+)f[4f !B" <@0&9c?"V+GoMK~a? }b9e\ P&0@k"?c*GEJX ?e}9 \4 \6 '''' 6\ N(&'65&'67327&+!65+"3yyys{w ccޱqXeXc6 6 c ,35'533#3!'#'5!5!5#53!5!5#!!-ʷ}} ckvG G @<<3ffX苜qXGccGJ 326&#!2+73 ### 3(ttvgnؐB(33#!!#'!'57!5#'5735׫$"q~q+!#!573#'5!3!'573!#'73!#'5;jjŠJss<wѡIjj8/w{,32#' 3%+ &5%6323'#57'53^VQ6>ѨABؒ6ʞG2k >Y3~||~Obs32732753"'#"'4323$4'5;+"'#"'53275'&'&5?5572%#&'&5%634%476=%@.!%,BE,#!-Q2" $nL/PuHED832#"&546324&"26%! !  Őb{=&*<<*(;E;R::R;KJ67Ϛ{ɬ)::)*<<**<<*):<'L67I&b'bb &b'bc &b'cb &b'cc &c'bb &c'bc &c'cb &c'cc  @FLRX^djp3264'&#"&47367'676756273#'#'5&'&'7&'677&'67'%%&'&'%6767%&'0/CB^0/AC/pkTcR|'N(OfUippqUfO''NQaQh!$ b)dLQk KRt!% c'd&//^000'N'|P_PfppoQ`Qy'N'P\ QgppmQ \Py,  M N>&`7" bK*V&"g{ M Mjn !-=4632#"&%462#"&! ! ! ! 676 &'& Q;:RR:;QBRtSS:;Qtu <=CA$32%s'l(;QQvRS:;QQ;:SSu tC<=@%8338H,'(+jn !-=4632#"&%462#"&! ! ! ! 7 767 '&Q;:RR:;QBRtSS:;Qtu <=CAs('s%23;QQvRS:;QQ;:SSu tC<=@G+'',H833jn !13264&#"32654&"! ! % 767' '&'Q;:RR:;QBQ;:SStRtu s$32%s'l(:SRvQQ;:SS:;QQu [8338H,''+  "*2:AIX3#''%#&'52#"'&5476!!'5%!!'53'5%3'5%3#'32765'&#"sNN99=>-1\ H0e%FKSwZGr=;=NN$E| 1 ?'_>?@7`d@\hPPPPy?+<>w_VG{?,rCA+ +"'5$76%&'547327676=&#~jt1/Q}](+VRxbO P >nS]] =fP+! &56;2'5$%75#"3ui1.P~N](7P,VSZycOpO >S\^ f0:1>7#'#53'&'&54767&'&=33676=3#326'&i($lm$(($[Uu&tU[$&uU[[UV$|ddb e|$% ZSSZ %_TYYT- #"32654&&5432!!#!5!&礡ɩPS'䤣أL"~|| - #%2654&#"#"767!5!3!!礡7䤣أLޜ~|| "326&#"!7!礡YpipH=U g\uS5264&#"#43233#!5 z{ym㗗y{(|j#53533#632#4654&#"#*jjoon}mZyH{zF2 1"32654'#"&4767!!53#5!!3!!#3!!pOO87O:=0LmkL/>Λ2  1O79NN970LؙL1KӘJJ-'<%#5#535&'&'5'73'3#'73'676=35'73'33◰zhNgeMjzzTThOʍ7NjYYӖy?! #!!!'!27674'&#.d ;6zFH%QM_\ǃ$P<]$!#"#&5463 67!2#654&#"V⩁"T]ts]U"X"1((1"u." 6&'67>3"#"54767&'&#52&͕LVa{.+ؔ)0zHUM\&ϖ=Bll)'ҕ*l8lB=j&'5 %$ 56?63#'[Wtutu4ZZ//[[5  @Eo&<"3264,'532'&54632264&" &$#"#"&547>B_^^l;͓hI^9l:͓hI (+|TlgMLx)+{TlϔgMM M>54'.#"32463227#"&5454&#"#"&'&54767632254&K2q'$#K1o'#0ߴGdAoc.% 3t88bWDs-Kx68<32>32#&'567'45'#&+"#4'3>$4&+"?w(K>R0D32>32gYYYD,.:?#)v$E?w(K>Ro}vvxJvaAjtAO]ƀwϧ  / ? !5!?=lXjj=?l=Xj=jj)127632#"'#576&#"4'5267>327&'"SkQmyz,~zi2@:$(.-)zW] ݾgvx-aX[&ŝ9{'Q32263227632&#""'&#"#"'&#"#'3232762327632&#"#"'&#"#"'&"#'Es- p86rV+)|m^?_354.#"!&'.54>325467675#53533#63232>54.#"P#3JTRJWVJQSOMJ4"?*&ElnhPL$ llill %LOhnlD')----+)QPQ((QPQ)+/ 6klj$?6FWWF6?$jlk6 }++--JHNRh|&'4>32"'4>32&'4>32&54>32&54>32#!5!'!567>54.#"32767>4.#"327732>4.#"327>54.#"732>54.#"M_ 6694S55.+C55C&.66 V\+55 c$M##$ 6$#$s`%#$d0"%)h #"#_33@]22-"40446/*33UJ"+33^1/K=0T* ####  #&$$&##&$$&#  B #### *"$$" U!'-2!35!#3!53573#'5#5!35!75!!5'57!s\\ss]]s JRRIJ~֛E77__vtt4!v7CQ^&54767&'&'5676767&'&54>32! 535#5##3654."!2>4.#"  <$))+N-N*)N-M,**%:  @ v<-MTM-?K5:66459<5&?HPPIK* ')+K**K+)' *KIPPH>&5<:6uN|l||l|-I+N))N+@6:55:5Q)5>o654&547!&54='&'654'67.5476;+"'5#"=6&'76767%25#654&'Fz-6 Z8. ,N0H!h6%`+EH )#M ;,Jga#iR k' M +1^hgo8:(@s.Pmz nx?.#1p#41`&>%!ac,,LHJ x}647| + OJJ)!0 P[32>4.#"32>54.#"!5&54767&'&546767&'&4>32'&'.#":e79e89f76e`[S &(*UM,N)(N-KV)&& \@ECApd88dpg669:%N&KRS* 'TM**MT' *SRK&N۠:9}qyyq}c $Tdhy67&'&"!3!67>54.#"!&'.54>325467675#53533#63232>54.#"!57!&'.54>3234'67632!P#3JTRJWVJQSOMJ4"?*&ElnhPL$ llill %LOhnlD')----s=BDw@>=))==AwDB=+)QPQ((QPQ)+/ 6klj$?6FWWF6?$jlk6 }++-- !yCB{C!$$!C{BCy! JHLP&'4>32"'4>32&'4>32&54>32&54>32#!5!5!M_ 6694S55.+C55C&.66 V\+55 c$))_33@]22-"40446/*33UJ"+33^1/NNOOU%)5!5!!35!#3!53573#'5#5!35!s\\ss]]s ^^/oo#E77v4@4767&'&'5676767&'&54>32!&535#5##3  <$))+N-N*)N-M,**%:  @%v<5&?HPPIK* ')+K**K+)' *KIPPH>&5<:6n5|l||l|L3?HN654&5473#!&5454'+#"#7&'654'67654&547;2547#";65'"3%:U"-6 Bu Zg0krX0c-h8E+`%s H>4wM-'9.QY / o8:qhPSmh #%Bz1"0@)5"@YR0.&54767&'&546767&'&4>32; &(*UM,N)(N-KV)&& 9:%N&KRS* 'TM**MT' *SRK&N۠:9C##"'##56'##"/547?^'5@_*SU&/UL ;Yԧ9UP(` XI.s222732#&547636=4'&# #4'&#"*t pz&=<xQ>hG:V Hek%PF5NP B|-&pA&NFX &&5 <F:^;" V gdG7236;2"##'65##"'&5476;235&'&=476e x<JT`(GeRUdfB3 VNTMT,P$ 66$0_ u3dUdt_}s*$"Rt0XX__/ik=ZG8*F 1 . ъf)MC =g9EkO 9!(-);&  ]t!y" & 2| ba$ U+  #8M35733!&54?'7'327!!"'&%#'7367654'77'7'&#"'676ի,&T>=c#]K9.U:1ʈ%`T?7>54&#"5>32&54?'7'327!!"'&%#'7367654'77'7'&#"'676]T@1$J=c#]K9.U:1ʈ%`T?32&54?'7'327!!"'&%#'7367654'77'7'&#"'676Z _3lFHe5^\VOosHGJI)`VKm1Sj,&T>=c#]K9.U:1ʈ%`T?=c#]K9.U:1ʈ%`T?=c#]K9.U:1ʈ%`T?=c#]K9.U:1ʈ%`T?=c#]K9.U:1ʈ%`T?=c#]K9.U:1ʈ%`T?32#"&e|e(<X<ħñ"32#"&$2#".46e|e(<X<ħñ"@<#"4.#"e|e:<#"< !<"#;zch =B4.#"$32>4."e|e:<#"< !<"#;"< !<"#<@;zch =B54.#"##"'5##"$'&'0!5!5&'.4>32!!676767'%''H&(G()G'%H(%'V W3WImuw>DE}AB|GE=md^JW4W Vs'H''H'(H''H`XAK|@X1(ԁ3"|}DD}|" 2/ "1X@|AX1# / 673&/'67 &'"&'6?&'3 ' K[]><+Gg['fBBe&\h?(K?]\K !;32T $ #AC,MMMv A5p_9D-M**  B@0"@R//>wA&oc/D&3.YaQ/5"1'"uE62/u= =!m- .... y 7%  %  32+#".=!"&'&'#&=4;7337_% 8)0/_^^M^1/ 9534<&&<&*(D>?GGzB6C{GG?>D9/C}&632#"&'.#"'#!#!#Ҹ62K#+~KF0R!9'/Nx_TV_T 'NQ9;:#8HL"CD|))Z) 532>4.#";267#&=&$32735&'.4>22[02[24Z1/[)'5*+X A323#67#&"#"/&'&547&#""'6%676V n*[n%'ZxL0<{2;&b;0&8a>!U*~EmLK}`? {a7c[ O&0>j!>a)E~CKW ={d{7 [+M57LL75M-Z '*''*' Y (5[ J5( \d (5J [4 ''/7O_2#".54>&'32367&%2327654'&''67&'&'&'676765467654'&#"7>326323#"'##"'&'#"&'&54767&'&54767232&'&#"6&%6767&'&'&#"676&5467&'&6732767&$$$$OG3%V cc V%4GL944m/122102/.303112.OF}6&V e"w?>v"pt #87! vn":;@A<:"nx !66# sp%./13/.UVT\<>"$!! !"#">kc V &6|FO 93399 <>#"#><  "$ZTU./43..V5$##$59gT;&'9Z^^Z9'':Tg9'(''&()I8:9889: Z_59eU;'( :8.>euvc>-7:bccb;7-?cwud?/8KWZZW **D@@D+8(':Te95^&)(&''(DA:AD.*!Y[[Y!& !-x67&'67&'4&6%67.'%4'6&#"&'6767&54?67&'&#"#&'#&'5&'"'67&'&47632>4.#"%2#".4>'7,3 3%/0),7=*#0*+3.22'8  YfT,1'').UfY >98 "2 B2;F_ XB?2C 3" 894ihgikce"S[XVWXZ#ejpMcNTvJKrZ1VlLWMI p jk%nA V{ww[11[ ww{V @#fd-#JM 7B/""0C7 NK",df#νhhοggQUXXUS !!Y,q@I@,qȤ7TU7S '!57|,q,Iw,q,ɤ窪8d %3!'#!52#"62#".54>" h9|M463%&$$5 O Dn; $$$$33'554#$/[QwGSGUW GJGZ*1=C&32632!!#!#!5!&"327&7&!&7326&#"6'XP}}R?99XezfH9?A:uutLFF"~|| -  GP8lGrr[0 $,8>& 67& '&'&'&!7!!! 6'&265"ut.77!u$lYoip@qDi4tEu.$rl,36l%eUg\xuvSc?\7 =1lHr-ؤ-9E6'#"'!!#!5!&'&326!7!%"327&7&326&#"suuW~WdP|ojp?9:v8?A:llGrE, || ~LDJg\u HOU(&  6&32!7!!!#!5!&yEߩPhpCLn[u~||  +D#"'&'&'&47>76327'7'%'27>764'&'."(F3"D"&%#}bV`ZZ^;D"&&$[X]:3G9:]:F=~=HS]^X&% iiD^29i\=<<92-1X?:<91*=X62'%'!!#5!5!5&'&'.546767''7'''7"2767>54&'&'&4p69].(EGGE@Z-<81VDEGFF'19T]9T:G5>+.11./:95>+.11./:9 \2:a(Eb_E@( %CE_bG(Hij:ο\ij+.wBAw./+.wABw./4+F!!#"'&'.546767675!5!' 2767>54&'&'&"<-Z@EGGEDVRbfNZ@EGGEDV18kbbjC9:/.11.+>59:/.11.+>5疑 (@E_bEC%##(@Eb_EC% kajP/.wBAw.+/.wABw.+ +F####"&'&'&54767>32333'7 '%32676764'&'.#"ܖU (@E_bEC%##(@Eb_EC% Uܭkaj/.wBAw.+/.wABw.+<-Z@EGGEDVRbfNZ@EGGEDV18kjC9:/.11.+>59:/.11.+>55 @  10432#"732654&#"陽…5 @  10432#"K +@kk k kKTX8Y104632#"&732654&#"ϑϑϘuSSuuSSu͒ΐSuuSSvvdPK!)7eK RX@ *.,&"($ k3,k($kk8991@&"6k0k 8<2<299990Y4632632#"'#"&7323&547&#"%6547232654&#"dϑRDDRϑRDDRϘuS?>Su^222Z>?SuuS ͒!!ΐSuXqpWv28ML88LM{WpqXuSSvTZ`z8Rm3#"2767>54&'&/2"'&'.5467676"2767>54&'&/2"'&'.5467676R#)$#R#$ $LK:C.25521@=:C.25521@=R#)$#R#$ $LK:C.25521@=:C.25521@=zZF)(JG()K.2IF21.2FI21F)(JG()K.2IF21.2FI21 J7Qk>767632"'&'.'!"'&'.546767632$"2767>54&'&'$"2767>54&'&'#61@=HK:C.25521@=:C.5%'21@=:C.25521@=HK:C.6#R#$$#R#$$R#)$#R#$ $5[51.2IF21.4`]21.2FI21.5[F)(GG()FF)(JG()KR 5%%%xr6׊eMM^xxV)7654'&'575#!&54767'5!s_vR$N::N$Rv_{aT,X@X,Ta{4b\)1%==%1)\b4ߴ:`\KDDK\`-&  6& #&yEߩPSCL"~{Y,!#!5!326& '6 !I(4~uP|Gjt ~|, 23"#"#"#5237 >>![ZVL;|| oJ,737!!'!!#!5!'!5!{{~zz~zdz|{||R{|xT% ! !5! #!7!# #T??LLwJ|A|JZt|J,$264&"&7673% %&uuu>hH]%VgVYFhݦuuv#gGέҔEgDX!#!5!&'&5%676'!HfN)]H;btWUJn|3Lu.:;͢8%|V^m3 76= '&  7654'7! '.54676! NΫ.8l?ΫNΫ,spppsppp>9`VhhV`"xx  hVc`VhhV`cVY9QN9ss9N^Q9sV^ -E  7654' 76= '& 76= '&! '.54676! ΫNΫkNΫ.8l?*NΫ.8l?spppsppp>9ghVc`VhhV`cV|`VhhV`"xx `VhhV`"xx Z9QN9ss9N^^Q9sV^m !1?U! '&'!  '&'&76767 76= '&  7654'7! '.54676! x8;41 ::; 9٫NΫ.8l?ΫNΫ,spppsppp>9d]]c]]] Փ`VhhV`"xx  hVc`VhhV`cVY9QN9ss9N^Q9sV^!-;K[s  '&'&76767! '&'! ! '&'!   7654' 76= '& 76= '&! '.54676! K ::; 98;418;41 ΫNΫkNΫ.8l?*NΫ.8l?spppsppp>9]]] ]]c]]cehVc`VhhV`cV|`VhhV`"xx `VhhV`"xx Z9QN9ss9N^^Q9s- ,"&54632#"767' 2654&#"@a^CF[^ccZ礡}[D>XUAB]~Lޜ~g]䤣أlPj'#"'&#"'&'&'&47>7632327>76&'&'&/&'&'&47>762!2!%327>764'&'.#"&#"327>764'&'&s* 0$+$$$ 1#*# ZaZ%% NT12 4 #HH  ")mROeb  , 0  +   ) . $J . %'.D"&B 1 $C mR )Ky    !   V!Edz267>54&'."#"'%"'&'.5467676;27>4.'&+"'&'.54676762%632$"267>54&'&.&&.&m,mQjP(!N!"(! aVf&&bZ55!("!N!(PjoQm,.&&.&q    l?W,>&#< A#"< " (( " <"#A <#&>,W?~    lOOj3!#!"'.'&47676?6767>'.'&#"#"'.'&47>763276;%32676764'.'&#"676764'.'&#"32eOuRd2!  HH# 7   ZTN +Za21#+$0 4$$$+$0 's  *   * OK) Rd#!>& 3"9*$"D. ' - D! 2 . , T% #: & (  IZx-4H67&'&'&+"'&'&'&476767632%632 #"'%#"'&'&'&54767676;276276767654'&'&'&"276767654'&'&'&""'&'&'&547676762"'&'&'&547676762'&'&'&547654'&'&'&";276-&#"+"276767654'&5476%327%&"'&'&476762I  Q\C--%("(/*0.,+"( /X]\9<\X/"$)0*3')"* %1*0CR[        22 2 2 2 %'   &J  &%C\d#_*]OhXC%&  J&   O]*       ")&`&"'$"/' <%ZS  % SZ%< /'* "%5"-($# ;8\= !  !  " /VC "  !  !  [uV/+    V^au 767>54&'&'&#"&54767632 '.5467&54732#"#"676767#"'&#"'67654 ozwbda_f_zx|wbdaM,krnulspsnunNJ*D$ lQ$" 6*D?"5'K(2- # >   :72 331cd툍i`4331cd퍇>mwn<;;8ro졘wp:;;BV0/M8:D@*|sa  -F(7 "*=8&0!2  1-5$& 6:B4V^ (B\w.'%&'&"632%6767>54$2"'&'.546767" 767>54&'&'&'2 '&'&547676?'*&$ 1$-+h+-$F3782**?1 $&>>9|wbdabc`zwbda_f_zxspsnunˎspsnulwI_"2[$  "" gI $[2!v 55 55 31cd퍅caf31cd툍i`43d;8ro졘wp:;;8rown<;x,A-57'36%33#3#!2#!3#3##$'#7$@d5{sVd]F0 0F]dVs{5⒒d@( jPP,PP` 0 ")- !676762!"'&'&'&54!X$#R#+/RFF$#R#$1Sh,  k-"s!|P476?6763&'&'&547632676767654'&547632!54'&'&54'&&#"'&/&'&'&#"#"'&'&/&'&#"&'&'&?6'&'#"'&'&#"!'476='654'&545454'327654'&'&327654'&/%4-)"$0JK&  )7    %0'# #6 +-L __^/s4* 1( .266 |/(1   \   #:7  lS&   x71]/~[#<$  o_%@,: $";vR $X$+|!5DX&PY;9Do6 b'n2  83eF] 4T&  &  /50$?- 1@& 3l K  C"P1 :03<D:5XI.)D&[+-1:   q/A8   g+jl9Lp{7654'"'&#"+"'&54?67676763276323273#5%6767'&#"6"/67#"27632327654'73654'676547&p/l0&J!cS%YE]{@C"$4>-;% ,(6Y>m!N$X6"/,(4sS?X$U>"sJ?K(`./4+2K2.0>S Zp0+1^' ;cs  /^"|Y/ 428ۇϕl%%ot5oA='Y$ aT* ''G+- %_kj~r}jL`І|\gK@/.85c($ (2LS>54/##326?%%3254'654'3>7632#"&547>32'% ;66I   }g ?6qn   -> 9@ H67;  zh| 8 >6!q    B5>%+?F4&'&/76765'7! !'!654'!4'!!$467>2"&'&!654' 33 ^^^RXI#J2VlP# ~!88!~ Kppph,p<(##(#id (2LS.#"227654&'''%'654+.#"65.'&54632#"'.6#"%  I66; o |>?%6!q   9  ;76H   |h> 86qm    BX{[%G'23 %%.'&"27>7%$!"#232%"'&'.4676762%#"#2%k      A>>dIID`nS   SnGYn 5>5 n)(%$#"#64'232%%&'&'&"27676&22k**!n``n!##3W 2327632#"'&'&5476'( > !~GH ".4F+@xH )0$'*' 23277632#"'&'&54763'( e` }{*279HF`0@xJL 1 ,A  ' 7 Ɏ877Ɏ77ɍ8ɍ? tt7tt7t7tt7uB2632#"'&'#"'&54767'&54763267632676 Q   x L$3 z(   6X3  6*=P*> "#  R26#"'#"'&'+"'&'#"'&547&'&54767&&5476326763276T 디% $$YyX$ zc0 + j :  (̢1#: _$ #- Խ =1 '2ĺ pD #!!!!!%!!!!!!!!#!5!36HVBBXBBUHVPBXyBpD !!!!!!""p"p"#pD35#7!!#!5!3rrsrspD!!%!!!!!!r"p"#p"#Rb !!#!5!3ppEU l3!!'#'!!#!!3!5@,r,,_ r,,_>v #!!!!!'!!!!!!!!#!5!3hm_|P_H_pDK#";54&'&'&#'!326767657'&'&'.+3!76767>5{dIB,$2$*DEh{LGC_RQ|66R_CIJ{hED*$2$,BFd{LGC_RQ66R_CIJKIB`OT|87O\FGKzdGB+%2%+BIdzKGF\OT87O`BHL{dGB+%2%+BId  #!! !!! 373#'7#ZAA:Llحmllmzlmllm|}}|d d}cT`C54'&54762327632#"'&+"'&5476=#"#"'&476323(L,68x86,L zFvd0000dvFz L,68x86,L zFvd0000dvFz zFvd0000dvFz L,68x86,L yFvd0110dvFy L,68x86,LV^&'##"&'&'&4767>32367675&'&'.5467676236767>32#"&'&'&'#"'&'.546767675&   R.-R  R-.R "  *!""! ((\(( !""!#%   " R.-R  R-.R    %#!""! ((\(( !""!**!""! ((\(( !""!#%    R.-R  R-.R "   %#!""! ((\(( !""!*  " R.-R  R-.R   Sa4&'&'&'.546767622676767>32#"&'&'&'.#"'&'.54676767>5"#"&'&'&4767>32(,$ ((*& :.r06$&**& )'De!  'd8:b&$$&b:8d'  )a@/!  ')*&$6/r/6$&*)'  ')?c'  &d8:b&!$&b:=_& (bCc"  &d8:b& $&b:=_& (a?/!  ')*&$6/r/6$&*)'  ')De!  'd8:b&$$&b:8d'  )a@)' ((*& :.r06$&**& ((T`0267632#"'&'&'!&'&'&54676763267632#"'&'#"'&'&'&5476767!6767632#"'&'"'&'&'&54767#"'&'&'&5476767632!#"'&'&'&54767#"'&'&'&476767632&'&5476767632!#"'.'&5476767632&'&54767676Z   ( &            <   4          % (      (   2     6           %    <    %  (   W_2767653"4'&'&Wspsnullunsps;8rown<;;j>-'O^__^Oq44H4"hdd0!% %!-@jjjk**37'73 #'xxxx.xx.x..x  pD #'!5!73!GFdFGrEGdGErFGqFGdGFqGEd@L     - FOFc,OO,cFd,PO,dGOP T` '%%%%%% % -wD{wwe#w%f{wwy||y{xxe#w%f{wwxEy||y % %  Zp/AppA/}}ET`     - Zq NqqN  NrqN qrT`% % -ZyllylyyT`%% %% -ZtGcVGttGVcGGstGWcGtsGcpD/3%!!%#'''%!5!%777xo:U.cF.d;UǩoxoU:e.Ec.U9oE.f:UūoxoU9g.Ff.U:oxo9U. 54'&5476276767632+"#"32;2#"'&'&/"'&5476=&'&'#"'&'&547676;232?&547'&#"+"'&'&54767632676'K,68x86,L qA'C<4GW>L d  f L>WG4L d  d L>WG454&'&/54'&5476276767632+"#"32;2#"'&'&/"'&5476=&'&'#"'&'&547676;232?&547'&#"+"'&'&54767632676o**YK,68x86,L qA'C<4GW>L d  f L>WG4L d  d L>WG42#'"372"'&'&/"'&476="'&547>Q!//VZ *nN+G80j@6RR6@j0/P1N TP#00VZ ,lO@W+G80j@6RN6@j03L/N  ]H,`,H Yc!77\4OO4VA7gU3',H^ ]H,`,L&3c!77\4OO7VA7fV4&,H^67654'&"327632#"'&'&/#"'&5476=#"'&'&5476763232?'&#"#"'&'&5476763254'&5476276767632#"'&#"#"'&#"327676%32767654'&'&#"#"Z8%1T1%85e %ZF\ +m8BS/?JV@6RTXN6@VGB1QB8n* \FZ% e53e!&ZFZ *n8BS/?JV@6RR6@VGB1QB8m+ \FZ&!e3DA 5<; > +F$H$F+ > ;<5 AcJ2QD++DQ2J (5H,'9,J&0f) T|\`j4OO7g`\|T 'g/& H,9',I4( (3J,&9-H &0f) T|\`j4OO4j`\|T 'g/&J,9',H5(""'!$(:UJJU:($!'""nFw"2767>54&'&'767632"'"'&'.'"'&'.546767"'&'.546767632.546767632=>343343>==>343343>x>%85670-),(-%8/[0!-(,)-02y/8%0%)-02y/8%-(.'&$W/:#-(,)-02;>/;),)-02;>/8%-( 06{IF{6006{FI{605+'g>:c.&".c;=g'+&1N%&W'+&.c:>k#"$.c:>g'+,B:>g'+&.c;=?nF\v%"'&'.546767"'&'.546767632.5467676267632"'"'&'.27654&'&'&"67&'&'&'276767&5467'&'&#"32767>54&/76767>54&'&'&#"Z0%8/y20-),(-!0[/8%-(,)0-<1:3%>(-%8/|/8%-(>%85670-),(-%8/[0!-(,)-02y/8%0M=  H C# B/g H /*x#$  8## H g/B PP  $#x*/%N1&+'g=;c."&.c:>g'.5 ?=;c.&&.c;=? 5+'g>:c.&".c;=g'+&1N8GG$> >$ c.,bB$#>  Ir0C >'#> LM >#$Bb,.$ >#'> C0rI T`)T:e&'#"&'&'&4767>3267'&#"327%32676764'&'.#"7632#"#.4767676324676762>322##"&'"'&'.5#"'.'&467"&'&'&4767>&'&'.'&'>76?&'326767767>5&'&'.#"767>7.'&/32>7674&'&'67'&'.#"67'&'.'67676767"2767>54&'&'"'&'.54?&'2767>54'7654&'&'&"67'&54676762:    $4 4$ww4 4 xy   %" !()-+U$"! ((\(( !"&S+-)(! '7M"# V2% A()-.R$"! ((\(( !"(O-,*(A"#2P"# "M    ! *4 2 kk  4 2 uKK        i2 4* !== 2 4  `_  wR#$$#R#$$  8 < c !<>     8 < d!!<>   "%UV*) !!$3R  R3&!-(-%Z& "#%(.2$( &&S+,))A!$3R  R3'A))XT$""#%(`$( "      i3+!x== 3 _`        !+3 kk 3 uKJ   F)(GG()F$    %3 3%ww3 3 xy   V^3N^"2767>54&'&/2"'&'.4676762 '&'&547676% %-z35++++++53z35++++++5pWDM69?=;9JHDM69?=;9JHSspsnunˎspsnul}}(.h<;h.((.h; +F$$> +F$H ;<5 A~ ;<5 A+DQ2J (5H,'9,J&0f) T|\`j4OO7g`\|T 'g/& H,9',I4( (3J,&9-H &0f) T|\`j4OO4j`\|T 'g/&J,9',H5(G+DQ2J$(:U$(:U3!'""!'""A''7'753'75377537'7'#5''#5'7#5'7'7<B-DH2#"2767>5!"&54$3!57!#"'&'.5467676#_>I-743TP>CPNDG-2.1/&D9 88 '.* !-8D_2{j@F'%.3r@Md7+4V/2&'&54676762"'&'.546767Zy*,&''&%1]~|45,-++-,54|45,-++-,5(+&a4|d΃fz4a&$(F*.j=3"&'&'&54767>32rJ6464NN4646Jp`684F@NLBD64:866D@NLBD668^~* i654'&#"632327632!"'&5!267&'&#"#"'&54763247632327654'&547632#" 6+Jo.^V|;-˙it36?̺fQMeEJS?(*$ s]vh2K)*NL13^v:Mc*ZeC03N35%&-Kt\K%9S >BWN=!$?$8(F!5{^?Z Q67654 547&'&+327#"'#536767&'&'&5432&5476323254'&5432?-BO>=v06&%K`dC+(k$'eM?$#=Hb B=)+8=.m9eb PB>$3g:84!EB7WPfG+1KHP<Ff#&T'0P+A'<}DC/'"05276767654'&'4rceNS((((`hm@DDF/CD}>C/GFCG !&547>2; 0!!6P<:! !$ ! "#{! !{54&#">32!5!>??qq>0ţ=as;N_/>!RL}A?rFi:}$:&N?(U?"Mt 6+A]A)9IYiy ]1.+. + !'+!+9*'!901! 4$32%4&#">32+32#"&'32654&'26??qq|=_ky4[\XZcksuD}[X@v hA?rs ?<:32#"&'32654&#"75!5!??qqYe2hvvhDw_X@ϰ?A?r%aVUa/  23/4/3и/4ܸA]A)9IYiy ]A&6FVfv ]A] +  + +,&+,/&,901! 4$32#"&54632"32654&#"7>325.??qq\NN\\NN\qºN w/aTJjA?rZbbZ[bb*= P# + + 01! 4$32%!35!??qqlUA?rv]K 1=++ +A]A)9IYiy ]A&6FVfv ]A]A ]A ) 9 I Y i y ]/9;9;/A;;]A;);9;I;Y;i;y;;;;;;; ]5+ )+ +28+201! 4$32#"&5463232654&'>54&#"2#"&546??qq_TT__TT_⾭vijvkKRRKMQQA?rlHQPIIPPI\vSttSvB>=BB=>B &23/4/ܸA]A)9IYiy ]3'и'/-A-&-6-F-V-f-v------- ]A--]+ +  +*0+*# 901! 4$32254&#"326#"&'4632#"&??qq鿹ºO w.aUJk<\NN[[NN\A?rK < O$[bb[[bb $0Ӻ%+%+++A]A)9IYiy ]A++]A+)+9+I+Y+i+y+++++++ ]+ .+ (01! 4$32!5##7##"&5463232654&#"??qq$ŸuF?@EE@?FpA?r*'$ =$>  767654'&'!5%3!!  '&'&54767̆mommom4mommomP\|~{{~||~{{~|96oooo6996oo  oo6}9:݈@>}~Ա~}>@@>}~,,~}> =6P  767654'&'!!567>54&#"5>32  '&'&54767̆mommom4mommom)4 \=)N=kP`aF7I׺\|~{{~||~{{~|96oooo6996oo  oo6_A.Xx;_x55'(IZV@>}~Ա~}>@@>}~,,~}> =B\  767654'&'#"&'532654&+532654&#"5>32  '&'&54767̆mommom4mommomttLUDWx~zB\RGr=\|~{{~||~{{~|96oooo6996oo  oo6yt'(xrjw_Z\bd @>}~Ա~}>@@>}~,,~}> ='A  767654'&'!33##!5  '&'&54767̆mommom4mommomh*˪+\|~{{~||~{{~|96oooo6996oo  oo6 @>}~Ա~}>@@>}~,,~}> =7Q  767654'&'!!>32#"&'532654&#"  '&'&54767̆mommom4mommomz#G#KSLVAC\|~{{~||~{{~|96oooo6996oo  oo6c ۻ)%}|X@>}~Ա~}>@@>}~,,~}> =%>X  767654'&'"32654&.#">32#"32  '&'&54767̆mommom4mommomllm=|< /Vڵ =|^\|~{{~||~{{~|96oooo6996oo  oo6EKۼ>-O@>}~Ա~}>@@>}~,,~}> = :  767654'&'!#!  '&'&54767̆mommom4mommom\N\|~{{~||~{{~|96oooo6996oo  oo6`E#@>}~Ա~}>@@>}~,,~}> =#9E_  767654'&'"2654&%.546  &54632654&#"  '&'&54767̆mommom4mommoms慄htdthutԄ9tihvvhit0\|~{{~||~{{~|96oooo6996oo  oo6,{{|kl{Eggss\hh\]hh@>}~Ա~}>@@>}~,,~}> =2>X  767654'&'53267#"&54632#"&2654&#"  '&'&54767̆mommom4mommom=|< .Vڴ=}mmlJ\|~{{~||~{{~|96oooo6996oo  oo6DJټ@>}~Ա~}>@@>}~,,~}> =+8Ca  76767654'&'&'"32654'.  735733!  '&'&'&5476767̆mo5885om4mo5885omT,+VUVV++2QPPQΠP3p\|~-,g%&݈@>}~~}>@@>}~~}> = $!5!#%  '&'&54767{\|~{{~||~{{~|#:9q @>}~Ա~}>@@>}~,,~}> =6>7>54&#">32!5  '&'&54767I7ݺFa`Lk=N)\\|~{{~||~{{~| ZI('55x_;xX._@>}~Ա~}>@@>}~,,~}> =(B>54&#">32+32#"&'32654&  '&'&54767ir׸G\\Bz~xWDUL2\|~{{~||~{{~|db\Z_wjrx('°t=@>}~Ա~}>@@>}~,,~}> = '! !335#$  '&'&54767hno\|~{{~||~{{~|  @>}~Ա~}>@@>}~,,~}> =7>32#"&'32654&#"!5  '&'&54767CAVHSK#G#\|~{{~||~{{~|=|}'' %@>}~Ա~}>@@>}~,,~}> = $>2#"&546.#"32654&#">32  '&'&54767PmmlC|=ϵѴV/ <|=\|~{{~||~{{~|+޸KE@>}~Ա~}>@@>}~,,~}> = !35$  '&'&54767>h\|~{{~||~{{~|@fE@>}~Ա~}>@@>}~,,~}> = +E2"&46' 654&'>54& 74632#"&  '&'&54767Yt愄/tԃuhtt-tihvvhit0\|~{{~||~{{~|{lk|{{Essgg]hh]\hh@>}~Ա~}>@@>}~,,~}> =$>%32#"3267#"&'"&54632  '&'&54767!C}= дѳV. <|=Allm\|~{{~||~{{~|Q/=޸JDg@>}~Ա~}>@@>}~,,~}> =  :2#"&546$  !5##7  '&'&54767eddedddB¡\|~{{~||~{{~|>-/#&%q @>}~Ա~}>@@>}~,,~}>uPj !!5!!Pp#@pppt 7%FN4NGuP85 zD<22pJJt '-ZKFGNuP!!u\lE>~~>uu+"&'.546?!".4>3!'.5467>2p4,,$$,,42.p ,.".2."., puP8!5! %JZPJJuP8!5! %JHJJuP8 #3#3#3!!5 xx<<oJpppJJuP8 55!#3#3#3oPxx<<΄ΊXXXXu}~ !! ~PD! 6>l>>PD ! DR>l>>P  BlvvuPb3!5 5! '&'.u$##+* ZJMM*+##$0U%!JJ!%UuP84676763!5 5! u$##+* ZJMM*+##$0U%!JJ!%U0!! ^r{VXeoouP855!Dq΄Ξ0uj%5!!53  !<9h9>uj%5!!53  !<9h9>+Z !73#57!!+ Id&+ъ2&+Z 5!'53#'!!!+dI|&22 !'!'!53 !Odcndh 2 3#5!7!!! ndnd;ch dd !53#'5!'! !]n2n22r-hJdc;dJdd 7!573#5!! !2+2n2nr-hLJd;cdJ<6767632"'&'&'! <'CZmo~yti^Z\X^Vqoti^?)X6nGCZ.//+]Y݀z_X0//+]>Iʞ BP "&*.37#37#37#37#5!!!!3'#3'#3'#3'#<<< 7&#"7'7 !%*BF8WU{FC*9oX:WubP 55!5!!'!XXddPRt '327'' !!iFB*8X:*CF9XUpt>*%&#">7'&'&">327&5467>7tBEH#&NKX$W/,0$" D5Hp*G6$"!0,0Y"W!F&'&#GGCuaP'467#"!4676?'&'.5!3!.5P5#$%"//"%X$# 5eeJ(0Y! "X0(Jet*.'.54?'#"&'2767.'32t)H5 X"$ #0,0X"KN&#EHEBCGG&'&KW"Y0,0$"E6GsPX'<6%"'&'.54676$4676762"'&'&&'.54676762$/+z >_ $#R#af#R#)>xbQu 88RK68# 88  vc<*676767632#"'&'&'&%.5467.546A ''+/54<3o8n23'9%%%%bb%%%&:?$ fLLf#&#/:&'X23X'rr'X32XV2c"'&'.54?654&'&'&#!"#!".4?64/&4676763!23!2767>54/&546767622 Z ;:td Z   c   uu  c  2c"'&'.54?654&'&'&+"#!".4?64'&4676763!2;2767>54/&546767622pW\xj IJ \W   8  uP^'#76767&'&/3#>7!5!!5!.'PSJl..&GG&GlHSi7*nK Kn**7OUnm'66'1U=Hd)dH=n&*'$&'&#"'67667 h7Hm^:-3 RE SRQO1̡LHO&57$'&54&#""OER 3-:^mH7hH܏1OQ S #u ! ! j.u-10 3%!#3!Zddd/ #3!53#5ddZd{3 #pph # 3hp&HHT&IIT[[ '#'#'##'x\xxjjxx\x,x\ehhP8\xYY73373737+.x\xxjjxx\x.x\8Phhe\x,OlD=072767>54'&'&'&"7#7676767632#"'&ew@RNJV !'7$"!3!&'&'&'!#!2767676wx !1cbbc1! "1cbbc1" `x]\LM&  &ML\;RR &ML\]]\LM&ZwxZQvcbddbcvQZ[RwcbddbcwR[xV''LM\7=e=7\ML'e;6\ML''''LM\6d 8   2@ @@ 00 ]1@   990@   <<@ <<KSX << Y5!!dx yxUZxxu 8   2@ OO __ ]1@  990@   <<@ <<KSX << Y'7!5!'7 wxy xZwxxd 8ڶ 22@ PP_ _O O]1@    9220@   <<@ <<@ <<@ <<KSX <<<< Y5!'7'7!dxxwxxUZxxwZwxxd 8!!5!! s]xwx]ix]xZx]xiu 87'!5!'7'7!5 ii]xwx]iix]xwZwx]xd 8!7'!!5!'7'XiiiI]xwx]h]xwxiii]xZx]]xwZwxd 8 !5!3# Y#xwxݪ-xZxYu 8 #3!'7'7xwx-\xwZwxd 8 !5!53#5! Y]xwx]Q7ii]xZx]Eiiu 8 !'7'7!#3!7'Q]xwx]iic]xwZwx]\iiu 8%77777773'7'7#'''''''uFFxwxcnFFFxwZwxnF,X@j,,X j,,X@'j,j,,Xj,,X@'j,j,,X 'j,j,,X@'j,'j,j,@j,@'j,j,@'j,j,@'j,'j,j,@'j,j,@'j,'j,j,@'j,'j,j,@'j,'j,'j,j j,@'j,j, 'j,j,@'j,'j,j, 'j,j,@'j,'j,j, 'j,'j,j,@'j,'j,'j,j@'jj,@'j,'jj,@'j,'jj,@'j,'j,'jj,@'j,'jj,@'j,'j,'jj,@'j,'j,'jj,@'j,'j,'j,'jjj,@'j,j, 'j,j,@'j,'j,j,'j,j,@'j,'j,j, 'j,'j,j,@'j,'j,'j,j@'jj,@'j,'jj,@'j,'jj,@'j,'j,'jj,@'j,'jj,@'j,'j,'jj,@'j,'j,'jj,@'j,'j,'j,'jj 'jj,@'j,'jj, 'j,'jj,@'j,'j,'jj, 'j,'jj,@'j,'j,'jj, 'j,'j,'jj,@'j,'j,'j,'jj@'j'jj,@'j,'j'jj,@'j,'j'jj,@'j,'j,'j'jj,@'j,'j'jj,@'j,'j,'j'jj,@'j,'j,'j'jj,@'j,'j,'j,'j'jj,pXj,p,pX@'j,j,p,pX 'j,j,p,pX@'j,'j,j,p,pX'j,j,p,pX@'j,'j,j,p,pX 'j,'j,j,p,pX@'j,'j,'j,j,p,p@'jj,p,p@'j,'jj,p,p@'j,'jj,p,p@'j,'j,'jj,p,p@'j,'jj,p,p@'j,'j,'jj,p,p@'j,'j,'jj,p,p@'j,'j,'j,'jj,p,p 'jj,p,p@'j,'jj,p,p 'j,'jj,p,p@'j,'j,'jj,p,p 'j,'jj,p,p@'j,'j,'jj,p,p 'j,'j,'jj,p,p@'j,'j,'j,'jj,p,p@'j'jj,p,p@'j,'j'jj,p,p@'j,'j'jj,p,p@'j,'j,'j'jj,p,p@'j,'j'jj,p,p@'j,'j,'j'jj,p,p@'j,'j,'j'jj,p,p@'j,'j,'j,'j'jj,p,p'jj,p,p@'j,'jj,p,p 'j,'jj,p,p@'j,'j,'jj,p,p'j,'jj,p,p@'j,'j,'jj,p,p 'j,'j,'jj,p,p@'j,'j,'j,'jj,p,p@'j'jj,p,p@'j,'j'jj,p,p@'j,'j'jj,p,p@'j,'j,'j'jj,p,p@'j,'j'jj,p,p@'j,'j,'j'jj,p,p@'j,'j,'j'jj,p,p@'j,'j,'j,'j'jj,p,p 'j'jj,p,p@'j,'j'jj,p,p 'j,'j'jj,p,p@'j,'j,'j'jj,p,p 'j,'j'jj,p,p@'j,'j,'j'jj,p,p 'j,'j,'j'jj,p,p@'j,'j,'j,'j'jj,p,p@'j'j'jj,p,p@'j,'j'j'jj,p,p@'j,'j'j'jj,p,p@'j,'j,'j'j'jj,p,p@'j,'j'j'jj,p,p@'j,'j,'j'j'jj,p,p@'j,'j,'j'j'jj,p,p@'j,'j,'j,'j'j'jj,ppjp,p@'j,jp,p 'j,jp,p@'j,'j,jp,p'j,jp,p@'j,'j,jp,p 'j,'j,jp,p@'j,'j,'j,jpp@'jjp,p@'j,'jjp,p@'j,'jjp,p@'j,'j,'jjp,p@'j,'jjp,p@'j,'j,'jjp,p@'j,'j,'jjp,p@'j,'j,'j,'jjpp 'jjp,p@'j,'jjp,p 'j,'jjp,p@'j,'j,'jjp,p 'j,'jjp,p@'j,'j,'jjp,p 'j,'j,'jjp,p@'j,'j,'j,'jjpp@'j'jjp,p@'j,'j'jjp,p@'j,'j'jjp,p@'j,'j,'j'jjp,p@'j,'j'jjp,p@'j,'j,'j'jjp,p@'j,'j,'j'jjp,p@'j,'j,'j,'j'jjpp'jjp,p@'j,'jjp,p 'j,'jjp,p@'j,'j,'jjp,p'j,'jjp,p@'j,'j,'jjp,p 'j,'j,'jjp,p@'j,'j,'j,'jjpp@'j'jjp,p@'j,'j'jjp,p@'j,'j'jjp,p@'j,'j,'j'jjp,p@'j,'j'jjp,p@'j,'j,'j'jjp,p@'j,'j,'j'jjp,p@'j,'j,'j,'j'jjpp 'j'jjp,p@'j,'j'jjp,p 'j,'j'jjp,p@'j,'j,'j'jjp,p 'j,'j'jjp,p@'j,'j,'j'jjp,p 'j,'j,'j'jjp,p@'j,'j,'j,'j'jjpp@'j'j'jjp,p@'j,'j'j'jjp,p@'j,'j'j'jjp,p@'j,'j,'j'j'jjp,p@'j,'j'j'jjp,p@'j,'j,'j'j'jjp,p@'j,'j,'j'j'jjp,p@'j,'j,'j,'j'j'jjp,p'j,pjp,p@'j,'j,pjp,p 'j,'j,pjp,p@'j,'j,'j,pjp,p'j,'j,pjp,p@'j,'j,'j,pjp,p 'j,'j,'j,pjp,p@'j,'j,'j,'j,pjp,p@'j'j,pjp,p@'j,'j'j,pjp,p@'j,'j'j,pjp,p@'j,'j,'j'j,pjp,p@'j,'j'j,pjp,p@'j,'j,'j'j,pjp,p@'j,'j,'j'j,pjp,p@'j,'j,'j,'j'j,pjp,p 'j'j,pjp,p@'j,'j'j,pjp,p 'j,'j'j,pjp,p@'j,'j,'j'j,pjp,p 'j,'j'j,pjp,p@'j,'j,'j'j,pjp,p 'j,'j,'j'j,pjp,p@'j,'j,'j,'j'j,pjp,p@'j'j'j,pjp,p@'j,'j'j'j,pjp,p@'j,'j'j'j,pjp,p@'j,'j,'j'j'j,pjp,p@'j,'j'j'j,pjp,p@'j,'j,'j'j'j,pjp,p@'j,'j,'j'j'j,pjp,p@'j,'j,'j,'j'j'j,pjp,p'j'j,pjp,p@'j,'j'j,pjp,p 'j,'j'j,pjp,p@'j,'j,'j'j,pjp,p'j,'j'j,pjp,p@'j,'j,'j'j,pjp,p 'j,'j,'j'j,pjp,p@'j,'j,'j,'j'j,pjp,p@'j'j'j,pjp,p@'j,'j'j'j,pjp,p@'j,'j'j'j,pjp,p@'j,'j,'j'j'j,pjp,p@'j,'j'j'j,pjp,p@'j,'j,'j'j'j,pjp,p@'j,'j,'j'j'j,pjp,p@'j,'j,'j,'j'j'j,pjp,p 'j'j'j,pjp,p@'j,'j'j'j,pjp,p 'j,'j'j'j,pjp,p@'j,'j,'j'j'j,pjp,p 'j,'j'j'j,pjp,p@'j,'j,'j'j'j,pjp,p 'j,'j,'j'j'j,pjp,p@'j,'j,'j,'j'j'j,pjp,p@'j'j'j'j,pjp,p@'j,'j'j'j'j,pjp,p@'j,'j'j'j'j,pjp,p@'j,'j,'j'j'j'j,pjp,p@'j,'j'j'j'j,pjp,p@'j,'j,'j'j'j'j,pjp,p@'j,'j,'j'j'j'j,pjp,p@'j,'j,'j,'j'j'j'j,pjpd?8 !5!53#5!s]xwx]ii]xZx]EiiuP8 !'7'7!#3!7']xwx]siic]xwZwx]\ii 3'#'##-Z-x\xxx\.x\n #\733737#x\xxx\xZ'x\# n\xO'=%"'&'&'&767670327676764'&'&'&pk_V1..1Vbrx`Xk_V1..1V_kpIxXE?#!!';B]YQS@?#!!';BQ9.-\ZnllnZ_.x$-\ZnllnZ\-.)xF!F@RNJV>lmGСBk>DdW0Xdtsݓ.W@#.  -&.%)/K TX)8Y299ܴ]<<999991@ &$-/22907&54&'>5!2;#"#!532654&+CI02Kl>>l5UU5D>kB0GmstݔdXЎW2  5 1Vd22h' %#3 5' :' 73 ٪L^8bb:'B 7''ٛ>PNq'B '''ٛ>PNq^D'B ''>PN'B%  '''tNP'B5  5''bNP#u  u-3!3!!#!#!5 L3ͨ--Ӫ--333333#######5Ϩ---Ӫ---:k7!!  767654'&'$  $'&'&547676h08rtrrtr@rtrrtr VGFFGrGFFG;:rs죟sr:;;:rssr:Ŭɪ:k3?  767654'&'$  $'&'&547676!!#!5!rtrrtr@rtrrtr VGFFGrGFFGssB;:rs죟sr:;;:rssr:ŬɪKss:k3?  767654'&'$  $'&'&547676   ' rtrrtr@rtrrtr VGFFGrGFFG]x3w32x3B;:rs죟sr:;;:rssr:Ŭɪ3x23w3xuM %' o& ' % JuM327!5!>2&#"!!"&' ;E 2&#"!!!!"&' ;E $;E Ϊ@z٨zuM&#"%"&'73275%>2";EC;EJ綠mzzuM*3&#"&'67"&'7327&'&54767>2";EIq(P >6D;E]InoSu=,HK%)AH!+p$ z1IosV2";E+@/V]H6H\nUm;D [>wfP3,,I6x/Ur]HH]lVzM>wrN3 F4uM!3#!!>2&#"!!"&'732w~9F 9 }9Gr0}}uM+3#>2&#""&'73273264&c)~9GcBnnVs~9F (6o~ç|K|oU}uMp.3#327264&#">2&#"632#"'"&'z;E-8pƖqS;E;DܛWI3>6я]z!zuM 13#64&"327&'&767>2&#""&'˔֐;E]InoSu;EcBnnVszяϐ-1Io7sV2&#"!!"&'73273!#3;~9G9G ūI}ޭ{ tMm-&#"!2#567&'!"&'7327!5!>2";Ed_``!;D ܻ`;`*I6ƌebIz`:H:`*F4uM#&#"7'"&'7327'7'7>2";Exx;EzxXyxzyxإzuM*327#467>2&#"#4'"&' ;E-A 4yy;E Z>Vy|-2PIϼ+zEa82JzuM'&#"63"&'7327&'&53>2";E*y;E\?Vy~+&8'zLFaI1zuM>32&#"#"&'7327!5KL~9GALK~9G⧅}}gkb>32&#"#"&'73275!KL~9GALK~9G⧅}}Р?j&  P$j& ' PW P@$ 5 5FѶeѦ 55FѶ///m' P/& P'' P'' P' P/ ' PN:A%#"'&'&'&#"5>32326#"'&'&'&#"5>32326 5jbn ^Xbh`n ^Vhjbn ^Xbh`n ^Vg@PNE;=LTNE;=KPD:32326#"'&'&'&#"5>3232655jbn ^Xbh`n ^Vhjbn ^Xbh`n ^VePNE;=LTNE;=KPD:327&#"56767326 5jbDS4WVhjbm\Y@/Xbh`ES3VXbhZmMp[Y@1Vg@PD4KUNE;@LTNE4LRN"*,@J^po_N5<#"'3267#"/'7&#"5>327&#"5>32732655jbDS4WVhjbm\Y@/Xbh`ES3VXbh`n[Y@1VePD4KUNE;@LTNE4LRND:@J^T 5!5!-5 !5!uu/0\^ҲЪ~T -55!55!usҲЪ᪪/0N%#"/&'&#"5>32326!! 5jan^Xbh`n^Vf@PD:32326!!55jan^Xbh`n^VfPD:323265-5ian^Xbian^VgsuOE;=LSNE; =KJ/0:ҲЪ !(#"/&'&#"5>32326-5 5ian^Xbian^VeuOE;=LSNE; =KJҲЪ/0, -55!55!us%ҲЪ᪪(/0٪, 5!5!-5 !5!uu%/0\~ҲЪ^6 5 5 -55uu/0V/ҲЪа/6 -555 5uuҲЪ۰/'/0K/& 55p/ѦѶ& 5 5p/om//&' P/&' P{ 5!5 5!@Ѫop9{ !5! 5 !5!@Ѫ555@pNpop 55 5@p pU(".#"#"&'5327>76325hV^ n`hbX^ nbj@TL>7632 5hV^ n`hbX^ nbj?TL>֪VJ<:DNTL<:DNDop$+5!5!.#"#"&'53276767632 5hV^ n`hbX^ nbj@>֪VJ<:DNTL<:DNDf $!!!5!676762!!&'&'&!!C.8d 6WYYV7 e8-;Z{+DD\93[2332[0<[EC,W7!!%5$$}y]]x|W%!5505%$}$y|]]W !!'7!5!%5$ZZ N$}qPP]]x|W !!'7!5!55%$ZZ N}$qPP|]] K75!5!%5$!:[]3֪k-QtXVv K75!5!55$%$][:!3֪kVXQ-qK!5!7!5!7!!!!'%5$&`ȉ)P"_=6!:[]ss1st-QtXVvqK!5!7!5!7!!!!'55$%$&`ȉ)P"_=6][:!ss1stVXQ-y:E#"'&'&'&#"5>76326#"'&'&'&#"5>32>%5$ian ^Xbib` ^Vgian ^Xbian g!:[](NE;=LTN9 A=KOE;=LSNE;C E-QtXVvy:E#"'&'&'&#"5>76326#"'&'&'&#"5>32>55$%$ian ^Xbib` ^Vgian ^Xbian e][:!(NE;=LTN9 A=KOE;=LSNE;C EVXQ-6A#"'3267#"/'7&#"5>327&#"56767326%5$jbDS4WVhjbm\Y@/Xbh`ES3VXbhZmMp[Y@1Vg!:[]$PD4KUNE;@LTNE4LRN"*,@J-QtXVv6A#"'3267#"/'7&#"5>327&#"5676732655$%$jbDS4WVhjbm\Y@/Xbh`ES3VXbhZmMp[Y@1Ve][:!$PD4KUNE;@LTNE4LRN"*,@JVXQ-7 5@pppo%5555òi ' '!]#\e#N\#]x#L   !77 ! \ݿ##N]##4 !7 7:\#]x#L]ݿ#\eL#1 4  %''' !]ݿ#\eL#1\ݿ#]j#7P~ % ! !!5 5!3!   7?~% !!3 *^V !!^*  ^V!!!^ ' '!##L  !  ##4%7 7#L4L#1 4  ! L#1#7P~ % ! !3!߆^V ! !! !ECuR #7!5!7Zxx/{xx:xu-R '!5!'xx vx:xH% 7!!7vx{/xxxƪxvH-% 3'!!'Zxx vxx$!%!!W7 r$!!!W7 $!!,7r32 &}f[_ &}f[, %$R/ %$R !2+##5332654&+!ʿ[qrqqϐђАfT$@  $ !? %29999991@&  B  $/999990KSX9Y"@&]@Bz%%%&'&&& &66FFhuuw]]#.+;#"&! 32654&#A{>ٿJxn?M~hb–m؍OH#(07#5#"''7&546;7&'&#"5>327354326=-?\g`n;) T`TeZx_958>cc3Vfa<}NV{ E..''rOs+Ax.ٴ) 3{ B333#;#"'&'##53w1ѪKsQ fև3͏oNP r>7!#4&#"#3676323#d||BYZucce22wxLj%3###3!E3A1wH33 3###%̟8ǹiEL#\ !!#!5!sP=g՚oAX` !!#!5!qjLl}e`R%sw-@ 221/053#5# !232#"MT+焀\\xEEf! !+53265##-}-MDnh %!#3!3҈Rsw%#3>3 !"&#" 7MT!焀UHUk:E={0#3 632#54&"$\^TރQr)m`Tῆrr:T*D  # #3 3 67632#54&#"f:9:76&7#"733%3h kjwrq-xўD|Hv`Q~PH_##"$'5332654&76#"#3$32Ұ $Zh9dR˟YP[yfPu .63 ?# 6%#"?3327632#5&7$'E ۬99 Z. IBauyh$4Q ( dcZe~PA45Gx=%' iK_#6#"#3$324RhiFu~ufP_#6#"#3$32$32#6#"UlhQtxlokg_Q,X $6#"72767#"7#"'53;73$32iO_{k'jh jWz{+Ά8B~BADk6Yl4_ "6#"3%$32#6#"#7#"73$32eRr;'ih삸{$, }Q,ȯW_!#6#"#3$32h5^ ,hs 6#"32%##"73$32oNqm]I4,ǰP9_ "6#"32%#7#"76##3$32$36eoNmIy[fy_,ο}_m )32767$76%&#"#"=3326323Esyx cV&J]z7Sr#1X-;=m;@@]krw?|ӆP[!#6#"#'! #5&#"$36is" ~ ,8|{aAth_%#"7332%332%3#7#",r\iӮ-Ӯ-hr_%#"7332%3#,rs¯Ӯ-##7#"7#"73327332%3LB\Nt2־Q BizhNs^y'h 3$32#6#"#7#"73325mT@ rhsÊr2UyQ,ԯӮh]332%3#7#"7M7ph^ʈa&Ԯ-fJ_6#"$7327! 3$36je!Duc2x-+9KFƺF4DZhJ%#"7#"7332%332%'3#r\h$xmЯӮ-Ӯ,i{"_ -6&32%6#2%#7#'#7!"3$32$32oGp }YH֖t U@,tSP-mnϯ-;,ů1.dE%##3%3%73#mgQ6Z{OBUE3{P\oR{oS{x~P\_$32#6#"#3{ɇ^qQ,_hr`%#"733273#rɜگӮ.@~hh_%#"7332%3!#532$‰rir;.UIYӮ-W׋PT#3$32#6#"|jcKJ={th,8Q,VA`27#73$32 #6#"[wX$(+~sez3殮z3 7# %33C8id,*>'jKp'2ֲ\-XC)P`!6#"#3$32$32#6#"s_`\Dui‰qt,`Q,<\_ #6#"6 %'73 &!"#3$6")g]سŝ,*#s^Qzn(`a_3 73!8`!T^$97C%F`$# /33 73$'#%&'R$waְ;",dRmQr54'&'&s~&&~~ڢ~.]=@N\N\.]=zz❞zz}qa !SM!R}|pas?#-n@.  '&$ /$ .9999991@ .'& ) )./9999999046$327#"''7&7&#"4'32>s~&Ġn~ڢĠnՑꏧw֜\w֜\zvijޝzwkj!^`|g^` .@   <<<2221/03#3#3#3#):@  1/<0@22 # #3.]F; -@    1@  /<<03!#!#!"9q><@  9/1 ]@ /<220KBPX@     @     @ Y333 # # \Xds3{ 1@   <2<2??]1/<2<20%3#3#3#3#\ 7@  91/0@ BKSXY" !!!!&TdD՚ohh $@    1/<<2203#3#3#hhh8o !@  /221/220!!!!5!!o&.-ժo1/,@! ',01*$ 022122<20!"'53 !"563 676!2&# !27# '&%4rmyymrO4%%4Trmyymr4*B6!*:'(8) 6AB6 )*!6oP@   <<222<<<<21@   /<2<<22<<2203!3!!!!#!#!5!!5!!n""xxyyrr3@21/03!!!ժ,o7@   /<<2<<21@ /<2<203!!!!#!5!!5!CCPPxyr7@ KTX@8Y221/0@ 0 @ P ` ]73#3#>@ 10@ BKSXY"47!5!32654'3! $x˿ßwNetwc #/9@1E- !'E0<2<21@ 0*$002654&#""$54$322654&#""$54$32,,,,PIIPPIIPPIIPPIIPs'(@ ) (1@ #(046$32#"$&732>54.#"s~&&~~ڢ~\ww֜\\ww֜\zz❞zz}``}|``s,P@  ! #.# -9991@ ! ((-99046$32'#"$&73277654.#"s~&&~l~\wj\ww֜\zz➞ikwz|`^jI|``; -@   1@   /2203!3!#,dq9d (@   <<<<1/03#3#3#QIh ?@     <2<2??? ]1/<2<20#53#533#3#3#h+Is'+>@- )(( ,9//)]1@+(#,046$32#"$&732>54.#"3#s~&&~~ڢ~\ww֜\\ww֜\zz❞zz}``}|``s>,P@  %$#& !.! -9991@ #&$%((-99046$327#"$&732>54''&#"s~&Ġn~ڢ~\ww֜\pw֜\zvikzz|``|?l^`sr%1=G@8&,20><2<21@/; 5 )##>9//0! #"&547 !&54632! 32654&#"4&#"326sS_  _mz,,,,,,,,gs'O;H66H;O'sz<11<;22<11<;//d #@   <<1/<203!!#!5!IIjk=;;sr3?Kf@F4%+6:0L2<2<29/<<1@=(I C (7##11L9///<20! #"&547"333###3&54632! 32654&#"4&#"326sS_ ̻A;z,,,,,,,,gs'O;H6ߊ6H;OO4z<11<;22<11<;//;@   2<21/220]!!!33##!!!>ժFh*;@ 1/<0)3!3;+y=@ B <1/20KSX@Y!# 5!!!8ks#O@%$!  /<<22<2<21@  /<<<2<<<2032653#2#4&##"#3"3ʊyʊy+VVF%F.@ KTX@8Y1/0!##u-s+f@- ,&'  #+ /<<<222<2<21@+*   #*'"/<<<2<<<29/<205!5"3332653#!!2#4&##"#35ʊAyʊy>FV>=VF=6-@ 1/20!3!3M-n^$36767#"&546?>7>5#53 Ya^gHZX/'-93B$S #C98ŸLVV/5<4-5^1Y72&  PW:X!##:o#5!#&X3!3hXo!533oXKN'6'6'6'6'6&6'6&6'6&6&6'6&6'6&6&6'6'6'6&6'6&6&6'6'6&6&6&6&6&6&6&6'6&6'6&6&6&6&6'6&6&6&6&6&6&6'6&6&6&6&6&6&6&6&6&6&6&6&6&6&6&6&6'6%3F %#"3!"$54$;3@8ʦ1X'7)5!3!+s*j.v !#! !3vb w1Oks'&s'H\=#)# 031j/6T5;.'3;3! &546#"3A{>ٿJx8w~bw+؍hh9;+ .#"#632[hq`QQ,D:=;;< !"3!"3!"&5467.54$3!DՔ| #orqp ˘h$h(E )5!!5!!5!EP9ª,s2)8)*@ 8AKTX8Y1  /<03! #4&#"!!ˮî$*\u sZ@  21  /0# !3! !5aPh//+ji>!!>>!##>@>'_>'_# !##!!>@##!!!!>#!!!!V>֨`!!!!VVrid{jXn`+v)4>@01, *$6E591@ $ *052220#"'&'&#"#"'&547673!27676323 4'&'3ft[na`zxz{n[tfCGo~[U]LKfdKJ]U[~oFCD@@DDDk63366336Fk!<@!  # E"91@  ! "2220!"$"# 33276762324rTRrƒ>IxddyI?ВP8[ 77 [8G<r&,>{&s   !3#!! ! H0x:;hLH+fabgp{ "326&33###" rhո  983#!#!#3! !9҈_:o%+kj{"-#5#"&547!#3!63!54&#"5>32"326=?/j`TeZ߬ofasP`A"..''f{bsٴ)e767!!3##!#!!&aO)p(?x4&A D+k`76765!!3##!#!![(bR-f}v(UԓR:d6T356765!!#!T:WO)fb0d+L`356765!!+!L3DS{X^}з3oP! !!+##-}) `! !!### >?h˸ʹ`3'Ps'y2qu{&Ry.se3#%3# '&76   1L  F<HqC{3#%3#"32654&' ! hJ IHn98s j&&'yryq{'yo'y.':W '/7?GO%3#%3#3#%3#3#%3#"264"264$"264"264$"264"264$"2642+ '&' &547"#"&546;&546 676 3#J"{iihiihiihiihiihiihiihG4UU32UU4IF]97R̬\dfʬ\ʫZee̫ZҜf!!!2+5327654&#!#!qmL>87||ժFwrKK"9+32+532765||BuƣF1n!&edH08L*!!!2!"'&'5327654'&+5!#!^eicUQsj~cd\]ժ˚8+lhzy$1KKIJJ+7L402!"'&'5327654'&+5!;#"&5#533!AicUQ^cdjTmcd\[jKsբe8+lh%12KKKJN`>¨{Rg|1&'&547632&'&#";#"32767#"$546p<HmmFEMUUU8%~` !!!!#+`Ӕo{V 3 3#!+!# ! !J9҈_҈_%s%>+{'{ 5@M"326=%#5#"'#5#"&5463!54&#"5>3205>32"326=63!54&#"߬o?nQ?`TeZxeZ߬o5y`[A3f{bsٴ)Lfa' fa..''~D''f{bsٴ)hn< - 3676! ! '&'!# !  J-p;:xżP.g%H}[[Xr%H{{{"-82 '&'#"&5463!54&#"5>3 6"326="32654&y7!``TeZ*qO߬o{ǝ>REa..''f{bsٴ)nq !3!2653! '!#%{J®sv%_r\4h{{(3%#"&5463!54&#"5>3232653#5# "326=H`TeZ||Cu߬oߍo..''{fcPf{bsٴ) !!#3 3%Lj_:+{N{ ("326=5#"&5463!54&#"5>323߬o?`TeZ^\3f{bsٴ)ͪfa..''5 )!#!#333#%~gY_:gci5R{N{"-0!5#"&5463!54&#"5>32333#"326=!#u?`TeZxgƚÛ߬oGfa..''~mc3f{bsٴ)V !+53276?!#3 3%lKMJ|ثL*+2_:q?=$%2@{VN{'2!5#"&5463!54&#"5>323+5326?"326=u?`TeZ^N|lLT3߬ofa..''wj8zHB3f{bsٴ)s'{ j33#! !##53ʿ3ʿչwH1r3!!3 ###53¹"%kǹ#Ĥf 37!!_(^M*c37#xIS 33#!!#53ʨ_YQx 33###53YR j% 3#! '&#5376 !&'! 76;:~ ż ~HjiF wvҵCҤֆ {'23##"'&'#53676"!&'&!3276o ~~ oV?s?VLVVM{~͐~sUUu%gstgs j$. 676! ! '&'!     ':/##.;:xŽ.$#.yHH5==5[[4=<4HHHq{ 1"32654&!"32654&'267632#"'&'#",nn霜ǝ98 32654&#%!2+3###538ʿ/ϒqrqqĐV{&  533>32#"&'3##5ܧ$:{{:djgdaad̐2'!2+##"&'&5476;2654&+-\0:32#"'# XSܧ3),4:32#"&ܧ$5:{{dj+daa 326&#332+3##5#538ʿ'ђ H^ddV&  533>32#"&'3##5ܧ$:{{:djgdaad̐ !#!5!)+Vy{3#\{V3"&4&#"#367632o͚Qfe}–}CBV{3"&'4&#"#3>32dJlʣ||Bua ed#Ib !5!5!5!b>>I5:@ K TX8Y991@ _]0 P]3#5qeo7@ KTKT[X8Y10@ @P`p]#o+MVT&#"3733#;#"&50# 76327M\P=x1F<5K9p|t !33#!#ĪjA{3##4&#"#3>32d||BuR`ed9(%!5!#$'&''7&5!2.# !26uƍ(T+p^op+jkSU̒%nHF_`_w%V{&0:%!"&'5326=#"'&''7&53253732654'&'&#"ZaQQR9|~Ch!t|9!.R 2R,*[cbSp#c'8>:bc2c==W367'&'&#"dǹ!BucJ! 3>|\jTo2c=edxY1c90u@O_$+#.+#'7! 7-&'&'#3767A{>ٿJxʚ+~I+,JJ= ~hb3BFk>dNU ?(B(D8cJ{.#"%#'73>32JI,!-!:.˾4bTo2c<fc/.#"%!"&'532654&/'%&'&54$32Hs_wT"+W6lj{ra+eM0ei76vcew'8l0/EF~n|w".`&'{/.#"%#"&'532654&/'%&'&54632NZb-!K,RZlfae$O!#>&Lf?((TT@I! cc (L##55YQKP%ca&J#546;!3#!#-v"0^i1Fd+93!533##!##53!5jj2ii}}}\rk\\~~G'1.#"!3267#"&'#"&54632>32$"32654ogW`usC~>?Ce3-XX*1Zml^]lUdaY2jpa==><><<>L⁂po`w #!5!!5Pp+ɪF #";##"$54$3@/+X 3333! +m3#mD U%3 3# # #3>:9w+X10!5!-ЈX'3I(sInhX#'3h'OW`4X#'3v5]dDZX#'3 |;d07!X#(ẌI$Qh$Rn4$S`$TnhX#7OhWh$VhQ4RnS`4X#7]vDdn4$[4V4QdRdZX%#7d|!70`$`n[VdQ0<0^X133ֈX: #'+/37ڷ/$0(7,48<<<<<#+ 3'<<<<< <<<<< <<<<<9̰XKRX8K bf TX30<xN\adUrn$.%675!26! $547&# !&'$! $ ce'4'T8 N!Vm0w_c-SR@@]wlo6! 3!4!"#! 6"Zn':SE/Os n6! 3! 54'#5364##'! 85<'0[%|s}Ns(P n &"673! ! 7! 547&5! 3hf=G=e H6ߴ_c vK]XKRF.%@n "! ! %!$#"! !663 I W .<s~\Fy-Cm!n## #! ƤۮȤ{C~fSyn6! 3 5+53$54'!6+<'0ܯd$DxxfnU(}1(!n6! 73! 54'#53$54$53605!s]{%0߳?C-?rݲynn5% 3! %5'6%5%5!!3`]JVO;2x}ΰ_n&#5% #! #5%$!$7 63 } u|bbIK^(w4J! 3! 54'73J#+5-J-RkmvIK&|nj$3254'##533! 547 X֒./w@DD\u&IR2'! 3! &#"#&'#53263 '48DB§Kiq.5ThMn 7! ! !#"$53;265+5765!"%5!263 F2dڂJ|;o&I+mvyف;͉5pr)Z{n5! 73! '#'235#7E!?дB<mݩN$^n*7675!23 #=! # !&'$x`ىxvS8߱b" K a`TTr@mMpRcEn4! 3! 54736734!"!?5 Dc (Ԕ( t9n4#&#  ! 5!4#"#54!5 63 s`1 ㈲6UKIr] =`|::J74#"6#=&#! ĮځUuh=^ub|p# 325&+53$54$73(r׆̫Z ${Hp,=ceTn4 &# ! ! 5!63zD䦔PpYql>J=RII$!26! #54#"67 ! 3! 5!"[`%礧 0Iωy:DDUwqR`n\##3#! 73! # !3'33;#"[?~W#;H 5^g^%"Di5N-6ϥGJ !! 7! 363ˢ9&&UXvn_%N2!%!5 65&%'%7764&#532MPsyPjJ@JKp̊nz(ES8KJ7n5&! 3! 4+53254'#53254!#53 35!!-ӚmvvQIųyaNGnx>& 3! 4'#5327&+53654!5 #\0'loM}ҥSg~\VNn_6 $! 27#! 3"%#',$*۾?.hxx`S^;^On4! 53! 5+53$#%4%%({[FLxqnB ! 53! !#53$#3!2735! -ng!!} )掎F`own%!$! 5)4! ! %#$! 3#3&29 # ㌌bxl!j`?~ʸn6 ,4&#  !"'!5 5!"! 5$7 6!| '/ڋ%v'Úk݇lx'Ŀz#32%$76#"##"6%3$32Bpr.HZd D]]ǩ*H$OH5*N,FhI(2:(jnd(0<$47'&'#&%'67$%&573265&5#"6kVorb32#4&#"#9`M1Cuȸ||MM 7BuƸ||e,'"xMfca?'Gzed\V5<!"'&76763!!32653#5#"&5#3!#"&5332765!"3ە^SWsv||CusCuȸ||WVۃ^SBWLa{fcBVfcf__{{V H!&#5#"&5332654/&763!6763232653#5#"'&=4&#"#9`M1Cuȸ||MM 7c%Zk>8nClbd||xe,'"xMfca?'Gz2XO{fcx{䟞[B`&0NV 332673 &Vv aWV` v ޞKKJLJ[`&DN~`27676=3#!5!c\@&@exj`Qq73>53zK-b[;Iwz?-b\;2Nh`i8^X dwNji8^X VnZ7X`##!5!ʺe/я`#4.#!5!2%# '>ni+ՅĔ^;kjt@,?]ET`X`!2#!5!2>4.#!Xז\##\(qf==fq(`AiiA*HnuunH*X!!3!\\CL$`)!2!4.#5Ӄ5W !3WmO`<٧^h=)X`#4.#!5!2Tt7ӂ5m)<``#4.#!#"'53265#5!2 $@pP${5NA&G.Cl,^`Jce:%r3C-!5!3!----XS&"@NS&N@XS'X&"@XS'X'"L@`&'u`&'`&'XH`'(X`'!)X`'*`&+Y`' ,Y`' -zk&/Y`' 0XV`'1X`'2X'Q3Xp&05Xx`'!7`&8Vd`&q:`&|;X`'Q=V_&>X`'?XS`'9 @`&At'",XH' q(X' A2& ;X, ##54>7#33>53r`#8!2-A,x#8"2.@,eX5AnEQ`Q2,  BL 6AnE RaQ1, '19 '193 X&41 ~X'15 '0 '03 X&40c ~X&50c '2 '23 X&42c ~X&52c'19'193&41L~&51L'2&32&42cL~&52cL'L&3L0a&4L+p~a&5L+p'/x~\F&6/x?&7/,~ x&8/>'2xx\F&62x?&72,x x&82> (f'1[ >f'1}>\/&1 8>>/&1 8 (f'.[ >f'.&8\/&.88>/&.8 (f'0[ >f'02>\/&08>>/&08 (f'2[ >f'22>\/&28>>/&28}R'.+]}GR'.+}'.]}G'.}'/]}G'/}'L]}G'L '/ _ ~&/ /&_L> ~/&L>)7%#"'$47332767654'&54767;#"'&/cͷ?Ahž#62 #dGG&+@XA:g!axL54#"%473303576 !! &5"'&3254&'?TKJ&|tD.^(.E:q!&PET*4pHuJ6>(E&7 kcCryblBc5/iCp4  '/qFl&/qFl&/Kl&/K @&qx 6&x @r'>q 6r'> @4&q 64& @&q/, 6&/, J&r1'1 X'14 ~X&51X %+53276=3+HZ#c,1VV,1jٻ~X%+53276=3;#"+MZ#c,11,c7nVV,1jj1,JrX&Q.c~X&R.cpn"56$3=gi~wun52&$=Ԛuw~ig* '/&'&#"#67632O,$e5Fqp[?8WH7  $0GJI  '327673#"'&'O,$a9Gqp[?8W7  $,KJI Pt,l&it,Pu,i,k ;#"'&=3!1,cK\WL71,\W+Pv,Pw,l'w,iPx,l'x,iPy,l'y,idz,l'z,i<{,l&i{,UO'|U&|l9'}Ul9&} @'}>q 6&}>l '~Ul &~'}>r&}XD&Q}+p~&R}+pyU 3;#"'&1,cKPWskj1,\e'-9&3-9X&4-~X&5-'.p^&.^ '. &3.&4.cR~&5.cR'/&3/&4/cR~&5/cR (f'-[ >f&-\/&- >/&- (f[ >f0%3#"'&'&'!27# '&5767"#"5$3 "(1{R=IrbJIԖ^` __&m3HZdP^vc–e4)?6 [_w\/&'&'&5672+5327676SSgURHKLXJKݣdht^#4b4bBPH:jV>/);#"'&'+53276767&'&'&5672~AI2hrBV~(;E)Kݣdht^eSgURHK 4b)N"w6a.%PH:jV# ('-?[ >&-?\L&- >L&- }R]}GR &'3;#"'#"'532767654"9aRQS,cKa].-fgsT!"#?zNuIS,!&* 1p*D}'-E]}G&-E b&_ ~&3;#"'!5 767654x I*eK2D0# &pgM,>ꅗ:H~ b'-q _ ~&-q a GF%7653323;#"'#"'&''&'#&'$473327676'&/3N0%@nS,cKvDm% I01_@8'TPxmil_Qb_y^@@$:|_2&aS,`[ F{GHܳ&%0l}=J<~ 1%+53276=3327653763#"'&'#"'&+8LcKc,P,+hm,%@n\Kf%#?70`DAbH<;!.,Pd@dczg2&q\ =!1(78#"'&'#"'&'+53276=3327653763;#"'%#?70`DAbH<)+8LcKc,P,+hm,%@nS,cKvD =!1(I;!.,Pd@dczg2&aS,`Z '/ a G&/  &/ 7&/ c <I)"'&5#&'$47332767654'367676;#"/"3276'&'&u&4-JXPxmil_Qf[+!' (s{lHX}a*=RKgL~큻%MGHܳ&%Dl7(2l^F"%GMF ,\v7Ql?[F2 .327654'&#"!"'&'+53276=36767632Ш큺%0LJNA'fKc,P-e_KUskl?[F*#=,PdrNP2T?!'Dmx+8)"'&'+53276=36767632;#"/327654'&#"JNA'fKc,P-e_KUqm*=RKg਑큺%0L*#=,PdrNP2T?!'DKH ,\vl?[F '- c &- 2&- &- e))5!3%632;#"/%3276'&'&#"@o\Dui*=RKg큻%0Pz\?c!'EMF ,\v?]DQx %3276'&'&#")5!3%6329큻%0Pzu \Duiʸ?]DQx\?c!'Emx))5!3%632;#"/%3276'&'&#"8 \Dui*=RKg큻%0Pz\?c!'EMF ,\v?]DQx'-Re&-R&-R&-Ru *gu %+! '&7.54762;# '!2764"[b=D}a_[9^DU)k_1ocz2t*n@00@p[C+ @Mkl=v8`3$*727&'&5763"327%+5SF7J \X];d}M4F!Ť$/%+532767&'&5476762;#""654'v`kB;(aD hYYh MXD=p`vʨ4/gg/($'UZ'-)74--47)-'bM,(U __ u F'-wgu L&-F&-wL&-'-~\L&6-?&7-~ ~&8-kH'.R~k &9.k?&:.,~ ~&;.8l!D#"'5327654'&'&7676'&'$54733276763;#"'J&P DfXRNB8D-<9_h$$EB|=Q#!v+6(  %{{qe))5!27654'&54767;#"'&/66-62 hGG&+@XA:g!a_h$$EB|=Q#!v+6(  %?+)x.m#$%653;#"'#"'$&733276N1,cKpNyUcE@A(IPmI~jkj1,3.(B"[\ss~B"5 +5327653WPKc,1se\,1j%+5327653;#"SMKc,11,cKVV,1jkj1,^ngt5%327654'&'&#"#"'&#4763&547632;#"bzL,5;(.;D K2KxAZM\HT((&iK*9:X DD(PNNOmf7*(?$GC,,m$%#"'+5326767632%327654'&#"dan@ht4W^Q[a>/4(*X.[4fb0G1P8TYNE5EK&)/4:''5)24fb0$#1P8S1>,E5EX !a%H'-?  +&8-?&'-R4~'-R5p^ $&'&'&'3;#"'&'#"'&5476 xRot$8pKZI-&8:m*12e CY>)2'+eO,3;I0D-=67654'&#"27&'&5476&'5#"'+5327654'&$"':A4N--0M,Q@(Jxb 41}! @H=.%4-+#%v iEN@TSZ 'D49g=ql)D%'i.C!v-3j  ;AWE L9P)8K6(S/VL_+Y9K1\SJr765&'&'&54767632;#"'&#"#"'$4733276L[/,4PT*uW ##rpl$-AIqYhu?AB[M!3!+ (;=A<^ĸ#0{bV` )gZZrN J'. r '. X&Q.c~X&R.c.&|,.&|,&},&}, &~ &~T#"'53273676537M͞jK`Uq%BUG FA+7T#"'5327367653;#"'&4;IʡjK`Uq%"@Pif<[A FA+7DT)TL* 35'5467676?67654&#">32,X\"$߸g^aOl39ZZ8L{4<+VZ@EL89CFnY1^5YVed 73!!d00#N@ | $327654&#632!"'327654&#|4w=Ưވdudo^,~#r;BYWa{zzp4=8hd  kxww 33 !7>'.'Z '8ZA xzebcz\  #%%|  6uSXSX #%| *uSX !#3!53#Xմm8 !!!!!p+E$## $&6$ 67!!!!&zzz : zSN{{ : {{ 0 |3#ȴ+ !#3 |x.xq={C #3|M3M  3  #t8/.R9/S.Lw3  #t8R9SL !!!!!!!|p,Dܴ$E+!$$o$'64."26 $&6$ "&462^^ޟ^^zzz : zRtRRtRߞ__ߞ__X{{ : {{RRtRR$54$!"#63 ( 57~bYfԶ* 33 3# ȴ^+_C 4."2>#&'.4>2fH}}HH}}zf@HGAhxyy|HH|}HHL;%w%]a{w DD663! )327&#!36'hPcp~qAA k{qS3%!!!!!!-x9vq dddsd !!!!!#3#oQn.ddqs&&$#"32767!5!# !2deVRuu^oRaG@;@&5dSUmnHFcIf3%!#3!53#.nXddddq dddd fY6765%!#!53265-V?O?nqd J^ dd0 !3 #!3pdw@1q 2 !!!3ddo o !#!! !3!3_Gbn}qR+q  r'( ! '&76 7& 676'&&:żGlllli$ #ab2222jT%%5$c$-6&/.4%&  %5 64&/.$ Pdo&nŢmngzoʷ-[ʚ)'NXd''pui$2Xf| / 3%!!!!rpq ddq $!&%! 65! X!!Y fqba@`|gd5\*$ 3%! 3!dq d+D 3!3%! ! 3! !D5D:9:9d|q  d+l 3%! 3 ! #(\~vbL:H|dq d22{ 3!! #3ndp29V{{",34&'3!5#"&546;54&#"5>3 5#">76/=Kd?Vu`Tw86/^b;:gCzӆ]YfaH..t''UNHGgwt-!>32#"&'!4'&'676763&#"327N:||:^,<<,9RKM_]daadt= z =OsKTdihtJq{#%#"!2&'&#"3276%M]-ULEmGJXHCQRHV,${z$d$$>:##dWS%&-!!5#"323327654'&'&#"N:||v9,<<,^(]_MK^daDDaZKsO=  =Td6Jthio}{!327# 32!.#"}K_mk)#i̩J@b]u-)8 CqzӾ/ 3476%#"!!!#5354763g.9:9|WX -8J_D8d97ddddTVqV{#.=65326=#"325!!"&32767654'&#"jlQR:||:Nry^,<<,9/KM_]=ʌo,*qdaDDad-w=  =OsKihtJH "34'&3'!>32!4&#"! GS5‡OIƁkk h@[:Lded\ПU5 33#!!JKOhV #676#532765!3#%G(=1l$%OQRaеT0Hd01``2 !3 #!3OHіmdi#L&5#"'&5!3J=(G%RQOLiH0T0Z``~J^d{"&1<!>32>32!4&#"!4&#"!3%34'&%34'&OIƁԝTށkkkkd[ GS5 GS5`edJv\П\ПUh h@[: h@[:H{ "34'&%3'!>32!4&#"! GS5‡OIƁkk h@[:hded\ПUqu{ #2#"27&"676'&s3x33x3d4'pp'3(pp({98  kp-$-R-ۀ-qV{-%!!>32#"&4'&'&'676#&#"32N:||9,<<,^؆]_MKdaaKsO= z =oHJthiqV{-%#"325!!3#32767654'&#":||:N<^,<<,9(KM_]daDDad=  =OsK2HHihtJ{3'!>32.#"!N:4I,hdfc˾zo{E67654'&/&'&5432654&/.54632.#"#"&'i'K&'q4=B%%U+.39GSOjqL4vfLJ\_opPx3Zl=vf03"3;@{R?Bsl37'*7CoT78^UNO,, z1$YXDL#/%%7%&7#!!;!"&5#53*\{KsբjU|7N(dUNdudTD` "%&'&5##!5#"&5!3265! GS5CIƁTkkTS hl[:hded0=` 3%! 3!YT^^d\hdTV`3!3%!!3! !bTNdhhdjjjL` 3%! 3 ! #U|p|[hd-s=V`7%! 3+53267>^]_lP|XQ+ۙdi8{dCYXb` 3%!!!5!\vwhddhddh$%s'&'(#)s*;+f-j.j/031s23s4T567)8h9D:=;;<\={-{DEq{FqZGq{H/IqVZ{JdKyLVyMN9u{Pd{Qqu{RV{SqVZ{TJ{Uo{V7WX{X=`YV5`Z;y`[=V`\X`]   6/&"27 d3{44{3s s#Տ0,-k37!!5!5%6bJJgq ddd HdH(7!676'&'$32!!7676&#")`"LlDbZE0Q](=ymd͕@9\9pd9hbiddAbs$*0"'5327&+5327&#"56325654&'>54+!ĪeO6?;2:L uWEdJj D d <h@Ѳ|!ŐUl$yXZ#3 !!3#!!5Qpq3d\#66'&#"!! !"'532gd1jKEн܁\`I Kd# F_h$$EB|=Q&v+6(  %z|qe #!5!27653WPEc,1se\,1j<m%%#"'#!5!26767632%327654'&#"an@h 4W^Q[a>/4(*X-.*4fb0G1P8TYNE5EK&)d%&H-Rn1%+53276=3327653763#"'&'#"'&+8Lcc,P,+hm,%@n\Kf%#?70`DAbH<;!.,Pd@dczg2&q\ =!1(*?'-~7 .327654'&#"!"'&'+53276=367676324큺%0LJNA'fc,P-e_KUskl?[F*#=,PdrNP2T?!'Dmx?n&/ &H.]R'/]RHL&-q'-? F'-4'-}"-'7G3;27&'&5476&'5#"'+"'&327654'&67654'&#"1,c4N--0M,Q@(JxPWFb 41}!$"':Askj1, iEN@TSZ 'D49g=ql)\e;%'i.C!_\PWskj1,h$$EB|=Q&v+6(  %z|qe\e/%327654'&#"#"'+"'&53;26767632>/4(*X-.*an@hPW1,c4W^Q[aE5EK&)d%fb0\ekj1,G1P8TY'-R4z;3;276=3327653763#"'&'#"'&'+"'&1,cnc,P,+hm,%@n\Kf%#?70`DAbH<)+8LcܚPWskj1,,Pd@dczg2&q\ =!1(I;!.\eh$3;27&'&5763"327%+"'&1,csK4X}ں>SF7J \PWskj1,];d}M4F!Ť\e'-~5+83;276=36767632)"'&'+"'&327654'&#"1,cnc,P-e_KUskJNA'fܚPW큺%0Lskj1,,PdrNP2T?!'Dmx*#=\e%l?[F'.~5z'/ ('.iR4'/iR4'-}"'-K +D'-7R#h'-)%#!"'&53;276=31HPW1,cc,1VV\ekj1,,1jٻ*:33!276767'&54767632#!"'&654'&321,cTO<?aNbNLZB`.NJ|mePW)B,4((7(*Hskj1, ]027EW-3E$2Hf3Џ,'\eX+M;3*)3P&F !;3#!. Y_$ F !; 7!'!%3 YٍF %=F !;"4767632"'&'&!'!%30&$I Yٍ$$% %=F !;,048"'&'&4767632"'&'&4767632!'!%3$$%$%$ Yٍ?H%$HG %=F !;+AEIM"'&'&4767632"'&'&476762"'&'&4767632!'!%3$$%$H$%$ Yٍ?H%$ JHHG %=F !;+AW[_c476762#"'&'&4767632"'&'$476762#"'&'4767632"'&'&!'!%3'H$%$%HH$%$%H Yٍ$JJ%$J%$S$J %=F !;+AWnrvz476762#"'&'&4767632"'&'$476762#"'&'4767632"'&'&4767632"'&'&!'!%3'H$%$%HH$%$%H&$I Yٍ$JJ%$J%$S$J$$% %= F !;*@Ui"'&'&476762"'&'&5476762 "'&'&4767632"'&'&'476762"'&'.76762"'&'&54767632!'!%3$H%$HJ&$UJHJH~J&$ YٍRHJ%$HG$$%$HGH%$H %=F !;!476762"'&'&!'!%3JH Yٍ$$% %=F !;,048476762"'&'&%4767632"'&'&!'!%3JHd&$I Yٍ$$%%$$% %=F !;,BFJN476762"'&'&"'&'&4767632"'&'&4767632!'!%3JH$$%$%$ Yٍ$$%H%$HG %=F !;,AW[_c476762"'&'&"'&'&4767632"'&'&476762"'&'&4767632!'!%3JH$$%$H$%$ Yٍ$$%H%$ JHHG %=F !;+AWmquy476762"'&'&476762#"'&'&4767632"'&'$476762#"'&'4767632"'&'&!'!%3JH]H$%$%HH$%$%H Yٍ$$%.$JJ%$J%$S$J %= F !;+AWm476762"'&'&476762#"'&'&4767632"'&'$476762#"'&'4767632"'&'&4767632"'&'&!'!%3JH]H$%$%HH$%$%H&$I Yٍ$$%.$JJ%$J%$S$J$$% %= F !;*@Vk476762"'&'&%"'&'&476762"'&'&5476762 "'&'&4767632"'&'&'476762"'&'.76762"'&'&54767632!'!%3JH$H%$HJ&$UJHJH~J&$ Yٍ$$%HJ%$HG$$%$HGH%$H %=F !;+/37"'&'&4767632"'&'&5476762!'!%3rJ%$$Jm Yٍ@H$%$%H %=F !;"8N4767632"'&'&!'!%3"'&'&4767632"'&'&54767620&$I YٍJ%$$J$$% %=H$%$%HF !;,048Nd"'&'&4767632"'&'&4767632!'!%3"'&'&4767632"'&'&5476762$$%$%$ YٍJ%$$J?H%$HG %=H$%$%HF !;+AEIMcy"'&'&4767632"'&'&476762"'&'&4767632!'!%3"'&'&4767632"'&'&5476762$$%$H$%$ YٍJ%$$J?H%$ JHHG %=H$%$%H F !;)>SW[_t476762"'&'&476762"'&'$476762"'&'476762"'&'&!'!%3"'&'&4767632"'&'&476762'HIIHHIIH YٍI%$$I$II%$I%$S$I %=HIIH F !;+AWnrvz476762#"'&'&4767632"'&'$476762#"'&'4767632"'&'&4767632"'&'&!'!%3"'&'&4767632"'&'&5476762'H$%$%HH$%$%H&$I YٍJ%$$J$JJ%$J%$S$J$$% %=H$%$%H F !;*@Ui"'&'&476762"'&'&5476762 "'&'&4767632"'&'&'476762"'&'.76762"'&'&54767632!'!%3"'&'&4767632"'&'&5476762$H%$HJ&$UJHJH~J&$ YٍJ%$$JRHJ%$HG$$%$HGH%$H %=H$%$%HF !;+AEIM"'&'&4767632%"'&'&4767632"'&'&5476762!'!%3rJ%$$$%$Jm Yٍ@H$%JI $%H %=F !;+AX\`d"'&'&4767632%"'&'&4767632"'&'&54767624767632"'&'&!'!%3rJ%$$$%$J&$I Yٍ@H$%JI $%H$$% %=F !;+AXnrvz"'&'&4767632%"'&'&4767632"'&'&5476762"'&'&4767632"'&'&4767632!'!%3rJ%$$$%$JV$$%$%$ Yٍ@H$%JI $%HH%$HG %= F !;+AXm"'&'&4767632%"'&'&4767632"'&'&5476762"'&'&4767632"'&'&476762"'&'&4767632!'!%3rJ%$$$%$JV$$%$H$%$ Yٍ@H$%JI $%HH%$ JHHG %= F !;+AWm"'&'&4767632%"'&'&4767632"'&'&5476762%476762#"'&'&4767632"'&'$476762#"'&'4767632"'&'&!'!%3rJ%$$$%$JH$%$%HH$%$%H Yٍ@H$%JI $%Hz$JJ%$J%$S$J %= F !;+AWm"'&'&4767632%"'&'&4767632"'&'&5476762%476762#"'&'&4767632"'&'$476762#"'&'4767632"'&'&4767632"'&'&!'!%3rJ%$$$%$JH$%$%HH$%$%H&$I Yٍ@H$%JI $%Hz$JJ%$J%$S$J$$% %= F !;+AVl"'&'&4767632%"'&'&4767632"'&'&5476762!"'&'&476762"'&'&5476762 "'&'&4767632"'&'&'476762"'&'.76762"'&'&54767632!'!%3rJ%$$$%$JI$H%$HJ&$UJHJH~J&$ Yٍ@H$%JI $%HHJ%$HG$$%$HGH%$H %=F !;)>SW[_476762"'&'&476762"'&'$476762"'&'476762"'&'&!'!%3HIIHHIIH Yٍ$II%$I%$S$I %=F !;!6K`u4767632"'&'&!'!%3476762"'&'&476762"'&'$476762"'&'476762"'&'&0&$I YٍHIIHHIIH$I %=m$II%$I%$S$I F !;,048Ndz"'&'&4767632"'&'&4767632!'!%3476762#"'&'&4767632"'&'$476762#"'&'4767632"'&'&$$%$%$ YٍH$%$%HH$%$%H?H%$HG %=m$JJ%$J%$S$J F !;+AEIMcy"'&'&4767632"'&'&476762"'&'&4767632!'!%3476762#"'&'&4767632"'&'$476762#"'&'4767632"'&'&$$%$H$%$ YٍH$%$%HH$%$%H?H%$ JHHG %=m$JJ%$J%$S$J F !;+AW[_cy476762#"'&'&4767632"'&'$476762#"'&'4767632"'&'&!'!%3476762#"'&'&4767632"'&'$476762#"'&'4767632"'&'&'H$%$%HH$%$%H YٍH$%$%HH$%$%H$JJ%$J%$S$J %=m$JJ%$J%$S$J F !;+AWnrvz476762#"'&'&4767632"'&'$476762#"'&'4767632"'&'&4767632"'&'&!'!%3476762#"'&'&4767632"'&'$476762#"'&'4767632"'&'&'H$%$%HH$%$%H&$I YٍH$%$%HH$%$%H$JJ%$J%$S$J$$% %=m$JJ%$J%$S$J F !;*@Ui"'&'&476762"'&'&5476762 "'&'&4767632"'&'&'476762"'&'.76762"'&'&54767632!'!%3476762#"'&'&4767632"'&'$476762#"'&'4767632"'&'&$H%$HJ&$UJHJH~J&$ YٍH$%$%HH$%$%HRHJ%$HG$$%$HGH%$H %=m$JJ%$J%$S$JF !; !7Mcy7!'!%3476762#"'&'&4767632"'&'$476762#"'&'4767632"'&'&476762"'&'& YٍH$%$%HH$%$%HJHF %=m$JJ%$J%$S$J$$% F !;"8Ndz4767632"'&'&!'!%3476762#"'&'&4767632"'&'$476762#"'&'4767632"'&'&476762"'&'&0&$I YٍH$%$%HH$%$%HJH$$% %=m$JJ%$J%$S$J$$% F !;,048Ndz"'&'&4767632"'&'&4767632!'!%3476762#"'&'&4767632"'&'$476762#"'&'4767632"'&'&476762"'&'&$$%$%$ YٍH$%$%HH$%$%HJH?H%$HG %=m$JJ%$J%$S$J$$% F !;+AEIMcy"'&'&4767632"'&'&476762"'&'&4767632!'!%3476762#"'&'&4767632"'&'$476762#"'&'4767632"'&'&476762"'&'&$$%$H$%$ YٍH$%$%HH$%$%HJH?H%$ JHHG %=m$JJ%$J%$S$J$$% F !;+AW[_cy476762#"'&'&4767632"'&'$476762#"'&'4767632"'&'&!'!%3476762#"'&'&4767632"'&'$476762#"'&'4767632"'&'&476762"'&'&'H$%$%HH$%$%H YٍH$%$%HH$%$%HJH$JJ%$J%$S$J %=m$JJ%$J%$S$J$$% F !;+AWnrvz476762#"'&'&4767632"'&'$476762#"'&'4767632"'&'&4767632"'&'&!'!%3476762#"'&'&4767632"'&'$476762#"'&'4767632"'&'&476762"'&'&'H$%$%HH$%$%H&$I YٍH$%$%HH$%$%HJH$JJ%$J%$S$J$$% %=m$JJ%$J%$S$J$$%F !;*@Ui"'&'&476762"'&'&5476762 "'&'&4767632"'&'&'476762"'&'.76762"'&'&54767632!'!%3476762#"'&'&4767632"'&'$476762#"'&'4767632"'&'&476762"'&'&$H%$HJ&$UJHJH~J&$ YٍH$%$%HH$%$%HJHRHJ%$HG$$%$HGH%$H %=m$JJ%$J%$S$J$$% F !; ":Pf|7!'!%3"'&'&54767632"'&'&54767632 "'&'&4767632"'&'&'476762"'&'.76762"'&'&54767632 Yٍ$$%%$$%J%$0$H%$HJ%$F %=%$J&$$%H$%$%HH$%$%H F !;"9Qg}4767632"'&'&!'!%3"'&'&54767632"'&'&54767632 "'&'&4767632"'&'&'476762"'&'.76762"'&'&547676320&$I Yٍ$$%%$$%J%$0$H%$HJ%$$$% %=%$J&$$%H$%$%HH$%$%H F !;,048Og}"'&'&4767632"'&'&4767632!'!%3"'&'&54767632"'&'&54767632 "'&'&4767632"'&'&'476762"'&'.76762"'&'&54767632$$%$%$ Yٍ$$%%$$%J%$0$H%$HJ%$?H%$HG %=%$J&$$%H$%$%HH$%$%H F !;+AEIMd|"'&'&4767632"'&'&476762"'&'&4767632!'!%3"'&'&54767632"'&'&54767632 "'&'&4767632"'&'&'476762"'&'.76762"'&'&54767632$$%$H$%$ Yٍ$$%%$$%J%$0$H%$HJ%$?H%$ JHHG %=%$J&$$%H$%$%HH$%$%H F !;+AW[_cz476762#"'&'&4767632"'&'$476762#"'&'4767632"'&'&!'!%3"'&'&54767632"'&'&54767632 "'&'&4767632"'&'&'476762"'&'.76762"'&'&54767632'H$%$%HH$%$%H Yٍ$$%%$$%J%$0$H%$HJ%$$JJ%$J%$S$J %=%$J&$$%H$%$%HH$%$%HF !;+AWnrvz476762#"'&'&4767632"'&'$476762#"'&'4767632"'&'&4767632"'&'&!'!%3"'&'&54767632"'&'&54767632 "'&'&4767632"'&'&'476762"'&'.76762"'&'&54767632'H$%$%HH$%$%H&$I Yٍ$$%%$$%J%$0$H%$HJ%$$JJ%$J%$S$J$$% %=%$J&$$%H$%$%HH$%$%HF !;*@Ui "'&'&476762"'&'&5476762 "'&'&4767632"'&'&'476762"'&'.76762"'&'&54767632!'!%3"'&'&5476762"'&'&5476762 "'&'&4767632"'&'.76762"'&'.76762"'&'&4767632$H%$HI&$UIHIH}I&$ Yٍ$I%$II%$0$H%$HI%$RHI%$HG$$%$HGH%$H %=%$I&$IHIIHHIIHm!5!!$ fm !!7!!!! %=m?'m"2#"'&'&47676!!7!!!!E$$% %=&$Ih?'m+/37476762#"'&'&476762"'&'&!!7!!!!H%$HG %=|$I;$%$?'m+AEIM476762#"'&'&476762"'&'&476762"'&'&!!7!!!!H%$ JHHG %=|$$%2$H.$%$?'m+AW[_c2"'&'&5476762#"'&'&47672#"'&'&547672"'&'&47676!!7!!!!N$JJ%$J%$S$J %=H$%$%H"H$%$%Hq?'m+AWnrvz2"'&'&5476762#"'&'&47672#"'&'&547672"'&'&476762#"'&'&47676!!7!!!!N$JJ%$J%$S$J$$% %=H$%$%H"H$%$%H &$Ih?' m*@Ui%476762"'&'&%4767632"'&'&476762"'&'4767672"'&'$4767>"'&'4767632'&'!!7!!!!HJ%$HG$$%$HGH%$H %=$H%$H3J&$JHJHJ&$?'m!2#"'&'&47676!!7!!!!E$$% %=kJH?'m,0482#"'&'&476762#"'&'&47676!!7!!!!E$$%%$$% %=iJH&$Ih?'m,BFJN2#"'&'&47676476762#"'&'&476762"'&'&!!7!!!!E$$%H%$HG %=kJH$$%;$%$?'m,AW[_c2#"'&'&47676476762#"'&'&476762"'&'&476762"'&'&!!7!!!!E$$%H%$ JHHG %=kJH$$%2$H.$%$?'m+AWmquy2#"'&'&476762"'&'&5476762#"'&'&47672#"'&'&547672"'&'&47676!!7!!!!E$$%.$JJ%$J%$S$J %=kJHH$%$%H"H$%$%Hq?' m+AWm2#"'&'&476762"'&'&5476762#"'&'&47672#"'&'&547672"'&'&476762#"'&'&47676!!7!!!!E$$%.$JJ%$J%$S$J$$% %=kJHH$%$%H"H$%$%H &$Ih?' m*@Vk2#"'&'&47676476762"'&'&%4767632"'&'&476762"'&'4767672"'&'$4767>"'&'4767632'&'!!7!!!!E$$%HJ%$HG$$%$HGH%$H %=kJH&$H%$H3J&$JHJHJ&$?'m+/37476762#"'&'4767632"'&'&!!7!!!!H$%$%H %=J%$S$J?'m"8N2#"'&'&47676!!7!!!!476762#"'&'4767632"'&'&E$$% %=H$%$%H&$Ih?'IJ%$S$Jm,048Nd476762#"'&'&476762"'&'&!!7!!!!476762#"'&'4767632"'&'&H%$HG %=H$%$%H|$$%;$%$?'IJ%$S$Jm+AEIMcy476762#"'&'&476762"'&'&476762"'&'&!!7!!!!476762#"'&'4767632"'&'&H%$ JHHG %=H$%$%H|$$%2$H.$%$?'IJ%$S$J m+AW[_cy2"'&'&5476762#"'&'&47672#"'&'&547672"'&'&47676!!7!!!!476762#"'&'4767632"'&'&N$JJ%$J%$S$J %=H$%$%HH$%$%H"H$%$%Hq?'IJ%$S$J m+AWnrvz2"'&'&5476762#"'&'&47672#"'&'&547672"'&'&476762#"'&'&47676!!7!!!!476762#"'&'4767632"'&'&N$JJ%$J%$S$J$$% %=H$%$%HH$%$%H"H$%$%H &$Ih?'IJ%$S$J m*@Ui%476762"'&'&%4767632"'&'&476762"'&'4767672"'&'$4767>"'&'4767632'&'!!7!!!!476762#"'&'4767632"'&'&HJ%$HG$$%$HGH%$H %=H$%$%H$H%$H3J&$JHJHJ&$?'IJ%$S$Jm+AEIM476762#"'&'476762"'&'&4767632"'&'&!!7!!!!H$%JI $%H %=J%$J$$%.$J?'m+AX\`d476762#"'&'476762"'&'&4767632"'&'&2#"'&'&47676!!7!!!!H$%JI $%H$$% %=J%$J$$%.$J+&$Ih?'m+AXnrvz476762#"'&'476762"'&'&4767632"'&'&476762#"'&'&476762"'&'&!!7!!!!H$%JI $%HH%$HG %=J%$J$$%.$J$$%;$%$?' m+AXm476762#"'&'476762"'&'&4767632"'&'&476762#"'&'&476762"'&'&476762"'&'&!!7!!!!H$%JI $%HH%$ JHHG %=J%$J$$%.$J$$%2$H.$%$?' m+AWm476762#"'&'476762"'&'&4767632"'&'&2"'&'&5476762#"'&'&47672#"'&'&547672"'&'&47676!!7!!!!H$%JI $%Hz$JJ%$J%$S$J %=J%$J$$%.$J4H$%$%H"H$%$%Hq?' m+AWm476762#"'&'476762"'&'&4767632"'&'&2"'&'&5476762#"'&'&47672#"'&'&547672"'&'&476762#"'&'&47676!!7!!!!H$%JI $%Hz$JJ%$J%$S$J$$% %=J%$J$$%.$J4H$%$%H"H$%$%H &$Ih?' m+AVl476762#"'&'476762"'&'&4767632"'&'&476762"'&'&%4767632"'&'&476762"'&'4767672"'&'$4767>"'&'4767632'&'!!7!!!!H$%JI $%HHJ%$HG$$%$HGH%$H %=J%$J$$%.$J$H%$H3J&$JHJHJ&$?'m)>SW[_2"'&'&476762#"'&'&47672#"'&'&47672"'&'&47676!!7!!!!N$II%$I%$S$I %=tHIIH"HIIH ?'m!6K`u2"'&'&47676!!7!!!!2"'&'&476762#"'&'&47672#"'&'&47672"'&'&47676E$I %=m$II%$I%$S$I&$Ih?'HIIH"HIIH m,048Ndz476762#"'&'&476762"'&'&!!7!!!!2"'&'&5476762#"'&'&47672#"'&'&547672"'&'&47676H%$HG %=m$JJ%$J%$S$J|$$%;$%$?'H$%$%H"H$%$%H m+AEIMcy476762#"'&'&476762"'&'&476762"'&'&!!7!!!!2"'&'&5476762#"'&'&47672#"'&'&547672"'&'&47676H%$ JHHG %=m$JJ%$J%$S$J|$$%2$H.$%$?'H$%$%H"H$%$%H m+AW[_cy2"'&'&5476762#"'&'&47672#"'&'&547672"'&'&47676!!7!!!!2"'&'&5476762#"'&'&47672#"'&'&547672"'&'&47676N$JJ%$J%$S$J %=m$JJ%$J%$S$JH$%$%H"H$%$%Hq?'H$%$%H"H$%$%H m)>Simqu2"'&'&476762#"'&'&47672#"'&'&47672"'&'&476762"'&'&47676!!7!!!!2"'&'&476762#"'&'&47672#"'&'&47672"'&'&47676N$II%$I%$S$I$I %=m$II%$I%$S$IHIIH"HIIH &$Ih?'HIIH"HIIH m*@Ui%476762"'&'&%4767632"'&'&476762"'&'4767672"'&'$4767>"'&'4767632'&'!!7!!!!2"'&'&5476762#"'&'&47672#"'&'&547672"'&'&47676HJ%$HG$$%$HGH%$H %=m$JJ%$J%$S$J$H%$H3J&$JHJHJ&$?'H$%$%H"H$%$%Hm !7Mcy!!7!!!!2"'&'&5476762#"'&'&47672#"'&'&547672"'&'&476762#"'&'&47676 %=m$JJ%$J%$S$J$$%m?'H$%$%H"H$%$%H JH m"8Ndz2#"'&'&47676!!7!!!!2"'&'&5476762#"'&'&47672#"'&'&547672"'&'&476762#"'&'&47676E$$% %=m$JJ%$J%$S$J$$%&$Ih?'H$%$%H"H$%$%H JH m+/37Lav476762#"'&'&476762"'&'&!!7!!!!2"'&'&476762#"'&'&47672#"'&'&47672"'&'&476762"'&'&47676H%$HG %=m$II%$I%$S$I$I|$I;$%$?'HIIH"HIIH JH m+AEIMcy476762#"'&'&476762"'&'&476762"'&'&!!7!!!!2"'&'&5476762#"'&'&47672#"'&'&547672"'&'&476762#"'&'&47676H%$ JHHG %=m$JJ%$J%$S$J$$%|$$%2$H.$%$?'H$%$%H"H$%$%H JH m+AW[_cy2"'&'&5476762#"'&'&47672#"'&'&547672"'&'&47676!!7!!!!2"'&'&5476762#"'&'&47672#"'&'&547672"'&'&476762#"'&'&47676N$JJ%$J%$S$J %=m$JJ%$J%$S$J$$%H$%$%H"H$%$%Hq?'H$%$%H"H$%$%H JH m+AWnrvz2"'&'&5476762#"'&'&47672#"'&'&547672"'&'&476762#"'&'&47676!!7!!!!2"'&'&5476762#"'&'&47672#"'&'&547672"'&'&476762#"'&'&47676N$JJ%$J%$S$J$$% %=m$JJ%$J%$S$J$$%H$%$%H"H$%$%H &$Ih?'H$%$%H"H$%$%H JHm*@Ui%476762"'&'&%4767632"'&'&476762"'&'4767672"'&'$4767>"'&'4767632'&'!!7!!!!2"'&'&5476762#"'&'&47672#"'&'&547672"'&'&476762#"'&'&47676HJ%$HG$$%$HGH%$H %=m$JJ%$J%$S$J$$%$H%$H3J&$JHJHJ&$?'H$%$%H"H$%$%H JH m ":Pf|!!7!!!!4767632"'&'&%4767632#"'&'&476762"'&'4767672"'&'&%4767>#"'&'&4767632'&' %=%$J&$$%H$%$%HH$%$%Hm?'|$$%%$$%3J%$$H%$HkJ%$ m"9Qg}2#"'&'&47676!!7!!!!4767632"'&'&%4767632#"'&'&476762"'&'4767672"'&'&%4767>#"'&'&4767632'&'E$$% %=%$J&$$%H$%$%HH$%$%H&$Ih?'|$$%%$$%3J%$$H%$HkJ%$ m,048Og}476762#"'&'&476762"'&'&!!7!!!!4767632"'&'&%4767632#"'&'&476762"'&'4767672"'&'&%4767>#"'&'&4767632'&'H%$HG %=%$J&$$%H$%$%HH$%$%H|$$%;$%$?'|$$%%$$%3J%$$H%$HkJ%$ m+AEIMd|476762#"'&'&476762"'&'&476762"'&'&!!7!!!!4767632"'&'&%4767632#"'&'&476762"'&'4767672"'&'&%4767>#"'&'&4767632'&'H%$ JHHG %=%$J&$$%H$%$%HH$%$%H|$$%2$H.$%$?'|$$%%$$%3J%$$H%$HkJ%$ m+AW[_cz2"'&'&5476762#"'&'&47672#"'&'&547672"'&'&47676!!7!!!!4767632"'&'&%4767632#"'&'&476762"'&'4767672"'&'&%4767>#"'&'&4767632'&'N$JJ%$J%$S$J %=%$J&$$%H$%$%HH$%$%HH$%$%H"H$%$%Hq?'|$$%%$$%3J%$$H%$HkJ%$m)>Simqu2"'&'&476762#"'&'&47672#"'&'&47672"'&'&476762"'&'&47676!!7!!!!4767632"'&'&%4767632"'&'&476762'&'4767>"'&'&%4767>"'&'&476762'&'N$II%$I%$S$I$I %=%$I&$IHIIHHIIHHIIH"HIIH &$Ih?'|$I%$I4I%$$H%$HlI%$m*@Ui %476762"'&'&%4767632"'&'&476762"'&'4767672"'&'$4767>"'&'4767632'&'!!7!!!!4767632"'&'&%4767632"'&'&476762'&'4767>"'&'&%4767>"'&'&476762'&'HI%$HG$$%$HGH%$H %=%$I&$IHIIHHIIH$H%$H4I&$IHIHI&$?'|$I%$I4I%$$H%$HlI%$gm "3!254#%!2#!"54!xxxxAA,Gxxxyxxygm$03;#"'##65##"5476"3!254#%!2#!"54!3#'!#A; lB;;Bl ;"xxxxAAK Қ DDy~&%Nkk̛N%&VxxxyxxyUgm$0I#"'##65##"5476"3!254#%!2#!"54!!56754&#"5>32A; lB;;Bl ;"xxxxAA"?XhU4zHM98y~&%Nkk̛N%&Vxxxyxxy?rn81^BQ##{l0gm$0Y#"'##65##"5476"3!254#%!2#!"54#"&'532654&+532654&#"5>32A; lB;;Bl ;"xxxxAA\e9}F4wCmxolV^^ad_(fQI7Zy~&%Nkk̛N%&VxxxyxxymR|yOFJLl?<:=svcE`gm$03>#"'##65##"5476"3!254#%!2#!"54 !33##5!5A; lB;;Bl ;"xxxxAA5by~&%Nkk̛N%&Vxxxyxxy]mygm$0Q#"'##65##"5476"3!254#%!2#!"54!!67632#"&'53264&#"A; lB;;Bl ;"xxxxAAy^^a`<~B9>>Eoo4h6y~&%Nkk̛N%&Vxxxyxxy_ MLKJq ffgm$0@`#"'##65##"5476"3!254#%!2#!"54"327654'&&'&#"67632#"&547632A; lB;;Bl ;"xxxxAAGX3333XW33331221DD &9:DTTXWll122y~&%Nkk̛N%&Vxxxyxxy45[Z4554Z[54bg KL1LMONuv gm$07#"'##65##"5476"3!254#%!2#!"54!#!A; lB;;Bl ;"xxxxAAiH3y~&%Nkk̛N%&Vxxxyxxy0gm$0=[j#"'##65##"5476"3!254#%!2#!"54"32764'%&'&546 #"'&54767327654'&"A; lB;;Bl ;"xxxxAA55j]\655T./RQ./SZ85UVUV56-/.UQ100/0/y~&%Nkk̛N%&Vxxxyxxy[,+KLV,++]12Hdt::dJ01:7PyAAAAyN98?&%%$A?&%%$gm$0P_#"'##65##"5476"3!254#%!2#!"54532767#"&547632#"'&2654'&#"A; lB;;Bl ;"xxxxAA.1220DC #<9EWXWXkl122Xf33XU5443y~&%Nkk̛N%&Vxxxyxxyg KK/MNoouv rh\Z4554Z\44gm$0>JQ#"'##65##"5476"3!254#%!2#!"54"27654/2#"&546573A; lB;;Bl ;"xxxxAA2332233yty~&%Nkk̛N%&VxxxyxxyVVVVVVV)t'gm$0=#"'##65##"5476"3!254#%!2#!"543+53265A; lB;;Bl ;"xxxxAAA@1(TFy~&%Nkk̛N%&VxxxyxxyܕFE`Tlgm$0J#"'##65##"5476"3!254#%!2#!"54#"&54632.#"3267A; lB;;Bl ;"xxxxAA<1e9ɴ9f0/j6||{}7j.y~&%Nkk̛N%&Vxxxyxxyt"$$"gm4@L"#"&54632&#"32#"'##65##"5476"3!254#%!2#!"54VX~_ Ua`UU`aA; lB;;Bl ;"xxxxAA,ۥ(j8pny~&%Nkk̛N%&Vxxxyxxygm$0;#"'##65##"5476"3!254#%!2#!"5433 ##A; lB;;Bl ;"xxxxAAjixy~&%Nkk̛N%&VxxxyxxyazBmgm!-0867632 &547632"3!254#%!2#!"54!3#'!#7>T>}}?V<7xxxxAAK Қ DDv>G-;n;-GAxxxyxxyUgm!-F67632 &547632"3!254#%!2#!"54!!56754&#"5>327>T>}}?V<7xxxxAA"?XhU4zHM98v>G-;n;-GAxxxyxxy?rn81^BQ##{l0gm!-V67632 &547632"3!254#%!2#!"54#"&'532654&+532654&#"5>327>T>}}?V<7xxxxAA\e9}F4wCmxolV^^ad_(fQI7Zv>G-;n;-GAxxxyxxymR|yOFJLl?<:=svcE`gm!-0;67632 &547632"3!254#%!2#!"54 !33##5!57>T>}}?V<7xxxxAA5bv>G-;n;-GAxxxyxxy]mygm!-N67632 &547632"3!254#%!2#!"54!!67632#"&'53264&#"7>T>}}?V<7xxxxAAy^^a`<~B9>>Eoo4h6v>G-;n;-GAxxxyxxy_ MLKJq ffgm!-=]67632 &547632"3!254#%!2#!"54"327654'&&'&#"67632#"&5476327>T>}}?V<7xxxxAAGX3333XW33331221DD &9:DTTXWll122v>G-;n;-GAxxxyxxy45[Z4554Z[54bg KL1LMONuv gm!-467632 &547632"3!254#%!2#!"54!#!7>T>}}?V<7xxxxAAiH3v>G-;n;-GAxxxyxxy0gm!-:Xg67632 &547632"3!254#%!2#!"54"32764'%&'&546 #"'&54767327654'&"7>T>}}?V<7xxxxAA55j]\655T./RQ./SZ85UVUV56-/.UQ100/0/v>G-;n;-GAxxxyxxy[,+KLV,++]12Hdt::dJ01:7PyAAAAyN98?&%%$A?&%%$gm!-M\67632 &547632"3!254#%!2#!"54532767#"&547632#"'&2654'&#"7>T>}}?V<7xxxxAA.1220DC #<9EWXWXkl122Xf33XU5443v>G-;n;-GAxxxyxxyg KK/MNoouv rh\Z4554Z\44gm!-;GN67632 &547632"3!254#%!2#!"54"27654/2#"&5465737>T>}}?V<7xxxxAA2332233ytv>G-;n;-GAxxxyxxyVVVVVVV)t'gm!-:67632 &547632"3!254#%!2#!"543+532657>T>}}?V<7xxxxAAA@1(TFv>G-;n;-GAxxxyxxyܕFE`Tlgm!-G67632 &547632"3!254#%!2#!"54#"&54632.#"32677>T>}}?V<7xxxxAA<1e9ɴ9f0/j6||{}7j.v>G-;n;-GAxxxyxxyt"$$"xm1=I"#"&54632&#"3267632 &547632"3!254#%!2#!"54VX~_ Ua`UU`a7>T>}}?V<7xxxxAA,ۥ(j8p0v>G-;n;-GAxxxyxxygm!-867632 &547632"3!254#%!2#!"5433 ##7>T>}}?V<7xxxxAAjixv>G-;n;-GAxxxyxxyazBmgm!)0 00"3!254#%!2#!"54!3#'!#hfxxxxAAK Қ DD xxxyxxyUgm70 00"3!254#%!2#!"54!!56754&#"5>32hfxxxxAA"?XhU4zHM98 xxxyxxy?rn81^BQ##{l0gmG0 00"3!254#%!2#!"54#"&'532654&+532654&#"5>32hfxxxxAA\e9}F4wCmxolV^^ad_(fQI7Z xxxyxxymR|yOFJLl?<:=svcE`gm!,0 00"3!254#%!2#!"54 !33##5!5hfxxxxAA5b xxxyxxy]mygm?0 00"3!254#%!2#!"54!!67632#"&'53264&#"hfxxxxAAy^^a`<~B9>>Eoo4h6 xxxyxxy_ MLKJq ffgm.N0 00"3!254#%!2#!"54"327654'&&'&#"67632#"&547632hfxxxxAAGX3333XW33331221DD &9:DTTXWll122 xxxyxxy45[Z4554Z[54bg KL1LMONuv gm%0 00"3!254#%!2#!"54!#!hfxxxxAAiH3 xxxyxxy0gm+IX0 00"3!254#%!2#!"54"32764'%&'&546 #"'&54767327654'&"hfxxxxAA55j]\655T./RQ./SZ85UVUV56-/.UQ100/0/ xxxyxxy[,+KLV,++]12Hdt::dJ01:7PyAAAAyN98?&%%$A?&%%$gm>M0 00"3!254#%!2#!"54532767#"&547632#"'&2654'&#"hfxxxxAA.1220DC #<9EWXWXkl122Xf33XU5443 xxxyxxyg KK/MNoouv rh\Z4554Z\44gm,8?0 00"3!254#%!2#!"54"27654/2#"&546573hfxxxxAA2332233yt xxxyxxyVVVVVVV)t'gm+0 00"3!254#%!2#!"543+53265hfxxxxAAA@1(TF xxxyxxyܕFE`Tlgm80 00"3!254#%!2#!"54#"&54632.#"3267hfxxxxAA<1e9ɴ9f0/j6||{}7j. xxxyxxyt"$$"gm".:0 00"#"&54632&#"32"3!254#%!2#!"54hf5VX~_ Ua`UU`auxxxxAAAۥ(j8poxxxyxxygm)0 00"3!254#%!2#!"5433 ##hfxxxxAAjix xxxyxxyazBmgm !! !"3!254#%!2#!"540xxxxAA1GG}xxxyxxygm#/;>F65'&'&547632&54 632'"3!254#%!2#!"54!3#'!#U9H5?K1||1K?5I9xxxxAAK Қ DDL C4$jj$4F LxxxyxxyUgm#/;T65'&'&547632&54 632'"3!254#%!2#!"54!!56754&#"5>32U9H5?K1||1K?5I9xxxxAA"?XhU4zHM98L C4$jj$4F Lxxxyxxy?rn81^BQ##{l0gm#/;d65'&'&547632&54 632'"3!254#%!2#!"54#"&'532654&+532654&#"5>32U9H5?K1||1K?5I9xxxxAA\e9}F4wCmxolV^^ad_(fQI7ZL C4$jj$4F LxxxyxxymR|yOFJLl?<:=svcE`gm#/;>I65'&'&547632&54 632'"3!254#%!2#!"54 !33##5!5U9H5?K1||1K?5I9xxxxAA5bL C4$jj$4F Lxxxyxxy]mygm#/;\65'&'&547632&54 632'"3!254#%!2#!"54!!67632#"&'53264&#"U9H5?K1||1K?5I9xxxxAAy^^a`<~B9>>Eoo4h6L C4$jj$4F Lxxxyxxy_ MLKJq ffgm#/;Kk65'&'&547632&54 632'"3!254#%!2#!"54"327654'&&'&#"67632#"&547632U9H5?K1||1K?5I9xxxxAAGX3333XW33331221DD &9:DTTXWll122L C4$jj$4F Lxxxyxxy45[Z4554Z[54bg KL1LMONuv gm#/;B65'&'&547632&54 632'"3!254#%!2#!"54!#!U9H5?K1||1K?5I9xxxxAAiH3L C4$jj$4F Lxxxyxxy0gm#/;Hfu65'&'&547632&54 632'"3!254#%!2#!"54"32764'%&'&546 #"'&54767327654'&"U9H5?K1||1K?5I9xxxxAA55j]\655T./RQ./SZ85UVUV56-/.UQ100/0/L C4$jj$4F Lxxxyxxy[,+KLV,++]12Hdt::dJ01:7PyAAAAyN98?&%%$A?&%%$gm#/;[j65'&'&547632&54 632'"3!254#%!2#!"54532767#"&547632#"'&2654'&#"U9H5?K1||1K?5I9xxxxAA.1220DC #<9EWXWXkl122Xf33XU5443L C4$jj$4F Lxxxyxxyg KK/MNoouv rh\Z4554Z\44gm#/;IU\65'&'&547632&54 632'"3!254#%!2#!"54"27654/2#"&546573U9H5?K1||1K?5I9xxxxAA2332233ytL C4$jj$4F LxxxyxxyVVVVVVV)t'gm#/;H65'&'&547632&54 632'"3!254#%!2#!"543+53265U9H5?K1||1K?5I9xxxxAAA@1(TFL C4$jj$4F LxxxyxxyܕFE`Tlgm#/;U65'&'&547632&54 632'"3!254#%!2#!"54#"&54632.#"3267U9H5?K1||1K?5I9xxxxAA<1e9ɴ9f0/j6||{}7j.L C4$jj$4F Lxxxyxxyt"$$"gm#/;MW65'&'&547632&54 632'"3!254#%!2#!"54"#"&54632&#"32U9H5?K1||1K?5I9xxxxAA3VX~_ Ua`UU`aL C4$jj$4F Lxxxyxxyۥ(j8pgm#/;F65'&'&547632&54 632'"3!254#%!2#!"5433 ##U9H5?K1||1K?5I9xxxxAAjixL C4$jj$4F LxxxyxxyazBmgm +!%%!%%"3!254#%!2#!"54decb`bMxxxxAAnξ;3o(T"(Uxxxyxxyjn ! ! tu u jn  !! ! ,=C`tu <=u jn ! !  ! ut~<A tu<=jn ! !  ! ut~<A tu<=jn ! ! ! ! tu <=CAu tC<=@jn ! ! % tu `Au {@Cjn ! ! 0 tu Au {@Cjn % ! ! +aC ut@C tujV#+3462"7"32654$"&462"32654462"6"&4622>7>54&'&'>54&#"&547&"'654.#"'72>32%%"&''%&/'%.547&54632B\BB\t- .B\BB\, -o    lN.  ;qsV6C70AIbbOSC**CSObbIA07C6Vsq;  .8L+ʏ]KY YK]+8ggg=>uggg=>"6''6']6''6'$9]W>:LktLJ73(#XQik\B?&STTS&?B\kiQX#(37JLtkL>W]9rlȡ~3D#@mm@#D3~lȬr Kj - "(,"&4632'2654#"3#"&46327'7#5%32767654'&'7>732>7>54'.#"&$ &/.#"3276%2654#"'747'&'#".'.54>7>32676 767>32+"&'&'&'&'& '326y2>=32>=-5nnI3=>23=>S39?*nB?94iEB9?B  R' 8%/6 1.4&++ #?Y==Y?# ++&4.1 6/%8 'R  -*?9 9 !;+57? B:),#3A32%A(77(A%23A3#,):B ?75+;! 9 "`  B6Ĉ6B  _# 4aa7k~nnnnAnnnn-ںMғv$DK;7" D;KD$v h5WM' 1 *L7.4(#"NemmeN"#(4.7L* 1 'MW5hNA*,PI  ,9 :kR4_5"2S''RNNR''S2"5_4Rk: 9,  IP,*0(sBD0H.&&.H0DBs($'&=j(2AN7327327#"'#""'72#"'&547632">7&>32#"'&327654'&#"654.'&'&#"&'%% 767%767%7&54>76?62>?''! '&'7&''\E[:TT:[E\lJDEI>zz>Z+Q (F65/AFeN$0+EdFB/56F( Qy 0( ,@ *tt* B g굤g  &<]ii];& l m nmuvmmm b@,,@bdx==x.L #$-G0,a&0$4%Ca,0G-$#  ;t.f>v::rAe.t+B,E@y>zwwz>y9L,B=|9jwAu: a a :uAwj9|BQW.>. .>.QWB j %1;Gh462"7"32654"547632"&462432#"'&"3265473267!"& 7654'>54'&#".#" 632+ '.'&'#"&'&'&54632676&#";67&%32767654&'&#"RtRRt78,%,% RtRRt%,%,78j`;j|TVZGqpGZVT|j7aij "Y:8mm8:Y" jia (+G&<5t5<&G+( tRRtRh11R $ $ tRRtR$ $k11TXLTr˚,0^1ioE55Eoi1^0,|,6[?Ki{pn7LL7np{iK?[6,|R:3/{W``W{/3:R jn ".49>BF4632#"&%462#"&! ! ! ! ! 67##%67#5#Q;:RR:;QBRtSS:;Qm<=CAtu XLL Hd e;QQ;:SS:;QQ;:SSC<=@u jj *%Z*Rdf jn #/5:?CG! ! ! ! 462#4&"!462#4&"! 67##%67#5#1<=CAtu Č=T=)Č=T=XLL Hd eC<=@u ŋSwwSŋSwwSj *%Z*Rdf _jn #/Y~5#67##67#%! 462#4&"!462#4&"! "'&/! &"&5476?&7! 4'#"'&/&'&! 6?"'462#4&"!462#4&"! ! ! ! ! %!7276Č=T=ɌČ=T=tu <=CABW!\ʎ\ŋSwwSŋSwwSu tC<=@j{u\\jn #/;AJ"&547462#4&"!462#4&"! ! ! ! ! %!7276AL6Č=T=ɌČ=T=tu <=CABW!\ʎ\,8"+6,#5 ŋSwwSŋSwwSu tC<=@j{u\\jn %+3%%''7'7! ! ! ! ! %!$76|'MM٠MMtu <=CABW!\\'nnUUnnu tC<=@j{u\\jc*5IW_7767 '&! /! '462#"&%4632#"&4$! ! 7&%654$! 6! &#"32s('s%22<=RtSS:;QQ;:RR:;Q ۼCAJKCݰG,&',H923QC<=99*;QQ;:SS:;QQvRS\\ t[\6JQrrQJ6nnj0-9J%462#"&%4632#"&'7 767 '&! ! 6 %! 7/M?RtSS:;QQ;:RR:;QMMs('s%22<=CA*go;QQ;:SS:;QQvRSno>G,&',H923QC<=@** t/0jn'297 767 '&! ! ! ! 4632#"&-%s('s%22<=CAtu Q;:RR:;Q'MMG,&',H923QC<=@u ;QQvRSdnnjn'3?7 767 '&462#4&"!462#4&"! ! ! ! s('s%22,Č=T=ɌČ=T=tu <=CAG,&',H923ŋSwwSŋSwwSu tC<=@jn 7CQ462#4&"!462#4&"!27&'# 3 536! ! ! 327674'&fČ=T=)Č=T= &?)   #I=#   )?& >2<tu <=CAs('s%22%?A>ϾDLD 1GG1 DLD>A?%*u tC<=@G,&',H923jn#3<! 4'#"&5"&=#! ! %7767 '&!&'&! 1<=Tn즦nUtu ss('s%22`C<àOddddOu [G,&',H923;jn)5!!5!2767!! ! ! ! lʎ's%2~tu <=CA',H929u tC<=@jn%15!4632#"&%462#"&! ! ! ! LvQ;:RR:;QBRtSS:;Qtu <=CAq;QQvRS:;QQ;:SSu tC<=@jn #5!!5!5!! ! ! ! tu <=CA凇yu tC<=@jn )7! ! ! ! 5!5!2#"&545!5!2#"&5451<=CAtu x:RR:;QVx:SS:;QC<=@u -Q;:SS:Q;:SS:jn *6B"&475!%7 '%4632#"&%462#"&! ! ! ! PA6L6= MXMXMQ;:RR:;QBRtSS:;Qtu <=CA5O66O5Eonno;QQvRS:;QQ;:SSu tC<=@jn'35!"&53265!"&53265! ! ! ! L6Č=T=7Č=T=?tu <=CAqŋSwwSŋSwwSbu tC<=@jn%1%'4632#"&%462#"&! ! ! ! 9g9Q;:RR:;QBRtSS:;Qtu <=CA{{;QQvRS:;QQ;:SSu tC<=@jnB'! ! ! ! 7"'&'&#"'67623276762&__Z<=CAtu _4) FF "58 yFF "54( FFy\__C<=@u _Wi"bc(!__9("bb("_i"bb"(9_jn #/;4632#"&%462#"&7'7'7'! ! ! ! Q;:RR:;QBRtSS:;QPA<NvX..XvN>#u tC<=@jn")6BN2#'&5&76334764632#"&-%7'7'7'! ! ! ! j<2> &@(   "VQ;:RR:;Q'MMنPA<ϾDLD 1GN;QQvRSdnn>NvX..XvN>#u tC<=@jn $0<462#4&"!462#4&"7'7'7'! ! ! ! Č=T=ɌČ=T=PA<NvX..XvN>#u tC<=@jn $0<7'7'7'"&53265!"&53265! ! ! ! PA<NvX..XvN>ŋSwwSŋSwwSbu tC<=@jn ".8>4632#"&%462#"&! ! ! ! %5!#"&5!#26Q;:RR:;QBRtSS:;Qm<=CAtu ČU=T=;QQ;:SS:;QQ;:SSC<=@u cŋSwwjn )394632#"&-%! ! ! ! %5!#"&5!#26Q;:RR:;Q'MM<=CAtu ČU=T=;QQvRSdnnC<=@u cŋSwwjn %/5! ! ! ! '7'7%%5!#"&5!#261<=CAtu 2MM'MMČU=T=C<=@u UnnnnŋSwwjn)5F%7 '%4632#"&%462#"&! ! ! ! 676 &'&#&MXMXMQ;:RR:;QBRtSS:;Qtu <=CA%23$s(ʎ'onno;QQvRS:;QQ;:SSu tC<=@%8338H,'',jn"-9EV%'6762&'&"%7 '%4632#"&%462#"&! ! ! ! 676 &'&#&yFFyT;MXMXMQ;:RR:;QBRtSS:;Qtu <=CA%23$s(ʎ'9("bb"(9<<donno;QQvRS:;QQ;:SSu tC<=@%8338H,'',jn)5F'4632#"&%462#"&%! ! ! ! 676 &'&#&MM+Q;:RR:;QBRtSS:;Q/M%tu <=CA%23$s(ʎ'gno;QQvRS:;QQ;:SSou tC<=@%8338H,'',jn(,7BFV676 &'&#&! ! ! ! %462#"&%4632#"&''6762&'&"%23$s(ʎ'<=CAtu (/M?RtSS:;QQ;:RR:;QMMyFFyTL8338H,'',C<=@u o;QQ;:SS:;QQvRSno 9("bb"(9<<jn #4O! ! ! ! "&53265676 &'&#&"&54?&'&532651<=CAtu HČ=T=%23$s(ʎ'F:M L6 M:F=T=C<=@u ŋSwwS8338H,'',bQ?7#+6,#5? RbSwwSjn*6676 &'&#&%%''7'7! ! ! ! %23$s(ʎ''MM٠MMtu <=CAL8338H,'',"nnUUnnu tC<=@jn!-9' 7 676 &'&#&"&47! ! ! ! ___/%23$s(ʎ'B6L6<=CAtu \___8338H,'',#5O66O5C<=@u jn ".4<4632#"&%462#"&! ! ! ! !4 !&'& Q;:RR:;QBRtSS:;Qtu <=CA''EkjE;QQ;:SS:;QQ;:SSu tC<=@Fa`LtuLjn)5;C%7 '%4632#"&%462#"&! ! ! ! !4 !&'& MXMXMQ;:RR:;QBRtSS:;Qtu <=CA''EkjEonno;QQvRS:;QQ;:SSu tC<=@Fa`LtuLjn NZflx32654&#"!&'& !4 ! 4'#&'#5"'#5&47&'##"&'##5! ! 4632#"&%6754&#"326'#"&546325&'&'67%&'%67%tJUioOLr7EkjE?'' <=5D%Dm8D++!"D"!++D8nD%D6tu q"!# ##  rLOoiUJt#!"$ g!"$!"+O# *"!$RluIOoo`LtuLF7C<;.)nY6G$@<<=j<<@$F7Y*.żu !!# OooOIulR #!!y (  &!--! jn '-5' 7 ' 7! ! ! ! !4 !&'& ______tu <=CA''EkjE___X___?u tC<=@Fa`LtuLjn)5AGO767632#"&53265!"&53265! ! ! ! !4 !&'& U% $  ';Č=T=7Č=T=?tu <=CA''EkjEt2  "$ŋSwwSŋSwwSbu tC<=@Fa`LtuLjn %+3%%''7'7! ! ! ! !4 !&'& |'MM٠MMtu <=CA''EkjE'nnUUnnu tC<=@Fa`LtuL_jn =b%!4 '7'7%%! "'&/! &"&5476?&7! 4'#"'&/&'&! 6?"'''MM'MM.tu ];6L *+ L6<\<=%&-)//)-LFtUnnnnu%&69 96&%C<9-ǚ -9jn*6462"4632#"&%462#"&! ! ! ! ,ԖQ;:RR:;QBRtSS:;Qtu <=CAZԖԖ;;QQ;:SS:;QQ;:SSu tC<=@jn%1=%7 '%4632#"&%462#"&462"! ! ! ! MXMXMQ;:RR:;QBRtSS:;QKjKKjtu <=CAonno;QQvRS:;QQ;:SSjKKjKu tC<=@jn#.:F"&47462"%7 '%4632#"&%462#"&! ! ! ! PA6L6ԖUMXMXMQ;:RR:;QBRtSS:;Qtu <=CA5O66O5.ԖԖRonno;QQvRS:;QQ;:SSu tC<=@#<5nk&462 &462%'%%7462"5.'46767 #5476764&"#5 '#54&/&'&'."% 7547676767>76767&'& QRtSSIQQuRRMXM~MXȖԖHVh=;;=hVH&z':%i)8^'ny'^8)i%:'z&Lw l08< 3233<80(SuQQuSSuQQvRnooԖԖx>[1'Sk ߰ kS1[>$n9(#mq,%@76?62>?''! '&&''7&''%4."#462!4."#462&'32?67#5#"'\>xcev>rt6;#y]M4f굡g.G *tt*  &<]ii];& ikhdtt^b e11B1Č1B1Č:$(2+$) `3H:G??4.x==x%B DG}KSB$bCJAi?l:1wv85j?g>LCR4.f>v::rAeME9jwAu: a a :uAwj9DMDVW$@"<<@6 @"O`DQ+ZEEY,Č+ZEEY,Č  c'F aa C `j?H]654.'&'& &'6?#"'% 76767%767#"&/27#"'7327 $'&54732"&546?4''7&54>76?62>?'#"&/ '&&'4."#462!4."#462&'32?67#5#"' *tt* P,3,04f鶢f.0,4.RȂ\>xbfv>rt6<"x|%7>4Zfd &<^ij]<& hjZ4<6$,4,tt*$0B2Č0B2Č:$(2,$( `4H:F>@4|(,.f>v::rAe.*',,3<%WLi?l:1wv85j?gD`(<3,.x==x%B DG}KSBA6%,4JDME9jwAu: a a :uAwj9DMD44,%6<3*hb]p-o+ZEEY,Č+ZEEY,Č  c'F aa C :j&*_27#"'7327 $'&54732#"'267#"%% 76767%767%7654.'&'&#"&'&54>76?62>?''! '&&''7&''%4632#"'&7">7&#"'&'67632327654'&#"\>xcev>rt6;#yprw??52H:u}M4f굡g.G *tt*  &<]ii];& ikhdtt^b ecC>]0L!(C8$0+E8C%$M/2-;Cc .* ,@.x==x%B DG}KSBh ELME N$bCJAi?l:1wv85j?g>LCR4.f>v::rAeME9jwAu: a a :uAwj9DMDVW$@"<<@6 @"O`DF_W;E !I+ /!-! CB*&_z 5=jJ7327327#"'#""'72%654.'&'&#"&'%% 767%767%7&54>76?62>?''! '&'7&''>32#'&'4632%2347632#'&546\E[:TT:[E\lJDEI>zz>Z *tt* B g굤g  &<]ii];& l m nmuvmmm  :-.>>1@/=# -:  #=/@1>>b@,,@bdx==x.8t.f>v::rAe.t+B,E@y>zwwz>y9L,B=|9jwAu: a a :uAwj9|BQW.>. .>.QWB0B=1JJ=B*HGrB0GH*B=ϾJJ1= =j(7Du-'"'72#"'&547632">7&>32#"'&327654'&#"654.'&'&#"&'%% 767%767%7&54>76?62>?''! '&'7&''2767!/MMMs>zz>Z+Q (F65/AFeN$0+EdFB/56F( Qy 0( ,@ *tt* B g굤g  &<]ii];& l m nmuvmmm ʎ(s"5gonno=x==x.L #$-G0,a&0$4%Ca,0G-$#  ;t.f>v::rAe.t+B,E@y>zwwz>y9L,B=|9jwAu: a a :uAwj9|BQW.>. .>.QWB(+H65=j'4i#"'&547632">7&>32#"'&327654'&#"654.'&'&#"&'%% 76?%767%72>?''! '&''7&''7&'54>76?7'7'7'27#"'7l+Q (F65/AFeN$0+EdFB/56F( Qy 0( ,@ *tt*  B f굡g i];&  l m nmttmmm l &<]PA<wdev>L #$-G0,a&0$4%Ca,0G-$#  ;s.f>v::rAe.$A+B,E@y>zwvz>y9L,B a :uAwj9WBQW.>..>.QWB`*9jwAu: a:=NwY.-YwN=.x==x =j'4e#"'&547632">7&>32#"'&327654'&#"654.'&'&#"&'%% 767%767%7&54>76?62>?''! '&'7&''62&"%6 &#"27#"'7'%%l+Q (F65/AFeN$0+EdFB/56F( Qy 0( ,@ *tt* B g굤g  &<]ii];& l m nmuvmmm GFF`T`Ȑ[>wdev>MM{/ML #$-G0,a&0$4%Ca,0G-$#  ;t.f>v::rAe.t+B,E@y>zwwz>y9L,B=|9jwAu: a a :uAwj9|BQW.>. .>.QWBcc_<<`.x==x=noo=j ,4d"&545"'7276?.53265!"&532656 & &6?6?62>?'' '7&''!2$7%767%7654/&'& &'%%BM 6L6nv>[[3 M=T=7Č=T=`n &<]ii];&+ l m nmudfvmmm ;Yg A+tt* B ?5O66,5=x..c?SwwSŋSwwSڵ`|jau: a a :ua̠|BQW.>.* .>.QWBz>y9L,B+Qb::Tnk+B,E@y>=j4s{654.'&'&#"&'%% 76?%767%72>?''! '&''7&''7&'54>76?!&'& !476327'* *tt*  B f굡g i];&  l m nmttmmm l &<]EkjE?(___ڃs.f>v::rAe.$A+B,E@y>zwvz>y9L,B a :uAwj9WBQW.>..>.QWB`*9jwAu: aGaKtuK礣~____jn'29676 &'& ! ! ! ! %4632#"&%5%%22%s'l(<=CAtu Q;:RR:;Q'MM8329H,'&,@=<Ct b:SRvQQUnn @03#u)@ dd1<20KTKT[X@878YKTK T[KT[X@878YKTKT[X@878YKTX@878Y@````pppp]3#%3#^ys@B10KSXY"K TX@878YKTX@878Y@ %%6FVjg //]]3#7Ju@!  VV 99991<2990K TX@878YKTX@878Y ]'.#"#4632326=3#"&9 $(}gV$=09" (}gT";9! 2-ev 3)dw @B10KSXY"K TX@878YKTX@878Y@*$$5CUU//]]#ę1w@ 91<90K TX@878YKTX@878YKTX@878Y@ //- ]3#'#Ӌ1@ 91290K TK T[K T[K T[X@878YKTX@878YKTX@878Y@ "  ]373Ӌ 9 #.#"#>32v cSRav 6978w{z9 j@ VV120K TX@878YKTX@878YKTKT[X@878Y332673#"&v cSRav 6978w{zfGd10KTKT[X@878YKTX@878Y3#@1<203#3#䙋N#!#ęę53#73#'3# 3#3#'3#}}d 3#3#'3#}}d3#3#d 3#3#3#3#dd&;#"'&'#"'$&733$767654'3F??7KXQ~XR\,>%!$'$&73!2%7&'&547676323!!"'654'&'&#"xhn}@AQ+"R:4RQP ioh4"(=)1$+<'g\^sM6,|y$K2S%jAzG' <8BN?0654'&323276767'&54767632#!V)B,4((7(*HTO<?aNbNLZB`.NJ|m+M;3*)3P& ]027EW4,E$2Hf3Џ,' !5;#"'+5327&'&54767632"67654'&'&f$'و'$A??8 D?$ 9P2*I1C299(M.L,0W 5+5DE2.4! k .@%&'&'&547676323!!#'$'&5473!2766'&'&#"B.y9()Wp8c20-=^E>><l/"'"3 9Ld/  #+m=E2X:zFNV}`kL:DbZzWK# :<,; ?7 8X4~X5 %4'&"2>"'&4762<R8R8z?@?@@?@(8)*8@@@@@?? '.'>3&4'.cR>P~&5'.cR>P'0 3&40cL~&50cL >&}8\K&}X>K&}X >&1?\F&1 >F&1  >&/\F&/>F&/ >&'-?0>\L&'08- >>L&'08- 3_+ 5__bV'J@!B  6991/<2990KSXY"]33+532765#ոRQi&&}``01}` 2@  F <<221/<20@  @ P ` p ]33###53ø`<ĤV.` 54!333##"3276!5R w{i&V`p?`3A0c3'q="Ua4'q"[^3'*Pq=cZ'#d"UcZ'%d"UaZ'#dqaZ'%dqvj 3'$\q=cZ''b"Uvj V'"}$\cW''u*|vj0Z'#@d$\c:'&u#(Dcm:'%D&uvc u'&u$vV Y')P$pVZ')P#dVZ')P%dV')Pc['&u{Pn&Z,,!!,,O=32653#"&[hq`=QQ, &&m &3;#"'!5 767654x I*e2D0# &pgM,>ꅗ:H~#'`'S'SF'8@'+ '.cQ~@'+ '.cR ~r'>9 9F KSKQZX8Y1/0@  @ P ` p ]3;#"&5Li a^q%qqu {&JOw`73#!!dž$Nd`Vw`#676#732767!5ʆ#5H2K1i0/N)deеT0Hd01``vg{'y{&3#3## +@     22221/220!#3!53#^ժ ?!5 ?8'tXz8 U'uXz8'zt8'wXz8 U'xXz8 'z,w$'w}$'x}N@ T1/0333N@T 1/20%3!533yոBy@ T1/0)533ysոBq8@ E EԶ0]991@  /0 6& #" 3 *NYh> éA@E E Զ0]91@    /<20 6& "'!53&54 3 *NNJhh> é!8@ E EԶ0]991@  /0 6& &54 #"'!5 hYNJ>z=x 4@   2291@  /290)33!x³j*]Qix 6@   2291@    /2290%!5!33xtj³瓓]Qi' 4@     2291@    /290#5!33j³]Q=q) #33mCq"q )5333!mm"q)533#mOq $@  1/2<0)3!33OkUq""Oq (@   1 /22<0)533!33OιUΓ""q $@  1/2<0)533!3kιU"Oq $@   <1/2035!!5!3ΓK"Oq $@   1/20#5!!5!3ΓK"q @ 1/0!5!!5kqKq:@!E E ܲ@]ܲ@ ]1@  /<0!&'.4> !2>4."RJr 惃sKR9[ZZ 1ũbbŨ1 p`88`p`88!>@#E E"ܲ@]ܲ@]1@  /2<0%!!5!&'.4> 2>4."RJr 惃sKRQ[ZZ{ 1ũbbŨ1 p`88`p`88O:@!EE ܲ@]ܲ@]1@  /<0#5!&'.4> 2>4."RJr 惃sKRQ[ZZ{ 1ũbbŨ1 p`88`p`88O &@    21 /03"3#!5!>k fO "  21 /03"3#!5!>c f $@   21 /03"3#!5!pk fq7@ E<21@  /<20!!##"&6 !354'&"3.Cf^v ]8mr^<Uf"qɃ]8ƃ;@! E <21@ /2<20%!##"&6 !3!554'&"3.Cf^v7]8mr^K<Uf"Ƀ]8ƃ7@ E<21@  /<20%!##"&6 !!554'&"3.Cf^v]8mr^K<UfɃ]8ƃ ,@   <<1@  /03!!!!!55Փ/ 0@   <<1@   /20#53!!!!!55B/D ,@    <<1@  /0)53!!!!ys55B/= ,@  <<1@  /0!!5!!5!355ߒѓ 0@  <<1@  /20#5!!5!!5!355ՓLѓ ,@    <<1@  /0)5!!5!!5!,55Lѓ *@  <1@   20!!27654'&3!23,R4,,=ٹUiXO]Oz}I_"_Ҥ.@  <1@  /220#533!23!!27654'&ιUiXO,R4,,=B_Ҥ]Oz}I_ *@  <1@   /20!!27654'&533!2#,R4,,= ιUiXXXl]Oz}I_"B_ҭ@@  ܲ_]9@  /999@  10!4'&'5!!5Mc4B_9V@9D@   ܲ_]9@  /2999@  10#5!&'&'&'5!! 5Mc4BX]9V@9$@@   ܲ_]9@  /999@  10#5!&'&'&'5! 5Mc4B X]9Vq=:@   91@ /̲]촍]0!533T9 >@  91@ /2̲]촍]0#5!533hՓL9 :@  91@ /̲]촍]0#5!53hL9+#1@%!$1@  #/2203432>3234&#"!4&#"!}x5%^qZHZlK--Xh|ŕnc%5@'#&1@  $/2220#53432>3234&#"!4&#"!}x5%^qZHZl[K--Xh|ŕnc#1@%!$1@  "/220#53432>324&#"!4&#"!}x5%^ZHZl[K--Xh&|ŕnc= -@   <<1@  /<<0!!5!3!!!KK?1@   <<1@  /2<<0#5!!5!3!!!KK? -@   <<1@  /<<0)5!!5!3!!@KK?=X>@ <<<<1@  /2<<<220%!!5!3!3!!!=KøL??XB@  <<<<1@  /22<<<220#5!!5!3!3!!!%!KøL=??>@  <<<<1@  /2<<<<<0)5!!5!3!3!!!0KøL=??Oq %@   1/203!3!$Uq"KOq *@    1@  /220#53!3!$U"Kq %@  1 /20)53!!kUޓK=C  1@ B/0KSX@Y!!!tFs0hB~ F  1@ B /20KSX@Y!5!!!tFlhhB~BC  1@ B/0KSX@Y!5!!tFlh0B~B+ 8@!  <<1@    /2<20327654'&+!!!2/!m]%i ; @ED\qQE=4."RJrCEoJRXErrJS9[ZZ 1SV/ { 2Ʀ1 "p_88_p`88*#5!5&'.4767675!5!!2>4."RJrCEoJRXErrJS9[ZZ 1SV/ { 2Ʀ1 "p_88_p`88O(#5!5&'.4767675!5!2>4."RJrCEoJRXErrJSQ[ZZ 1SV/ { 2Ʀ1 {"p_88_p`88Q %@   1/0!!#!3BQ *@  1@  /20#5!!#!3ԓ} %@   1/0#5!!#!+Q (@   <1 /0!!#3!3OQ -@   <1@   /20#5!!#3!3ԓ} (@    <1 /0#5!!#3!B /@   <<1@   /20!!!5!3z;  K"qѓB3@   <<1@  /220!53!!5!3z;7 K"ѓm /@    <<1@  /20!53!!5!z;7 K"ѓ+q &B@%(E# E'ܲ@ ]<<ܲ@]1@ # $ /<<02>4."&'.4767673! [ZZRJrCEoJRXErrJS"p_88_p`88~ 1SV/ { 2Ʀ1  (F@ *E#'E)ܲ@]<<ܲ@#]1@' (/2<<02>4."!5!5&'.4767673 [ZZlRJrCEoJRXErrJS"p_88_p`88 1SV/ { 2Ʀ1 O &B@(E# E&'ܲ@ ]<<ܲ@]1@ #  %/<<02>4."5&'.4767673!5 [ZZRJrCEoJRXErrJS0"p_88_p`88 1SV/ { 2Ʀ1 {q*!&'.4767675!5!!!2>4."RJrCEoJRNXErrJS9[ZZ 1SV/ 2Ʀ1 "p_88_p`88 ,%!5!5&'.4767675!5!!2>4."RJrCEoJRNXErrJSQ[ZZ 1SV/ 2Ʀ1 p_88_p`88O*)5!5&'.4767675!5!!2>4."0RJrCEoJRNXErrJSQ[ZZ 1SV/ 2Ʀ1 p_88_p`88 'b'bb 'b'bc 'b'cb 'b'cc 'c'bb 'c'bc 'c'cb 'c'cc  :@   @ ? o ]9999991 2<0#'##'##'d2222222dddddV!#!3!3#3jժVV8`!##333#{}`9VVX{ %5#"&5332653!"&'5326Cuȸ||aQQRjBfca{+,*}GR'>}GR'-}G'L'-}Gx'0}G'2 ~&'>X  ~&'-4H ~&'-('-4H ~'.  ~'2 G&'-_ - &'-R-7&'-R- G&0x  &0  7&0  G&'/ 0x  &'/ 0  7&'/ 0  &.x2&.X&.X &/~ 2&/ &/ &/R&/|R&/|Ru F&/,@&/,F&/,\&6-k?&7- &8-\L&6'--k?&7'-~- ~&8'--\&60?&70, &80,k &9-k?&:-~ ~&;-k &9/k?&:/,~ x&;/>7%2$6=4'%$=4767!;#"&'#!"'$4733k1yY `h_ /.Z\9 Sl ?AhXl k7>c`7# #5&E^209&b \^~B" #5!276'&'%$=4767!#. cY `h_ >_߸h,n7>ba7# #5&qe)#5!27654'%$=4767!;#"&'#9pY `h_ /.ZZ8 `h7?ba7# #5&E_/(W&(>F&>&>&-Fr&-r&-&0X&0&0+&,>F+&->+&.>+&,.X+&-.+&..4&,/4&-/K4&./K#&-j&-&-#4&/4&/4&/#&0& &0c &0+&8'-?&-'-R&4-~'-R&5-+&8'-?&>&'-R&4>P~'-R&5>P +&8/& X&40c ~X&50c5 b@ <2991/0K TX @ 878YKTKT[KT[X  @878Y P ]#53#3+e $@/  !# #%" " "!& %999919990KTKT[KT[X%%%@878Y@ ttttv]33267#"&546?>7>5#537ZZ:3mN`^gIYX0&DeWX5^1YnFC98ŸLVV/5<6XuX %#!5!276=3%Hc,1VV,1jٻ#!!!!# -#!!!R0S O -#f# !! !!5 N+)# m@>2&#"#"&'7327 ֳPd \ jkPd 켰}켰H&LL Q'L'LL@-6?67632&#"#"'&'7327&'&54767676'4'&' uphmdNPd ]z vphmdNPd fuV?bd4?V?fj4`\cM["jݜx9`\cM"gݢzBfd3vAif3HMQZc67632&#"!67632&#"#"'&'7327!#"'&'7327&'&54767!!676'4'& uphmdNPd  upimdNQd ^z upimdNQd  vphmdNPd fu"V?fj4Q V?bd4`\cMl`\cM["jݜx9`\cM@`\cM#hݢz[Aif3qiBfd3 Pmqu~67632&#"!67632&#"!67632&#"#"'&'7327!#"'&'7327!#"'&'7327&'&54767!)!67654'& uphmdNPd  upimdNQd  uphmdNQd ]z vphmeNPd  upimdNQd  vphmdNPd fu"""V?fj4YV>be4`\cMl`\cMl`\cM["jݜx9`\cM@`\cM@`\cM#hݢzA[Aif3qiBfd33&#"7#754'&'#"&'7327#4767>32nSb ~YfMfpH>> fpSb =[Bzz fp)"X*e e*mH鿬Bxۛz鿭>4'>7'7&#"7#"&'7327&'&54767>32mV?fj4Vs eSb ~kef%Uz lkSb fu lkAif3ETieX[mee_X9鿬"gݢz=.'>7'&#"'#"&'7327&'&54767>32mV?fj41M>V vfSb fj lkSb fu lkAif3]Di[wf&["Yfj9鿬"gݢz P# ! !Ass # % O P# ! ! O $# # #KuuO;>^8bC# 3 35.Ae8^?R u7!!  767654'&'  $'&'&7676R<¡¡?3dccddccdYTRzzSSSRRYR u3?  767654'&'  $'&'&7676!!#!5!<¡¡?3dccddccdɵeepTRzzSSSRRYɵjeeR u3?  767654'&'  $'&'&7676   ' <¡¡?3dccddccdɵsssspTRzzSSSRRYɵssssY&L'L'L L@327!5!>32&#"!!#"&'wSb -}# lkTb "r/ lk۸鿭?/鿬@'327!5!!5!>32&#"!!!!#"&'wSb n lkSb uc lk۸T鿭_O鿬@&#"#"&'73275>32nSb %,, lkSb %9, lk \鿬鿭@,5&#"&'67#"&'7327&'&54767>32nSb h9q-XLa lkSb fu lk-V?fj4[:\f.i3 9鿬"gݢzAif34&#"676='3'#"&'7327&'&53>32nSb =[Bzf L fx jkS` XqH?> jkgLBx+f f+ݘz鿬#XڡnHcJ@!!!!!>2&#"!!"&'732f* ֲPc  ΰPe  `켱b@,!!>2&#"#"&'7327326&f*֌:, ֲPd ]z jkPc 9L~켯["jUx9켱l2G1!!327326&# >32&#"632#"'#"&'+Sb &@Oàv"jkSb S`${g jk¸X(L(XKT/鿬@ 4!!6& 327&'&767>32&#"#"&'_*Sb fu lkSb ]z lk(͓l"gz["jTx9鿬@"&7!>2&#"!!#"&'73273!#3 ֲPd A fePd "C;켱RfwxKKB/&#"!2#567&'!#"&'7327!5!>32nSb $~ˇ y/ lkS` -c C& lkgL)鿬fcJ@%&#"7 '#"&'7327' 7>32nSb ީd# lkSb !g lkޫ鿬de鿭@,327#7>32&#"#'#"&'wSb @\-J۫ lkSb Xz@ lk۸)FqG% 鿭r"b/XG鿬@)&#"63#"&'7327&'&3>32nSb <~ lkSb Yz= lk 6s.7鿬!b/FE鿭N >2&#"#"&'7327!5 ֲPd \ kjPd 켱}켱 xL@>2&#"#"&'73275! ֲPd \ kjPd HV켱}켱^_<++LY mQY^f55q=3=dd?y}s)3s\\?uLsLsyD{={\{fqqq/q999qqJ+o#7=V;=3X55^R\sd5^5bs#5`b?yyyyyys\;\\\3 LsLsLsLsLsLf {{{{{{{fqqqqq9999qqqqqqH==y{y{y{sfqsfqsfqsfq)q3 qqqqqq3sq3sq3sq3sqTx\9\9\9\9\9r\9?u9u9uuFLsqLsqLsqs/qJJJ+o+o+o+o#7#7#7DV={\3X{\3X{\3X/ }}ssfq3 }qqLu3s~\ 9 =LsNgvsq7r+d#7#7N={\3XTT\h3qT]hX\] ` d <qKsday{\9Lsqqy{y{{3sq3sq?LsqLsqTX9 ` d <q3squy{{LfHy{y{qq\9\9LsqLsqJJ+o#7,Gqqq{\3Xy{qLsqLsqLsqLsq=79qqy f u +o3XPP}  yq\9@sq J qefqqqqq|SA4Pq9qq q``9t*KM:+#qqGpPPOJI>>t+o7#7#7q=V=f3X3XXmXXXXLsPqq;VVqXXqvqq77:7/<66JO<u1ufu]H^H 6&:uuuuuu  3s3soouuuuddLhuTzuuu%q7]yq$U $ zw(j#Lcxh!c+qc3x+x.pppp*pw<.::3efqe\sDy}uy{\Ls\?yLsLs{=LsN\FqSFq qSZkq=xJvkqJqqdGp;Gpq?qWWGpAOpLsq0q@GGrwxssFqU-~Od$s6sq,J7Opfq9Lsqs5UsssJs\\\T\J#y}}@e(!TLss#y{=6|<}o{p4kq5FA33L ;q;fq<=p;rR>Qdqtqq/4dq+o9998L07/3=;xs*` D3 GLsk7sS[2Lsq@R2@R2s<qsq pv9xssfq;XXX.j}!&4fG8=(5F!A!=2*ISsqsfq<=={=;yt|||\(5F?56].I6r|29y{y{{qLuqLuq(5F!ATX33LsqLsqLsqodq#=#=#=|4QfG8{=;{=;}q -qn6.3sGq/STL ZTL'AtLsqDVT>LLXv!]Z-]D`F d#iUxgZ%UdM|x2LsRnuu>ZCqNqCq,qj,< {n0oz)oqF~dDDcc/NDdc\\fcYXLX^X:.X:0LX;XXOoX.4X1XQXXXXBbS(?99l9lC91***}} ffuuXK5k1CCOOLLLRLLLLLUL<L<LdL\W5kVz*******}}}}}}}}}== fuKKKKKK5k5k)n)))))))*CCC1LLLRLLLRLjLL<L<Ld9qd==;;q;q=x==D=;==p==q==.qqB[B[{d{d]xmxs[")>WE_IIY"~h~h@sx2OsOsxMo`P{P@@@@`NzBza\d>N c c]ccY]dji::xnnond$P<Py<x<xd@2 PKnddZ nxyxd<<o<nPd$dZddd)hd$dZd.d.Jdd$d^d.<Z. ddJd$d$<.Z.d$)d.d$xdd$doddjZdPdndyyyy'''''w'w'ww'w Xc^c^%H Ewyyyywwwwwwywwwwwwwwwyy^^^l4wl4w4y4yywyFFFF*F*F*FAA8F3F3FFFF*F*F*Fzzwuuuwwwuu&w&w&wwFF wwwFFGwyFyFFwFFFwwwFFGwy=Fy=FGwGw=F=FwFFFFFV+V+FFV+V+VY]YFFF"F"F"F"FGFGFGF F F F F wwww?w?w?wYSSwSwSSSFFFFYwyyyyMMwwdwSSyy4yFwwFFww```````FwFw     FFwwFF%w%!%!%w%w%!%!Y )#su` z    s 4 s 3  E p 2 O 3wq= {>fq$S9( 3qfyqyqy3/qqq222</=V3X5x=2ZLr u//SH||NYHG p+"M"M>G/Mmu>GVGVGTR>GnzhuuEuOGGOGOGmu\#=nnuV&7yGSG%nzu=nV&7yKySG%tV29>GGGOGT_>G=nIzIIVz[quuIuEqOGOGFK\#^YGu@zV&7~77#7OG[[[[BBy{}}}sfq)q)q)q)q)qqqqqq/3sq\9\9???uMuMu9u9LsqLsqLsqLsqJJJJT+o+o+o+o+o#7#7#7#7y=y=DVDVDVDVDV{=;{=;={\3X{\3X{\3X#V={//&qy{y{y{y{y{y{y{y{y{y{y{y{qqqqqqqq\Z9D\9LsqLsqLsqLsqLsqLsqLsqNgvNgvNgvNgvNgv====' FqFqFqFqFqFqFqFqyy'iSSSSSS0l7hx qqqqqqoE.k_FqFqSc<qqFqFqFqFqFqFqFqFqyy'i7hxk_FqFqFqFqFqFqFqyyy<pr\\D~{aNsVddddd%%%%9933W q q(()((()( 33?nn=V`Jd=n=dn8N(ffadp5Wnz5?5f5\5l5Y5S999og0u5W55^5b5?5f5\5l5Y5S999og"MVGOGuVG<uhuTzu0umuu\#Vs`" .;F_q( ..D]1uj C===P=&C&Cs#&<<oI HZ;jDN hR6nLsbBSV,y('y\XNND?yJ\}WJT9hgd(V FhZ $<|3uuWZ[O=;6Q ^^b?fbfl\bya W{=w= =us)9~=}== ]=;;;9fqq y) ysesWdud    du,dudududvdvdd*ZZd-Opdduudwddxvxddddudud  dududuku7^H^^^@^^^uzz^uwududdud7u7y#_ZZ,dDX===,,ff+uPuuu+uPuuu+u+u+uyyy``>>**yyby*cc| a aXXJr;xxdxxd++* 8 8 P 8 x PFq 8#+7'Y,,,,,,,,,,<<<<<<xxxxxxxhh''''''''''''''''''''''q''''''''''llgg'''''''''''''''''pprppppppppp7p7Tpp''''3'''ppppp'''',h,d,,,,+,}}_}} ,,,B,d,,,,,,,,,,},,,dZd2E\,,,,,,,,,,,,,,,WWW,,,,,S,,,,,],,,,,m,,E,,,,A,,,U,,Q,0,,,U,,L,0,C,,X,,B,,X,,,x, ,,,,,,,,,,,,,,1,,,,,,,,,,,X,X,j,, T},y,},),,,,,,,d  f9  dT YxDVVVVVIVVx+5X3ppppR >pTVSTWW/V0/0002p@TTTTpnnTVaaTT,f,z,z,z,z,xNNx>NnX~#9Uwlf,,,,,,,,,,                    uuuuuuuuuuuuuu++<uusunOss[YOO Bu xd xu xd xd xu xd xd xu xd xu xu,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,duwOwO::: u+u+u+u+u+u+u+u+u+u+u++u+u+u+u+k  77^^  7^uuHH''''$$"pMMu 9 u H#?{\3X@sy@s= DVh<GpPqbfr {\{2PiIPlhPmPihhsshhfch{dPhhPVz]P<`FPPdz|"h5z,qssu@xC@~yyv{\{\ssg)?>8{\(oo:o\:o\csssss$d{=syNsNs6??,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,}F)3s??ss{\u;yy3D{=}yy\Lsu#sffffr+d pv9;<@>speKkT5L mLsqsq s&q:Bz<<| s&qffss7S+o { { #{{{{se? q#Sjxt  s&q 222Lsq  u 9553|M.U3?J+h'GRwF\ Dn`#Zn`nn`n#Z`n3nnnnon9nnqnn YnnnnnOnn2nn)nnn1pnn!2nxnnnnnszwddddddddddd$d$d$dKdKdKdKdKd_<_<_<_<_<_<q/ / ///}/o } <VJN1X?,XXuX`XNXXYYYXLX^X:Y?Y0YLX;XXoX2X1XXXB.X;XX:j:j:j:j:j:jKH KH ************}3}}3}}3}}3}jj))k))k))k))k:j8k""""C:j:jC:jp*XXXiXXXXXXXXXXX9p9lpl"9lplC:j9p:j1J:j:j*********}3}}3}jj 3# 3#  f^f^uBuuBu/KH 5kk kpSI:j1J8"CC:j..TT4dddd:D_ j d:}d}xzd8vvddDd}d,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,c3s$f"=3LrDrlK{fqo/q5 "qqq+o7=HVhL=Xy}s)3s\?uLsLsyD{={\{fqqq/q999qqJ+o#7=V;=3XkZqAjd9*}*fC uK 5k *} fuK5k4VV4j4/44V//@bb@?@ $6C ;C $@@b ;6@C ///////////////////////////@///////////////////////////////WWWWWWWWX xKW= @WW Y_WWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWW Y_WWWW#WW WWWW: Y`W:W=W=W=W=W=W=Ws N:jH k :j:j:j********_9xxxxxxxxvxxvxxvxxxvxvxxxx,p:jj9Jqq9O99:::qd=dd=;;;;;;q;;;q=xxx==D=DD;;;====p==q======...qq,,,,,,,,.j3}3}3}3}3}jjjjj 3# 3# 3#  ^BuH H H k k n)kkk)k)k)kppp:j:j:j55??4#   G G G G PR PR PR? 0 $%*K-r294K7D9:;< R&Y\99999 &&&&&K&D: $$$$$9$&$*$2$4$7a$9}$:$>?@@@@@ABXCpDDF$FHHIIJ KXKLLM,MN8NOHOtOP,PQQQQRRS S8ShSTUUUUVV@VXVpVVWWWWXXDXtY<ZtZZZ[ [$[\\]]<]h]]____``,`D`\``bTblbbbbccpddee4ede|ffLfxfffggg4gLgpgggggh h4hDiii<i`iiiiijj4jXj|jjjjkkkHkllllmm8m\mmmmn,nPntnnnnoop,pDphppppqlqr rDr\rtrrrsttHthttttuvvvvw w0wXwpwwwwxx,xTxlxxxyXyz zDztzzz{{${<{T{l{{{{||4|L|d|||||}<~~~ Xxt8p<P |H`x d$ @l(`,44 (@Xp0Pp $<Td|\t,D\t$4Ld| $<Tl,D\t<T ,D\t(xX<D@L(ŒL\p Ũh$L(ɈʬD̔μlP$4PԤՈ@@ڄ\ܐߴLxXX@T`th T $Ht|<LP8(l@`d$| d      ( `  0  D l   l $Td (Lx T8`0@tLPL4H\ | 4Xtt 8TLp , h   !!!(!<!!!!""\"""#$######$$$8$`$$%$%%%&&&P&h&|&&'4'H'\'x'(((D(T(d((()$)4)D)x)))))*(*X*p*****++ +8+H+X++, ,,,,,,-`-p---...../l/|00011 181P1h123l3456D6778X889|:8:H:;X<<<=>D?P?@x@@@@@A0BBC`C|CD\E EFpGGH\HlIIxIJ`JKLM@MNOhOPPQQRHRSPSTXUU U0U@UVV,V<VLWWX(X8XPXhXY YYZpZZZZ[H[\H\`\x\\\]x]]^L^\_P```aaabbb`bpbbcccd0ddeTeef`g ghhhxi@ijjjkl`lmmnnnno8oHoXoopppqxqr@rrsDstuu4uvxvw4wDwTwdwtxxy4yLydy|yzz{\{||}4}t}~(px4Ldp|`,T|(PTp4Ld8X4((\ lh84$`<Lx Dhx(8Ph,D\t4t$th8|8| 8DTdd0t ,<LHt<`ŒÀ8\ļpż(ǨȘt0ʌ8ːˠ̠ͤLτϼDXlѸ4|Xӄp(HP֤֔hװ`ج$٬ټLۄL8ݰ4D8\߄H| |T@|dLp0plD `t dd@`\,D`x@X @X 8T`p@\dx@\`L4 Dx     , D d |       $ < T l        4 L d |       , L d      8P| $<TlLd\|,<L\ll(p@4@L0|t L !!!""#4##$L$%h%&&d&&'T'((,(l(()4))*\+ +,-@-./0(012p334P5 567X789X:8:;>>?4??@,@AAAB\BC8CDhDEEFFFGHHhH|HI,IJ$JK4KLMN NxO`PpPQ$QtQR0RRSLStSTHTUUUV0VVW0WX8XxXXY`YZZtZ[<[[\\X\]]X]^<^___`d`aHaabbcPcddpde<effggghlhi8ijjxjk<kl$llm`mnXno oop,pxppq q$qqqqrHr`rxrrrrrss s8sPshsssssst$tDtdttuu\uuuv v8v\vtvvvvvvw wpwwwxx4xLxdx|xxxxxy y$y<yTylyyzz0z@zXzz{D{\{t{{| |$|<|T|l||||||}},}D}\}t}}~~~0~~@X0H`x4h 8Ph(@Xp8P0H`x 8Ph4Th(0H`Dp $<Tl,D\$<00H`xXhTl4Ld| $<T 8 8 $<Tlt,xx\t4Phx $8Ph\@X4DTl 8Ph<h,h(dh0H`x 4d4\ \@PPxPxhD` DÀÐ`ĸH<tƸ(ǘǨ(Ȅ(xɘɨ<LʀH˘h̴̘8p͠08ϤHPѸҐ\x ՜0Tֈ$׸<ؤ|ټTXېܔ(<Pdhx޸D߀H\0tHpx | \< <P$Dp0H`x 8Ph(@`(@Xp0H`x(@Xp0H`x @Xp0H`x @`x 8Ph(@Xp0H`x 8Ph(@Xp(@Xp0H`x 8Ph(@Xx 8Ph0H`x 8Ph(@Xp0\(@Xp $<Tl   < X p        4 P l       $ < T l        < X t        8 P l     4Ld|0H`x,Hd 8H`p(@Xp0H`x 8Ph(@Xp0H`x0@P0H`|4Ldt4Ld|4P`|,HXtDT0l`  L !(!h!!!"@"X"X"X"X"X"X"X"X"X#$%%,%L%h%%%&4&&&'p''(D(p((()()X)p))**H*x***++ +D++, ,@,h,,--T--.$.$.$.$.$.$.$.$.$.$.$.$.$.x./0,0012 2T2p223 33333334 4 444H4\4p444444455$585L5`5t5556$67d78 899:;t;;==>D?@lAABBC4ChCDLDDDEE@ExEEFGHHIDIJxJJJKLM4MMNO0PPQ QPSTUTUVdW|XxY(Z@Z[[\t\]]t]]^^^^_`a abdcDcpdeef<fg@gghiiiijPjjk0k\klm0mhmnhnnno o@o`oooopp p@p`pppppqqq(q@q`qqqqqqrrr(r8rPrprrrrrss s8sXshsxsstuvxvvww$wxy4y{|(|X|||}4}~(~hH  `l0h X@Tl,4Xt<lTT L LD<X\TT80x,Td0XPHPTT Xl| \|Ll@t4L0 ThpD,(@`@8xlń<ƨ8 Lȴ`ɤ,ʘ@ˬ̘xμϐTЌ0LҼ,pӴ Ԍ0լ,֘d|`ؔڔd ݼޠ`d<x <l\ xP(xL0\ T d@ h8XpXTTDTx ,PtP4tP 0\((Px4XxhX p  P ` p     P     0 h    (\@<h (,,"%'t''''((P((()<)))**<*`****++4+X+|+++,,(,P,|,,--,-T-|---.$.T..../(/P/x///00H0t00011D1t1122D2x2233T3334(4\4445 585`55566@6l6667,7X77788`889989h99: :L::;4;d;;;<<0>4>P>l>>>>>??0?L?h???@B<CCC(CDCXClCCCCDD DDD`DDDEPEFGtGIIJJ JLJhJJJKK,KHKpKKKLLLHLdLLLLM M<MhMMMNNHNO,OPQ@QR`RSSlST0TTTU UUV,VXVVVW$WhWWWWXXDXpXXXY@YlYZZ@ZZ[[\\]](]P]x]]]^^0_ _`Di(l lDllm\mnoopsuv,vwwpxz|zz{|}X}~|@,4<(p<$Dd\x TDl D$h hp`|ld(@(Dt 8  Dxh<HȀx̜͐DҠ`TpԘ԰xLDXpxt$l4x8Dt \`h  l  h  T @ 8hH,D\x8D 0  !P!"l"##X#$&0($)P+,/X458489:<=>@XACC|CDPDEE8ETEpEEFF,GGH\HI@J`KHKL$L`LLLMMDMlMMMNTNO4OQ QRTTTWXZZ[]]^_`acd8dehf0fglh4hijLkk@klkkklllm$mxmmnn npnnoodoppPppqDqrrssLst0tu<v vwxy|yz<zxzz{{0{H{`{| |}~< L$`|| 0D`|0D`|0Lp<p Dp$P|@d@l4p Dp$P|@d@l4p$P|,`0T @tD,p Dp$P|@d@l4p$P|,`0T @tD,p$P|,`0T @tD,p LP0lD,p`$pP`( 8t@th(pX<dxDTl0H`x`,|ŐLư ǐȠ0ɌXʼ4Ld˨8̈|Ψ,tϸ|$ќԠpռL֔$׀ר$P|بLلټHtڜ,\,hܬ<`ݜ$ޔ,8HLhL|LH\4hx( \<(8XhLPD\L$4D0D4 p8l4D`,l|X l P    \ @Ddt$<(h<\|4Ld| $<Tl,D\t4Ld| $<Tl,D\t8HX 0@ 0@P 0@P<X|  8 ` p   !|","D"\"#<#$$t$%%P%%%&&x&' ',())x))*h*x****++8+`+++,,$,D,h,,,,-(-T---..L.|.//0,0<0011l2H2334p45456 677,7<7778 8P8|99:@:;@;<$<=H=> >t>?8?X?x?@$@4@\@A AA|ABBCHCDDpDEtEFdFG@GH$H4H`HHIILIxIIIJJ$J8JLJ`JtJJJJJK K K4KHK\KKKKKLNQ\TVW WtWXXY\YZ`Z[[\4\]]l]^P^_ _`8`a,abbpbcDcd0ddelef\fg0ghHhiijXjk kklHlmmmn<noop(pq(qr$rs,st8tu\vvw`x xyzd{ {|X} }8}l}}~<~d~4|@Xp(@Xt 8Ph(@X $<Tl,D\t4Ld| $<Tl,D\t4Ld|8HXp0H`x0H`p$4Ld| $<Tl$4D\ttttttttttttttttt Th4H`t(@Xp,D\t4Ld|l@Xpx0H`xdxpXp0H`xTHXDTd $<Td(8(@Xp,,,,,,l(X\xH4|tDx(p(D`|0X$LtDl8`,T$Lt@l 4`,T| Lt@h 4\,T|¤À,h0|LDŽǼ0l(pʰ(<̤ltθ4\Dl| dtՄՔդմ$4DTdtքִ֤֔$4DTdtׄהפ״$4DTdt؄ؔؤPt0ۼ`p݀ݐݠݰ 0@P`pހސޠް 0@P`p߀ߐߠ߰ D\t,D(@Xhlpd(@XX8,\LlLH   l < "p$p&)(+.0247p:4=<@l@@ALBCD@EGpGHIJL`NPPQSTV<X8Zl[h\^$_adfgi4jlo(qtHuw|yl{~$l0 PhD@tTT<P(8$<|L @,xhphĸŴƈ,h(Ȍ\ɸ$ 4TTTجٰڄݤބߐpl` |Pd<|dtXX$d`  ,l,L `! !@!"@"|"""##D#h#$$,$<$%&8''' '0'@''''(( (8(P(h(((((())0)P)p)* ***++$+@+\+x++++,, ,<,X,t,,,,---4-l---.. .8.X.x..///$/</h///00l0000011101H11123(34 445(5X556,6x677X889T9::`:;<8<<=T=>>p>?t?@AAB BxBCD,DE4EFFG$GHH`HI,IJ$JK|L$LLMXMNO,O|OP$PQQRRSSdST TdTUUUVhW,WXYDYZXZlZZZZ[ [D[h[[\4\p\\] ],]D]\]t]]]]]^^<^T^l^^^^^__,_D_\_t_____```4`L`l`````a a$a<aTalab0bc$c<cTclccccccdd,dDd\dtdddddeee4eLede|eeeef f,fLflfffgDh<hPhhhii`ixijhkmLmnooop<pqLr$ss8st(tuPuvpwwx\xyzz{${{mT+h >2   : `   (Z4;b ;; 0    " F m " : %: h: ; ;Copyright (c) 2003 by Bitstream, Inc. All Rights Reserved. Copyright (c) 2006 by Tavmjong Bah. All Rights Reserved. DejaVu changes are in public domain Copyright (c) 2003 by Bitstream, Inc. All Rights Reserved. Copyright (c) 2006 by Tavmjong Bah. All Rights Reserved. DejaVu changes are in public domain DejaVu SansDejaVu SansBookBookDejaVu SansDejaVu SansDejaVu SansDejaVu SansVersion 2.37Version 2.37DejaVuSansDejaVuSansDejaVu fonts teamDejaVu fonts teamhttp://dejavu.sourceforge.nethttp://dejavu.sourceforge.netFonts are (c) Bitstream (see below). DejaVu changes are in public domain. Glyphs imported from Arev fonts are (c) Tavmjung Bah (see below) Bitstream Vera Fonts Copyright ------------------------------ Copyright (c) 2003 by Bitstream, Inc. All Rights Reserved. Bitstream Vera is a trademark of Bitstream, Inc. Permission is hereby granted, free of charge, to any person obtaining a copy of the fonts accompanying this license ("Fonts") and associated documentation files (the "Font Software"), to reproduce and distribute the Font Software, including without limitation the rights to use, copy, merge, publish, distribute, and/or sell copies of the Font Software, and to permit persons to whom the Font Software is furnished to do so, subject to the following conditions: The above copyright and trademark notices and this permission notice shall be included in all copies of one or more of the Font Software typefaces. The Font Software may be modified, altered, or added to, and in particular the designs of glyphs or characters in the Fonts may be modified and additional glyphs or characters may be added to the Fonts, only if the fonts are renamed to names not containing either the words "Bitstream" or the word "Vera". This License becomes null and void to the extent applicable to Fonts or Font Software that has been modified and is distributed under the "Bitstream Vera" names. The Font Software may be sold as part of a larger software package but no copy of one or more of the Font Software typefaces may be sold by itself. THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL BITSTREAM OR THE GNOME FOUNDATION BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM OTHER DEALINGS IN THE FONT SOFTWARE. Except as contained in this notice, the names of Gnome, the Gnome Foundation, and Bitstream Inc., shall not be used in advertising or otherwise to promote the sale, use or other dealings in this Font Software without prior written authorization from the Gnome Foundation or Bitstream Inc., respectively. For further information, contact: fonts at gnome dot org. Arev Fonts Copyright ------------------------------ Copyright (c) 2006 by Tavmjong Bah. All Rights Reserved. Permission is hereby granted, free of charge, to any person obtaining a copy of the fonts accompanying this license ("Fonts") and associated documentation files (the "Font Software"), to reproduce and distribute the modifications to the Bitstream Vera Font Software, including without limitation the rights to use, copy, merge, publish, distribute, and/or sell copies of the Font Software, and to permit persons to whom the Font Software is furnished to do so, subject to the following conditions: The above copyright and trademark notices and this permission notice shall be included in all copies of one or more of the Font Software typefaces. The Font Software may be modified, altered, or added to, and in particular the designs of glyphs or characters in the Fonts may be modified and additional glyphs or characters may be added to the Fonts, only if the fonts are renamed to names not containing either the words "Tavmjong Bah" or the word "Arev". This License becomes null and void to the extent applicable to Fonts or Font Software that has been modified and is distributed under the "Tavmjong Bah Arev" names. The Font Software may be sold as part of a larger software package but no copy of one or more of the Font Software typefaces may be sold by itself. THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL TAVMJONG BAH BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM OTHER DEALINGS IN THE FONT SOFTWARE. Except as contained in this notice, the name of Tavmjong Bah shall not be used in advertising or otherwise to promote the sale, use or other dealings in this Font Software without prior written authorization from Tavmjong Bah. For further information, contact: tavmjong @ free . fr.Fonts are (c) Bitstream (see below). DejaVu changes are in public domain. Glyphs imported from Arev fonts are (c) Tavmjung Bah (see below) Bitstream Vera Fonts Copyright ------------------------------ Copyright (c) 2003 by Bitstream, Inc. All Rights Reserved. Bitstream Vera is a trademark of Bitstream, Inc. Permission is hereby granted, free of charge, to any person obtaining a copy of the fonts accompanying this license ("Fonts") and associated documentation files (the "Font Software"), to reproduce and distribute the Font Software, including without limitation the rights to use, copy, merge, publish, distribute, and/or sell copies of the Font Software, and to permit persons to whom the Font Software is furnished to do so, subject to the following conditions: The above copyright and trademark notices and this permission notice shall be included in all copies of one or more of the Font Software typefaces. The Font Software may be modified, altered, or added to, and in particular the designs of glyphs or characters in the Fonts may be modified and additional glyphs or characters may be added to the Fonts, only if the fonts are renamed to names not containing either the words "Bitstream" or the word "Vera". This License becomes null and void to the extent applicable to Fonts or Font Software that has been modified and is distributed under the "Bitstream Vera" names. The Font Software may be sold as part of a larger software package but no copy of one or more of the Font Software typefaces may be sold by itself. THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL BITSTREAM OR THE GNOME FOUNDATION BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM OTHER DEALINGS IN THE FONT SOFTWARE. Except as contained in this notice, the names of Gnome, the Gnome Foundation, and Bitstream Inc., shall not be used in advertising or otherwise to promote the sale, use or other dealings in this Font Software without prior written authorization from the Gnome Foundation or Bitstream Inc., respectively. For further information, contact: fonts at gnome dot org. Arev Fonts Copyright ------------------------------ Copyright (c) 2006 by Tavmjong Bah. All Rights Reserved. Permission is hereby granted, free of charge, to any person obtaining a copy of the fonts accompanying this license ("Fonts") and associated documentation files (the "Font Software"), to reproduce and distribute the modifications to the Bitstream Vera Font Software, including without limitation the rights to use, copy, merge, publish, distribute, and/or sell copies of the Font Software, and to permit persons to whom the Font Software is furnished to do so, subject to the following conditions: The above copyright and trademark notices and this permission notice shall be included in all copies of one or more of the Font Software typefaces. The Font Software may be modified, altered, or added to, and in particular the designs of glyphs or characters in the Fonts may be modified and additional glyphs or characters may be added to the Fonts, only if the fonts are renamed to names not containing either the words "Tavmjong Bah" or the word "Arev". This License becomes null and void to the extent applicable to Fonts or Font Software that has been modified and is distributed under the "Tavmjong Bah Arev" names. The Font Software may be sold as part of a larger software package but no copy of one or more of the Font Software typefaces may be sold by itself. THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL TAVMJONG BAH BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM OTHER DEALINGS IN THE FONT SOFTWARE. Except as contained in this notice, the name of Tavmjong Bah shall not be used in advertising or otherwise to promote the sale, use or other dealings in this Font Software without prior written authorization from Tavmjong Bah. For further information, contact: tavmjong @ free . fr.http://dejavu.sourceforge.net/wiki/index.php/Licensehttp://dejavu.sourceforge.net/wiki/index.php/LicenseDejaVu SansDejaVu SansBookBook~Zm  !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghjikmlnoqprsutvwxzy{}|~      !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~      !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~      !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~      !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~      !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~      !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~      !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~      !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~                           ! " # $ % & ' ( ) * + , - . / 0 1 2 3 4 5 6 7 8 9 : ; < = > ? @ A B C D E F G H I J K L M N O P Q R S T U V W X Y Z [ \ ] ^ _ ` a b c d e f g h i j k l m n o p q r s t u v w x y z { | } ~                            ! " # $ % & ' ( ) * + , - . / 0 1 2 3 4 5 6 7 8 9 : ; < = > ? @ A B C D E F G H I J K L M N O P Q R S T U V W X Y Z [ \ ] ^ _ ` a b c d e f g h i j k l m n o p q r s t u v w x y z { | } ~                            ! " # $ % & ' ( ) * + , - . / 0 1 2 3 4 5 6 7 8 9 : ; < = > ? @ A B C D E F G H I J K L M N O P Q R S T U V W X Y Z [ \ ] ^ _ ` a b c d e f g h i j k l m n o p q r s t u v w x y z { | } ~                            ! " # $ % & ' ( ) * + , - . / 0 1 2 3 4 5 6 7 8 9 : ; < = > ? @ A B C D E F G H I J K L M N O P Q R S T U V W X Y Z [ \ ] ^ _ ` a b c d e f g h i j k l m n o p q r s t u v w x y z { | } ~                            ! " # $ % & ' ( ) * + , - . / 0 1 2 3 4 5 6 7 8 9 : ; < = > ? @ A B C D E F G H I J K L M N O P Q R S T U V W X Y Z [ \ ] ^ _ ` a b c d e f g h i j k l m n o p q r s t u v w x y z { | } ~        !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~      !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~      !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~      !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~      !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~      !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~      !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~      !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~      !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~      !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~      !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklm sfthyphenAmacronamacronAbreveabreveAogonekaogonek Ccircumflex ccircumflex Cdotaccent cdotaccentDcarondcaronDcroatEmacronemacronEbreveebreve Edotaccent edotaccentEogonekeogonekEcaronecaron Gcircumflex gcircumflex Gdotaccent gdotaccent Gcommaaccent gcommaaccent Hcircumflex hcircumflexHbarhbarItildeitildeImacronimacronIbreveibreveIogonekiogonekIJij Jcircumflex jcircumflex Kcommaaccent kcommaaccent kgreenlandicLacutelacute Lcommaaccent lcommaaccentLcaronlcaronLdotldotNacutenacute Ncommaaccent ncommaaccentNcaronncaron napostropheEngengOmacronomacronObreveobreve Ohungarumlaut ohungarumlautRacuteracute Rcommaaccent rcommaaccentRcaronrcaronSacutesacute Scircumflex scircumflex Tcommaaccent tcommaaccentTcarontcaronTbartbarUtildeutildeUmacronumacronUbreveubreveUringuring Uhungarumlaut uhungarumlautUogonekuogonek Wcircumflex wcircumflex Ycircumflex ycircumflexZacutezacute Zdotaccent zdotaccentlongsuni0180uni0181uni0182uni0183uni0184uni0185uni0186uni0187uni0188uni0189uni018Auni018Buni018Cuni018Duni018Euni018Funi0190uni0191uni0193uni0194uni0195uni0196uni0197uni0198uni0199uni019Auni019Buni019Cuni019Duni019Euni019FOhornohornuni01A2uni01A3uni01A4uni01A5uni01A6uni01A7uni01A8uni01A9uni01AAuni01ABuni01ACuni01ADuni01AEUhornuhornuni01B1uni01B2uni01B3uni01B4uni01B5uni01B6uni01B7uni01B8uni01B9uni01BAuni01BBuni01BCuni01BDuni01BEuni01BFuni01C0uni01C1uni01C2uni01C3uni01C4uni01C5uni01C6uni01C7uni01C8uni01C9uni01CAuni01CBuni01CCuni01CDuni01CEuni01CFuni01D0uni01D1uni01D2uni01D3uni01D4uni01D5uni01D6uni01D7uni01D8uni01D9uni01DAuni01DBuni01DCuni01DDuni01DEuni01DFuni01E0uni01E1uni01E2uni01E3uni01E4uni01E5Gcarongcaronuni01E8uni01E9uni01EAuni01EBuni01ECuni01EDuni01EEuni01EFuni01F0uni01F1uni01F2uni01F3uni01F4uni01F5uni01F6uni01F7uni01F8uni01F9 Aringacute aringacuteAEacuteaeacute Oslashacute oslashacuteuni0200uni0201uni0202uni0203uni0204uni0205uni0206uni0207uni0208uni0209uni020Auni020Buni020Cuni020Duni020Euni020Funi0210uni0211uni0212uni0213uni0214uni0215uni0216uni0217 Scommaaccent scommaaccentuni021Auni021Buni021Cuni021Duni021Euni021Funi0220uni0221uni0222uni0223uni0224uni0225uni0226uni0227uni0228uni0229uni022Auni022Buni022Cuni022Duni022Euni022Funi0230uni0231uni0232uni0233uni0234uni0235uni0236dotlessjuni0238uni0239uni023Auni023Buni023Cuni023Duni023Euni023Funi0240uni0241uni0242uni0243uni0244uni0245uni0246uni0247uni0248uni0249uni024Auni024Buni024Cuni024Duni024Euni024Funi0250uni0251uni0252uni0253uni0254uni0255uni0256uni0257uni0258uni0259uni025Auni025Buni025Cuni025Duni025Euni025Funi0260uni0261uni0262uni0263uni0264uni0265uni0266uni0267uni0268uni0269uni026Auni026Buni026Cuni026Duni026Euni026Funi0270uni0271uni0272uni0273uni0274uni0275uni0276uni0277uni0278uni0279uni027Auni027Buni027Cuni027Duni027Euni027Funi0280uni0281uni0282uni0283uni0284uni0285uni0286uni0287uni0288uni0289uni028Auni028Buni028Cuni028Duni028Euni028Funi0290uni0291uni0292uni0293uni0294uni0295uni0296uni0297uni0298uni0299uni029Auni029Buni029Cuni029Duni029Euni029Funi02A0uni02A1uni02A2uni02A3uni02A4uni02A5uni02A6uni02A7uni02A8uni02A9uni02AAuni02ABuni02ACuni02ADuni02AEuni02AFuni02B0uni02B1uni02B2uni02B3uni02B4uni02B5uni02B6uni02B7uni02B8uni02B9uni02BAuni02BBuni02BCuni02BDuni02BEuni02BFuni02C0uni02C1uni02C2uni02C3uni02C4uni02C5uni02C8uni02C9uni02CAuni02CBuni02CCuni02CDuni02CEuni02CFuni02D0uni02D1uni02D2uni02D3uni02D4uni02D5uni02D6uni02D7uni02DEuni02DFuni02E0uni02E1uni02E2uni02E3uni02E4uni02E5uni02E6uni02E7uni02E8uni02E9uni02ECuni02EDuni02EEuni02F3uni02F7 gravecomb acutecombuni0302 tildecombuni0304uni0305uni0306uni0307uni0308 hookabovecombuni030Auni030Buni030Cuni030Duni030Euni030Funi0310uni0311uni0312uni0313uni0314uni0315uni0316uni0317uni0318uni0319uni031Auni031Buni031Cuni031Duni031Euni031Funi0320uni0321uni0322 dotbelowcombuni0324uni0325uni0326uni0327uni0328uni0329uni032Auni032Buni032Cuni032Duni032Euni032Funi0330uni0331uni0332uni0333uni0334uni0335uni0336uni0337uni0338uni0339uni033Auni033Buni033Cuni033Duni033Euni033Funi0340uni0341uni0342uni0343uni0344uni0345uni0346uni0347uni0348uni0349uni034Auni034Buni034Cuni034Duni034Euni034Funi0351uni0352uni0353uni0357uni0358uni035Auni035Cuni035Duni035Euni035Funi0360uni0361uni0362uni0370uni0371uni0372uni0373uni0374uni0375uni0376uni0377uni037Auni037Buni037Cuni037Duni037Euni037Ftonos dieresistonos Alphatonos anoteleia EpsilontonosEtatonos Iotatonos Omicrontonos Upsilontonos OmegatonosiotadieresistonosAlphaBetaGammauni0394EpsilonZetaEtaThetaIotaKappaLambdaMuNuXiOmicronPiRhoSigmaTauUpsilonPhiChiPsi IotadieresisUpsilondieresis alphatonos epsilontonosetatonos iotatonosupsilondieresistonosalphabetagammadeltaepsilonzetaetathetaiotakappalambdauni03BCnuxiomicronrhosigma1sigmatauupsilonphichipsiomega iotadieresisupsilondieresis omicrontonos upsilontonos omegatonosuni03CFuni03D0theta1Upsilon1uni03D3uni03D4phi1omega1uni03D7uni03D8uni03D9uni03DAuni03DBuni03DCuni03DDuni03DEuni03DFuni03E0uni03E1uni03E2uni03E3uni03E4uni03E5uni03E6uni03E7uni03E8uni03E9uni03EAuni03EBuni03ECuni03EDuni03EEuni03EFuni03F0uni03F1uni03F2uni03F3uni03F4uni03F5uni03F6uni03F7uni03F8uni03F9uni03FAuni03FBuni03FCuni03FDuni03FEuni03FFuni0400uni0401uni0402uni0403uni0404uni0405uni0406uni0407uni0408uni0409uni040Auni040Buni040Cuni040Duni040Euni040Funi0410uni0411uni0412uni0413uni0414uni0415uni0416uni0417uni0418uni0419uni041Auni041Buni041Cuni041Duni041Euni041Funi0420uni0421uni0422uni0423uni0424uni0425uni0426uni0427uni0428uni0429uni042Auni042Buni042Cuni042Duni042Euni042Funi0430uni0431uni0432uni0433uni0434uni0435uni0436uni0437uni0438uni0439uni043Auni043Buni043Cuni043Duni043Euni043Funi0440uni0441uni0442uni0443uni0444uni0445uni0446uni0447uni0448uni0449uni044Auni044Buni044Cuni044Duni044Euni044Funi0450uni0451uni0452uni0453uni0454uni0455uni0456uni0457uni0458uni0459uni045Auni045Buni045Cuni045Duni045Euni045Funi0460uni0461uni0462uni0463uni0464uni0465uni0466uni0467uni0468uni0469uni046Auni046Buni046Cuni046Duni046Euni046Funi0470uni0471uni0472uni0473uni0474uni0475uni0476uni0477uni0478uni0479uni047Auni047Buni047Cuni047Duni047Euni047Funi0480uni0481uni0482uni0483uni0484uni0485uni0486uni0487uni0488uni0489uni048Auni048Buni048Cuni048Duni048Euni048Funi0490uni0491uni0492uni0493uni0494uni0495uni0496uni0497uni0498uni0499uni049Auni049Buni049Cuni049Duni049Euni049Funi04A0uni04A1uni04A2uni04A3uni04A4uni04A5uni04A6uni04A7uni04A8uni04A9uni04AAuni04ABuni04ACuni04ADuni04AEuni04AFuni04B0uni04B1uni04B2uni04B3uni04B4uni04B5uni04B6uni04B7uni04B8uni04B9uni04BAuni04BBuni04BCuni04BDuni04BEuni04BFuni04C0uni04C1uni04C2uni04C3uni04C4uni04C5uni04C6uni04C7uni04C8uni04C9uni04CAuni04CBuni04CCuni04CDuni04CEuni04CFuni04D0uni04D1uni04D2uni04D3uni04D4uni04D5uni04D6uni04D7uni04D8uni04D9uni04DAuni04DBuni04DCuni04DDuni04DEuni04DFuni04E0uni04E1uni04E2uni04E3uni04E4uni04E5uni04E6uni04E7uni04E8uni04E9uni04EAuni04EBuni04ECuni04EDuni04EEuni04EFuni04F0uni04F1uni04F2uni04F3uni04F4uni04F5uni04F6uni04F7uni04F8uni04F9uni04FAuni04FBuni04FCuni04FDuni04FEuni04FFuni0500uni0501uni0502uni0503uni0504uni0505uni0506uni0507uni0508uni0509uni050Auni050Buni050Cuni050Duni050Euni050Funi0510uni0511uni0512uni0513uni0514uni0515uni0516uni0517uni0518uni0519uni051Auni051Buni051Cuni051Duni051Euni051Funi0520uni0521uni0522uni0523uni0524uni0525uni0531uni0532uni0533uni0534uni0535uni0536uni0537uni0538uni0539uni053Auni053Buni053Cuni053Duni053Euni053Funi0540uni0541uni0542uni0543uni0544uni0545uni0546uni0547uni0548uni0549uni054Auni054Buni054Cuni054Duni054Euni054Funi0550uni0551uni0552uni0553uni0554uni0555uni0556uni0559uni055Auni055Buni055Cuni055Duni055Euni055Funi0561uni0562uni0563uni0564uni0565uni0566uni0567uni0568uni0569uni056Auni056Buni056Cuni056Duni056Euni056Funi0570uni0571uni0572uni0573uni0574uni0575uni0576uni0577uni0578uni0579uni057Auni057Buni057Cuni057Duni057Euni057Funi0580uni0581uni0582uni0583uni0584uni0585uni0586uni0587uni0589uni058Auni05B0uni05B1uni05B2uni05B3uni05B4uni05B5uni05B6uni05B7uni05B8uni05B9uni05BAuni05BBuni05BCuni05BDuni05BEuni05BFuni05C0uni05C1uni05C2uni05C3uni05C6uni05C7uni05D0uni05D1uni05D2uni05D3uni05D4uni05D5uni05D6uni05D7uni05D8uni05D9uni05DAuni05DBuni05DCuni05DDuni05DEuni05DFuni05E0uni05E1uni05E2uni05E3uni05E4uni05E5uni05E6uni05E7uni05E8uni05E9uni05EAuni05F0uni05F1uni05F2uni05F3uni05F4uni0606uni0607uni0609uni060Auni060Cuni0615uni061Buni061Funi0621uni0622uni0623uni0624uni0625uni0626uni0627uni0628uni0629uni062Auni062Buni062Cuni062Duni062Euni062Funi0630uni0631uni0632uni0633uni0634uni0635uni0636uni0637uni0638uni0639uni063Auni0640uni0641uni0642uni0643uni0644uni0645uni0646uni0647uni0648uni0649uni064Auni064Buni064Cuni064Duni064Euni064Funi0650uni0651uni0652uni0653uni0654uni0655uni0657uni065Auni0660uni0661uni0662uni0663uni0664uni0665uni0666uni0667uni0668uni0669uni066Auni066Buni066Cuni066Duni066Euni066Funi0670uni0674uni0679uni067Auni067Buni067Cuni067Duni067Euni067Funi0680uni0681uni0682uni0683uni0684uni0685uni0686uni0687uni0688uni0689uni068Auni068Buni068Cuni068Duni068Euni068Funi0690uni0691uni0692uni0693uni0694uni0695uni0696uni0697uni0698uni0699uni069Auni069Buni069Cuni069Duni069Euni069Funi06A0uni06A1uni06A2uni06A3uni06A4uni06A5uni06A6uni06A7uni06A8uni06A9uni06AAuni06ABuni06ACuni06ADuni06AEuni06AFuni06B0uni06B1uni06B2uni06B3uni06B4uni06B5uni06B6uni06B7uni06B8uni06B9uni06BAuni06BBuni06BCuni06BDuni06BEuni06BFuni06C6uni06C7uni06C8uni06CBuni06CCuni06CEuni06D0uni06D5uni06F0uni06F1uni06F2uni06F3uni06F4uni06F5uni06F6uni06F7uni06F8uni06F9uni07C0uni07C1uni07C2uni07C3uni07C4uni07C5uni07C6uni07C7uni07C8uni07C9uni07CAuni07CBuni07CCuni07CDuni07CEuni07CFuni07D0uni07D1uni07D2uni07D3uni07D4uni07D5uni07D6uni07D7uni07D8uni07D9uni07DAuni07DBuni07DCuni07DDuni07DEuni07DFuni07E0uni07E1uni07E2uni07E3uni07E4uni07E5uni07E6uni07E7uni07EBuni07ECuni07EDuni07EEuni07EFuni07F0uni07F1uni07F2uni07F3uni07F4uni07F5uni07F8uni07F9uni07FAuni0E3Funi0E81uni0E82uni0E84uni0E87uni0E88uni0E8Auni0E8Duni0E94uni0E95uni0E96uni0E97uni0E99uni0E9Auni0E9Buni0E9Cuni0E9Duni0E9Euni0E9Funi0EA1uni0EA2uni0EA3uni0EA5uni0EA7uni0EAAuni0EABuni0EADuni0EAEuni0EAFuni0EB0uni0EB1uni0EB2uni0EB3uni0EB4uni0EB5uni0EB6uni0EB7uni0EB8uni0EB9uni0EBBuni0EBCuni0EBDuni0EC0uni0EC1uni0EC2uni0EC3uni0EC4uni0EC6uni0EC8uni0EC9uni0ECAuni0ECBuni0ECCuni0ECDuni0ED0uni0ED1uni0ED2uni0ED3uni0ED4uni0ED5uni0ED6uni0ED7uni0ED8uni0ED9uni0EDCuni0EDDuni10A0uni10A1uni10A2uni10A3uni10A4uni10A5uni10A6uni10A7uni10A8uni10A9uni10AAuni10ABuni10ACuni10ADuni10AEuni10AFuni10B0uni10B1uni10B2uni10B3uni10B4uni10B5uni10B6uni10B7uni10B8uni10B9uni10BAuni10BBuni10BCuni10BDuni10BEuni10BFuni10C0uni10C1uni10C2uni10C3uni10C4uni10C5uni10D0uni10D1uni10D2uni10D3uni10D4uni10D5uni10D6uni10D7uni10D8uni10D9uni10DAuni10DBuni10DCuni10DDuni10DEuni10DFuni10E0uni10E1uni10E2uni10E3uni10E4uni10E5uni10E6uni10E7uni10E8uni10E9uni10EAuni10EBuni10ECuni10EDuni10EEuni10EFuni10F0uni10F1uni10F2uni10F3uni10F4uni10F5uni10F6uni10F7uni10F8uni10F9uni10FAuni10FBuni10FCuni1401uni1402uni1403uni1404uni1405uni1406uni1407uni1409uni140Auni140Buni140Cuni140Duni140Euni140Funi1410uni1411uni1412uni1413uni1414uni1415uni1416uni1417uni1418uni1419uni141Auni141Buni141Duni141Euni141Funi1420uni1421uni1422uni1423uni1424uni1425uni1426uni1427uni1428uni1429uni142Auni142Buni142Cuni142Duni142Euni142Funi1430uni1431uni1432uni1433uni1434uni1435uni1437uni1438uni1439uni143Auni143Buni143Cuni143Duni143Euni143Funi1440uni1441uni1442uni1443uni1444uni1445uni1446uni1447uni1448uni1449uni144Auni144Cuni144Duni144Euni144Funi1450uni1451uni1452uni1454uni1455uni1456uni1457uni1458uni1459uni145Auni145Buni145Cuni145Duni145Euni145Funi1460uni1461uni1462uni1463uni1464uni1465uni1466uni1467uni1468uni1469uni146Auni146Buni146Cuni146Duni146Euni146Funi1470uni1471uni1472uni1473uni1474uni1475uni1476uni1477uni1478uni1479uni147Auni147Buni147Cuni147Duni147Euni147Funi1480uni1481uni1482uni1483uni1484uni1485uni1486uni1487uni1488uni1489uni148Auni148Buni148Cuni148Duni148Euni148Funi1490uni1491uni1492uni1493uni1494uni1495uni1496uni1497uni1498uni1499uni149Auni149Buni149Cuni149Duni149Euni149Funi14A0uni14A1uni14A2uni14A3uni14A4uni14A5uni14A6uni14A7uni14A8uni14A9uni14AAuni14ABuni14ACuni14ADuni14AEuni14AFuni14B0uni14B1uni14B2uni14B3uni14B4uni14B5uni14B6uni14B7uni14B8uni14B9uni14BAuni14BBuni14BCuni14BDuni14C0uni14C1uni14C2uni14C3uni14C4uni14C5uni14C6uni14C7uni14C8uni14C9uni14CAuni14CBuni14CCuni14CDuni14CEuni14CFuni14D0uni14D1uni14D2uni14D3uni14D4uni14D5uni14D6uni14D7uni14D8uni14D9uni14DAuni14DBuni14DCuni14DDuni14DEuni14DFuni14E0uni14E1uni14E2uni14E3uni14E4uni14E5uni14E6uni14E7uni14E8uni14E9uni14EAuni14ECuni14EDuni14EEuni14EFuni14F0uni14F1uni14F2uni14F3uni14F4uni14F5uni14F6uni14F7uni14F8uni14F9uni14FAuni14FBuni14FCuni14FDuni14FEuni14FFuni1500uni1501uni1502uni1503uni1504uni1505uni1506uni1507uni1510uni1511uni1512uni1513uni1514uni1515uni1516uni1517uni1518uni1519uni151Auni151Buni151Cuni151Duni151Euni151Funi1520uni1521uni1522uni1523uni1524uni1525uni1526uni1527uni1528uni1529uni152Auni152Buni152Cuni152Duni152Euni152Funi1530uni1531uni1532uni1533uni1534uni1535uni1536uni1537uni1538uni1539uni153Auni153Buni153Cuni153Duni153Euni1540uni1541uni1542uni1543uni1544uni1545uni1546uni1547uni1548uni1549uni154Auni154Buni154Cuni154Duni154Euni154Funi1550uni1552uni1553uni1554uni1555uni1556uni1557uni1558uni1559uni155Auni155Buni155Cuni155Duni155Euni155Funi1560uni1561uni1562uni1563uni1564uni1565uni1566uni1567uni1568uni1569uni156Auni1574uni1575uni1576uni1577uni1578uni1579uni157Auni157Buni157Cuni157Duni157Euni157Funi1580uni1581uni1582uni1583uni1584uni1585uni158Auni158Buni158Cuni158Duni158Euni158Funi1590uni1591uni1592uni1593uni1594uni1595uni1596uni15A0uni15A1uni15A2uni15A3uni15A4uni15A5uni15A6uni15A7uni15A8uni15A9uni15AAuni15ABuni15ACuni15ADuni15AEuni15AFuni15DEuni15E1uni1646uni1647uni166Euni166Funi1670uni1671uni1672uni1673uni1674uni1675uni1676uni1680uni1681uni1682uni1683uni1684uni1685uni1686uni1687uni1688uni1689uni168Auni168Buni168Cuni168Duni168Euni168Funi1690uni1691uni1692uni1693uni1694uni1695uni1696uni1697uni1698uni1699uni169Auni169Buni169Cuni1D00uni1D01uni1D02uni1D03uni1D04uni1D05uni1D06uni1D07uni1D08uni1D09uni1D0Auni1D0Buni1D0Cuni1D0Duni1D0Euni1D0Funi1D10uni1D11uni1D12uni1D13uni1D14uni1D16uni1D17uni1D18uni1D19uni1D1Auni1D1Buni1D1Cuni1D1Duni1D1Euni1D1Funi1D20uni1D21uni1D22uni1D23uni1D26uni1D27uni1D28uni1D29uni1D2Auni1D2Buni1D2Cuni1D2Duni1D2Euni1D30uni1D31uni1D32uni1D33uni1D34uni1D35uni1D36uni1D37uni1D38uni1D39uni1D3Auni1D3Buni1D3Cuni1D3Duni1D3Euni1D3Funi1D40uni1D41uni1D42uni1D43uni1D44uni1D45uni1D46uni1D47uni1D48uni1D49uni1D4Auni1D4Buni1D4Cuni1D4Duni1D4Euni1D4Funi1D50uni1D51uni1D52uni1D53uni1D54uni1D55uni1D56uni1D57uni1D58uni1D59uni1D5Auni1D5Buni1D5Duni1D5Euni1D5Funi1D60uni1D61uni1D62uni1D63uni1D64uni1D65uni1D66uni1D67uni1D68uni1D69uni1D6Auni1D77uni1D78uni1D7Buni1D7Duni1D85uni1D9Buni1D9Cuni1D9Duni1D9Euni1D9Funi1DA0uni1DA1uni1DA2uni1DA3uni1DA4uni1DA5uni1DA6uni1DA7uni1DA8uni1DA9uni1DAAuni1DABuni1DACuni1DADuni1DAEuni1DAFuni1DB0uni1DB1uni1DB2uni1DB3uni1DB4uni1DB5uni1DB6uni1DB7uni1DB8uni1DB9uni1DBAuni1DBBuni1DBCuni1DBDuni1DBEuni1DBFuni1DC4uni1DC5uni1DC6uni1DC7uni1DC8uni1DC9uni1E00uni1E01uni1E02uni1E03uni1E04uni1E05uni1E06uni1E07uni1E08uni1E09uni1E0Auni1E0Buni1E0Cuni1E0Duni1E0Euni1E0Funi1E10uni1E11uni1E12uni1E13uni1E14uni1E15uni1E16uni1E17uni1E18uni1E19uni1E1Auni1E1Buni1E1Cuni1E1Duni1E1Euni1E1Funi1E20uni1E21uni1E22uni1E23uni1E24uni1E25uni1E26uni1E27uni1E28uni1E29uni1E2Auni1E2Buni1E2Cuni1E2Duni1E2Euni1E2Funi1E30uni1E31uni1E32uni1E33uni1E34uni1E35uni1E36uni1E37uni1E38uni1E39uni1E3Auni1E3Buni1E3Cuni1E3Duni1E3Euni1E3Funi1E40uni1E41uni1E42uni1E43uni1E44uni1E45uni1E46uni1E47uni1E48uni1E49uni1E4Auni1E4Buni1E4Cuni1E4Duni1E4Euni1E4Funi1E50uni1E51uni1E52uni1E53uni1E54uni1E55uni1E56uni1E57uni1E58uni1E59uni1E5Auni1E5Buni1E5Cuni1E5Duni1E5Euni1E5Funi1E60uni1E61uni1E62uni1E63uni1E64uni1E65uni1E66uni1E67uni1E68uni1E69uni1E6Auni1E6Buni1E6Cuni1E6Duni1E6Euni1E6Funi1E70uni1E71uni1E72uni1E73uni1E74uni1E75uni1E76uni1E77uni1E78uni1E79uni1E7Auni1E7Buni1E7Cuni1E7Duni1E7Euni1E7FWgravewgraveWacutewacute Wdieresis wdieresisuni1E86uni1E87uni1E88uni1E89uni1E8Auni1E8Buni1E8Cuni1E8Duni1E8Euni1E8Funi1E90uni1E91uni1E92uni1E93uni1E94uni1E95uni1E96uni1E97uni1E98uni1E99uni1E9Auni1E9Buni1E9Cuni1E9Duni1E9Euni1E9Funi1EA0uni1EA1uni1EA2uni1EA3uni1EA4uni1EA5uni1EA6uni1EA7uni1EA8uni1EA9uni1EAAuni1EABuni1EACuni1EADuni1EAEuni1EAFuni1EB0uni1EB1uni1EB2uni1EB3uni1EB4uni1EB5uni1EB6uni1EB7uni1EB8uni1EB9uni1EBAuni1EBBuni1EBCuni1EBDuni1EBEuni1EBFuni1EC0uni1EC1uni1EC2uni1EC3uni1EC4uni1EC5uni1EC6uni1EC7uni1EC8uni1EC9uni1ECAuni1ECBuni1ECCuni1ECDuni1ECEuni1ECFuni1ED0uni1ED1uni1ED2uni1ED3uni1ED4uni1ED5uni1ED6uni1ED7uni1ED8uni1ED9uni1EDAuni1EDBuni1EDCuni1EDDuni1EDEuni1EDFuni1EE0uni1EE1uni1EE2uni1EE3uni1EE4uni1EE5uni1EE6uni1EE7uni1EE8uni1EE9uni1EEAuni1EEBuni1EECuni1EEDuni1EEEuni1EEFuni1EF0uni1EF1Ygraveygraveuni1EF4uni1EF5uni1EF6uni1EF7uni1EF8uni1EF9uni1EFAuni1EFBuni1F00uni1F01uni1F02uni1F03uni1F04uni1F05uni1F06uni1F07uni1F08uni1F09uni1F0Auni1F0Buni1F0Cuni1F0Duni1F0Euni1F0Funi1F10uni1F11uni1F12uni1F13uni1F14uni1F15uni1F18uni1F19uni1F1Auni1F1Buni1F1Cuni1F1Duni1F20uni1F21uni1F22uni1F23uni1F24uni1F25uni1F26uni1F27uni1F28uni1F29uni1F2Auni1F2Buni1F2Cuni1F2Duni1F2Euni1F2Funi1F30uni1F31uni1F32uni1F33uni1F34uni1F35uni1F36uni1F37uni1F38uni1F39uni1F3Auni1F3Buni1F3Cuni1F3Duni1F3Euni1F3Funi1F40uni1F41uni1F42uni1F43uni1F44uni1F45uni1F48uni1F49uni1F4Auni1F4Buni1F4Cuni1F4Duni1F50uni1F51uni1F52uni1F53uni1F54uni1F55uni1F56uni1F57uni1F59uni1F5Buni1F5Duni1F5Funi1F60uni1F61uni1F62uni1F63uni1F64uni1F65uni1F66uni1F67uni1F68uni1F69uni1F6Auni1F6Buni1F6Cuni1F6Duni1F6Euni1F6Funi1F70uni1F71uni1F72uni1F73uni1F74uni1F75uni1F76uni1F77uni1F78uni1F79uni1F7Auni1F7Buni1F7Cuni1F7Duni1F80uni1F81uni1F82uni1F83uni1F84uni1F85uni1F86uni1F87uni1F88uni1F89uni1F8Auni1F8Buni1F8Cuni1F8Duni1F8Euni1F8Funi1F90uni1F91uni1F92uni1F93uni1F94uni1F95uni1F96uni1F97uni1F98uni1F99uni1F9Auni1F9Buni1F9Cuni1F9Duni1F9Euni1F9Funi1FA0uni1FA1uni1FA2uni1FA3uni1FA4uni1FA5uni1FA6uni1FA7uni1FA8uni1FA9uni1FAAuni1FABuni1FACuni1FADuni1FAEuni1FAFuni1FB0uni1FB1uni1FB2uni1FB3uni1FB4uni1FB6uni1FB7uni1FB8uni1FB9uni1FBAuni1FBBuni1FBCuni1FBDuni1FBEuni1FBFuni1FC0uni1FC1uni1FC2uni1FC3uni1FC4uni1FC6uni1FC7uni1FC8uni1FC9uni1FCAuni1FCBuni1FCCuni1FCDuni1FCEuni1FCFuni1FD0uni1FD1uni1FD2uni1FD3uni1FD6uni1FD7uni1FD8uni1FD9uni1FDAuni1FDBuni1FDDuni1FDEuni1FDFuni1FE0uni1FE1uni1FE2uni1FE3uni1FE4uni1FE5uni1FE6uni1FE7uni1FE8uni1FE9uni1FEAuni1FEBuni1FECuni1FEDuni1FEEuni1FEFuni1FF2uni1FF3uni1FF4uni1FF6uni1FF7uni1FF8uni1FF9uni1FFAuni1FFBuni1FFCuni1FFDuni1FFEuni2000uni2001uni2002uni2003uni2004uni2005uni2006uni2007uni2008uni2009uni200Auni200Buni200Cuni200Duni200Euni200Funi2010uni2011 figuredashuni2015uni2016 underscoredbl quotereverseduni201Funi2023onedotenleadertwodotenleaderuni2027uni2028uni2029uni202Auni202Buni202Cuni202Duni202Euni202Funi2031minuteseconduni2034uni2035uni2036uni2037uni2038uni203B exclamdbluni203Duni203Euni203Funi2040uni2041uni2042uni2043uni2045uni2046uni2047uni2048uni2049uni204Auni204Buni204Cuni204Duni204Euni204Funi2050uni2051uni2052uni2053uni2054uni2055uni2056uni2057uni2058uni2059uni205Auni205Buni205Cuni205Duni205Euni205Funi2060uni2061uni2062uni2063uni2064uni206Auni206Buni206Cuni206Duni206Euni206Funi2070uni2071uni2074uni2075uni2076uni2077uni2078uni2079uni207Auni207Buni207Cuni207Duni207Euni207Funi2080uni2081uni2082uni2083uni2084uni2085uni2086uni2087uni2088uni2089uni208Auni208Buni208Cuni208Duni208Euni2090uni2091uni2092uni2093uni2094uni2095uni2096uni2097uni2098uni2099uni209Auni209Buni209Cuni20A0 colonmonetaryuni20A2lirauni20A5uni20A6pesetauni20A8uni20A9uni20AAdongEurouni20ADuni20AEuni20AFuni20B0uni20B1uni20B2uni20B3uni20B4uni20B5uni20B8uni20B9uni20BAuni20BDuni20D0uni20D1uni20D6uni20D7uni20DBuni20DCuni20E1uni2100uni2101uni2102uni2103uni2104uni2105uni2106uni2107uni2108uni2109uni210Buni210Cuni210Duni210Euni210Funi2110Ifrakturuni2112uni2113uni2114uni2115uni2116uni2117 weierstrassuni2119uni211Auni211BRfrakturuni211D prescriptionuni211Funi2120uni2121uni2123uni2124uni2125uni2126uni2127uni2128uni2129uni212Auni212Buni212Cuni212D estimateduni212Funi2130uni2131uni2132uni2133uni2134alephuni2136uni2137uni2138uni2139uni213Auni213Buni213Cuni213Duni213Euni213Funi2140uni2141uni2142uni2143uni2144uni2145uni2146uni2147uni2148uni2149uni214Buni214Euni2150uni2151uni2152onethird twothirdsuni2155uni2156uni2157uni2158uni2159uni215A oneeighth threeeighths fiveeighths seveneighthsuni215Funi2160uni2161uni2162uni2163uni2164uni2165uni2166uni2167uni2168uni2169uni216Auni216Buni216Cuni216Duni216Euni216Funi2170uni2171uni2172uni2173uni2174uni2175uni2176uni2177uni2178uni2179uni217Auni217Buni217Cuni217Duni217Euni217Funi2180uni2181uni2182uni2183uni2184uni2185uni2189 arrowleftarrowup arrowright arrowdown arrowboth arrowupdnuni2196uni2197uni2198uni2199uni219Auni219Buni219Cuni219Duni219Euni219Funi21A0uni21A1uni21A2uni21A3uni21A4uni21A5uni21A6uni21A7 arrowupdnbseuni21A9uni21AAuni21ABuni21ACuni21ADuni21AEuni21AFuni21B0uni21B1uni21B2uni21B3uni21B4carriagereturnuni21B6uni21B7uni21B8uni21B9uni21BAuni21BBuni21BCuni21BDuni21BEuni21BFuni21C0uni21C1uni21C2uni21C3uni21C4uni21C5uni21C6uni21C7uni21C8uni21C9uni21CAuni21CBuni21CCuni21CDuni21CEuni21CF arrowdblleft arrowdblup arrowdblright arrowdbldown arrowdblbothuni21D5uni21D6uni21D7uni21D8uni21D9uni21DAuni21DBuni21DCuni21DDuni21DEuni21DFuni21E0uni21E1uni21E2uni21E3uni21E4uni21E5uni21E6uni21E7uni21E8uni21E9uni21EAuni21EBuni21ECuni21EDuni21EEuni21EFuni21F0uni21F1uni21F2uni21F3uni21F4uni21F5uni21F6uni21F7uni21F8uni21F9uni21FAuni21FBuni21FCuni21FDuni21FEuni21FF universaluni2201 existentialuni2204emptysetgradientelement notelementuni220Asuchthatuni220Cuni220Duni220Euni2210uni2213uni2214uni2215uni2216 asteriskmathuni2218uni2219uni221Buni221C proportional orthogonalangleuni2221uni2222uni2223uni2224uni2225uni2226 logicaland logicalor intersectionunionuni222Cuni222Duni222Euni222Funi2230uni2231uni2232uni2233 thereforeuni2235uni2236uni2237uni2238uni2239uni223Auni223Bsimilaruni223Duni223Euni223Funi2240uni2241uni2242uni2243uni2244 congruentuni2246uni2247uni2249uni224Auni224Buni224Cuni224Duni224Euni224Funi2250uni2251uni2252uni2253uni2254uni2255uni2256uni2257uni2258uni2259uni225Auni225Buni225Cuni225Duni225Euni225F equivalenceuni2262uni2263uni2266uni2267uni2268uni2269uni226Auni226Buni226Cuni226Duni226Euni226Funi2270uni2271uni2272uni2273uni2274uni2275uni2276uni2277uni2278uni2279uni227Auni227Buni227Cuni227Duni227Euni227Funi2280uni2281 propersubsetpropersuperset notsubsetuni2285 reflexsubsetreflexsupersetuni2288uni2289uni228Auni228Buni228Cuni228Duni228Euni228Funi2290uni2291uni2292uni2293uni2294 circleplusuni2296circlemultiplyuni2298uni2299uni229Auni229Buni229Cuni229Duni229Euni229Funi22A0uni22A1uni22A2uni22A3uni22A4 perpendicularuni22A6uni22A7uni22A8uni22A9uni22AAuni22ABuni22ACuni22ADuni22AEuni22AFuni22B0uni22B1uni22B2uni22B3uni22B4uni22B5uni22B6uni22B7uni22B8uni22B9uni22BAuni22BBuni22BCuni22BDuni22BEuni22BFuni22C0uni22C1uni22C2uni22C3uni22C4dotmathuni22C6uni22C7uni22C8uni22C9uni22CAuni22CBuni22CCuni22CDuni22CEuni22CFuni22D0uni22D1uni22D2uni22D3uni22D4uni22D5uni22D6uni22D7uni22D8uni22D9uni22DAuni22DBuni22DCuni22DDuni22DEuni22DFuni22E0uni22E1uni22E2uni22E3uni22E4uni22E5uni22E6uni22E7uni22E8uni22E9uni22EAuni22EBuni22ECuni22EDuni22EEuni22EFuni22F0uni22F1uni22F2uni22F3uni22F4uni22F5uni22F6uni22F7uni22F8uni22F9uni22FAuni22FBuni22FCuni22FDuni22FEuni22FFuni2300uni2301houseuni2303uni2304uni2305uni2306uni2307uni2308uni2309uni230Auni230Buni230Cuni230Duni230Euni230F revlogicalnotuni2311uni2318uni2319uni231Cuni231Duni231Euni231F integraltp integralbtuni2324uni2325uni2326uni2327uni2328uni232Buni232Cuni2373uni2374uni2375uni237Auni237Duni2387uni2394uni239Buni239Cuni239Duni239Euni239Funi23A0uni23A1uni23A2uni23A3uni23A4uni23A5uni23A6uni23A7uni23A8uni23A9uni23AAuni23ABuni23ACuni23ADuni23AEuni23CEuni23CFuni23E3uni23E5uni23E8uni2422uni2423uni2460uni2461uni2462uni2463uni2464uni2465uni2466uni2467uni2468uni2469SF100000uni2501SF110000uni2503uni2504uni2505uni2506uni2507uni2508uni2509uni250Auni250BSF010000uni250Duni250Euni250FSF030000uni2511uni2512uni2513SF020000uni2515uni2516uni2517SF040000uni2519uni251Auni251BSF080000uni251Duni251Euni251Funi2520uni2521uni2522uni2523SF090000uni2525uni2526uni2527uni2528uni2529uni252Auni252BSF060000uni252Duni252Euni252Funi2530uni2531uni2532uni2533SF070000uni2535uni2536uni2537uni2538uni2539uni253Auni253BSF050000uni253Duni253Euni253Funi2540uni2541uni2542uni2543uni2544uni2545uni2546uni2547uni2548uni2549uni254Auni254Buni254Cuni254Duni254Euni254FSF430000SF240000SF510000SF520000SF390000SF220000SF210000SF250000SF500000SF490000SF380000SF280000SF270000SF260000SF360000SF370000SF420000SF190000SF200000SF230000SF470000SF480000SF410000SF450000SF460000SF400000SF540000SF530000SF440000uni256Duni256Euni256Funi2570uni2571uni2572uni2573uni2574uni2575uni2576uni2577uni2578uni2579uni257Auni257Buni257Cuni257Duni257Euni257Fupblockuni2581uni2582uni2583dnblockuni2585uni2586uni2587blockuni2589uni258Auni258Blfblockuni258Duni258Euni258Frtblockltshadeshadedkshadeuni2594uni2595uni2596uni2597uni2598uni2599uni259Auni259Buni259Cuni259Duni259Euni259F filledboxH22073uni25A2uni25A3uni25A4uni25A5uni25A6uni25A7uni25A8uni25A9H18543H18551 filledrectuni25ADuni25AEuni25AFuni25B0uni25B1triagupuni25B3uni25B4uni25B5uni25B6uni25B7uni25B8uni25B9triagrtuni25BBtriagdnuni25BDuni25BEuni25BFuni25C0uni25C1uni25C2uni25C3triaglfuni25C5uni25C6uni25C7uni25C8uni25C9circleuni25CCuni25CDuni25CEH18533uni25D0uni25D1uni25D2uni25D3uni25D4uni25D5uni25D6uni25D7 invbullet invcircleuni25DAuni25DBuni25DCuni25DDuni25DEuni25DFuni25E0uni25E1uni25E2uni25E3uni25E4uni25E5 openbulletuni25E7uni25E8uni25E9uni25EAuni25EBuni25ECuni25EDuni25EEuni25EFuni25F0uni25F1uni25F2uni25F3uni25F4uni25F5uni25F6uni25F7uni25F8uni25F9uni25FAuni25FBuni25FCuni25FDuni25FEuni25FFuni2600uni2601uni2602uni2603uni2604uni2605uni2606uni2607uni2608uni2609uni260Auni260Buni260Cuni260Duni260Euni260Funi2610uni2611uni2612uni2613uni2614uni2615uni2616uni2617uni2618uni2619uni261Auni261Buni261Cuni261Duni261Euni261Funi2620uni2621uni2622uni2623uni2624uni2625uni2626uni2627uni2628uni2629uni262Auni262Buni262Cuni262Duni262Euni262Funi2630uni2631uni2632uni2633uni2634uni2635uni2636uni2637uni2638uni2639 smileface invsmilefacesununi263Duni263Euni263Ffemaleuni2641maleuni2643uni2644uni2645uni2646uni2647uni2648uni2649uni264Auni264Buni264Cuni264Duni264Euni264Funi2650uni2651uni2652uni2653uni2654uni2655uni2656uni2657uni2658uni2659uni265Auni265Buni265Cuni265Duni265Euni265Fspadeuni2661uni2662clubuni2664heartdiamonduni2667uni2668uni2669 musicalnotemusicalnotedbluni266Cuni266Duni266Euni266Funi2670uni2671uni2672uni2673uni2674uni2675uni2676uni2677uni2678uni2679uni267Auni267Buni267Cuni267Duni267Euni267Funi2680uni2681uni2682uni2683uni2684uni2685uni2686uni2687uni2688uni2689uni268Auni268Buni268Cuni268Duni268Euni268Funi2690uni2691uni2692uni2693uni2694uni2695uni2696uni2697uni2698uni2699uni269Auni269Buni269Cuni269Euni269Funi26A0uni26A1uni26A2uni26A3uni26A4uni26A5uni26A6uni26A7uni26A8uni26A9uni26AAuni26ABuni26ACuni26ADuni26AEuni26AFuni26B0uni26B1uni26B2uni26B3uni26B4uni26B5uni26B6uni26B7uni26B8uni26C0uni26C1uni26C2uni26C3uni26E2uni2701uni2702uni2703uni2704uni2706uni2707uni2708uni2709uni270Cuni270Duni270Euni270Funi2710uni2711uni2712uni2713uni2714uni2715uni2716uni2717uni2718uni2719uni271Auni271Buni271Cuni271Duni271Euni271Funi2720uni2721uni2722uni2723uni2724uni2725uni2726uni2727uni2729uni272Auni272Buni272Cuni272Duni272Euni272Funi2730uni2731uni2732uni2733uni2734uni2735uni2736uni2737uni2738uni2739uni273Auni273Buni273Cuni273Duni273Euni273Funi2740uni2741uni2742uni2743uni2744uni2745uni2746uni2747uni2748uni2749uni274Auni274Buni274Duni274Funi2750uni2751uni2752uni2756uni2758uni2759uni275Auni275Buni275Cuni275Duni275Euni2761uni2762uni2763uni2764uni2765uni2766uni2767uni2768uni2769uni276Auni276Buni276Cuni276Duni276Euni276Funi2770uni2771uni2772uni2773uni2774uni2775uni2776uni2777uni2778uni2779uni277Auni277Buni277Cuni277Duni277Euni277Funi2780uni2781uni2782uni2783uni2784uni2785uni2786uni2787uni2788uni2789uni278Auni278Buni278Cuni278Duni278Euni278Funi2790uni2791uni2792uni2793uni2794uni2798uni2799uni279Auni279Buni279Cuni279Duni279Euni279Funi27A0uni27A1uni27A2uni27A3uni27A4uni27A5uni27A6uni27A7uni27A8uni27A9uni27AAuni27ABuni27ACuni27ADuni27AEuni27AFuni27B1uni27B2uni27B3uni27B4uni27B5uni27B6uni27B7uni27B8uni27B9uni27BAuni27BBuni27BCuni27BDuni27BEuni27C5uni27C6uni27E0uni27E6uni27E7uni27E8uni27E9uni27EAuni27EBuni27F0uni27F1uni27F2uni27F3uni27F4uni27F5uni27F6uni27F7uni27F8uni27F9uni27FAuni27FBuni27FCuni27FDuni27FEuni27FFuni2800uni2801uni2802uni2803uni2804uni2805uni2806uni2807uni2808uni2809uni280Auni280Buni280Cuni280Duni280Euni280Funi2810uni2811uni2812uni2813uni2814uni2815uni2816uni2817uni2818uni2819uni281Auni281Buni281Cuni281Duni281Euni281Funi2820uni2821uni2822uni2823uni2824uni2825uni2826uni2827uni2828uni2829uni282Auni282Buni282Cuni282Duni282Euni282Funi2830uni2831uni2832uni2833uni2834uni2835uni2836uni2837uni2838uni2839uni283Auni283Buni283Cuni283Duni283Euni283Funi2840uni2841uni2842uni2843uni2844uni2845uni2846uni2847uni2848uni2849uni284Auni284Buni284Cuni284Duni284Euni284Funi2850uni2851uni2852uni2853uni2854uni2855uni2856uni2857uni2858uni2859uni285Auni285Buni285Cuni285Duni285Euni285Funi2860uni2861uni2862uni2863uni2864uni2865uni2866uni2867uni2868uni2869uni286Auni286Buni286Cuni286Duni286Euni286Funi2870uni2871uni2872uni2873uni2874uni2875uni2876uni2877uni2878uni2879uni287Auni287Buni287Cuni287Duni287Euni287Funi2880uni2881uni2882uni2883uni2884uni2885uni2886uni2887uni2888uni2889uni288Auni288Buni288Cuni288Duni288Euni288Funi2890uni2891uni2892uni2893uni2894uni2895uni2896uni2897uni2898uni2899uni289Auni289Buni289Cuni289Duni289Euni289Funi28A0uni28A1uni28A2uni28A3uni28A4uni28A5uni28A6uni28A7uni28A8uni28A9uni28AAuni28ABuni28ACuni28ADuni28AEuni28AFuni28B0uni28B1uni28B2uni28B3uni28B4uni28B5uni28B6uni28B7uni28B8uni28B9uni28BAuni28BBuni28BCuni28BDuni28BEuni28BFuni28C0uni28C1uni28C2uni28C3uni28C4uni28C5uni28C6uni28C7uni28C8uni28C9uni28CAuni28CBuni28CCuni28CDuni28CEuni28CFuni28D0uni28D1uni28D2uni28D3uni28D4uni28D5uni28D6uni28D7uni28D8uni28D9uni28DAuni28DBuni28DCuni28DDuni28DEuni28DFuni28E0uni28E1uni28E2uni28E3uni28E4uni28E5uni28E6uni28E7uni28E8uni28E9uni28EAuni28EBuni28ECuni28EDuni28EEuni28EFuni28F0uni28F1uni28F2uni28F3uni28F4uni28F5uni28F6uni28F7uni28F8uni28F9uni28FAuni28FBuni28FCuni28FDuni28FEuni28FFuni2906uni2907uni290Auni290Buni2940uni2941uni2983uni2984uni29CEuni29CFuni29D0uni29D1uni29D2uni29D3uni29D4uni29D5uni29EBuni29FAuni29FBuni2A00uni2A01uni2A02uni2A0Cuni2A0Duni2A0Euni2A0Funi2A10uni2A11uni2A12uni2A13uni2A14uni2A15uni2A16uni2A17uni2A18uni2A19uni2A1Auni2A1Buni2A1Cuni2A2Funi2A6Auni2A6Buni2A7Duni2A7Euni2A7Funi2A80uni2A81uni2A82uni2A83uni2A84uni2A85uni2A86uni2A87uni2A88uni2A89uni2A8Auni2A8Buni2A8Cuni2A8Duni2A8Euni2A8Funi2A90uni2A91uni2A92uni2A93uni2A94uni2A95uni2A96uni2A97uni2A98uni2A99uni2A9Auni2A9Buni2A9Cuni2A9Duni2A9Euni2A9Funi2AA0uni2AAEuni2AAFuni2AB0uni2AB1uni2AB2uni2AB3uni2AB4uni2AB5uni2AB6uni2AB7uni2AB8uni2AB9uni2ABAuni2AF9uni2AFAuni2B00uni2B01uni2B02uni2B03uni2B04uni2B05uni2B06uni2B07uni2B08uni2B09uni2B0Auni2B0Buni2B0Cuni2B0Duni2B0Euni2B0Funi2B10uni2B11uni2B12uni2B13uni2B14uni2B15uni2B16uni2B17uni2B18uni2B19uni2B1Auni2B1Funi2B20uni2B21uni2B22uni2B23uni2B24uni2B53uni2B54uni2C60uni2C61uni2C62uni2C63uni2C64uni2C65uni2C66uni2C67uni2C68uni2C69uni2C6Auni2C6Buni2C6Cuni2C6Duni2C6Euni2C6Funi2C70uni2C71uni2C72uni2C73uni2C74uni2C75uni2C76uni2C77uni2C79uni2C7Auni2C7Buni2C7Cuni2C7Duni2C7Euni2C7Funi2D00uni2D01uni2D02uni2D03uni2D04uni2D05uni2D06uni2D07uni2D08uni2D09uni2D0Auni2D0Buni2D0Cuni2D0Duni2D0Euni2D0Funi2D10uni2D11uni2D12uni2D13uni2D14uni2D15uni2D16uni2D17uni2D18uni2D19uni2D1Auni2D1Buni2D1Cuni2D1Duni2D1Euni2D1Funi2D20uni2D21uni2D22uni2D23uni2D24uni2D25uni2D30uni2D31uni2D32uni2D33uni2D34uni2D35uni2D36uni2D37uni2D38uni2D39uni2D3Auni2D3Buni2D3Cuni2D3Duni2D3Euni2D3Funi2D40uni2D41uni2D42uni2D43uni2D44uni2D45uni2D46uni2D47uni2D48uni2D49uni2D4Auni2D4Buni2D4Cuni2D4Duni2D4Euni2D4Funi2D50uni2D51uni2D52uni2D53uni2D54uni2D55uni2D56uni2D57uni2D58uni2D59uni2D5Auni2D5Buni2D5Cuni2D5Duni2D5Euni2D5Funi2D60uni2D61uni2D62uni2D63uni2D64uni2D65uni2D6Funi2E18uni2E1Funi2E22uni2E23uni2E24uni2E25uni2E2Euni4DC0uni4DC1uni4DC2uni4DC3uni4DC4uni4DC5uni4DC6uni4DC7uni4DC8uni4DC9uni4DCAuni4DCBuni4DCCuni4DCDuni4DCEuni4DCFuni4DD0uni4DD1uni4DD2uni4DD3uni4DD4uni4DD5uni4DD6uni4DD7uni4DD8uni4DD9uni4DDAuni4DDBuni4DDCuni4DDDuni4DDEuni4DDFuni4DE0uni4DE1uni4DE2uni4DE3uni4DE4uni4DE5uni4DE6uni4DE7uni4DE8uni4DE9uni4DEAuni4DEBuni4DECuni4DEDuni4DEEuni4DEFuni4DF0uni4DF1uni4DF2uni4DF3uni4DF4uni4DF5uni4DF6uni4DF7uni4DF8uni4DF9uni4DFAuni4DFBuni4DFCuni4DFDuni4DFEuni4DFFuniA4D0uniA4D1uniA4D2uniA4D3uniA4D4uniA4D5uniA4D6uniA4D7uniA4D8uniA4D9uniA4DAuniA4DBuniA4DCuniA4DDuniA4DEuniA4DFuniA4E0uniA4E1uniA4E2uniA4E3uniA4E4uniA4E5uniA4E6uniA4E7uniA4E8uniA4E9uniA4EAuniA4EBuniA4ECuniA4EDuniA4EEuniA4EFuniA4F0uniA4F1uniA4F2uniA4F3uniA4F4uniA4F5uniA4F6uniA4F7uniA4F8uniA4F9uniA4FAuniA4FBuniA4FCuniA4FDuniA4FEuniA4FFuniA644uniA645uniA646uniA647uniA64CuniA64DuniA650uniA651uniA654uniA655uniA656uniA657uniA662uniA663uniA664uniA665uniA666uniA667uniA668uniA669uniA66AuniA66BuniA66CuniA66DuniA66EuniA68AuniA68BuniA68CuniA68DuniA694uniA695uniA698uniA699uniA708uniA709uniA70AuniA70BuniA70CuniA70DuniA70EuniA70FuniA710uniA711uniA712uniA713uniA714uniA715uniA716uniA71BuniA71CuniA71DuniA71EuniA71FuniA722uniA723uniA724uniA725uniA726uniA727uniA728uniA729uniA72AuniA72BuniA730uniA731uniA732uniA733uniA734uniA735uniA736uniA737uniA738uniA739uniA73AuniA73BuniA73CuniA73DuniA73EuniA73FuniA740uniA741uniA746uniA747uniA748uniA749uniA74AuniA74BuniA74EuniA74FuniA750uniA751uniA752uniA753uniA756uniA757uniA764uniA765uniA766uniA767uniA780uniA781uniA782uniA783uniA789uniA78AuniA78BuniA78CuniA78DuniA78EuniA790uniA791uniA7A0uniA7A1uniA7A2uniA7A3uniA7A4uniA7A5uniA7A6uniA7A7uniA7A8uniA7A9uniA7AAuniA7F8uniA7F9uniA7FAuniA7FBuniA7FCuniA7FDuniA7FEuniA7FF uni02E5.5 uni02E6.5 uni02E7.5 uni02E8.5 uni02E9.5 uni02E5.4 uni02E6.4 uni02E7.4 uni02E8.4 uni02E9.4 uni02E5.3 uni02E6.3 uni02E7.3 uni02E8.3 uni02E9.3 uni02E5.2 uni02E6.2 uni02E7.2 uni02E8.2 uni02E9.2 uni02E5.1 uni02E6.1 uni02E7.1 uni02E8.1 uni02E9.1stemuniF000uniF001uniF002uniF003uniF400uniF401uniF402uniF403uniF404uniF405uniF406uniF407uniF408uniF409uniF40AuniF40BuniF40CuniF40DuniF40EuniF40FuniF410uniF411uniF412uniF413uniF414uniF415uniF416uniF417uniF418uniF419uniF41AuniF41BuniF41CuniF41DuniF41EuniF41FuniF420uniF421uniF422uniF423uniF424uniF425uniF426uniF428uniF429uniF42AuniF42BuniF42CuniF42DuniF42EuniF42FuniF430uniF431uniF432uniF433uniF434uniF435uniF436uniF437uniF438uniF439uniF43AuniF43BuniF43CuniF43DuniF43EuniF43FuniF440uniF441uniF6C5uniFB00uniFB03uniFB04uniFB05uniFB06uniFB13uniFB14uniFB15uniFB16uniFB17uniFB1DuniFB1EuniFB1FuniFB20uniFB21uniFB22uniFB23uniFB24uniFB25uniFB26uniFB27uniFB28uniFB29uniFB2AuniFB2BuniFB2CuniFB2DuniFB2EuniFB2FuniFB30uniFB31uniFB32uniFB33uniFB34uniFB35uniFB36uniFB38uniFB39uniFB3AuniFB3BuniFB3CuniFB3EuniFB40uniFB41uniFB43uniFB44uniFB46uniFB47uniFB48uniFB49uniFB4AuniFB4BuniFB4CuniFB4DuniFB4EuniFB4FuniFB52uniFB53uniFB54uniFB55uniFB56uniFB57uniFB58uniFB59uniFB5AuniFB5BuniFB5CuniFB5DuniFB5EuniFB5FuniFB60uniFB61uniFB62uniFB63uniFB64uniFB65uniFB66uniFB67uniFB68uniFB69uniFB6AuniFB6BuniFB6CuniFB6DuniFB6EuniFB6FuniFB70uniFB71uniFB72uniFB73uniFB74uniFB75uniFB76uniFB77uniFB78uniFB79uniFB7AuniFB7BuniFB7CuniFB7DuniFB7EuniFB7FuniFB80uniFB81uniFB82uniFB83uniFB84uniFB85uniFB86uniFB87uniFB88uniFB89uniFB8AuniFB8BuniFB8CuniFB8DuniFB8EuniFB8FuniFB90uniFB91uniFB92uniFB93uniFB94uniFB95uniFB96uniFB97uniFB98uniFB99uniFB9AuniFB9BuniFB9CuniFB9DuniFB9EuniFB9FuniFBA0uniFBA1uniFBA2uniFBA3uniFBAAuniFBABuniFBACuniFBADuniFBD3uniFBD4uniFBD5uniFBD6uniFBD7uniFBD8uniFBD9uniFBDAuniFBDBuniFBDCuniFBDEuniFBDFuniFBE4uniFBE5uniFBE6uniFBE7uniFBE8uniFBE9uniFBFCuniFBFDuniFBFEuniFBFFuniFE00uniFE01uniFE02uniFE03uniFE04uniFE05uniFE06uniFE07uniFE08uniFE09uniFE0AuniFE0BuniFE0CuniFE0DuniFE0EuniFE0FuniFE20uniFE21uniFE22uniFE23uniFE70uniFE71uniFE72uniFE73uniFE74uniFE76uniFE77uniFE78uniFE79uniFE7AuniFE7BuniFE7CuniFE7DuniFE7EuniFE7FuniFE80uniFE81uniFE82uniFE83uniFE84uniFE85uniFE86uniFE87uniFE88uniFE89uniFE8AuniFE8BuniFE8CuniFE8DuniFE8EuniFE8FuniFE90uniFE91uniFE92uniFE93uniFE94uniFE95uniFE96uniFE97uniFE98uniFE99uniFE9AuniFE9BuniFE9CuniFE9DuniFE9EuniFE9FuniFEA0uniFEA1uniFEA2uniFEA3uniFEA4uniFEA5uniFEA6uniFEA7uniFEA8uniFEA9uniFEAAuniFEABuniFEACuniFEADuniFEAEuniFEAFuniFEB0uniFEB1uniFEB2uniFEB3uniFEB4uniFEB5uniFEB6uniFEB7uniFEB8uniFEB9uniFEBAuniFEBBuniFEBCuniFEBDuniFEBEuniFEBFuniFEC0uniFEC1uniFEC2uniFEC3uniFEC4uniFEC5uniFEC6uniFEC7uniFEC8uniFEC9uniFECAuniFECBuniFECCuniFECDuniFECEuniFECFuniFED0uniFED1uniFED2uniFED3uniFED4uniFED5uniFED6uniFED7uniFED8uniFED9uniFEDAuniFEDBuniFEDCuniFEDDuniFEDEuniFEDFuniFEE0uniFEE1uniFEE2uniFEE3uniFEE4uniFEE5uniFEE6uniFEE7uniFEE8uniFEE9uniFEEAuniFEEBuniFEECuniFEEDuniFEEEuniFEEFuniFEF0uniFEF1uniFEF2uniFEF3uniFEF4uniFEF5uniFEF6uniFEF7uniFEF8uniFEF9uniFEFAuniFEFBuniFEFCuniFEFFuniFFF9uniFFFAuniFFFBuniFFFCuniFFFDu10300u10301u10302u10303u10304u10305u10306u10307u10308u10309u1030Au1030Bu1030Cu1030Du1030Eu1030Fu10310u10311u10312u10313u10314u10315u10316u10317u10318u10319u1031Au1031Bu1031Cu1031Du1031Eu10320u10321u10322u10323u1D300u1D301u1D302u1D303u1D304u1D305u1D306u1D307u1D308u1D309u1D30Au1D30Bu1D30Cu1D30Du1D30Eu1D30Fu1D310u1D311u1D312u1D313u1D314u1D315u1D316u1D317u1D318u1D319u1D31Au1D31Bu1D31Cu1D31Du1D31Eu1D31Fu1D320u1D321u1D322u1D323u1D324u1D325u1D326u1D327u1D328u1D329u1D32Au1D32Bu1D32Cu1D32Du1D32Eu1D32Fu1D330u1D331u1D332u1D333u1D334u1D335u1D336u1D337u1D338u1D339u1D33Au1D33Bu1D33Cu1D33Du1D33Eu1D33Fu1D340u1D341u1D342u1D343u1D344u1D345u1D346u1D347u1D348u1D349u1D34Au1D34Bu1D34Cu1D34Du1D34Eu1D34Fu1D350u1D351u1D352u1D353u1D354u1D355u1D356u1D538u1D539u1D53Bu1D53Cu1D53Du1D53Eu1D540u1D541u1D542u1D543u1D544u1D546u1D54Au1D54Bu1D54Cu1D54Du1D54Eu1D54Fu1D550u1D552u1D553u1D554u1D555u1D556u1D557u1D558u1D559u1D55Au1D55Bu1D55Cu1D55Du1D55Eu1D55Fu1D560u1D561u1D562u1D563u1D564u1D565u1D566u1D567u1D568u1D569u1D56Au1D56Bu1D5A0u1D5A1u1D5A2u1D5A3u1D5A4u1D5A5u1D5A6u1D5A7u1D5A8u1D5A9u1D5AAu1D5ABu1D5ACu1D5ADu1D5AEu1D5AFu1D5B0u1D5B1u1D5B2u1D5B3u1D5B4u1D5B5u1D5B6u1D5B7u1D5B8u1D5B9u1D5BAu1D5BBu1D5BCu1D5BDu1D5BEu1D5BFu1D5C0u1D5C1u1D5C2u1D5C3u1D5C4u1D5C5u1D5C6u1D5C7u1D5C8u1D5C9u1D5CAu1D5CBu1D5CCu1D5CDu1D5CEu1D5CFu1D5D0u1D5D1u1D5D2u1D5D3u1D7D8u1D7D9u1D7DAu1D7DBu1D7DCu1D7DDu1D7DEu1D7DFu1D7E0u1D7E1u1D7E2u1D7E3u1D7E4u1D7E5u1D7E6u1D7E7u1D7E8u1D7E9u1D7EAu1D7EBu1EE00u1EE01u1EE02u1EE03u1EE05u1EE06u1EE07u1EE08u1EE09u1EE0Au1EE0Bu1EE0Cu1EE0Du1EE0Eu1EE0Fu1EE10u1EE11u1EE12u1EE13u1EE14u1EE15u1EE16u1EE17u1EE18u1EE19u1EE1Au1EE1Bu1EE1Cu1EE1Du1EE1Eu1EE1Fu1EE21u1EE22u1EE24u1EE27u1EE29u1EE2Au1EE2Bu1EE2Cu1EE2Du1EE2Eu1EE2Fu1EE30u1EE31u1EE32u1EE34u1EE35u1EE36u1EE37u1EE39u1EE3Bu1EE61u1EE62u1EE64u1EE67u1EE68u1EE69u1EE6Au1EE6Cu1EE6Du1EE6Eu1EE6Fu1EE70u1EE71u1EE72u1EE74u1EE75u1EE76u1EE77u1EE79u1EE7Au1EE7Bu1EE7Cu1EE7Eu1F030u1F031u1F032u1F033u1F034u1F035u1F036u1F037u1F038u1F039u1F03Au1F03Bu1F03Cu1F03Du1F03Eu1F03Fu1F040u1F041u1F042u1F043u1F044u1F045u1F046u1F047u1F048u1F049u1F04Au1F04Bu1F04Cu1F04Du1F04Eu1F04Fu1F050u1F051u1F052u1F053u1F054u1F055u1F056u1F057u1F058u1F059u1F05Au1F05Bu1F05Cu1F05Du1F05Eu1F05Fu1F060u1F061u1F062u1F063u1F064u1F065u1F066u1F067u1F068u1F069u1F06Au1F06Bu1F06Cu1F06Du1F06Eu1F06Fu1F070u1F071u1F072u1F073u1F074u1F075u1F076u1F077u1F078u1F079u1F07Au1F07Bu1F07Cu1F07Du1F07Eu1F07Fu1F080u1F081u1F082u1F083u1F084u1F085u1F086u1F087u1F088u1F089u1F08Au1F08Bu1F08Cu1F08Du1F08Eu1F08Fu1F090u1F091u1F092u1F093u1F0A0u1F0A1u1F0A2u1F0A3u1F0A4u1F0A5u1F0A6u1F0A7u1F0A8u1F0A9u1F0AAu1F0ABu1F0ACu1F0ADu1F0AEu1F0B1u1F0B2u1F0B3u1F0B4u1F0B5u1F0B6u1F0B7u1F0B8u1F0B9u1F0BAu1F0BBu1F0BCu1F0BDu1F0BEu1F0C1u1F0C2u1F0C3u1F0C4u1F0C5u1F0C6u1F0C7u1F0C8u1F0C9u1F0CAu1F0CBu1F0CCu1F0CDu1F0CEu1F0CFu1F0D1u1F0D2u1F0D3u1F0D4u1F0D5u1F0D6u1F0D7u1F0D8u1F0D9u1F0DAu1F0DBu1F0DCu1F0DDu1F0DEu1F0DFu1F311u1F312u1F313u1F314u1F315u1F316u1F317u1F318u1F42Du1F42Eu1F431u1F435u1F600u1F601u1F602u1F603u1F604u1F605u1F606u1F607u1F608u1F609u1F60Au1F60Bu1F60Cu1F60Du1F60Eu1F60Fu1F610u1F611u1F612u1F613u1F614u1F615u1F616u1F617u1F618u1F619u1F61Au1F61Bu1F61Cu1F61Du1F61Eu1F61Fu1F620u1F621u1F622u1F623u1F625u1F626u1F627u1F628u1F629u1F62Au1F62Bu1F62Du1F62Eu1F62Fu1F630u1F631u1F632u1F633u1F634u1F635u1F636u1F637u1F638u1F639u1F63Au1F63Bu1F63Cu1F63Du1F63Eu1F63Fu1F640u1F643 dlLtcaronDieresisAcuteTildeGrave CircumflexCaron uni0311.caseBreve Dotaccent Hungarumlaut Doublegrave arabic_dot arabic_2dots arabic_3dotsarabic_3dots_aarabic_2dots_a arabic_4dots uni066E.fina uni066E.init uni066E.medi uni06A1.fina uni06A1.init uni06A1.medi uni066F.fina uni066F.init uni066F.medi uni06BA.init uni06BA.medi arabic_ring uni067C.fina uni067C.init uni067C.medi uni067D.fina uni067D.init uni067D.medi uni0681.fina uni0681.init uni0681.medi uni0682.fina uni0682.init uni0682.medi uni0685.fina uni0685.init uni0685.medi uni06BF.fina uni06BF.init uni06BF.mediarabic_gaf_barEng.altuni0268.dotlessuni029D.dotless uni03080304 uni03040308 uni03070304 uni03080301 uni03080300 uni03040301 uni03040300 uni03030304 uni0308030C uni03030308 uni030C0307 uni03030301 uni03020301 uni03020300 uni03020303 uni03060303 uni03060301 uni03060300 uni03060309 uni03020309 uni03010307 brailledotJ.alt uni0695.finauniFEAE.fina.longstart uni06B5.fina uni06B5.init uni06B5.medi uni06CE.fina uni06CE.init uni06CE.medi uni0692.final.alt uni06D5.finauni0478.monographuni0479.monographiogonek.dotlessuni2148.dotlessuni2149.dotlessuni1E2D.dotlessuni1ECB.dotlessdcoI.alt arrow.base uni0651064B uni0651064C uni064B0651 uni0651064E uni0651064F uni064E0651 uni0654064E uni0654064F uni07CA.fina uni07CA.medi uni07CA.init uni07CB.fina uni07CB.medi uni07CB.init uni07CC.fina uni07CC.medi uni07CC.init uni07CD.fina uni07CD.medi uni07CD.init uni07CE.fina uni07CE.medi uni07CE.init uni07CF.fina uni07CF.medi uni07CF.init uni07D0.fina uni07D0.medi uni07D0.init uni07D1.fina uni07D1.medi uni07D1.init uni07D2.fina uni07D2.medi uni07D2.init uni07D3.fina uni07D3.medi uni07D3.init uni07D4.fina uni07D4.medi uni07D4.init uni07D5.fina uni07D5.medi uni07D5.init uni07D6.fina uni07D6.medi uni07D6.init uni07D7.fina uni07D7.medi uni07D7.init uni07D8.fina uni07D8.medi uni07D8.init uni07D9.fina uni07D9.medi uni07D9.init uni07DA.fina uni07DA.medi uni07DA.init uni07DB.fina uni07DB.medi uni07DB.init uni07DC.fina uni07DC.medi uni07DC.init uni07DD.fina uni07DD.medi uni07DD.init uni07DE.fina uni07DE.medi uni07DE.init uni07DF.fina uni07DF.medi uni07DF.init uni07E0.fina uni07E0.medi uni07E0.init uni07E1.fina uni07E1.medi uni07E1.init uni07E2.fina uni07E2.medi uni07E2.init uni07E3.fina uni07E3.medi uni07E3.init uni07E4.fina uni07E4.medi uni07E4.init uni07E5.fina uni07E5.medi uni07E5.init uni07E6.fina uni07E6.medi uni07E6.init uni07E7.fina uni07E7.medi uni07E7.init Ringabove uni2630.alt uni2631.alt uni2632.alt uni2633.alt uni2634.alt uni2635.alt uni2636.alt uni2637.alt uni047E.diacuni048A.brevelessuni048B.brevelessy.alt uni0689.fina uni068A.fina uni068B.fina uni068F.fina uni0690.fina uni0693.fina uni0694.fina uni0696.fina uni0697.fina uni0699.fina uni069A.fina uni069A.init uni069A.medi uni069B.fina uni069B.init uni069B.medi uni069C.fina uni069C.init uni069C.medi uni069D.fina uni069D.init uni069D.medi uni069E.fina uni069E.init uni069E.medi uni069F.fina uni069F.init uni069F.medi uni06A0.fina uni06A0.init uni06A0.medi uni06A2.fina uni06A2.init uni06A2.medi uni06A3.fina uni06A3.init uni06A3.medi uni06A5.fina uni06A5.init uni06A5.medi uni06A7.fina uni06A7.init uni06A7.medi uni06A8.fina uni06A8.init uni06A8.medi uni06AA.fina uni06AA.init uni06AA.medi uni06AB.fina uni06AB.init uni06AB.medi uni06AC.fina uni06AC.init uni06AC.medi uni06AE.fina uni06AE.init uni06AE.medi uni06B0.fina uni06B0.init uni06B0.medi uni06B2.fina uni06B2.init uni06B2.medi uni06B4.fina uni06B4.init uni06B4.medi uni06B6.fina uni06B6.init uni06B6.medi uni06B7.fina uni06B7.init uni06B7.medi uni06B8.fina uni06B8.init uni06B8.medi uni06B9.fina uni06B9.init uni06B9.medi uni06BC.fina uni06BC.init uni06BC.medi uni06BD.fina uni06BD.init uni06BD.mediexclamdown.casequestiondown.case uni2E18.caseuni066E.init.mathproduct.displayuni2210.displaysummation.displayintegral.displayuni222C.displayuni222D.displayuni222E.displayuni222F.displayuni2230.displayuni2231.displayuni2232.displayuni2233.displayuni22C0.displayuni22C1.displayuni22C2.displayuni22C3.displayuni2A00.displayuni2A01.displayuni2A02.displayuni2A0C.displayuni2A0D.displayuni2A0E.displayuni2A0F.displayuni2A10.displayuni2A11.displayuni2A12.displayuni2A13.displayuni2A14.displayuni2A15.displayuni2A16.displayuni2A17.displayuni2A18.displayuni2A19.displayuni2A1A.displayuni2A1B.displayuni2A1C.display@%2%%A:B2SAS//2ݖ}ٻ֊A}G}G͖2ƅ%]%]@@%d%d%A2dA  d   A(]%]@%..%A  %d%@~}}~}}|d{T{%zyxw v utsrqponl!kjBjSih}gBfedcba:`^ ][ZYX YX WW2VUTUBTSSRQJQP ONMNMLKJKJIJI IH GFEDC-CBAK@?>=>=<=<; <@; :987876765 65 43 21 21 0/ 0 / .- .- ,2+*%+d*)*%)('%(A'%&% &% $#"!! d d BBBdB-B}d       -d@--d++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++endesive-2.19.1/examples/ca/000077500000000000000000000000001504236674500156235ustar00rootroot00000000000000endesive-2.19.1/examples/ca/170647371793814353188311742751744469876499188224000077700000000000000000000000001504236674500265122demo2_ca.root.crt.pemustar00rootroot00000000000000endesive-2.19.1/examples/ca/248075908521160111375160830087228812224077410680000077700000000000000000000000001504236674500261162demo2_user3.crt.pemustar00rootroot00000000000000endesive-2.19.1/examples/ca/288528155615202608532924619510015678088367985326000077700000000000000000000000001504236674500261652demo2_user2.crt.pemustar00rootroot00000000000000endesive-2.19.1/examples/ca/571131681754382479759372987552620622065870021143000077700000000000000000000000001504236674500262712demo2_ca.sub.crt.pemustar00rootroot00000000000000endesive-2.19.1/examples/ca/98315084947916818053205948128474780334601525706000077700000000000000000000000001504236674500261012demo2_user1.crt.pemustar00rootroot00000000000000endesive-2.19.1/examples/ca/demo2_ca.root.crt.pem000066400000000000000000000022141504236674500215470ustar00rootroot00000000000000-----BEGIN CERTIFICATE----- MIIDLTCCAhWgAwIBAgIUHeQXwdDU4jyXtdItkEjDOw/SigAwDQYJKoZIhvcNAQEL BQAwHTEbMBkGA1UEAwwSQUEgVHJpU29mdCBSb290IENBMCAXDTI1MDYxMTE4Mjgw MloYDzIwNjUwNjAxMTgyODAyWjAdMRswGQYDVQQDDBJBQSBUcmlTb2Z0IFJvb3Qg Q0EwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCGHskGb4Gd364QhbS6 i2NmHbJf4N5LhDJPwRjDACuRqRu42fEB+MwKvAIYoS2wVihYubf/dRZFc0/4yyCH 7I1Mkh1YoQRjl3q51pKWjUjm5Ua611NDLHvkDU8ecQWj2qjHcJtV39ay3L/TIyvS tesIR+o2oOkfxzaLjkhrH08DOy5L3gvETexV7GBbmSQTaI9jvNuD9oKZs6ba1S5O 65pPEC/u3/udZgRBKd+lB/qlLk7HNuN0trwEfZLvdBC4pS9Fc0DbUcHnsNBwWFc9 VjrzzJDYHdWmZtYGg5rc7efx5+zVw26wm58caJv5ihi0An4J/I8i5I4TKoLMgcJP 2r7VAgMBAAGjYzBhMA8GA1UdEwEB/wQFMAMBAf8wHwYDVR0jBBgwFoAUPkWmCmbq vZJeJaiLKy8j/la8iHEwHQYDVR0OBBYEFD5Fpgpm6r2SXiWoiysvI/5WvIhxMA4G A1UdDwEB/wQEAwIBhjANBgkqhkiG9w0BAQsFAAOCAQEAPc3cf1CHKSaF4BDM8UHT 4B5VMdj7uZSxsQ+IerrOi6QfMIUuesVc/h9oN9eBLoTCCQsFB7nrizwmyd2xIK9d jOuPQZexu9VhBIeJE8Fh86gG0U6IQxXw9NXW10yaW9w5RAYQqH3w+VPsaPDXnceX b0yjM1vtmV9WrMNoXWPil7vYuea0HAar80IyUKwrzEOZa8zqDz1HElC0rukVh0Yl 5PHkVptl11d81ukyKeXGP6PFt1JI31vgAEZHdykz8w7SjAu0g+QrM2LCZV915wLu OAS3ptxRmdNymk1zYHEyPt7CRdgUV1NWhE1N0RQMuf1CnXRPWZ6+Ls83xVzoO1i7 WA== -----END CERTIFICATE----- endesive-2.19.1/examples/ca/demo2_ca.root.crt.pem.cer000066400000000000000000000014611504236674500223220ustar00rootroot000000000000000-0<-H;Ҋ0  *H  010U AA TriSoft Root CA0  250611182802Z20650601182802Z010U AA TriSoft Root CA0"0  *H 0 o߮cf_K2O+ -V(XuEsO LXcz֒HFSC,{ OqڨpUֲܿ#+ҵG66HkO;.K MU`[$hcۃ.NO/fA)ߥ.N6t}t/Es@QpXW=V:̐զfnh~ "*́Oھc0a0U00U#0>E f꽒^%+/#Vq0U>E f꽒^%+/#Vq0U0  *H  =P)&AU1z΋0.z\h7ׁ. <&ݱ ]AaaNCL[9D}ShםǗoL3[_Vh]c◻عB2P+Ck=GPF%VeW|2)?ŷRH[FGw)3Ҍ +3be_u8QrMs`q2>EWSVMM BtOY.7\;XXendesive-2.19.1/examples/ca/demo2_ca.sub.crt.pem000066400000000000000000000025471504236674500213660ustar00rootroot00000000000000-----BEGIN CERTIFICATE----- MIIDzzCCAregAwIBAgIUZApuK7Hcoiz740Eknrz1eN5zohcwDQYJKoZIhvcNAQEL BQAwHTEbMBkGA1UEAwwSQUEgVHJpU29mdCBSb290IENBMB4XDTI1MDYxMTE4Mjgw MloXDTM1MDYwOTE4MjgwMlowJTEjMCEGA1UEAwwaQUEgVHJpU29mdCBJbnRlcm1l ZGlhdGUgQ0EwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCHZyrEWyxN iwVC5afAaVU4hlDEBTeqFsu0YPkFRRNFPVhX+CrLMPlKLy97Zq86Viw9Tu2ob8QN EUeYIDpjcYjZqJZj2fdaoCMam/WwZlonQqvyEzqRshe4kRACUdfDdfamCK6RFini Yxfq34B+27yI3aFwIY1/3oQKm0uP92fLpIzL5w3HT94CZEdGVDuALPs9D/kF+PG1 Si+S8/m3rZx3PfCAQAhvh2V1pG3LqFf/UiFXWoLWLex3w4APPwRbuFUYjtarLr+5 GhUfmOf16rH5Ic6tbdlMFDaet/VBasbmCc+OBjL0R1GEErnB/8Nr5IXTYV55cZDJ Z/3b0M9wh1AfAgMBAAGjgf4wgfswEgYDVR0TAQH/BAgwBgEB/wIBADAtBgNVHR8E JjAkMCKgIKAehhxodHRwOi8vY2EudHJpc29mdC5jb20ucGwvY3JsMGYGCCsGAQUF BwEBBFowWDArBggrBgEFBQcwAoYfaHR0cDovL2NhLnRyaXNvZnQuY29tLnBsL2Nh Y2VydDApBggrBgEFBQcwAYYdaHR0cDovL2NhLnRyaXNvZnQuY29tLnBsL29jc3Aw HwYDVR0jBBgwFoAUPkWmCmbqvZJeJaiLKy8j/la8iHEwHQYDVR0OBBYEFLuhhALL AEAUz1v1QQzM00vhi4lIMA4GA1UdDwEB/wQEAwIBhjANBgkqhkiG9w0BAQsFAAOC AQEAPjIEUaksu9VvPmQZ8MSTLBAzRWg+un6Ww9GZZ1gBfBoENyxz6+va5D90N/Jg qJP58WJUtfdTLiHDTRb2z5h4cl4YHCf4HmgMgrzLhe7yjAjtpRokfzQlUFmcQewh KJgUH4eOw1g04etMCQbMx0wDF3J35hsKwiTxIEwjhYsqCmCXs9LKtJj/RFSTOp4r kSzAfYYTMYWW/nRtVtjq4BgMR29f8BiM1q7/GrBlppc4fdadwnOOh8M8ZM7NUEhR 6Xk69Ut7P4VvbyYuv+lkXpWJ2quDpXu5IF0GwBGfWkXnFps9k5FFTAzIBOXPab4x Q88Jg+YGQMFmfnVvfKh8ySi2WA== -----END CERTIFICATE----- endesive-2.19.1/examples/ca/demo2_ca.sub.crt.pem.cer000066400000000000000000000017231504236674500221310ustar00rootroot0000000000000000d n+ܢ,A$xs0  *H  010U AA TriSoft Root CA0 250611182802Z 350609182802Z0%1#0!U AA TriSoft Intermediate CA0"0  *H 0 g*[,MBiU8P7˴`EE=XW*0J//{f:V,=No G :cq٨cZ#fZ'B:Qu)c߀~ۼݡp!ބ Kgˤ OdGFT;,=J/w=@oeum˨WR!WZ-wÀ?[U֫.!έmL6Aj ώ2GQka^yqgpP00U00-U&0$0" http://ca.trisoft.com.pl/crl0f+Z0X0++0http://ca.trisoft.com.pl/cacert0)+0http://ca.trisoft.com.pl/ocsp0U#0>E f꽒^%+/#Vq0U@[A KዉH0U0  *H  >2Q,o>dē,3Eh>~љgX|7,s?t7`bTS.!MϘxr^'h ˅$4%PYA!(X4L Lrw $ L#* `ʴDT:+,}1tmV Go_֮e8}֝s10U trisoft.com.pl1#0! *H  demo1@trisoft.com.pl0"0  *H 0 iEG~hf> x}rԅ &EÜ0/nGІ[xR~!֕P2#  񏪞U{eOJM|)'Bq]5)DYɴR}dG+./X6U'v!-Z3ϛSbA g޳'N~ɽG(Ad T1iDhJ :>7ժҒ]h88Rq3W0PI4cm0}HQmO0K0 U00U#0@[A KዉH0-U&0$0" http://ca.trisoft.com.pl/crl0f+Z0X0++0http://ca.trisoft.com.pl/cacert0)+0http://ca.trisoft.com.pl/ocsp0U0demo1@trisoft.com.pl03U%,0*++ +7  +$0U* Ih]2H/0U0  *H  "sؗ3V-`KNXNlڧj>qE)"SY D$Uunz^ dWϵ(g`@{A TnEqqll*gctb@1Lv1Ƿ;|uF';ϝbs+nQxNo"lK;mC{=&̔<&*WAd/xH,4}'V1p{32|8ɢHC8+endesive-2.19.1/examples/ca/demo2_user1.key.pem000066400000000000000000000033461504236674500212500ustar00rootroot00000000000000-----BEGIN RSA PRIVATE KEY----- Proc-Type: 4,ENCRYPTED DEK-Info: AES-256-CBC,13CA42E4D2AB6F9EE44A8ECD4FC53348 ZQfwakGfrfP4lMZJVUww1q4OGVrRsZf4V/iJr66lJLqDp27SEBIqYFbW65ds3lYI C32CLwrjtdSL8ABuaAd9jXiIX/XuTIIfokg6TuKZUXgagCCIAn7vh1fp9WJiipGH 6La8gFCuD9rJBP2GgCS/W74lKNxgfuryHvmpRdKpLQBjvOtjpffQxSpB0oOEkf3e UoJJyzgZhmuJXHPUsBHKknINwj+n6gwOnh7YRbR1VGQTHM6uopp9hpguphk9lP3t /z7i6hKPC1uLvkleiE20ic7JVxebPkKtMoZj/7LVHZ0PDCj5QOxPmfc5lpvLyj2E HoPOsJM9LkLUefaj1xzg3qWZx6rre3fYqWGUruqKgjy9niVlUB6JXV88YOU5onQc 23imLM1dUB+E53cWe+oxOUsqTbnbW2Pw3cCNHzFqWXHwFGmRk7e3bnp3rRD2DpBW mCJmqYqpPL0QSFPs1w5WLS+/beFRJHkTd7mNJMTKuur2l27enZzqw8NaJ89cNZPE uLW1fwlejSP0n6JBw1DiNSc50FKLeE089jM7f9nLwbOFxpEo0ZEYsMZcFyEVqYP+ QX/bd+uHS8OFXUIpVR2brjYgQK+XNPBXejxGPJIfzj6CRH3cwhVUiMlAKdgt21Wt mGbIDS0nfvZNlB5zfV33EiCSQGgG3lDst3kS1UUf78GgsuvTnuNbChc28VgAvYG6 jTZsSKNHd1Jls+Wbx7fm11sq5EoJpYtXiKQoVz13Xi99LTTTdFZFW3yMkwlbVf25 h5Y4Gv9OW4BPyCQpHpK11ubWuHzNjud2XDb4syKpK2a6EGPWOfS+Kc9J9q5f9qKN 2vGGuRKQoSEEn3mnGGdwULvA2yj9kATkt57uge7xLYO4YyTeZJESx4/ruaF6FJOg didGM4h0Xh78UB6mN5PPmxXTYx5CQ3E3JPbfyWPRT3a6JAnyTHLtJNBPxCBHo2PA zEX9tGRyH5iA7XSllxvK7VhKrtI1dEBbwvCoXr77mZbBiva/IRzdPtjpwS8zZBsU CJAZsz1Y7B0cZ97VPg9zSwxs8nCsZhemOml5/gpwoXuGmX7jK6IEvVojrI/RlkSD 9ktNKgzxCjHlHYW4mUkcFOYqdQnqxn4YIiHE1PaqGlT/7u7QSVkksagaSnLT/vyd PnExNwUNR2eG256ZB7oS4glm3HlwWk9svpUo2C05uZP126eoyvafiTWLr7axX94G I5LlPeB+wwELef2bPvq0WjLklSPqNRBbopNZvtrWXzn0zSBz/kDzjsQtEoSRZU5I DABLStYuy863VGdnqf5uEhdStKyKjnetJaGxOXJMkS+oJUOUSiGYztdg22tcK7Kp yuX0qe3xirIF3YcIaQOnHQTJ4Yqjm1q/sTwj3jkuqdtH5b3zs8BzRkbR81zCmFkH MNsuGwF1GhUVmYS1wMvtUG4w9c9s44sLPoiJhMNNrycJREXnIMAe9yztZX2PQaey zOcOzX3yIJ6N9Ob9K0l0R+89nrPEDJbXQRwjbhuWlmMvZY3KQM3+VgMJtJDL11In 7LqeEyRno5ojyUN8XVovExqPHzr3HcAx3twf0mquhYgzbuIGVpe0LT2FFrkOTkYy -----END RSA PRIVATE KEY----- endesive-2.19.1/examples/ca/demo2_user1.p12000066400000000000000000000075661504236674500203120ustar00rootroot000000000000000r0( *H 00 Z *H  K0 G0 @ *H 0_ *H  0R01 *H  0$qmm4aѤfN 0 *H  0 `He*S|(|]㓈=fJ}%Ϥk%x ;`N &S0hxB)y%dcpmEܭRVd~atrΠugBm6GZ>bU׶Ȱ˜ZOtS'>d D Ucr=éWlZF譐tEQ شf@.|S߮Cv=ODQQlmP03NDf[U1\@It+ną,EG;W+-^4t&0اH"?eB0ןveaRxࠤ&Vo&1uqM bN"&IcTl}u_zU LLmȫ"0!SꞭ Ad( LI:%\ E1l\ nPia&?kJGWSv`;|Lߢ&D/QY}cqg[Wkpk0ʃXjQ;ԥyOt q"Bڊ Xu4Ç"!#At(ۓ`vxy5X*=X lhtWCxFJ[V" ؓZq7PzR?`KM ,*kIo! gt,K!]W!( ~U|p5bP:96/iQ |r,afDTchb[qW1-A.n#Ѯ1̋N_3C[*g/ŶQyeϏ/rĚx'nƤEQ|= GN:?C?2ԎwB+ȣ(M:lE5=9a*!t3K q.RƄ)TcčD+QS{'}ɴ;%%s0eDB9;EXb́q{Kg΂h5y"&{c+6{20!',s4r/c#$[6)LT{{0 p,q0)WI.gV %MФNſ=½aCM/!.l8;'y ([=#3APf$ WDS59rq=:PpwL;]˒(Eb!Ən PH 5t >\!aWZWU=Ven#ݱL-o5D*fѝe,'G '1'(yauIC]<}J4; tG1H0! *H  1USER cert0# *H  1Ts ȽsW/w;-OwHEm0A010  `He b偅Zf;|s̑& VSi6endesive-2.19.1/examples/ca/demo2_user1.pub.pem000066400000000000000000000007031504236674500212400ustar00rootroot00000000000000-----BEGIN PUBLIC KEY----- MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA0+yOafFFG0d+aP3yFOxm l5M+vgl/prN4fcT2ctSFIBom+0Uc68OcMC9uR9CG+xFbqXgUUn4hxBLAutaV8FCR v7KGMvAjDX+5tf8Mm/GPqp7gVXu662UO/0/dSrpN5XwpJw7BQhCicd5dNY0pRFna 0cm0Un2sZEeKtOTqKy65L4m/WA/8NorMVQX/DifwdiHvCMje88Mt5Vozz5tTnPBi Qaj6Ccdn3rPhtfInyU6AfpiK7cm9RyjnQRtkCs0EElQcMWnjRBDL22hK49AJIDqs xD43v/Gj1arSkl1oOMwYOIdS4xBx0jMQtI1XqzBQSR0VNL5jmgZtgzB9SKnwUYtt EwIDAQAB -----END PUBLIC KEY----- endesive-2.19.1/examples/ca/demo2_user2.crt.pem000066400000000000000000000030011504236674500212350ustar00rootroot00000000000000-----BEGIN CERTIFICATE----- MIIEQjCCAyqgAwIBAgIUMooMynJ146HDsH1AQ+ij62oGUq4wDQYJKoZIhvcNAQEL BQAwJTEjMCEGA1UEAwwaQUEgVHJpU29mdCBJbnRlcm1lZGlhdGUgQ0EwHhcNMjUw NzEzMDkzMzQ5WhcNMjYwNzEzMDkzMzQ5WjA+MRcwFQYDVQQDDA50cmlzb2Z0LmNv bS5wbDEjMCEGCSqGSIb3DQEJARYUZGVtbzJAdHJpc29mdC5jb20ucGwwggEiMA0G CSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCrzTveSY2QKTuxVmJn4fYwrzZ0Sv9i 34VN6zrn+ac6cGmhfKaNeBMUnLrtRsZ1sUhN+sNOTgdupWeY/tlt78FJXY/uyc9y V4QBDRpxCLvH6rcjexbwTf3geAO1AA8nmRR/aweXggKk84sFg12QfV9MxgVNAN5x sBTwNPq/EEuD7ar+Aztn8dcg2/GkZZ6Ab0tu7jXQEwy25lXWKKZW7avbsoK7aDpB +mAIWN21whXMbTqIgsjx7aQOOm05A2g5UzWN/eCVvVlDcIFhBxGlHeiF2r9slkZS oC08neaqKlTLgyV8l8scHnzryI/wVP0pvg3qNqxr532lorOi/mGdcHudAgMBAAGj ggFPMIIBSzAMBgNVHRMBAf8EAjAAMB8GA1UdIwQYMBaAFLuhhALLAEAUz1v1QQzM 00vhi4lIMC0GA1UdHwQmMCQwIqAgoB6GHGh0dHA6Ly9jYS50cmlzb2Z0LmNvbS5w bC9jcmwwZgYIKwYBBQUHAQEEWjBYMCsGCCsGAQUFBzAChh9odHRwOi8vY2EudHJp c29mdC5jb20ucGwvY2FjZXJ0MCkGCCsGAQUFBzABhh1odHRwOi8vY2EudHJpc29m dC5jb20ucGwvb2NzcDAfBgNVHREEGDAWgRRkZW1vMkB0cmlzb2Z0LmNvbS5wbDAz BgNVHSUELDAqBggrBgEFBQcDAgYIKwYBBQUHAwQGCisGAQQBgjcKAwwGCCsGAQUF BwMkMB0GA1UdDgQWBBSvX/NWnQ5db3+aFPugiON/OZB87jAOBgNVHQ8BAf8EBAMC A/gwDQYJKoZIhvcNAQELBQADggEBAEtk7sXGYLP/PruWo1tmGKuY3bSorD/0qGmt 5nXqcrj8lc+UkS2OV0OGjLA7G7IlJPWnePkgACDC5MxZWseWIEQrH2OQVWtLwkoJ +3tYfLeyMhd0Me/jmgDvE6lyXItzo8I77efSSfhS/etOFAldvBPV7qBTKnx7PV7p xbiy5w/1CwGGDGG1UXBBuh+F/sKwNkNeDp3v5iTWkgtPUDkPvSwDFUOJyl9CIXyc ejWhLTueudO6TDav6kS41rDFPlVdMYrKPZoAXSQ3tY4WapmIyJq2VVVoiQBdWFTe GrarSkIhLYyJEIHVc4Q9u4Lpb6WxqnEo8k7NUvZovDw6MWM8YEg= -----END CERTIFICATE----- endesive-2.19.1/examples/ca/demo2_user2.crt.pem.cer000066400000000000000000000021061504236674500220120ustar00rootroot000000000000000B0*2 ruð}@CjR0  *H  0%1#0!U AA TriSoft Intermediate CA0 250713093349Z 260713093349Z0>10U trisoft.com.pl1#0! *H  demo2@trisoft.com.pl0"0  *H 0 ;I);Vbg06tJb߅M::pi|xFuHMNNngmI]rW q#{Mx'k]}_LMq4K;g eoKn5 U(V۲h:A`Xݵm::m9h9S5YCpaڿlFR-<*T˃%||ȏT) 6k}ap{O0K0 U00U#0@[A KዉH0-U&0$0" http://ca.trisoft.com.pl/crl0f+Z0X0++0http://ca.trisoft.com.pl/cacert0)+0http://ca.trisoft.com.pl/ocsp0U0demo2@trisoft.com.pl03U%,0*++ +7  +$0U_V]o9|0U0  *H  Kd`>[fݴ?iurϔ-WC;%$x YZǖ D+cUkKJ {X|2t1r\s;IRN ]S*|{=^Ÿ  aQpA°6C^$֒ OP9,C_B!|z5-;ӺL6Dְ>U]1=]$7jȚUUh]XTJB!-s=oq(NRh<:1c<`Hendesive-2.19.1/examples/ca/demo2_user2.key.pem000066400000000000000000000033461504236674500212510ustar00rootroot00000000000000-----BEGIN RSA PRIVATE KEY----- Proc-Type: 4,ENCRYPTED DEK-Info: AES-256-CBC,432E91A73338F65EF028B48F7A75C8D5 9s4U5Cwn9ajLjX42GuoOrhsbBWSWofZ7XMt+08UkVagWoKUbxIjOv4BKhF5AUDtq lPneYDiZNNNx8wKrI/okPGBrE4ftfGZC414Xb/EpgVIr+H4JutIcR04H3xWUHYUI +6oE6SD/vD6XTzAMMgpHU43hKnLRHE8Utyfk+v4wlCl/O8oLHVWdK0jD7r0bq4vp CqbWJd8y3GbeYvaoke5CCOH9fEW50vLlcwFewrf6y8NBINyPf0JM/Puju8W+7DR+ MgK/9vtdxVnX+RAs/0i2T5tehklQxZhfJC3YEbUCjdZPgtNRFVWpbRnpzCXFYFJX dpKX1WuINGpcQk8BJ3KLDUOrv3nqHyUshQ6MCcRUTr+gvAAV7Nr3y3MowqfwD8QX p8QoIqFVFDtwvQAePb8VrMqizMqAzmaOWE2sA3Vd0pAPZZncXcFbwMwK3TM3aUwR EuvasRgJ7ujiDXMJS35P53js+yNduFRi0W5C5kEGsMQs8GtAEJ2j65nEfONx0nzS AKHJNH8XTvVzIwcf1SU0dA34Bl37h90X/xFbkxZ5Z7EnZidbXuOOJ9tqVNFPi4Xh is9v/1gAz2VXMWywkDAVz0o194veM2ynuBamF3mxJD+NKHp6t3Qf/6FGBPUD/yOL AT/1o+z/OwGSm/DHM47jhUArx4A5ATLZ0CbpE6ViRfsFv/YiQXVK0AmFQQNi5fca QdVdz9DGFqWa4Q2sSYPcAa7b0iwZ5QSWJmYmKzQ2oDER4G+qxpx4t20D/ipB1FD/ FDjsf9M3fEktoqSvLZdUzs3J59VMyESMwfnj7RV12EUOea4lfpxWW7t0DkJiLMkE Kp2yvvdYr5zSt5Gfz+WOhU6Fsmql7w4ONYLZxx/64hrcL5IFgPn0fgJZudU15xJd uApZ4i9qo2PtBO/I6kTKB8l/fUzCSIyzunRefO2YHlNoJ8yIVJpBd/f36j+m2LqJ BukwxetYLGdBX+jPdspXUUJc2YeKjJJsYoGcOQqozn5fS1CmvnWr3mElZuCix4JZ aI7eueFXxNKBh6YjLOItgGb6p8hS4zbdhr1rbB4qxB6tqgnfjikfGKhogAJ8TTTB nn5SvPcvyV+o4Qyyn7OktRHQkYv5vM76gwymQjsCYpBTjyYMUsDdXkfO40AIcXoN XDbM9OSyfwpuxlvN6t94IdnXdEnFTDEA8F6SWA3ILlv2kMW+4We3HTaRJERPj0Zx B2FdzHsYgG2mAsWbls0qP7M+NTVtT6k1tMCn7aNrKv1Wxt4vkrJRFT7JWA9zq07q KLZWJSDic1tkykURYnNbjkgsS3kAb6w5doSqZT9mDXJS9FE52UVNHDRhFmUa+myN FtgSeJ7be86wxcpV4xkc3ylZrmzC2yVMeySmm66mpPf3Cox/VGN+xByv9rS18KgN Su1vpjn+GXPsUZGklURmKgG9cIvW4eOvsTcYZomH6ef9VC06t+P4u18C03ZkkGiu 3pI0I16piBAA+z9w2mf4AWiXLOVQ2+85nyHFOnyStKSR1/AX5cmLPVkoklfDhp8A DAKDe1cIpIqyqDXIIJIhQKpZSNdRKzDm9Hs24106+4EnHdGmJtpl0wiGS2m0lPts -----END RSA PRIVATE KEY----- endesive-2.19.1/examples/ca/demo2_user2.p12000066400000000000000000000075661504236674500203130ustar00rootroot000000000000000r0( *H 00 Z *H  K0 G0 @ *H 0_ *H  0R01 *H  0$8t6WPN 0 *H  0 `He*k@J0eKÀ TŃb4I10 Z;k H3l$^i'gO ,>= PxȝtK:maK/Q~ܯ5P+x/SMc-Bw#<ݷ"f öج:R7P@3i:nW< P|0͔m]NSZ\ajzA&736wꩮ:^sp}NΎBhq #)`v2Y)Dt. 4Y0AbI~aF<`x}ۓ_c;Exr,[s[!j)s GO:aQZduOG+Jq^eTtQH5b@ k[Wtrqd9z{<ħ=̵@k5bשUjKǥ31auЈ']P) \%ɿi 1vh0L+S2q)w͏:.KQb%bG4Fm(!YcLf-'_{+Yp<*΢9ZJ͗a˦Po,pq㣃}gfgӝ>\طΘ:L eJ@^WU+d@%IWr:8&22'P ,y >wEJ'Թ_)8cpsrb;dFiK)*0 #@GG„C;Qé}B y@Y6v0(m(.#Tzs!`ʮyZx"~Wf:Pƽw T3uk$gxEZpM@y׼k6FLHkpv7cmWW0Li.FxZfũ]D뛌MJ}\7m:L:l9ݲ= @w!$"p֬-[ @ 3u>m]rpٛ"M#" &b͋- 炠W{MN ySh=mbHIt$p,Ik }Lj!)m㚽c⿩IAj!q^\)߿8YF0@!ȋf7qFuG|.- cE+ oH=U^O<8VؿMY ==AК ye$- Aԙ_sJol< KTlwcUI̳-Qt"k 4(SE6FF-Sp'=MA$0UڜKь;d5&y \9{H "Eu͏o:Ag{uoc Qg~Ԇ@l} z K'':.<tr3G0m :k|h_ ½;?-$~R2ܡ 1L*JG&m];#w x#xzi h fS,2m.e3ųS7׍>@ lⰉy zq50zj:*/`~q0gPi*˕8'5"YWYO섷AF_](3)n]6 @mUL]QB<^/إPP7kpEq)eR+yKJ. Lto7*6>:+ؙ.>yB쮼B-1''18o1ٚX^,W78Uhp"I5:V`97)8EiZv uCкQch3"u0ul ~v a2tEG$0nh#,V 9ZG tP_+9l-6sC[;d' '{F b60ʈQޡy Gھ|?q3e/g4USnvak.𘿳|k߄*y:k5Qc r6nn% ұ%жQ9*ǥlۉ.`ڲR;3*L\zۍHQ9#x67+0 *H 00 *H  9050_ *H  0R01 *H  0$/E@hmN 0 *H  0 `He*lJ=7Đ9Lƿ"r~/B)lIFzieI. ,Zyjgq0 "JrZ1+E&U@1g|* +D K1 KV٣<@1ln%@*Q\s`wԏNchAv69Pvk{7/p DGw\'% ZLړA Ξĸ0v!m Ն0N6eb ch[ǖsY>3Gy?&"IR25u#@f߹J}EFc\BZosh%Kxs;71kEmTC~>Rldof/+aQ/4z2Wdc]ywXh "dlS=bT7qXeK j5n#g#[2upUn277f'Or3g~/?Rm}l-d+ȼqN=&٪5OM=_8rAxYTV%׾,ew@p|mum1WVu+}1$zL% LR[5r}M>\9LL)+{ZYЦ_$!n ;I^Vow/6zz2a;Qw5CJ6AqiTv}}{D/]|`AY#?Z'&vi x3nU1WdnЖ $Ov/y==,O+xj#g ȊAQMF*|`zϓHXk͋w[^zs=#8ܿE}5;($1~aP[ 1H0! *H  1USER cert0# *H  1e|q]$5"Ȃ0A010  `He 87y%WP^Ҿݗ cm=dYendesive-2.19.1/examples/ca/demo2_user2.pub.pem000066400000000000000000000007031504236674500212410ustar00rootroot00000000000000-----BEGIN PUBLIC KEY----- MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAq8073kmNkCk7sVZiZ+H2 MK82dEr/Yt+FTes65/mnOnBpoXymjXgTFJy67UbGdbFITfrDTk4HbqVnmP7Zbe/B SV2P7snPcleEAQ0acQi7x+q3I3sW8E394HgDtQAPJ5kUf2sHl4ICpPOLBYNdkH1f TMYFTQDecbAU8DT6vxBLg+2q/gM7Z/HXINvxpGWegG9Lbu410BMMtuZV1iimVu2r 27KCu2g6QfpgCFjdtcIVzG06iILI8e2kDjptOQNoOVM1jf3glb1ZQ3CBYQcRpR3o hdq/bJZGUqAtPJ3mqipUy4MlfJfLHB5868iP8FT9Kb4N6jasa+d9paKzov5hnXB7 nQIDAQAB -----END PUBLIC KEY----- endesive-2.19.1/examples/ca/demo2_user3.crt.pem000066400000000000000000000030011504236674500212360ustar00rootroot00000000000000-----BEGIN CERTIFICATE----- MIIEQjCCAyqgAwIBAgIUK3QbxJq1Fxh92yf7qlq0NU4isXgwDQYJKoZIhvcNAQEL BQAwJTEjMCEGA1UEAwwaQUEgVHJpU29mdCBJbnRlcm1lZGlhdGUgQ0EwHhcNMjUw NzEzMDkzMzQ5WhcNMjYwNzEzMDkzMzQ5WjA+MRcwFQYDVQQDDA50cmlzb2Z0LmNv bS5wbDEjMCEGCSqGSIb3DQEJARYUZGVtbzNAdHJpc29mdC5jb20ucGwwggEiMA0G CSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDnTcm7NaS12tO9psWoMRRPxOUjDm38 xsmSj0K7GlnfSLG/2KqItqp0HuZaTSDNKspx7yhfTL40hW2cDnT4tAYT3G7SG9z+ n3/pu1wylu1LJeC7pdFJgays3M+K9tQ9I6wY7+puwjiHrYu4SZqntNMruXPAhXy9 Ty2LhSO+3oMB+AtK82UXvFcskw9I1IJu9VMvOnvJr61GQXxDOkGpbGmmNQ8XpPwm P87mOLyi0cUqN3eaEmCRTu0KmazeTVmcTw4gYqWr+Usqit5XjXJKa/Ms1KTGVKsk OIEVo3IK3hZVVCl79msExR2AnAp53oBzAOqPJKsywTNPgHdNon0CQCe7AgMBAAGj ggFPMIIBSzAMBgNVHRMBAf8EAjAAMB8GA1UdIwQYMBaAFLuhhALLAEAUz1v1QQzM 00vhi4lIMC0GA1UdHwQmMCQwIqAgoB6GHGh0dHA6Ly9jYS50cmlzb2Z0LmNvbS5w bC9jcmwwZgYIKwYBBQUHAQEEWjBYMCsGCCsGAQUFBzAChh9odHRwOi8vY2EudHJp c29mdC5jb20ucGwvY2FjZXJ0MCkGCCsGAQUFBzABhh1odHRwOi8vY2EudHJpc29m dC5jb20ucGwvb2NzcDAfBgNVHREEGDAWgRRkZW1vM0B0cmlzb2Z0LmNvbS5wbDAz BgNVHSUELDAqBggrBgEFBQcDAgYIKwYBBQUHAwQGCisGAQQBgjcKAwwGCCsGAQUF BwMkMB0GA1UdDgQWBBRYSlcpYIHkZ8xdetJFOMBv2dNGrDAOBgNVHQ8BAf8EBAMC A/gwDQYJKoZIhvcNAQELBQADggEBAGezAAq/XgUlOioryjG2t4rAno/WxX+Y13v3 tOAgsSYcUJ3H+lttteA9YWeUSul37rUzjNQzub4bg1RmzkR7PhMIPjDDkbaZyXn3 pTRtKAXIeWjTIRvqIDkHYjrlT9bC2oYTwlxXQ4FszumkdJBFEyr8JFs25i2SzRnK 0sW4hJTYZcIvv3015rW8GLDBLlpXjfR/1jiD662hCLc3ibFO0gjeTs4K1/TNGdzq ulH2NRqmD2rrD2hFP4uVsryOsTeSLoH/0RH+56yQhpuenLXnQzleKafMjvxuw90q 7ge+0lkykWXas/8wISMTgmOSbDl/49f+fTYKcBkKxjoBsK6XENc= -----END CERTIFICATE----- endesive-2.19.1/examples/ca/demo2_user3.crt.pem.cer000066400000000000000000000021061504236674500220130ustar00rootroot000000000000000B0*+tĚ}'Z5N"x0  *H  0%1#0!U AA TriSoft Intermediate CA0 250713093349Z 260713093349Z0>10U trisoft.com.pl1#0! *H  demo3@trisoft.com.pl0"0  *H 0 Mɻ5ӽŨ1O#mɒBYHتtZM *q(_L4mtn\2K%໥Iϊ=#n8I+s|O-#ރ JeW,HԂnS/:{ɯFA|C:Ali5&?8*7w`N MYO bK*WrJk,ԤT$8r UT){k yހs$23OwM}@'O0K0 U00U#0@[A KዉH0-U&0$0" http://ca.trisoft.com.pl/crl0f+Z0X0++0http://ca.trisoft.com.pl/cacert0)+0http://ca.trisoft.com.pl/ocsp0U0demo3@trisoft.com.pl03U%,0*++ +7  +$0UXJW)`g]zE8oF0U0  *H  g ^%:*+1{ &P[m=agJw33TfD{>>0Ñy4m(yh! 9b:Oچ\WCltE*$[6-Ÿe/}5浼.ZW8뭡7NN Q5jhE?7.笐C9^)̎n*Y2eڳ0!#cl9}6 p :endesive-2.19.1/examples/ca/demo2_user3.key.pem000066400000000000000000000033461504236674500212520ustar00rootroot00000000000000-----BEGIN RSA PRIVATE KEY----- Proc-Type: 4,ENCRYPTED DEK-Info: AES-256-CBC,6F74D43BFD983962443F8AA7E7B1474A O8kOPAT5Z3Ljy2cO5YHA6iPTlxZ9ES0RdhhT2liz6umjf07LksNPAfTY4uUvD6Qf dYuCxLCBiMhwEb2TH2m3kbKRPUNOGK9qWTsTNUMndL9m7SE3onagmmqNAwyvF/Kj 91kgcGU/lBPzJ+twVnN+1Zsy8uQysf48ousNZMjTTAx7kw7SEHer/oEVu7YeD28E tE4dWOxR3wC0wFWOZzjBPv9GSCDu1t5yn7r+ccTTE9CcvCbuZp1x/vtO0ALclQp3 befpgoCHeq/15MNSPRQdTf4ffWzgzTbP+1hyZfkGRDMYxjn3L4mRpJNfGqoxkb01 i5Fv810IFMf8qDmcKRI2jeh4BO5G1MKZhuiV//uyqYWfe8IU+2JKcLQ7lCHUrfPP 7HlV7tyvp24tScvRttAMvdfXWpGPZWyWbu4VxRrgK7T8F/zIWKpUhpuRl+mkLApa YM4mYXDRB16olk7pfWwDrYw8bonvlGQMCYZ+ZylhcSPmDdkxk7XsI30cfh2iHcSb UGsLcAuGM8l9ouemh7N1Q73VnV67Ln3L3G1os96au5fCEsh9Yeyykw3haBIvN5ip c+EGR/9pE4e9Dm6mjBwYvSo/smRHm4HvHs/h1Na6QtWm2/gjS16iNlb0O7CJQxkb +v+w1EyBZeME/gawVqdPw26U5o9sQCEnLxVJJ+ANx8UyR08brDUU/owrcBNyzlBt BL6Exqe7vFhMyEEmodZUvJG+Xi6N1EOYo1yrWeQto+cyVr/PhWpculQaroKvCC9L oZTyZiKcJhiHYDrgR20I0HWyySta4iSnhYrMeySlc6k6WFUx6HiG0Aln9x7Fx5ca 39r/deT2d1ixYyUmX5aqdIcAAqJGcjW5VAanxx4BeRBNhmFG4Ll0PNMLARg5p2kC D96ny4+n20CQmdhHQ+IfPCc2oaw8mavOR5e+RWwasqbHp8GBU6IYJ2rW8MW0FcYZ SFa3MtevQQS7algofOnmoiV5Hobn/p82j0MQXSd8L02shLplPcPfo3fy0UFCDRMz zJf1aokh3hT7nTQYNE6t0qxXc3bYyCpW3dof+LAyj8Q6pMalppPatVODx1n/PM9e AFiX2wqjN9Ud4EUHRrwoIitdDjjDeug68GDA1Cnyacd4JLmS5q6KMOjDQ9Y0HRiz Emw5S3li0gD0Gr4YhfFMEjzgwnOqC3LCLcYg6JeRcPBpBfIquRvxy4S+yC2ibQ9m qYhUSxYoIEkqVGRWk8C3aFTVagl3/fvw2llkVwmhozyLSWECprVa+haXICY6iO3q kx67WgjXAAQ08vwl0M+A4JZOSMuJM9/eilTwoKaaVZnLR+XY0/0RA9RvqRrgIwas 3h2NJlnkp4ihQzqMnqUoHFF+jB20rlnMg/w1MlxBLE2c2j9GfwfjPpKGJZ7gZHcE j1lVp7I4SEcGIPVzWJ6UsY2EE23X7AwAXEzePOiHkyJvPzAXIC2cyCafPmA64Gwe SSIIwDpJdjMIsoipU8oexTssJIFxScIrh/46xWTAyvqk2tbJ+74HGDIYx2VbOTpe quSJf55a0xIP+o4/nulypuS5B7n7q295GrAjsfkj4F+0cvgfyoOQtFy0BjwSmWm0 -----END RSA PRIVATE KEY----- endesive-2.19.1/examples/ca/demo2_user3.p12000066400000000000000000000075661504236674500203140ustar00rootroot000000000000000r0( *H 00 Z *H  K0 G0 @ *H 0_ *H  0R01 *H  0$y^5N/j4PN 0 *H  0 `He*.r] 5fvb,]KrHð~~n$%Tx琞^:=y7tͬU*mKIr\JZW~j*{zX_Uᣀ(ݝX:0OZy7TX};/e|F`3 wX~۔Z1*<z5C~^p jGT kbDF7hlpN<}XPX$3$4TTfٿ]WNB&TRXIrl8~t-Gh12W^ tb2 0@ʳM25oh M2nXQV6ޝӗpk>heeZ! Pt-i Cm/n 9DM);C3A咍%z\Ce2ix+OIx0n*ubF*D:a3*{;6bD2mUT%#-?m $Xvn6?zD<'F1Ys6Ĝg/V~k{눶ـX f;w;^k @DJhα,VDô_+*֕}gך)b.YdJx8pBr~vu+/ s)JDX"FC%@i`6"XK4~) X3mT<(L^]^m/NlFA&5.c|]^3տ3-}6DC\4uM82C[G)z)@cb{Zk? mI}oej;Kgy4x>$hgg`@@+do4dBwᕟ1O?1UsaΎ錮Dc5-wE;*OsFiWc>Ecuz[BK\i5kbg`.qj'"]K*bXsFdڐ%VJ-ֿ?UG=~ !଑N8W320|cj1 /"݊*ZLJ4, Ur8רC&x?lNqT⸲ Zڗe5a+jxi evj^)DYeQJ[ViS ߽жC^Y\g_4I؅`ۍg-+RpDD؏ng[ 寴зC_K;|f!6xS #=lMY3]@A&vFX ŰW(-/y6طҐk&[~?CJHF5'ʮ[I$W-LX^L5[?(I*e\_4rRO'=5=~q5"N'l4q3R +T5XVs'Ph$^Z=kO>|Ӳ MGuD3zd@uNWݷw3L =agN0iWSpHAF;y{/A z!3VFQO ԼnPY%漉ѪL?1[O=X9 ֺ֤tB TmQKufR"~Fqs]SAu&^RC'ۙͰv2=Ă %|&L~Yeeb,Ŀ">~⡔9]72A5 0 *H 00 *H  9050_ *H  0R01 *H  0$1:(=l)L12N 0 *H  0 `He*u϶³1F /Оje͋7jgоodݞ$ hLy1 1r 2D$3~! P۝iIIHӈ1 Uvo ]J89pMBMCUhޅ6T:Ӗw4_Ȭxňkp+cx ۥDdD3yOmF)+&9pKػ+ܹBaH=mLd{WJWHbrqÌ'LsoДV7_ WV0/y) A@P4Ə.fպ.c%"7HT<(a##Q$WYg;I \V=AZ>CeB1kha}ynLLG g2B>5MF69ϝURnՌؼ \ԱL&v "svKK0F}NY,u$yNJGݺ3e S̞s 8(_ mpG0&7Dw<@PmԌnәZ~Y #ș6-8p`S}K DcvE^ u˯6e:6/_7]ɯ)wdd߼vr[xb_7K̓"W^By WV,Erk908^0D ]f'#IlYULu`1ÐbWF%3԰3稐.&?;`&_LZ3LJ w?[o5h%܊rU͸a4EdՀt~0J:C]Έ4T1H0! *H  1USER cert0# *H  1!rr_^B 0A010  `He [{iS!m_:`\I0ˆf xendesive-2.19.1/examples/ca/demo2_user3.pub.pem000066400000000000000000000007031504236674500212420ustar00rootroot00000000000000-----BEGIN PUBLIC KEY----- MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA503JuzWktdrTvabFqDEU T8TlIw5t/MbJko9CuxpZ30ixv9iqiLaqdB7mWk0gzSrKce8oX0y+NIVtnA50+LQG E9xu0hvc/p9/6btcMpbtSyXgu6XRSYGsrNzPivbUPSOsGO/qbsI4h62LuEmap7TT K7lzwIV8vU8ti4Ujvt6DAfgLSvNlF7xXLJMPSNSCbvVTLzp7ya+tRkF8QzpBqWxp pjUPF6T8Jj/O5ji8otHFKjd3mhJgkU7tCpms3k1ZnE8OIGKlq/lLKoreV41ySmvz LNSkxlSrJDiBFaNyCt4WVVQpe/ZrBMUdgJwKed6AcwDqjySrMsEzT4B3TaJ9AkAn uwIDAQAB -----END PUBLIC KEY----- endesive-2.19.1/examples/cert-info-hsm.py000077500000000000000000000061631504236674500202760ustar00rootroot00000000000000#!/usr/bin/env vpython3 # *-* coding: utf-8 *-* import sys from endesive import pdf, hsm import os import sysconfig os.environ['SOFTHSM2_CONF'] = 'softhsm2.conf' if not os.path.exists(os.path.join(os.getcwd(), 'softhsm2.conf')): open('softhsm2.conf', 'wt').write('''\ log.level = DEBUG directories.tokendir = %s/softhsm2/ objectstore.backend = file slots.removable = false ''' % os.getcwd()) if not os.path.exists(os.path.join(os.getcwd(), 'softhsm2')): os.mkdir(os.path.join(os.getcwd(), 'softhsm2')) # #!/bin/bash #SOFTHSM2_CONF=softhsm2.conf #softhsm2-util --label "endesive" --slot 1 --init-token --pin secret1 --so-pin secret2 #softhsm2-util --show-slots # if sys.platform == 'win32': dllpath = r'W:\binw\SoftHSM2\lib\softhsm2-x64.dll' else: dllpath = os.path.join(sysconfig.get_config_var('LIBDIR'), "softhsm/libsofthsm2.so") import PyKCS11 as PK11 class Signer(hsm.HSM): def certificate(self): self.login("endesieve", "secret1") keyid = bytes((0x66,0x66,0x90)) try: pk11objects = self.session.findObjects([(PK11.CKA_CLASS, PK11.CKO_CERTIFICATE)]) all_attributes = [ #PK11.CKA_SUBJECT, PK11.CKA_VALUE, #PK11.CKA_ISSUER, #PK11.CKA_CERTIFICATE_CATEGORY, #PK11.CKA_END_DATE, PK11.CKA_ID, ] for pk11object in pk11objects: try: attributes = self.session.getAttributeValue(pk11object, all_attributes) except PK11.PyKCS11Error as e: continue attrDict = dict(list(zip(all_attributes, attributes))) cert = bytes(attrDict[PK11.CKA_VALUE]) if keyid == bytes(attrDict[PK11.CKA_ID]): return keyid, cert finally: self.logout() return None, None def sign(self, keyid, data, mech): self.login("endesieve", "secret1") try: privKey = self.session.findObjects([(PK11.CKA_CLASS, PK11.CKO_PRIVATE_KEY), (PK11.CKA_ID, keyid)])[0] mech = getattr(PK11, 'CKM_%s_RSA_PKCS' % mech.upper()) sig = self.session.sign(privKey, data, PK11.Mechanism(mech, None)) return bytes(sig) finally: self.logout() import binascii from cryptography.hazmat import backends from cryptography.hazmat.primitives import hashes, serialization from cryptography.hazmat.primitives.asymmetric import padding from cryptography.hazmat.primitives.serialization import pkcs12 from asn1crypto import x509, pem def cert2asn(cert, cert_bytes=True): if isinstance(cert, x509.Certificate): return cert if cert_bytes: cert_bytes = cert.public_bytes(serialization.Encoding.PEM) else: cert_bytes = cert if pem.detect(cert_bytes): _, _, cert_bytes = pem.unarmor(cert_bytes) return x509.Certificate.load(cert_bytes) def main(): hsm = Signer(dllpath) hsm.login("endesieve", "secret1") keyid = bytes((0x66,0x66,0x90)) ic = hsm.cert_load(keyid) hsm.logout() print(ic) ic = cert2asn(ic, False) print(ic) main() endesive-2.19.1/examples/cert-info-p12.py000077500000000000000000000022461504236674500201070ustar00rootroot00000000000000#!/usr/bin/env vpython3 # *-* coding: utf-8 *-* import sys import pprint import binascii from cryptography.hazmat import backends from cryptography.hazmat.primitives import hashes, serialization from cryptography.hazmat.primitives.asymmetric import padding from cryptography.hazmat.primitives.serialization import pkcs12 from asn1crypto import x509, pem def cert2asn(cert): cert_bytes = cert.public_bytes(serialization.Encoding.PEM) if pem.detect(cert_bytes): _, _, cert_bytes = pem.unarmor(cert_bytes) return x509.Certificate.load(cert_bytes) def main(): if len(sys.argv) == 3: p12name = sys.argv[1] p12pass = sys.argv[2] else: p12name = 'ca/demo2_user1.p12' p12pass = '1234' print(len(sys.argv), p12name, p12pass) with open(p12name, 'rb') as fp: p12pk, p12pc, p12oc = pkcs12.load_key_and_certificates(fp.read(), p12pass.encode(), backends.default_backend()) signature = p12pk.sign( b"message", padding.PKCS1v15(), hashes.SHA1() ) cert = cert2asn(p12pc) print('issuer', cert.issuer.native) print('subject', cert.subject.native) pprint.pprint(cert.native) main() endesive-2.19.1/examples/cert-info-pem.py000077500000000000000000000013371504236674500202660ustar00rootroot00000000000000#!/usr/bin/env vpython3 # *-* coding: utf-8 *-* import sys import pprint import binascii from cryptography.hazmat import backends from cryptography.hazmat.primitives import hashes, serialization from cryptography.hazmat.primitives.asymmetric import padding from cryptography.hazmat.primitives.serialization import pkcs12 from asn1crypto import x509, pem def cert2asn(cert_bytes): if pem.detect(cert_bytes): _, _, cert_bytes = pem.unarmor(cert_bytes) return x509.Certificate.load(cert_bytes) def main(): if len(sys.argv) == 2: pemname = sys.argv[1] else: pemname = 'ca/demo2_ca.sub.crt.pem' data = open(pemname, 'rb').read() cert = cert2asn(data) pprint.pprint(cert.native) main() endesive-2.19.1/examples/cert-install000077500000000000000000000002031504236674500175620ustar00rootroot00000000000000#!/bin/bash # sudo ./cert-install cp ca/demo2_ca.root.crt.pem /usr/share/ca-certificates/mozilla/ update-ca-certificates --default endesive-2.19.1/examples/cert-make-hsm.py000077500000000000000000000047701504236674500202620ustar00rootroot00000000000000#!/usr/bin/env vpython3 # coding: utf-8 import os import sys import sysconfig if "--force" in sys.argv: if os.path.exists(os.path.join(os.getcwd(), 'softhsm2')): import shutil shutil.rmtree(os.path.join(os.getcwd(), 'softhsm2')) os.environ['SOFTHSM2_CONF'] = 'softhsm2.conf' if not os.path.exists(os.path.join(os.getcwd(), 'softhsm2.conf')): open('softhsm2.conf', 'wt').write('''\ log.level = DEBUG directories.tokendir = %s/softhsm2/ objectstore.backend = file slots.removable = false ''' % os.getcwd()) if not os.path.exists(os.path.join(os.getcwd(), 'softhsm2')): os.mkdir(os.path.join(os.getcwd(), 'softhsm2')) # #!/bin/bash #SOFTHSM2_CONF=softhsm2.conf #softhsm2-util --label "endesive" --slot 1 --init-token --pin secret1 --so-pin secret2 #softhsm2-util --show-slots # if sys.platform == 'win32': dllpath = r'W:\binw\SoftHSM2\lib\softhsm2-x64.dll' else: dllpath = os.path.join(sysconfig.get_config_var('LIBDIR'), "softhsm/libsofthsm2.so") from endesive import hsm import PyKCS11 as PK11 ''' Create two certificates: 1. self signed hsm CA certificate with serial equal to HSM keyID=0x01 2. hsm USER 1 certificate with serial equal to HSM keyID=0x666690 ''' class HSM(hsm.HSM): def main(self): rootcakeyID = bytes((0x1,)) rec = self.session.findObjects([(PK11.CKA_CLASS, PK11.CKO_PRIVATE_KEY), (PK11.CKA_ID, rootcakeyID)]) if len(rec) == 0: label = 'hsm Root CA' self.gen_privkey(label, rootcakeyID) self.ca_gen(label, rootcakeyID, label) self.cert_export('cert-hsm-ca-root', rootcakeyID) cakeyID = bytes((0x2,)) rec = self.session.findObjects([(PK11.CKA_CLASS, PK11.CKO_PRIVATE_KEY), (PK11.CKA_ID, cakeyID)]) if len(rec) == 0: label = 'hsm Intermediate CA' self.gen_privkey(label, cakeyID) self.ca_sign(cakeyID, label, 2, label, 365 * 10, rootcakeyID) self.cert_export('cert-hsm-ca-sub', cakeyID) keyID = bytes((0x66,0x66,0x90)) rec = self.session.findObjects([(PK11.CKA_CLASS, PK11.CKO_PRIVATE_KEY), (PK11.CKA_ID, keyID)]) if len(rec) == 0: label = 'hsm USER 1' self.gen_privkey(label, keyID) self.ca_sign(keyID, label, 0x666690, "hsm USER 1", 365, cakeyID) self.cert_export('cert-hsm-user1', keyID) def main(): cls = HSM(dllpath) cls.create("endesieve", "secret1", "secret2") cls.login("endesieve", "secret1") try: cls.main() finally: cls.logout() main() endesive-2.19.1/examples/cert-make.py000077500000000000000000000444451504236674500175000ustar00rootroot00000000000000#!/usr/bin/env vpython3 # *-* coding: utf-8 *-* import typing import datetime import os, os.path import sys import glob import uuid from asn1crypto.core import UTF8String from cryptography import x509 from cryptography.hazmat.backends import default_backend from cryptography.hazmat.primitives import serialization, hashes from cryptography.hazmat.primitives.asymmetric import rsa from cryptography.hazmat.primitives.serialization import pkcs12 from cryptography.x509.oid import NameOID, ExtendedKeyUsageOID force = "--force" in sys.argv ( ca_root, ca_root_key, ca_sub, ca_sub_key, cert1, cert1_key, cert1_pub, cert1_p12, cert2, cert2_key, cert2_pub, cert2_p12, cert3, cert3_key, cert3_pub, cert3_p12, ) = ( "demo2_ca.root.crt.pem", "demo2_ca.root.key.pem", "demo2_ca.sub.crt.pem", "demo2_ca.sub.key.pem", "demo2_user1.crt.pem", "demo2_user1.key.pem", "demo2_user1.pub.pem", "demo2_user1.p12", "demo2_user2.crt.pem", "demo2_user2.key.pem", "demo2_user2.pub.pem", "demo2_user2.p12", "demo2_user3.crt.pem", "demo2_user3.key.pem", "demo2_user3.pub.pem", "demo2_user3.p12", ) class Main(object): def key_create(self) -> rsa.RSAPrivateKey: return rsa.generate_private_key( public_exponent=65537, key_size=2048, backend=default_backend() ) def key_save(self, fname: str, key: rsa.RSAPrivateKey, password: str) -> None: # Write our key to disk for safe keeping with open(os.path.join("ca", fname), "wb") as f: if not password: f.write( key.public_key().public_bytes( encoding=serialization.Encoding.PEM, format=serialization.PublicFormat.SubjectPublicKeyInfo, ) ) else: f.write( key.private_bytes( encoding=serialization.Encoding.PEM, format=serialization.PrivateFormat.TraditionalOpenSSL, encryption_algorithm=serialization.BestAvailableEncryption( password.encode("utf-8") ), ) ) def key_load(self, fname: str, password: str) -> rsa.RSAPrivateKey: with open(os.path.join("ca", fname), "rb") as f: private_key = serialization.load_pem_private_key( f.read(), password.encode("utf-8"), default_backend() ) return private_key def cert_save(self, fname: str, data: x509.Certificate) -> None: with open(os.path.join("ca", fname), "wb") as f: f.write(data.public_bytes(serialization.Encoding.PEM)) with open(os.path.join("ca", fname) + ".cer", "wb") as f: f.write(data.public_bytes(serialization.Encoding.DER)) cwd = os.getcwd() os.chdir("ca") os.symlink(fname, str(data.serial_number)) os.chdir(cwd) def cert_load(self, fname: str) -> x509.Certificate: with open(os.path.join("ca", fname), "rb") as f: return x509.load_pem_x509_certificate(f.read(), default_backend()) def csr_load(self, fname: str) -> x509.CertificateSigningRequest: with open(os.path.join("ca", fname), "rb") as f: return x509.load_pem_x509_csr(data=f.read(), backend=default_backend()) def csr_create( self, email: str, key: rsa.RSAPrivateKey, country: typing.Union[str, None] = None, state: typing.Union[str, None] = None, locality: typing.Union[str, None] = None, organization: typing.Union[str, None] = None, commonname: typing.Union[str, None] = None, ) -> x509.CertificateSigningRequest: names = [] for t, v in ( (NameOID.COUNTRY_NAME, country), (NameOID.STATE_OR_PROVINCE_NAME, state), (NameOID.LOCALITY_NAME, locality), (NameOID.ORGANIZATION_NAME, organization), (NameOID.COMMON_NAME, commonname), ): if v: names.append(x509.NameAttribute(t, v)) names.append(x509.NameAttribute(NameOID.EMAIL_ADDRESS, email)) return ( x509.CertificateSigningRequestBuilder() .subject_name(x509.Name(names)) .sign( # Sign the CSR with our private key. key, hashes.SHA256(), default_backend(), ) ) def csr_sign(self, csr: x509.CertificateSigningRequest) -> x509.Certificate: emails = csr.subject.get_attributes_for_oid(NameOID.EMAIL_ADDRESS) names = [ x509.RFC822Name(emails[0].value), #x509.OtherName( # x509.ObjectIdentifier('1.3.6.1.4.1.311.20.2.3'), # #'john.doe@domain.tld'.encode("utf-8") # UTF8String('john.doe@domain.tld').dump() #), #x509.DNSName('trisoft.com.pl'), ] return ( x509.CertificateBuilder() .subject_name(csr.subject) .issuer_name(self.ca_sub_cert.subject) .public_key(csr.public_key()) .serial_number(x509.random_serial_number()) .not_valid_before(datetime.datetime.utcnow()) .not_valid_after(datetime.datetime.utcnow() + datetime.timedelta(days=365)) .add_extension( x509.BasicConstraints(ca=False, path_length=None), critical=True ).add_extension( x509.AuthorityKeyIdentifier.from_issuer_public_key( self.ca_sub_pk.public_key() ), critical=False, ).add_extension( x509.CRLDistributionPoints( [ x509.DistributionPoint( full_name=[ x509.UniformResourceIdentifier( "http://ca.trisoft.com.pl/crl" ) ], relative_name=None, reasons=None, crl_issuer=None, ) ] ), critical=False, ).add_extension( x509.AuthorityInformationAccess( [ x509.AccessDescription( x509.OID_CA_ISSUERS, x509.UniformResourceIdentifier( "http://ca.trisoft.com.pl/cacert" ), ), x509.AccessDescription( x509.OID_OCSP, x509.UniformResourceIdentifier( "http://ca.trisoft.com.pl/ocsp" ), ), ] ), critical=False, ).add_extension( x509.SubjectAlternativeName(names), critical=False, ).add_extension( # certificate_policies x509.ExtendedKeyUsage([ x509.OID_CLIENT_AUTH, # 1.3.6.1.5.5.7.3.2 #x509.OID_SERVER_AUTH, x509.OID_EMAIL_PROTECTION, x509.ObjectIdentifier("1.3.6.1.4.1.311.10.3.12"), # document signing x509.ObjectIdentifier("1.3.6.1.5.5.7.3.36"), # document signing #x509.ObjectIdentifier("1.3.6.1.5.5.7.3.21"), # ssh client #x509.ObjectIdentifier("1.3.6.1.5.5.7.3.22"), # ssh server #1.2.840.113583.1.1.7.1.0 .. 11 # https://www.adobe.com/devnet-docs/acrobatetk/tools/DigSigDC/oids.html ]), critical=False, ).add_extension( x509.SubjectKeyIdentifier.from_public_key(csr.public_key()), critical=False, ).add_extension( x509.KeyUsage( # Digital Signature: Indicates that the key can be used for digital signatures to verify the authenticity and integrity of data. digital_signature=True, # Non-Repudiation: Used in conjunction with digital signatures to provide an additional layer of protection against denial of signature. content_commitment=True, # nonRepudiation # Key Encipherment: Specifies that the key can be used for encrypting other keys, typically for key transport. key_encipherment=True, # Data Encipherment: Indicates that the key can be used for data encryption and decryption. data_encipherment=True, # Key Agreement: Used when the key is involved in key exchange agreements, such as Diffie-Hellman. key_agreement=True, # Encipher Only: Specifies that the key can only be used for encryption, not decryption. encipher_only=False, # Decipher Only: Specifies that the key can only be used for decryption, not encryption. decipher_only=False, # ca # Certificate Signing: Specifies that the key can be used to sign other certificates, typically used by Certificate Authorities. key_cert_sign=False, # CRL Signing: Indicates that the key can be used to sign Certificate Revocation Lists (CRLs). crl_sign=False, ), critical=True, ).sign( private_key=self.ca_sub_pk, algorithm=hashes.SHA256(), backend=default_backend(), ) ) def pk12_save( self, name: bytes, cert: x509.Certificate, key: rsa.RSAPrivateKey, fname: str, password: str, ) -> None: data = pkcs12.serialize_key_and_certificates( name=name, key=key, cert=cert, cas=[self.ca_sub_cert], encryption_algorithm=serialization.BestAvailableEncryption( password.encode("utf8") ), ) with open(os.path.join("ca", fname), "wb") as f: f.write(data) def pk12_load(self, fname: str, password: str) -> pkcs12.PKCS12KeyAndCertificates: with open(os.path.join("ca", fname), "rb") as fp: return pkcs12.load_key_and_certificates( fp.read(), password.encode("utf-8"), default_backend() ) def ca_createroot(self, key: rsa.RSAPrivateKey) -> x509.Certificate: subject = issuer = x509.Name( [ x509.NameAttribute(NameOID.COMMON_NAME, "AA TriSoft Root CA"), ] ) return ( x509.CertificateBuilder() .subject_name(subject) .issuer_name(issuer) .public_key(key.public_key()) .serial_number(x509.random_serial_number()) .not_valid_before(datetime.datetime.utcnow()) .not_valid_after( # Our certificate will be valid for 40 years datetime.datetime.utcnow() + datetime.timedelta(days=40 * 365) ).add_extension( x509.BasicConstraints( ca=True, path_length=None, # pathlen: is equal to the number of CAs/ICAs it can sign ), critical=True, ).add_extension( x509.AuthorityKeyIdentifier.from_issuer_public_key(key.public_key()), critical=False, ).add_extension( x509.SubjectKeyIdentifier.from_public_key(key.public_key()), critical=False, ).add_extension( x509.KeyUsage( digital_signature=True, content_commitment=False, # nonRepudiation key_encipherment=False, data_encipherment=False, key_agreement=False, encipher_only=False, decipher_only=False, # ca key_cert_sign=True, crl_sign=True, ), critical=True, ).sign( # Sign our certificate with our private key key, hashes.SHA256(), default_backend(), ) ) def ca_createsub(self, key: rsa.RSAPrivateKey, rootcert: x509.Certificate, rootkey: rsa.RSAPrivateKey) -> x509.Certificate: subject = x509.Name( [ x509.NameAttribute(NameOID.COMMON_NAME, "AA TriSoft Intermediate CA"), ] ) return ( x509.CertificateBuilder() .subject_name(subject) .issuer_name(rootcert.subject) .public_key(key.public_key()) .serial_number(x509.random_serial_number()) .not_valid_before(datetime.datetime.utcnow()) .not_valid_after( # Our certificate will be valid for 10 years datetime.datetime.utcnow() + datetime.timedelta(days=10 * 365) ).add_extension( x509.BasicConstraints( ca=True, path_length=0, # pathlen: is equal to the number of CAs/ICAs it can sign ), critical=True, ).add_extension( x509.CRLDistributionPoints( [ x509.DistributionPoint( full_name=[ x509.UniformResourceIdentifier( "http://ca.trisoft.com.pl/crl" ) ], relative_name=None, reasons=None, crl_issuer=None, ) ] ), critical=False, ).add_extension( x509.AuthorityInformationAccess( [ x509.AccessDescription( x509.OID_CA_ISSUERS, x509.UniformResourceIdentifier( "http://ca.trisoft.com.pl/cacert" ), ), x509.AccessDescription( x509.OID_OCSP, x509.UniformResourceIdentifier( "http://ca.trisoft.com.pl/ocsp" ), ), ] ), critical=False, ).add_extension( x509.AuthorityKeyIdentifier.from_issuer_subject_key_identifier( rootcert.extensions.get_extension_for_class(x509.SubjectKeyIdentifier).value ), critical=False, ).add_extension( x509.SubjectKeyIdentifier.from_public_key(key.public_key()), critical=False, ).add_extension( x509.KeyUsage( digital_signature=True, content_commitment=False, # nonRepudiation key_encipherment=False, data_encipherment=False, key_agreement=False, encipher_only=False, decipher_only=False, # ca key_cert_sign=True, crl_sign=True, ), critical=True, ).sign( # Sign our certificate with our private key rootkey, hashes.SHA256(), default_backend(), ) ) def CA(self) -> None: create = force or not ( os.path.exists(os.path.join("ca", ca_sub)) and os.path.exists(os.path.join("ca", ca_sub_key)) ) if create: for fqname in glob.glob("ca/*"): os.unlink(fqname) print("CA generating certificate") ca_root_pk = self.key_create() ca_root_cert = self.ca_createroot(ca_root_pk) self.key_save(ca_root_key, ca_root_pk, "1234") self.cert_save(ca_root, ca_root_cert) ca_sub_pk = self.key_create() ca_sub_cert = self.ca_createsub(ca_sub_pk, ca_root_cert, ca_root_pk) self.key_save(ca_sub_key, ca_sub_pk, "1234") self.cert_save(ca_sub, ca_sub_cert) else: print("CA using certificate") ca_root_pk = self.key_load(ca_root_key, "1234") ca_root_cert = self.cert_load(ca_root) ca_sub_pk = self.key_load(ca_sub_key, "1234") ca_sub_cert = self.cert_load(ca_sub) self.ca_root_cert = ca_root_cert self.ca_root_pk = ca_root_pk self.ca_sub_cert = ca_sub_cert self.ca_sub_pk = ca_sub_pk def USER(self, no, cert, cert_key, cert_pub, cert_p12) -> None: create = force or not ( os.path.exists(os.path.join("ca", cert)) and os.path.exists(os.path.join("ca", cert_key)) and os.path.exists(os.path.join("ca", cert_pub)) and os.path.exists(os.path.join("ca", cert_p12)) ) if create: client_pk = self.key_create() client_csr = self.csr_create( "demo%d@trisoft.com.pl" % no, client_pk, commonname='trisoft.com.pl', ) client_cert = self.csr_sign(client_csr) self.cert_save(cert, client_cert) self.key_save(cert_key, client_pk, "1234") self.key_save(cert_pub, client_pk, None) self.pk12_save( "USER cert".encode("utf-8"), client_cert, client_pk, cert_p12, "1234" ) # os.chmod(pkcs12 % user, stat.S_IRUSR | stat.S_IWUSR) # 0o600 perms def USERs(self): self.USER(1, cert1, cert1_key, cert1_pub, cert1_p12) self.USER(2, cert2, cert2_key, cert2_pub, cert2_p12) self.USER(3, cert3, cert3_key, cert3_pub, cert3_p12) print("Generating certificates") cls = Main() cls.CA() cls.USERs() endesive-2.19.1/examples/certum.py000066400000000000000000000006061504236674500171130ustar00rootroot00000000000000import sys if sys.platform == "win32": dllpath = r"c:\windows\system32\cryptoCertum3PKCS.dll" else: import ctypes as ct if 1: openssl_1_1 = [ ct.CDLL('/usr/lib/x86_64-linux-gnu/libcrypto.so', ct.RTLD_GLOBAL), ct.CDLL('/usr/lib/x86_64-linux-gnu/libssl.so', ct.RTLD_GLOBAL), ] dllpath = '/devel/lib/pkcs11libs/libcryptoCertum3PKCS.so' endesive-2.19.1/examples/certum/000077500000000000000000000000001504236674500165375ustar00rootroot00000000000000endesive-2.19.1/examples/certum/enveloped-t.xml000066400000000000000000000320161504236674500215050ustar00rootroot00000000000000 VAT-7 17 1 2017 2 3215 7791011327 Nazwa firmy 630303023 0 3108 3108 0 0 998293 49915 901697 72135 3334214 766869 3177289 187401 44326 8864 0 0 0 0 66801 15364 0 0 0 0 0 0 0 0 0 8713129 913147 512089 54480 12531 8152972 1279013 0 0 -138 1380 1804875 0 0 0 0 891728 0 0 0 0 891728 2 2 2 914842496 2017-05-09 1 not(ancestor-or-self::ds:Signature)TDvzyhJhtfEyOX3o5bpsjwsOIUAx6m1ye+qf4culo3g=WKT7AdMwsLp0rRTqb9D81r2jIXlXbOi8xrVzYwnXduU=MFh5o+hbIGNpd4kfaj6EcH3utDRiruFXpR28MSLN9tjd3z44WX6/jnbHlJGADp9O rKJlkanS5QclkdUNihiRYyeuq7lPwY+1Clo8bNamzR2lyBfBLDGBnLuidHvLPLsi KD5ntq8/8Y2xP83GycAzsTV/qyPd/fIcUwgTejR+cglpKRrhhc6z4sfMx8/0cCVJ c+CzgxUn6c1v7+xOAe3PrIB7yUtV+EHZVL/ZEf+VDwQKI9xopcKn9zYLYx1F8R9H vl1sDDFcCYX6R6R4d8PG2MgUoMAeKGcspZnbioINi7CYLH9P33Wn8cpietnU7xyK jS+vFA8n45OgWjbKV+iiXQ==MIIHeTCCBWGgAwIBAgIQP6Zj23WXXaawMu8t3MSN6DANBgkqhkiG9w0BAQsFADBl MQswCQYDVQQGEwJQTDEhMB8GA1UECgwYQXNzZWNvIERhdGEgU3lzdGVtcyBTLkEu MRgwFgYDVQQDDA9DZXJ0dW0gUUNBIDIwMTcxGTAXBgNVBGEMEFZBVFBMLTUxNzAz NTk0NTgwHhcNMTkwMjIxMDYwMDAwWhcNMjEwMjIwMDYwMDAwWjBpMRkwFwYDVQQD DBBEYXJpdXN6IE1hamV3c2tpMRAwDgYDVQQqDAdEYXJpdXN6MREwDwYDVQQEDAhN YWpld3NraTEaMBgGA1UEBRMRUE5PUEwtNjIwMjE2MDQ2MTYxCzAJBgNVBAYTAlBM MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAzUt3RBeGDmhzz53Lzvcf zuT3dNiwZZrwPGVBfyXKjdHRrM0yegoegB/2z/5EJy7oMLB6X73BYElYJHINq6HH gFECckdombrEoyFyfCFEGp+6SkJS6KzICxTYrC/NcigAqC+LcoYJb3bdeRq12c8/ KjF3aU1pfa+sFUSTKVEpCPOTHYLkH/j3/yP4b72smAH+FNkZqzws0CMWFK37CrRw fpap5rsSCWqa8mQD/kYjEoP4DWE9QBxa/f3ay5QgyLnQ6Wjb/+CiiaXgySmzeoTE JlaajOrJ/25K2H6EpIKMaCnWBJ7/Vvii9Pb1QIHBr5fJf68aNbQLtRctAfLsm7V2 8QIDAQABo4IDHzCCAxswDAYDVR0TAQH/BAIwADA2BgNVHR8ELzAtMCugKaAnhiVo dHRwOi8vcWNhLmNybC5jZXJ0dW0ucGwvcWNhXzIwMTcuY3JsMHIGCCsGAQUFBwEB BGYwZDAsBggrBgEFBQcwAYYgaHR0cDovL3FjYS0yMDE3LnFvY3NwLWNlcnR1bS5j b20wNAYIKwYBBQUHMAKGKGh0dHA6Ly9yZXBvc2l0b3J5LmNlcnR1bS5wbC9xY2Ff MjAxNy5jZXIwHwYDVR0jBBgwFoAUJ/HYTmBQaLZh/mgbKGxt5AtzCU0wHQYDVR0O BBYEFKdCzxALmtKNEeOdaLS/Uh7WevmAMA4GA1UdDwEB/wQEAwIGwDCCAUgGA1Ud IASCAT8wggE7MAkGBwQAi+xAAQIwggEsBgwqhGgBhvZ3AgQBDAEwggEaMC0GCCsG AQUFBwIBFiFodHRwOi8vd3d3LmNlcnR1bS5wbC9yZXBvenl0b3JpdW0wgegGCCsG AQUFBwICMIHbMB8WGEFzc2VjbyBEYXRhIFN5c3RlbXMgUy5BLjADAgEBDIG3Q2Vy dGlmaWNhdGUgUG9saWN5IGFuZCBDZXJ0aWZpY2F0aW9uIFByYWN0aWNlIFN0YXRl bWVudCBvZiBDZXJ0dW0ncyBRdWFsaWZpZWQgQ2VydGlmaWNhdGlvbiBTZXJ2aWNl cy4gTW9yZSBpbmZvcm1hdGlvbiBjYW4gYmUgZm91bmQgaW4gdGhlIENlcnRpZmlj YXRlIFBvbGljeSBvbiBodHRwczovL3d3dy5jZXJ0dW0uZXUuMIHCBggrBgEFBQcB AwSBtTCBsjAIBgYEAI5GAQEwCAYGBACORgEEMIGGBgYEAI5GAQUwfDA8FjZodHRw czovL3JlcG9zaXRvcnkuY2VydHVtLnBsL1BEUy9DZXJ0dW1fUUNBLVBEU19FTi5w ZGYTAmVuMDwWNmh0dHBzOi8vcmVwb3NpdG9yeS5jZXJ0dW0ucGwvUERTL0NlcnR1 bV9RQ0EtUERTX1BMLnBkZhMCcGwwEwYGBACORgEGMAkGBwQAjkYBBgEwDQYJKoZI hvcNAQELBQADggIBAGXD5An9jvqtjPhvGreSGBBU/QWe8zOmEIDt1k6xlEbmbWnC WGKFOP+UMtSuKaQLyViBZASB0cYvXByriBn6XuUKba9zAQIhisfiqd4rFbDihSaj xn4ub4s1lr4JeZmbbRjg7LmdxY5zbjjOoLRCA8LJojflrkSZOX9fRaTSzLX47IS/ i/c4GuI03Y9DwUzRAtHOre60r/dmG3Unwvl1+LbYLzwvaIye8n/o91CRA4+mc6eK M1yBiQRCJbtShy8V8yrJPb9d1s4VO3EptY5PIWFIIIUz9sg2SsOWRxTv3Zl35GJ0 IT4xsMDhCmmpfoCOK4jZSjZclG+A95PN4d0737EosQxojcFQOMMQNsPQ34axqu6D cHAVqWiHvQvnDFvsROtlzWcOxdwcnemfmdN4qOEndOPYInkcAJ5Nmzxp5SiH/EHz 8FphyIi87kc6PmW0ancHHoxZB59CiJiAuxFp3ULryxH8RGt/IIjN4WqOPdq2y7f6 OJ3T6UbWX5wdhsIVQl7ZMFsuG5S6MjbRJLWoCWPgV49yTz149hf142saG5PWi7Tz ams9vAIwfNvIpismhKdN3+IrpK9UCvf9vSqP1JnlRxUo7qb2VyX8qN+PqtixWfs7 uPb7NtsAmbMZJFWwotHMCq6d/CwTWm1oJPCh3HLQIujuCYRr4JmPbFvQfiyv2020-11-24T00:34:35ZwnJg+5guQblWVpTXg+djFHlCdB/NAcI4Ts21xCGR6jE=2.5.4.97=#0C10564154504C2D35313730333539343538,CN=Certum QCA 2017,O=Asseco Data Systems S.A.,C=PL84605310358877569721335889391052426728MIME-Version: 1.0 Content-Type: text/xml Content-Transfer-Encoding: binary Content-Disposition: filename="enveloped-t.xml"http://www.certum.pl/OIDAsURI/signedFile/1.2.616.1.113527.3.1.1.3.1Opis formatu dokumentu oraz jego pełna nazwahttp://www.certum.pl/OIDAsURI/signedFile.pdftext/xmlMIIL/wYJKoZIhvcNAQcCoIIL8DCCC+wCAQMxDTALBglghkgBZQMEAgEwggEPBgsq hkiG9w0BCRABBKCB/wSB/DCB+QIBAQYLKoRoAYb2dwIEAQ4wMTANBglghkgBZQME AgEFAAQgQK5JNEChIaBQyAoULT/6P7pggPZ83B9V2pqdAcfhYt8CBxHDeUvoYroY DzIwMjAxMTI0MDAzNDM3WjADAgEBAgkAgmXpougiAU+gaqRoMGYxCzAJBgNVBAYT AlBMMSEwHwYDVQQKDBhBc3NlY28gRGF0YSBTeXN0ZW1zIFMuQS4xGTAXBgNVBAMM EENlcnR1bSBRVFNUIDIwMTcxGTAXBgNVBGEMEFZBVFBMLTUxNzAzNTk0NTihHjAc BggrBgEFBQcBAwEBAAQNMAswCQYHBACBl14BAaCCBqQwggagMIIEiKADAgECAhQR k3NfF8F+FE0/ko9hm7/VAn2x6TANBgkqhkiG9w0BAQ0FADBvMQswCQYDVQQGEwJQ TDEdMBsGA1UECgwUTmFyb2Rvd3kgQmFuayBQb2xza2kxJjAkBgNVBAMMHU5hcm9k b3dlIENlbnRydW0gQ2VydHlmaWthY2ppMRkwFwYDVQRhDBBWQVRQTC01MjUwMDA4 MTk4MB4XDTE3MDMxNTEwMjMxOFoXDTI4MDMxNTIzNTk1OVowZjELMAkGA1UEBhMC UEwxITAfBgNVBAoMGEFzc2VjbyBEYXRhIFN5c3RlbXMgUy5BLjEZMBcGA1UEAwwQ Q2VydHVtIFFUU1QgMjAxNzEZMBcGA1UEYQwQVkFUUEwtNTE3MDM1OTQ1ODCCAiIw DQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAMhUEU2e8zcRK0C3DftH+TcIdnT6 jBd3WfTqHUiQtX+aDgTo+a6tSGVcACaMV97NsexP8jPNQ2Y3eHbmUDwL8X+XHQAB KWNd5LxgJ0VJD0RMrU2OzISrfA9FVowWQU2ay4SOI22JKLJy6c4FXgGBPhng2PRM WzE7GUjsXXwTxhbQdP0KsMxSu4wMsD89bkh3pjJRAJ8k6i4gza6gPGc5jL8efvL5 2hYVoeby2xSyO7q3dksmw+2HEnCjVh9c1v6emtBbTE9ZTdxkG1wCMeR7N1FS0Tm4 C6b983YJKPbMjjqXJK2X/dxAc/eVvUJa5HpJR5O6kH6pG1IW7/MJ4SowaMeIn8Rp IDA8ZBre0nqy8wOsVkt939KkpgsvpuA0cYkcaEzzbHC7pLDcPYcxJ7+P6xQTIOTZ Fab5FyyigVoIvzW+4G56uFwGlBCj6B+Op5mK1YZ4VfXUQyT3CLQYUbUwKesqztPW yiw1oWjHJ1+aPsjwhvof/XAHv5dOJWLHBmi8BCwl8MRYUfHBKdu0OYTQRCMwNTHg Ssxfutuj6I/m/6yoHbOW9aEBSdCXtBrxAb6OAA7V/LadbQ6BoMzf86JMIo2eX84L CL9xa6XAFSN+jn/OG45OpOIz42yRPerkcjI04h1m3j7jAHwDsdcWAEBvZlY9pWVe hOFlAmimlffOQtnjAgMBAAGjggE7MIIBNzAWBgNVHSUBAf8EDDAKBggrBgEFBQcD CDAMBgNVHRMBAf8EAjAAMIGsBgNVHSMEgaQwgaGAFCmzyMTfo4f4ZgUSWP1GKriY DXmHoXOkcTBvMQswCQYDVQQGEwJQTDEdMBsGA1UECgwUTmFyb2Rvd3kgQmFuayBQ b2xza2kxJjAkBgNVBAMMHU5hcm9kb3dlIENlbnRydW0gQ2VydHlmaWthY2ppMRkw FwYDVQRhDBBWQVRQTC01MjUwMDA4MTk4ghRA+PeKsONkEFaRyNngLPjBxkAKRjAx BgNVHSABAf8EJzAlMCMGBFUdIAAwGzAZBggrBgEFBQcCARYNd3d3Lm5jY2VydC5w bDAOBgNVHQ8BAf8EBAMCBsAwHQYDVR0OBBYEFLK9EssHgeJ7o7BhHUpDeaiH9NB2 MA0GCSqGSIb3DQEBDQUAA4ICAQCRHo3UHB8iA7n233wd62M36kI7U06VehHGJAxR GaLVCc94olliDhM887OwzmVDOj2z3Ve5ggcaVG8Jpy2TxnYUr0M+kkjrvRd+Ek36 M2gAMLT0m6kqHxg18V0s0icMeOvlYrWqhx8qDC++AwfVLOOm4QIMCvY+jPCeZ1LN 3uEzpKUbpifSYRZvxYjsSVV0Brmej1HuOUnBSA8ykvdMzhLM+N8dVmXCdqfmRRe6 tMtNPr125JzaGqiysRK/Dubq8747T5CINSlXXQQELXtjxh4bANAXKHAcvoQLnS42 07JJ4bbPsGcGupp6V4/ZScmVCaSDGZirP3Xkltxf1/YnXdNTr0fTx8q+gXifdt2f 14SX9FNJD+UC/qnuQy4MYz48D3Jy+j2vqURL494HkgLb0lHE38L55p83z6b1vTF9 QXwaBJc6+rEDooh9oP4QyGlaHMBjbTopwMeajZsFEVYMnZnfqpYruOFw6rkz+ZPi ZjlC6h5PFtMweIwqpnNS6Yb5SEQbeMk7FH11W2ExL4PGttg2wfjPaXdT7QOn5T0o f6oGKjHPjYh1s5kCTPNHl0xlqH/oRdbkW3sQVHRWBdQfekA5PIr83U8CjP71K5BC fvUVb9t/CF6Vo559KHr6ORg71POtU8kBDDRXZABF3hj0DqoXZfCJPKPN7Asd2Pym 0xHdVjGCBBswggQXAgEBMIGHMG8xCzAJBgNVBAYTAlBMMR0wGwYDVQQKDBROYXJv ZG93eSBCYW5rIFBvbHNraTEmMCQGA1UEAwwdTmFyb2Rvd2UgQ2VudHJ1bSBDZXJ0 eWZpa2FjamkxGTAXBgNVBGEMEFZBVFBMLTUyNTAwMDgxOTgCFBGTc18XwX4UTT+S j2Gbv9UCfbHpMA0GCWCGSAFlAwQCAQUAoIIBZDAaBgkqhkiG9w0BCQMxDQYLKoZI hvcNAQkQAQQwHAYJKoZIhvcNAQkFMQ8XDTIwMTEyNDAwMzQzN1owLwYJKoZIhvcN AQkEMSIEIONve3idZH4Qr4wdR52n217VC3wBeJpuVXwjc6dZzCRwMDcGCyqGSIb3 DQEJEAIvMSgwJjAkMCIEIGc76KHakn22PMq3yz56w1LcOutqjaPio1nKFY0KRA24 MIG9BgsqhkiG9w0BCRACDDGBrTCBqjCBpzCBpAQUbiPNuWfwbT/ahTFsW0c2HNVV QqwwgYswc6RxMG8xCzAJBgNVBAYTAlBMMR0wGwYDVQQKDBROYXJvZG93eSBCYW5r IFBvbHNraTEmMCQGA1UEAwwdTmFyb2Rvd2UgQ2VudHJ1bSBDZXJ0eWZpa2Fjamkx GTAXBgNVBGEMEFZBVFBMLTUyNTAwMDgxOTgCFBGTc18XwX4UTT+Sj2Gbv9UCfbHp MA0GCSqGSIb3DQEBCwUABIICABBaNZQZ/0wIuRLGZ5+AWRdTlnwFtgesGIq/EeTB EX/Gqd/nhvEle2Vd6mJoi1cdPDm5iPXrpmJDhV8l/U3Bh9fWCBnT26bGa/p2Rb+3 30jf/8P3UIg7TFWnFyME2bvL+b175XMPAgs4Am7re+wr1AFijqF8OEDdXiI/TojA B38SQ04gfuhQ0WZrIFrIXh4e5fB9W/IvrwpB5DZWvXZulPp7/WqkG4O2WJ9mC3Qp NpqxLhlP+MjLx5SENtNVrF5ZHDCuDa9kHAJNOEn2ESPTMk+vxomt+QR82GtufP2/ T77nTuQrOngtug12emJ257BtK2igJsAi1SGOROx7ltIxA7V/arVeoLUxf1MQbpOh bNQLpfaZc/I7QFoM3HOM4s3DPUxol46sWdt52TJdX8Rvdlyr6uUekm9p2gMQBTDS j1YNggZV46qPS4Yg/BpVREOfQxYsAJZ37BEc4fNqiI0VcOSI5lWOl6Kmwabzs5a6 jsBhiX5Q8cu/VAZTZ7JxInSAuToYFpUL41H16u/Gwe0tat0hlYMdb3U1wkVREKj0 c1tPDY/6S04pG8OKNiaFjGcDrn4/SFAYNIlvT6R8xGywOKBFKvRR4/7TJZlahuTn 8L4tiSfBeKaT+K6FMrAuuQimOerhNYVtOQKCbGigePIl1Rkdy4VB9IfQRGociyIF Rvszendesive-2.19.1/examples/certum/enveloped-t.xml.config000066400000000000000000000212141504236674500227470ustar00rootroot00000000000000 3.4.0.0 cryptoCertumPKCS11 aetpkss1 cryptoCertum3PKCS crypto3PKCS CCPkiP11 OCSCryptoki SimplySignPKCS opensc-pkcs11 cryptoCertum3PKCS crypto3PKCS SimplySignPKCS cryptoCertum3PKCS crypto3PKCS SimplySignPKCS false false aavYulUYP6qrcNT82yHa8g== IMPLICIT XML falsetrue yes true false T SHA_256 true true true MIIHeTCCBWGgAwIBAgIQP6Zj23WXXaawMu8t3MSN6DANBgkqhkiG9w0BAQsFADBlMQswCQYDVQQGEwJQTDEhMB8GA1UECgwYQXNzZWNvIERhdGEgU3lzdGVtcyBTLkEuMRgwFgYDVQQDDA9DZXJ0dW0gUUNBIDIwMTcxGTAXBgNVBGEMEFZBVFBMLTUxNzAzNTk0NTgwHhcNMTkwMjIxMDYwMDAwWhcNMjEwMjIwMDYwMDAwWjBpMRkwFwYDVQQDDBBEYXJpdXN6IE1hamV3c2tpMRAwDgYDVQQqDAdEYXJpdXN6MREwDwYDVQQEDAhNYWpld3NraTEaMBgGA1UEBRMRUE5PUEwtNjIwMjE2MDQ2MTYxCzAJBgNVBAYTAlBMMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAzUt3RBeGDmhzz53LzvcfzuT3dNiwZZrwPGVBfyXKjdHRrM0yegoegB/2z/5EJy7oMLB6X73BYElYJHINq6HHgFECckdombrEoyFyfCFEGp+6SkJS6KzICxTYrC/NcigAqC+LcoYJb3bdeRq12c8/KjF3aU1pfa+sFUSTKVEpCPOTHYLkH/j3/yP4b72smAH+FNkZqzws0CMWFK37CrRwfpap5rsSCWqa8mQD/kYjEoP4DWE9QBxa/f3ay5QgyLnQ6Wjb/+CiiaXgySmzeoTEJlaajOrJ/25K2H6EpIKMaCnWBJ7/Vvii9Pb1QIHBr5fJf68aNbQLtRctAfLsm7V28QIDAQABo4IDHzCCAxswDAYDVR0TAQH/BAIwADA2BgNVHR8ELzAtMCugKaAnhiVodHRwOi8vcWNhLmNybC5jZXJ0dW0ucGwvcWNhXzIwMTcuY3JsMHIGCCsGAQUFBwEBBGYwZDAsBggrBgEFBQcwAYYgaHR0cDovL3FjYS0yMDE3LnFvY3NwLWNlcnR1bS5jb20wNAYIKwYBBQUHMAKGKGh0dHA6Ly9yZXBvc2l0b3J5LmNlcnR1bS5wbC9xY2FfMjAxNy5jZXIwHwYDVR0jBBgwFoAUJ/HYTmBQaLZh/mgbKGxt5AtzCU0wHQYDVR0OBBYEFKdCzxALmtKNEeOdaLS/Uh7WevmAMA4GA1UdDwEB/wQEAwIGwDCCAUgGA1UdIASCAT8wggE7MAkGBwQAi+xAAQIwggEsBgwqhGgBhvZ3AgQBDAEwggEaMC0GCCsGAQUFBwIBFiFodHRwOi8vd3d3LmNlcnR1bS5wbC9yZXBvenl0b3JpdW0wgegGCCsGAQUFBwICMIHbMB8WGEFzc2VjbyBEYXRhIFN5c3RlbXMgUy5BLjADAgEBDIG3Q2VydGlmaWNhdGUgUG9saWN5IGFuZCBDZXJ0aWZpY2F0aW9uIFByYWN0aWNlIFN0YXRlbWVudCBvZiBDZXJ0dW0ncyBRdWFsaWZpZWQgQ2VydGlmaWNhdGlvbiBTZXJ2aWNlcy4gTW9yZSBpbmZvcm1hdGlvbiBjYW4gYmUgZm91bmQgaW4gdGhlIENlcnRpZmljYXRlIFBvbGljeSBvbiBodHRwczovL3d3dy5jZXJ0dW0uZXUuMIHCBggrBgEFBQcBAwSBtTCBsjAIBgYEAI5GAQEwCAYGBACORgEEMIGGBgYEAI5GAQUwfDA8FjZodHRwczovL3JlcG9zaXRvcnkuY2VydHVtLnBsL1BEUy9DZXJ0dW1fUUNBLVBEU19FTi5wZGYTAmVuMDwWNmh0dHBzOi8vcmVwb3NpdG9yeS5jZXJ0dW0ucGwvUERTL0NlcnR1bV9RQ0EtUERTX1BMLnBkZhMCcGwwEwYGBACORgEGMAkGBwQAjkYBBgEwDQYJKoZIhvcNAQELBQADggIBAGXD5An9jvqtjPhvGreSGBBU/QWe8zOmEIDt1k6xlEbmbWnCWGKFOP+UMtSuKaQLyViBZASB0cYvXByriBn6XuUKba9zAQIhisfiqd4rFbDihSajxn4ub4s1lr4JeZmbbRjg7LmdxY5zbjjOoLRCA8LJojflrkSZOX9fRaTSzLX47IS/i/c4GuI03Y9DwUzRAtHOre60r/dmG3Unwvl1+LbYLzwvaIye8n/o91CRA4+mc6eKM1yBiQRCJbtShy8V8yrJPb9d1s4VO3EptY5PIWFIIIUz9sg2SsOWRxTv3Zl35GJ0IT4xsMDhCmmpfoCOK4jZSjZclG+A95PN4d0737EosQxojcFQOMMQNsPQ34axqu6DcHAVqWiHvQvnDFvsROtlzWcOxdwcnemfmdN4qOEndOPYInkcAJ5Nmzxp5SiH/EHz8FphyIi87kc6PmW0ancHHoxZB59CiJiAuxFp3ULryxH8RGt/IIjN4WqOPdq2y7f6OJ3T6UbWX5wdhsIVQl7ZMFsuG5S6MjbRJLWoCWPgV49yTz149hf142saG5PWi7Tzams9vAIwfNvIpismhKdN3+IrpK9UCvf9vSqP1JnlRxUo7qb2VyX8qN+PqtixWfs7uPb7NtsAmbMZJFWwotHMCq6d/CwTWm1oJPCh3HLQIujuCYRr4JmPbFvQfiyv true false false true BES INCLUSIVE false false false false http://time.certum.pl false http://time.certum.pl http://qts10.clide.certum.pl http://localhost:801/pk-tsa http://public-qlts.certum.pl http://public-qlts.certum.pl/qts-17 http://public-qlts.certum.pl/qts-17 yes MIIHeTCCBWGgAwIBAgIQP6Zj23WXXaawMu8t3MSN6DANBgkqhkiG9w0BAQsFADBlMQswCQYDVQQGEwJQTDEhMB8GA1UECgwYQXNzZWNvIERhdGEgU3lzdGVtcyBTLkEuMRgwFgYDVQQDDA9DZXJ0dW0gUUNBIDIwMTcxGTAXBgNVBGEMEFZBVFBMLTUxNzAzNTk0NTgwHhcNMTkwMjIxMDYwMDAwWhcNMjEwMjIwMDYwMDAwWjBpMRkwFwYDVQQDDBBEYXJpdXN6IE1hamV3c2tpMRAwDgYDVQQqDAdEYXJpdXN6MREwDwYDVQQEDAhNYWpld3NraTEaMBgGA1UEBRMRUE5PUEwtNjIwMjE2MDQ2MTYxCzAJBgNVBAYTAlBMMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAzUt3RBeGDmhzz53LzvcfzuT3dNiwZZrwPGVBfyXKjdHRrM0yegoegB/2z/5EJy7oMLB6X73BYElYJHINq6HHgFECckdombrEoyFyfCFEGp+6SkJS6KzICxTYrC/NcigAqC+LcoYJb3bdeRq12c8/KjF3aU1pfa+sFUSTKVEpCPOTHYLkH/j3/yP4b72smAH+FNkZqzws0CMWFK37CrRwfpap5rsSCWqa8mQD/kYjEoP4DWE9QBxa/f3ay5QgyLnQ6Wjb/+CiiaXgySmzeoTEJlaajOrJ/25K2H6EpIKMaCnWBJ7/Vvii9Pb1QIHBr5fJf68aNbQLtRctAfLsm7V28QIDAQABo4IDHzCCAxswDAYDVR0TAQH/BAIwADA2BgNVHR8ELzAtMCugKaAnhiVodHRwOi8vcWNhLmNybC5jZXJ0dW0ucGwvcWNhXzIwMTcuY3JsMHIGCCsGAQUFBwEBBGYwZDAsBggrBgEFBQcwAYYgaHR0cDovL3FjYS0yMDE3LnFvY3NwLWNlcnR1bS5jb20wNAYIKwYBBQUHMAKGKGh0dHA6Ly9yZXBvc2l0b3J5LmNlcnR1bS5wbC9xY2FfMjAxNy5jZXIwHwYDVR0jBBgwFoAUJ/HYTmBQaLZh/mgbKGxt5AtzCU0wHQYDVR0OBBYEFKdCzxALmtKNEeOdaLS/Uh7WevmAMA4GA1UdDwEB/wQEAwIGwDCCAUgGA1UdIASCAT8wggE7MAkGBwQAi+xAAQIwggEsBgwqhGgBhvZ3AgQBDAEwggEaMC0GCCsGAQUFBwIBFiFodHRwOi8vd3d3LmNlcnR1bS5wbC9yZXBvenl0b3JpdW0wgegGCCsGAQUFBwICMIHbMB8WGEFzc2VjbyBEYXRhIFN5c3RlbXMgUy5BLjADAgEBDIG3Q2VydGlmaWNhdGUgUG9saWN5IGFuZCBDZXJ0aWZpY2F0aW9uIFByYWN0aWNlIFN0YXRlbWVudCBvZiBDZXJ0dW0ncyBRdWFsaWZpZWQgQ2VydGlmaWNhdGlvbiBTZXJ2aWNlcy4gTW9yZSBpbmZvcm1hdGlvbiBjYW4gYmUgZm91bmQgaW4gdGhlIENlcnRpZmljYXRlIFBvbGljeSBvbiBodHRwczovL3d3dy5jZXJ0dW0uZXUuMIHCBggrBgEFBQcBAwSBtTCBsjAIBgYEAI5GAQEwCAYGBACORgEEMIGGBgYEAI5GAQUwfDA8FjZodHRwczovL3JlcG9zaXRvcnkuY2VydHVtLnBsL1BEUy9DZXJ0dW1fUUNBLVBEU19FTi5wZGYTAmVuMDwWNmh0dHBzOi8vcmVwb3NpdG9yeS5jZXJ0dW0ucGwvUERTL0NlcnR1bV9RQ0EtUERTX1BMLnBkZhMCcGwwEwYGBACORgEGMAkGBwQAjkYBBgEwDQYJKoZIhvcNAQELBQADggIBAGXD5An9jvqtjPhvGreSGBBU/QWe8zOmEIDt1k6xlEbmbWnCWGKFOP+UMtSuKaQLyViBZASB0cYvXByriBn6XuUKba9zAQIhisfiqd4rFbDihSajxn4ub4s1lr4JeZmbbRjg7LmdxY5zbjjOoLRCA8LJojflrkSZOX9fRaTSzLX47IS/i/c4GuI03Y9DwUzRAtHOre60r/dmG3Unwvl1+LbYLzwvaIye8n/o91CRA4+mc6eKM1yBiQRCJbtShy8V8yrJPb9d1s4VO3EptY5PIWFIIIUz9sg2SsOWRxTv3Zl35GJ0IT4xsMDhCmmpfoCOK4jZSjZclG+A95PN4d0737EosQxojcFQOMMQNsPQ34axqu6DcHAVqWiHvQvnDFvsROtlzWcOxdwcnemfmdN4qOEndOPYInkcAJ5Nmzxp5SiH/EHz8FphyIi87kc6PmW0ancHHoxZB59CiJiAuxFp3ULryxH8RGt/IIjN4WqOPdq2y7f6OJ3T6UbWX5wdhsIVQl7ZMFsuG5S6MjbRJLWoCWPgV49yTz149hf142saG5PWi7Tzams9vAIwfNvIpismhKdN3+IrpK9UCvf9vSqP1JnlRxUo7qb2VyX8qN+PqtixWfs7uPb7NtsAmbMZJFWwotHMCq6d/CwTWm1oJPCh3HLQIujuCYRr4JmPbFvQfiyv false default 1606177413950 1530218665897 NEVER false /devel/00mirror-cvs/00-m32/endesive/examples/certum endesive-2.19.1/examples/certum/enveloped.xml000066400000000000000000000210621504236674500212430ustar00rootroot00000000000000 VAT-7 17 1 2017 2 3215 7791011327 Nazwa firmy 630303023 0 3108 3108 0 0 998293 49915 901697 72135 3334214 766869 3177289 187401 44326 8864 0 0 0 0 66801 15364 0 0 0 0 0 0 0 0 0 8713129 913147 512089 54480 12531 8152972 1279013 0 0 -138 1380 1804875 0 0 0 0 891728 0 0 0 0 891728 2 2 2 914842496 2017-05-09 1 not(ancestor-or-self::ds:Signature)TDvzyhJhtfEyOX3o5bpsjwsOIUAx6m1ye+qf4culo3g=KVUN7BiUOfcQFzWk4AQF+cMMV324HHnyMMr26MFEi5o=l/4AOuBOJOQkS0aLAZ7+yw5lGlXWqqmy4bH02xyV0e/TRcGWx1Y/dBNvwot35tl1 pQ+5RZHVEcgYhy+Bj3NjgkAb7WmkPf3216J5nwWdP9Y2t58klCxWZdGL5gJ2ZWkV 1udBygTCpaD/59N/7LsZsgOWwWFcZ4u+Q0wGwO0XtxRjHx8W08FaELYWudhX7C/o bI3fuHJO2/GVWR2cf8BiILaPPbNnFncE7reNDY7HZh2GtpMk0EFaNzryUIEGNojm WKsMF9BUHZjNThM94lKV0DghjeFCqOwIV0sdsotuB360zc8GbLQDFYaWTIJeIpdz cl2lCpKPWo0jWiemrKbggQ==MIIHeTCCBWGgAwIBAgIQP6Zj23WXXaawMu8t3MSN6DANBgkqhkiG9w0BAQsFADBl MQswCQYDVQQGEwJQTDEhMB8GA1UECgwYQXNzZWNvIERhdGEgU3lzdGVtcyBTLkEu MRgwFgYDVQQDDA9DZXJ0dW0gUUNBIDIwMTcxGTAXBgNVBGEMEFZBVFBMLTUxNzAz NTk0NTgwHhcNMTkwMjIxMDYwMDAwWhcNMjEwMjIwMDYwMDAwWjBpMRkwFwYDVQQD DBBEYXJpdXN6IE1hamV3c2tpMRAwDgYDVQQqDAdEYXJpdXN6MREwDwYDVQQEDAhN YWpld3NraTEaMBgGA1UEBRMRUE5PUEwtNjIwMjE2MDQ2MTYxCzAJBgNVBAYTAlBM MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAzUt3RBeGDmhzz53Lzvcf zuT3dNiwZZrwPGVBfyXKjdHRrM0yegoegB/2z/5EJy7oMLB6X73BYElYJHINq6HH gFECckdombrEoyFyfCFEGp+6SkJS6KzICxTYrC/NcigAqC+LcoYJb3bdeRq12c8/ KjF3aU1pfa+sFUSTKVEpCPOTHYLkH/j3/yP4b72smAH+FNkZqzws0CMWFK37CrRw fpap5rsSCWqa8mQD/kYjEoP4DWE9QBxa/f3ay5QgyLnQ6Wjb/+CiiaXgySmzeoTE JlaajOrJ/25K2H6EpIKMaCnWBJ7/Vvii9Pb1QIHBr5fJf68aNbQLtRctAfLsm7V2 8QIDAQABo4IDHzCCAxswDAYDVR0TAQH/BAIwADA2BgNVHR8ELzAtMCugKaAnhiVo dHRwOi8vcWNhLmNybC5jZXJ0dW0ucGwvcWNhXzIwMTcuY3JsMHIGCCsGAQUFBwEB BGYwZDAsBggrBgEFBQcwAYYgaHR0cDovL3FjYS0yMDE3LnFvY3NwLWNlcnR1bS5j b20wNAYIKwYBBQUHMAKGKGh0dHA6Ly9yZXBvc2l0b3J5LmNlcnR1bS5wbC9xY2Ff MjAxNy5jZXIwHwYDVR0jBBgwFoAUJ/HYTmBQaLZh/mgbKGxt5AtzCU0wHQYDVR0O BBYEFKdCzxALmtKNEeOdaLS/Uh7WevmAMA4GA1UdDwEB/wQEAwIGwDCCAUgGA1Ud IASCAT8wggE7MAkGBwQAi+xAAQIwggEsBgwqhGgBhvZ3AgQBDAEwggEaMC0GCCsG AQUFBwIBFiFodHRwOi8vd3d3LmNlcnR1bS5wbC9yZXBvenl0b3JpdW0wgegGCCsG AQUFBwICMIHbMB8WGEFzc2VjbyBEYXRhIFN5c3RlbXMgUy5BLjADAgEBDIG3Q2Vy dGlmaWNhdGUgUG9saWN5IGFuZCBDZXJ0aWZpY2F0aW9uIFByYWN0aWNlIFN0YXRl bWVudCBvZiBDZXJ0dW0ncyBRdWFsaWZpZWQgQ2VydGlmaWNhdGlvbiBTZXJ2aWNl cy4gTW9yZSBpbmZvcm1hdGlvbiBjYW4gYmUgZm91bmQgaW4gdGhlIENlcnRpZmlj YXRlIFBvbGljeSBvbiBodHRwczovL3d3dy5jZXJ0dW0uZXUuMIHCBggrBgEFBQcB AwSBtTCBsjAIBgYEAI5GAQEwCAYGBACORgEEMIGGBgYEAI5GAQUwfDA8FjZodHRw czovL3JlcG9zaXRvcnkuY2VydHVtLnBsL1BEUy9DZXJ0dW1fUUNBLVBEU19FTi5w ZGYTAmVuMDwWNmh0dHBzOi8vcmVwb3NpdG9yeS5jZXJ0dW0ucGwvUERTL0NlcnR1 bV9RQ0EtUERTX1BMLnBkZhMCcGwwEwYGBACORgEGMAkGBwQAjkYBBgEwDQYJKoZI hvcNAQELBQADggIBAGXD5An9jvqtjPhvGreSGBBU/QWe8zOmEIDt1k6xlEbmbWnC WGKFOP+UMtSuKaQLyViBZASB0cYvXByriBn6XuUKba9zAQIhisfiqd4rFbDihSaj xn4ub4s1lr4JeZmbbRjg7LmdxY5zbjjOoLRCA8LJojflrkSZOX9fRaTSzLX47IS/ i/c4GuI03Y9DwUzRAtHOre60r/dmG3Unwvl1+LbYLzwvaIye8n/o91CRA4+mc6eK M1yBiQRCJbtShy8V8yrJPb9d1s4VO3EptY5PIWFIIIUz9sg2SsOWRxTv3Zl35GJ0 IT4xsMDhCmmpfoCOK4jZSjZclG+A95PN4d0737EosQxojcFQOMMQNsPQ34axqu6D cHAVqWiHvQvnDFvsROtlzWcOxdwcnemfmdN4qOEndOPYInkcAJ5Nmzxp5SiH/EHz 8FphyIi87kc6PmW0ancHHoxZB59CiJiAuxFp3ULryxH8RGt/IIjN4WqOPdq2y7f6 OJ3T6UbWX5wdhsIVQl7ZMFsuG5S6MjbRJLWoCWPgV49yTz149hf142saG5PWi7Tz ams9vAIwfNvIpismhKdN3+IrpK9UCvf9vSqP1JnlRxUo7qb2VyX8qN+PqtixWfs7 uPb7NtsAmbMZJFWwotHMCq6d/CwTWm1oJPCh3HLQIujuCYRr4JmPbFvQfiyv2020-11-24T00:32:43ZwnJg+5guQblWVpTXg+djFHlCdB/NAcI4Ts21xCGR6jE=2.5.4.97=#0C10564154504C2D35313730333539343538,CN=Certum QCA 2017,O=Asseco Data Systems S.A.,C=PL84605310358877569721335889391052426728MIME-Version: 1.0 Content-Type: text/xml Content-Transfer-Encoding: binary Content-Disposition: filename="enveloped.xml"http://www.certum.pl/OIDAsURI/signedFile/1.2.616.1.113527.3.1.1.3.1Opis formatu dokumentu oraz jego pełna nazwahttp://www.certum.pl/OIDAsURI/signedFile.pdftext/xmlendesive-2.19.1/examples/certum/enveloped.xml.config000066400000000000000000000212161504236674500225100ustar00rootroot00000000000000 3.4.0.0 cryptoCertumPKCS11 aetpkss1 cryptoCertum3PKCS crypto3PKCS CCPkiP11 OCSCryptoki SimplySignPKCS opensc-pkcs11 cryptoCertum3PKCS crypto3PKCS SimplySignPKCS cryptoCertum3PKCS crypto3PKCS SimplySignPKCS false false aavYulUYP6qrcNT82yHa8g== IMPLICIT XML falsetrue yes true false BES SHA_256 true true true MIIHeTCCBWGgAwIBAgIQP6Zj23WXXaawMu8t3MSN6DANBgkqhkiG9w0BAQsFADBlMQswCQYDVQQGEwJQTDEhMB8GA1UECgwYQXNzZWNvIERhdGEgU3lzdGVtcyBTLkEuMRgwFgYDVQQDDA9DZXJ0dW0gUUNBIDIwMTcxGTAXBgNVBGEMEFZBVFBMLTUxNzAzNTk0NTgwHhcNMTkwMjIxMDYwMDAwWhcNMjEwMjIwMDYwMDAwWjBpMRkwFwYDVQQDDBBEYXJpdXN6IE1hamV3c2tpMRAwDgYDVQQqDAdEYXJpdXN6MREwDwYDVQQEDAhNYWpld3NraTEaMBgGA1UEBRMRUE5PUEwtNjIwMjE2MDQ2MTYxCzAJBgNVBAYTAlBMMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAzUt3RBeGDmhzz53LzvcfzuT3dNiwZZrwPGVBfyXKjdHRrM0yegoegB/2z/5EJy7oMLB6X73BYElYJHINq6HHgFECckdombrEoyFyfCFEGp+6SkJS6KzICxTYrC/NcigAqC+LcoYJb3bdeRq12c8/KjF3aU1pfa+sFUSTKVEpCPOTHYLkH/j3/yP4b72smAH+FNkZqzws0CMWFK37CrRwfpap5rsSCWqa8mQD/kYjEoP4DWE9QBxa/f3ay5QgyLnQ6Wjb/+CiiaXgySmzeoTEJlaajOrJ/25K2H6EpIKMaCnWBJ7/Vvii9Pb1QIHBr5fJf68aNbQLtRctAfLsm7V28QIDAQABo4IDHzCCAxswDAYDVR0TAQH/BAIwADA2BgNVHR8ELzAtMCugKaAnhiVodHRwOi8vcWNhLmNybC5jZXJ0dW0ucGwvcWNhXzIwMTcuY3JsMHIGCCsGAQUFBwEBBGYwZDAsBggrBgEFBQcwAYYgaHR0cDovL3FjYS0yMDE3LnFvY3NwLWNlcnR1bS5jb20wNAYIKwYBBQUHMAKGKGh0dHA6Ly9yZXBvc2l0b3J5LmNlcnR1bS5wbC9xY2FfMjAxNy5jZXIwHwYDVR0jBBgwFoAUJ/HYTmBQaLZh/mgbKGxt5AtzCU0wHQYDVR0OBBYEFKdCzxALmtKNEeOdaLS/Uh7WevmAMA4GA1UdDwEB/wQEAwIGwDCCAUgGA1UdIASCAT8wggE7MAkGBwQAi+xAAQIwggEsBgwqhGgBhvZ3AgQBDAEwggEaMC0GCCsGAQUFBwIBFiFodHRwOi8vd3d3LmNlcnR1bS5wbC9yZXBvenl0b3JpdW0wgegGCCsGAQUFBwICMIHbMB8WGEFzc2VjbyBEYXRhIFN5c3RlbXMgUy5BLjADAgEBDIG3Q2VydGlmaWNhdGUgUG9saWN5IGFuZCBDZXJ0aWZpY2F0aW9uIFByYWN0aWNlIFN0YXRlbWVudCBvZiBDZXJ0dW0ncyBRdWFsaWZpZWQgQ2VydGlmaWNhdGlvbiBTZXJ2aWNlcy4gTW9yZSBpbmZvcm1hdGlvbiBjYW4gYmUgZm91bmQgaW4gdGhlIENlcnRpZmljYXRlIFBvbGljeSBvbiBodHRwczovL3d3dy5jZXJ0dW0uZXUuMIHCBggrBgEFBQcBAwSBtTCBsjAIBgYEAI5GAQEwCAYGBACORgEEMIGGBgYEAI5GAQUwfDA8FjZodHRwczovL3JlcG9zaXRvcnkuY2VydHVtLnBsL1BEUy9DZXJ0dW1fUUNBLVBEU19FTi5wZGYTAmVuMDwWNmh0dHBzOi8vcmVwb3NpdG9yeS5jZXJ0dW0ucGwvUERTL0NlcnR1bV9RQ0EtUERTX1BMLnBkZhMCcGwwEwYGBACORgEGMAkGBwQAjkYBBgEwDQYJKoZIhvcNAQELBQADggIBAGXD5An9jvqtjPhvGreSGBBU/QWe8zOmEIDt1k6xlEbmbWnCWGKFOP+UMtSuKaQLyViBZASB0cYvXByriBn6XuUKba9zAQIhisfiqd4rFbDihSajxn4ub4s1lr4JeZmbbRjg7LmdxY5zbjjOoLRCA8LJojflrkSZOX9fRaTSzLX47IS/i/c4GuI03Y9DwUzRAtHOre60r/dmG3Unwvl1+LbYLzwvaIye8n/o91CRA4+mc6eKM1yBiQRCJbtShy8V8yrJPb9d1s4VO3EptY5PIWFIIIUz9sg2SsOWRxTv3Zl35GJ0IT4xsMDhCmmpfoCOK4jZSjZclG+A95PN4d0737EosQxojcFQOMMQNsPQ34axqu6DcHAVqWiHvQvnDFvsROtlzWcOxdwcnemfmdN4qOEndOPYInkcAJ5Nmzxp5SiH/EHz8FphyIi87kc6PmW0ancHHoxZB59CiJiAuxFp3ULryxH8RGt/IIjN4WqOPdq2y7f6OJ3T6UbWX5wdhsIVQl7ZMFsuG5S6MjbRJLWoCWPgV49yTz149hf142saG5PWi7Tzams9vAIwfNvIpismhKdN3+IrpK9UCvf9vSqP1JnlRxUo7qb2VyX8qN+PqtixWfs7uPb7NtsAmbMZJFWwotHMCq6d/CwTWm1oJPCh3HLQIujuCYRr4JmPbFvQfiyv true false false true BES INCLUSIVE false false false false http://time.certum.pl false http://time.certum.pl http://qts10.clide.certum.pl http://localhost:801/pk-tsa http://public-qlts.certum.pl http://public-qlts.certum.pl/qts-17 http://public-qlts.certum.pl/qts-17 yes MIIHeTCCBWGgAwIBAgIQP6Zj23WXXaawMu8t3MSN6DANBgkqhkiG9w0BAQsFADBlMQswCQYDVQQGEwJQTDEhMB8GA1UECgwYQXNzZWNvIERhdGEgU3lzdGVtcyBTLkEuMRgwFgYDVQQDDA9DZXJ0dW0gUUNBIDIwMTcxGTAXBgNVBGEMEFZBVFBMLTUxNzAzNTk0NTgwHhcNMTkwMjIxMDYwMDAwWhcNMjEwMjIwMDYwMDAwWjBpMRkwFwYDVQQDDBBEYXJpdXN6IE1hamV3c2tpMRAwDgYDVQQqDAdEYXJpdXN6MREwDwYDVQQEDAhNYWpld3NraTEaMBgGA1UEBRMRUE5PUEwtNjIwMjE2MDQ2MTYxCzAJBgNVBAYTAlBMMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAzUt3RBeGDmhzz53LzvcfzuT3dNiwZZrwPGVBfyXKjdHRrM0yegoegB/2z/5EJy7oMLB6X73BYElYJHINq6HHgFECckdombrEoyFyfCFEGp+6SkJS6KzICxTYrC/NcigAqC+LcoYJb3bdeRq12c8/KjF3aU1pfa+sFUSTKVEpCPOTHYLkH/j3/yP4b72smAH+FNkZqzws0CMWFK37CrRwfpap5rsSCWqa8mQD/kYjEoP4DWE9QBxa/f3ay5QgyLnQ6Wjb/+CiiaXgySmzeoTEJlaajOrJ/25K2H6EpIKMaCnWBJ7/Vvii9Pb1QIHBr5fJf68aNbQLtRctAfLsm7V28QIDAQABo4IDHzCCAxswDAYDVR0TAQH/BAIwADA2BgNVHR8ELzAtMCugKaAnhiVodHRwOi8vcWNhLmNybC5jZXJ0dW0ucGwvcWNhXzIwMTcuY3JsMHIGCCsGAQUFBwEBBGYwZDAsBggrBgEFBQcwAYYgaHR0cDovL3FjYS0yMDE3LnFvY3NwLWNlcnR1bS5jb20wNAYIKwYBBQUHMAKGKGh0dHA6Ly9yZXBvc2l0b3J5LmNlcnR1bS5wbC9xY2FfMjAxNy5jZXIwHwYDVR0jBBgwFoAUJ/HYTmBQaLZh/mgbKGxt5AtzCU0wHQYDVR0OBBYEFKdCzxALmtKNEeOdaLS/Uh7WevmAMA4GA1UdDwEB/wQEAwIGwDCCAUgGA1UdIASCAT8wggE7MAkGBwQAi+xAAQIwggEsBgwqhGgBhvZ3AgQBDAEwggEaMC0GCCsGAQUFBwIBFiFodHRwOi8vd3d3LmNlcnR1bS5wbC9yZXBvenl0b3JpdW0wgegGCCsGAQUFBwICMIHbMB8WGEFzc2VjbyBEYXRhIFN5c3RlbXMgUy5BLjADAgEBDIG3Q2VydGlmaWNhdGUgUG9saWN5IGFuZCBDZXJ0aWZpY2F0aW9uIFByYWN0aWNlIFN0YXRlbWVudCBvZiBDZXJ0dW0ncyBRdWFsaWZpZWQgQ2VydGlmaWNhdGlvbiBTZXJ2aWNlcy4gTW9yZSBpbmZvcm1hdGlvbiBjYW4gYmUgZm91bmQgaW4gdGhlIENlcnRpZmljYXRlIFBvbGljeSBvbiBodHRwczovL3d3dy5jZXJ0dW0uZXUuMIHCBggrBgEFBQcBAwSBtTCBsjAIBgYEAI5GAQEwCAYGBACORgEEMIGGBgYEAI5GAQUwfDA8FjZodHRwczovL3JlcG9zaXRvcnkuY2VydHVtLnBsL1BEUy9DZXJ0dW1fUUNBLVBEU19FTi5wZGYTAmVuMDwWNmh0dHBzOi8vcmVwb3NpdG9yeS5jZXJ0dW0ucGwvUERTL0NlcnR1bV9RQ0EtUERTX1BMLnBkZhMCcGwwEwYGBACORgEGMAkGBwQAjkYBBgEwDQYJKoZIhvcNAQELBQADggIBAGXD5An9jvqtjPhvGreSGBBU/QWe8zOmEIDt1k6xlEbmbWnCWGKFOP+UMtSuKaQLyViBZASB0cYvXByriBn6XuUKba9zAQIhisfiqd4rFbDihSajxn4ub4s1lr4JeZmbbRjg7LmdxY5zbjjOoLRCA8LJojflrkSZOX9fRaTSzLX47IS/i/c4GuI03Y9DwUzRAtHOre60r/dmG3Unwvl1+LbYLzwvaIye8n/o91CRA4+mc6eKM1yBiQRCJbtShy8V8yrJPb9d1s4VO3EptY5PIWFIIIUz9sg2SsOWRxTv3Zl35GJ0IT4xsMDhCmmpfoCOK4jZSjZclG+A95PN4d0737EosQxojcFQOMMQNsPQ34axqu6DcHAVqWiHvQvnDFvsROtlzWcOxdwcnemfmdN4qOEndOPYInkcAJ5Nmzxp5SiH/EHz8FphyIi87kc6PmW0ancHHoxZB59CiJiAuxFp3ULryxH8RGt/IIjN4WqOPdq2y7f6OJ3T6UbWX5wdhsIVQl7ZMFsuG5S6MjbRJLWoCWPgV49yTz149hf142saG5PWi7Tzams9vAIwfNvIpismhKdN3+IrpK9UCvf9vSqP1JnlRxUo7qb2VyX8qN+PqtixWfs7uPb7NtsAmbMZJFWwotHMCq6d/CwTWm1oJPCh3HLQIujuCYRr4JmPbFvQfiyv false default 1606177413950 1530218665897 NEVER false /devel/00mirror-cvs/00-m32/endesive/examples/certum endesive-2.19.1/examples/certum/enveloped1.xml000066400000000000000000000234571504236674500213360ustar00rootroot00000000000000 VAT-7 17 1 2017 2 3215 7791011327 Nazwa firmy 630303023 0 3108 3108 0 0 998293 49915 901697 72135 3334214 766869 3177289 187401 44326 8864 0 0 0 0 66801 15364 0 0 0 0 0 0 0 0 0 8713129 913147 512089 54480 12531 8152972 1279013 0 0 -138 1380 1804875 0 0 0 0 891728 0 0 0 0 891728 2 2 2 914842496 2017-05-09 1 not(ancestor-or-self::ds:Signature) TDvzyhJhtfEyOX3o5bpsjwsOIUAx6m1ye+qf4culo3g= KVUN7BiUOfcQFzWk4AQF+cMMV324HHnyMMr26MFEi5o= l/4AOuBOJOQkS0aLAZ7+yw5lGlXWqqmy4bH02xyV0e/TRcGWx1Y/dBNvwot35tl1 pQ+5RZHVEcgYhy+Bj3NjgkAb7WmkPf3216J5nwWdP9Y2t58klCxWZdGL5gJ2ZWkV 1udBygTCpaD/59N/7LsZsgOWwWFcZ4u+Q0wGwO0XtxRjHx8W08FaELYWudhX7C/o bI3fuHJO2/GVWR2cf8BiILaPPbNnFncE7reNDY7HZh2GtpMk0EFaNzryUIEGNojm WKsMF9BUHZjNThM94lKV0DghjeFCqOwIV0sdsotuB360zc8GbLQDFYaWTIJeIpdz cl2lCpKPWo0jWiemrKbggQ== MIIHeTCCBWGgAwIBAgIQP6Zj23WXXaawMu8t3MSN6DANBgkqhkiG9w0BAQsFADBl MQswCQYDVQQGEwJQTDEhMB8GA1UECgwYQXNzZWNvIERhdGEgU3lzdGVtcyBTLkEu MRgwFgYDVQQDDA9DZXJ0dW0gUUNBIDIwMTcxGTAXBgNVBGEMEFZBVFBMLTUxNzAz NTk0NTgwHhcNMTkwMjIxMDYwMDAwWhcNMjEwMjIwMDYwMDAwWjBpMRkwFwYDVQQD DBBEYXJpdXN6IE1hamV3c2tpMRAwDgYDVQQqDAdEYXJpdXN6MREwDwYDVQQEDAhN YWpld3NraTEaMBgGA1UEBRMRUE5PUEwtNjIwMjE2MDQ2MTYxCzAJBgNVBAYTAlBM MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAzUt3RBeGDmhzz53Lzvcf zuT3dNiwZZrwPGVBfyXKjdHRrM0yegoegB/2z/5EJy7oMLB6X73BYElYJHINq6HH gFECckdombrEoyFyfCFEGp+6SkJS6KzICxTYrC/NcigAqC+LcoYJb3bdeRq12c8/ KjF3aU1pfa+sFUSTKVEpCPOTHYLkH/j3/yP4b72smAH+FNkZqzws0CMWFK37CrRw fpap5rsSCWqa8mQD/kYjEoP4DWE9QBxa/f3ay5QgyLnQ6Wjb/+CiiaXgySmzeoTE JlaajOrJ/25K2H6EpIKMaCnWBJ7/Vvii9Pb1QIHBr5fJf68aNbQLtRctAfLsm7V2 8QIDAQABo4IDHzCCAxswDAYDVR0TAQH/BAIwADA2BgNVHR8ELzAtMCugKaAnhiVo dHRwOi8vcWNhLmNybC5jZXJ0dW0ucGwvcWNhXzIwMTcuY3JsMHIGCCsGAQUFBwEB BGYwZDAsBggrBgEFBQcwAYYgaHR0cDovL3FjYS0yMDE3LnFvY3NwLWNlcnR1bS5j b20wNAYIKwYBBQUHMAKGKGh0dHA6Ly9yZXBvc2l0b3J5LmNlcnR1bS5wbC9xY2Ff MjAxNy5jZXIwHwYDVR0jBBgwFoAUJ/HYTmBQaLZh/mgbKGxt5AtzCU0wHQYDVR0O BBYEFKdCzxALmtKNEeOdaLS/Uh7WevmAMA4GA1UdDwEB/wQEAwIGwDCCAUgGA1Ud IASCAT8wggE7MAkGBwQAi+xAAQIwggEsBgwqhGgBhvZ3AgQBDAEwggEaMC0GCCsG AQUFBwIBFiFodHRwOi8vd3d3LmNlcnR1bS5wbC9yZXBvenl0b3JpdW0wgegGCCsG AQUFBwICMIHbMB8WGEFzc2VjbyBEYXRhIFN5c3RlbXMgUy5BLjADAgEBDIG3Q2Vy dGlmaWNhdGUgUG9saWN5IGFuZCBDZXJ0aWZpY2F0aW9uIFByYWN0aWNlIFN0YXRl bWVudCBvZiBDZXJ0dW0ncyBRdWFsaWZpZWQgQ2VydGlmaWNhdGlvbiBTZXJ2aWNl cy4gTW9yZSBpbmZvcm1hdGlvbiBjYW4gYmUgZm91bmQgaW4gdGhlIENlcnRpZmlj YXRlIFBvbGljeSBvbiBodHRwczovL3d3dy5jZXJ0dW0uZXUuMIHCBggrBgEFBQcB AwSBtTCBsjAIBgYEAI5GAQEwCAYGBACORgEEMIGGBgYEAI5GAQUwfDA8FjZodHRw czovL3JlcG9zaXRvcnkuY2VydHVtLnBsL1BEUy9DZXJ0dW1fUUNBLVBEU19FTi5w ZGYTAmVuMDwWNmh0dHBzOi8vcmVwb3NpdG9yeS5jZXJ0dW0ucGwvUERTL0NlcnR1 bV9RQ0EtUERTX1BMLnBkZhMCcGwwEwYGBACORgEGMAkGBwQAjkYBBgEwDQYJKoZI hvcNAQELBQADggIBAGXD5An9jvqtjPhvGreSGBBU/QWe8zOmEIDt1k6xlEbmbWnC WGKFOP+UMtSuKaQLyViBZASB0cYvXByriBn6XuUKba9zAQIhisfiqd4rFbDihSaj xn4ub4s1lr4JeZmbbRjg7LmdxY5zbjjOoLRCA8LJojflrkSZOX9fRaTSzLX47IS/ i/c4GuI03Y9DwUzRAtHOre60r/dmG3Unwvl1+LbYLzwvaIye8n/o91CRA4+mc6eK M1yBiQRCJbtShy8V8yrJPb9d1s4VO3EptY5PIWFIIIUz9sg2SsOWRxTv3Zl35GJ0 IT4xsMDhCmmpfoCOK4jZSjZclG+A95PN4d0737EosQxojcFQOMMQNsPQ34axqu6D cHAVqWiHvQvnDFvsROtlzWcOxdwcnemfmdN4qOEndOPYInkcAJ5Nmzxp5SiH/EHz 8FphyIi87kc6PmW0ancHHoxZB59CiJiAuxFp3ULryxH8RGt/IIjN4WqOPdq2y7f6 OJ3T6UbWX5wdhsIVQl7ZMFsuG5S6MjbRJLWoCWPgV49yTz149hf142saG5PWi7Tz ams9vAIwfNvIpismhKdN3+IrpK9UCvf9vSqP1JnlRxUo7qb2VyX8qN+PqtixWfs7 uPb7NtsAmbMZJFWwotHMCq6d/CwTWm1oJPCh3HLQIujuCYRr4JmPbFvQfiyv 2020-11-24T00:32:43Z wnJg+5guQblWVpTXg+djFHlCdB/NAcI4Ts21xCGR6jE= 2.5.4.97=#0C10564154504C2D35313730333539343538,CN=Certum QCA 2017,O=Asseco Data Systems S.A.,C=PL 84605310358877569721335889391052426728 MIME-Version: 1.0 Content-Type: text/xml Content-Transfer-Encoding: binary Content-Disposition: filename="enveloped.xml" http://www.certum.pl/OIDAsURI/signedFile/1.2.616.1.113527.3.1.1.3.1 Opis formatu dokumentu oraz jego pełna nazwa http://www.certum.pl/OIDAsURI/signedFile.pdf text/xml endesive-2.19.1/examples/certum/enveloping-t.xml000066400000000000000000000321261504236674500216740ustar00rootroot00000000000000M3Y1B8UVntW148L5j1WTARAg398zhsojGS+gxNFNDqQ=k0GnjWXift0VQapC8di5ni4YmUqy728W7fYWeaXUkZY=Cpisg0ecmkE4g51dE4AZbO163paurPBNsFbhyLY54NH4DXvTvB6onzyq93uziVFt ZyCL1J/B/emDmM0Ou2aDODWMCg36OatjeGrzoZVcRdf1IEnytthBvq0qHbgse7Sz b+fyEpEQpXidCDOGDSB8FShcidwd1NI/gGNUFbBQYyzwoPdngQS5xTKwOs0oyT/O xPqD6JmczdssOJXKWV/1sXF/R4SWy7aFBtsfoQ+U4ocKjuQhEfkgAh0DDdGfRFhu 2LqRs8o8IOARxNoYO9da1LyXqSIgGqkGWg4cU0SwAPtzQoScJQTm6dnUlUKNp73n 2z8aaQ0XVq2A1JlROgulNw==MIIHeTCCBWGgAwIBAgIQP6Zj23WXXaawMu8t3MSN6DANBgkqhkiG9w0BAQsFADBl MQswCQYDVQQGEwJQTDEhMB8GA1UECgwYQXNzZWNvIERhdGEgU3lzdGVtcyBTLkEu MRgwFgYDVQQDDA9DZXJ0dW0gUUNBIDIwMTcxGTAXBgNVBGEMEFZBVFBMLTUxNzAz NTk0NTgwHhcNMTkwMjIxMDYwMDAwWhcNMjEwMjIwMDYwMDAwWjBpMRkwFwYDVQQD DBBEYXJpdXN6IE1hamV3c2tpMRAwDgYDVQQqDAdEYXJpdXN6MREwDwYDVQQEDAhN YWpld3NraTEaMBgGA1UEBRMRUE5PUEwtNjIwMjE2MDQ2MTYxCzAJBgNVBAYTAlBM MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAzUt3RBeGDmhzz53Lzvcf zuT3dNiwZZrwPGVBfyXKjdHRrM0yegoegB/2z/5EJy7oMLB6X73BYElYJHINq6HH gFECckdombrEoyFyfCFEGp+6SkJS6KzICxTYrC/NcigAqC+LcoYJb3bdeRq12c8/ KjF3aU1pfa+sFUSTKVEpCPOTHYLkH/j3/yP4b72smAH+FNkZqzws0CMWFK37CrRw fpap5rsSCWqa8mQD/kYjEoP4DWE9QBxa/f3ay5QgyLnQ6Wjb/+CiiaXgySmzeoTE JlaajOrJ/25K2H6EpIKMaCnWBJ7/Vvii9Pb1QIHBr5fJf68aNbQLtRctAfLsm7V2 8QIDAQABo4IDHzCCAxswDAYDVR0TAQH/BAIwADA2BgNVHR8ELzAtMCugKaAnhiVo dHRwOi8vcWNhLmNybC5jZXJ0dW0ucGwvcWNhXzIwMTcuY3JsMHIGCCsGAQUFBwEB BGYwZDAsBggrBgEFBQcwAYYgaHR0cDovL3FjYS0yMDE3LnFvY3NwLWNlcnR1bS5j b20wNAYIKwYBBQUHMAKGKGh0dHA6Ly9yZXBvc2l0b3J5LmNlcnR1bS5wbC9xY2Ff MjAxNy5jZXIwHwYDVR0jBBgwFoAUJ/HYTmBQaLZh/mgbKGxt5AtzCU0wHQYDVR0O BBYEFKdCzxALmtKNEeOdaLS/Uh7WevmAMA4GA1UdDwEB/wQEAwIGwDCCAUgGA1Ud IASCAT8wggE7MAkGBwQAi+xAAQIwggEsBgwqhGgBhvZ3AgQBDAEwggEaMC0GCCsG AQUFBwIBFiFodHRwOi8vd3d3LmNlcnR1bS5wbC9yZXBvenl0b3JpdW0wgegGCCsG AQUFBwICMIHbMB8WGEFzc2VjbyBEYXRhIFN5c3RlbXMgUy5BLjADAgEBDIG3Q2Vy dGlmaWNhdGUgUG9saWN5IGFuZCBDZXJ0aWZpY2F0aW9uIFByYWN0aWNlIFN0YXRl bWVudCBvZiBDZXJ0dW0ncyBRdWFsaWZpZWQgQ2VydGlmaWNhdGlvbiBTZXJ2aWNl cy4gTW9yZSBpbmZvcm1hdGlvbiBjYW4gYmUgZm91bmQgaW4gdGhlIENlcnRpZmlj YXRlIFBvbGljeSBvbiBodHRwczovL3d3dy5jZXJ0dW0uZXUuMIHCBggrBgEFBQcB AwSBtTCBsjAIBgYEAI5GAQEwCAYGBACORgEEMIGGBgYEAI5GAQUwfDA8FjZodHRw czovL3JlcG9zaXRvcnkuY2VydHVtLnBsL1BEUy9DZXJ0dW1fUUNBLVBEU19FTi5w ZGYTAmVuMDwWNmh0dHBzOi8vcmVwb3NpdG9yeS5jZXJ0dW0ucGwvUERTL0NlcnR1 bV9RQ0EtUERTX1BMLnBkZhMCcGwwEwYGBACORgEGMAkGBwQAjkYBBgEwDQYJKoZI hvcNAQELBQADggIBAGXD5An9jvqtjPhvGreSGBBU/QWe8zOmEIDt1k6xlEbmbWnC WGKFOP+UMtSuKaQLyViBZASB0cYvXByriBn6XuUKba9zAQIhisfiqd4rFbDihSaj xn4ub4s1lr4JeZmbbRjg7LmdxY5zbjjOoLRCA8LJojflrkSZOX9fRaTSzLX47IS/ i/c4GuI03Y9DwUzRAtHOre60r/dmG3Unwvl1+LbYLzwvaIye8n/o91CRA4+mc6eK M1yBiQRCJbtShy8V8yrJPb9d1s4VO3EptY5PIWFIIIUz9sg2SsOWRxTv3Zl35GJ0 IT4xsMDhCmmpfoCOK4jZSjZclG+A95PN4d0737EosQxojcFQOMMQNsPQ34axqu6D cHAVqWiHvQvnDFvsROtlzWcOxdwcnemfmdN4qOEndOPYInkcAJ5Nmzxp5SiH/EHz 8FphyIi87kc6PmW0ancHHoxZB59CiJiAuxFp3ULryxH8RGt/IIjN4WqOPdq2y7f6 OJ3T6UbWX5wdhsIVQl7ZMFsuG5S6MjbRJLWoCWPgV49yTz149hf142saG5PWi7Tz ams9vAIwfNvIpismhKdN3+IrpK9UCvf9vSqP1JnlRxUo7qb2VyX8qN+PqtixWfs7 uPb7NtsAmbMZJFWwotHMCq6d/CwTWm1oJPCh3HLQIujuCYRr4JmPbFvQfiyv2020-11-24T00:31:05ZwnJg+5guQblWVpTXg+djFHlCdB/NAcI4Ts21xCGR6jE=2.5.4.97=#0C10564154504C2D35313730333539343538,CN=Certum QCA 2017,O=Asseco Data Systems S.A.,C=PL84605310358877569721335889391052426728MIME-Version: 1.0 Content-Type: text/xml Content-Transfer-Encoding: binary Content-Disposition: filename="enveloping-t.xml"http://www.certum.pl/OIDAsURI/signedFile/1.2.616.1.113527.3.1.1.3.1Opis formatu dokumentu oraz jego pełna nazwahttp://www.certum.pl/OIDAsURI/signedFile.pdftext/xmlMIIL/wYJKoZIhvcNAQcCoIIL8DCCC+wCAQMxDTALBglghkgBZQMEAgEwggEPBgsq hkiG9w0BCRABBKCB/wSB/DCB+QIBAQYLKoRoAYb2dwIEAQ4wMTANBglghkgBZQME AgEFAAQgHJLbYR6mHcdL0D1fDcHjQrCpvhQN+7ahdDxFjp2esdgCBxHDeUvtmt0Y DzIwMjAxMTI0MDAzMTA3WjADAgEBAgkAvstb5rP06y6gaqRoMGYxCzAJBgNVBAYT AlBMMSEwHwYDVQQKDBhBc3NlY28gRGF0YSBTeXN0ZW1zIFMuQS4xGTAXBgNVBAMM EENlcnR1bSBRVFNUIDIwMTcxGTAXBgNVBGEMEFZBVFBMLTUxNzAzNTk0NTihHjAc BggrBgEFBQcBAwEBAAQNMAswCQYHBACBl14BAaCCBqQwggagMIIEiKADAgECAhQR k3NfF8F+FE0/ko9hm7/VAn2x6TANBgkqhkiG9w0BAQ0FADBvMQswCQYDVQQGEwJQ TDEdMBsGA1UECgwUTmFyb2Rvd3kgQmFuayBQb2xza2kxJjAkBgNVBAMMHU5hcm9k b3dlIENlbnRydW0gQ2VydHlmaWthY2ppMRkwFwYDVQRhDBBWQVRQTC01MjUwMDA4 MTk4MB4XDTE3MDMxNTEwMjMxOFoXDTI4MDMxNTIzNTk1OVowZjELMAkGA1UEBhMC UEwxITAfBgNVBAoMGEFzc2VjbyBEYXRhIFN5c3RlbXMgUy5BLjEZMBcGA1UEAwwQ Q2VydHVtIFFUU1QgMjAxNzEZMBcGA1UEYQwQVkFUUEwtNTE3MDM1OTQ1ODCCAiIw DQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAMhUEU2e8zcRK0C3DftH+TcIdnT6 jBd3WfTqHUiQtX+aDgTo+a6tSGVcACaMV97NsexP8jPNQ2Y3eHbmUDwL8X+XHQAB KWNd5LxgJ0VJD0RMrU2OzISrfA9FVowWQU2ay4SOI22JKLJy6c4FXgGBPhng2PRM WzE7GUjsXXwTxhbQdP0KsMxSu4wMsD89bkh3pjJRAJ8k6i4gza6gPGc5jL8efvL5 2hYVoeby2xSyO7q3dksmw+2HEnCjVh9c1v6emtBbTE9ZTdxkG1wCMeR7N1FS0Tm4 C6b983YJKPbMjjqXJK2X/dxAc/eVvUJa5HpJR5O6kH6pG1IW7/MJ4SowaMeIn8Rp IDA8ZBre0nqy8wOsVkt939KkpgsvpuA0cYkcaEzzbHC7pLDcPYcxJ7+P6xQTIOTZ Fab5FyyigVoIvzW+4G56uFwGlBCj6B+Op5mK1YZ4VfXUQyT3CLQYUbUwKesqztPW yiw1oWjHJ1+aPsjwhvof/XAHv5dOJWLHBmi8BCwl8MRYUfHBKdu0OYTQRCMwNTHg Ssxfutuj6I/m/6yoHbOW9aEBSdCXtBrxAb6OAA7V/LadbQ6BoMzf86JMIo2eX84L CL9xa6XAFSN+jn/OG45OpOIz42yRPerkcjI04h1m3j7jAHwDsdcWAEBvZlY9pWVe hOFlAmimlffOQtnjAgMBAAGjggE7MIIBNzAWBgNVHSUBAf8EDDAKBggrBgEFBQcD CDAMBgNVHRMBAf8EAjAAMIGsBgNVHSMEgaQwgaGAFCmzyMTfo4f4ZgUSWP1GKriY DXmHoXOkcTBvMQswCQYDVQQGEwJQTDEdMBsGA1UECgwUTmFyb2Rvd3kgQmFuayBQ b2xza2kxJjAkBgNVBAMMHU5hcm9kb3dlIENlbnRydW0gQ2VydHlmaWthY2ppMRkw FwYDVQRhDBBWQVRQTC01MjUwMDA4MTk4ghRA+PeKsONkEFaRyNngLPjBxkAKRjAx BgNVHSABAf8EJzAlMCMGBFUdIAAwGzAZBggrBgEFBQcCARYNd3d3Lm5jY2VydC5w bDAOBgNVHQ8BAf8EBAMCBsAwHQYDVR0OBBYEFLK9EssHgeJ7o7BhHUpDeaiH9NB2 MA0GCSqGSIb3DQEBDQUAA4ICAQCRHo3UHB8iA7n233wd62M36kI7U06VehHGJAxR GaLVCc94olliDhM887OwzmVDOj2z3Ve5ggcaVG8Jpy2TxnYUr0M+kkjrvRd+Ek36 M2gAMLT0m6kqHxg18V0s0icMeOvlYrWqhx8qDC++AwfVLOOm4QIMCvY+jPCeZ1LN 3uEzpKUbpifSYRZvxYjsSVV0Brmej1HuOUnBSA8ykvdMzhLM+N8dVmXCdqfmRRe6 tMtNPr125JzaGqiysRK/Dubq8747T5CINSlXXQQELXtjxh4bANAXKHAcvoQLnS42 07JJ4bbPsGcGupp6V4/ZScmVCaSDGZirP3Xkltxf1/YnXdNTr0fTx8q+gXifdt2f 14SX9FNJD+UC/qnuQy4MYz48D3Jy+j2vqURL494HkgLb0lHE38L55p83z6b1vTF9 QXwaBJc6+rEDooh9oP4QyGlaHMBjbTopwMeajZsFEVYMnZnfqpYruOFw6rkz+ZPi ZjlC6h5PFtMweIwqpnNS6Yb5SEQbeMk7FH11W2ExL4PGttg2wfjPaXdT7QOn5T0o f6oGKjHPjYh1s5kCTPNHl0xlqH/oRdbkW3sQVHRWBdQfekA5PIr83U8CjP71K5BC fvUVb9t/CF6Vo559KHr6ORg71POtU8kBDDRXZABF3hj0DqoXZfCJPKPN7Asd2Pym 0xHdVjGCBBswggQXAgEBMIGHMG8xCzAJBgNVBAYTAlBMMR0wGwYDVQQKDBROYXJv ZG93eSBCYW5rIFBvbHNraTEmMCQGA1UEAwwdTmFyb2Rvd2UgQ2VudHJ1bSBDZXJ0 eWZpa2FjamkxGTAXBgNVBGEMEFZBVFBMLTUyNTAwMDgxOTgCFBGTc18XwX4UTT+S j2Gbv9UCfbHpMA0GCWCGSAFlAwQCAQUAoIIBZDAaBgkqhkiG9w0BCQMxDQYLKoZI hvcNAQkQAQQwHAYJKoZIhvcNAQkFMQ8XDTIwMTEyNDAwMzEwN1owLwYJKoZIhvcN AQkEMSIEINO/1JeND9+rqAXAI/PkJBbK4wTQIvmiAguIMrx92YrTMDcGCyqGSIb3 DQEJEAIvMSgwJjAkMCIEIGc76KHakn22PMq3yz56w1LcOutqjaPio1nKFY0KRA24 MIG9BgsqhkiG9w0BCRACDDGBrTCBqjCBpzCBpAQUbiPNuWfwbT/ahTFsW0c2HNVV QqwwgYswc6RxMG8xCzAJBgNVBAYTAlBMMR0wGwYDVQQKDBROYXJvZG93eSBCYW5r IFBvbHNraTEmMCQGA1UEAwwdTmFyb2Rvd2UgQ2VudHJ1bSBDZXJ0eWZpa2Fjamkx GTAXBgNVBGEMEFZBVFBMLTUyNTAwMDgxOTgCFBGTc18XwX4UTT+Sj2Gbv9UCfbHp MA0GCSqGSIb3DQEBCwUABIICADsp9YN0qhWSjJ07oospAtx7V0kln3u/FX0CE+oO 0niNmGO3iYYl6MeQWOSjQGDtXHzohDunYV8hTphRRkrbgGvGrYMsul6lI0aRDhI4 sS7ggWmyhS+PHnVSWNxGSWYQ/uXFOT1AYmaoLTKAquTFlJdC8y5mfj7gh+aEYoEc AcHf9tuoRrYJW+qSSrOmUR/pyTjgLnDprGengvqNMUdrSfI71JgJCOVk0xuTpRJl tGzuVocFevNLm5Hi55TCPN3EI4LtL9DkUMGVrrtPSOY06VlDZVjTvQNr0ZXiuDtq StmflUADP/89nkDud6oaTGAq4dwqyFH6JxAUw7fiko+dc+9uhOwreZLm3LKeFHw6 qiD1T2hxmooj7D7jGVBKaTl/Wf/ss03Hcod7bD96VU8mao/fku7ReCaBAmhQ8sEr Hk30m6QvjPylajI4OM5VuYzi/DUDW2+uaCkSYtM5SXcJhBVxHHxNJ4EZqCs+q/j6 O7t9r1Q3zQx80iOvnJUKnUZa3u6KKKQmD3+9EHvIefp59YvrHnxl4qpIr1cij4uW Re+MlIOV2Cm4jSOPUwBPf7me0viDQM8OrGUYUmQ0oHi/F7jZyMQ9dIAQyhL5mANP X1L4a4McrHvt/LWZoXAymttUZlcnLtK5mxy/H4nhh268TWV38Oo0leTiqhjlfAbZ ixvJ VAT-7 17 1 2017 2 3215 7791011327 Nazwa firmy 630303023 0 3108 3108 0 0 998293 49915 901697 72135 3334214 766869 3177289 187401 44326 8864 0 0 0 0 66801 15364 0 0 0 0 0 0 0 0 0 8713129 913147 512089 54480 12531 8152972 1279013 0 0 -138 1380 1804875 0 0 0 0 891728 0 0 0 0 891728 2 2 2 914842496 2017-05-09 1 endesive-2.19.1/examples/certum/enveloping-t.xml.config000066400000000000000000000212151504236674500231350ustar00rootroot00000000000000 3.4.0.0 cryptoCertumPKCS11 aetpkss1 cryptoCertum3PKCS crypto3PKCS CCPkiP11 OCSCryptoki SimplySignPKCS opensc-pkcs11 cryptoCertum3PKCS crypto3PKCS SimplySignPKCS cryptoCertum3PKCS crypto3PKCS SimplySignPKCS false false aavYulUYP6qrcNT82yHa8g== IMPLICIT XML falsetrue yes true false T SHA_256 false true true MIIHeTCCBWGgAwIBAgIQP6Zj23WXXaawMu8t3MSN6DANBgkqhkiG9w0BAQsFADBlMQswCQYDVQQGEwJQTDEhMB8GA1UECgwYQXNzZWNvIERhdGEgU3lzdGVtcyBTLkEuMRgwFgYDVQQDDA9DZXJ0dW0gUUNBIDIwMTcxGTAXBgNVBGEMEFZBVFBMLTUxNzAzNTk0NTgwHhcNMTkwMjIxMDYwMDAwWhcNMjEwMjIwMDYwMDAwWjBpMRkwFwYDVQQDDBBEYXJpdXN6IE1hamV3c2tpMRAwDgYDVQQqDAdEYXJpdXN6MREwDwYDVQQEDAhNYWpld3NraTEaMBgGA1UEBRMRUE5PUEwtNjIwMjE2MDQ2MTYxCzAJBgNVBAYTAlBMMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAzUt3RBeGDmhzz53LzvcfzuT3dNiwZZrwPGVBfyXKjdHRrM0yegoegB/2z/5EJy7oMLB6X73BYElYJHINq6HHgFECckdombrEoyFyfCFEGp+6SkJS6KzICxTYrC/NcigAqC+LcoYJb3bdeRq12c8/KjF3aU1pfa+sFUSTKVEpCPOTHYLkH/j3/yP4b72smAH+FNkZqzws0CMWFK37CrRwfpap5rsSCWqa8mQD/kYjEoP4DWE9QBxa/f3ay5QgyLnQ6Wjb/+CiiaXgySmzeoTEJlaajOrJ/25K2H6EpIKMaCnWBJ7/Vvii9Pb1QIHBr5fJf68aNbQLtRctAfLsm7V28QIDAQABo4IDHzCCAxswDAYDVR0TAQH/BAIwADA2BgNVHR8ELzAtMCugKaAnhiVodHRwOi8vcWNhLmNybC5jZXJ0dW0ucGwvcWNhXzIwMTcuY3JsMHIGCCsGAQUFBwEBBGYwZDAsBggrBgEFBQcwAYYgaHR0cDovL3FjYS0yMDE3LnFvY3NwLWNlcnR1bS5jb20wNAYIKwYBBQUHMAKGKGh0dHA6Ly9yZXBvc2l0b3J5LmNlcnR1bS5wbC9xY2FfMjAxNy5jZXIwHwYDVR0jBBgwFoAUJ/HYTmBQaLZh/mgbKGxt5AtzCU0wHQYDVR0OBBYEFKdCzxALmtKNEeOdaLS/Uh7WevmAMA4GA1UdDwEB/wQEAwIGwDCCAUgGA1UdIASCAT8wggE7MAkGBwQAi+xAAQIwggEsBgwqhGgBhvZ3AgQBDAEwggEaMC0GCCsGAQUFBwIBFiFodHRwOi8vd3d3LmNlcnR1bS5wbC9yZXBvenl0b3JpdW0wgegGCCsGAQUFBwICMIHbMB8WGEFzc2VjbyBEYXRhIFN5c3RlbXMgUy5BLjADAgEBDIG3Q2VydGlmaWNhdGUgUG9saWN5IGFuZCBDZXJ0aWZpY2F0aW9uIFByYWN0aWNlIFN0YXRlbWVudCBvZiBDZXJ0dW0ncyBRdWFsaWZpZWQgQ2VydGlmaWNhdGlvbiBTZXJ2aWNlcy4gTW9yZSBpbmZvcm1hdGlvbiBjYW4gYmUgZm91bmQgaW4gdGhlIENlcnRpZmljYXRlIFBvbGljeSBvbiBodHRwczovL3d3dy5jZXJ0dW0uZXUuMIHCBggrBgEFBQcBAwSBtTCBsjAIBgYEAI5GAQEwCAYGBACORgEEMIGGBgYEAI5GAQUwfDA8FjZodHRwczovL3JlcG9zaXRvcnkuY2VydHVtLnBsL1BEUy9DZXJ0dW1fUUNBLVBEU19FTi5wZGYTAmVuMDwWNmh0dHBzOi8vcmVwb3NpdG9yeS5jZXJ0dW0ucGwvUERTL0NlcnR1bV9RQ0EtUERTX1BMLnBkZhMCcGwwEwYGBACORgEGMAkGBwQAjkYBBgEwDQYJKoZIhvcNAQELBQADggIBAGXD5An9jvqtjPhvGreSGBBU/QWe8zOmEIDt1k6xlEbmbWnCWGKFOP+UMtSuKaQLyViBZASB0cYvXByriBn6XuUKba9zAQIhisfiqd4rFbDihSajxn4ub4s1lr4JeZmbbRjg7LmdxY5zbjjOoLRCA8LJojflrkSZOX9fRaTSzLX47IS/i/c4GuI03Y9DwUzRAtHOre60r/dmG3Unwvl1+LbYLzwvaIye8n/o91CRA4+mc6eKM1yBiQRCJbtShy8V8yrJPb9d1s4VO3EptY5PIWFIIIUz9sg2SsOWRxTv3Zl35GJ0IT4xsMDhCmmpfoCOK4jZSjZclG+A95PN4d0737EosQxojcFQOMMQNsPQ34axqu6DcHAVqWiHvQvnDFvsROtlzWcOxdwcnemfmdN4qOEndOPYInkcAJ5Nmzxp5SiH/EHz8FphyIi87kc6PmW0ancHHoxZB59CiJiAuxFp3ULryxH8RGt/IIjN4WqOPdq2y7f6OJ3T6UbWX5wdhsIVQl7ZMFsuG5S6MjbRJLWoCWPgV49yTz149hf142saG5PWi7Tzams9vAIwfNvIpismhKdN3+IrpK9UCvf9vSqP1JnlRxUo7qb2VyX8qN+PqtixWfs7uPb7NtsAmbMZJFWwotHMCq6d/CwTWm1oJPCh3HLQIujuCYRr4JmPbFvQfiyv true false false true BES INCLUSIVE false false false false http://time.certum.pl false http://time.certum.pl http://qts10.clide.certum.pl http://localhost:801/pk-tsa http://public-qlts.certum.pl http://public-qlts.certum.pl/qts-17 http://public-qlts.certum.pl/qts-17 yes MIIHeTCCBWGgAwIBAgIQP6Zj23WXXaawMu8t3MSN6DANBgkqhkiG9w0BAQsFADBlMQswCQYDVQQGEwJQTDEhMB8GA1UECgwYQXNzZWNvIERhdGEgU3lzdGVtcyBTLkEuMRgwFgYDVQQDDA9DZXJ0dW0gUUNBIDIwMTcxGTAXBgNVBGEMEFZBVFBMLTUxNzAzNTk0NTgwHhcNMTkwMjIxMDYwMDAwWhcNMjEwMjIwMDYwMDAwWjBpMRkwFwYDVQQDDBBEYXJpdXN6IE1hamV3c2tpMRAwDgYDVQQqDAdEYXJpdXN6MREwDwYDVQQEDAhNYWpld3NraTEaMBgGA1UEBRMRUE5PUEwtNjIwMjE2MDQ2MTYxCzAJBgNVBAYTAlBMMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAzUt3RBeGDmhzz53LzvcfzuT3dNiwZZrwPGVBfyXKjdHRrM0yegoegB/2z/5EJy7oMLB6X73BYElYJHINq6HHgFECckdombrEoyFyfCFEGp+6SkJS6KzICxTYrC/NcigAqC+LcoYJb3bdeRq12c8/KjF3aU1pfa+sFUSTKVEpCPOTHYLkH/j3/yP4b72smAH+FNkZqzws0CMWFK37CrRwfpap5rsSCWqa8mQD/kYjEoP4DWE9QBxa/f3ay5QgyLnQ6Wjb/+CiiaXgySmzeoTEJlaajOrJ/25K2H6EpIKMaCnWBJ7/Vvii9Pb1QIHBr5fJf68aNbQLtRctAfLsm7V28QIDAQABo4IDHzCCAxswDAYDVR0TAQH/BAIwADA2BgNVHR8ELzAtMCugKaAnhiVodHRwOi8vcWNhLmNybC5jZXJ0dW0ucGwvcWNhXzIwMTcuY3JsMHIGCCsGAQUFBwEBBGYwZDAsBggrBgEFBQcwAYYgaHR0cDovL3FjYS0yMDE3LnFvY3NwLWNlcnR1bS5jb20wNAYIKwYBBQUHMAKGKGh0dHA6Ly9yZXBvc2l0b3J5LmNlcnR1bS5wbC9xY2FfMjAxNy5jZXIwHwYDVR0jBBgwFoAUJ/HYTmBQaLZh/mgbKGxt5AtzCU0wHQYDVR0OBBYEFKdCzxALmtKNEeOdaLS/Uh7WevmAMA4GA1UdDwEB/wQEAwIGwDCCAUgGA1UdIASCAT8wggE7MAkGBwQAi+xAAQIwggEsBgwqhGgBhvZ3AgQBDAEwggEaMC0GCCsGAQUFBwIBFiFodHRwOi8vd3d3LmNlcnR1bS5wbC9yZXBvenl0b3JpdW0wgegGCCsGAQUFBwICMIHbMB8WGEFzc2VjbyBEYXRhIFN5c3RlbXMgUy5BLjADAgEBDIG3Q2VydGlmaWNhdGUgUG9saWN5IGFuZCBDZXJ0aWZpY2F0aW9uIFByYWN0aWNlIFN0YXRlbWVudCBvZiBDZXJ0dW0ncyBRdWFsaWZpZWQgQ2VydGlmaWNhdGlvbiBTZXJ2aWNlcy4gTW9yZSBpbmZvcm1hdGlvbiBjYW4gYmUgZm91bmQgaW4gdGhlIENlcnRpZmljYXRlIFBvbGljeSBvbiBodHRwczovL3d3dy5jZXJ0dW0uZXUuMIHCBggrBgEFBQcBAwSBtTCBsjAIBgYEAI5GAQEwCAYGBACORgEEMIGGBgYEAI5GAQUwfDA8FjZodHRwczovL3JlcG9zaXRvcnkuY2VydHVtLnBsL1BEUy9DZXJ0dW1fUUNBLVBEU19FTi5wZGYTAmVuMDwWNmh0dHBzOi8vcmVwb3NpdG9yeS5jZXJ0dW0ucGwvUERTL0NlcnR1bV9RQ0EtUERTX1BMLnBkZhMCcGwwEwYGBACORgEGMAkGBwQAjkYBBgEwDQYJKoZIhvcNAQELBQADggIBAGXD5An9jvqtjPhvGreSGBBU/QWe8zOmEIDt1k6xlEbmbWnCWGKFOP+UMtSuKaQLyViBZASB0cYvXByriBn6XuUKba9zAQIhisfiqd4rFbDihSajxn4ub4s1lr4JeZmbbRjg7LmdxY5zbjjOoLRCA8LJojflrkSZOX9fRaTSzLX47IS/i/c4GuI03Y9DwUzRAtHOre60r/dmG3Unwvl1+LbYLzwvaIye8n/o91CRA4+mc6eKM1yBiQRCJbtShy8V8yrJPb9d1s4VO3EptY5PIWFIIIUz9sg2SsOWRxTv3Zl35GJ0IT4xsMDhCmmpfoCOK4jZSjZclG+A95PN4d0737EosQxojcFQOMMQNsPQ34axqu6DcHAVqWiHvQvnDFvsROtlzWcOxdwcnemfmdN4qOEndOPYInkcAJ5Nmzxp5SiH/EHz8FphyIi87kc6PmW0ancHHoxZB59CiJiAuxFp3ULryxH8RGt/IIjN4WqOPdq2y7f6OJ3T6UbWX5wdhsIVQl7ZMFsuG5S6MjbRJLWoCWPgV49yTz149hf142saG5PWi7Tzams9vAIwfNvIpismhKdN3+IrpK9UCvf9vSqP1JnlRxUo7qb2VyX8qN+PqtixWfs7uPb7NtsAmbMZJFWwotHMCq6d/CwTWm1oJPCh3HLQIujuCYRr4JmPbFvQfiyv false default 1606177413950 1530218665897 NEVER false /devel/00mirror-cvs/00-m32/endesive/examples/certum endesive-2.19.1/examples/certum/enveloping.xml000066400000000000000000000212101504236674500214230ustar00rootroot00000000000000Hu0jm34cGsI0O+z4YPy5a2q3gwEDsa0XxjjdnQfcOr4=kL5NhTGi+ACI2nqHO1j0jskjmCxHfMctla3YPfieNRk=OdmzU2pouhW+3sPv1F/rhf66XBnu1p7vb0W2a+tBQOBAiYq27PFqHcytAUxtQbqG X3sF2cj812TE8uPt1jatToNrP8Ow3OWYAllEyJ784agLf35Q+aAuNALBU7p4iz7y sSwLbCU7tSSVtfaEzC4fNkdWoVEFBVpvMbkI+ywZPPc2qBTZ4xFJDjKVpQ6tp2eQ y7N6CYViMNXLSoR/jgIwCbxDAGm2JmYOju6igyWD7Nq3BPTEoYmsLkmigSX7ELRI lXmb7H6VbL5YQbfitDj0QIfT4ZFHWhZ9jC6I/mrosS4zC+bAMuYNo+L4x/01vumR k7BfnNgxA8twXZ0e5g3iPA==MIIHeTCCBWGgAwIBAgIQP6Zj23WXXaawMu8t3MSN6DANBgkqhkiG9w0BAQsFADBl MQswCQYDVQQGEwJQTDEhMB8GA1UECgwYQXNzZWNvIERhdGEgU3lzdGVtcyBTLkEu MRgwFgYDVQQDDA9DZXJ0dW0gUUNBIDIwMTcxGTAXBgNVBGEMEFZBVFBMLTUxNzAz NTk0NTgwHhcNMTkwMjIxMDYwMDAwWhcNMjEwMjIwMDYwMDAwWjBpMRkwFwYDVQQD DBBEYXJpdXN6IE1hamV3c2tpMRAwDgYDVQQqDAdEYXJpdXN6MREwDwYDVQQEDAhN YWpld3NraTEaMBgGA1UEBRMRUE5PUEwtNjIwMjE2MDQ2MTYxCzAJBgNVBAYTAlBM MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAzUt3RBeGDmhzz53Lzvcf zuT3dNiwZZrwPGVBfyXKjdHRrM0yegoegB/2z/5EJy7oMLB6X73BYElYJHINq6HH gFECckdombrEoyFyfCFEGp+6SkJS6KzICxTYrC/NcigAqC+LcoYJb3bdeRq12c8/ KjF3aU1pfa+sFUSTKVEpCPOTHYLkH/j3/yP4b72smAH+FNkZqzws0CMWFK37CrRw fpap5rsSCWqa8mQD/kYjEoP4DWE9QBxa/f3ay5QgyLnQ6Wjb/+CiiaXgySmzeoTE JlaajOrJ/25K2H6EpIKMaCnWBJ7/Vvii9Pb1QIHBr5fJf68aNbQLtRctAfLsm7V2 8QIDAQABo4IDHzCCAxswDAYDVR0TAQH/BAIwADA2BgNVHR8ELzAtMCugKaAnhiVo dHRwOi8vcWNhLmNybC5jZXJ0dW0ucGwvcWNhXzIwMTcuY3JsMHIGCCsGAQUFBwEB BGYwZDAsBggrBgEFBQcwAYYgaHR0cDovL3FjYS0yMDE3LnFvY3NwLWNlcnR1bS5j b20wNAYIKwYBBQUHMAKGKGh0dHA6Ly9yZXBvc2l0b3J5LmNlcnR1bS5wbC9xY2Ff MjAxNy5jZXIwHwYDVR0jBBgwFoAUJ/HYTmBQaLZh/mgbKGxt5AtzCU0wHQYDVR0O BBYEFKdCzxALmtKNEeOdaLS/Uh7WevmAMA4GA1UdDwEB/wQEAwIGwDCCAUgGA1Ud IASCAT8wggE7MAkGBwQAi+xAAQIwggEsBgwqhGgBhvZ3AgQBDAEwggEaMC0GCCsG AQUFBwIBFiFodHRwOi8vd3d3LmNlcnR1bS5wbC9yZXBvenl0b3JpdW0wgegGCCsG AQUFBwICMIHbMB8WGEFzc2VjbyBEYXRhIFN5c3RlbXMgUy5BLjADAgEBDIG3Q2Vy dGlmaWNhdGUgUG9saWN5IGFuZCBDZXJ0aWZpY2F0aW9uIFByYWN0aWNlIFN0YXRl bWVudCBvZiBDZXJ0dW0ncyBRdWFsaWZpZWQgQ2VydGlmaWNhdGlvbiBTZXJ2aWNl cy4gTW9yZSBpbmZvcm1hdGlvbiBjYW4gYmUgZm91bmQgaW4gdGhlIENlcnRpZmlj YXRlIFBvbGljeSBvbiBodHRwczovL3d3dy5jZXJ0dW0uZXUuMIHCBggrBgEFBQcB AwSBtTCBsjAIBgYEAI5GAQEwCAYGBACORgEEMIGGBgYEAI5GAQUwfDA8FjZodHRw czovL3JlcG9zaXRvcnkuY2VydHVtLnBsL1BEUy9DZXJ0dW1fUUNBLVBEU19FTi5w ZGYTAmVuMDwWNmh0dHBzOi8vcmVwb3NpdG9yeS5jZXJ0dW0ucGwvUERTL0NlcnR1 bV9RQ0EtUERTX1BMLnBkZhMCcGwwEwYGBACORgEGMAkGBwQAjkYBBgEwDQYJKoZI hvcNAQELBQADggIBAGXD5An9jvqtjPhvGreSGBBU/QWe8zOmEIDt1k6xlEbmbWnC WGKFOP+UMtSuKaQLyViBZASB0cYvXByriBn6XuUKba9zAQIhisfiqd4rFbDihSaj xn4ub4s1lr4JeZmbbRjg7LmdxY5zbjjOoLRCA8LJojflrkSZOX9fRaTSzLX47IS/ i/c4GuI03Y9DwUzRAtHOre60r/dmG3Unwvl1+LbYLzwvaIye8n/o91CRA4+mc6eK M1yBiQRCJbtShy8V8yrJPb9d1s4VO3EptY5PIWFIIIUz9sg2SsOWRxTv3Zl35GJ0 IT4xsMDhCmmpfoCOK4jZSjZclG+A95PN4d0737EosQxojcFQOMMQNsPQ34axqu6D cHAVqWiHvQvnDFvsROtlzWcOxdwcnemfmdN4qOEndOPYInkcAJ5Nmzxp5SiH/EHz 8FphyIi87kc6PmW0ancHHoxZB59CiJiAuxFp3ULryxH8RGt/IIjN4WqOPdq2y7f6 OJ3T6UbWX5wdhsIVQl7ZMFsuG5S6MjbRJLWoCWPgV49yTz149hf142saG5PWi7Tz ams9vAIwfNvIpismhKdN3+IrpK9UCvf9vSqP1JnlRxUo7qb2VyX8qN+PqtixWfs7 uPb7NtsAmbMZJFWwotHMCq6d/CwTWm1oJPCh3HLQIujuCYRr4JmPbFvQfiyv2020-11-24T00:24:21ZwnJg+5guQblWVpTXg+djFHlCdB/NAcI4Ts21xCGR6jE=2.5.4.97=#0C10564154504C2D35313730333539343538,CN=Certum QCA 2017,O=Asseco Data Systems S.A.,C=PL84605310358877569721335889391052426728MIME-Version: 1.0 Content-Type: text/xml Content-Transfer-Encoding: binary Content-Disposition: filename="xml-certum-enveloped-bes.xml"http://www.certum.pl/OIDAsURI/signedFile/1.2.616.1.113527.3.1.1.3.1Opis formatu dokumentu oraz jego pełna nazwahttp://www.certum.pl/OIDAsURI/signedFile.pdftext/xml VAT-7 17 1 2017 2 3215 7791011327 Nazwa firmy 630303023 0 3108 3108 0 0 998293 49915 901697 72135 3334214 766869 3177289 187401 44326 8864 0 0 0 0 66801 15364 0 0 0 0 0 0 0 0 0 8713129 913147 512089 54480 12531 8152972 1279013 0 0 -138 1380 1804875 0 0 0 0 891728 0 0 0 0 891728 2 2 2 914842496 2017-05-09 1 endesive-2.19.1/examples/certum/enveloping.xml.config000066400000000000000000000212171504236674500226760ustar00rootroot00000000000000 3.4.0.0 cryptoCertumPKCS11 aetpkss1 cryptoCertum3PKCS crypto3PKCS CCPkiP11 OCSCryptoki SimplySignPKCS opensc-pkcs11 cryptoCertum3PKCS crypto3PKCS SimplySignPKCS cryptoCertum3PKCS crypto3PKCS SimplySignPKCS false false aavYulUYP6qrcNT82yHa8g== IMPLICIT XML falsetrue yes true false BES SHA_256 false true true MIIHeTCCBWGgAwIBAgIQP6Zj23WXXaawMu8t3MSN6DANBgkqhkiG9w0BAQsFADBlMQswCQYDVQQGEwJQTDEhMB8GA1UECgwYQXNzZWNvIERhdGEgU3lzdGVtcyBTLkEuMRgwFgYDVQQDDA9DZXJ0dW0gUUNBIDIwMTcxGTAXBgNVBGEMEFZBVFBMLTUxNzAzNTk0NTgwHhcNMTkwMjIxMDYwMDAwWhcNMjEwMjIwMDYwMDAwWjBpMRkwFwYDVQQDDBBEYXJpdXN6IE1hamV3c2tpMRAwDgYDVQQqDAdEYXJpdXN6MREwDwYDVQQEDAhNYWpld3NraTEaMBgGA1UEBRMRUE5PUEwtNjIwMjE2MDQ2MTYxCzAJBgNVBAYTAlBMMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAzUt3RBeGDmhzz53LzvcfzuT3dNiwZZrwPGVBfyXKjdHRrM0yegoegB/2z/5EJy7oMLB6X73BYElYJHINq6HHgFECckdombrEoyFyfCFEGp+6SkJS6KzICxTYrC/NcigAqC+LcoYJb3bdeRq12c8/KjF3aU1pfa+sFUSTKVEpCPOTHYLkH/j3/yP4b72smAH+FNkZqzws0CMWFK37CrRwfpap5rsSCWqa8mQD/kYjEoP4DWE9QBxa/f3ay5QgyLnQ6Wjb/+CiiaXgySmzeoTEJlaajOrJ/25K2H6EpIKMaCnWBJ7/Vvii9Pb1QIHBr5fJf68aNbQLtRctAfLsm7V28QIDAQABo4IDHzCCAxswDAYDVR0TAQH/BAIwADA2BgNVHR8ELzAtMCugKaAnhiVodHRwOi8vcWNhLmNybC5jZXJ0dW0ucGwvcWNhXzIwMTcuY3JsMHIGCCsGAQUFBwEBBGYwZDAsBggrBgEFBQcwAYYgaHR0cDovL3FjYS0yMDE3LnFvY3NwLWNlcnR1bS5jb20wNAYIKwYBBQUHMAKGKGh0dHA6Ly9yZXBvc2l0b3J5LmNlcnR1bS5wbC9xY2FfMjAxNy5jZXIwHwYDVR0jBBgwFoAUJ/HYTmBQaLZh/mgbKGxt5AtzCU0wHQYDVR0OBBYEFKdCzxALmtKNEeOdaLS/Uh7WevmAMA4GA1UdDwEB/wQEAwIGwDCCAUgGA1UdIASCAT8wggE7MAkGBwQAi+xAAQIwggEsBgwqhGgBhvZ3AgQBDAEwggEaMC0GCCsGAQUFBwIBFiFodHRwOi8vd3d3LmNlcnR1bS5wbC9yZXBvenl0b3JpdW0wgegGCCsGAQUFBwICMIHbMB8WGEFzc2VjbyBEYXRhIFN5c3RlbXMgUy5BLjADAgEBDIG3Q2VydGlmaWNhdGUgUG9saWN5IGFuZCBDZXJ0aWZpY2F0aW9uIFByYWN0aWNlIFN0YXRlbWVudCBvZiBDZXJ0dW0ncyBRdWFsaWZpZWQgQ2VydGlmaWNhdGlvbiBTZXJ2aWNlcy4gTW9yZSBpbmZvcm1hdGlvbiBjYW4gYmUgZm91bmQgaW4gdGhlIENlcnRpZmljYXRlIFBvbGljeSBvbiBodHRwczovL3d3dy5jZXJ0dW0uZXUuMIHCBggrBgEFBQcBAwSBtTCBsjAIBgYEAI5GAQEwCAYGBACORgEEMIGGBgYEAI5GAQUwfDA8FjZodHRwczovL3JlcG9zaXRvcnkuY2VydHVtLnBsL1BEUy9DZXJ0dW1fUUNBLVBEU19FTi5wZGYTAmVuMDwWNmh0dHBzOi8vcmVwb3NpdG9yeS5jZXJ0dW0ucGwvUERTL0NlcnR1bV9RQ0EtUERTX1BMLnBkZhMCcGwwEwYGBACORgEGMAkGBwQAjkYBBgEwDQYJKoZIhvcNAQELBQADggIBAGXD5An9jvqtjPhvGreSGBBU/QWe8zOmEIDt1k6xlEbmbWnCWGKFOP+UMtSuKaQLyViBZASB0cYvXByriBn6XuUKba9zAQIhisfiqd4rFbDihSajxn4ub4s1lr4JeZmbbRjg7LmdxY5zbjjOoLRCA8LJojflrkSZOX9fRaTSzLX47IS/i/c4GuI03Y9DwUzRAtHOre60r/dmG3Unwvl1+LbYLzwvaIye8n/o91CRA4+mc6eKM1yBiQRCJbtShy8V8yrJPb9d1s4VO3EptY5PIWFIIIUz9sg2SsOWRxTv3Zl35GJ0IT4xsMDhCmmpfoCOK4jZSjZclG+A95PN4d0737EosQxojcFQOMMQNsPQ34axqu6DcHAVqWiHvQvnDFvsROtlzWcOxdwcnemfmdN4qOEndOPYInkcAJ5Nmzxp5SiH/EHz8FphyIi87kc6PmW0ancHHoxZB59CiJiAuxFp3ULryxH8RGt/IIjN4WqOPdq2y7f6OJ3T6UbWX5wdhsIVQl7ZMFsuG5S6MjbRJLWoCWPgV49yTz149hf142saG5PWi7Tzams9vAIwfNvIpismhKdN3+IrpK9UCvf9vSqP1JnlRxUo7qb2VyX8qN+PqtixWfs7uPb7NtsAmbMZJFWwotHMCq6d/CwTWm1oJPCh3HLQIujuCYRr4JmPbFvQfiyv true false false true BES INCLUSIVE false false false false http://time.certum.pl false http://time.certum.pl http://qts10.clide.certum.pl http://localhost:801/pk-tsa http://public-qlts.certum.pl http://public-qlts.certum.pl/qts-17 http://public-qlts.certum.pl/qts-17 yes MIIHeTCCBWGgAwIBAgIQP6Zj23WXXaawMu8t3MSN6DANBgkqhkiG9w0BAQsFADBlMQswCQYDVQQGEwJQTDEhMB8GA1UECgwYQXNzZWNvIERhdGEgU3lzdGVtcyBTLkEuMRgwFgYDVQQDDA9DZXJ0dW0gUUNBIDIwMTcxGTAXBgNVBGEMEFZBVFBMLTUxNzAzNTk0NTgwHhcNMTkwMjIxMDYwMDAwWhcNMjEwMjIwMDYwMDAwWjBpMRkwFwYDVQQDDBBEYXJpdXN6IE1hamV3c2tpMRAwDgYDVQQqDAdEYXJpdXN6MREwDwYDVQQEDAhNYWpld3NraTEaMBgGA1UEBRMRUE5PUEwtNjIwMjE2MDQ2MTYxCzAJBgNVBAYTAlBMMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAzUt3RBeGDmhzz53LzvcfzuT3dNiwZZrwPGVBfyXKjdHRrM0yegoegB/2z/5EJy7oMLB6X73BYElYJHINq6HHgFECckdombrEoyFyfCFEGp+6SkJS6KzICxTYrC/NcigAqC+LcoYJb3bdeRq12c8/KjF3aU1pfa+sFUSTKVEpCPOTHYLkH/j3/yP4b72smAH+FNkZqzws0CMWFK37CrRwfpap5rsSCWqa8mQD/kYjEoP4DWE9QBxa/f3ay5QgyLnQ6Wjb/+CiiaXgySmzeoTEJlaajOrJ/25K2H6EpIKMaCnWBJ7/Vvii9Pb1QIHBr5fJf68aNbQLtRctAfLsm7V28QIDAQABo4IDHzCCAxswDAYDVR0TAQH/BAIwADA2BgNVHR8ELzAtMCugKaAnhiVodHRwOi8vcWNhLmNybC5jZXJ0dW0ucGwvcWNhXzIwMTcuY3JsMHIGCCsGAQUFBwEBBGYwZDAsBggrBgEFBQcwAYYgaHR0cDovL3FjYS0yMDE3LnFvY3NwLWNlcnR1bS5jb20wNAYIKwYBBQUHMAKGKGh0dHA6Ly9yZXBvc2l0b3J5LmNlcnR1bS5wbC9xY2FfMjAxNy5jZXIwHwYDVR0jBBgwFoAUJ/HYTmBQaLZh/mgbKGxt5AtzCU0wHQYDVR0OBBYEFKdCzxALmtKNEeOdaLS/Uh7WevmAMA4GA1UdDwEB/wQEAwIGwDCCAUgGA1UdIASCAT8wggE7MAkGBwQAi+xAAQIwggEsBgwqhGgBhvZ3AgQBDAEwggEaMC0GCCsGAQUFBwIBFiFodHRwOi8vd3d3LmNlcnR1bS5wbC9yZXBvenl0b3JpdW0wgegGCCsGAQUFBwICMIHbMB8WGEFzc2VjbyBEYXRhIFN5c3RlbXMgUy5BLjADAgEBDIG3Q2VydGlmaWNhdGUgUG9saWN5IGFuZCBDZXJ0aWZpY2F0aW9uIFByYWN0aWNlIFN0YXRlbWVudCBvZiBDZXJ0dW0ncyBRdWFsaWZpZWQgQ2VydGlmaWNhdGlvbiBTZXJ2aWNlcy4gTW9yZSBpbmZvcm1hdGlvbiBjYW4gYmUgZm91bmQgaW4gdGhlIENlcnRpZmljYXRlIFBvbGljeSBvbiBodHRwczovL3d3dy5jZXJ0dW0uZXUuMIHCBggrBgEFBQcBAwSBtTCBsjAIBgYEAI5GAQEwCAYGBACORgEEMIGGBgYEAI5GAQUwfDA8FjZodHRwczovL3JlcG9zaXRvcnkuY2VydHVtLnBsL1BEUy9DZXJ0dW1fUUNBLVBEU19FTi5wZGYTAmVuMDwWNmh0dHBzOi8vcmVwb3NpdG9yeS5jZXJ0dW0ucGwvUERTL0NlcnR1bV9RQ0EtUERTX1BMLnBkZhMCcGwwEwYGBACORgEGMAkGBwQAjkYBBgEwDQYJKoZIhvcNAQELBQADggIBAGXD5An9jvqtjPhvGreSGBBU/QWe8zOmEIDt1k6xlEbmbWnCWGKFOP+UMtSuKaQLyViBZASB0cYvXByriBn6XuUKba9zAQIhisfiqd4rFbDihSajxn4ub4s1lr4JeZmbbRjg7LmdxY5zbjjOoLRCA8LJojflrkSZOX9fRaTSzLX47IS/i/c4GuI03Y9DwUzRAtHOre60r/dmG3Unwvl1+LbYLzwvaIye8n/o91CRA4+mc6eKM1yBiQRCJbtShy8V8yrJPb9d1s4VO3EptY5PIWFIIIUz9sg2SsOWRxTv3Zl35GJ0IT4xsMDhCmmpfoCOK4jZSjZclG+A95PN4d0737EosQxojcFQOMMQNsPQ34axqu6DcHAVqWiHvQvnDFvsROtlzWcOxdwcnemfmdN4qOEndOPYInkcAJ5Nmzxp5SiH/EHz8FphyIi87kc6PmW0ancHHoxZB59CiJiAuxFp3ULryxH8RGt/IIjN4WqOPdq2y7f6OJ3T6UbWX5wdhsIVQl7ZMFsuG5S6MjbRJLWoCWPgV49yTz149hf142saG5PWi7Tzams9vAIwfNvIpismhKdN3+IrpK9UCvf9vSqP1JnlRxUo7qb2VyX8qN+PqtixWfs7uPb7NtsAmbMZJFWwotHMCq6d/CwTWm1oJPCh3HLQIujuCYRr4JmPbFvQfiyv false default 1606177413950 1530218665897 NEVER false /devel/00mirror-cvs/00-m32/endesive/examples/certum endesive-2.19.1/examples/certum/xml-certum000077500000000000000000000001661504236674500205650ustar00rootroot00000000000000#!/bin/bash /devel/bin/proCertumSmartSign-8.1.15/proCertumSmartSign.sh \ $* #--configuration $1.config \ #--sign $1 \ endesive-2.19.1/examples/csmimersaca.cer000066400000000000000000000032661504236674500202310ustar00rootroot0000000000000000 2',Wl0  *H  0z1 0 UPL1!0U Asseco Data Systems S.A.1'0%U Certum Certification Authority10UCertum Trusted Root CA0 230801080949Z 380723080949Z0N1 0 UPL1!0U Asseco Data Systems S.A.10U Certum SMIME RSA CA0"0  *H 0 ӹ_L{U0xd0ɫZp 1= -t?mzk$3>+is2\?Dљ%n;>_(𝦜ZK5O}Qe[#WD_C~ QK_9azFva_Qgog!ENriZ 6Z_"0<*-DtϟOS#rKGEb\fz7WKu,10XQI ʼnzK°c̍F*t=r()"\042\047\134\177-\377]') def e(s): if isinstance(s, bytes): s = str(s, "latin-1") return ESC_PAT.sub(lambda m: "&#%d;" % ord(m.group(0)), s) def dumpxml(out, obj, codec=None): if obj is None: out.write("") return if isinstance(obj, dict): out.write('\n' % len(obj)) for (k, v) in obj.items(): out.write("%s\n" % k) out.write("") dumpxml(out, v) out.write("\n") out.write("") return if isinstance(obj, list): out.write('\n' % len(obj)) for v in obj: dumpxml(out, v) out.write("\n") out.write("") return if isinstance(obj, ((str,), bytes)): out.write('%s' % (len(obj), e(obj))) return if isinstance(obj, PDFStream): if codec == "raw": out.write(obj.get_rawdata()) elif codec == "binary": out.write(obj.get_data()) else: out.write("\n\n") dumpxml(out, obj.attrs) out.write("\n\n") if codec == "text": data = obj.get_data() out.write('%s\n' % (len(data), e(data))) out.write("") return if isinstance(obj, PDFObjRef): out.write('' % obj.objid) return if isinstance(obj, PSKeyword): out.write("%s" % obj.name) return if isinstance(obj, PSLiteral): out.write("%s" % obj.name) return if isnumber(obj): out.write("%s" % obj) return raise TypeError(obj) def dumptrailers(out, doc): for xref in doc.xrefs: out.write("\n") dumpxml(out, xref.trailer) out.write("\n\n\n") return def dumpallobjs(out, doc, codec=None): visited = set() out.write("") for xref in doc.xrefs: for objid in xref.get_objids(): if objid in visited: continue visited.add(objid) try: obj = doc.getobj(objid) if obj is None: continue out.write('\n' % objid) dumpxml(out, obj, codec=codec) out.write("\n\n\n") except PDFObjectNotFound as e: print("not found: %r" % e) dumptrailers(out, doc) out.write("") return def dumpoutline( outfp, fname, objids, pagenos, password="", dumpall=False, codec=None, extractdir=None, ): fp = open(fname, "rb") parser = PDFParser(fp) doc = PDFDocument(parser, password) pages = { page.pageid: pageno for (pageno, page) in enumerate(PDFPage.create_pages(doc), 1) } def resolve_dest(dest): if isinstance(dest, str): dest = resolve1(doc.get_dest(dest)) elif isinstance(dest, PSLiteral): dest = resolve1(doc.get_dest(dest.name)) if isinstance(dest, dict): dest = dest["D"] if isinstance(dest, PDFObjRef): dest = dest.resolve() return dest try: outlines = doc.get_outlines() outfp.write("\n") for (level, title, dest, a, se) in outlines: pageno = None if dest: dest = resolve_dest(dest) pageno = pages[dest[0].objid] elif a: action = a if isinstance(action, dict): subtype = action.get("S") if subtype and repr(subtype) == "/'GoTo'" and action.get("D"): dest = resolve_dest(action["D"]) pageno = pages[dest[0].objid] s = e(title).encode("utf-8", "xmlcharrefreplace") outfp.write('\n'.format(level, s)) if dest is not None: outfp.write("") dumpxml(outfp, dest) outfp.write("\n") if pageno is not None: outfp.write("%r\n" % pageno) outfp.write("\n") outfp.write("\n") except PDFNoOutlines: pass parser.close() fp.close() return LITERAL_FILESPEC = LIT("Filespec") LITERAL_EMBEDDEDFILE = LIT("EmbeddedFile") def extractembedded( outfp, fname, objids, pagenos, password="", dumpall=False, codec=None, extractdir=None, ): def extract1(objid, obj): filename = os.path.basename(obj.get("UF") or obj.get("F").decode()) fileref = obj["EF"].get("UF") or obj["EF"].get("F") fileobj = doc.getobj(fileref.objid) if not isinstance(fileobj, PDFStream): error_msg = ( "unable to process PDF: reference for %r is not a " "PDFStream" % filename ) raise PDFValueError(error_msg) if fileobj.get("Type") is not LITERAL_EMBEDDEDFILE: raise PDFValueError( "unable to process PDF: reference for %r " "is not an EmbeddedFile" % (filename) ) path = os.path.join(extractdir, "%.6d-%s" % (objid, filename)) if os.path.exists(path): raise IOError("file exists: %r" % path) print("extracting: %r" % path) os.makedirs(os.path.dirname(path), exist_ok=True) out = open(path, "wb") out.write(fileobj.get_data()) out.close() return with open(fname, "rb") as fp: parser = PDFParser(fp) doc = PDFDocument(parser, password) extracted_objids = set() for xref in doc.xrefs: for objid in xref.get_objids(): obj = doc.getobj(objid) if ( objid not in extracted_objids and isinstance(obj, dict) and obj.get("Type") is LITERAL_FILESPEC ): extracted_objids.add(objid) extract1(objid, obj) return def dumppdf( outfp, fname, objids, pagenos, password="", dumpall=False, codec=None, extractdir=None, ): fp = open(fname, "rb") parser = PDFParser(fp) doc = PDFDocument(parser, password) if objids: for objid in objids: obj = doc.getobj(objid) dumpxml(outfp, obj, codec=codec) if pagenos: for (pageno, page) in enumerate(PDFPage.create_pages(doc)): if pageno in pagenos: if codec: for obj in page.contents: obj = stream_value(obj) dumpxml(outfp, obj, codec=codec) else: dumpxml(outfp, page.attrs) if dumpall: dumpallobjs(outfp, doc, codec=codec) if (not objids) and (not pagenos) and (not dumpall): dumptrailers(outfp, doc) fp.close() if codec not in ("raw", "binary"): outfp.write("\n") return def create_parser(): parser = ArgumentParser(description=__doc__, add_help=True) parser.add_argument( "files", type=str, default=None, nargs="+", help="One or more paths to PDF files.", ) parser.add_argument( "--debug", "-d", default=False, action="store_true", help="Use debug logging level.", ) procedure_parser = parser.add_mutually_exclusive_group() procedure_parser.add_argument( "--extract-toc", "-T", default=False, action="store_true", help="Extract structure of outline", ) procedure_parser.add_argument( "--extract-embedded", "-E", type=str, help="Extract embedded files" ) parse_params = parser.add_argument_group( "Parser", description="Used during PDF parsing" ) parse_params.add_argument( "--page-numbers", type=int, default=None, nargs="+", help="A space-seperated list of page numbers to parse.", ) parse_params.add_argument( "--pagenos", "-p", type=str, help="A comma-separated list of page numbers to parse. Included for " "legacy applications, use --page-numbers for more idiomatic " "argument entry.", ) parse_params.add_argument( "--objects", "-i", type=str, help="Comma separated list of object numbers to extract", ) parse_params.add_argument( "--all", "-a", default=False, action="store_true", help="If the structure of all objects should be extracted", ) parse_params.add_argument( "--password", "-P", type=str, default="", help="The password to use for decrypting PDF file.", ) output_params = parser.add_argument_group( "Output", description="Used during output generation." ) output_params.add_argument( "--outfile", "-o", type=str, default="-", help='Path to file where output is written. Or "-" (default) to ' "write to stdout.", ) codec_parser = output_params.add_mutually_exclusive_group() codec_parser.add_argument( "--raw-stream", "-r", default=False, action="store_true", help="Write stream objects without encoding", ) codec_parser.add_argument( "--binary-stream", "-b", default=False, action="store_true", help="Write stream objects with binary encoding", ) codec_parser.add_argument( "--text-stream", "-t", default=False, action="store_true", help="Write stream objects as plain text", ) return parser def main(argv=None): parser = create_parser() args = parser.parse_args(args=argv) if args.debug: logging.getLogger().setLevel(logging.DEBUG) if args.outfile == "-": outfp = sys.stdout else: outfp = open(args.outfile, "w") if args.objects: objids = [int(x) for x in args.objects.split(",")] else: objids = [] if args.page_numbers: pagenos = {x - 1 for x in args.page_numbers} elif args.pagenos: pagenos = {int(x) - 1 for x in args.pagenos.split(",")} else: pagenos = set() password = args.password if args.raw_stream: codec = "raw" elif args.binary_stream: codec = "binary" elif args.text_stream: codec = "text" else: codec = None if args.extract_toc: extractdir = None proc = dumpoutline elif args.extract_embedded: extractdir = args.extract_embedded proc = extractembedded else: extractdir = None proc = dumppdf for fname in args.files: proc( outfp, fname, objids, pagenos, password=password, dumpall=args.all, codec=codec, extractdir=extractdir, ) outfp.close() return 0 if __name__ == "__main__": sys.exit(main()) endesive-2.19.1/examples/hsm000077500000000000000000000000551504236674500157550ustar00rootroot00000000000000SOFTHSM2_CONF=softhsm2.conf softhsm2-util $* endesive-2.19.1/examples/hsm-pkcs000077500000000000000000000002341504236674500167120ustar00rootroot00000000000000#!/bin/bash export OPENSC_DEBUG=9 export PYKCS11LIB=/usr/lib/softhsm/libsofthsm2.so export SOFTHSM_CONF=./softhsm2.conf pkcs11-tool --module $PYKCS11LIB $* endesive-2.19.1/examples/java-compile000077500000000000000000000002331504236674500175330ustar00rootroot00000000000000#!/bin/bash thisdir=`dirname $0` jars="$thisdir" addjar(){ jars="$jars:$1" } for fname in $thisdir/java/*.jar; do addjar $fname done javac -cp $jars $1endesive-2.19.1/examples/kir.py000066400000000000000000000006121504236674500163760ustar00rootroot00000000000000import sys if sys.platform == "win32": dllpath = r"c:\windows\system32\cryptoCertum3PKCS.dll" else: import ctypes as ct if 0: openssl_1_1 = [ ct.CDLL('/usr/lib/x86_64-linux-gnu/libcrypto.so', ct.RTLD_GLOBAL), ct.CDLL('/usr/lib/x86_64-linux-gnu/libssl.so', ct.RTLD_GLOBAL), ] dllpath = '/devel/lib/pkcs11libs/libCCGraphiteP11.2.0.5.6.so' endesive-2.19.1/examples/m2-demo.py000077500000000000000000000204361504236674500170620ustar00rootroot00000000000000#!/usr/bin/env vpython2 import os import os.path import smtplib import datetime from email.MIMEMultipart import MIMEMultipart from email.MIMEBase import MIMEBase from email.MIMEText import MIMEText from email.Utils import COMMASPACE, formatdate from email import Encoders from M2Crypto import BIO, Rand, SMIME, X509 randpool = '/tmp/randpool.dat' ca_cert = 'ca/demo2_ca.crt.pem' # we need to have access to both keys signer_key = 'ca/demo2_user1.key.pem' signer_cert = 'ca/demo2_user1.crt.pem' recipient_key = 'ca/demo2_user2.key.pem' recipient_cert = 'ca/demo2_user2.crt.pem' def makebuf(text): return BIO.MemoryBuffer(text) class Demo: def sign(self): # Make a MemoryBuffer of the message. buf = makebuf('a sign of our times') # Seed the PRNG. Rand.load_file(randpool, -1) # Instantiate an SMIME object; set it up; sign the buffer. s = SMIME.SMIME() s.load_key(signer_key, signer_cert) p7 = s.sign(buf, SMIME.PKCS7_DETACHED) # Recreate buf. buf = makebuf('a sign of our times') # Output p7 in mail-friendly format. out = BIO.MemoryBuffer() out.write('From: sender@example.dom\n') out.write('To: recipient@example.dom\n') out.write('Subject: M2Crypto S/MIME testing\n') s.write(out, p7, buf) result = out.read() # Save the PRNG's state. Rand.save_file(randpool) open('smime-m2-sign.txt', 'wt').write(result) def verify(self): # Instantiate an SMIME object. s = SMIME.SMIME() # Load the signer's cert. x509 = X509.load_cert(signer_cert) sk = X509.X509_Stack() sk.push(x509) s.set_x509_stack(sk) # Load the signer's CA cert. st = X509.X509_Store() st.load_info(ca_cert) s.set_x509_store(st) # Load the data, verify it. p7, data = SMIME.smime_load_pkcs7('smime-m2-sign.txt') v = s.verify(p7) print v print data print data.read() def encrypt(self): # Make a MemoryBuffer of the message. buf = makebuf('a sign of our times') # Seed the PRNG. Rand.load_file(randpool, -1) # Instantiate an SMIME object. s = SMIME.SMIME() # Load target cert to encrypt to. x509 = X509.load_cert(recipient_cert) sk = X509.X509_Stack() sk.push(x509) s.set_x509_stack(sk) # Set cipher: 3-key triple-DES in CBC mode. s.set_cipher(SMIME.Cipher('des_ede3_cbc')) # Encrypt the buffer. p7 = s.encrypt(buf) # Output p7 in mail-friendly format. out = BIO.MemoryBuffer() out.write('From: sender@example.dom\n') out.write('To: recipient@example.dom\n') out.write('Subject: M2Crypto S/MIME testing\n') s.write(out, p7) result = out.read() # Save the PRNG's state. Rand.save_file(randpool) open('smime-m2-encrypt.txt', 'wt').write(result) def decrypt(self): # Instantiate an SMIME object. s = SMIME.SMIME() # Load private key and cert. s.load_key(recipient_key, recipient_cert) # Load the encrypted data. p7, data = SMIME.smime_load_pkcs7('smime-m2-encrypt.txt') # Decrypt p7. out = s.decrypt(p7) print out def sign_and_encrypt(self): # Make a MemoryBuffer of the message. buf = makebuf('a sign of our times') # Seed the PRNG. Rand.load_file(randpool, -1) # Instantiate an SMIME object. s = SMIME.SMIME() # Load signer's key and cert. Sign the buffer. s.load_key(signer_key, signer_cert) p7 = s.sign(buf, SMIME.PKCS7_DETACHED) # Load target cert to encrypt the signed message to. x509 = X509.load_cert(recipient_cert) sk = X509.X509_Stack() sk.push(x509) s.set_x509_stack(sk) # Set cipher: 3-key triple-DES in CBC mode. s.set_cipher(SMIME.Cipher('des_ede3_cbc')) # Create a temporary buffer. tmp = BIO.MemoryBuffer() # Write the signed message into the temporary buffer. s.write(tmp, p7, buf) # Encrypt the temporary buffer. p7 = s.encrypt(tmp) # Output p7 in mail-friendly format. out = BIO.MemoryBuffer() out.write('From: sender@example.dom\n') out.write('To: recipient@example.dom\n') out.write('Subject: M2Crypto S/MIME testing\n') s.write(out, p7) result = out.read() # Save the PRNG's state. Rand.save_file(randpool) open('smime-m2-sign-encrypt.txt', 'wt').write(result) def decrypt_and_verify(self): # Instantiate an SMIME object. s = SMIME.SMIME() # Load private key and cert. s.load_key(recipient_key, recipient_cert) # Load the signed/encrypted data. p7, data = SMIME.smime_load_pkcs7('smime-m2-sign-encrypt.txt') # After the above step, 'data' == None. # Decrypt p7. 'out' now contains a PKCS #7 signed blob. out = s.decrypt(p7) # Load the signer's cert. x509 = X509.load_cert(signer_cert) sk = X509.X509_Stack() sk.push(x509) s.set_x509_stack(sk) # Load the signer's CA cert. st = X509.X509_Store() st.load_info(ca_cert) s.set_x509_store(st) # Recall 'out' contains a PKCS #7 blob. # Transform 'out'; verify the resulting PKCS #7 blob. p7_bio = BIO.MemoryBuffer(out) p7, data = SMIME.smime_load_pkcs7_bio(p7_bio) v = s.verify(p7) print v def sign_and_attachment(self): server = 'mail.example.dom' sender = 'sender@example.dom' to = ['recipient@example.dom',] subject = 'test' text = 'test message' files=['m2-demo.py'] attachments={} bcc=[] if isinstance(to,str): to = [to] # create multipart message msg = MIMEMultipart() # attach message text as first attachment msg.attach( MIMEText(text) ) # attach files to be read from file system for file in files: part = MIMEBase('application', "octet-stream") part.set_payload( open(file,"rb").read() ) Encoders.encode_base64(part) part.add_header('Content-Disposition', 'attachment; filename="%s"' % os.path.basename(file)) msg.attach(part) # attach filest read from dictionary for name in attachments: part = MIMEBase('application', "octet-stream") part.set_payload(attachments[name]) Encoders.encode_base64(part) part.add_header('Content-Disposition', 'attachment; filename="%s"' % name) msg.attach(part) # put message with attachments into into SSL' I/O buffer msg_str = msg.as_string() buf = BIO.MemoryBuffer(msg_str) # load seed file for PRNG Rand.load_file(randpool, -1) smime = SMIME.SMIME() # load certificate smime.load_key(signer_key, signer_cert) # sign whole message p7 = smime.sign(buf, SMIME.PKCS7_DETACHED) # create buffer for final mail and write header out = BIO.MemoryBuffer() out.write('From: %s\n' % sender) out.write('To: %s\n' % COMMASPACE.join(to)) out.write('Date: %s\n' % formatdate(localtime=True)) out.write('Subject: %s\n' % subject) out.write('Auto-Submitted: %s\n' % 'auto-generated') # convert message back into string buf = BIO.MemoryBuffer(msg_str) # append signed message and original message to mail header smime.write(out, p7, buf) # load save seed file for PRNG Rand.save_file(randpool) # extend list of recipents with bcc adresses to.extend(bcc) result = out.read() open('smime-m2-attachment.txt', 'wt').write(result) return # finaly send mail smtp = smtplib.SMTP(server) smtp.sendmail(sender, to, result ) smtp.close() def main(): cls = Demo() if 0: cls.sign() cls.encrypt() cls.sign_and_encrypt() cls.sign_and_attachment() cls.verify() cls.decrypt() cls.decrypt_and_verify() main() endesive-2.19.1/examples/mypy.ini000066400000000000000000000010101504236674500167270ustar00rootroot00000000000000[mypy] ;strict = True ;strict_bytes = True local_partial_types = True ;disallow_any_unimported = True ;show_traceback = True pretty = True always_false = MYPYC plugins = mypy.plugins.proper_plugin python_version = 3.11 ;exclude = mypy/typeshed/|mypyc/test-data/|mypyc/lib-rt/ ;enable_error_code = ignore-without-code,redundant-expr ;enable_incomplete_feature = PreciseTupleTypes show_error_code_links = True ;try_statements = 25 [mypy-mypy.*] # TODO: enable for `mypyc` and other files as well warn_unreachable = True endesive-2.19.1/examples/pdf-acrobat.pdf000066400000000000000000002120751504236674500201240ustar00rootroot00000000000000%PDF-1.6 % 13 0 obj <> endobj 24 0 obj <>/Filter/FlateDecode/ID[<91E90C762D9B7F4BB01E4DF9BF08293C>]/Index[13 20]/Info 12 0 R/Length 66/Prev 70406/Root 14 0 R/Size 33/Type/XRef/W[1 2 1]>>stream hbbd``b`j @a5Dq H_f`bdXRϸ@6 endstream endobj startxref 0 %%EOF 32 0 obj <>stream hb```fFn130p<FPP z[8. 3#fZtH3dMd҇0\0R endstream endobj 14 0 obj <> endobj 15 0 obj <> endobj 16 0 obj <>>>/Subtype/Form/Type/XObject>>stream /FRM Do endstream endobj 17 0 obj <>>>/Subtype/Form/Type/XObject>>stream H*T0T0BgU)c0 endstream endobj 18 0 obj <>/Subtype/Form/Type/XObject>>stream % DSBlank endstream endobj 19 0 obj <>/ProcSet[/PDF/Text]>>/Subtype/Form/Type/XObject>>stream HUnS1+\~tPHWbЖ@Ҵi%Ds|C$(QB%^t;dd {$T(#< *> P٢Tӧ=|Gāq.2+܇6$1#ŗ˨؂C,B *yO(hEW2tYy-m&%hB$F- M X TXUfRS,B60ےMRv*3\ၒ3'''[@ # TV#xf k`DC4!ȇ<H+5 GQ#щ(QZoEĂ4X:B1XivO$G鎨VsV\7zܸ8YbBD`(׋F`:o ySD ~$I#VW%+>ӵ8ZgXANeXn vKh;9cII)PVpVEK 6,am[I>C+@mŸYWMs ;~_>b: 0,quQL E(]vޙ׻ߗgm4>[驪-׮]Cq u#FeI::^ՖB-::,_mo~<ƞye/7/ے%U{no3//M' "vWν:o endstream endobj 20 0 obj <>stream H\V t׼_wvb)j!$<HB18M'̈́ٙdv$DkQQz* RSBAJ)(H"EE0DX Cad$RLEJH5R#" iFd$t iEC N/Q4r P[hzZA2ځ>cY/-m;ww]Iyڿοٿf LM-p/8kՠ/( `O/JpKpOp!4Bq}PWКжо{ X!6Ucc  ۀbاE5I6|8> /Yxށw=c*x?߅GgWB!NBEB/We(f3Ōg1̴1bQf9$yyg^a~żlb2ۙf/9aN2+b v4;.bcvUZv;{=^f͉Pn87+&rSrnW~%8KsrrOpOs5ܫn+{{{;} (oK{i|%_7w]|_˿#GiS!7o c L~ /4 -BR0 ~aU!  '3?/0(.P & A3P@;c`/~^.8 "") `q8R-+N9bCQU1%.{ŕ/u-O~xTxA"~)/ 3pIpk3dxMx{)ȑ"/D6GG>\ DQ:*FFGGESYhKԈvGWD*QdqcKjak$\8~BXך1IUJuN:چ[ks!倊#O-).m== pFX1W1XFJI5ZḊ1dܷu.(+`y`46k/gv 6wǻcw}5Z"&*DIS ITIQi+RJmRTU+4j@Q:s?{wJ0̹={h4-"F#,Q1d$&ܘɤ&3+垏W<:( 1D:k '&xR'gsp lB:x-Xt:ӳ9)Xg5+BF, ˺M|#G<y>|)))))))))))))))) 'O ?A~ 'O? AVN5Ԭ+#y׽%^v2o4'Wo4 MFхQSSSSSSSӨӨӨӨӨӨӨӨ Q.D]u!Bԅөөөөөөөө S LAxh44A&DO@JJJJJJJFFFFFFFF]u!Bԅ Q.DNNNNNNNN]0a A=]V۸mCva(w|X.SAlFx.'s2D>2CX𪳪ȝfTQM><)Lzf?^_qU棟I2Z7wHc4;sn'hy#,v,7cv='{;1qJnvȂ.\ӾQS1L8M;_&CSpD'SV,\^qmd#L{2|sdN)#cFDB)Ғsp0S'dZ,%`98I9g1#5*HAIVRrrII˽v[fZ2&'-(;̤,37)js1ytn`@'(*Ŝ0w;^܏QTc(!AQ\zQu⻘g`ދ`(Y'Q&`Aǂ>7h^9X۰/cQZ.Q',i’XrqKXKkKϠeQ$~Pve(߉(GXփeOa<,?`EVXq+`e+۰"V-Ī}XV`V Pщ?XkbX;)*O-ۅuX*W`/AC6njQ T@4{~kPmTjZPӅQ| 5PV6Z AU~x Gl b(6}Ӹ||[4PE.ԟB4 .4@MSyx d7[8|A9  *_C @!pͧ| -}hy0bQl;ma;x5Յ]FV~ j5Ǡ6Av BOA_}?>ϱ{#vOg{V3 ƾоh:t vxN3 .x +^x{޷Y؏Xga$> |y3z+у+߃2w,,~I,cK7,sbTgsxVسb"+βҁ[Xi6 +UXuCXšI!`6'xZ+ֺv ko#PO`$̺1+'hA۲>\ʆlxleL,&濳ًWbÖil`&/r¾&la}b 'c;s;YŮ*dhv''hCxב3%ҕHO" ߛAHTkF':jMb}ˡcr8n"-G&q$}91sHEN INv?'H|9s vc!C$ؑ- IXIVHGFRKILRIGIɩS9uΜ^#HdOəN ]rfpn 9?pK.bK^RH]Hj!iCG.R<]˥\q'Wΐ#}yd##̿U-Wݹj KETJv'"'G\kVJ]ɝIn9\wF'gEy#! 7sc?(\Ma87fnS$:sk2 c=)؉Ps55f:5!ԤQS3O? /y񌗿W*u0- ovv8o S'䉸fl4{,J\QG>.cĢX<ar(H+%oic&mmki{TMv5bW։UhƋ&GY/*0[:/ytrNyb*yW. (DKtwk/6b)b{IlŮ ;w*ݮ}{׋vZNڋP-QQ#q8qrLqT-=HXFzႱ4mhn sR+!tiRMT귙׫mbe!)F25&zsK[1]ouYiTWz*㵻>^]>*iQNxgci 6U$ź!pS*M:D4pj[\LP2w4l)ڽV2٘B1ĆeT7ruFɣow[C箲oMVۭ_~׭*ҳݳUj(hk_G\**=Ir⏘gs}WF45#~ wdQ3K?[djha8'6}h*͛8%ʌTEJLjt27*@XX+W\zj Fo긱`di^ǎ}o-;|N3\'ѪE宮2~otjrvlt:499}MΟd*mpZϝNiu|]_fyf{_8\FΝ<ܨs-Bߥ&^a]9lViTWm#D"T˨QFVQ[VYeuT hHд APE"ڄ6q3IŹxjHzy}}{u68n&AL~crB*a^CFe8yĘ,Z~Oݲ" oJB{#i2?kj5vv cEWJuddXA,R ^uZT<1`'1BwmLAЎfMLh-`R1SP'6 !P A`8:Iy o;5WcMsb8H?C (O2 '1Xe($Q#m*Z&D%Ÿ$?Y$W@\2i)<1q1'<%1tX)TrjY(W-\8+̅:ζB`*B*brydDz ^ [wQ? DVkE cHikE `qo/8H"`5Z:>t/` l)(x֔:2;g ~乑K:pCB.\?$+ /D:s;LdVާ_yElWnrIwV2aQrV>aE诣l|MG3KdѸWrhmqc]D@ 5맖o@J ⱐ[`юR1M"ebTk "2rsܜ,JT )Jf;<36v` |MRLyg%Lha@ Բv] 6 P VX z܊:`67vs۶ͤf_P(عIѽFQgqD^4El nN aEti=|$5SA ;pGs`#C[T ]GuW [u%:F"{mP&(qUU:swTK)ہ+?@U0:IlOh1'D'I2k^OKW˄3'ٰm}OkZG`:!Ūl9ma> ,ͅOoǷAN '). O $1gaS FA *j`jHs85 r65_ûix0+æeI؟k ,x´Y+xޅ%?Y7W ?'fSQ;OhmX>hap4q T3{' bq)"|("$C;{Cc~!"<Ϟ bp|;\hp'nMh!ofq?=#ȩnjb]M:ANdS@cK/'.]ؕҊr+n3BS'QڊFL_)kո3|㺲[51%l`o5yd8;E%_$C].gE.ӻEo{×/Hu1V*tcM\(uLv`^ʺ'd.aCc8φ%oNOc%Owre 7sT': Z6=(iRejVjqIvЍZS # qEׅثNf$+ :b!0 0z74d _n<78׍ :|'4ꆃn-g2@~7F`n*4U&Ssb4]IUeIîvh EY"*4 68idQ&Ȫ"F (7;hH# q9㭞מ3s2U{wؐc9} @,O<ȧ y@,A霥>x0@o>0߹BQꄴHZF߁Wwx@ب h]}rġ?^`YDy 8QhxMB^ iPM$H4řl?E5s 0Fξc\MG$#d 0X( _{]W{z)JGlc/9lIW8_o$#O9|Jf1D]`N^`&(f6+reҫ- M8,3Áդ [p s%{=S~!’3#XsoXA^b׍rDT;\0|uijCl"SKOaFpfٽƝX]W Q/qYU̳G{O_}љG4΋oz=< ֕7R,|𹎤#zJ 7䞸b~I:2-n8v& IX6}]B/狅e /  r!r W[q:eeT#8JI؊Ÿ ~#V{DWR,NGNJ?8$1aK~#}P@Wck"o- MRU{ j9 55ZgӶ0&22aq5W5 :PMHd\& i O~ ߭ O[;W7 @),1oѻH <|Lqt6Q0H|K`S MeKw Z>&8§ iDN- "ν_O4?8fNYpZ*~$墦[M/`tqjA="wU0,B3p-1igtButW=!O-[uVjo 3<6xhiJ$E#{hXQDj ۃEMݭ=+{Z>t(JK,hk>yF5 :7mx\ >`8 >ؼ#Wk?,oۏ?|+3cʷD3? xO^W (pỏhm;4kB4'!¼.mv}rWdd\鲫1oƔo b|-fzN̫! K+|#n7X"M-S)Ҡ_ÐG/evHU :G!6VڏEܝDEXSHu PY Q4!j.\MN=ǨpJ/{Bs|O={z 3+ pOa &RU^'W\ˇ008ZgO{" :b(IDr#mzp|LVZ3UkF52 38@Gp|dfA,nKB4 \-L#'(wsB yv曙 ;&_puCvϙ\*"G8%c[Єtj2I&y&`r9kX# v !>d7,Y )-.ʝ`BuA7ԅ $T]LOq#\=ÚfMg]v?`: sy| U%7UHϔ$<Բa$y”SL͇^!v|[0;xx*53LEU- %'KH=wSrm K-G^~6#̅*Ef hD[sq>d{ Z4xXjq9[]~.Q*$Blp]`DZhP t<8 C@Hnz~⛽Ƽ !jy&3;$ -pp +kjD#CXA.Cz$ȭP+ yyK kf=w/)ڛSyƺJ-hoh1WϏ7' x_vY?)V"XP%DBҫߦ8X/RMҢsyIZeӲeRefYe67"1R6yǶ=$5& e;?jQ4Q}`E&ミ̖%DSgP' u=Վ`UC;K%"ᙺ;֌IJ1 ,:F =dal Sy NM@>Ť\whMS2#X8(zy̅RG+6D.8lpLA2}-1g;M. h)hͷd5qb/\i%knOTaH]{*Jxf7Nks"rG=0[ Q/e*M2 |`UO=D P /B4G1<OX_֤ZEE%UHơ^>׸ylweR)<嗡`P;khK6]ł?==ݞnn;\XצR%*~!! 賍jEEت\qnŢYTh=T¯Ewje13Aid6/#7᤯Jpk̾/e[835f35朶$|xӉ/BFB Y٫qqc!0vjh]`k4 a~1o߫ 2[qaEpR{ t]l0e FsYd6t=: # Wq}ۇ{n RN"43bFfD9ӌzPlXuW0g7]ZNΥ@LPuv~E(nڹŖ1V*}$&Г 'c#*7HKU谈½3_~Owt?ã-08<`[RYZ~]E?oos(^fSkس<]YyAThhldV ?XN{:46LW{TtJ΋E=uي6vX.//`@ N^Ds qq_?O'ɎK%U9 DqL*ggLlom$]-|!Y[ oӅ7G\ 'F!(NPF"4 3nDT]($4B9{$} z{q:tcdz 屐"_0~"*,@7Ӈbp4bh*L$e'˙S^ Fd޹FFyJ['>:&Y#qT|('"i_*+z#<Yh 2(.(`r#MU%0 pHcayEd˓pJo si{Mo ozpVo6_["=A_;yRx(vϊ`zid}]AQ\yw-SĢmUd7b'2'p( ph9fA.f@n2"Ȩ1fJ4꯭֭TxUU{z`g3 LFs^}h0|ox'J:+$2؃:%ٗ hw%v9"[}4P{ sZ<^zXZb{P):.8tJeϺz DO-`)FU+|W) W Faj*?_H%$(}1Lmv fzCm[Ll0y I Jod%ZwI:jT5XcdM\}U#˝EGL8^j=ifU".K y;]/B˃Y*Tqu)\{ɏ8g(< wxbG6[ϋJX0vWw_ǥk~`;ne^'vnġPpc~\mH{Ú$oG5oފ!qLOj[>~~A\~05flm%Q^o31'tnyhΧSϓ$O>&]t^tIm\5 [/˕JQ|1mUV%Z#bwM9ay /knւ/ah^@-sںFNKsMg &_)^)ny݌H Jc"FEפ q-8 ,בJTDtSX""Q y.$= Uъw4(|L@V&Obq060~[<"hdolKcMe_W"=z4bwz?R mZXy{h5/>GRuJba.4n xdeaq.{\ r̋C&T =${P)Cq37Sxh&zACwoЏ:-CZ7";4m![&0 W|~AB $)c/VK!{+w'!(k6 +b{XԮlt׳ &+s6l-Zz:vLM,"`$ۻ Et \5SM;)Z?UQȀ{2ֽB[G >g9ӐQV^F^VLR&*D&:>3< (\V(  Ԇs0l g_LN-^߆6>-`"(ON!y$qQsvC:&{I2%7#+MIL a)'‘.?!WC,<f?;X%"sENMOwk;gK\G[+GJ}8}bw(7`n wvͲ~Y)Una~sI̭cEprb;j..o Qg"D+Jiw;tIm-}ۼ#*:T ;0!`1ZP/ )jp-p(s.>x{ouD4݋SVc  jlDx{#ė}Ty'yʜnۋg÷/Ctp<U|#e?bHAkX دŅ*'ELINqyNBZa_)`- SYlֶ)\rR䆽<,ctNzuT0.B aIf 0XH`!^'z=2a;;a+հ_ꁽGݤLKr$Y?$8q> g?,gGW;Ԭt g!qݝ;-0#uzѺ`tFwZwT܏ξ|<%|KYg/eO.q.N!%E &܀Y!Qom͛ZΏwϩ4/9|B4"CZ0e&G>0<_h>ks1 Tx>¯=vAEsQ" Ɨ0$Ԏ:\Wavv3 ^O&d z!>0 sf%#, -!pN~_ՖbTװ>!lA٥F]iyZwn:W@҇jS8jcʊMETXfNChX9"uVyDm]mLK1O=;=IiQ 4m ?d*ȔF BU޹x*j98;FLg)JM)UH W *pkd sE0۠me;rr^!Js2 < dnbdΔ89SyYm4~>cȨ [#E<<e^Yg[A/(E c9c;LWCx+ljz+=Bk<׍LtL uT*(d#%҃4,7:c.ғ^ W/@;RK#qm#FWNl{Xay|y>'='3ik|}uv¹ںؔ42!CklPcCv[4/c Ӊ=(ك~9"gIJ8˫†ÔWm "ū{NazRfȒb,_+hQY 1Ӯ "WΧ]&đbMcaTŖCfA!I />stiƹ̣q% fJD nCB6vg=MndاĀX&kQ;G^I9r‡Q|l%{aGaC`D V:eh!Vuyޣ6rFa9a'kMVҶjgɣt*(}j*v4t}\KkZY+v$a*v7BkJ L ٫TmU* j*EC*M b27.m#؊hقphGDe7- " ȾE@iȈaiE1͔BJ|8e$!ħFW,aBSϞI CTwQ,n04Jl:ɲgV"@5|mƦ7l:.qE6wVSy3vY"6μgVp9^VXuu :X6[&'4.46>*a ]%ŰK|J79q 57h54̈́6z>[gr%kJr{r%}մWAgż]$5 Ij-@ڗ5ڗ];oU~Pb< 9\ {tYƲ# MHI1N>MR%^jc3ұ|4ȋiMl0E98WV+:%67`YA kqKՔmexT‚bՋ#Ѽx"QQ,ťIdҡe0vUc|҄j>-i^""iJ5P|7~ؿ;9-K ~0X2ZɕnJg~GIԁar!7z ѸUn Ga1sQ]%soN dfbZy[V "v/VkƃUS{P<`>GfR$R;ݦdhw[8_UɗIۥDf{4ZwxBNU%G@*u>օ&քD&ҳEr9+չPDsK#eE)̉6"N& |/-kfF^4~$fJ>0A! <>Ç!_ms{Մ=[ ?[7.f/>Dg$ w+n2w?fC)*MQV(8{Q"3ŽjU7fʣߚLIZdo)!tf":"Tz*X15$$D _uu8m~i %hD_ˠU}G{~Qu9&KsVLebAn,k7b}F\cM`TV@+j}Z]K*, tZpHTk]iDLPH/jBV֌|TIӀb eHY~8c4LFYlp+1:_a旒d5cky^bo&/ۗ냅)fڵfvJH-~ *q߫nn ϥѱEI'Sb8j< M DPbDf`F<'!(VGjc~c^0 ;Zpxj™T9Cz laƲhYL&Od~!DpւZǤt1-.e+7,S*cR:M"IcWB4IÞrVnv693丸˾uo /Toj\ũ4Wvm^DZHkڎL7N;&:7nށl,&1OmpzJAl'=+Ƥ&b}? [g "9x7\BcBY殢yK^gd #b3DUҴ~~Usϩ"#j<8|M(mmJSM. gw3 1>'^$n\`=!vs.q `1w&WUQ|b=hEV>#@ PbFIK*J eiQ!Qmj +k9̀SiSJcTnve u!%Pɳ?+I-2ؑ윓{ —s;; ">{vDll>'4RW/D6+іCSչe\uf쮿V^1^j`AE#@kTuW`.Ĭh7ι@95a&Fn4w]i7?gp?;>І ڈo d^Gw n[DmuXjy`kW/׹`w/ A1P7Aά ix ,ߚ[];ǠO6# Bp ջ˾G]<.4`? g/tONU'Ծ1 à?6CTG*ӦvHCN1OGp_uk8/>SUwɕ4]V#"ѻjӦvàHgujzgu3hy iKbl!蝖]i@֗F= Ym{ 6x.<~j`~,{HLp="g 3+c0m33wX+Zz6qa܃(Süb`k,n3ɽ.u.@Ȉ6t̻,P9tBU1.XrjihR<}qqal!/oc?-ݸ@,)3)#=a>fWvh3LlpLGsj9>aG"1 ޏ-(RHӅhJ9-p+̺Ƕޭd:nwYYuL]oՐP`D"@VFA-?Ot pQ{랻NCSy\,ZoƁ x`Yp'x%rDڈM0VFPVab %g32qcuv.똵?^ߦC{5u'ޛ])״po?V|G]uAM R 4lB |A>ъآVguu{s;sfrors~u(t;i-pIV~˛m_\:zl^5~>3a26o߁NwhkOޘ}AiYB0]Ʌc3~z]ڛEl ?0q]&oa^;_+݁mZԖ| u$ R~2}Xa=Cr/{oA{SGxn/.s^B?۫)j^7w_@z:6LzN.]*޵BC{ M.&M~=ޒz]+ ;I~.;',y,S^kWV BwEɛļ%y}/͵l~ =c :хwb>rjyԜZ݅;k4Hkɺ<"TbA>Nn}(<,H%<,C4"9+bOfn?;_Ll0~w{pvwL4#H8ZEL06. Π69Vi uU5NS`i&쎃OV~=cfy9فD@TEg,Q]/kbFExBPhmF #[q0RQD]El~@ ' HiwgZxP)d )8D$p @ue-7I9x2Im`1G֜%=ị]4Mv#[ x5,>,BKG[Ƨ&?dM \psVWX1|&>e1(Ѯ~n\KZP11'm^2Ml˕VqD-) F#>v$r?BYY8?2- +M#&;r 0CcBMOA>]Ǭ$e )hn:IzMX>,#1: ìF6i<-X̣R! *_TZ ng 1Gh͋U^ߢ^gWĖ)͠ Xy \hw_L7! kB"޳lC)̼D-od}ړwx Ӄm' qcjϕDҭ!.Z I6!',#bԇ ږN.>Zav?^Wb݆EQi5]:% 3cF x0փޫ)PHV#àeº'JHXU'qSlS`xfF%^/kԆMjڰqeA)x Kqv2Yv|$LTЁcGNE ÛaZ#aMG?;fYwf8%,('f<`Y念?19, ̦SjK'S "J&<_BzzNybܰ,^(Mx >B-B*4-FaH /vT=hT@X \^l+XB?&={.) Չ6NDs$NDh^DF>P#ٜ Xv{I/1dp" d"0la[|!@C%6$g}?鞶Z',-px*p^P Yjօ;+V?0T{6T㷮SYߺ!noĉ;[-( "؇Z'Jۘ)͎1QMMt[oYϞS]P"3 ejj=I8mVUjcϮmGuy q+20[9GT`0f9+VW(AiԜ ~FOe^l^,׈"-+_ŃKS[ϼ(}!πߧ➌r*^NW=ZRR蓩td}J&_*.O]pKO!V|KhtG9O;K[;›}/d H!z+ND  5+1 *8 YWc3_R*EfVRzahNE 1 D9$dЄH8Er)ʐY" 6V}7ҙ^WB$dj]Z隨 XIeLAtYV5!؝ƆٞF#!mm:TȵG)IED05*}sIou>[ztq#?ګ4(+ XcC/yE\&3j4FpP 8T\ @d]ATn#MPtd@Qy UsTƱj]}}9'mT jЦQpX . "bl*h , |.]Po͍j-|v/uzU;`,]f _0z>k{յ7np+kLFzB:Z]V!iiWtz}] gcr#2v+:ha@`+ 9 ~a" k#1LTtķx M щq߹PLѢ]^*^yͅrpgת b%fGqiwW >i+Li >|742O"e+~T#B{7$'e΁n8A~)hj!v{7h%EV*]|Ą7O+1GB8N JDx>S!v䄅PTe- M:<I5I#4$V$IݛbhOD e4r@ ᷮHFH)^ׇ!^ AG84 1kgg5FaÎQ``*R$e]=AuvDz0K9k։耼21l>C9Zʙ/9!2 1ēU*8$q1q V7'ؗimm6%#e&tidM=~]Ȟ!RB'7b{"&844zccu;2B|>mQh W4sH@ד[fZ4ޚˑ?(u/CklRJilVEGj3 d )g9qI+,`8.+W8i4ڒAj>]&\xE>|HłPK!V*Ho ‡T9LmΠ5˞Ar[tyjR!G县&$V)+hj`ar O /I#}"4$ "T;:]d [ nr>Fѷ&0d4/gf?N_'R[Z!԰5l(Ϝ{`HNˏ*ghh! ж:(g(DU$qEࠢc  (&ޛ D7 e)o$YzTW)Z~ N`Trk,j kkw߈~ fN!qsEeeY\ "B9iWbu9Ysiſ uL FXqB>F{H^W. qXs{!G*gQ rA,Zr Wd;3÷ΕpGe1mQn#{Bߔ<0\n/ uTry ]; :M7Eut\q6O"3IW[i04Z'cѭb[* 籌ǞWSKU"zڨp[pѬHYbQNMKa*R[B9+p;ᐱ.n^H SAAZ ^$TJP!?u_w=NqQJ-SO wD$p3PHw3L n*~i[o _`6ƅV!vjjE7Zg񦐌7Z[.ku:>Z@UKEYG$(R(vtS(Qj hu龙ôsn]:r=>g}4O"S=ws(DVV'yt%ԢJ ^hLNv]2$>iM$D7<$yN W7p2xeUdےBM$ ԞRn`ktKnW=GԚ jҕ RwiY@4S5mkCC,'3HԋI K {*#!ؔ[@}EܠznwacE|q?ܯ0'$עoҨ|.[>G˹v2f#=QB6`Dg+j.c4YHDe: mVҧ+D%` 4 Ks[4;y<.('KcVrAkZF Z"P b7[ fL/a ^Ep .Q SO`cbkk,tRcRbJl(F@ȶ_ZX#f'j}BU=~B㡦k~mA_ (*s {?+-.7Q]>f aK<{agx0f'SN+IܤQ ZF"GǽQ`n,7lbH~'̫H *'ކ;ˆڷ!li/4qGrmK FUJ||"LԚr6XDFJ(sUs`fm"r{Xnf$2_וb9$~oe7*S0 d<\eݾ?.>_cc=}2FɔY;켞|VŻ.<7eu_/uIVjIAJܝr]KU"'(՞|ag0f'{WiPk_P|rFLa 6a7zd#>2PҪh i;ѤpÀ0p&;Pt&QF.grI\Ɛ/}On"_&';Qᙟ,c%/^Edn'BsBeF#ӥ>zfXy zD&7covb_p@|]EV X] :!BDPFaXht")T`}4 džAL;8&RvLVosNK,:>GWy!T?9ټP .mHMEǨa?$U$R˸". ]IJYj±cx(]֣IITrGEe9I{ذT(O_ګ4(+J&84Aaz;MB%ґH*?ƶG+Ϸ}|S^[Ewaø ;Q: vA3?XtH_cO}B%_ts_W(;D?oXB4 -FMaQIeb FWȘh!ɣa4kr6'֒T%/hmd}XMfD'dˏ0/Q ;'O){zgj`YYyR!S_浪5&4T?c Sd#[浳grp)i QY_hzEctpdhD(G޳ykOO\^`ȣdrVA(xS,ח! 0nH~HI=  9>D--B+vsg??(PY0{m$b5suxܠ-W h y56F]<+;|yJПiE"b}T@AdmflkyL?Z 1v`;& Dr߫$?|Q)΢eBG+8``8H Q;zCϿ2!\KŔU[GDSSrW]g{U wROӔh4P6QFW#bu6|8oByS"Wi5є:} 9tnt^sfj7GUw648.~IKXGogh+CXoR\MpT\˳^ţ5TҸ=Ly} `NRcI䝪KN~B 0 ]ӊwV"%685o 1~F.g0hL7QSM]y4#ӧX4ޞ[E\H q 48\zϩHg +PRϤPV3fY]a>G8(룻`[$k`Ψ_Mw!UYVWU4c4 dϋ.asF;rOJs4Q ّR=n}XX"DP a 1D! Ihގc;/2rIu09C4,{i=Op5[FFn"z,z?rUi蔤*80/Hg#[cu`8SMDhK'Պy^\kÐoAMe͕fxK|ryqDCOe#j<}S=}W\^vٮQ)c\UJY vrTVfv{rRYDm %v֬6Go>N_%V1;v1w_>bN4 i'oh{Z'6Oh=i{*EqZKm~\'V=P`ɓB)HK0VM^t}>@>sLu]3R{}4b曡#Kmxf]5`tšx%[obwj##8v? awC f7΢:$.pBsހDl>!hG$ ыќ$v<ބ`D Y宫9m$fB\\-a?^//m+;YH46VDJF]5 ӊs偙\3Mu VKs0KDwǖxOxUkAM5{%lb|"}EaχTa}mkn0F/Y#,` n7I0Is$yHBNT+c|cXv:M,ZZTrQ=+=S{5ufqp/g{٘k:>ve+n[BҭA "/*/MWE@A ]Vc잛pfDDpqG==;ww% lQ^..qr\a~悼PG++S&G܃qF; u۵x@dʄŞPlxW(+BT)ijQ;q (@~:[7)n N}9(0/zWzf\F~z|I_ 4uERq&>.tAZ{yx4# e`hFVB.2aDuIwRGHXv-^%5M-!_Oڣvv)#sEsqz;)tw:F_bctINAQ2_ȕ2L,rp'n<ǰ5 |_12'u妚7N5I1XmL\Hw?=[AjCÂ4+}jG2r̳ 82[ZD~d-H᭫ҕoCU3<6я;PdU%جN!-aIf $Q#,a1ƬQ\̝hʒ[`!gɮe4>(5L{d.0N)ڰ/I֊hr+ZNl$ NW'T pOV t*,y?j97G`&а vb6/61Ƀ4_tk a~ %4کfhgɓ< ڌCs 52X>h@H$ACd pŖqۿ<#<*7HXJLK6MoNXo֫=tdge'k2RMH"]MJfL.!vm+ 1%!*J2 nvFcηyη3s8ggZ.St0֌8R#^"oE V[G; uT/~u7q+^d/gr*k{ܢh*-t@8יž ˘ܕaz)O(_0C9II^&-Cݏ&÷ cb ^M &)9iMh=*p5V5$+05É&x yH~r×mUEL%G,%NqlQzΉ7M]Wmܚ c 8j;zaJ6@jBA/=H،NhT[HW5Xj6ʠ;H20DhO{?7,xl\2iɫY1)٢׾+[GA=+9M @HN<aCX[~asa%2`$UMI{!ZM#?Nr"l`DS`O>A42fmvks;UQ0 3$̐q^yfs0יJzsKra&]CpXG0 jZ?]}=Ba-Lm=e oNWA@+J"G2uC ƙa-;"< P/P CJI! :GCچX4Iz2T'(a:^xW`hpFa#$?O$7ldH8"0 fvB*9[[M[0﹅KujͱBNjIXzJ,r, ;eGjwpGΪ=ƿ%K_gq}TG8Mp[5Oáfbxk (C5pj·hUk AQUTST1_UЂ:zi7DCn7_ɨ[m*qR=d MqM#go?`Kٕ_MS ʄW].y,fң;"H6uy S8߆Z7 [z΍J5̼,ZSzy[PР,>웋yKf#U!똵_!VNi.!L<LtET4w2ԛ+]zXur,9^Nfe$g>&R[g0}FۼՆnb5%ߧd{`,fg'9!LjU߈Y <$D3 8s ।KQFcD$KaE?8=i R`7S5JM΅]IMdM=\A f1r B"ڰヅd+}\uhҨ$L8mU0nW\]EEWE ( ""DdQ#ƠM5zKΙ]3'vWn}_]u4JnnY7DjLh0"DT2mI^p,x17xi1Fqv6D RSSuYHEyk^8 yk[WA0ኇ|8FRc,Дxw0N҇ԋR㙈0rƲ??}!)47:j^c'6#k8wn@zڸ}H/Aĸw2Rъ5k5t®> .Pf4d KUſ2"٣ڥd,}DgK"6?`9&c[Bn2:Bo9P=sVކ|5>a>!C; &ݦWy3B8sSŕ }sАesLwd3~Fhmꆵ%2 0AUrlj 桩r0I8D75$R&-0<議}?d04) k"Ck;&#y4 I4VGšH LpwBjɈt, |XʊHDߺ_UEmLkģCs'jrd)bSQ}X|6bU q) 9V^X4kȚ6ҝ5ePduYS- xǩ"Tr׀w՚B(d2Ki֠ld iʼ;y.l-[䧤{WHARYVF#Vx`$eD_[gv?ș4([svX;!ۏ--1Xhc.0Fp@QK.!>5뷠"4qG7ǰ1) !ETTp2zRO !|& Fj@j>sB!pBy {axn߻eMXjBN.^"৮ӿg:~pL=;\!+t1cvr6PV ˖Wd5un~j.,x œcg?+>*+OQnJoCٴ ݺ]F 9burfI 5=L} #<;P|/GބukQ1: *EQvX%2!`hQŅa e?8Ev8T ꌶ7̏/*SxΜ9+y{? GBR2|Q$PN8SC6MJUJH`C+ v{;MY[+-6NT3XJU0Q[Zwlagw#YkWՏ7VDP9]u/- f}hcka2c"*erˆ7N8%d4|H<爮zW EUFi)l%;,88UO[[[ 'ڡ6H388*f!CgWL, >yT0Z΁bs+bi6-(KЯwJ"s,ȺȤ Z,XI$>A-D5N!>6 LJAP(~4Q_fUn@<(JFYHY*2ryno_Zǟ`81 nBӓZбTeWg2١}GZ8j/v~L81 wZ.րCUe[1.9Ȧјg;2硉gA"#B尘k "7w5`6Fy"*戹{ixE C9jbSqYtCrGa#*//ԝO`(Ln3;ڀ%y6>%Dw$'_:ᒾsn$"t$N |? QDDz;\ JwZʵRLMV'#qehC%n|,&ơ(C'@ᐺL0`t# ׀ +b Y"W_aQ3(~7 amõ[)}k@S^UYSX] g7+ ܾw].{ TtYP h?fd'7!5;6\݊YGc>?%kV O23Uﭒǩ:ӭm~#5l #  d.n񒐌h'@HyĖLB_eߩ OXf#ZRάHb&g0n΍C&QQOmA;ߑYe5{<6CMCДKQN<&]-K*I"ȳu^ DC3o|_@ryccNlZzSe=֌})I'h*ӟo!9H-hbse2/yh}3HaFS/Ӡc?h `hNb~: 'kx^ҨBYonyoZfPoXZ%{2g %D \0g ߜ7H,dD<_:Bĵ`jp,^$~3 Zb6Dza#}8P^}v5x\Td:\Ozb\AfboɦiVއo uWӫW E}MAZ+Q"{yXo7mE#Y~Bc Z4'[3fdЫwPWEՋaz\uN:Y4Z>Nq`3  Y #$AkOa6ШM M܁%>p.Mefh?</O,"u`):0y IpC= aq uF/39lj9sA"+*"]Y$ $\. +\Tr)`@V4*]}ѱ_jwѿ2g&}b =5xy.4M)y.yk4`6Wd&2,5zaӤ\ f.m)ڨa">|W?̯ x*I1{> cx 4~h?{7it7 _[Ghvc~1Y%GK8*;. r;dA=M7VcD l 8XP}J5׊-\q38q3==>~?[uOzʒSԓ'beZE 4cǼᓇ` '&>T72,4ŨbJQXmmV`R`b~xQّʓ}'^]pCmDE^愈 :d<'LiJb k$ ?WM-snnS]N)#% ~z%U 925ZuB9Zhl~}5e((<_zSJZ~Sl2e÷ ^j ܇g+NUk7u h}=S2ByfdžX;l2kCOߛ+(D1 %Bd o>q࢜M|C?8̱ӊ+7UwI5&- +ˎ ǃFbEhXrrEY(II QSv::_=~4N:iKX7 Chvt`C=QkfwIMG3fӿEj!д9˂ѦzBڔ)oeQ= !%в~XK̠نp J Ip _v">ɉkt?hu6\U/oX[TSتRSWFqFn0#9jI]v^xێjuM𚜽NBed 0-_%?Kf@ŨmPwarI76nSoetT% -4o>^uiAD%Q[ؚ\\>#C!:5G1  r$J֕JHj) L.ن50R*ːgoՖ8Ik.!vՆ\12,GXevQ  f.c(]GL@v_TjU+&Hg>%(Q%"5(LZEfEF9; cl?lĀm7XMЎI#2䀬_[a&z3akD9o._XN+>Yۋ74/b;hxO&B0i2r6İɗh7_JtwLOc,^N^atA~q"J/~iDDUCMt\;ٸlMsJrJUBRA< _E򥬜=}ARMW|(dАhqtV~=À]Gq)[4V\IYŌذخS^B2#Kq8M$ G'gԬ4tj`5I aΧEJ?ҤwpD! +ņo֤g: (.셤Yrj8)\fr7sRk1 (ªm]Zm}TRB $  (!(<*7@|Tef~t߽nk3;o>GLIU j`udRpxIpi1n?ΦoOyw寳W~Oopu.W JD^#Q` +z`C:xEg(ccB1->TqޗVK0lZu2-CpK+ݓw.̛Gy`ex9c;hfnˍ@֝i)8qs/(&lk\:}*m-7y%zvX?xŸ;r"W)`;^ܸa2dp47f82w$)gLy8I7,<5EE34t[O—FG3$65ĉn:L6񩩉JcJ#v+碾;.X'9*HAZx#<*-mOYW\t!*vPd AD9(S1n1#:E壋ѻpl.ܻo=!H9Zr3U/\|3.#L>ͯ1x~F}&.—.6D>H0B @$X@PaR6H,?+#8zl{faΰ%d3|G2k LW3"l M=7TژƀގěZNu;fZD>jEjē#L;9rwA#~G ^>=H1|>>H?=hh4"ihBlPߺ2?uG<=D2X ӱ2A_7dߵ'k/Jw'Qŕfu3\e޷dI2ʄ@zѸ{4k'Ng@049-i㻋rm}1Z wsV0í밿g.e(.Aѫ/sRI}F\0~淝BSMZsU.;U0 =dcX[ &>=>r$"H;;۫gFlk3+}9{`95S6r4nt(7u)P0f.}U>kϚc] &^Sm<7n\W D[^#]a2Z;O0n|)(wV0pϛUm`zQ ?͎MnK:8OU=|3cDxcC! {:iI itJv {PuIn;3P!Z!1b~FLj(#cafmö\C%s$Ka2DKavam+E!f` {__T Nt)j^:ۣJ*K#ó%\ K\h, W>r ܠn< ㇸ$N$ W+26cV.;" ]ƠrU&1(ݽ8l{<v>Ssh\]6rU,X_čc-죁$*1. W'I Yo5S\P!5VH"8VrM/ ko3bGwn̡VK**‘l4R>x\Ƨҩg_Nþwyڏ5sOk} e]-ϏCKE(*NY*ܬ5%ψRՑJ/wi6֑FjW֗/Ēhi"REֽ ?g |ǎ]By@welCrf< 9%:͌ΈV@9Sy6b=%^HJKbcshmn+ -kjzPNBΖB=!bZ{-to%gEԑs"~v3#PͣG9EC1dz`Ko%&-bȀ1LTIB#ڃ0d՘F-vE8XFN66 U. 8`x tX6@] Vq85w]8L'{wN#f$d6Ty^AVB؃ȰÞ1'׎^l8mv"~Fo W3szs7;VBN$< 7E8)TR"XANM|iԡqt|cёYQnH=zsX$|X EoH &C:'_/p;Y*J#[Vf|8-݂a;rW@H\ -x2S}DtHyCzYf'z1gyZGeٓ ꛽ QoO(J^#ם-xFyʅ"30Hb߁?@Z UVr&:^f 0kn^n067q 11ۗEC`^Xf+z%%MzM!8g|Xt558_֣[f@)zdE)fw=;JbQsÐؙ$:h*+k}E'+|M < EbIUwѺ_akf7 ƴ~imDk)4=EVr&W4Iò@_NH!0yKмjKР)XY|ȬGmmEV2Il`,֯qǵ?K3q:86$|A\dl?\NP 1&)e(ߴ@@rJJܯFÆc`xGDJ8oډ7iWS\.Q狻k ^,KObJ?RZϢm#=#̽ C:MxYn D%#L`:'WTJ\MBbܗ1_ȼ}#6/,&FMSM_-Z~XRdTFyF}/I[..BU Xy$8H&*g8ʫ@M-1O}HŻC\Y8D~_P~vMn- >O֖dm%GYD%ڥ!oka~ k!-!/nn,qy%x-7c![b8!V#i\!?/.YNy\= Q"q[>C [Yu2'%=/ЬQgf]ZBUЪ0k$)qF"r{}l:_BB|l'#GA6wj Mq`2Yg%.0o WJo&D-\ed?c+U,qVXO :`9<*@GL{5KXnTCֱ$ad(Eu fz WVX9lYGt:!ce)Jjj]Jqת4G~aŮ!%Horb^4PIA_hU+"F!{ISH^>R|=aaxxalXv Đ]\s}*QۣKL8m`r>$5!08M:?{(2`*80Gl lx7.8z9UH|b(n+q{X=(Z=54mxˮ |28U5^Gn//EnԱ2JV--; ,z8_'hmnl؉@_jO+Ot!<"|`~bJWhp B^ EQnj }0!-0~J v8{I_^[*=%+ح.* eX|e\?3޴;L+A&1IR QuuG/,|-b0#sFcl+CNItߴFV-Ls -{6ScɞN^g?be %Fzl,,e+1HQelZ6|Z+&%f`՞2BIsU*,=ȁ|ݯC/'3zf#k{vS }[ɗ{!7MKaA>.P& ^FR'_k1ʶ38v^U K\%&`Hd-T@x\wȹN)Š);ee 9U}MwvnOKja!K/PC.R'D&Bu5 @jUeGy#3' lnմ7hyo1@,8V!,-dOg$[b -rLimtMP V*_SF?2#,we|$;>; 8Lv/g&%G1Ў-Eh 0&0pJEEij,َ BS@_wzME:GH 1'm \ݑ8Y!҆5#`^ȏ}'1A M?GCR?Pk'#@&aYM%& EMX-?xc!6>%Ec~Dq,p"QAixx+VT*q$ 6#3mGYrX endstream endobj 21 0 obj <>stream hWr8!nqIU\%ē"! 1H( X(٪6~~ 3sK)_N#LX3lf鄽x'R{^o͞%̛TYcdqb}&hwyx 8*Q]XR;-,1dɦGH%u"KWjbݲp߉.EY'~?4)~/0ƥ,mMbB6M"bbDqtm%UZ:~S5uVFfMcaq!#J PͬiPuZlKXJK1/"#tO&,qc@PbIix|lYT&ԗ(IC&ߔN2 9K1aY?-?XƉߔ%ۤyL9eŔ$q_C/sJ'~ p @ٔycA㼜5E8Xө,9|E8gkõXҸ%e?&}l[(AD0cVb4 H#{O}3ddH(4{ 2 Gҍ$𙨓~,a}Qe119,$JJ#Ix9d޽~,˷%A”SU< @9èyr̨w$%GI4kK861K+K+^\OOVnE)A>Z3NVK MW/mh:R0AjESOo-a+l\вi[ZVw-lvۍlh6e*hh7MZp+%Lga%Zy>hFkZZ-/аR[d'[pL8 aK8??>38 . [x,(Zb3{+,*-J %Pְ4Ѐ-| -8]mxyrJW2w%|aU͐M'VVPO(a+-(1nc:RX SyN?iV '؏aɦWaΊJA5C(VǢtI6΢Hp ů"0QiޛV7/?"em6YRhmZ3YA-JV5ɚ6΁v~ IPw*iw Y 2 ըNǯְ+z\ΏOPnHxp'5yG: 6tds:΂`~G;V<֛ Лf3}*F/u aX"8c!hB `9 6jdh;M07#s J+a n*E ]v> Tx =:2#1Km?= ׀g[iI:D-qW+g+Qs}O'8uBrF/ 6\9YaExxD2/lnNK&K\XˣP;_~cS_w'rxCd\ endstream endobj 22 0 obj <>stream 2 J 0.57 w BT /F1 13.00 Tf ET BT 75.22 778.46 Td (Hello, world page=0.) Tj ET endstream endobj 23 0 obj </Filter/Adobe.PPKLite/M(D:20200315103639+01'00')/Name(mak@trisoft.com.pl)/Prop_Build<>/Filter<>/PubSec<>>>/SubFilter/adbe.pkcs7.detached/Type/Sig>> endobj 1 0 obj <> endobj 2 0 obj <>stream 2 J 0.57 w BT /F1 13.00 Tf ET BT 75.22 778.46 Td (Hello, world page=1.) Tj ET endstream endobj 3 0 obj <>stream h|n0 _O0P PV 04\.hVCG!$E1^b]-/=|@_]E^9mfP͊0<*' f3M cS(\@Dл*u?]DKoЧbx. XMr E ToxbXA+ d9:󫶎CQE4؜R?,o6BgH>.쵴+hdjęg iP冨Dp)Ȭo8hJK|l}s?lnh =m-.P ŀTNmW ѷy%|/..'p9R;Dhv->stream 2020-03-14T22:58:02 2020-03-15T10:36:39+01:00 2020-03-15T10:36:39+01:00 PyFPDF 1.7.2 http://pyfpdf.googlecode.com/ uuid:6d35bb07-c29d-4cb7-8dc4-ec2822b99836 uuid:9d4919bc-74a9-4fe8-a8a2-3db5a6a25b28 application/pdf endstream endobj 5 0 obj <>stream h24T0Pw/+Q0L)64 )bC* RS # endstream endobj 6 0 obj <>stream hTɻ 0_!룔.nBfпwX4ק|\SzFFtd. wړF/!w"s6Zs%Ŭ"+yǟuj# endstream endobj 7 0 obj <>/Filter/FlateDecode/ID[<91E90C762D9B7F4BB01E4DF9BF08293C>]/Info 12 0 R/Length 57/Root 14 0 R/Size 13/Type/XRef/W[1 3 1]>>stream hbb&FFFG& D2փH ,2 L^/X%#d" # endstream endobj startxref 116 %%EOF endesive-2.19.1/examples/pdf-adobe-webcapture-x509.rsa_sha1.pdf000066400000000000000000006373651504236674500241420ustar00rootroot00000000000000%PDF-1.6 % 4 0 obj <>stream JFIFddDuckydAdobedx<  ! 1"AaQq2#BR3%'(rC$5 ?`0 `0 `0 `0 `0 `0 `0 `0 `0 `0 `0 `0 `0 `0 `0 `0 `0   p Rj],fʬQL*)!CDD0=1&A(j@z p$p?f`0 `0 `0 `0 yRkSDܿ,K8t.'} BmPjH,N҉S WFyul9qn]asz&C*,[XNr;&\={>Ã{?(WP]65&{[g/Q!/V:T{/,VɪGSw\P Htd;j|$uxLظ(w&.&A(`uN (06HoN!M/x}׋v3y]-4*tKhtƲf>2E^`A/Q`b6ђ׍d۶iBi35-h6UؼQ1{ $Ck< 0X}umjJiWsFO\Dp=A2U1NTCz^Dڏ|\LZ*)@]M>7WRr9tΪʜLa ل݂ ? pw_Nۤ/Cp<z遮MgNO3jNGpdRk^ݖrڛz[2)N Ֆqf?q\~`gރK5Za\m;_.hhͥ tD( WX::i)ܣD]/7%Ğ87nHk8[ʖ1Rz:ǓRWu5!VՄh&g 3@L' {1vǎ5;+Fnm0ӶJ8G%CGʩR\Q0 `0 `0 FyLmߞks'UtQ25-uI,@;a!Dݽ+<->KDq>o$TjKD[ ;DN:):׍jB%bY OWjS)׉Ԓrܒl ^  Z#x|֬{qAJ.o@R%w1C@:ok;'w FSZͩz`Ԥ,YL[&|) `0 C:j|2ČkU[D#aWh"*K*VEGM<Vr*.ز, NA$^Hk*IC%*Q2% J|no Iqӷd[1[ J٪`T̫8(YAeoI:p" 4['~j\yM! uַV6rC*TjE1  )PL p?e$ݷa]Df#˅1SILLc@ P8s˞}!~3dm*^^ nOWI/c2"FWPRX ^X Fe玔w^Z5Vz[Ԅs9uTϢ,Ue4~[9HU8= OHl/BQRfB~.^MscBTaβzdS`.w_Sˮy;5n]daXkMlݢ!87n݈^"f11H_T4_ID]+ڞkdnʲm &`>%O~#|]<غ[}rz/k}C:xX$ d 8p`t LP<{m"ZcwF}Ay4mK^OYG<"I5e*:EYr0B`/}߾y듛ei?q&RE6)H&|9#_w$ l浰f!:>ԺvZIS\ԱΉ*VmJWT( {ėxx»Hnu:s[MZtWiRyzÔt97na"`0 `0FS5N63U8ص аHww9]곎ZEJQoفbg Q<|pkDzf*ҏ;I9KfΝBF/.trI.d)%E$L(I1;棟T/^?vڳ>`Uz~ٱnQ/"AU2+60DB >^46_#U5fRv7 z+E\<ȮDɤPtZ`zY&© eT"i$D( R(_~_0Qސ.mŏ@"jT#v*DFQ7ДQC$q q{o|UGx, \nדeڦGM;Z6m^q]<z$M77P?EZ#* AJ NeEvQ04l|mJ9>'$tY4A(]~e;D T/_CYǀW#mͅh K2G95ƊYȵ3x(N)_A8e{ȔQMk9ĿlUPNݩ[]v)APi cj |{DvN+ur:5M)m (|έPX5/A@1G&so܁H_dUr FȗJ2”:VX@ hVzvS"Y6VRyNa=boDIJBd!lnH"@dI$PR2HB|q׊M/ =khƭl.TcxAyLrIb0Uf(_e a(L]mî sJZnrHP}[pӷi;D`HI$٣*B1>^jg nL+BRlG iѭ53}%n@>Ǩv3u|@vn7h}zzz|~CO C8b=C_c?pu<7yʵw*yUkĂcL+i)F,f X;Jiu̦`0 rÞf4x5E!^eJ&I#K aFh64N2dWDon_!}Ż `G&޵(.DG"t@@0\R} /Xͯ)gNNd a] a!HsJj ŋvmk'nyQVpsHR7jVP KԡzJoG| B1TwPlKodvo&J"bRI5AD)Ɉ@#LTŅ_"|$5b4]IppIy+=ID}Js(,)JB((((t`|M4VhZu*vg6@>~ډ QLDD?e~^yVgѭg008o C@6 .Wo eT}4d֘GmRCu%6^:˸$ssczK>2m,J t~{| <3+8 ?Jp, 3jHmXJ "1DT?P2ck8=}*{ld6VPTZ&ޜ˸:(}:{yKAᦽV^z+irYuЫM[EvDJUmDLQyLOD>F>8i7[_PTݵ ,C0&΁fn%G?Ӱ.[쩘xHC*M \Y\nrSKXQǒ;Yj H-e b$S#`xw`w=۵,-bW]͒9-bDJEQuD>Rj2@|򡺼sI-/ تȩ. :bfJ'C10?OX %P?ƒw@0iG}R!ׯp8ks(j3FJY 4W )Gn$U@7@#|Vp lDB%lQ,Ź˃u$v'0ǠO+ʎFm2Uo_2Tպt1 d}vD>'xᏏz̥cz6,콺Pܿ"9B(CDڻWHЩw~冱 2_E۷A 6j- RA QH"i$ J?p4' Cla?OR `0 {pUMSS]yҦ83Uzu:۰靵]-" vUXjzv+FA-#!!JkzeS_"ATU芵j$n. Ѭ["ݣrCDFtTs2*2lw,T"UÁ`0#5Ledf5&ȗOx!TvSX!$끈e&;Is3I߯*rѻ:lDW魒f@օ_/UHT}ݢp:ժc鼃vͤ#H@ljݬ&s,l‘@"=8%'y d@mgrْ5 thNlĄР&>^V][ӺjMP-C.Hu#jJ.ܠ*O0aҽ 6|u&*#oyQg1;$E 58΄ah8귶=ɭ-$fmidXvdvjw*,!niF&2ׯY]w` 3qvHR)@L q3O(zmiO7?O3O=Nއ`p>Tj꣢>zme#C$^>=/:z`0 `0 `0 rkͤw.ZՖnZ ce_fBEN'VE;eA6s(<+|Uқ#5A&1s޸qnt)D_ם~7K> xaGw~.:=gï߁ 7%lN׻  zW0з[$Ja|eo߬Urvf`K'07 nNPbA5lnAMQ &I!!@0= `0 `0 `0 `0 !@@}06hzv`a?ܼ1w(=]Gqcu0ہ`0 `0 `0  endstream endobj 5 0 obj <>stream xwTSϽ7PkhRH H.*1 J"6DTpDQ2(C"QDqpId߼y͛~kg}ֺLX Xňg` lpBF|،l *?Y"1P\8=W%Oɘ4M0J"Y2Vs,[|e92<se'9`2&ctI@o|N6(.sSdl-c(2-yH_/XZ.$&\SM07#1ؙYrfYym";8980m-m(]v^DW~ emi]P`/u}q|^R,g+\Kk)/C_|Rax8t1C^7nfzDp 柇u$/ED˦L L[B@ٹЖX!@~(* {d+} G͋љς}WL$cGD2QZ4 E@@A(q`1D `'u46ptc48.`R0) @Rt CXCP%CBH@Rf[(t CQhz#0 Zl`O828.p|O×X ?:0FBx$ !i@ڐH[EE1PL ⢖V6QP>U(j MFkt,:.FW8c1L&ӎ9ƌaX: rbl1 {{{;}#tp8_\8"Ey.,X%%Gщ1-9ҀKl.oo/O$&'=JvMޞxǥ{=Vs\x ‰N柜>ucKz=s/ol|ϝ?y ^d]ps~:;/;]7|WpQoH!ɻVsnYs}ҽ~4] =>=:`;cܱ'?e~!ańD#G&}'/?^xI֓?+\wx20;5\ӯ_etWf^Qs-mw3+?~O~ endstream endobj 6 0 obj <>stream JFIFHHvExifMM*bj(1r2iHHAdobe Photoshop CS Windows2009:03:07 12:09:40P&(.@HHJFIFHH Adobe_CMAdobed            P"?   3!1AQa"q2B#$Rb34rC%Scs5&DTdE£t6UeuF'Vfv7GWgw5!1AQaq"2B#R3$brCScs4%&5DTdEU6teuFVfv'7GWgw ?}i]{ ֹ¼|pK}GC,m[kfcL=W&݊'<2MzͿzS3(@Nf+7>g f6?WQ+f`]b+- f7[=J gJ}zO %26ˏh)U&Oz{)ȉ55=FO `xu!YnUC4Ϋ#'8ʽ/Nh<\8ZؽZڶ>_:be8; ]QA,1Tj [v,O"g㉇nu<_)W[uSjk_k?;-?wj=:ʳ/͑=ΩKE{CR3+OLw:={e_lٲ՝gCdu,N2!kH+3xKr=/;_t ى||Q}Mh6e5ǵ1 ְLaX- s{t?]65fl{Yjߥe[QvEѲ5VMHID_=OTʩ$ꤗʩ$ꤗʩ$ꤗʩ$ꤗʩ$ HPhotoshop 3.08BIM8BIM%F &Vڰw8BIMHH8BIM&?8BIM x8BIM8BIM 8BIM 8BIM' 8BIMH/fflff/ff2Z5-8BIMp8BIM8BIM8BIM@@8BIM8BIMMP tecxoftSmallPnullboundsObjcRct1Top longLeftlongBtomlongRghtlongPslicesVlLsObjcslicesliceIDlonggroupIDlongoriginenum ESliceOrigin autoGeneratedTypeenum ESliceTypeImg boundsObjcRct1Top longLeftlongBtomlongRghtlongPurlTEXTnullTEXTMsgeTEXTaltTagTEXTcellTextIsHTMLboolcellTextTEXT horzAlignenumESliceHorzAligndefault vertAlignenumESliceVertAligndefault bgColorTypeenumESliceBGColorTypeNone topOutsetlong leftOutsetlong bottomOutsetlong rightOutsetlong8BIM( ?8BIM8BIM \P@JFIFHH Adobe_CMAdobed            P"?   3!1AQa"q2B#$Rb34rC%Scs5&DTdE£t6UeuF'Vfv7GWgw5!1AQaq"2B#R3$brCScs4%&5DTdEU6teuFVfv'7GWgw ?}i]{ ֹ¼|pK}GC,m[kfcL=W&݊'<2MzͿzS3(@Nf+7>g f6?WQ+f`]b+- f7[=J gJ}zO %26ˏh)U&Oz{)ȉ55=FO `xu!YnUC4Ϋ#'8ʽ/Nh<\8ZؽZڶ>_:be8; ]QA,1Tj [v,O"g㉇nu<_)W[uSjk_k?;-?wj=:ʳ/͑=ΩKE{CR3+OLw:={e_lٲ՝gCdu,N2!kH+3xKr=/;_t ى||Q}Mh6e5ǵ1 ְLaX- s{t?]65fl{Yjߥe[QvEѲ5VMHID_=OTʩ$ꤗʩ$ꤗʩ$ꤗʩ$ꤗʩ$8BIM!SAdobe PhotoshopAdobe Photoshop CS8BIM2http://ns.adobe.com/xap/1.0/ 1 80 20 1 72/1 72/1 2 2009-03-07T12:09:40+05:00 2009-03-07T12:09:40+05:00 2009-03-07T12:09:40+05:00 Adobe Photoshop CS Windows uuid:38cc7da1-0ae6-11de-a1ae-9dc14dc7ffc8 adobe:docid:photoshop:38cc7da0-0ae6-11de-a1ae-9dc14dc7ffc8 adobe:docid:photoshop:e3a3fea9-0ae6-11de-a1ae-9dc14dc7ffc8 image/jpeg XICC_PROFILE HLinomntrRGB XYZ  1acspMSFTIEC sRGB-HP cprtP3desclwtptbkptrXYZgXYZ,bXYZ@dmndTpdmddvuedLview$lumimeas $tech0 rTRC< gTRC< bTRC< textCopyright (c) 1998 Hewlett-Packard CompanydescsRGB IEC61966-2.1sRGB IEC61966-2.1XYZ QXYZ XYZ o8XYZ bXYZ $descIEC http://www.iec.chIEC http://www.iec.chdesc.IEC 61966-2.1 Default RGB colour space - sRGB.IEC 61966-2.1 Default RGB colour space - sRGBdesc,Reference Viewing Condition in IEC61966-2.1,Reference Viewing Condition in IEC61966-2.1view_. \XYZ L VPWmeassig CRT curv #(-27;@EJOTY^chmrw| %+28>ELRY`gnu| &/8AKT]gqz !-8COZfr~ -;HUcq~ +:IXgw'7HYj{+=Oat 2FZn  % : O d y  ' = T j " 9 Q i  * C \ u & @ Z t .Id %A^z &Ca~1Om&Ed#Cc'Ij4Vx&IlAe@e Ek*Qw;c*R{Gp@j>i  A l !!H!u!!!"'"U"""# #8#f###$$M$|$$% %8%h%%%&'&W&&&''I'z''( (?(q(())8)k))**5*h**++6+i++,,9,n,,- -A-v--..L.../$/Z///050l0011J1112*2c223 3F3334+4e4455M555676r667$7`7788P8899B999:6:t::;-;k;;<' >`>>?!?a??@#@d@@A)AjAAB0BrBBC:C}CDDGDDEEUEEF"FgFFG5G{GHHKHHIIcIIJ7J}JK KSKKL*LrLMMJMMN%NnNOOIOOP'PqPQQPQQR1R|RSS_SSTBTTU(UuUVV\VVWDWWX/X}XYYiYZZVZZ[E[[\5\\]']x]^^l^__a_``W``aOaabIbbcCccd@dde=eef=ffg=ggh?hhiCiijHjjkOkklWlmm`mnnknooxop+ppq:qqrKrss]sttptu(uuv>vvwVwxxnxy*yyzFz{{c{|!||}A}~~b~#G k͂0WGrׇ;iΉ3dʋ0cʍ1fΏ6n֑?zM _ɖ4 uL$h՛BdҞ@iءG&vVǥ8nRĩ7u\ЭD-u`ֲK³8%yhYѹJº;.! zpg_XQKFAǿ=ȼ:ɹ8ʷ6˶5̵5͵6ζ7ϸ9к<Ѿ?DINU\dlvۀ܊ݖޢ)߯6DScs 2F[p(@Xr4Pm8Ww)KmAdobed@P      u!"1A2# QBa$3Rqb%C&4r 5'S6DTsEF7Gc(UVWdte)8fu*9:HIJXYZghijvwxyzm!1"AQ2aqB#Rb3 $Cr4%ScD&5T6Ed' sFtUeuV7)(GWf8vgwHXhx9IYiy*:JZjz ?4R2" oUn ^鞢;OfJh >Ǡm*lj%%66Jzq5lt,c{Cz/ūm;;-gehPPo:MEҿ'0x{?T_3j9ٛӶ32KOf{eVnb;o.+xE5 L]E]KD u07ؑuʯ;9)rU ?F:{nGNmW&PM,9eX^'Gou {k&v|o{m ohm؛A|sH{vbvn]âJ|:X9f{%w˦ȸMb9dhG* ( +AZ:75M;5%};Y;U7V3&L!MYMnW^*r%pҘ}3x7'se#`'hGm̻͑R$x* dWc(.N}'AqEkuH摤W:THإ[0U$?r߼kEU7m6rDf|[cxO"YT=;jH++.kvok= TT4I;!EWM4T$xX9#o&o=RL S>SN.{;i Wd\"K H{iOV_lu6%ӝE vVm}0_y9=ͼvNX1G366TyIIj#^no3k^%ѻ΋}m=Dq7j =Pa; ܋E܂zxtEkZGvc΢ղSU{tz3z:=O?͟e=Swovet>쭃]`0yyUG6\f& ܌uw/[wN7{-Q]sѽZ+]IAڛk}䥤wY JY䣫z"/%I3 qMr0,(WHCi6ڟr={o;6vK+ve!o hYQۙ_VQ6o~u%MwNo QW4]A6e4~-I-[E<~ZRpkqi}jL9?8Vsͭj:y}پ)貕4f_*>Ke'>m7͕4QvvЎ߮7#`m +-TRӚOXZRHev^;/}k8?:_\'c|G=iԛ[ >~M;tm.^jMlBfLrZ'Z}׺Hvo^;;q=$8Y ʎx*:h͙UT lSn@r$+{uߺ^׽u~{ߺ^׽u~{ߺ^ endstream endobj 11 0 obj <>>>/T(Alice-1-1096825554)/V 7 0 R/P 12 0 R/AP<>>> endobj 7 0 obj <>/DigestMethod/MD5/DigestLocation[0 0]/DigestValue(aa)/TransformMethod/DocMDP>>]/Type/Sig/Name(Alice)/M(D:20091004152818+05'00')/Cert(0[0Ġ\nE.H10\r\t*H\r0^10\fUAlice10U\nTecxoft1 0\tU QA1 0\t*H\r\talice@tecxoft.com1 0\tUUS0\r090729102132Z\r140729102132Z0^10\fUAlice10U\nTecxoft1 0\tU QA1 0\t*H\r\talice@tecxoft.com1 0\tUUS00\r\t*H\r0П!+gσHSEZg7~ȭ^BˁcF\bhܜ:hYwYMy"ŏjȶ/箧c X"C{7oD3GW~qgB͛ߴ"` 00\t*H/\n0 U0\r\t*H\r_\t8s\nVI;UpehR\nɰv/SubFilter/adbe.x509.rsa_sha1/Location(Sign Location / city)/ByteRange [0 30700 30964 181761 ] /Filter/Adobe.PPKLite>> endobj 14 0 obj <> endobj 15 0 obj <> endobj 3 0 obj <> endobj 8 0 obj <>/Subtype/Form/BBox[0 0 100 100]/Matrix [1 0 0 1 0 0]/Length 18/FormType 1/Filter/FlateDecode>>stream xSUp vIW endstream endobj 10 0 obj <>/ProcSet [/PDF /Text /ImageB /ImageC /ImageI]>>/Subtype/Form/BBox[0 0 180 90]/Matrix [1 0 0 1 0 0]/Length 29/FormType 1/Filter/FlateDecode>>stream x+T0T0BM endstream endobj 1 0 obj <>/ProcSet [/PDF /Text /ImageB /ImageC /ImageI]>>/Subtype/Form/BBox[0 0 180 90]/Matrix [1 0 0 1 0 0]/Length 71/FormType 1/Filter/FlateDecode>>stream x+T03176P0A=C c# BX!9WA?"P%_!P F!00P4P(J ݹC~ endstream endobj 2 0 obj <>/ProcSet [/PDF /Text /ImageB /ImageC /ImageI]/Font<>>>/Subtype/Form/BBox[0 0 380 154]/Matrix [1 0 0 1 0 0]/Length 263/FormType 1/Filter/FlateDecode>>stream xAN0E>_$ ɮ U F k呥ͼ(CKV ,>+Qf=y5ach{Kڗ$I?`rfE)X(q=RݷkB/IXhb8U)).bgњGp7Q Qx,1/MΦ*03] RV6Nbfs8H!3iy~>zjTqNy endstream endobj 9 0 obj <>/ProcSet [/PDF /Text /ImageB /ImageC /ImageI]>>/Subtype/Form/BBox[0 0 180 90]/Matrix [1 0 0 1 0 0]/Length 34/FormType 1/Filter/FlateDecode>>stream x+T0T0BgU)c endstream endobj 16 0 obj <>stream 2009-10-04T15:28:19+05:00 2008-05-13T19:03:02+05:00 2009-10-04T15:28:19+05:00 application/pdf Developer Resources for Java Technology uuid:b97b984b-f7d7-4a16-be38-b3b79f445622 uuid:e397e890-bc17-4438-989c-cde8ff4bd55d Acrobat Web Capture 8.0 endstream endobj 17 0 obj <>/Pattern<>/ColorSpace<>/Font<>>>/MediaBox[0.0 0.0 612.0 792.0]/ID 52 0 R/StructParents 1/Annots 53 0 R/Rotate 0>> endobj 53 0 obj [54 0 R 55 0 R 56 0 R 57 0 R 58 0 R 59 0 R 60 0 R 61 0 R 62 0 R 63 0 R 64 0 R 65 0 R 66 0 R 67 0 R 68 0 R 69 0 R 70 0 R 71 0 R 72 0 R 73 0 R 74 0 R 75 0 R 76 0 R 77 0 R 78 0 R 79 0 R 80 0 R 81 0 R 82 0 R 83 0 R 84 0 R 85 0 R 86 0 R 87 0 R 88 0 R 89 0 R 90 0 R 91 0 R 92 0 R 93 0 R 94 0 R 95 0 R 96 0 R 97 0 R 98 0 R 99 0 R] endobj 54 0 obj <>/BS<>/Subtype/Link/Rect[14.9268 702.307 89.561 767.985]>> endobj 55 0 obj <>/BS<>/Subtype/Link/Rect[97.0244 755.745 349.592 766.94]>> endobj 56 0 obj <>/BS<>/Subtype/Link/Rect[97.0244 704.099 150.449 715.294]>> endobj 57 0 obj <>/BS<>/Subtype/Link/Rect[14.9268 623.195 89.561 688.873]>> endobj 58 0 obj <>/BS<>/Subtype/Link/Rect[97.0244 682.902 260.193 694.098]>> endobj 59 0 obj <>/BS<>/Subtype/Link/Rect[97.0244 618.717 143.48 629.912]>> endobj 60 0 obj <>/BS<>/Subtype/Link/Rect[14.9268 544.083 89.561 609.761]>> endobj 61 0 obj <>/BS<>/Subtype/Link/Rect[97.0244 591.252 346.123 602.447]>> endobj 62 0 obj <>/BS<>/Subtype/Link/Rect[267.768 552.143 308.988 563.339]>> endobj 63 0 obj <>/BS<>/Subtype/Link/Rect[14.9268 494.227 229.19 505.422]>> endobj 64 0 obj <>/BS<>/Subtype/Link/Rect[14.9268 442.581 68.3514 453.776]>> endobj 65 0 obj <>/BS<>/Subtype/Link/Rect[14.9268 409.443 81.1303 420.638]>> endobj 66 0 obj <>/BS<>/Subtype/Link/Rect[95.675 409.443 144.45 420.638]>> endobj 67 0 obj <>/BS<>/Subtype/Link/Rect[158.995 409.443 222.868 420.638]>> endobj 68 0 obj <>/BS<>/Subtype/Link/Rect[237.413 409.443 283.868 420.638]>> endobj 69 0 obj <>/BS<>/Subtype/Link/Rect[298.413 409.443 340.229 420.638]>> endobj 70 0 obj <>/BS<>/Subtype/Link/Rect[14.9268 364.961 156.612 376.156]>> endobj 71 0 obj <>/BS<>/Subtype/Link/Rect[14.9268 331.226 192.619 342.421]>> endobj 72 0 obj <>/BS<>/Subtype/Link/Rect[14.9268 273.012 49.7735 284.207]>> endobj 73 0 obj <>/BS<>/Subtype/Link/Rect[64.3182 273.012 141.556 284.207]>> endobj 74 0 obj <>/BS<>/Subtype/Link/Rect[156.1 273.012 233.348 284.207]>> endobj 75 0 obj <>/BS<>/Subtype/Link/Rect[14.9268 228.53 152.537 239.725]>> endobj 76 0 obj <>/BS<>/Subtype/Link/Rect[14.9268 182.257 265.771 193.452]>> endobj 77 0 obj <>/BS<>/Subtype/Link/Rect[14.9268 168.225 75.9059 179.42]>> endobj 78 0 obj <>/BS<>/Subtype/Link/Rect[32.839 140.014 78.1345 151.209]>> endobj 79 0 obj <>/BS<>/Subtype/Link/Rect[32.839 125.982 126.92 137.178]>> endobj 80 0 obj <>/BS<>/Subtype/Link/Rect[32.839 111.951 79.2839 123.146]>> endobj 81 0 obj <>/BS<>/Subtype/Link/Rect[32.839 97.92 76.9747 109.115]>> endobj 82 0 obj <>/BS<>/Subtype/Link/Rect[14.9268 50.6019 59.052 61.7971]>> endobj 83 0 obj <>/BS<>/Subtype/Link/Rect[73.5967 50.6019 179.861 61.7971]>> endobj 84 0 obj <>/BS<>/Subtype/Link/Rect[194.406 50.6019 276.293 61.7971]>> endobj 85 0 obj <>/BS<>/Subtype/Link/Rect[290.837 50.6019 358.775 61.7971]>> endobj 86 0 obj <>/BS<>/Subtype/Link/Rect[373.32 50.6019 415.136 61.7971]>> endobj 87 0 obj <>/BS<>/Subtype/Link/Rect[485.122 755.789 579.203 766.984]>> endobj 88 0 obj <>/BS<>/Subtype/Link/Rect[485.122 738.026 531.567 749.221]>> endobj 89 0 obj <>/BS<>/Subtype/Link/Rect[485.122 720.263 529.258 731.459]>> endobj 90 0 obj <>/BS<>/Subtype/Link/Rect[485.122 702.5 531.003 713.696]>> endobj 91 0 obj <>/BS<>/Subtype/Link/Rect[485.122 684.738 521.714 695.933]>> endobj 92 0 obj <>/BS<>/Subtype/Link/Rect[485.122 666.975 562.924 678.17]>> endobj 93 0 obj <>/BS<>/Subtype/Link/Rect[485.122 652.943 522.863 664.139]>> endobj 94 0 obj <>/BS<>/Subtype/Link/Rect[485.122 635.18 537.961 646.376]>> endobj 95 0 obj <>/BS<>/Subtype/Link/Rect[485.122 578.309 572.233 589.504]>> endobj 96 0 obj <>/BS<>/Subtype/Link/Rect[485.122 564.278 517.639 575.473]>> endobj 97 0 obj <>/BS<>/Subtype/Link/Rect[485.122 546.515 557.125 557.71]>> endobj 98 0 obj <>/BS<>/Subtype/Link/Rect[485.122 532.484 564.094 543.679]>> endobj 99 0 obj <>/BS<>/Subtype/Link/Rect[485.122 514.721 526.927 525.916]>> endobj 19 0 obj <>stream HWsHNrή=H!]m핍lrI6uAh#$" _o$@*,Mׯ{.^"/q4,駟e 'fDlFǙ>N2R_^fw';IY?|y5C_~z` $)xHy뇡C.bny̗ܣp;2 d3Ӎ)y>4^EB30~,wq̇A4+繹|Av=kxl@ZxU."vSuU Iz0 gs5i3*,{ ]n[maiЭues@/86,PkOkjEB(qӚq.8ʹcU>ב[SĞe,c/ ݬS2:8Rs g]k޿H;R˗%`[K iH*^ץۥr4lMpWJ/XS)~R6#5<+N·gڲwTVoujA*͕UP@B:qzzSUZO.mrb>:ٿM4jc{FǪ8LвW[nõ;mA!:W+F``ʮAA2l:TGdMZe0x{H\ .tWp՛V0àjR(dZ'M,B{ձx%= J>,. %ƒCߪ֠\ڠ@9At&1Lf ͻ1^$Q/ K<2=- J21C$3Q S2 ñM{~{`_,ͳhib4N(0-Ѝ4WӋ#Cןg&/ҫGfY^R[S^(-5 ]j/"47Eg)ElA]V`/gi 2͢{Cy1)ӛ%E Ń l*S<~6?<3L<1 3X*ydiXefwୃ&SfDd*jךb7bme99F+&U*;/-#t|Ń[Pu~5cE>Đk/tmRN $5dh~.NpPJRٓfQsV1GUTL 4i<1ɬj|.Rb&#ǒU>slBĿY O߆-'$ڻa'dV/JF" mi34.I{:_v@߂L/ݝ/WjK75 ;3o/*BUhM2wK9G|O%%_R&QR>ir4j>n #I*rZJKHY1|wwx/ldQTbհh-0Ts w$ bGўvUm5FS˅jod{6oyA|\T7pt)&YXJL(Y je)*i6 #Keۇ1 x9ZIqFj-q`} 6S(K| ~ŶUPۻ/!$@UP"4N3k;2Dyݹy3Q֧mRn | l 3 ;Fnh&{pjXllEhL+!W֥Ti!˞t[);`n~Ƌ0w" SkU`>b@}G Z_|-$ |KnTmnU*O?i)2[9bKh+d Ku3}߫Dž!aB]ga -,Fu᭪+ЕO֨B'OӯƆ]n c>эUqr@z%jxA|WO[? +HKPZ݂K|;Si 0f # =L[dbU!T KݰWq_TZ&jpټEuZ[(o E@^4@/f5}8QFU1L%ԡu=x7}YqLAWpMX' 6w]vܵgq.gεɅABAt endstream endobj 100 0 obj (\b%+2E\nD!) endobj 101 0 obj <>stream HOzS͹fɭ@h!PAB:CA8-D< •Z?.o8˲QoJcj36wÎcǗ>~f'}|gP!O( @/Cf4"Ą %7JK01/7vE8:mSsĖEҴckjg”zT('\bsſ5G$g}1#5x#YU`O6rUJv)к\I^7igeH.]̖bb!7tʕ^f/1e[?:>|}s"hnp\'{"hI*g]6եYhyd̓Ug|}‴7$>stream H9qj$*Zst@ $(7mӵl0XfM$Njĉ_%='g/m,ٳхCD"KD r9,XBY u_0lMf3l&٬QȠ\f.|NeSRvn6~f&c2e3YܕN!d%TrGEC7JlD%o2 c>fO09Tr:n,';؊% )AS{䋙b^,*ڸ2 ʥPΰe;f6R(N*F u(N .rZ -h͇yDۂqF\ (A}hP(45L\yXȫ7G31 y-Lb^DJכC|G&& jp]̐gM{t~֕L) p@1F=FBR^t:INR.uMHC:HA HȡW = ':cN'%ZaDO:j ߱ (vcBQϓbTD)tRI@"H0Yh|hgC rU4Q|Aa _HrܾWU.z#)+AxWW~e: U qw%4} qJÍp/L3w46); XC@AhUXy: MݾxN$7CJ%x2nH\G4V#$ٖ$fˍx(< YZ§Ķm 0pHnߍzIC[CBN6Gxpݕo)>txFsj!.2:4t<cN(`XQ+1Ri?@z.lG7̮ 7*h(j1-\[{Wuv y:qP=(*ShSbGykw?#sVo މ=m-+®y{cßyxfqp:&5{Šבv`!YŲL߄LAo@0zkmCz6Vijd:G21^.Wpʘo5\8U׈jl"#a\yO| ҍh7\ᙧuLI>\ޏAņ(?}ZƦͰJ +' H7^'ۈr/ede8DqhcG93[r9G /EɓUw߉HheR6t t<w)~θ5m}5wFu+1D5Iل}vZZr3l 3TIul ᮽsFaS2ثcLĩs d:B9]٧ 9!.}N"JR;MADqT*dgF G70NwsFIPN|aWFլZV8u$0ʕWMSo壁6Z-z/j_v»F|Z3{{Jm`ԡv endstream endobj 102 0 obj (yژ?]uϬ) endobj 103 0 obj <>stream ol֩|VwZf{lӃ탤o)qֻ%RrZ򓨹c}-lk逭}+cvX؋匹vqHh\v՛]݁Vuz፬ڬʼnN`~+f{FvrΈJމ4\ӅsvkSsݧ~їMsېo얭ľɗFx@dqLeݍ솫c}imylԳwpwYMouُ_]DHN~Km8}p8Î#RbCQ endstream endobj 20 0 obj <>stream HtLgK[R5+(D0: )" Bm0Rd3<1Qh D hsqfPy﷔y_L|yZ}?:Dp%dM;2. 0!yM /k#HÙF455o\Q:"}XBxd“@/A/e>{G + zs"^ j4tÙH3yOƝaq,L  cZ{tE1"Vsev= ?̆WsH`Ιu7=aQӃoEvh4F"m 5HW% A,"H5}̾*#7]ntf!@;*wI%δ{EFL0FsZ*/j >Hr#@ ɂv{+,Ԟ @ )U(LS*9ܾdm5kO 0n%F|k5|xuVFnjkNZYu~J8 V*G*U0%2+w>x035u¾#BxB;pGwA P<T͇dzӃf[ss8<6[sBBn3l a`Fwsg 5oEs &CcVߔ`'$kYǛǯ!lff}]Fb,[eԜQ)!@[و`Bï2ȰވYҒΪ_æ/b۵3_xuhxKlWpPYkY&i0(! `ׯEz2+ƬzC90TRZRyTɴLZmp2++k!J8* O" "R$*ׯ_<7ݻ l4l 6!ǯ=ɬ@spjd B'Nz<햼O}[X3`YYYSS{S1B0 D@yy۷&- EZQO^֭8`ԊC8i 3` !k{m]<w=hwU(:_{D\fdԲ1PQ=O2:#"2 (l kaaݺ>Yn!2w2ĈreЕy!n$Uiq༎~W,–LRRM$nԒ 8ĵBA05Q|Y)uK,mS{3H钒ɱ}PPMTXk4z}g1ahn WQ9 rj4W."ni\^W)ۛqh 1o>e@o2x55O:Wb#]pFٜ^"(`!W@y1xA,#i 0F,Tc7!W3qRqebΧrpc%BS?GHs%%g<[3bO|#CZ-@$12F>w$//:$kKW? //9 1F49"F~c]KmP3- I/*F?8.- ztG!v:I 0+e`Įd7ec#V--ҕuuIҎ a8eƟQ ,/[a CFV*`;Ѣx(-;> <(<®RScdgd9xxglMWU%#"zE0D *XUx.)DuеjXƮV8HX  #`$ErTuO۰UD$! at9V>DŽQ=iI`#B *$IuC8sCt~>W.#_I|9ƘfO<**v=Z%;{+2B %r udiC(' _te~e&qܦ{.uRZ`pzAkZ3he6; pDlpB7I{(7Ssz9skKt;ceаbޚ]5|Z?}=P a2DζMnIF|W7S\nwjE3d:\1` hUe-Br , ݗ)Apyuo)ҹo ›sPW"m! ]o ﻛK 7dKzDXuM<<@ D϶J$]_ )y0tgq$+nIo\nlJ:~hѕ|Jɾ_ʝ;|`Q@ $/$AF"]BF)VQ$]tlh_NJ+_uo>h RkFÀImj\!HԆ1@9{|6v! P>)y!l{^?2#r\ Z**@a86ll׶Gg0YP'%UJZE a԰ <"550~iELX+O3a aE&VMXv[ZpzU;w~otxXy0bdߛTRDPȔ߿Ж 8}X&ht$#Hh²7d%^ZdlݴϙF%w} `0m i=2hF(8{ / U!s[+x}С%bp9#,VnLI$L~ Vk4'8c=dhe2 r՛I `WZ䌾\KupFcr<wWe֪rrZZ٭vB:+F\AvHqMDڛ7 -Ðg>I1l=<IfJ¥AF~kqZJyW00!o#p:{?RB9DU}~ưѵQ/h1ܨ^TQHB%$І <`'g"wbZYPh4a~"^r*/5D endstream endobj 104 0 obj (^S$eh7\\[) endobj 105 0 obj <>stream U嫯ɴϳpmvg843r8(IWKSV7EpmUMm2 *vWdC5%FF+)nP.g4otGHNzQ20col6WG6G5%ZilIVH{0iOwk0%86X*)SDqJއke7#TS)S9 2'#4&xc"G)8w)$4GF6V7udvKQ((j8XXFD&,JYse2a/58$A*QxfCK4yET8yYoŚ5C'FcWȎbWfWEff"K:#IRjwi|Th[E$VX8j 44YsZhĴVgd4U&FeDd")"z]5) r)6QK}ũqHx\*!K2 B;Dxe1JSVyFgB1v%{Yv|284 (7*K1jHvvjCQL_[*K:郅ftݐQl]C@\eFht\B&*Q'j{ Q]+B;p4#-3iWW)LYVaKTI8!jHT)3'$,A0u\!OgxWb=LpE @FKg9yʌlNoY>닯u?;`yר/d!a0;_zBbx^Q8Eɺmyz[Py;a endstream endobj 21 0 obj <>stream HTUMlj ~q6TyKZqI1f,Ȉ_"MGH3l#ιso?}ba8>GuvN؎N,;C2='f,Pc;  ~}݈] /!3͢cK't:eZ4܎bao ob=kw0}qB/z K;8;ƝgYeYRT&ɒ K:piDY':@)iZMGQXRA&7l"uMEd.)5|]b x|oKqox*ʸK]kf,\-VgwM:bȚǍE9<2D(>7`@}neV /-WUȾ=d\ـ|E]R,R\M֐řxkc2hx aR^Wr۟5(Ձ7|I ]cUD, na#jufI 8P_:ٮ&3zsmTU˻"a`dr&KhDdB%ʩT  +k2}YUK($O!!bdyWjX'lZ&^fcj,R,-MxpǛV TY'+ZY٪/_Qǻ©wSpSCu|?γִ Oe? RE@DAnwwYmK);l{;HE,Ù<~ZK=u}T] #U<1T5]k, pah$L!Os?L!Oqh=M:L.K@$!_(ŐȢpWEi i7צJ<9e}㻡:(- C>EUPl1<{әV:͠2Zhtn+.T>KѠ4]?ȿ‹@@%YQd`;]qk!2^Lpi_Q VKJY>zSc`MYj\D3LlḰd{Zj0eZR1_RZQCN4W0wT˨D\n^g1j< | ~Qbި<_J̳L1 *a@]+F2Nܾ2{ef0{@}T냱|Tz\UkմZ/fMHr̷V^. bV~o. U.]ks?޻r?/Eȼ>\|R!{̼\A୕_[>չ{,F+aW"Own}Y/F?@'r#:aIU0cnÍ bZijԒG+r R=lV6{11SܥGXҚSrxIGQڮ?{w$;y} ]X UtBssw%VCs G')#$0o{w\w0"]+ez5|ֿI d]Y?􆰎T :Wt5aƞ85M 8q88)90r"Dˮ]^2a`c߯q]iP4 Fao9% 362͐0fI g9YC!%r0Qh,M! Ʉq&xA)ςk k.@I j0 #0 o(ZD"Q@O'dbY#IFouf]Z%[ ݾýq |^Dۻ1&_^.JjAQT'J71GDċr,']_PXD;;ߺ-;}5d(KxU{(2^٬V(őՉ B\wZ3@Qؿ0اӼirpQD!?_}M}3"9JiRi2r^Y[(uDāJ^jnqTqQ>9aiid i I GAM25A`Z8f yn!2ޒ_J;ywJ3Տ'ɺP]HQVk: nN-zfCj:S+.ܜt ?{1uSRYg~%`8'I"*j&X763M&Twv~xDpra֤Qq Ie6Ñ@&l|( K¯.W›pʼt$&G*ZXT%?K+š!O|TO_ԏyFRpt>,=mE-Dd.Y,m7<7KЈGj o-yx[,\޾rXCsT+ׄ=nTj^q1Q(9ߋ)kI*ZzY.?[SmQ]fR 9;;YoX&Sz+$?`q*JRӸǾTC| g-q[RXaA@?nK\>Zy'p:cvsNP&P7|[eQ]iiup !tangх$.]qJ% &1a-:)\ W MKMS~)Q3YL . FS\/͕rU_>='߼:lN `|zSllʓ  &'Q.` f~<8enԌ gC±UTB8}krs(Lc4|f7Sh3??<|:?]:XZzz~+>9l>C?xH-?2=RX[[+L##f^38b+/?{-Fd*b`DOc֭EϞ@9g OӂwvbDL>Zλۺo&\<&!daj@t@'g8Q4- ֏4Sݎ^QI4x̺FBM)xheJz211G5.H1BW>iyi*wlk8XL, ЅdcԜl4UX"J\MSz:!T/W[U:^%Uã KtŧRM.1QyV+Y1C=ǐZ޺?a`f.AU.]iy_huG;E"ϋ=eK1ymBIլܹД\#~{S)25S@b?& w58ܥUeײ~~nq^S,WuZŕ {WDiW[ ]eղ^JB"PW,.{+8«‚b<,cQ#0Y"j/·H*F^XHRvzcRJWp6}>Y3<4 1 ˁ(s\ 6Ay !Ba1̳r%[gl:5q6A]I%(8r {N" 7\XOxG;^HKB:@paPwZ,1Ғ$Sh'HKw>o r5#?S*>'}S1U0*\8E7`0 endstream endobj 106 0 obj <>stream HypUOE,߃~!d0EGFY$&BԠ"HT"DDVW@EET@v*þGޜI?jfj{ۧAD)7ekϯD5ۯMlXq7pDFRĴ8|'Q{&yILJ֨S- |BҧC>4rNjDmtG'>zF/ }1 G 00SQ%( g}s|m؉؋q ~9\Aa&+ &e^ysE~ x ;oM~>%#򯺟W­p`a0TdA<)x oa]|#?g؂Q'qgqWQ.ԔJFJI?H'*#d'aKls$Gsk<\9kr^+y5x=̟;x|R\g"_pW'tFtw.܋~3P(A&c <1O)!Q_Q󸌀XR]z zPIDJRZ-FJ;Unۥtn2X$Y)庳ڪr^y&?ͫ\ _K|.x$ ]=p?ɂc1\<|x[yR*SVJ IDI 9 ?PLfE5L2 S+FEki#m]t~tY{oQ4RG4S/3f|LͽK9|EuUse2,SU4n2K[4Ը-(bE7e7U7B0ō7Sn7dzhkͨGǪǫ*kfUS+\/WTB*Qۊ֖bdgYCߩz{^T/֪y e䅪#vZ5hy7a mZEM}2-nݓ96ѮZ6`0ʣIEeV+Q=zUKkHtc1ǘk,4V9<3<]u%¬{<Uk`Nh&y]5dW:v};>cx;ng3%2{=^33S5 66M&77_c:aN=iD;x'vrYlgYu;6gsKu Ɣai\Yom?ݿ @0rS`21*-Jg?Sˋ-êmXyVZd>[fwGW0)Ȏ(vV:QJ'־NYt ~=yUtnP:7y#* tN*:yNV_UI.(G\KP:!:c`̭G&xSu41Ƹ@+oUU޲qR !F'2+yy.DM5>|% r k{(YڴFu|?o=<[d:ИalD7 X B|R),0?l R%Bh|a) 0qp ~pZX G99q,|Oqi>gP2_a [*'578o-w8=!?S)?/&_N㷰| m 3 v:ꦺ/0"xk/x$FX a 6Ʊ),]NGG(ΣUOK*Yx69<<x^x1/Gޓ6qok؋'Z^ũl08q6t JtnJu65v]tWILrM@i{AwDuVu픎BwQp=BUQJz,J==/}OTVYT)٬KBjZTB>ԏcѩ(@ƘӒP'Ic.2ү:I" v-$ˉ*Um@qM2#Eڰɑ3Wn5 F4\f~BUr?ęHk,>h$L~B>o4y'_08 W@HF{]6Af*}BؒtEdrW/#99WVf 8@eh%'1B0,@]2…g@4\&b&@!p򴛥|ESdbʼxf6D p`8QCFt}I!›׷[Du3#$R8k/\3"ޤO8ƫ48 =$Z!5fAt, HBV IxWE0GA˕(E91m))VTrP)#6! 2I8vJHU*ݯ{^FSG^a}>j ֌ق{,|9rJX-+eh5Ze+{X0c4 T xM' rd֫̆jau%.T^*gU7d;>*!eFDn?v-hܧɢQEX"@;,(&ιN/wO<Xk-4Pa&Na26x! M@+eq22mI=VNl|.m~Oe9F~w?{*DxF,M[bhY+J2Jd+326 m>"u{}}=jc1QXxqq1h߲]F%|2ϋQTrx*Zf6اin+8ߣ˧JVjh2>}"7tS{;7S=:";1Q_%Pޥ/do7bRz#AmO|߹~\#.Բ/aU$Q;5*KP_ObP[1޶//Ut>uW~a[ ޶P Q8Rm˚q6f_mJmASi{e)6ŃDiGp!dsf/!F{ qB-Q4uky1D||K\B+7)܄uzmP?sͶ[:kx[Bew4|=Q헤+穆;awYԹ+pfnf@~/Q9%SMz9="\vwz%ӊ N~jR'<3~1h:񑏹3GdO6t`Wꠁ)MQ_ U#;l(̙"`D0† V-5/ Io(~!QF#R#]Œ/,wn~՟IpY;$Q'yn99E>SXjѓErp|4g O{<zi1cKu0NA !GV'%[z$<B7l75ZEu}PV^Y3w K ߫,`do1p+-S+<3 %{<砨y[%4sK F~2Z|YOA373 ](!682TY ;ޙ@[kKӻ ~B_8N"R[kq_,>`J䵸\r%S$ai黻D[,b1,!9{x;vKV? 0yZ4,HZoGAB|?m FW9@k X.J ^% 4tX̱Jck9^3b6Iz5g/qRJi立yx~|`<ّXk5`/!,`;֘>PevZIs/i+o|@yyA>ƀ <vѧmG`D[/Pfy]'!~'"i@3=޻~y$@-y&XywHDZ ƷhI(KҡhbA"ZSѩZZi2SMk t0rs39wv+5r̐<^ۨf̣y ̿S3j_JmMC5Ac)COoxm^ B_y?l0vx9( e?By s$;$hkÝ%Dz!1xH?h/p@N ^#7_K+|}S|~kIUs.3yj4M/K6)OJa7N<٧b{O܃-OØy?l6h-d#x,ϓ.krM'k#8ܾ}}'% m.pp4T^?*MFR]<e_6iVv[Hq}lzѳXEyh3l&lz78dz5'f'vb>xODڍB0ȓ)2Jw:nKiU92/UoQF#Y4}뎥^2^P~X!"_hɢY>NeT=#RG;2,ڃ6^@2 Zi-_vZ͘ϣ8ׁU5j>vְF}Pg?^>4D$W;-]M{n e%RJNSп1Z-Óxa1 ^٠yJtz\揥̽VcJKS5^'^=G[4/VmȤV+{HoJ1}b>=l~Kb1lz'CPs1JV9jܗխ`Tʓ|ȱzl~ 66xYdkl/3>9OnJܓ`]3zjMVk=fqhq l죩Rr/Uh_*[1}Do@&yr~\%5:.&\{y1{/NgZYFztO8{ڹ3q)4{xb^WQ}%hTi o 9ݓ1%>?S{,gɩ@{8αm?soe|$!%G~r"| Ρ9CwH| ߦpMKM^y?u٪~築Uνn|S}0eH#} }#dh 2P3nk./R;"s A7KϞqd?[T7Ӈ7'a.?̽;e2ߣ.gyR=$ƓW;_rgg HtqTAb9O {=[}o";WTg1ƕ ؇ti~BBBBBBU!!!!!!!!!!!!!!!!!!!cDz2IT@D"%% im]u Z7)-}HWƦ>Zw(( ,zO٥D$Jz2-NݨL4/,Ljfi ;Mdܢu 2.|elJΘuj=BUKt'Ф!ZO4$}֓ilvSʌ#ZO!xՓ;nErp~NԥrK=*qRO6Rҕlt+lte#+)]HFJW6Rҕlte#}Ms"d_~{y.9wJ=zFRv+뮑zKWfO"7H}ԟz[XO2{"A"CK># B*k#)XXc). Hle#lIFr-55ӅxG -<+ˬIYؙˬl+ +1;!m,S&EZweY]G] `C)\W ņ{ƒz-",19;Z4^ƊLD"{D$ZB.z5a "٦Llޗfm;+ѦDäUVOy$#xLd9z,KO.2J4';+Dsբ$XRFGj y{{.mdinͼ'V+yjZbctLԕS4^"Z9zk VuB=U?Ž9dwp`GIhkYK:0[Z,4C3T8' $b c7v$Ԣ㫃;Tۯ]7w Diz/9ȑٽs:GD֨Wij'>U?-^us̄[z|1{ҁ=K>-CīH'5=FCk]^0~:'ra43Y9bP"疕z{|Εb:Ck\DNV5PmgGGKD~lJH(ٜ&un)3к>SIY~Dw;G1(Z|l'3Wx|? :o\HVc9ȏŻeCWd\M?kLȵytj'@d:cX/6'5L?-8!k |ʬcul\%Zyp]<%99n{.bg/]kt&c$C;oG=R۲MҡO\$eJpm FY!8W]9{yPF28ZhM_FAGFmeiVbI]afAGХ~ Q,xP)WWqQqv * k z&a!XLX}9[Tb3r*ѩ-JD:A AH {canBB4T R֋*Ԩ-#f!s}kȤ5pS㎒dG&p̍.l1CPłYf *q+B}AMê(բf2Ȓɚ0FG ݬ FHsXFkCdw2Ity}Ë%X5g᧮Pc3$Ag0 %@'"D<3g_g6 YZ"L2SDӳgo>*"~fHFu2'H>@S>O@t334C2z^Nz^I jz ^G7Mfz Fow;]4{>z?} ×!z2^Ƙka=Ca': Ix;k1ޥOcDH{@gx }@_/a2aa//:9DL0Uو#5:}Iߢow=>~H? )~N_үh'm۶m۶m۶m۶m۶!xlMpn3l&lcs[hl-̖ [ilu6FdmmmvNe>ovĎ1;n'줝v9;o]+vծua7ݶ;v@~#{lO=TW[{g}OپWf__Cp@HBhAXCxD@DDBdDATDCt@LBlA\C|$@B$Bb$AR$Cr@JBjAZCzd@FdBfdAVdCv@NBnA^C~@ABaAQCq@IBiAYCyT@ETBeTAUTCu@MBmA]C}4@C4Bc4AS4Cs@KBkA[C{t@GtBgtAWtCw@OBoA_C @ ` P pHhXxLDLdLTLtLl\|,B,b,R,rJjZ p6b6c bcvbvcbNN .. nn ^^ >> ~~ ):0(18C0$C140,1<#0"#123{؇P}Q>X}OI>٧T}Y>\}/Eؗ/{㔶Mi&iӤkP.YrI1~̌cffffffƓNr=qww}wt&Eg9t.Gt!]D%t)]Ft%]EW5t-]G t#D7-t+Ft'Ew=t/G =D#(=F$=EO3,=G "D/+*F&Eo;.G!}D')}F%}E_7-}G#h@ F#2hB͘ɘ6b>6clͰ9 [cl=v ;cLîZЊ<03юY c쉽7Afc梀yD1 ЃEa_,F?00%Xe@q4À0J(rB6T.<01c%VPqQ8XqNI8Tq~_W5~w=?O3o;_7?Y8\q.ER\qUZ\qnMV܆q]^܇CxQ<SxY<^KxU[x]>GS|W[|~5xMnn,7ȓx2Oxmơo[oo;̻4ޕs[3x&,ލw=xOދ}gǝ<p/^E//~Aޏx /e?A|0Ygslra+lU^.{s<㼒W|G||'|̧|g`Xd۱+;"̺\;U rK+T\'mT4u3*+bsGNɱHZSsuMj`gi^9]D,TPBA`KAZ"鑬mڶ*);LQT'aXϔ_-z40-KkcJ̏cf)yZ`U,xЩU*R&4Z`ҢꙖ홥 U-ۈli<#uKpM𤹌Θ%tĂjSY*jplŊ_b\cEO49_DMۗ+sT a[N5vPj_Ѣ?/7=$5ҚҞY iI>Ӓ%.˭d%iI%$I$HO\jN-Ipb9ēX'mkvtP-Z>g"Vʚ!ic$̰v9MӾkjЍ熭ftuKdL{(CySCM&)/yXTpWI"B. S8^|:.o}Csy֪NV ;zBm4gZ k]grW--AkkS?ݡ[ZSfT-1Ws>f]B!rAUAB9!lgRP$Τܔb)t5rnߴ f83[b[Sav~y$4f lK SoI&ĎI`R.“8>ADM ɫKx LT *~T`p'+ϗ._HF&+‚_nh›=iN6tG#MׅO:M|v ITѬ#lXm.~M Zt;1kɨ`pS_ES"4[4̍b쇖MShժ&'Tְ0h g"3?jZ"l;)LM$E}"IL\5Zb|)l* :aϧP#Q MJSnұخq-Z5tzfoLa}[%fŊE/ $ЏO=WdX$ʺH샻8Qכ|kW:+x^6цQ4Zy 9E=* UhTѨTCF= }5*kT6lP٠áC=I/ f-˗vQq9.m@/vsx]o[o}>H{6޻e<(qZ.ֻAϰUs/rߞIMGKJ/6vOɡKH&\_͗)mIFzZg|587ڳ}%u擾d9oE&'ƽy&=(sr* j'}iDoJ=Q}K EFFd"r~ Be+Ϣrj=Pf^=*b; Xi՜*v+eur؉E.y לkC1'*s/ '!cNbhՒzsZ (R_4|Ѩ'؂h*DAip["D(ʼnl vJz̐`Uiy#N=BdٱC<AI_̑J$*+̇X>(̇f4;WZ4ÂCK=v(5V23 *a@*^6 4[OϋqN/}jl_w@۽* cY/.4JF`4c>W~++)p]` WQ#_8e Lk8\)S8e L)2Sp Pr|~Yl3Yr<Bn2<;~'?sO\o-c[ Kkw''̋3/ċ/ΛN:9E r"κCL>4g+7@;蹑;7"m'FTDG*oDNT|P;Tt],,xYQT5ECR):b)N)(^Y2@hoh(:a|vJ:8*"?gbH|3OtR R R R R R Rv@(ÀÀÀÀ+ P)+I=]-rz(l Fa3t53)J(_Qj3j7-EVȫ8(q,pUyq9 fM/ U/ 8@<7}|,XyZZyۉgQg '8pI>kZe+h\SH9؃62Ҋ=[#u26zdH8j2\ pƂׂx xjF7&p.5sqƁݻ]pr6u9J :l-UjV%ۺR!EY*zHMQ뺒ICSٝyԪ+7oy3ofL<ՑPPPceO5]փ!qXyI c珁#a%S:qjDibhb \ƈuK+M:%#lx;4yZƋk6TZƋks6vLZ.TTw$uax73p {$3'R/J"sZYܶZ⭧⭧&Dq9EZL{`xש2b5o:WFfCJ$2AMƚT2n&bMI FܰG*7XzH|ګ7Vʸe=w5FUYɊm Y1Ӭ8{8OYY,-jFXSԲbmͬ7%=zQ幞0Ef8GygqG͢Yed vL1kKAnqM\q/Ib+^x kL9)`MfucZ ?XMeK̚%Zb,_DB5KK!} K÷&ﻡ jzQJ$bʢ&RJ"!Y5>10, o;-#cmiX[w*Ωq6X"Nɞ!X_vk8փR% x3754Ս{^ cAH(@#)`PMBspm}z2g]V:L<}N~,}3g37wdcr!+u@5!0V?hry@C={@6HmOT: n!(BhlB}CXM)q媱$0M' @5}nA5;[d'@")XF1oH#$.߱_mkbD!fh''<b,u+@z݀A` 0f+xTA"寐D?,(']Od>:czOإ@$IA$i8=')8^EcJji5 d d d bgܫǷu)2ߤ>jLjyjAjǩv:>HM֛Fש]vڝv2k->2e%'A2 ۺ~ @(5y[kޱ+qV*,*P hY@Su@P mK@)9: g n`"VV֪¡xho.L:DX44BueZe%5F H ,(ebbRpUp$aD1|2{-*S> _S-WѢgм _T.@fL-G]ӥpkz-* +O݆`/6aE/`۳RyEe'.v[uqFLO[[6@UH`krGX!Ϊ8r{#O+Мs:^N8gS#ϕ}N*s_RA2pՅf>;D(\3_\>ON6 ԥiAM-qg-y'JK>缸?:9D[Y~|7@qosez#Qz`uv$xvWJ®I>0&G7lžMiS{lL&Ikݚnfγ59htH7D_lcq3s݌.O>y7 d_gbo2d>_Wrp)<}5G$Nz6o:ܚ4Nl2{p4Y1jOGm2 䜮9gpi>%gml+=PJ n7^SgyZ:K yɍ18 &`\C!,8-1ܰ'>_SBy] 2dzo endstream endobj 107 0 obj <> endobj 108 0 obj <> endobj 109 0 obj <> endobj 110 0 obj [109 0 R] endobj 111 0 obj <>stream H\j0 ~ Cq F vc̰Fqy)n`o}i'l Oq [GO(y.v2QiuN84UU?Dpxvǣo=pj#n'gkp8ȠW3!茝Z'OI?068ȆFTYUVHS` xzw.̒' "xb vԯ1o endstream endobj 40 0 obj <>>>/XStep 6/BBox[0 0 6 10]/Matrix[0.746338 0.0 0.0 0.746338 2.98537 3.92488]/YStep 10/Length 28/PaintType 1/PatternType 1>>stream q 6 0 0 10 0 0 cm /BGIm Do Q endstream endobj 41 0 obj <>>>/XStep 6/BBox[0 0 6 10]/Matrix[0.746338 0.0 0.0 0.746338 2.98537 1.08878]/YStep 10/Length 28/PaintType 1/PatternType 1>>stream q 6 0 0 10 0 0 cm /BGIm Do Q endstream endobj 42 0 obj <>>>/XStep 6/BBox[0 0 6 10]/Matrix[0.746338 0.0 0.0 0.746338 2.98537 5.71609]/YStep 10/Length 28/PaintType 1/PatternType 1>>stream q 6 0 0 10 0 0 cm /BGIm Do Q endstream endobj 43 0 obj <>>>/XStep 6/BBox[0 0 6 10]/Matrix[0.746338 0.0 0.0 0.746338 2.98537 2.88]/YStep 10/Length 28/PaintType 1/PatternType 1>>stream q 6 0 0 10 0 0 cm /BGIm Do Q endstream endobj 36 0 obj <>>>/XStep 6/BBox[0 0 6 10]/Matrix[0.746338 0.0 0.0 0.746338 2.98537 0.0438995]/YStep 10/Length 28/PaintType 1/PatternType 1>>stream q 6 0 0 10 0 0 cm /BGIm Do Q endstream endobj 37 0 obj <>>>/XStep 6/BBox[0 0 6 10]/Matrix[0.746338 0.0 0.0 0.746338 2.98537 5.56683]/YStep 10/Length 28/PaintType 1/PatternType 1>>stream q 6 0 0 10 0 0 cm /BGIm Do Q endstream endobj 38 0 obj <>>>/XStep 5/BBox[0 0 5 156]/Matrix[0.746338 0.0 0.0 0.746338 0.0 44.9737]/YStep 156/Length 29/PaintType 1/PatternType 1>>stream q 5 0 0 156 0 0 cm /BGIm Do Q endstream endobj 39 0 obj <>>>/XStep 340/BBox[0 0 340 9]/Matrix[0.746338 0.0 0.0 0.746338 216.439 5.2683]/YStep 9/Length 29/PaintType 1/PatternType 1>>stream q 340 0 0 9 0 0 cm /BGIm Do Q endstream endobj 33 0 obj <>>>/XStep 6/BBox[0 0 6 10]/Matrix[0.746338 0.0 0.0 0.746338 2.98537 0.939514]/YStep 10/Length 28/PaintType 1/PatternType 1>>stream q 6 0 0 10 0 0 cm /BGIm Do Q endstream endobj 35 0 obj <>>>/XStep 6/BBox[0 0 6 10]/Matrix[0.746338 0.0 0.0 0.746338 2.98537 6.46243]/YStep 10/Length 28/PaintType 1/PatternType 1>>stream q 6 0 0 10 0 0 cm /BGIm Do Q endstream endobj 34 0 obj <>>>/XStep 6/BBox[0 0 6 10]/Matrix[0.746338 0.0 0.0 0.746338 2.98537 6.26927]/YStep 10/Length 28/PaintType 1/PatternType 1>>stream q 6 0 0 10 0 0 cm /BGIm Do Q endstream endobj 24 0 obj <>>>/XStep 6/BBox[0 0 6 10]/Matrix[0.746338 0.0 0.0 0.746338 2.98537 4.52196]/YStep 10/Length 28/PaintType 1/PatternType 1>>stream q 6 0 0 10 0 0 cm /BGIm Do Q endstream endobj 27 0 obj <>>>/XStep 6/BBox[0 0 6 10]/Matrix[0.746338 0.0 0.0 0.746338 2.98537 2.98537]/YStep 10/Length 28/PaintType 1/PatternType 1>>stream q 6 0 0 10 0 0 cm /BGIm Do Q endstream endobj 28 0 obj <>>>/XStep 1700/BBox[0 0 1700 40]/Matrix[0.746338 0.0 0.0 0.746338 14.9268 21.9424]/YStep 40/Length 31/PaintType 1/PatternType 1>>stream q 1700 0 0 40 0 0 cm /BGIm Do Q endstream endobj 25 0 obj <>>>/XStep 9/BBox[0 0 9 9]/Matrix[0.746338 0.0 0.0 0.746338 4.47804 4.03024]/YStep 9/Length 27/PaintType 1/PatternType 1>>stream q 9 0 0 9 0 0 cm /BGIm Do Q endstream endobj 26 0 obj <>>>/XStep 6/BBox[0 0 6 10]/Matrix[0.746338 0.0 0.0 0.746338 1.49268 5.97073]/YStep 10/Length 28/PaintType 1/PatternType 1>>stream q 6 0 0 10 0 0 cm /BGIm Do Q endstream endobj 31 0 obj <>>>/XStep 1700/BBox[0 0 1700 40]/Matrix[0.746338 0.0 0.0 0.746338 14.9268 12.0907]/YStep 40/Length 31/PaintType 1/PatternType 1>>stream q 1700 0 0 40 0 0 cm /BGIm Do Q endstream endobj 32 0 obj <>>>/XStep 9/BBox[0 0 9 9]/Matrix[0.746338 0.0 0.0 0.746338 4.47804 2.38829]/YStep 9/Length 27/PaintType 1/PatternType 1>>stream q 9 0 0 9 0 0 cm /BGIm Do Q endstream endobj 29 0 obj <>>>/XStep 1700/BBox[0 0 1700 40]/Matrix[0.746338 0.0 0.0 0.746338 14.9268 24.9278]/YStep 40/Length 31/PaintType 1/PatternType 1>>stream q 1700 0 0 40 0 0 cm /BGIm Do Q endstream endobj 30 0 obj <>>>/XStep 9/BBox[0 0 9 9]/Matrix[0.746338 0.0 0.0 0.746338 4.47804 0.298538]/YStep 9/Length 27/PaintType 1/PatternType 1>>stream q 9 0 0 9 0 0 cm /BGIm Do Q endstream endobj 23 0 obj <>>>/XStep 5/BBox[0 0 5 156]/Matrix[0.746338 0.0 0.0 0.746338 0.0 49.0039]/YStep 156/Length 29/PaintType 1/PatternType 1>>stream q 5 0 0 156 0 0 cm /BGIm Do Q endstream endobj 117 0 obj <>/ColorSpace<>/Font<>>>/MediaBox[0.0 0.0 612.0 792.0]/ID 52 0 R/StructParents 2/Annots 123 0 R/Rotate 0>> endobj 123 0 obj [124 0 R 125 0 R 126 0 R 127 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] endobj 124 0 obj <>/BS<>/Subtype/Link/Rect[14.9268 709.279 60.4537 730.923]>> endobj 125 0 obj <>/BS<>/Subtype/Link/Rect[156.732 720.325 198.557 730.027]>> endobj 126 0 obj <>/BS<>/Subtype/Link/Rect[210.844 720.325 271.576 730.027]>> endobj 127 0 obj <>/BS<>/Subtype/Link/Rect[283.864 720.325 330.641 730.027]>> endobj 128 0 obj <>/BS<>/Subtype/Link/Rect[342.929 720.325 387.226 730.027]>> endobj 129 0 obj <>/BS<>/Subtype/Link/Rect[156.732 708.085 206.501 717.787]>> endobj 130 0 obj <>/BS<>/Subtype/Link/Rect[156.732 695.845 202.524 705.547]>> endobj 131 0 obj <>/BS<>/Subtype/Link/Rect[214.812 695.845 252.643 705.547]>> endobj 132 0 obj <>/BS<>/Subtype/Link/Rect[264.93 695.845 318.676 705.547]>> endobj 133 0 obj <>/BS<>/Subtype/Link/Rect[330.964 695.845 360.322 705.547]>> endobj 134 0 obj <>/BS<>/Subtype/Link/Rect[372.609 695.845 420.381 705.547]>> endobj 135 0 obj <>/BS<>/Subtype/Link/Rect[470.195 721.071 579.683 730.774]>> endobj 136 0 obj <>/BS<>/Subtype/Link/Rect[470.195 708.831 486.621 718.534]>> endobj 137 0 obj <>/BS<>/Subtype/Link/Rect[512.011 641.661 542.874 651.363]>> endobj 138 0 obj <>/BS<>/Subtype/Link/Rect[470.195 623.599 482.137 635.54]>> endobj 139 0 obj <>/BS<>/Subtype/Link/Rect[484.626 625.838 592.144 635.54]>> endobj 118 0 obj <>stream HVn8}Ẉ[$HJ|IvH4Qч4Lj%ѥd b+mnaX̌b͒»w$])ܹ^½ dt h; =BAp-d qި5Xd&KdPg Jhu:%a8ą32p*2` <$tQM9N1O8YڕQ`TKήl/cw r>GpZ,.^->py@|BIIV a{X>8  BCF/?u 6? NB,TV]K4\/W=7i{!ў~GՀC}Qiڋ|?@^$ k5 U0oM"M'=4a<̧ihb/1}W>C uÃm zGק8aA~yq*[C61zTEVmfc+kWxd!9OiPiljևqr~jLQ!7"M2UEbA$l-aDEՐ{=Bk{_r'J56oRuz6|RueUQyf6-XLȮ}[c%~ \'bSH({ ֦ZU eJApOMژk!t <[,Mr(r644pAVj-v~U ^3U}~X-F?dS&6{V3u%y9i9jNmQnÚ 7CD__ǖ(y[ύ v(:=#숷n\ iYH0f7ptnyap+ N O{a?-]WH*I ȑZwK<}xS:/FB endstream endobj 140 0 obj (An7V'#oM ) endobj 141 0 obj <>stream 䅦uSTV]hYnc}Ԣ͍ȹٳ됯 endstream endobj 120 0 obj <>stream HSْ 1$_dfR[cbP#u)忏l AB p^gh;:&$F 6{z\ 7pr~%<> ~.2uqysm-( +Z|<:c1/δ|e)%7AHz 7'cYi#˽E`iǼ'aXb7-%yQl-( Řwf>G0E endstream endobj 46 0 obj [/Indexed/DeviceRGB 255 103 0 R] endobj 50 0 obj <> endobj 44 0 obj [/Indexed/DeviceRGB 255 105 0 R] endobj 45 0 obj [/Indexed/DeviceRGB 255 101 0 R] endobj 122 0 obj [/Indexed/DeviceRGB 31 141 0 R] endobj 142 0 obj <> endobj 145 0 obj <> endobj 144 0 obj <>>> endobj 146 0 obj [149 0 R 149 0 R 149 0 R] endobj 147 0 obj [149 0 R 149 0 R] endobj 148 0 obj [149 0 R] endobj 150 0 obj <> endobj 151 0 obj [12 0 R/XYZ 0 670.474 null] endobj 152 0 obj [12 0 R/XYZ 0 768.029 null] endobj 18 0 obj <> endobj 153 0 obj <> endobj 197 0 obj <> endobj 198 0 obj (http://developers.sun.com/img/home/microformats.gif) endobj 175 0 obj <> endobj 199 0 obj (http://java.sun.com/) endobj 161 0 obj <> endobj 200 0 obj (http://java.sun.com/im/BL_fff.gif) endobj 160 0 obj <> endobj 201 0 obj (http://java.sun.com/im/BR_fff.gif) endobj 194 0 obj <> endobj 202 0 obj (http://java.sun.com/im/TL_fff.gif) endobj 163 0 obj <> endobj 203 0 obj (http://java.sun.com/im/TR_fff.gif) endobj 157 0 obj <> endobj 204 0 obj (http://java.sun.com/im/a2_bttn_search.gif) endobj 181 0 obj <> endobj 205 0 obj (http://java.sun.com/im/a2_corner_tr.gif) endobj 192 0 obj <> endobj 206 0 obj (http://java.sun.com/im/ar_dbl_blue.png) endobj 165 0 obj <> endobj 207 0 obj (http://java.sun.com/im/bg_dksunblue.gif) endobj 184 0 obj <> endobj 208 0 obj (http://java.sun.com/im/bg_navblue.gif) endobj 155 0 obj <> endobj 209 0 obj (http://java.sun.com/im/bg_titlebar.gif) endobj 167 0 obj <> endobj 210 0 obj (http://java.sun.com/im/generic_bl.gif) endobj 186 0 obj <> endobj 211 0 obj (http://java.sun.com/im/generic_br.gif) endobj 171 0 obj <> endobj 212 0 obj (http://java.sun.com/im/generic_tl.gif) endobj 188 0 obj <> endobj 213 0 obj (http://java.sun.com/im/generic_tr.gif) endobj 173 0 obj <> endobj 214 0 obj (http://java.sun.com/im/ic_feed_16x.gif) endobj 196 0 obj <> endobj 215 0 obj (http://java.sun.com/im/logo_sun_small_sdn.gif) endobj 158 0 obj <> endobj 216 0 obj (http://java.sun.com/im/sidenav_corners.gif) endobj 179 0 obj <> endobj 217 0 obj (http://java.sun.com/javaone/images/duke-gg.jpg) endobj 169 0 obj <> endobj 218 0 obj (http://www.sun.com/images/l2/l2_askxprt.gif) endobj 190 0 obj <> endobj 219 0 obj (http://www.sun.com/images/l2/l2_javaappsdk.gif) endobj 189 0 obj <> endobj 220 0 obj (http://www.sun.com/images/l2/l2_netbeans6.1.gif) endobj 182 0 obj <> endobj 221 0 obj (http://www.sun.com/images/l2/l2_portlets.gif) endobj 177 0 obj <> endobj 266 0 obj <> endobj 268 0 obj 1 endobj 264 0 obj <> endobj 265 0 obj 1 endobj 262 0 obj <> endobj 263 0 obj 1 endobj 260 0 obj <> endobj 261 0 obj 1 endobj 257 0 obj <> endobj 259 0 obj 1 endobj 256 0 obj <> endobj 254 0 obj <> endobj 255 0 obj 1 endobj 252 0 obj <> endobj 253 0 obj 2 endobj 250 0 obj <> endobj 248 0 obj <> endobj 246 0 obj <> endobj 244 0 obj <> endobj 243 0 obj <> endobj 242 0 obj <> endobj 240 0 obj <> endobj 239 0 obj <> endobj 238 0 obj <> endobj 180 0 obj (v|0) endobj 236 0 obj <> endobj 237 0 obj <>stream HDN0 tE &[Kʴ W h[j)wQ.Jsy}9jBR6RkNEjɠgޅYM?* endstream endobj 269 0 obj [/Indexed/DeviceRGB 63 270 0 R] endobj 270 0 obj <>stream Fi=RaC[j6QcLh~;YlEbt3M^zLnHkUuEbxFf|Hbt>]pSqE`qXxJlRnUtOp\|dPqA^rCg~VxJdyRsBbzAbwHf}EhOmKm6ShOj~Edz9Tg.EVVwQsLg{StWwUsLj՚Cd{C`rQrRrAXg endstream endobj 234 0 obj <> endobj 232 0 obj <> endobj 230 0 obj <> endobj 228 0 obj <> endobj 227 0 obj (Developer Resources for Java Technology) endobj 225 0 obj (\(nǠ) endobj 226 0 obj <> endobj 222 0 obj <> endobj 224 0 obj 1 endobj 271 0 obj <> endobj 272 0 obj [273 0 R] endobj 273 0 obj <> endobj 274 0 obj <> endobj 275 0 obj <> endobj 13 0 obj <>/Names 276 0 R/Type/Catalog/StructTreeRoot 142 0 R/SpiderInfo 271 0 R/Outlines 277 0 R/AcroForm<>/Font<>>>/DA(/Helv 0 Tf 0 g )/SigFlags 3>>/Metadata 16 0 R/PageMode/UseOutlines/Pages 18 0 R>> endobj 276 0 obj <> endobj 12 0 obj <>/Pattern<>/ColorSpace<>/Font<>>>/MediaBox[0.0 0.0 612.0 792.0]/ID 52 0 R/StructParents 0/Annots 311 0 R/Rotate 0>> endobj 311 0 obj [312 0 R 313 0 R 314 0 R 315 0 R 316 0 R 317 0 R 318 0 R 319 0 R 320 0 R 321 0 R 322 0 R 323 0 R 324 0 R 325 0 R 326 0 R 327 0 R 328 0 R 329 0 R 330 0 R 331 0 R 332 0 R 333 0 R 334 0 R 335 0 R 336 0 R 337 0 R 338 0 R 339 0 R 340 0 R 341 0 R 342 0 R 343 0 R 344 0 R 345 0 R 346 0 R 347 0 R 348 0 R 349 0 R 350 0 R 351 0 R 352 0 R 353 0 R 354 0 R 355 0 R 356 0 R 357 0 R 358 0 R 359 0 R 360 0 R 361 0 R 362 0 R 363 0 R 364 0 R 365 0 R 366 0 R 367 0 R 368 0 R 369 0 R 370 0 R 371 0 R 372 0 R 11 0 R] endobj 312 0 obj <>/BS<>/Subtype/Link/Rect[24.6293 756.195 39.2344 765.151]>> endobj 313 0 obj <>/BS<>/Subtype/Link/Rect[41.7242 756.195 59.0632 765.151]>> endobj 314 0 obj <>/BS<>/Subtype/Link/Rect[61.553 756.195 86.642 765.151]>> endobj 315 0 obj <>/BS<>/Subtype/Link/Rect[89.1318 756.195 137.028 765.151]>> endobj 316 0 obj <>/BS<>/Subtype/Link/Rect[139.517 756.195 202.018 765.151]>> endobj 317 0 obj <>/BS<>/Subtype/Link/Rect[204.508 756.195 219.565 765.151]>> endobj 318 0 obj <>/BS<>/Subtype/Link/Rect[24.6293 744.287 41.9601 753.243]>> endobj 319 0 obj <>/BS<>/Subtype/Link/Rect[26.1219 726.972 91.8164 735.928]>> endobj 320 0 obj <>/BS<>/Subtype/Link/Rect[101.176 726.972 192.435 735.928]>> endobj 321 0 obj <>/BS<>/Subtype/Link/Rect[14.9268 581.808 89.561 647.486]>> endobj 322 0 obj <>/BS<>/Subtype/Link/Rect[97.0244 635.246 273.546 646.442]>> endobj 323 0 obj <>/BS<>/Subtype/Link/Rect[97.0244 583.6 282.877 594.795]>> endobj 324 0 obj <>/BS<>/Subtype/Link/Rect[14.9268 562.404 346.477 573.599]>> endobj 325 0 obj <>/BS<>/Subtype/Link/Rect[14.9268 516.13 330.961 527.325]>> endobj 326 0 obj <>/BS<>/Subtype/Link/Rect[375.514 450.751 387.456 462.692]>> endobj 327 0 obj <>/BS<>/Subtype/Link/Rect[23.6411 415.69 85.1949 426.885]>> endobj 328 0 obj <>/BS<>/Subtype/Link/Rect[14.9268 401.658 109.582 412.853]>> endobj 329 0 obj <>/BS<>/Subtype/Link/Rect[14.9268 387.627 125.841 398.822]>> endobj 330 0 obj <>/BS<>/Subtype/Link/Rect[14.9268 373.596 127.554 384.791]>> endobj 331 0 obj <>/BS<>/Subtype/Link/Rect[14.9268 359.565 107.816 370.76]>> endobj 332 0 obj <>/BS<>/Subtype/Link/Rect[23.6411 326.129 84.0142 337.324]>> endobj 333 0 obj <>/BS<>/Subtype/Link/Rect[14.9268 312.097 72.416 323.293]>> endobj 334 0 obj <>/BS<>/Subtype/Link/Rect[14.9268 278.661 49.7735 289.856]>> endobj 335 0 obj <>/BS<>/Subtype/Link/Rect[14.9268 174.771 89.561 240.449]>> endobj 336 0 obj <>/BS<>/Subtype/Link/Rect[97.0244 208.654 366.415 219.85]>> endobj 337 0 obj <>/BS<>/Subtype/Link/Rect[14.9268 155.366 142.109 166.561]>> endobj 338 0 obj <>/BS<>/Subtype/Link/Rect[14.9268 103.719 61.3821 114.914]>> endobj 339 0 obj <>/BS<>/Subtype/Link/Rect[14.9268 70.5813 93.8987 81.7764]>> endobj 340 0 obj <>/BS<>/Subtype/Link/Rect[108.443 70.5813 205.429 81.7764]>> endobj 341 0 obj <>/BS<>/Subtype/Link/Rect[219.974 70.5813 260.63 81.7764]>> endobj 342 0 obj <>/BS<>/Subtype/Link/Rect[477.659 635.993 516.57 647.188]>> endobj 343 0 obj <>/BS<>/Subtype/Link/Rect[477.659 621.962 549.672 633.157]>> endobj 344 0 obj <>/BS<>/Subtype/Link/Rect[477.659 607.93 518.304 619.125]>> endobj 345 0 obj <>/BS<>/Subtype/Link/Rect[477.659 593.899 543.862 605.094]>> endobj 346 0 obj <>/BS<>/Subtype/Link/Rect[477.659 579.868 512.495 591.063]>> endobj 347 0 obj <>/BS<>/Subtype/Link/Rect[477.659 565.837 542.107 577.032]>> endobj 348 0 obj <>/BS<>/Subtype/Link/Rect[477.659 551.805 510.76 563.001]>> endobj 349 0 obj <>/BS<>/Subtype/Link/Rect[477.659 511.055 516.57 522.25]>> endobj 350 0 obj <>/BS<>/Subtype/Link/Rect[477.659 497.024 516.57 508.219]>> endobj 351 0 obj <>/BS<>/Subtype/Link/Rect[477.659 482.993 518.304 494.188]>> endobj 352 0 obj <>/BS<>/Subtype/Link/Rect[477.659 468.962 513.08 480.157]>> endobj 353 0 obj <>/BS<>/Subtype/Link/Rect[477.659 454.93 542.107 466.125]>> endobj 354 0 obj <>/BS<>/Subtype/Link/Rect[477.659 440.899 510.76 452.094]>> endobj 355 0 obj <>/BS<>/Subtype/Link/Rect[477.659 400.149 582.773 411.344]>> endobj 356 0 obj <>/BS<>/Subtype/Link/Rect[477.659 386.118 499.726 397.313]>> endobj 357 0 obj <>/BS<>/Subtype/Link/Rect[477.659 372.086 547.927 383.282]>> endobj 358 0 obj <>/BS<>/Subtype/Link/Rect[477.659 358.055 517.719 369.25]>> endobj 359 0 obj <>/BS<>/Subtype/Link/Rect[477.659 344.024 509.6 355.219]>> endobj 360 0 obj <>/BS<>/Subtype/Link/Rect[477.659 329.993 565.345 341.188]>> endobj 361 0 obj <>/BS<>/Subtype/Link/Rect[477.659 315.962 569.42 327.157]>> endobj 362 0 obj <>/BS<>/Subtype/Link/Rect[477.659 301.93 565.919 313.125]>> endobj 363 0 obj <>/BS<>/Subtype/Link/Rect[477.659 287.899 543.872 299.094]>> endobj 364 0 obj <>/BS<>/Subtype/Link/Rect[477.659 273.868 549.086 285.063]>> endobj 365 0 obj <>/BS<>/Subtype/Link/Rect[477.659 259.837 579.273 271.032]>> endobj 366 0 obj <>/BS<>/Subtype/Link/Rect[477.659 245.805 524.678 257.001]>> endobj 367 0 obj <>/BS<>/Subtype/Link/Rect[556.883 207.742 568.824 219.684]>> endobj 368 0 obj <>/BS<>/Subtype/Link/Rect[484.88 134.005 580.675 145.2]>> endobj 369 0 obj <>/BS<>/Subtype/Link/Rect[476.166 119.974 525.526 131.169]>> endobj 370 0 obj <>/BS<>/Subtype/Link/Rect[476.166 101.465 561.522 112.66]>> endobj 371 0 obj <>/BS<>/Subtype/Link/Rect[485.122 45.0411 530.417 56.2362]>> endobj 372 0 obj <>/BS<>/Subtype/Link/Rect[-1485.22 755.939 -1423.99 765.641]/PA<>>> endobj 51 0 obj <> endobj 47 0 obj [/Pattern/DeviceRGB] endobj 121 0 obj [/Indexed/DeviceRGB 63 374 0 R] endobj 310 0 obj [/Indexed/DeviceRGB 255 375 0 R] endobj 309 0 obj [/Indexed/DeviceRGB 255 376 0 R] endobj 373 0 obj <> endobj 278 0 obj <>stream HĔk@ WqTA)i7H;CJ޼;G˺ _Y!izs[~`Z>ע !}Z\juP@eQ9AVcTV.Q^J8RK4EeQ_Q%w>stream HMKA+룫À@!Y4 uS= a;2PG[,HX9爥VHȬq}n_"P#M|\6p|}{{ [+(R*ȶD\h~f$sv.K2FQ@2!4j1Pc0ATGD^j@&NFX=AwQ&gT=Vm4Blm@xR3iRLual䲂F57gq|gM0ʄJ,#DvZ mţw8_;F:a)zZ*3&6C){{7L>` -LH76ګ/`o}Nc> endobj 377 0 obj <> endobj 280 0 obj <>stream HԻjA~)ι̹1DNpRa4 oV4c qs9}vyq6_gwW0fW)&[( 9HH |?>;P0a{.~ OqPuR0\-|3#zp,zAJJ^j:k%:`ؚVx5+ĆʁyOnL*!fXГKk0`SjNdeA'*ّԲ+KEMV]Edar#&$WXJ1NPF$ ͗FmZ)۾WeWˊ̍(\r6'i: ը ȫ#Q/I %hb4)QM$R+n:w"a,>.? } endstream endobj 48 0 obj <> endobj 378 0 obj <> endobj 281 0 obj <>stream HTMO0G?i ڎ8B t?^LBVi\~'iK\,GμGpu߇=zY3 |y (0 qo($()$ $@Nc8W.q0B HfAgT?">Ia5  6D\[0xeL y#RgrVD d;}7EVe; #By$?ϰbE{߿h04uuQ)'{ yp벢rFb]Ff`abED Êa6~`6wsKv3 -`w:JM ',?"#"Ta2[8|5Bh㈌FuAR7[Sդ=DE8 -AR:$.V'F6o ^[yH1()yN ҷBSm U[lf+ 5 &ZT7 fDSjw: z73 hw ;_t:S *:{[7 47NlŬIW8)EL"UmrwF&pM >HK[«1G@MaIqNZJ#5TXnM+;CI,#Im endstream endobj 282 0 obj <>stream HUO0~pn"&N&eO@mФ-'.۪wZ P[7v}܁OٝE3 feoYJ V@)\,b"(FҊnTcKZk)#BtIƐ-E\qL$NmT, B!n{>jWF3{}>2":/H庴pIlCky Nhp6_`l[ 4Xjs}GN wFVcB/p-/( YxԊw*DaR|+a 'p>[C*pٔN0p]…p/[t J=KnDaw*Zjcz/n_WIuAVe:]6QÝƆ쾑62T6KK 3CC5Pj#IFy%)a#Am#H$֛x?p-Mz|BaXio)l$yxu^39ΞnճU&F1>stream HTn0 ? jH-,.)FE.0m+D_!e9Z͛7 5]0J Y$ "1 ܎{3³ꀱp&Sc % q=[K~N"$r"3dH;x<]LtyO QǒGȱ9*OӞn)HB3ygay) yB'0goTRSQ0>) U+#6} F#"Rè 4e0,LC CٵRpRNe q0XH`>stream HTo0~篸t?llRSmn{ 7a! 4J-RUMwq]&p$X.P/,lx #kUJs d$7~Rz0 mT;݀0DR ~ۥ>"A8d^]BCJRJ>=I8 ~ǭuc]Op]p, o`q~h{Rb%@ތ׵/zhC6RpVpVEVffX:(/+-R7r^iX\Uc:}z1Bhl9[mTYU ɺjbl s}d:?Y'7`!s0 `w=Xʴa?C|nRHiݏq _^ y /U;S骁Cr~QQo< س1Y3=LljQWU_j:+Ԋ3 endstream endobj 119 0 obj <>stream H,r0$A J96h j[mogvvG.UJaF 2֥4/}g*M"'djGWi\0sX-( XXzmR_D}.`|µ^*y8{g֢{rvĞ=EzDK,I}rCQ@xfhjmnNjCU endstream endobj 285 0 obj <>stream HTN0}WSNع^hժ}ܬ$NBo`*HE|ۙsa>stream Hb`ޅSbyW*iC|'{rrArLuW endstream endobj 380 0 obj <>stream H|j9o ) endstream endobj 112 0 obj <>]/BitsPerComponent 8/Width 6/ID 164 0 R/Length 27/Height 10/Filter/FlateDecode/Mask 380 0 R>>stream H:. #B B { endstream endobj 154 0 obj (DB2bQ&Y) endobj 381 0 obj <>stream endstream endobj 113 0 obj <>stream Hb`&`*#0؈xyC $ر~T &K endstream endobj 178 0 obj (k]#"ID2ww) endobj 383 0 obj <>stream endstream endobj 384 0 obj [/Indexed/DeviceRGB 3 383 0 R] endobj 114 0 obj <>stream H1 '7Y 4/hjྐƘѫ5Dj;5$Q[oI#*D4T pOz}H#8 sIO#a endstream endobj 166 0 obj (9MX$O) endobj 385 0 obj <>stream H2*6,\U:"$}iDˢ%Au+6s/qMN,`lUhQ`[f[X 螶r[lUOpAKhIe,cJ#[Ǵ/ P3˧bjxj>׼.:V&re $ &? endstream endobj 386 0 obj [/Indexed/DeviceRGB 63 385 0 R] endobj 115 0 obj <>stream HWks8L*$Jl꒪hmv$)oWD,3Aj˗4{Y:ֱuwϯucX:~ׯXɵM٫՝܅9jzJЫt1\]@ncZ#ge,4W. ѼF |򟯗X:ֱu~˿?/oq3ۥ5_p8  Y YLXWV_ܽҫ/w՞tw@la=+tH!5 v9-]_߬cX:[oSc.{<M$!9 $bMg_k0Kk.ηzs9tXvy_PM^e[]@YXڏh9\.ױucDzߨx,5~X(7? -C| ڤ%^TWe/M/Wوj+u  v"^&xn jMH"v݊nj0JkV]QB?o0:a0er6 HB(ʔ}d/}z|z'yOO$ݼ~EWGAYڐ_n)x-cJ3vu F  \QܩqF/\ID ɰJ ;qF͈=G{g*Q6uR%*ʍ=,_>pK tn%XOc\|,n-x(}K@#`;O1l+zhSUbĀJag pD`S$+ I> X 8JC7EJC쳴ddʂЩ.Vۢʠk9ϰo $;Ԉф,uQԗs?5LNv')j΁>Q=GFlhmZ;Z3?N7UY;fM WqEBO]KT-,vLf J&id ]+K.K2W.:ld8X@NHmڊR86@+PuPFKb`Xk(Z_"S4Uks8Gxder6wd jgvy_vfݼIib"2u0FEK=rO l[.;ټ 9!Y{ͨqi풝9^뽵ӛ6gxo',=NQ?βI~xek;*Y^&3?ndI;'!5o݃=D[ /).:4~N_\Kv/(Ds^U ]S)SqP)2FNXL/la=: $E$!MLTEea]\ء쒶ҕ'Tʻ 32f%BL/EOŘ>O<&MӦJDA$@1] qc6N ѐ@zTvАH )-nO= V0U"لs HMގ|`){c KD-|2.!a4EM:G/("maLuqaG>_ =t>yf&)Ky9ffMyloV9\uc38EsB'j}OpǥXC$,+h.@ ?Tg>3ٙQ4,2D4TVKDDL4)U\' ,lM&֣qx#7nyY9  iZ`h.u3)KÞ~sX)H\J1 l$4Xu`鷄&gB2tOL^̦"hKh0 JSMnvO56wVtNV)KCŶ7tOʥ]lHVrN Vn *kRI1IBf[ }$z3 1qqrnAjEI .z-)B j-\m&l`)0ߵz:;7J:ip6QAs,怀HɠjX٤z"" ib** >gK)>KƜy9sb_|!0*M[xzBzns8#Eh*: C]$~4W yEXM'hs"s1SMy]n^6H0`I{]\:r!s9uI`4 wNm<ܒmRʸvɶn͟jf$޽_ + $Clp;;4pq X#|]IX)\6r3Qn<}GBeQ^3=*z]$N =&Y>dUQYn%:ۛLucX5v}</[ jDCs@@44Z\X[<k- g _gRw)"&& 2GvRHګH^y?aFƜY9=I*>]z{BS4hb *NEMߤtIכcp n2*oѐ:^@$HdPA5X \N5 HBg1qPuqaGڥ ɫf9DY͎76eғNcfӼFdԍ&.^_:T\g8: @3#^D̮HDIX(ŴDOưmxLf qˈJda=}A@4Q9J$^|s/_|uhL 2%;2i ,J Q8Qi[]h0&nӎ LG<'3[$_5v;࿜LhaKnuF<"`]ȌuRxvRcХߙ+wϗ,?܎_uR˥^ƇChCN1kE$bI|;H2Kpפqc1TPy9` 5Ϥn~ @@ F]%A.+sjKpHvzS2Y\B6̬ JԧM|WS핻kir,ԒZ(LP֤J] $ɐ6aD1=@ Dc-2(Å`US핻Ѳ:T[U{s/7w0ANHzˀ@xĆ#}ތl*' * uȐ6,E4GfمFezXA 6$wQM| t 5 v 7nv~3,x1p~& 7vGT̛~Ls'϶ٽg!=Dp endstream endobj 191 0 obj (`\b'X_%ņ) endobj 387 0 obj <>stream 8Yp]z6Xp§SpCby7Zq7Zs]x;^vUt endstream endobj 388 0 obj [/Indexed/DeviceRGB 15 387 0 R] endobj 116 0 obj <>stream H4Ʒ A0nfAnZ*;Œ'[S endstream endobj 195 0 obj (88Pkg;) endobj 374 0 obj <>stream z157„Ùt0u/}2l.dE:6C59vc,yFx1hg^ڵp1n/4갇843^*32{2׿RLsjΧ~9FԾӳPRi[B endstream endobj 382 0 obj [/Indexed/DeviceRGB 15 381 0 R] endobj 168 0 obj (<~K\r\)J) endobj 258 0 obj <>stream JFIFHH"ExifMM*bj(1r2iHHAdobe Photoshop CS Macintosh2008:05:06 15:09:58dX&(. HHJFIFHH Adobe_CMAdobed            Xd"?   3!1AQa"q2B#$Rb34rC%Scs5&DTdE£t6UeuF'Vfv7GWgw5!1AQaq"2B#R3$brCScs4%&5DTdEU6teuFVfv'7GWgw ?G43c"oko؎ r~[>i]]>ViD*lrHuYHяg&]a ͘2݀;IwtV2;;f3 OdYguniʳà5;00{[XѮzyr 0:ɟ,G9&q) #ǰ:61c֊ ѳ.7V3f3 cڑ8d2Gj7ſsc@\nFV/ԇ5GuO[ jq cxcKJƏZα>E8~Yye9(8zEwOsgJkMP?yENo~),O$.wMˬM;"ekKF~=:[cCehDz#iIe}Tʻ'RD!DvM jT[uz:v!sMj`p%^{( *)^}LڀpI-0G.[GG.]f[lv!?{}Iخ˝kcZ.hwlMrl Tc|z~!(QN/oҬ[cwp{]^|Miul{l! \AsWc?R\3rd.bc36k}w=?TzP~O毫r k?OM1lgkT1JɖGJLiIVGJM|]S5$?IZRϪX:Gx k/׶-W[?Y\,{d<>4.^[^^5cϭ6T?szt*;'aGtÍqյH_䮿Sslw{yiE!i0y{ Y][ (k:M {l_nz}i7I =c:G?8=;jcp֒tc]3GƅP&'IgA3X0ͺel;[CZKgcѴ#~ba<%Éo1Ŋ;)zM_u2kJOV#$ %EV?cz~{ai'z,̻k58h2oϯ7쏶^88}&n=}Xhv-J~vzn^vaqꝙOfn..]]35溪v6P?Gи2+w-sԟQH#qu8s}ﻨ=r}:Ϳۭw?Vz)=\%k\`ahhK>] dǻ jkhCS' 1/'/nv=.^X$_guGd{{:1v5#Jg)kCc_|ltAZ^}99\S\4Ýo5z>'Xs,p פIifc |jM5el4| hJFD_:ٞ12\O{~vWet[[ys|9yza7vkVgLgTh!h>XzD֝uߠzH??J[߻vRNF}D'aL!䉭I[U_jXn[͡ g[WUtиT[GHXYsMPy%ic~JuU_N7cR~{X˽ ~qx*Hx[O{2viAREcRKTSRe_0s_QPnx,UȾթc78Cg$FѷI|:BPhotoshop 3.08BIM8BIM%F &Vڰw8BIM com.apple.print.PageFormat.PMHorizontalRes com.apple.print.ticket.creator com.apple.printingmanager com.apple.print.ticket.itemArray com.apple.print.PageFormat.PMHorizontalRes 72 com.apple.print.ticket.client com.apple.printingmanager com.apple.print.ticket.modDate 2006-06-05T20:33:24Z com.apple.print.ticket.stateFlag 0 com.apple.print.PageFormat.PMOrientation com.apple.print.ticket.creator com.apple.printingmanager com.apple.print.ticket.itemArray com.apple.print.PageFormat.PMOrientation 1 com.apple.print.ticket.client com.apple.printingmanager com.apple.print.ticket.modDate 2006-06-05T20:33:24Z com.apple.print.ticket.stateFlag 0 com.apple.print.PageFormat.PMScaling com.apple.print.ticket.creator com.apple.printingmanager com.apple.print.ticket.itemArray com.apple.print.PageFormat.PMScaling 1 com.apple.print.ticket.client com.apple.printingmanager com.apple.print.ticket.modDate 2006-06-05T20:33:24Z com.apple.print.ticket.stateFlag 0 com.apple.print.PageFormat.PMVerticalRes com.apple.print.ticket.creator com.apple.printingmanager com.apple.print.ticket.itemArray com.apple.print.PageFormat.PMVerticalRes 72 com.apple.print.ticket.client com.apple.printingmanager com.apple.print.ticket.modDate 2006-06-05T20:33:24Z com.apple.print.ticket.stateFlag 0 com.apple.print.PageFormat.PMVerticalScaling com.apple.print.ticket.creator com.apple.printingmanager com.apple.print.ticket.itemArray com.apple.print.PageFormat.PMVerticalScaling 1 com.apple.print.ticket.client com.apple.printingmanager com.apple.print.ticket.modDate 2006-06-05T20:33:24Z com.apple.print.ticket.stateFlag 0 com.apple.print.subTicket.paper_info_ticket com.apple.print.PageFormat.PMAdjustedPageRect com.apple.print.ticket.creator com.apple.printingmanager com.apple.print.ticket.itemArray com.apple.print.PageFormat.PMAdjustedPageRect 0.0 0.0 734 576 com.apple.print.ticket.client com.apple.printingmanager com.apple.print.ticket.modDate 2008-05-06T22:05:30Z com.apple.print.ticket.stateFlag 0 com.apple.print.PageFormat.PMAdjustedPaperRect com.apple.print.ticket.creator com.apple.printingmanager com.apple.print.ticket.itemArray com.apple.print.PageFormat.PMAdjustedPaperRect -18 -18 774 594 com.apple.print.ticket.client com.apple.printingmanager com.apple.print.ticket.modDate 2008-05-06T22:05:30Z com.apple.print.ticket.stateFlag 0 com.apple.print.PaperInfo.PMPaperName com.apple.print.ticket.creator com.apple.print.pm.PostScript com.apple.print.ticket.itemArray com.apple.print.PaperInfo.PMPaperName na-letter com.apple.print.ticket.client com.apple.print.pm.PostScript com.apple.print.ticket.modDate 2003-07-01T17:49:36Z com.apple.print.ticket.stateFlag 1 com.apple.print.PaperInfo.PMUnadjustedPageRect com.apple.print.ticket.creator com.apple.print.pm.PostScript com.apple.print.ticket.itemArray com.apple.print.PaperInfo.PMUnadjustedPageRect 0.0 0.0 734 576 com.apple.print.ticket.client com.apple.printingmanager com.apple.print.ticket.modDate 2006-06-05T20:33:24Z com.apple.print.ticket.stateFlag 0 com.apple.print.PaperInfo.PMUnadjustedPaperRect com.apple.print.ticket.creator com.apple.print.pm.PostScript com.apple.print.ticket.itemArray com.apple.print.PaperInfo.PMUnadjustedPaperRect -18 -18 774 594 com.apple.print.ticket.client com.apple.printingmanager com.apple.print.ticket.modDate 2006-06-05T20:33:24Z com.apple.print.ticket.stateFlag 0 com.apple.print.PaperInfo.ppd.PMPaperName com.apple.print.ticket.creator com.apple.print.pm.PostScript com.apple.print.ticket.itemArray com.apple.print.PaperInfo.ppd.PMPaperName US Letter com.apple.print.ticket.client com.apple.print.pm.PostScript com.apple.print.ticket.modDate 2003-07-01T17:49:36Z com.apple.print.ticket.stateFlag 1 com.apple.print.ticket.APIVersion 00.20 com.apple.print.ticket.privateLock com.apple.print.ticket.type com.apple.print.PaperInfoTicket com.apple.print.ticket.APIVersion 00.20 com.apple.print.ticket.privateLock com.apple.print.ticket.type com.apple.print.PageFormatTicket 8BIMxHH@Rg(HH(dh 8BIMHH8BIM&?8BIM 8BIM8BIM 8BIM 8BIM' 8BIMH/fflff/ff2Z5-8BIMp8BIM8BIM8BIM@@8BIM8BIMnullbaseNameTEXTUserboundsObjcRct1Top longLeftlongBtomlongXRghtlongdslicesVlLsObjcslicesliceIDlonggroupIDlongoriginenum ESliceOrigin autoGeneratedTypeenum ESliceTypeImg boundsObjcRct1Top longLeftlongBtomlongXRghtlongdurlTEXTnullTEXTMsgeTEXTaltTagTEXTcellTextIsHTMLboolcellTextTEXT horzAlignenumESliceHorzAligndefault vertAlignenumESliceVertAligndefault bgColorTypeenumESliceBGColorTypeNone topOutsetlong leftOutsetlong bottomOutsetlong rightOutsetlong8BIM( ?8BIM#8BIM dX,g JFIFHH Adobe_CMAdobed            Xd"?   3!1AQa"q2B#$Rb34rC%Scs5&DTdE£t6UeuF'Vfv7GWgw5!1AQaq"2B#R3$brCScs4%&5DTdEU6teuFVfv'7GWgw ?G43c"oko؎ r~[>i]]>ViD*lrHuYHяg&]a ͘2݀;IwtV2;;f3 OdYguniʳà5;00{[XѮzyr 0:ɟ,G9&q) #ǰ:61c֊ ѳ.7V3f3 cڑ8d2Gj7ſsc@\nFV/ԇ5GuO[ jq cxcKJƏZα>E8~Yye9(8zEwOsgJkMP?yENo~),O$.wMˬM;"ekKF~=:[cCehDz#iIe}Tʻ'RD!DvM jT[uz:v!sMj`p%^{( *)^}LڀpI-0G.[GG.]f[lv!?{}Iخ˝kcZ.hwlMrl Tc|z~!(QN/oҬ[cwp{]^|Miul{l! \AsWc?R\3rd.bc36k}w=?TzP~O毫r k?OM1lgkT1JɖGJLiIVGJM|]S5$?IZRϪX:Gx k/׶-W[?Y\,{d<>4.^[^^5cϭ6T?szt*;'aGtÍqյH_䮿Sslw{yiE!i0y{ Y][ (k:M {l_nz}i7I =c:G?8=;jcp֒tc]3GƅP&'IgA3X0ͺel;[CZKgcѴ#~ba<%Éo1Ŋ;)zM_u2kJOV#$ %EV?cz~{ai'z,̻k58h2oϯ7쏶^88}&n=}Xhv-J~vzn^vaqꝙOfn..]]35溪v6P?Gи2+w-sԟQH#qu8s}ﻨ=r}:Ϳۭw?Vz)=\%k\`ahhK>] dǻ jkhCS' 1/'/nv=.^X$_guGd{{:1v5#Jg)kCc_|ltAZ^}99\S\4Ýo5z>'Xs,p פIifc |jM5el4| hJFD_:ٞ12\O{~vWet[[ys|9yza7vkVgLgTh!h>XzD֝uߠzH??J[߻vRNF}D'aL!䉭I[U_jXn[͡ g[WUtиT[GHXYsMPy%ic~JuU_N7cR~{X˽ ~qx*Hx[O{2viAREcRKTSRe_0s_QPnx,UȾթc78Cg$FѷI|:8BIM!SAdobe PhotoshopAdobe Photoshop CS8BIMmoptdlTargetSettingsClrTObjc ColorTableClrsVlLsisExactboolMttCObjc NativeQuadBl longGrn longRd longTrnsbool addMetadatabool autoReduceboolcolorTableControlObjcColorTableControl lockedColorsVlLs shiftEntriesVlLsditherAlgorithmenumDitherAlgorithmDfsn ditherPercentlongd fileFormatenum FileFormatGIF interlacedboollossylong noMatteColorbool numColorslongreductionAlgorithmenumReductionAlgorithmAdptrolloverMasterPalettebooltransparencyDitherAlgorithmenumDitherAlgorithmNonetransparencyDitherAmountlongdwebShiftPercentlong zonedDitherObjc ZonedInfo channelIDlong emphasizeTextboolemphasizeVectorsboolfloorlongzonedHistogramWeightObjc ZonedInfo channelIDlong emphasizeTextboolemphasizeVectorsboolfloorlong zonedLossyObjc ZonedInfo channelIDlong emphasizeTextboolemphasizeVectorsboolfloorlong8BIMmsetnullHTMLBackgroundSettingsObjcnullBackgroundColorBluelongBackgroundColorGreenlongBackgroundColorRedlongBackgroundColorStatelongBackgroundImagePathTEXTUseImageAsBackgroundbool HTMLSettingsObjcnullAlwaysAddAltAttributebool AttributeCaselong CloseAllTagsboolEncodinglongEscapeDoubleByteURLCharsboolFileSavingSettingsObjcnull CopyBackgroundboolDuplicateFileNameBehaviorlongHtmlFileNameComponentsVlLslonglonglonglonglonglongImageSubfolderNameTEXTimages IncludeXMPboolNameCompatibilityObjcnull NameCompatMacboolNameCompatUNIXboolNameCompatWindowsboolOutputMultipleFilesboolSavingFileNameComponentsVlLs longlonglonglonglonglonglonglonglongSliceFileNameComponentsVlLslonglonglonglonglonglongUseImageSubfolderboolUseLongExtensionsboolGoLiveCompatibleboolImageMapLocationlong ImageMapTypelongIncludeCommentsboolIncludeZeroMarginsboolIndentlong LineEndingslong OutputXHTMLboolQuoteAllAttributesboolSpacersEmptyCellslongSpacersHorizontallongSpacersVerticallong StylesFormatlong TDWidthHeightlongTagCaselongUseCSSboolUseLongHTMLExtensionboolMetadataOutputSettingsObjcnull AddCustomIRboolAddEXIFboolAddXMPboolAddXMPSourceFileURIboolWriteMinimalXMPboolWriteXMPToSidecarFilesboolVersionlong8BIMms4w8BIM maniIRFR8BIMAnDsnullAFStlongFrInVlLsObjcnullFrIDlong[7FrGAdoub@`FStsVlLsObjcnullFsIDlongAFrmlongFsFrVlLslong[7LCntlong8BIMRoll8BIMmfri8BIM .xQQffff ..?EEffEffEQEQE .x?R.R.RRR R8BIMhttp://ns.adobe.com/xap/1.0/ 100 88 1 36864,40960,40961,37121,37122,40962,40963,37510,40964,36867,36868,33434,33437,34850,34852,34855,34856,37377,37378,37379,37380,37381,37382,37383,37384,37385,37386,37396,41483,41484,41486,41487,41488,41492,41493,41495,41728,41729,41730,41985,41986,41987,41988,41989,41990,41991,41992,41993,41994,41995,41996,42016,0,2,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,20,22,23,24,25,26,27,28,30;1950A5014F75F62F291450C54C033A8D 3 1 72/1 72/1 2 256,257,258,259,262,274,277,284,530,531,282,283,296,301,318,319,529,532,306,270,271,272,305,315,33432;B878EC2C42A5FEA26B4FB40DA745C253 2008-05-06T15:09:58-07:00 2008-05-06T15:09:58-07:00 2008-05-06T15:09:58-07:00 Adobe Photoshop CS Macintosh uuid:7C498E4B669B11DB9C7998478B319BFE uuid:C6F5DA9FF50C11DA9669E12E156B7522 uuid:1529C6C8FD0811DAA32BAA9DC9133E4C adobe:docid:photoshop:39cc216e-1d10-11dd-92d9-c224800627e7 image/jpeg XICC_PROFILE HLinomntrRGB XYZ  1acspMSFTIEC sRGB-HP cprtP3desclwtptbkptrXYZgXYZ,bXYZ@dmndTpdmddvuedLview$lumimeas $tech0 rTRC< gTRC< bTRC< textCopyright (c) 1998 Hewlett-Packard CompanydescsRGB IEC61966-2.1sRGB IEC61966-2.1XYZ QXYZ XYZ o8XYZ bXYZ $descIEC http://www.iec.chIEC http://www.iec.chdesc.IEC 61966-2.1 Default RGB colour space - sRGB.IEC 61966-2.1 Default RGB colour space - sRGBdesc,Reference Viewing Condition in IEC61966-2.1,Reference Viewing Condition in IEC61966-2.1view_. \XYZ L VPWmeassig CRT curv #(-27;@EJOTY^chmrw| %+28>ELRY`gnu| &/8AKT]gqz !-8COZfr~ -;HUcq~ +:IXgw'7HYj{+=Oat 2FZn  % : O d y  ' = T j " 9 Q i  * C \ u & @ Z t .Id %A^z &Ca~1Om&Ed#Cc'Ij4Vx&IlAe@e Ek*Qw;c*R{Gp@j>i  A l !!H!u!!!"'"U"""# #8#f###$$M$|$$% %8%h%%%&'&W&&&''I'z''( (?(q(())8)k))**5*h**++6+i++,,9,n,,- -A-v--..L.../$/Z///050l0011J1112*2c223 3F3334+4e4455M555676r667$7`7788P8899B999:6:t::;-;k;;<' >`>>?!?a??@#@d@@A)AjAAB0BrBBC:C}CDDGDDEEUEEF"FgFFG5G{GHHKHHIIcIIJ7J}JK KSKKL*LrLMMJMMN%NnNOOIOOP'PqPQQPQQR1R|RSS_SSTBTTU(UuUVV\VVWDWWX/X}XYYiYZZVZZ[E[[\5\\]']x]^^l^__a_``W``aOaabIbbcCccd@dde=eef=ffg=ggh?hhiCiijHjjkOkklWlmm`mnnknooxop+ppq:qqrKrss]sttptu(uuv>vvwVwxxnxy*yyzFz{{c{|!||}A}~~b~#G k͂0WGrׇ;iΉ3dʋ0cʍ1fΏ6n֑?zM _ɖ4 uL$h՛BdҞ@iءG&vVǥ8nRĩ7u\ЭD-u`ֲK³8%yhYѹJº;.! zpg_XQKFAǿ=ȼ:ɹ8ʷ6˶5̵5͵6ζ7ϸ9к<Ѿ?DINU\dlvۀ܊ݖޢ)߯6DScs 2F[p(@Xr4Pm8Ww)KmAdobed@Xd      u!"1A2# QBa$3Rqb%C&4r 5'S6DTsEF7Gc(UVWdte)8fu*9:HIJXYZghijvwxyzm!1"AQ2aqB#Rb3 $Cr4%ScD&5T6Ed' sFtUeuV7)(GWf8vgwHXhx9IYiy*:JZjz ?'qS6]m|:Z籲VCs-XcTXD'c<0 yJ ~pdh%r+Uǥr|No6!<]/aM~tR4Mz[CJ#0c3Mǹ@VGJcQ4n<+O n]ѐU^Yd8 Ёb YJ>-`">[0O{%R#&)uz~DZDXW[opb<#cfՂ JL[v6* UI;*>>bro*i1n4"i#4}*t debT)"4' z_QvWvg\uGoWGU d 2G*:0abMsM̯x/ /o_cq|@N댎in<>kgb1W ~,ۇuᰵC%-DEoNHs+l2n0o6vnmDIbFn"GUe:p# ?m}9cۮyvYH50@cE5;wUAu tqFwR.^q_[z#dڂʚIor}7k{vKzAϣ.fWɯUx̦+v#Z]Bƭ4 ؼ>. JQd[ wI^${#˸ '_n@8-?+ )ikpMgq`FʩM%B?$gk,NpdKI^a 0pT{sݴ$~hD,ʁ!&JkQC#c} ˓7WmWG$Rϥ2!&bgϒC.f?ky3ʺl'1GfD2GUcf[(Zsoc&jU'&*-=K0m!]'ߙvOefX0W>7cb^+ޢ,V8V_%wE2?ʅm+pi"32v]hp?, f" PEV4RzgGIjn͠KDfY"MR#NQme|NZ~p;_X5vw|moNFmSkg_Ux_ˇѵ߳;m5N;~Rm9Z݋ٛ_n䒒E7JfsoxguEG)o/^qyr3ҟ=%>bwV>hg_, Ec9Fe~}K:~}ƅK$Ԧ:Q#gA~Pf\_o:Iumj mŷ7N1xK =6\xrU^镺)w{cm}tlTPPQ=D=5hmձs`̫ak>Sm%ź"^*'>>~M֐k !"N\~|Oi>&-_bbqepUE_EM==V#-dXr=ɛ7\k,랶U ӨtܻXu7]HíNC+)"Qm27ŝ߳6vmMmC=:Sߊ9ZʸhSCL6e3T4pgaz}z;e[K7X&CHbF$ *)9?.{I_/}4 "(:i@u3*y.<؟q?9)[v5LQei"K2@"o,)k41Sk5bj%7P߄!#3x2IsF>= n)D%#H:C" /Wur"b?[o2S T0+6#1d / $IRk؋@M f]ŋˮ{ԕ9 v2=ʜuf FKwXǕsrXbPM d ^}&w 4>tX_)z ey:rT[+UwQSy)ih+f:'ݎ`pmZ;y5j%h3B Vp沺-ǨP|jJ?k<^S}P{qO8,2ۃib35Thڕ4/[IQ3MLĞ$/w;幋/#Yd+8E T!dQzuy6ck}oJ)g.*IEK->vV!=Ve7X賛cpW^aM":YA1'~r|'+It~)I<@UՈ tV /<3*sVR~xPx p* O['t+Mtv>؛y?pmmW;Ӹ<8ܵVX-"FJɱ0{nDU6tULYP> #tP#Y++Qy+Tt=ky9dHȎ/B}<8d FM@l-96g^uX^om.E Oۖ8>Ž ?N=ZO+QVm7σzza /?]u 4ꚘYnق_C=A5Uknݵ6$PPI?Wͼfyy"R"@MB̶6}]9RHɧâ+)JSxεiE}Htb=4I<ȭAKU*:K["߁7+mf$e=UЂ1= {,VJUd>[~]ks;%]GS3}ԘZJ/9\mED(>Jy5V\|ͶIl; {˩v80 ~9evf Eĸѿy;fѝC[:>&uBapuq6es}m1?c }I%.Qm(um={c77{Ac2UVR 1̕YhGJR{m =`1 kE kXʐ|m-)V*HLqX@§2ztO@)ܵ<-KV_.Hޟ-kPl͵-S =5Y2QsQ[_4dyk[&(cC_XXn`e-ᾱd@0MR֝FC[X9orI9Yd#RDTB5F.aߟ՟¿67W/wg5|{4:>OMTˠ^<  i->><7 YE|u۸i%Z jY?u7&hFCo_ә0ZkƧ5_gP>ǟp0_5Y~Nk7>-}}a~۵X*gZPʆG x-u4`'BP.p|7Zb(3_S2,KQe,X&ߓsgJaGuz ~Om:/">?lߐm:wlY 8[nh MR%`x"/X5åEտ3R9%\N:͏^Byaoᙢ u0ȭ)?O XS6 3f0{Wi*|S.E[#WIH=d&i,IW9s71&*0Hjq=J<(rųW+Y  TBWe~?;3U{6]I7/ ^2)OUsOQM餅Pi*Nc>~մr.|l :&!GVumwMǝy@w xQM_ϪQz|۲o~ڤLbmlV=dPUbqekD\]<1ԳF,2-0 R"#V%HalVS4 IĠӤ`. >ʓcmG;ꍛ쾷EJdE5uߡEGϥ.7!Y9~rxp랚IJǯڎEI;1ͲyXUoH>3׿|f= M7Usr_ϯ>(WK>U=Btp*MtTX1zM6O a*CO>4K$,NO=^l5\EkS R+YI`P7:$VE5ȃ=L*<#ߟi$>]) jRjW iڼO(*'[j~B(4[#GuY-d pP2W9oV)WY*ozd7gft=ܾͣSьܕ~6zlfݯV#UURX{2,nG: o$q|ܯ.Hm`1Ҫ<*I'תpIa.+v?}<1@v._._}+_OɴsžR_K,=E%T:m]>OSVQ M46˪U[4w4^>?K _O*v0h+7-&F TV#4< =o^CcwEO 'RY4-:ii`Υ߽m JE=WqQWRܔe\f+!O,EѫkQҫ6 *(VGz ?x~F/e7'WjSm[C%[[}Mܛ6i6{[vV>x}+Ǧ7;_5G"i蒻'hY%3 r4[$1EljT}jjOrNٟz{&$mt^.SkAߔ,[G㛷d=rr]o%|DR%rcެC{Gsƅi8zO|ee=П +~)t++7?\zqrNj]oU+; ; P:⪅)ڥJvyrN<}zPM?n: D: =娩j;TWk5U-UMed$;31$}2nswxwQT%UG??_Fr?r-[29#IcY%b>&y$cSFK!A"hXKb [aͶ6ܣXosby ) ָy={mUf>oU3̪ZFJ$g8{PgKfv:+}+N}乖2GP5-}t7B8nܥ7͏aM62cY@V%ԼX{=o+fWv\ϋuYHwFD^|~zlXz%")Xgm}k:lW ā+ф'cŬo24Nwul0@MH+b5!{yhmcUk{OnI?ww xxQS_xj5?i}7ZkRx~ק>| 9ߞ׹pUUuo?;j%-U{SmTk(Qv/5̦Bhr=_Q;zIEOMC{n(51%kyOon(.$Ʈ/˔U'y ;;*bbBp4[ịs$Rc$V?su6V#9΂QWRUX =%ean\6(5FG3/]u]@)ͪZųQcY26wIm>aYy~TmVP`wLH+_ϭ?w9.i7wl㗨d;&ma3r=(+cP4f " #WNy34?}4]Pv۟w}ywmfUl=f^3'PljYhrphĭMPac;m~7kkm] ݍ[5 Vd~}R>!so=[C3-`: ,r)# $ZpwgTM|3GQG%Bp-XC=?Kz~[*!2zR~ޘ9;{[΄4=:M-F9if40G65KX,K*piT ޕpoz姸3npbŶ`X9hHz?CBm}M6`6ݶsCwuC䪱ڼ=M`{w%T9?qy?lu&ۻk7Чn*]ɊjLNaP?Pkx o(Ac 0Ͻ;JJʴ# я[oy{o$+Sԫ2z.76NbY͘[SOq9,~br4sEWӰx&:?d/՗o1'œ?=3nZ_/kޜ?5O@;aW{^U/]g_p/o}'ePЪn޽{No -ʼn;qnÇܴ4yJ}<ڹ榨 |[@| u0+\ty|+Lźx-UUT]!V }.A"uUd$ GĒ$PkCJ52'uh՝jٟ,7Rm=w7eY(`DwژFoA+6dWCl^a7Bʅ[0:,T-}6h+c>bnjG+iYkdoqu{[7~i$]KzSW֙$ -4X,^DQdcM'RA P«(L*DUK4XݝBccy%ޜpY=g73t2&;UYW}mú[ JC}+lHGktӱhpJVpTԕk{Rɸ T?*~ZHuz"*e eaue`AV~RGO o&st~Wg#W4*vNoXd-#cfVbIU_t4D;( $}S 3ꆎhmomjNBbc5fVSov龏ru_u_ZSuW͵6=;KGbf(b=T4Ybğ~i]ͶT3&ڭ *i3B%L x%V>(Ȅ9U{4Z>c#j*{z*ׯ۹: Bk,;,pUE3*!uSM\nDVc_Ntai#">zѿ[}Jkqo}w^.çt7j?->U+"سN@#*RrUb_ 8QV*>?{gqEQ-JT_FT{f{%)xGU8ѽ)ӰǷbG ފYlp[r~U;~im6ׯ #m ?̼7۷/yGfDj¾dtg KযHoH(PѮ2O^/Q(>w-N<<;'1۲%kf]鵰sóU5=YI 0T҅pcbStK]5uWOH`(h*8#Kݷk76ئe e|@2S*[9G\f_=q;p^";.sQ4;"/R::~d*3efVzd5gzsDf8U$Ȃf!BkAZ `RlF!`¦5|׽u~{ߺE۷:qoZ1UJfGXFRomk`}uO{|.߽[tnŢbz68^tݿWˮ>JDZ+oQs k:'9.O/:z媩!dje.TE9HZ85/k^??O|&@˫m4¼q1o[_^K}8犯>>5k_O:NS endstream endobj 176 0 obj (c/z#-X]) endobj 375 0 obj <>stream 3+ 6dfU|d! Z,GCZx "tHvf5"' fz8gZ)$s[ptsFwxGXS+VV"9'Fff fv m2T3V6* Tjd1ZL<^H:ssr#M5Cl^g.(HnU(=:u+(;)"$;7L3+3SS9^UBfP(E19VS JnX_n%I<>=: 9lm { Ab_n|WfQ:PJ%!(<5   uh+>nj _~%8V@ q9;TY\Gno*3VX 'PS Oe^w]  &N1 ! (52 Rsp  P0",kn0__=m^.ON!\c1mlZ;cacRq/ endstream endobj 267 0 obj <>stream HTal!;bE8UL4]X wsg`gB1K2v]^ VCjl/"cDŽ̮jh#F2i"+rl8p>,24T(8@y{ɟRidǣ0=nG`=BLd BaW"'b?EHıOaOMٍ@RxBކ]< $ KIqDx ".%A<M! 0/ /} _ !$c؂0DKC.(!pPjҖsd0s x|<Z9¥Q[4\b pbF .%)[jM&Ti2a쁴"V+I#ed(Sϋgfc}g) !#ALF8燄-F\H" apӹl6;jNiYCt~/mxD"cݴI+PD8䏃2Q77f+Z :E;UF8M=bu]jᨿif0>Ep"l% XXG0̡}#F fI(L{l;XmaۉK@iP1p1iGYkZi:F ly)is@I0WbM˱c'a`qsrR.4aUbxO.;o_M5zlZ]F۶dF`NRYcL7>=]L}f+(A*$F*J8m'of#?׻T WMޣg QE#9 $I OCńov9֮;Uo`]M?)rIoY`"-b:cZ`\Zy3߿UD^QtBCgZlgiKC 􆠅͈^~Ʈ& hB`UItH)_9]n:wYa!P(*0ѱ܈#Ho S5 kw`0]raY0 B?,lN*A+j^4E۫>Ow؂̙ aL-"3x?3.m0#Id8g 0X-e `H7כ*ꃿmNB @&u}s p'ᨅU E{3ܖ*wGqUqQcՍ4E>*5֢z|I|R9dua4Fwp$^@R`ljή D;tHR􍼪LF[*&i]rTGiς÷a <`,a'eIّ+vikT9T[s޲;buT*Q$zLA3) qOtBB'!A0 hJGg}BV3_z-=^{W~IVdr2{d .A7k3,'H~t~6v g>Xa4eR)_ϓfnk/%'f1oܳZ}ݕCv8t"a]0uPӧPP(VT?V]mm2}`unrԩƓC}>w,3f;v7} '̢<}{`I`+6NC e՟v΀ZflO3А}n(_c}Af=joӉ4X7ջb[);TSc?|}p[f3?5o=fz|nͺK[g;&'l'^x0Yv^}LƫUcT/ۙF+ovv~~ǎ>Gn:M]vmwCe5qqKnL" QY&(-WɐIP&X8|OZ(2ZUs wm8 YtP@ M5*c]n|>y|f{vz/0Te?mmu曗'Ο築ݿy9VT H򚪄L ORje)=R݅0?6fMKO3]2י3giy.g9Kϝۿq|t$y*|[xKV:>&.67P!ݸa\g1aٕ' `bu!z۷kj2קf247uï.YQs~ҡvC,w˕=4$TRATM _y;eO.,jѬXc ML}^v"75wź-\U]dedT +§sw)IiS>AjjnI%|yz['q4:uJEڙsK&jOM@=Gk{Sur:#TJp:g/?_O\ڣƥFaxIzϪӿ{:0̏ZeKwWZ/ yaXW xHJ _K,J2X֘t7Nu>vs9U@eG(Ģ/=wZ," %B׼g~B*P(At?s|R?4&%^پ}tѾ޼G\mvU뗚L85위}v/*wc$ nw1CbI6 =0r~6i4ae۾vMo}m & #)(*NJ_yE=MehgP}oJO(SH;z l; ZjXGbhA%.|5({[+&}`D'I;l FC Ckl*J4{GbH#Ӣv6^utLܐjؘxLTt=aJ.d1 A&x&DbY'X ]3Dmlzh:ko_᭭>mB XԾieTcA>0HN3H ú@c b@ӑ{1fA1 3eՓm#]ohx2D,sb{.F[ܡwn (`? r:RѸ<>AMŲ0"GѾL:^ +*r+_Hf FGѸ!8ɋU8=#uP0!9Q[,b^QL#rLr[o4:sq2Wcoc=ʋD6[vnB1 9{'oL_bScJN/y{F?ޘxq"a̴bڢ~8 j +~5i05׭ ,PsEh (Ł@Q{Qb*r e Lp#t!ys_O`͍銰0lTw}CHuX,@P9qFŸmM?gw/1+g}啶98[>'[I5XMaVzzVvX$FPաRA09U0Im̍bgE^rஹfu8,̯Hp@OR> `/T@Z|3Q[Ί {3XD8;(d~3HnRbh$Td@Jȩy^1HŦ|ude!sZYP6 r6 ahC 0$; Q 9r6 cS P|Ze41:F׮4Y:)5h#2 ᗃX[(1fAg`m^p` թ+V'}y_Hrn8T3s`ti(`;f*SX< EE>w~YM׶(./c~_:,1~8'z YPq(66 7n,zo*")!TL>|w"7د6+6QrP,BnA+%+/v2{hІ4֎;"52%`'#,N 7NڦV֏Tofn{}My$zfn';PWlH{-[854Pl5<:{(`9yxmVF^혜X`;h=@[r |<m_QA#Nرoӣ'24M{;ܻHk&uc8?A#WfTgo"!?؄?biqb#KWa=xi0Kt] /]u= hQ-|& q-7G;&/>}w/_y|eS"_jH@0ڮKkq{AE<"g%q.[IMyq䧗Ń㗫zW:ow,E/K\hppbxpPOIrgѦ`j1*oTm!fG=7 ,WɆޏz4y6KbdVR)M  S9R\J_]VXjFV, ro߭] cn9,YJ㊀Rl˂ȗ,BL]T8dғ{ܸ0PW_nʟ}k2Lܪk5 # 8l iۂ" -{Fvmgq֋\|-|+1d/_L LA©f,vP\Ա&hDSħOߵHɂ'46vLn* ychX_. C~7_Y4yƲXOW^v~Mv'l緾ReK}\AeyNdR a(RE8Ѧ&8Fx;&G~2Ww޽rOoMl":x'B̭ra:.P)aV E鈂AXёÇ ~e}>G Z[ O=b8j^p]ge0\x8ekRQyjڐ7~>:Mq? a[䏅ܚXKa/D i@;s j[E G\]VynmD} mSE RP8HG?5x#녮c?h endstream endobj 174 0 obj (a>%FU7A0m) endobj 376 0 obj <>stream HbfX ecggJ09qsd\ISXR&q'OaI̝2%ekT鬩3XӧdKɞ17}[Ls3h.{< Ȟϑ#w>oBEy@3 W\@pOr+xVr)YD|%yJ+[[USzw-\u[oհag6M;vqh Bmu8ה3SOqN=2ԳpN;2 s3q:1>stream H3iBOGk#6Ԕޮ;k+Iq -fcj+33,MDG*+ojl?2,$0C]a~^.Nt4x:;92u%yiI)qA~^ _YQNZLX W`efbirY\7 endstream endobj 304 0 obj <>>>/XStep 6/BBox[0 0 6 10]/Matrix[0.746338 0.0 0.0 0.746338 1.49268 2.96275]/YStep 10/Length 28/PaintType 1/PatternType 1>>stream q 6 0 0 10 0 0 cm /BGIm Do Q endstream endobj 306 0 obj <>>>/XStep 1700/BBox[0 0 1700 40]/Matrix[0.746338 0.0 0.0 0.746338 14.9268 1.61934]/YStep 40/Length 31/PaintType 1/PatternType 1>>stream q 1700 0 0 40 0 0 cm /BGIm Do Q endstream endobj 307 0 obj <>>>/XStep 9/BBox[0 0 9 9]/Matrix[0.746338 0.0 0.0 0.746338 4.47804 6.09738]/YStep 9/Length 27/PaintType 1/PatternType 1>>stream q 9 0 0 9 0 0 cm /BGIm Do Q endstream endobj 308 0 obj <>>>/XStep 5/BBox[0 0 5 156]/Matrix[0.746338 0.0 0.0 0.746338 0.0 8.91667]/YStep 156/Length 29/PaintType 1/PatternType 1>>stream q 5 0 0 156 0 0 cm /BGIm Do Q endstream endobj 299 0 obj <>>>/XStep 340/BBox[0 0 340 9]/Matrix[0.746338 0.0 0.0 0.746338 216.439 5.48351]/YStep 9/Length 29/PaintType 1/PatternType 1>>stream q 340 0 0 9 0 0 cm /BGIm Do Q endstream endobj 183 0 obj (!\r|t%ݞ[ <) endobj 389 0 obj <>stream B`u;ZpUpUpkEbw5UkZt6Vl@^sJfzyu|SnxlazXr?^s~=\qNj}Ok~wJg{9XnHeyrh_x\vB`tYtFdx7WmDbvte~{<[p>\qMi|]wWrQlpA_td|jnc|:Yn8XmKh{azGdxqgRm;Zo7Vl endstream endobj 390 0 obj [/Indexed/DeviceRGB 63 389 0 R] endobj 241 0 obj <>stream HvQ PCCP@h ǯ׶TA<"~9ghpV'qƈ'9E$ed0i˵WNtg[Q$qNA2t?D:&mqT'1Np@2t?đ3NyNq(ȪaҖk- endstream endobj 300 0 obj <>>>/XStep 50/BBox[0 0 50 64]/Matrix[0.746338 0.0 0.0 0.746338 22.3902 42.9514]/YStep 64/Length 29/PaintType 1/PatternType 1>>stream q 50 0 0 64 0 0 cm /BGIm Do Q endstream endobj 187 0 obj (B_>ƕҲ\r s}) endobj 391 0 obj <>stream endstream endobj 392 0 obj [/Indexed/DeviceRGB 3 391 0 R] endobj 249 0 obj <>stream HbbF !!$3dp @ x endstream endobj 301 0 obj <>>>/XStep 7/BBox[0 0 7 7]/Matrix[0.746338 0.0 0.0 0.746338 0.0 2.49814]/YStep 7/Length 27/PaintType 1/PatternType 1>>stream q 7 0 0 7 0 0 cm /BGIm Do Q endstream endobj 172 0 obj (`FZ۟q|$Sd#) endobj 393 0 obj <>stream endstream endobj 394 0 obj [/Indexed/DeviceRGB 3 393 0 R] endobj 251 0 obj <>stream Hb`dfffF!4bR x endstream endobj 302 0 obj <>>>/XStep 7/BBox[0 0 7 7]/Matrix[0.746338 0.0 0.0 0.746338 1.49268 2.49814]/YStep 7/Length 27/PaintType 1/PatternType 1>>stream q 7 0 0 7 0 0 cm /BGIm Do Q endstream endobj 185 0 obj (m2qK3X0) endobj 395 0 obj <>stream endstream endobj 396 0 obj [/Indexed/DeviceRGB 3 395 0 R] endobj 245 0 obj <>stream Hb`F \&@ x endstream endobj 296 0 obj <>>>/XStep 7/BBox[0 0 7 7]/Matrix[0.746338 0.0 0.0 0.746338 0.0 1.90257]/YStep 7/Length 27/PaintType 1/PatternType 1>>stream q 7 0 0 7 0 0 cm /BGIm Do Q endstream endobj 170 0 obj (O6Y}\)) endobj 397 0 obj <>stream endstream endobj 398 0 obj [/Indexed/DeviceRGB 3 397 0 R] endobj 247 0 obj <>stream Hbf0 &!@@ x endstream endobj 298 0 obj <>>>/XStep 7/BBox[0 0 7 7]/Matrix[0.746338 0.0 0.0 0.746338 1.49268 1.90257]/YStep 7/Length 27/PaintType 1/PatternType 1>>stream q 7 0 0 7 0 0 cm /BGIm Do Q endstream endobj 297 0 obj <>>>/XStep 1700/BBox[0 0 1700 40]/Matrix[0.746338 0.0 0.0 0.746338 14.9268 13.6933]/YStep 40/Length 31/PaintType 1/PatternType 1>>stream q 1700 0 0 40 0 0 cm /BGIm Do Q endstream endobj 287 0 obj <>>>/XStep 5/BBox[0 0 5 156]/Matrix[0.746338 0.0 0.0 0.746338 0.0 31.4341]/YStep 156/Length 29/PaintType 1/PatternType 1>>stream q 5 0 0 156 0 0 cm /BGIm Do Q endstream endobj 290 0 obj <>>>/XStep 9/BBox[0 0 9 9]/Matrix[0.746338 0.0 0.0 0.746338 4.47804 3.99081]/YStep 9/Length 27/PaintType 1/PatternType 1>>stream q 9 0 0 9 0 0 cm /BGIm Do Q endstream endobj 303 0 obj <>>>/XStep 6/BBox[0 0 6 10]/Matrix[0.746338 0.0 0.0 0.746338 2.98537 5.0372]/YStep 10/Length 28/PaintType 1/PatternType 1>>stream q 6 0 0 10 0 0 cm /BGIm Do Q endstream endobj 291 0 obj <>>>/XStep 6/BBox[0 0 6 10]/Matrix[0.746338 0.0 0.0 0.746338 2.98537 5.18497]/YStep 10/Length 28/PaintType 1/PatternType 1>>stream q 6 0 0 10 0 0 cm /BGIm Do Q endstream endobj 305 0 obj <>>>/XStep 6/BBox[0 0 6 10]/Matrix[0.746338 0.0 0.0 0.746338 2.98537 2.20111]/YStep 10/Length 28/PaintType 1/PatternType 1>>stream q 6 0 0 10 0 0 cm /BGIm Do Q endstream endobj 162 0 obj (4I݀#It) endobj 399 0 obj <>stream endstream endobj 400 0 obj [/Indexed/DeviceRGB 3 399 0 R] endobj 233 0 obj <>stream H$LL@6 [DӓT w endstream endobj 288 0 obj <>>>/XStep 7/BBox[0 0 7 7]/Matrix[0.746338 0.0 0.0 0.746338 4.47804 0.559158]/YStep 7/Length 27/PaintType 1/PatternType 1>>stream q 7 0 0 7 0 0 cm /BGIm Do Q endstream endobj 156 0 obj (\rjva۷) endobj 401 0 obj <>stream endstream endobj 402 0 obj [/Indexed/DeviceRGB 3 401 0 R] endobj 235 0 obj <>stream Hb`dfffF|0 !@ w endstream endobj 289 0 obj <>>>/XStep 7/BBox[0 0 7 7]/Matrix[0.746338 0.0 0.0 0.746338 3.7317 0.559158]/YStep 7/Length 27/PaintType 1/PatternType 1>>stream q 7 0 0 7 0 0 cm /BGIm Do Q endstream endobj 159 0 obj (?8\tŅc%S\nN) endobj 403 0 obj <>stream endstream endobj 404 0 obj [/Indexed/DeviceRGB 3 403 0 R] endobj 229 0 obj <>stream Hb`F \&&3#@ qw endstream endobj 294 0 obj <>>>/XStep 7/BBox[0 0 7 7]/Matrix[0.746338 0.0 0.0 0.746338 4.47804 4.45543]/YStep 7/Length 27/PaintType 1/PatternType 1>>stream q 7 0 0 7 0 0 cm /BGIm Do Q endstream endobj 193 0 obj (څ+ֽM+hŊ) endobj 405 0 obj <>stream endstream endobj 406 0 obj [/Indexed/DeviceRGB 3 405 0 R] endobj 231 0 obj <>stream H$ 4߹$LobA w endstream endobj 295 0 obj <>>>/XStep 7/BBox[0 0 7 7]/Matrix[0.746338 0.0 0.0 0.746338 3.7317 4.45543]/YStep 7/Length 27/PaintType 1/PatternType 1>>stream q 7 0 0 7 0 0 cm /BGIm Do Q endstream endobj 292 0 obj <>>>/XStep 6/BBox[0 0 6 10]/Matrix[0.746338 0.0 0.0 0.746338 1.49268 6.24666]/YStep 10/Length 28/PaintType 1/PatternType 1>>stream q 6 0 0 10 0 0 cm /BGIm Do Q endstream endobj 293 0 obj <>>>/XStep 1700/BBox[0 0 1700 40]/Matrix[0.746338 0.0 0.0 0.746338 14.9268 24.6067]/YStep 40/Length 31/PaintType 1/PatternType 1>>stream q 1700 0 0 40 0 0 cm /BGIm Do Q endstream endobj 286 0 obj <>>>/XStep 9/BBox[0 0 9 9]/Matrix[0.746338 0.0 0.0 0.746338 4.47804 6.69446]/YStep 9/Length 27/PaintType 1/PatternType 1>>stream q 9 0 0 9 0 0 cm /BGIm Do Q endstream endobj 52 0 obj (\)U`R:b֋p) endobj 277 0 obj <> endobj 407 0 obj <> endobj 408 0 obj <> endobj 149 0 obj <> 1<><> 2]/T()/P 143 0 R>> endobj 143 0 obj <> endobj 409 0 obj <> endobj xref 0 410 0000000000 65535 f 0000031881 00000 n 0000032174 00000 n 0000031322 00000 n 0000000015 00000 n 0000009977 00000 n 0000012665 00000 n 0000029715 00000 n 0000031410 00000 n 0000032691 00000 n 0000031629 00000 n 0000029549 00000 n 0000112245 00000 n 0000111883 00000 n 0000031146 00000 n 0000031245 00000 n 0000032955 00000 n 0000036399 00000 n 0000104812 00000 n 0000045136 00000 n 0000052253 00000 n 0000058335 00000 n 0000049135 00000 n 0000098316 00000 n 0000095903 00000 n 0000096710 00000 n 0000096973 00000 n 0000096169 00000 n 0000096435 00000 n 0000097777 00000 n 0000098052 00000 n 0000097239 00000 n 0000097514 00000 n 0000095104 00000 n 0000095637 00000 n 0000095371 00000 n 0000094037 00000 n 0000094305 00000 n 0000094571 00000 n 0000094836 00000 n 0000092976 00000 n 0000093242 00000 n 0000093508 00000 n 0000093774 00000 n 0000104158 00000 n 0000104207 00000 n 0000103980 00000 n 0000125461 00000 n 0000128865 00000 n 0000126981 00000 n 0000104029 00000 n 0000124282 00000 n 0000203660 00000 n 0000037017 00000 n 0000037357 00000 n 0000037535 00000 n 0000037713 00000 n 0000037892 00000 n 0000038065 00000 n 0000038239 00000 n 0000038417 00000 n 0000038593 00000 n 0000038770 00000 n 0000038967 00000 n 0000039152 00000 n 0000039338 00000 n 0000039523 00000 n 0000039697 00000 n 0000039884 00000 n 0000040065 00000 n 0000040225 00000 n 0000040425 00000 n 0000040608 00000 n 0000040775 00000 n 0000040927 00000 n 0000041080 00000 n 0000041244 00000 n 0000041410 00000 n 0000041584 00000 n 0000041743 00000 n 0000041916 00000 n 0000042077 00000 n 0000042234 00000 n 0000042400 00000 n 0000042573 00000 n 0000042752 00000 n 0000042924 00000 n 0000043084 00000 n 0000043259 00000 n 0000043421 00000 n 0000043581 00000 n 0000043730 00000 n 0000043877 00000 n 0000044022 00000 n 0000044168 00000 n 0000044333 00000 n 0000044499 00000 n 0000044665 00000 n 0000044825 00000 n 0000044986 00000 n 0000048514 00000 n 0000048552 00000 n 0000051399 00000 n 0000051435 00000 n 0000057480 00000 n 0000057517 00000 n 0000065180 00000 n 0000085581 00000 n 0000085827 00000 n 0000085897 00000 n 0000092649 00000 n 0000092676 00000 n 0000134920 00000 n 0000135425 00000 n 0000135790 00000 n 0000136367 00000 n 0000141277 00000 n 0000098581 00000 n 0000101913 00000 n 0000133330 00000 n 0000103173 00000 n 0000125498 00000 n 0000104256 00000 n 0000098928 00000 n 0000099075 00000 n 0000099226 00000 n 0000099404 00000 n 0000099582 00000 n 0000099763 00000 n 0000099940 00000 n 0000100120 00000 n 0000100298 00000 n 0000100477 00000 n 0000100656 00000 n 0000100833 00000 n 0000101013 00000 n 0000101191 00000 n 0000101369 00000 n 0000101555 00000 n 0000101731 00000 n 0000102992 00000 n 0000103028 00000 n 0000104305 00000 n 0000204143 00000 n 0000104471 00000 n 0000104413 00000 n 0000104518 00000 n 0000104561 00000 n 0000104596 00000 n 0000203977 00000 n 0000104623 00000 n 0000104722 00000 n 0000104767 00000 n 0000104880 00000 n 0000135292 00000 n 0000107252 00000 n 0000201010 00000 n 0000106518 00000 n 0000108283 00000 n 0000201625 00000 n 0000106095 00000 n 0000105910 00000 n 0000200393 00000 n 0000106377 00000 n 0000134529 00000 n 0000106960 00000 n 0000136053 00000 n 0000107398 00000 n 0000141823 00000 n 0000108593 00000 n 0000198172 00000 n 0000107688 00000 n 0000196954 00000 n 0000107978 00000 n 0000193079 00000 n 0000105776 00000 n 0000185447 00000 n 0000109226 00000 n 0000135645 00000 n 0000108439 00000 n 0000110388 00000 n 0000106667 00000 n 0000109069 00000 n 0000195380 00000 n 0000107107 00000 n 0000197566 00000 n 0000107543 00000 n 0000196342 00000 n 0000107833 00000 n 0000108909 00000 n 0000108750 00000 n 0000141094 00000 n 0000106814 00000 n 0000202239 00000 n 0000106236 00000 n 0000141496 00000 n 0000108124 00000 n 0000105292 00000 n 0000105705 00000 n 0000105870 00000 n 0000106042 00000 n 0000106183 00000 n 0000106324 00000 n 0000106465 00000 n 0000106606 00000 n 0000106755 00000 n 0000106902 00000 n 0000107048 00000 n 0000107195 00000 n 0000107340 00000 n 0000107486 00000 n 0000107631 00000 n 0000107776 00000 n 0000107921 00000 n 0000108066 00000 n 0000108218 00000 n 0000108377 00000 n 0000108527 00000 n 0000108687 00000 n 0000108843 00000 n 0000109002 00000 n 0000109162 00000 n 0000111551 00000 n 0000193645 00000 n 0000111606 00000 n 0000111459 00000 n 0000111496 00000 n 0000111400 00000 n 0000111345 00000 n 0000201772 00000 n 0000111290 00000 n 0000202384 00000 n 0000111235 00000 n 0000200538 00000 n 0000111180 00000 n 0000201156 00000 n 0000110424 00000 n 0000110479 00000 n 0000110333 00000 n 0000110278 00000 n 0000110223 00000 n 0000195708 00000 n 0000110168 00000 n 0000110113 00000 n 0000110058 00000 n 0000197711 00000 n 0000110003 00000 n 0000198318 00000 n 0000109948 00000 n 0000196488 00000 n 0000109893 00000 n 0000197099 00000 n 0000109819 00000 n 0000109874 00000 n 0000109745 00000 n 0000109800 00000 n 0000109690 00000 n 0000109616 00000 n 0000141861 00000 n 0000109671 00000 n 0000109542 00000 n 0000109597 00000 n 0000109468 00000 n 0000109523 00000 n 0000109394 00000 n 0000109449 00000 n 0000109320 00000 n 0000186301 00000 n 0000109375 00000 n 0000110889 00000 n 0000110938 00000 n 0000111625 00000 n 0000111664 00000 n 0000111691 00000 n 0000111748 00000 n 0000111780 00000 n 0000112184 00000 n 0000203696 00000 n 0000125887 00000 n 0000126489 00000 n 0000128378 00000 n 0000130272 00000 n 0000131101 00000 n 0000131938 00000 n 0000132751 00000 n 0000133717 00000 n 0000203396 00000 n 0000199063 00000 n 0000200745 00000 n 0000201361 00000 n 0000199329 00000 n 0000199859 00000 n 0000202853 00000 n 0000203120 00000 n 0000201975 00000 n 0000202590 00000 n 0000197912 00000 n 0000198787 00000 n 0000198523 00000 n 0000195110 00000 n 0000196072 00000 n 0000196694 00000 n 0000197302 00000 n 0000199593 00000 n 0000194037 00000 n 0000200126 00000 n 0000194304 00000 n 0000194580 00000 n 0000194844 00000 n 0000125597 00000 n 0000125547 00000 n 0000112973 00000 n 0000113487 00000 n 0000113666 00000 n 0000113833 00000 n 0000114001 00000 n 0000114175 00000 n 0000114355 00000 n 0000114533 00000 n 0000114711 00000 n 0000114869 00000 n 0000115036 00000 n 0000115195 00000 n 0000115382 00000 n 0000115540 00000 n 0000115728 00000 n 0000115920 00000 n 0000116114 00000 n 0000116318 00000 n 0000116523 00000 n 0000116728 00000 n 0000116933 00000 n 0000117137 00000 n 0000117332 00000 n 0000117526 00000 n 0000117707 00000 n 0000117904 00000 n 0000118101 00000 n 0000118290 00000 n 0000118479 00000 n 0000118640 00000 n 0000118797 00000 n 0000118964 00000 n 0000119144 00000 n 0000119325 00000 n 0000119505 00000 n 0000119696 00000 n 0000119880 00000 n 0000120066 00000 n 0000120239 00000 n 0000120396 00000 n 0000120554 00000 n 0000120713 00000 n 0000120871 00000 n 0000121034 00000 n 0000121200 00000 n 0000121374 00000 n 0000121540 00000 n 0000121707 00000 n 0000121883 00000 n 0000122049 00000 n 0000122218 00000 n 0000122384 00000 n 0000122564 00000 n 0000122728 00000 n 0000122901 00000 n 0000123079 00000 n 0000123257 00000 n 0000123413 00000 n 0000123572 00000 n 0000123734 00000 n 0000123907 00000 n 0000124068 00000 n 0000125647 00000 n 0000141532 00000 n 0000185483 00000 n 0000193115 00000 n 0000128156 00000 n 0000130044 00000 n 0000134565 00000 n 0000134771 00000 n 0000135328 00000 n 0000141774 00000 n 0000135681 00000 n 0000135742 00000 n 0000136089 00000 n 0000136318 00000 n 0000141131 00000 n 0000141228 00000 n 0000195417 00000 n 0000195659 00000 n 0000196379 00000 n 0000196440 00000 n 0000196990 00000 n 0000197051 00000 n 0000197602 00000 n 0000197663 00000 n 0000198209 00000 n 0000198270 00000 n 0000200429 00000 n 0000200490 00000 n 0000201047 00000 n 0000201108 00000 n 0000201663 00000 n 0000201724 00000 n 0000202275 00000 n 0000202336 00000 n 0000203767 00000 n 0000203854 00000 n 0000204196 00000 n trailer <]/Info 409 0 R/Size 410>> startxref 204370 %%EOF endesive-2.19.1/examples/pdf-alter.py000066400000000000000000000002511504236674500174660ustar00rootroot00000000000000import pymupdf doc = pymupdf.open('pdf-acrobat.pdf') page = doc[0] rects = page.search_for("world") page.add_highlight_annot(rects) doc.save("pdf-acrobat-modified.pdf") endesive-2.19.1/examples/pdf-annotate.py000077500000000000000000000006151504236674500201770ustar00rootroot00000000000000#!/usr/bin/env vpython3 from pdf_annotate import PdfAnnotator, Location, Appearance annotationtext = "some text" a = PdfAnnotator("pdf.pdf") a.add_annotation( "text", Location(x1=50, y1=50, x2=200, y2=100, page=0), Appearance( fill=(0, 0, 0), stroke_width=1, wrap_text=True, font_size=12, content=annotationtext, ), ) a.write("pdf-a.pdf") endesive-2.19.1/examples/pdf-buggy.pdf000066400000000000000000000142161504236674500176230ustar00rootroot00000000000000%PDF-1.4 1 0 obj << /Title () /Creator (wkhtmltopdf 0.12.4) /Producer (Qt 4.8.7) /CreationDate (D:20200311201135+05'30') >> endobj 3 0 obj << /Type /ExtGState /SA true /SM 0.02 /ca 1.0 /CA 1.0 /AIS false /SMask /None>> endobj 4 0 obj [/Pattern /DeviceRGB] endobj 7 0 obj [0 /XYZ 29.7600000 813.679999 0] endobj 8 0 obj << /__WKANCHOR_2 7 0 R >> endobj 10 0 obj <> endobj 9 0 obj <> endobj 11 0 obj << /Type /Catalog /Pages 2 0 R /Outlines 9 0 R /PageMode /UseOutlines /Dests 8 0 R >> endobj 5 0 obj << /Type /Page /Parent 2 0 R /Contents 12 0 R /Resources 14 0 R /Annots 15 0 R /MediaBox [0 0 595 842] >> endobj 14 0 obj << /ColorSpace << /PCSp 4 0 R /CSp /DeviceRGB /CSpg /DeviceGray >> /ExtGState << /GSa 3 0 R >> /Pattern << >> /Font << /F6 6 0 R >> /XObject << >> >> endobj 15 0 obj [ ] endobj 12 0 obj << /Length 13 0 R /Filter /FlateDecode >> stream xRMK0ϯi2IDp Ҁ ]TXwESd{}}LRܵ/Ţn?j݂V,b,6|xaÀ4;v6P@~sƧg." z rcHP>n/p9Zq$rs?F=%i& `+CUVx36W@NJ{*G042)0vd_1N fu6JBj.G&K2ݴ8-$ endstream endobj 13 0 obj 279 endobj 16 0 obj << /Type /FontDescriptor /FontName /QQAAAA+TimesNewRomanPS-BoldMT /Flags 4 /FontBBox [-558.105468 -441.406250 2000 891.113281 ] /ItalicAngle 0 /Ascent 891.113281 /Descent -216.308593 /CapHeight 662.109375 /StemV 95.2148437 /FontFile2 17 0 R >> endobj 17 0 obj << /Length1 7856 /Length 20 0 R /Filter /FlateDecode >> stream xV{L[}@\cl6/#%@i05\b|}B;uNYkvmiYԩj&VmڣjtS?v{HW&f9&9Q?u|=4n9{%w2=y"OJޡoϣ,6uw8nQO7 U8`ZI2L>7OBxb&>#Ɂ/n@Ӻ̆ a֞UNg֛ ^#l%8Շ^pp0H&'Q/~0B:҈u4P&is4 pE_kO@.ah؂UԢ^jupC1<^\Qb2vZN]=nw}Kӵկ->-((Z|W;W8.7Ժu)g'7kpTٲ>U8MN_}Y_8G{ΥqkEN9Eb،9vL77|r2IJ\xSS0V}9$D)/fJ0kF}'--VI? z,쩬!5 ;{s7@zϟ~rf8qn玻Iˋ};G ϒWH6Be9ΐY*TM[zBCGvl'Gn/<8FL6 r) z>@\)o5ډ5fhm޻%.v;<~& Gwmh,jXNuFXtMg`-D 683#w(mn Mn޹GRF֯#98[:g!c-7mcg4VoyCNmm! OUUij~"֧I X0,bİ>sڗK5~:(Ta}oJt|[сPDz)<&-e?mA\߸k&q\A3 /d/.Q[{(;m(x#ee{jkowط_GyPxr~OfBdDH el}k/߰[0;lK}R4LFX!ii b&@=@~MgW洞HA^?{}Lտ0OqI6&g68 SE]ESqq!^u%Ax#^2skwxP#[wX'!=g7zF밸3! _X6±I+F~MK A6 4t>Z-j81*O8ց`xc= os,@±aslIfXoq _x53|c{6b~c6a؈r5`Dy3c((kX_ft8%Oٻ#e}Zq[<1oyc 8F++k(jXPU [ǘO4Õ(V= [_sLʡ1rhmdc`؎Z jLgS6Ǩobw61m&1C od9/3J.ǸLvpTkAO5c̿ ìqLlM+48Fy 0֥&1ƭ c` $|TY&Q1Q.3O&^IP$ޓ93L*>|1-eqԏ(zF.a'.Yv8㹉ŨA@Ԇ~eHଂ |=é"/e0*+Qf3qTsu\N}kDfGdU1CJTP)8gƮ5sb\T4Ϟu+匨ܑJIWS> /FontDescriptor 16 0 R /CIDToGIDMap /Identity /W [0 [772 772 440 276 496 248 248 662 496 552 552 330 ] ] >> endobj 19 0 obj << /Length 441 >> stream /CIDInit /ProcSet findresource begin 12 dict begin begincmap /CIDSystemInfo << /Registry (Adobe) /Ordering (UCS) /Supplement 0 >> def /CMapName /Adobe-Identity-UCS def /CMapType 2 def 1 begincodespacerange <0000> endcodespacerange 2 beginbfrange <0000> <0000> <0000> <0001> <000B> [<0048> <0065> <006C> <006F> <002C> <0009> <0054> <0061> <0070> <006E> <0021> ] endbfrange endcmap CMapName currentdict /CMap defineresource pop end end endstream endobj 6 0 obj << /Type /Font /Subtype /Type0 /BaseFont /TimesNewRomanPS-BoldMT /Encoding /Identity-H /DescendantFonts [18 0 R] /ToUnicode 19 0 R>> endobj 2 0 obj << /Type /Pages /Kids [ 5 0 R ] /Count 1 /ProcSet [/PDF /Text /ImageB /ImageC] >> endobj xref 0 21 0000000000 65535 f 0000000009 00000 n 0000005689 00000 n 0000000163 00000 n 0000000258 00000 n 0000000659 00000 n 0000005541 00000 n 0000000295 00000 n 0000000346 00000 n 0000000495 00000 n 0000000387 00000 n 0000000557 00000 n 0000000966 00000 n 0000001321 00000 n 0000000780 00000 n 0000000946 00000 n 0000001341 00000 n 0000001607 00000 n 0000004778 00000 n 0000005048 00000 n 0000004757 00000 n trailer << /Size 21 /Info 1 0 R /Root 11 0 R >> startxref 5787 %%EOF endesive-2.19.1/examples/pdf-dump-dss.py000077500000000000000000000046111504236674500201220ustar00rootroot00000000000000#!/usr/bin/env vpython3 # *-* coding: utf-8 *-* from asn1crypto import ( algos, cms, core, crl, keys, ocsp, parser, pdf, pem, pkcs12, tsp, util, version, x509, ) from endesive.pdf.PyPDF2 import pdf, generic as po from endesive.signer import cert2asn class Dumper: def __init__(self, fname): self.pdf = pdf.PdfFileReader(open(fname, "rb")) def show(self): root = self.pdf.trailer["/Root"] dss = root["/DSS"] print(dss) self.showCerts(dss["/Certs"]) self.showVRI(dss["/VRI"]) self.showOCSPs(dss["/OCSPs"]) self.showCRLs(dss["/CRLs"]) def showCert(self, der): pem = cert2asn(der, False) # pem.debug() print(pem.serial_number) print(pem.issuer.native) print(pem.subject.native) def showOCSP(self, der): data = ocsp.OCSPResponse.load(der) print(data.native["response_status"]) certs = data.basic_ocsp_response.native["certs"] cert = certs[0]["tbs_certificate"] print(cert["serial_number"]) print(cert["subject"]) # data.debug() def showCerts(self, objs): print("*" * 20, "Certs") for robj in objs: obj = robj.getObject() der = obj.getData() self.showCert(der) def showVRI(self, obj): print("*" * 20, "VRI") for k, robj in obj.items(): print("*" * 20, k) vobj = robj.getObject() print("/TU", vobj["/TU"]) print("*" * 10, "VRI-cert") for robj in vobj["/Cert"]: der = robj.getObject().getData() self.showCert(der) try: robjs = vobj["/OCSP"] except KeyError: robjs = [] for robj in robjs: print("*" * 10, "VRI-OCSP") der = robj.getObject().getData() self.showOCSP(der) def showOCSPs(self, objs): print("*" * 20, "OCSPs") for robj in objs: obj = robj.getObject() der = obj.getData() print("*" * 10, "OCSP") self.showOCSP(der) def showCRLs(self, objs): print("*" * 20, "CRLs") for robj in objs: obj = robj.getObject() print(obj) def main(): cls = Dumper("pdf-signed-cms-m32_ocsp.pdf") cls.show() main() endesive-2.19.1/examples/pdf-dump-offsets.py000077500000000000000000000050271504236674500210040ustar00rootroot00000000000000#!/usr/bin/env vpython3 class Main: def __init__(self, fname): with open(fname, "rb") as fi: self.data = fi.read() self.xrefs = [] def find(self, s, start=0): i = self.data.find(s, start) if i >= 0: i += len(s) return i def readline(self, start): i1 = i0 = start while self.data[i1] not in b'\r\n': i1 += 1 n = i1 while self.data[n] in b'\r\n': n += 1 return self.data[i0:i1].strip(), n def xref(self): xref = 0 while True: xref = self.find(b'\nxref\n', xref) if xref < 0: break n = xref while True: line, n = self.readline(n) line = line.split() try: assert len(line) == 2 off, cnt = int(line[0]), int(line[1]) except: break for i in range(cnt): line, n = self.readline(n) line = line.split() if line[-1] == b'n': offset = int(line[0]) line1 = self.readline(offset)[0].split() try: assert len(line1) == 3 and int(line1[0]) == off + i except: print('bad xref:', line, line1, 'off:', off+i, len(line1)) print(line1, off+i, offset) #self.xref.append( def byterange(self): start = self.find(b'/ByteRange') i0 = self.find(b'[', start) i1 = self.find(b']', start) line = self.data[i0:i1-1] line = line.split() br = [int(line[0]), int(line[1]), int(line[2]), int(line[3])] print(br, [hex(i) for i in br]) c = self.data[br[1]] print('[{:06x}]: {:d} {:02x}'.format(br[1], c, c)) c = self.data[br[2]] print('[{:06x}]: {:d} {:02x}'.format(br[2], c, c)) print(len(self.data), br[2]+br[3]) contents = self.data[br[0] + br[1] + 1 : br[2] - 1] print('[contents]:', len(contents)) def main(self): self.xref() self.byterange() for fname in ( #"pdf-certum.pdf", #"pdf-acrobat.pdf", 'pdf-signed-java.pdf', 'pdf-signed-pypdf.pdf', 'pdf-encrypted-signed-java.pdf', 'pdf-encrypted-signed-pypdf.pdf', ): print('*'*20, fname) try: cls = Main(fname) except IOError: continue cls.main() endesive-2.19.1/examples/pdf-dump.py000077500000000000000000000020771504236674500173370ustar00rootroot00000000000000#!/usr/bin/env vpython3 # *-* coding: utf-8 *-* import sys def show(fname): print('*' * 20, fname) data = open(fname, 'rb').read() s = data.find(b'xref') while s > 0: e = data.find(b'trailer', s) - 1 offsets = data[s:e].split(b'\n') print(offsets) if 1: for offset in offsets[2:]: offset = offset.split() if len(offset) != 3: continue offset = int(offset[0], 10) sdata = data[offset:offset + 32].split(b'\n')[0] print(offset, '->', sdata) s = data.find(b'%%EOF', e) print('%%EOF at', s) s = data.find(b'xref', s) s = data.find(b'/ByteRange') if s > 0: start = data.find(b'[', s) + 1 end = data.find(b']', s) byterange = [int(i, 10) for i in data[start:end].split()] print('/ByteRange', ':', s, start, end, ':', byterange) print('/Contents', ':', chr(data[byterange[1]]), '...', chr(data[byterange[2] - 1])) def main(): show(sys.argv[1]) main() endesive-2.19.1/examples/pdf-encrypt.py000077500000000000000000000007011504236674500200460ustar00rootroot00000000000000#!/usr/bin/env vpython3 # *-* coding: utf-8 *-* import sys from PyPDF2 import PdfFileReader, PdfFileWriter fname = "pdf.pdf" with open(fname, "rb") as in_file: input_pdf = PdfFileReader(in_file) output_pdf = PdfFileWriter() output_pdf.appendPagesFromReader(input_pdf) output_pdf.encrypt("1234", "1234") fname = fname.replace('.pdf', '-encrypted.pdf') with open(fname, "wb") as out_file: output_pdf.write(out_file) endesive-2.19.1/examples/pdf-linearized.pdf000066400000000000000000002110041504236674500206260ustar00rootroot00000000000000%PDF-1.6 % 13 0 obj <> endobj 24 0 obj <>/Filter/FlateDecode/ID[<7671C61FC4FF65086CCE130671E2C66A><19D64D7E48DF47DF93327CFD5C8AA1A2>]/Index[13 26]/Info 12 0 R/Length 68/Prev 69839/Root 14 0 R/Size 39/Type/XRef/W[1 2 1]>>stream hbbd``b`j @a5DqkB q/X* L Fr endstream endobj startxref 0 %%EOF 38 0 obj <>stream hb````fF.130p< CGG8AA!Ez:XAH3-X2L@&20\0 endstream endobj 14 0 obj <> endobj 15 0 obj <> endobj 16 0 obj <>>>/Subtype/Form/Type/XObject>>stream /FRM Do endstream endobj 17 0 obj <>>>/Subtype/Form/Type/XObject>>stream H*T0T0BgU)c0 endstream endobj 18 0 obj <>/Subtype/Form/Type/XObject>>stream % DSBlank endstream endobj 19 0 obj <>/ProcSet[/PDF/Text]>>/Subtype/Form/Type/XObject>>stream HUMo$5Wa-HIq%8"1.E $~=ܓ̀D]z~6%jX'{ŐucMqWks(['Uy-dp2d[8,c#mlvp#ϛ TxW hobZKк ` Q1X'@vtLF\BPc4Ƥ!gu V)Hx{i$M(`뭞 (̓m*r&8B&tKk s*IFvW(̇P+$D(H.vM0񪂯8 fU Qt/pbQc&QXds0}(f2;6I"If 3BJ`;lC>PC4A}::`(0h&:q݄aZ Y!d$jĒ9P4Oy Ai܇HK9ӽ4\7Z\nAGw65# $rݓeȲ/̯[/ǯצMArZv|r`O5/~%p!Kv9秗{^j][<ʼn>9.Cszt)0uq?:M%60~b·w=>>stream H\V t׼_wvb)j!$<HB18M'̈́ٙdv$DkQQz* RSBAJ)(H"EE0DX Cad$RLEJH5R#" iFd$t iEC N/Q4r P[hzZA2ځ>cY/-m;ww]Iyڿοٿf LM-p/8kՠ/( `O/JpKpOp!4Bq}PWКжо{ X!6Ucc  ۀbاE5I6|8> /Yxށw=c*x?߅GgWB!NBEB/We(f3Ōg1̴1bQf9$yyg^a~żlb2ۙf/9aN2+b v4;.bcvUZv;{=^f͉Pn87+&rSrnW~%8KsrrOpOs5ܫn+{{{;} (oK{i|%_7w]|_˿#GiS!7o c L~ /4 -BR0 ~aU!  '3?/0(.P & A3P@;c`/~^.8 "") `q8R-+N9bCQU1%.{ŕ/u-O~xTxA"~)/ 3pIpk3dxMx{)ȑ"/D6GG>\ DQ:*FFGGESYhKԈvGWD*QdqcKjak$\8~BXך1IUJuN:چ[ks!倊#O-).m== pFX1W1XFJI5ZḊ1dܷu.(+`y`46k/gv 6wǻcw}5Z"&*DIS ITIQi+RJmRTU+4j@Q:s?{wJ0̹={h4-"F#,Q1d$&ܘɤ&3+垏W<:( 1D:k '&xR'gsp lB:x-Xt:ӳ9)Xg5+BF, ˺M|#G<y>|)))))))))))))))) 'O ?A~ 'O? AVN5Ԭ+#y׽%^v2o4'Wo4 MFхQSSSSSSSӨӨӨӨӨӨӨӨ Q.D]u!Bԅөөөөөөөө S LAxh44A&DO@JJJJJJJFFFFFFFF]u!Bԅ Q.DNNNNNNNN]0a A=]V۸mCva(w|X.SAlFx.'s2D>2CX𪳪ȝfTQM><)Lzf?^_qU棟I2Z7wHc4;sn'hy#,v,7cv='{;1qJnvȂ.\ӾQS1L8M;_&CSpD'SV,\^qmd#L{2|sdN)#cFDB)Ғsp0S'dZ,%`98I9g1#5*HAIVRrrII˽v[fZ2&'-(;̤,37)js1ytn`@'(*Ŝ0w;^܏QTc(!AQ\zQu⻘g`ދ`(Y'Q&`Aǂ>7h^9X۰/cQZ.Q',i’XrqKXKkKϠeQ$~Pve(߉(GXփeOa<,?`EVXq+`e+۰"V-Ī}XV`V Pщ?XkbX;)*O-ۅuX*W`/AC6njQ T@4{~kPmTjZPӅQ| 5PV6Z AU~x Gl b(6}Ӹ||[4PE.ԟB4 .4@MSyx d7[8|A9  *_C @!pͧ| -}hy0bQl;ma;x5Յ]FV~ j5Ǡ6Av BOA_}?>ϱ{#vOg{V3 ƾоh:t vxN3 .x +^x{޷Y؏Xga$> |y3z+у+߃2w,,~I,cK7,sbTgsxVسb"+βҁ[Xi6 +UXuCXšI!`6'xZ+ֺv ko#PO`$̺1+'hA۲>\ʆlxleL,&濳ًWbÖil`&/r¾&la}b 'c;s;YŮ*dhv''hCxב3%ҕHO" ߛAHTkF':jMb}ˡcr8n"-G&q$}91sHEN INv?'H|9s vc!C$ؑ- IXIVHGFRKILRIGIɩS9uΜ^#HdOəN ]rfpn 9?pK.bK^RH]Hj!iCG.R<]˥\q'Wΐ#}yd##̿U-Wݹj KETJv'"'G\kVJ]ɝIn9\wF'gEy#! 7sc?(\Ma87fnS$:sk2 c=)؉Ps55f:5!ԤQS3O? /y񌗿W*u0- ovv8o S'䉸fl4{,J\QG>.cĢX<ar(H+%oic&mmki{TMv5bW։UhƋ&GY/*0[:/ytrNyb*yW. (DKtwk/6b)b{IlŮ ;w*ݮ}{׋vZNڋP-QQ#q8qrLqT-=HXFzႱ4mhn sR+!tiRMT귙׫mbe!)F25&zsK[1]ouYiTWz*㵻>^]>*iQNxgci 6U$ź!pS*M:D4pj[\LP2w4l)ڽV2٘B1ĆeT7ruFɣow[C箲oMVۭ_~׭*ҳݳUj(hk_G\**=Ir⏘gs}WF45#~ wdQ3K?[djha8'6}h*͛8%ʌTEJLjt27*@XX+W\zj Fo긱`di^ǎ}o-;|N3\'ѪE宮2~otjrvlt:499}MΟd*mpZϝNiu|]_fyf{_8\FΝ<ܨs-Bߥ&^a]9lViTWm#D"T˨QFVQ[VYeuT hHд APE"ڄ6q3IŹxjHzy}}{u68n&AL~crB*a^CFe8yĘ,Z~Oݲ" oJB{#i2?kj5vv cEWJuddXA,R ^uZT<1`'1BwmLAЎfMLh-`R1SP'6 !P A`8:Iy o;5WcMsb8H?C (O2 '1Xe($Q#m*Z&D%Ÿ$?Y$W@\2i)<1q1'<%1tX)TrjY(W-\8+̅:ζB`*B*brydDz ^ [wQ? DVkE cHikE `qo/8H"`5Z:>t/` l)(x֔:2;g ~乑K:pCB.\?$+ /D:s;LdVާ_yElWnrIwV2aQrV>aE诣l|MG3KdѸWrhmqc]D@ 5맖o@J ⱐ[`юR1M"ebTk "2rsܜ,JT )Jf;<36v` |MRLyg%Lha@ Բv] 6 P VX z܊:`67vs۶ͤf_P(عIѽFQgqD^4El nN aEti=|$5SA ;pGs`#C[T ]GuW [u%:F"{mP&(qUU:swTK)ہ+?@U0:IlOh1'D'I2k^OKW˄3'ٰm}OkZG`:!Ūl9ma> ,ͅOoǷAN '). O $1gaS FA *j`jHs85 r65_ûix0+æeI؟k ,x´Y+xޅ%?Y7W ?'fSQ;OhmX>hap4q T3{' bq)"|("$C;{Cc~!"<Ϟ bp|;\hp'nMh!ofq?=#ȩnjb]M:ANdS@cK/'.]ؕҊr+n3BS'QڊFL_)kո3|㺲[51%l`o5yd8;E%_$C].gE.ӻEo{×/Hu1V*tcM\(uLv`^ʺ'd.aCc8φ%oNOc%Owre 7sT': Z6=(iRejVjqIvЍZS # qEׅثNf$+ :b!0 0z74d _n<78׍ :|'4ꆃn-g2@~7F`n*4U&Ssb4]IUeIîvh EY"*4 68idQ&Ȫ"F (7;hH# q9㭞מ3s2U{wؐc9} @,O<ȧ y@,A霥>x0@o>0߹BQꄴHZF߁Wwx@ب h]}rġ?^`YDy 8QhxMB^ iPM$H4řl?E5s 0Fξc\MG$#d 0X( _{]W{z)JGlc/9lIW8_o$#O9|Jf1D]`N^`&(f6+reҫ- M8,3Áդ [p s%{=S~!’3#XsoXA^b׍rDT;\0|uijCl"SKOaFpfٽƝX]W Q/qYU̳G{O_}љG4΋oz=< ֕7R,|𹎤#zJ 7䞸b~I:2-n8v& IX6}]B/狅e /  r!r W[q:eeT#8JI؊Ÿ ~#V{DWR,NGNJ?8$1aK~#}P@Wck"o- MRU{ j9 55ZgӶ0&22aq5W5 :PMHd\& i O~ ߭ O[;W7 @),1oѻH <|Lqt6Q0H|K`S MeKw Z>&8§ iDN- "ν_O4?8fNYpZ*~$墦[M/`tqjA="wU0,B3p-1igtButW=!O-[uVjo 3<6xhiJ$E#{hXQDj ۃEMݭ=+{Z>t(JK,hk>yF5 :7mx\ >`8 >ؼ#Wk?,oۏ?|+3cʷD3? xO^W (pỏhm;4kB4'!¼.mv}rWdd\鲫1oƔo b|-fzN̫! K+|#n7X"M-S)Ҡ_ÐG/evHU :G!6VڏEܝDEXSHu PY Q4!j.\MN=ǨpJ/{Bs|O={z 3+ pOa &RU^'W\ˇ008ZgO{" :b(IDr#mzp|LVZ3UkF52 38@Gp|dfA,nKB4 \-L#'(wsB yv曙 ;&_puCvϙ\*"G8%c[Єtj2I&y&`r9kX# v !>d7,Y )-.ʝ`BuA7ԅ $T]LOq#\=ÚfMg]v?`: sy| U%7UHϔ$<Բa$y”SL͇^!v|[0;xx*53LEU- %'KH=wSrm K-G^~6#̅*Ef hD[sq>d{ Z4xXjq9[]~.Q*$Blp]`DZhP t<8 C@Hnz~⛽Ƽ !jy&3;$ -pp +kjD#CXA.Cz$ȭP+ yyK kf=w/)ڛSyƺJ-hoh1WϏ7' x_vY?)V"XP%DBҫߦ8X/RMҢsyIZeӲeRefYe67"1R6yǶ=$5& e;?jQ4Q}`E&ミ̖%DSgP' u=Վ`UC;K%"ᙺ;֌IJ1 ,:F =dal Sy NM@>Ť\whMS2#X8(zy̅RG+6D.8lpLA2}-1g;M. h)hͷd5qb/\i%knOTaH]{*Jxf7Nks"rG=0[ Q/e*M2 |`UO=D P /B4G1<OX_֤ZEE%UHơ^>׸ylweR)<嗡`P;khK6]ł?==ݞnn;\XצR%*~!! 賍jEEت\qnŢYTh=T¯Ewje13Aid6/#7᤯Jpk̾/e[835f35朶$|xӉ/BFB Y٫qqc!0vjh]`k4 a~1o߫ 2[qaEpR{ t]l0e FsYd6t=: # Wq}ۇ{n RN"43bFfD9ӌzPlXuW0g7]ZNΥ@LPuv~E(nڹŖ1V*}$&Г 'c#*7HKU谈½3_~Owt?ã-08<`[RYZ~]E?oos(^fSkس<]YyAThhldV ?XN{:46LW{TtJ΋E=uي6vX.//`@ N^Ds qq_?O'ɎK%U9 DqL*ggLlom$]-|!Y[ oӅ7G\ 'F!(NPF"4 3nDT]($4B9{$} z{q:tcdz 屐"_0~"*,@7Ӈbp4bh*L$e'˙S^ Fd޹FFyJ['>:&Y#qT|('"i_*+z#<Yh 2(.(`r#MU%0 pHcayEd˓pJo si{Mo ozpVo6_["=A_;yRx(vϊ`zid}]AQ\yw-SĢmUd7b'2'p( ph9fA.f@n2"Ȩ1fJ4꯭֭TxUU{z`g3 LFs^}h0|ox'J:+$2؃:%ٗ hw%v9"[}4P{ sZ<^zXZb{P):.8tJeϺz DO-`)FU+|W) W Faj*?_H%$(}1Lmv fzCm[Ll0y I Jod%ZwI:jT5XcdM\}U#˝EGL8^j=ifU".K y;]/B˃Y*Tqu)\{ɏ8g(< wxbG6[ϋJX0vWw_ǥk~`;ne^'vnġPpc~\mH{Ú$oG5oފ!qLOj[>~~A\~05flm%Q^o31'tnyhΧSϓ$O>&]t^tIm\5 [/˕JQ|1mUV%Z#bwM9ay /knւ/ah^@-sںFNKsMg &_)^)ny݌H Jc"FEפ q-8 ,בJTDtSX""Q y.$= Uъw4(|L@V&Obq060~[<"hdolKcMe_W"=z4bwz?R mZXy{h5/>GRuJba.4n xdeaq.{\ r̋C&T =${P)Cq37Sxh&zACwoЏ:-CZ7";4m![&0 W|~AB $)c/VK!{+w'!(k6 +b{XԮlt׳ &+s6l-Zz:vLM,"`$ۻ Et \5SM;)Z?UQȀ{2ֽB[G >g9ӐQV^F^VLR&*D&:>3< (\V(  Ԇs0l g_LN-^߆6>-`"(ON!y$qQsvC:&{I2%7#+MIL a)'‘.?!WC,<f?;X%"sENMOwk;gK\G[+GJ}8}bw(7`n wvͲ~Y)Una~sI̭cEprb;j..o Qg"D+Jiw;tIm-}ۼ#*:T ;0!`1ZP/ )jp-p(s.>x{ouD4݋SVc  jlDx{#ė}Ty'yʜnۋg÷/Ctp<U|#e?bHAkX دŅ*'ELINqyNBZa_)`- SYlֶ)\rR䆽<,ctNzuT0.B aIf 0XH`!^'z=2a;;a+հ_ꁽGݤLKr$Y?$8q> g?,gGW;Ԭt g!qݝ;-0#uzѺ`tFwZwT܏ξ|<%|KYg/eO.q.N!%E &܀Y!Qom͛ZΏwϩ4/9|B4"CZ0e&G>0<_h>ks1 Tx>¯=vAEsQ" Ɨ0$Ԏ:\Wavv3 ^O&d z!>0 sf%#, -!pN~_ՖbTװ>!lA٥F]iyZwn:W@҇jS8jcʊMETXfNChX9"uVyDm]mLK1O=;=IiQ 4m ?d*ȔF BU޹x*j98;FLg)JM)UH W *pkd sE0۠me;rr^!Js2 < dnbdΔ89SyYm4~>cȨ [#E<<e^Yg[A/(E c9c;LWCx+ljz+=Bk<׍LtL uT*(d#%҃4,7:c.ғ^ W/@;RK#qm#FWNl{Xay|y>'='3ik|}uv¹ںؔ42!CklPcCv[4/c Ӊ=(ك~9"gIJ8˫†ÔWm "ū{NazRfȒb,_+hQY 1Ӯ "WΧ]&đbMcaTŖCfA!I />stiƹ̣q% fJD nCB6vg=MndاĀX&kQ;G^I9r‡Q|l%{aGaC`D V:eh!Vuyޣ6rFa9a'kMVҶjgɣt*(}j*v4t}\KkZY+v$a*v7BkJ L ٫TmU* j*EC*M b27.m#؊hقphGDe7- " ȾE@iȈaiE1͔BJ|8e$!ħFW,aBSϞI CTwQ,n04Jl:ɲgV"@5|mƦ7l:.qE6wVSy3vY"6μgVp9^VXuu :X6[&'4.46>*a ]%ŰK|J79q 57h54̈́6z>[gr%kJr{r%}մWAgż]$5 Ij-@ڗ5ڗ];oU~Pb< 9\ {tYƲ# MHI1N>MR%^jc3ұ|4ȋiMl0E98WV+:%67`YA kqKՔmexT‚bՋ#Ѽx"QQ,ťIdҡe0vUc|҄j>-i^""iJ5P|7~ؿ;9-K ~0X2ZɕnJg~GIԁar!7z ѸUn Ga1sQ]%soN dfbZy[V "v/VkƃUS{P<`>GfR$R;ݦdhw[8_UɗIۥDf{4ZwxBNU%G@*u>օ&քD&ҳEr9+չPDsK#eE)̉6"N& |/-kfF^4~$fJ>0A! <>Ç!_ms{Մ=[ ?[7.f/>Dg$ w+n2w?fC)*MQV(8{Q"3ŽjU7fʣߚLIZdo)!tf":"Tz*X15$$D _uu8m~i %hD_ˠU}G{~Qu9&KsVLebAn,k7b}F\cM`TV@+j}Z]K*, tZpHTk]iDLPH/jBV֌|TIӀb eHY~8c4LFYlp+1:_a旒d5cky^bo&/ۗ냅)fڵfvJH-~ *q߫nn ϥѱEI'Sb8j< M DPbDf`F<'!(VGjc~c^0 ;Zpxj™T9Cz laƲhYL&Od~!DpւZǤt1-.e+7,S*cR:M"IcWB4IÞrVnv693丸˾uo /Toj\ũ4Wvm^DZHkڎL7N;&:7nށl,&1OmpzJAl'=+Ƥ&b}? [g "9x7\BcBY殢yK^gd #b3DUҴ~~Usϩ"#j<8|M(mmJSM. gw3 1>'^$n\`=!vs.q `1w&WUQ|b=hEV>#@ PbFIK*J eiQ!Qmj +k9̀SiSJcTnve u!%Pɳ?+I-2ؑ윓{ —s;; ">{vDll>'4RW/D6+іCSչe\uf쮿V^1^j`AE#@kTuW`.Ĭh7ι@95a&Fn4w]i7?gp?;>І ڈo d^Gw n[DmuXjy`kW/׹`w/ A1P7Aά ix ,ߚ[];ǠO6# Bp ջ˾G]<.4`? g/tONU'Ծ1 à?6CTG*ӦvHCN1OGp_uk8/>SUwɕ4]V#"ѻjӦvàHgujzgu3hy iKbl!蝖]i@֗F= Ym{ 6x.<~j`~,{HLp="g 3+c0m33wX+Zz6qa܃(Süb`k,n3ɽ.u.@Ȉ6t̻,P9tBU1.XrjihR<}qqal!/oc?-ݸ@,)3)#=a>fWvh3LlpLGsj9>aG"1 ޏ-(RHӅhJ9-p+̺Ƕޭd:nwYYuL]oՐP`D"@VFA-?Ot pQ{랻NCSy\,ZoƁ x`Yp'x%rDڈM0VFPVab %g32qcuv.똵?^ߦC{5u'ޛ])״po?V|G]uAM R 4lB |A>ъآVguu{s;sfrors~u(t;i-pIV~˛m_\:zl^5~>3a26o߁NwhkOޘ}AiYB0]Ʌc3~z]ڛEl ?0q]&oa^;_+݁mZԖ| u$ R~2}Xa=Cr/{oA{SGxn/.s^B?۫)j^7w_@z:6LzN.]*޵BC{ M.&M~=ޒz]+ ;I~.;',y,S^kWV BwEɛļ%y}/͵l~ =c :хwb>rjyԜZ݅;k4Hkɺ<"TbA>Nn}(<,H%<,C4"9+bOfn?;_Ll0~w{pvwL4#H8ZEL06. Π69Vi uU5NS`i&쎃OV~=cfy9فD@TEg,Q]/kbFExBPhmF #[q0RQD]El~@ ' HiwgZxP)d )8D$p @ue-7I9x2Im`1G֜%=ị]4Mv#[ x5,>,BKG[Ƨ&?dM \psVWX1|&>e1(Ѯ~n\KZP11'm^2Ml˕VqD-) F#>v$r?BYY8?2- +M#&;r 0CcBMOA>]Ǭ$e )hn:IzMX>,#1: ìF6i<-X̣R! *_TZ ng 1Gh͋U^ߢ^gWĖ)͠ Xy \hw_L7! kB"޳lC)̼D-od}ړwx Ӄm' qcjϕDҭ!.Z I6!',#bԇ ږN.>Zav?^Wb݆EQi5]:% 3cF x0փޫ)PHV#àeº'JHXU'qSlS`xfF%^/kԆMjڰqeA)x Kqv2Yv|$LTЁcGNE ÛaZ#aMG?;fYwf8%,('f<`Y念?19, ̦SjK'S "J&<_BzzNybܰ,^(Mx >B-B*4-FaH /vT=hT@X \^l+XB?&={.) Չ6NDs$NDh^DF>P#ٜ Xv{I/1dp" d"0la[|!@C%6$g}?鞶Z',-px*p^P Yjօ;+V?0T{6T㷮SYߺ!noĉ;[-( "؇Z'Jۘ)͎1QMMt[oYϞS]P"3 ejj=I8mVUjcϮmGuy q+20[9GT`0f9+VW(AiԜ ~FOe^l^,׈"-+_ŃKS[ϼ(}!πߧ➌r*^NW=ZRR蓩td}J&_*.O]pKO!V|KhtG9O;K[;›}/d H!z+ND  5+1 *8 YWc3_R*EfVRzahNE 1 D9$dЄH8Er)ʐY" 6V}7ҙ^WB$dj]Z隨 XIeLAtYV5!؝ƆٞF#!mm:TȵG)IED05*}sIou>[ztq#?ګ4(+ XcC/yE\&3j4FpP 8T\ @d]ATn#MPtd@Qy UsTƱj]}}9'mT jЦQpX . "bl*h , |.]Po͍j-|v/uzU;`,]f _0z>k{յ7np+kLFzB:Z]V!iiWtz}] gcr#2v+:ha@`+ 9 ~a" k#1LTtķx M щq߹PLѢ]^*^yͅrpgת b%fGqiwW >i+Li >|742O"e+~T#B{7$'e΁n8A~)hj!v{7h%EV*]|Ą7O+1GB8N JDx>S!v䄅PTe- M:<I5I#4$V$IݛbhOD e4r@ ᷮHFH)^ׇ!^ AG84 1kgg5FaÎQ``*R$e]=AuvDz0K9k։耼21l>C9Zʙ/9!2 1ēU*8$q1q V7'ؗimm6%#e&tidM=~]Ȟ!RB'7b{"&844zccu;2B|>mQh W4sH@ד[fZ4ޚˑ?(u/CklRJilVEGj3 d )g9qI+,`8.+W8i4ڒAj>]&\xE>|HłPK!V*Ho ‡T9LmΠ5˞Ar[tyjR!G县&$V)+hj`ar O /I#}"4$ "T;:]d [ nr>Fѷ&0d4/gf?N_'R[Z!԰5l(Ϝ{`HNˏ*ghh! ж:(g(DU$qEࠢc  (&ޛ D7 e)o$YzTW)Z~ N`Trk,j kkw߈~ fN!qsEeeY\ "B9iWbu9Ysiſ uL FXqB>F{H^W. qXs{!G*gQ rA,Zr Wd;3÷ΕpGe1mQn#{Bߔ<0\n/ uTry ]; :M7Eut\q6O"3IW[i04Z'cѭb[* 籌ǞWSKU"zڨp[pѬHYbQNMKa*R[B9+p;ᐱ.n^H SAAZ ^$TJP!?u_w=NqQJ-SO wD$p3PHw3L n*~i[o _`6ƅV!vjjE7Zg񦐌7Z[.ku:>Z@UKEYG$(R(vtS(Qj hu龙ôsn]:r=>g}4O"S=ws(DVV'yt%ԢJ ^hLNv]2$>iM$D7<$yN W7p2xeUdےBM$ ԞRn`ktKnW=GԚ jҕ RwiY@4S5mkCC,'3HԋI K {*#!ؔ[@}EܠznwacE|q?ܯ0'$עoҨ|.[>G˹v2f#=QB6`Dg+j.c4YHDe: mVҧ+D%` 4 Ks[4;y<.('KcVrAkZF Z"P b7[ fL/a ^Ep .Q SO`cbkk,tRcRbJl(F@ȶ_ZX#f'j}BU=~B㡦k~mA_ (*s {?+-.7Q]>f aK<{agx0f'SN+IܤQ ZF"GǽQ`n,7lbH~'̫H *'ކ;ˆڷ!li/4qGrmK FUJ||"LԚr6XDFJ(sUs`fm"r{Xnf$2_וb9$~oe7*S0 d<\eݾ?.>_cc=}2FɔY;켞|VŻ.<7eu_/uIVjIAJܝr]KU"'(՞|ag0f'{WiPk_P|rFLa 6a7zd#>2PҪh i;ѤpÀ0p&;Pt&QF.grI\Ɛ/}On"_&';Qᙟ,c%/^Edn'BsBeF#ӥ>zfXy zD&7covb_p@|]EV X] :!BDPFaXht")T`}4 džAL;8&RvLVosNK,:>GWy!T?9ټP .mHMEǨa?$U$R˸". ]IJYj±cx(]֣IITrGEe9I{ذT(O_ګ4(+J&84Aaz;MB%ґH*?ƶG+Ϸ}|S^[Ewaø ;Q: vA3?XtH_cO}B%_ts_W(;D?oXB4 -FMaQIeb FWȘh!ɣa4kr6'֒T%/hmd}XMfD'dˏ0/Q ;'O){zgj`YYyR!S_浪5&4T?c Sd#[浳grp)i QY_hzEctpdhD(G޳ykOO\^`ȣdrVA(xS,ח! 0nH~HI=  9>D--B+vsg??(PY0{m$b5suxܠ-W h y56F]<+;|yJПiE"b}T@AdmflkyL?Z 1v`;& Dr߫$?|Q)΢eBG+8``8H Q;zCϿ2!\KŔU[GDSSrW]g{U wROӔh4P6QFW#bu6|8oByS"Wi5є:} 9tnt^sfj7GUw648.~IKXGogh+CXoR\MpT\˳^ţ5TҸ=Ly} `NRcI䝪KN~B 0 ]ӊwV"%685o 1~F.g0hL7QSM]y4#ӧX4ޞ[E\H q 48\zϩHg +PRϤPV3fY]a>G8(룻`[$k`Ψ_Mw!UYVWU4c4 dϋ.asF;rOJs4Q ّR=n}XX"DP a 1D! Ihގc;/2rIu09C4,{i=Op5[FFn"z,z?rUi蔤*80/Hg#[cu`8SMDhK'Պy^\kÐoAMe͕fxK|ryqDCOe#j<}S=}W\^vٮQ)c\UJY vrTVfv{rRYDm %v֬6Go>N_%V1;v1w_>bN4 i'oh{Z'6Oh=i{*EqZKm~\'V=P`ɓB)HK0VM^t}>@>sLu]3R{}4b曡#Kmxf]5`tšx%[obwj##8v? awC f7΢:$.pBsހDl>!hG$ ыќ$v<ބ`D Y宫9m$fB\\-a?^//m+;YH46VDJF]5 ӊs偙\3Mu VKs0KDwǖxOxUkAM5{%lb|"}EaχTa}mkn0F/Y#,` n7I0Is$yHBNT+c|cXv:M,ZZTrQ=+=S{5ufqp/g{٘k:>ve+n[BҭA "/*/MWE@A ]Vc잛pfDDpqG==;ww% lQ^..qr\a~悼PG++S&G܃qF; u۵x@dʄŞPlxW(+BT)ijQ;q (@~:[7)n N}9(0/zWzf\F~z|I_ 4uERq&>.tAZ{yx4# e`hFVB.2aDuIwRGHXv-^%5M-!_Oڣvv)#sEsqz;)tw:F_bctINAQ2_ȕ2L,rp'n<ǰ5 |_12'u妚7N5I1XmL\Hw?=[AjCÂ4+}jG2r̳ 82[ZD~d-H᭫ҕoCU3<6я;PdU%جN!-aIf $Q#,a1ƬQ\̝hʒ[`!gɮe4>(5L{d.0N)ڰ/I֊hr+ZNl$ NW'T pOV t*,y?j97G`&а vb6/61Ƀ4_tk a~ %4کfhgɓ< ڌCs 52X>h@H$ACd pŖqۿ<#<*7HXJLK6MoNXo֫=tdge'k2RMH"]MJfL.!vm+ 1%!*J2 nvFcηyη3s8ggZ.St0֌8R#^"oE V[G; uT/~u7q+^d/gr*k{ܢh*-t@8יž ˘ܕaz)O(_0C9II^&-Cݏ&÷ cb ^M &)9iMh=*p5V5$+05É&x yH~r×mUEL%G,%NqlQzΉ7M]Wmܚ c 8j;zaJ6@jBA/=H،NhT[HW5Xj6ʠ;H20DhO{?7,xl\2iɫY1)٢׾+[GA=+9M @HN<aCX[~asa%2`$UMI{!ZM#?Nr"l`DS`O>A42fmvks;UQ0 3$̐q^yfs0יJzsKra&]CpXG0 jZ?]}=Ba-Lm=e oNWA@+J"G2uC ƙa-;"< P/P CJI! :GCچX4Iz2T'(a:^xW`hpFa#$?O$7ldH8"0 fvB*9[[M[0﹅KujͱBNjIXzJ,r, ;eGjwpGΪ=ƿ%K_gq}TG8Mp[5Oáfbxk (C5pj·hUk AQUTST1_UЂ:zi7DCn7_ɨ[m*qR=d MqM#go?`Kٕ_MS ʄW].y,fң;"H6uy S8߆Z7 [z΍J5̼,ZSzy[PР,>웋yKf#U!똵_!VNi.!L<LtET4w2ԛ+]zXur,9^Nfe$g>&R[g0}FۼՆnb5%ߧd{`,fg'9!LjU߈Y <$D3 8s ।KQFcD$KaE?8=i R`7S5JM΅]IMdM=\A f1r B"ڰヅd+}\uhҨ$L8mU0nW\]EEWE ( ""DdQ#ƠM5zKΙ]3'vWn}_]u4JnnY7DjLh0"DT2mI^p,x17xi1Fqv6D RSSuYHEyk^8 yk[WA0ኇ|8FRc,Дxw0N҇ԋR㙈0rƲ??}!)47:j^c'6#k8wn@zڸ}H/Aĸw2Rъ5k5t®> .Pf4d KUſ2"٣ڥd,}DgK"6?`9&c[Bn2:Bo9P=sVކ|5>a>!C; &ݦWy3B8sSŕ }sАesLwd3~Fhmꆵ%2 0AUrlj 桩r0I8D75$R&-0<議}?d04) k"Ck;&#y4 I4VGšH LpwBjɈt, |XʊHDߺ_UEmLkģCs'jrd)bSQ}X|6bU q) 9V^X4kȚ6ҝ5ePduYS- xǩ"Tr׀w՚B(d2Ki֠ld iʼ;y.l-[䧤{WHARYVF#Vx`$eD_[gv?ș4([svX;!ۏ--1Xhc.0Fp@QK.!>5뷠"4qG7ǰ1) !ETTp2zRO !|& Fj@j>sB!pBy {axn߻eMXjBN.^"৮ӿg:~pL=;\!+t1cvr6PV ˖Wd5un~j.,x œcg?+>*+OQnJoCٴ ݺ]F 9burfI 5=L} #<;P|/GބukQ1: *EQvX%2!`hQŅa e?8Ev8T ꌶ7̏/*SxΜ9+y{? GBR2|Q$PN8SC6MJUJH`C+ v{;MY[+-6NT3XJU0Q[Zwlagw#YkWՏ7VDP9]u/- f}hcka2c"*erˆ7N8%d4|H<爮zW EUFi)l%;,88UO[[[ 'ڡ6H388*f!CgWL, >yT0Z΁bs+bi6-(KЯwJ"s,ȺȤ Z,XI$>A-D5N!>6 LJAP(~4Q_fUn@<(JFYHY*2ryno_Zǟ`81 nBӓZбTeWg2١}GZ8j/v~L81 wZ.րCUe[1.9Ȧјg;2硉gA"#B尘k "7w5`6Fy"*戹{ixE C9jbSqYtCrGa#*//ԝO`(Ln3;ڀ%y6>%Dw$'_:ᒾsn$"t$N |? QDDz;\ JwZʵRLMV'#qehC%n|,&ơ(C'@ᐺL0`t# ׀ +b Y"W_aQ3(~7 amõ[)}k@S^UYSX] g7+ ܾw].{ TtYP h?fd'7!5;6\݊YGc>?%kV O23Uﭒǩ:ӭm~#5l #  d.n񒐌h'@HyĖLB_eߩ OXf#ZRάHb&g0n΍C&QQOmA;ߑYe5{<6CMCДKQN<&]-K*I"ȳu^ DC3o|_@ryccNlZzSe=֌})I'h*ӟo!9H-hbse2/yh}3HaFS/Ӡc?h `hNb~: 'kx^ҨBYonyoZfPoXZ%{2g %D \0g ߜ7H,dD<_:Bĵ`jp,^$~3 Zb6Dza#}8P^}v5x\Td:\Ozb\AfboɦiVއo uWӫW E}MAZ+Q"{yXo7mE#Y~Bc Z4'[3fdЫwPWEՋaz\uN:Y4Z>Nq`3  Y #$AkOa6ШM M܁%>p.Mefh?</O,"u`):0y IpC= aq uF/39lj9sA"+*"]Y$ $\. +\Tr)`@V4*]}ѱ_jwѿ2g&}b =5xy.4M)y.yk4`6Wd&2,5zaӤ\ f.m)ڨa">|W?̯ x*I1{> cx 4~h?{7it7 _[Ghvc~1Y%GK8*;. r;dA=M7VcD l 8XP}J5׊-\q38q3==>~?[uOzʒSԓ'beZE 4cǼᓇ` '&>T72,4ŨbJQXmmV`R`b~xQّʓ}'^]pCmDE^愈 :d<'LiJb k$ ?WM-snnS]N)#% ~z%U 925ZuB9Zhl~}5e((<_zSJZ~Sl2e÷ ^j ܇g+NUk7u h}=S2ByfdžX;l2kCOߛ+(D1 %Bd o>q࢜M|C?8̱ӊ+7UwI5&- +ˎ ǃFbEhXrrEY(II QSv::_=~4N:iKX7 Chvt`C=QkfwIMG3fӿEj!д9˂ѦzBڔ)oeQ= !%в~XK̠نp J Ip _v">ɉkt?hu6\U/oX[TSتRSWFqFn0#9jI]v^xێjuM𚜽NBed 0-_%?Kf@ŨmPwarI76nSoetT% -4o>^uiAD%Q[ؚ\\>#C!:5G1  r$J֕JHj) L.ن50R*ːgoՖ8Ik.!vՆ\12,GXevQ  f.c(]GL@v_TjU+&Hg>%(Q%"5(LZEfEF9; cl?lĀm7XMЎI#2䀬_[a&z3akD9o._XN+>Yۋ74/b;hxO&B0i2r6İɗh7_JtwLOc,^N^atA~q"J/~iDDUCMt\;ٸlMsJrJUBRA< _E򥬜=}ARMW|(dАhqtV~=À]Gq)[4V\IYŌذخS^B2#Kq8M$ G'gԬ4tj`5I aΧEJ?ҤwpD! +ņo֤g: (.셤Yrj8)\fr7sRk1 (ªm]Zm}TRB $  (!(<*7@|Tef~t߽nk3;o>GLIU j`udRpxIpi1n?ΦoOyw寳W~Oopu.W JD^#Q` +z`C:xEg(ccB1->TqޗVK0lZu2-CpK+ݓw.̛Gy`ex9c;hfnˍ@֝i)8qs/(&lk\:}*m-7y%zvX?xŸ;r"W)`;^ܸa2dp47f82w$)gLy8I7,<5EE34t[O—FG3$65ĉn:L6񩩉JcJ#v+碾;.X'9*HAZx#<*-mOYW\t!*vPd AD9(S1n1#:E壋ѻpl.ܻo=!H9Zr3U/\|3.#L>ͯ1x~F}&.—.6D>H0B @$X@PaR6H,?+#8zl{faΰ%d3|G2k LW3"l M=7TژƀގěZNu;fZD>jEjē#L;9rwA#~G ^>=H1|>>H?=hh4"ihBlPߺ2?uG<=D2X ӱ2A_7dߵ'k/Jw'Qŕfu3\e޷dI2ʄ@zѸ{4k'Ng@049-i㻋rm}1Z wsV0í밿g.e(.Aѫ/sRI}F\0~淝BSMZsU.;U0 =dcX[ &>=>r$"H;;۫gFlk3+}9{`95S6r4nt(7u)P0f.}U>kϚc] &^Sm<7n\W D[^#]a2Z;O0n|)(wV0pϛUm`zQ ?͎MnK:8OU=|3cDxcC! {:iI itJv {PuIn;3P!Z!1b~FLj(#cafmö\C%s$Ka2DKavam+E!f` {__T Nt)j^:ۣJ*K#ó%\ K\h, W>r ܠn< ㇸ$N$ W+26cV.;" ]ƠrU&1(ݽ8l{<v>Ssh\]6rU,X_čc-죁$*1. W'I Yo5S\P!5VH"8VrM/ ko3bGwn̡VK**‘l4R>x\Ƨҩg_Nþwyڏ5sOk} e]-ϏCKE(*NY*ܬ5%ψRՑJ/wi6֑FjW֗/Ēhi"REֽ ?g |ǎ]By@welCrf< 9%:͌ΈV@9Sy6b=%^HJKbcshmn+ -kjzPNBΖB=!bZ{-to%gEԑs"~v3#PͣG9EC1dz`Ko%&-bȀ1LTIB#ڃ0d՘F-vE8XFN66 U. 8`x tX6@] Vq85w]8L'{wN#f$d6Ty^AVB؃ȰÞ1'׎^l8mv"~Fo W3szs7;VBN$< 7E8)TR"XANM|iԡqt|cёYQnH=zsX$|X EoH &C:'_/p;Y*J#[Vf|8-݂a;rW@H\ -x2S}DtHyCzYf'z1gyZGeٓ ꛽ QoO(J^#ם-xFyʅ"30Hb߁?@Z UVr&:^f 0kn^n067q 11ۗEC`^Xf+z%%MzM!8g|Xt558_֣[f@)zdE)fw=;JbQsÐؙ$:h*+k}E'+|M < EbIUwѺ_akf7 ƴ~imDk)4=EVr&W4Iò@_NH!0yKмjKР)XY|ȬGmmEV2Il`,֯qǵ?K3q:86$|A\dl?\NP 1&)e(ߴ@@rJJܯFÆc`xGDJ8oډ7iWS\.Q狻k ^,KObJ?RZϢm#=#̽ C:MxYn D%#L`:'WTJ\MBbܗ1_ȼ}#6/,&FMSM_-Z~XRdTFyF}/I[..BU Xy$8H&*g8ʫ@M-1O}HŻC\Y8D~_P~vMn- >O֖dm%GYD%ڥ!oka~ k!-!/nn,qy%x-7c![b8!V#i\!?/.YNy\= Q"q[>C [Yu2'%=/ЬQgf]ZBUЪ0k$)qF"r{}l:_BB|l'#GA6wj Mq`2Yg%.0o WJo&D-\ed?c+U,qVXO :`9<*@GL{5KXnTCֱ$ad(Eu fz WVX9lYGt:!ce)Jjj]Jqת4G~aŮ!%Horb^4PIA_hU+"F!{ISH^>R|=aaxxalXv Đ]\s}*QۣKL8m`r>$5!08M:?{(2`*80Gl lx7.8z9UH|b(n+q{X=(Z=54mxˮ |28U5^Gn//EnԱ2JV--; ,z8_'hmnl؉@_jO+Ot!<"|`~bJWhp B^ EQnj }0!-0~J v8{I_^[*=%+ح.* eX|e\?3޴;L+A&1IR QuuG/,|-b0#sFcl+CNItߴFV-Ls -{6ScɞN^g?be %Fzl,,e+1HQelZ6|Z+&%f`՞2BIsU*,=ȁ|ݯC/'3zf#k{vS }[ɗ{!7MKaA>.P& ^FR'_k1ʶ38v^U K\%&`Hd-T@x\wȹN)Š);ee 9U}MwvnOKja!K/PC.R'D&Bu5 @jUeGy#3' lnմ7hyo1@,8V!,-dOg$[b -rLimtMP V*_SF?2#,we|$;>; 8Lv/g&%G1Ў-Eh 0&0pJEEij,َ BS@_wzME:GH 1'm \ݑ8Y!҆5#`^ȏ}'1A M?GCR?Pk'#@&aYM%& EMX-?xc!6>%Ec~Dq,p"QAixx+VT*q$ 6#3mGYrX endstream endobj 21 0 obj <>stream hXr8~nপdN</qf 8pq<5@RrYna 7^(^i"X)# t1G=!#R<7q"|)#!C|(PkMAvJeRYlV%Æp]YU861:SU]\U9?l!&=ş:a7v/t6;sVgZ5B @^qX ~cLң[5̓Copƞ(Gn>o4gJtJvOeYAxr6UYM4MMVfIte z2{s|pw{oGLɱ%0ƾ·euӞYAM[E N^nu8m88{$+E4D$ 0/ ^w GELj}?ƾ0`c`c?a<lnx"?@@vCg>53 po>tY}x1ּ A0I.;dZ.t![Yq:"z?ZRQ&䪠/]tS ]7 QZ7fe*֨2 tk(#־{Lk(By%ߖU)5jMUkE֚UW2{dOGQ0vٷ\7 /iUkN7m3o% s~w+KnGEϺ5R-jw ,K: IZ-( hMI)JhC_Z葾=7s)vCT6'N3؊NUҵ.,v7) V^YV \?B =nW[!13 Yl&aJ{{eA+ ZV#heA; YnASZ)؃e/YU{Ģsm<*`& *c6VmR]3YFz1N:ȰN_de|pױZn\y1([ڃӧײiW,Q9W2`W:;rfEe\Y=<6/ƘOT5P']5Z̭^jV}fَ?}|["zb -=|.GQЂFҖ偋2Z.s%Wh1\@PnGCC`ވgy5yrya8Ejνre\e9dͱV?q}zAB_N[dznC3,_ď!'5|SOFE5nh$˜"A&(W꧖ v:|g->JY9-l\ů 0玬 endstream endobj 22 0 obj <>stream 2 J 0.57 w BT /F1 13.00 Tf ET BT 75.22 778.46 Td (Hello, world page=0.) Tj ET endstream endobj 23 0 obj </Filter/Adobe.PPKLite/M(D:20200323134641+08'00')/Name(member: 519FA33F-EB4B-49F6-AE61-C96E5D05433E FB28BB74-0859-43E2-B45B-A50DCA0EE607)/Prop_Build<>/Filter<>/PubSec<>>>/SubFilter/adbe.pkcs7.detached/Type/Sig>> endobj 1 0 obj <> endobj 2 0 obj <>stream 2 J 0.57 w BT /F1 13.00 Tf ET BT 75.22 778.46 Td (Hello, world page=1.) Tj ET endstream endobj 3 0 obj <>stream h|n0 _O0P PV 04\.hVCG!$E1^b]-/=|@_]E^9mfP͊0<*' f3M cS(\@Dл*u?]DKoЧbx. XMr E ToxbXA+ d9:󫶎CQE4؜R?,o6BgH>.쵴+hdjęg iP冨Dp)Ȭo8hJK|l}s?lnh =m-.P ŀTNmW ѷy%|/..'p9R;Dhv->stream 2020-03-21T18:57:44 2020-03-23T13:46:41+08:00 2020-03-23T13:46:41+08:00 PyFPDF 1.7.2 http://pyfpdf.googlecode.com/ application/pdf uuid:55bfd25f-fe4e-8c4d-9d8e-ef6c11955e3a uuid:25cd9a1e-b0a4-524f-b975-63e5fbf2156e endstream endobj 5 0 obj <>stream h24T0Pw/+Q0L)64 )bC* RS # endstream endobj 6 0 obj <>stream hTɱ _qKݩmBY* ݂Dܷ̐>8½ywKM4jDkgSƒ2f}HRi9{7 RUk渪y1_`y# endstream endobj 7 0 obj <>/Filter/FlateDecode/ID[<7671C61FC4FF65086CCE130671E2C66A><19D64D7E48DF47DF93327CFD5C8AA1A2>]/Info 12 0 R/Length 59/Root 14 0 R/Size 13/Type/XRef/W[1 3 1]>>stream hbb&F L@VddH Dx #d" ># endstream endobj startxref 116 %%EOF endesive-2.19.1/examples/pdf-make-wkhtml.py000077500000000000000000000007731504236674500206140ustar00rootroot00000000000000#!/usr/bin/env vpython3 from mako.template import Template from mako.runtime import Context from io import StringIO raw_html = '

Hello, ${name}!

' data = {'name': 'Tapan'} pdf_name = 'pdf-wkhtml.pdf' mytemplate = Template(raw_html) buf = StringIO() ctx = Context(buf, **data) mytemplate.render_context(ctx) html = buf.getvalue() import pdfkit WKHTMLTOPDF_OPTIONS = { 'page-size': 'A4', 'encoding': 'UTF-8', } pdfkit.from_string( html, pdf_name, options=WKHTMLTOPDF_OPTIONS ) endesive-2.19.1/examples/pdf-make.py000077500000000000000000000026031504236674500173020ustar00rootroot00000000000000#!/usr/bin/env vpython3 # *-* coding: utf-8 *-* import sys from optparse import OptionParser from endesive.pdf import fpdf parser = OptionParser() parser.add_option("-f", "--file", dest="filename", default="pdf.pdf", help="write document to FILE", metavar="FILE") parser.add_option("-l", "--link", action="store_true", dest="link", default=False, help="add link on page 1 to page 2") parser.add_option("-t", "--ttf", dest="pdf_font", default="", help="set ttf font for document") parser.add_option("-v", "--pdf-version", dest="pdf_version", default="1.3", help="set pdf vesion of generated document") (options, args) = parser.parse_args() doc = fpdf.FPDF() doc.pdf_version = options.pdf_version doc.set_compression(0) font = 'helvetica' if options.pdf_font: font = options.pdf_font.replace('\\', '/').split('/')[-1].split('.')[0] doc.add_font(font, '', options.pdf_font, True) for i in range(2): doc.add_page() doc.set_font(font, '', 13.0) link = None if options.link and i == 0: link = doc.add_link() doc.set_link(link, page=2) doc.cell(w=75.0, h=22.0, align='C', txt='Hello, world page=%d.' % i, border=0, ln=2, link=link) if font != 'helvetica': doc.cell(w=75.0, h=22.0, align='C', txt='ąćęłńóśżź', border=0, ln=2) doc.output(options.filename, "F") endesive-2.19.1/examples/pdf-sign-cms-hash-sign.py000077500000000000000000000061101504236674500217610ustar00rootroot00000000000000#!/usr/bin/env vpython3 # *-* coding: utf-8 *-* import sys import base64 import json from asn1crypto import pem as asn1pem from endesive import hsm import os import sysconfig os.environ["SOFTHSM2_CONF"] = "softhsm2.conf" if not os.path.exists(os.path.join(os.getcwd(), "softhsm2.conf")): open("softhsm2.conf", "wt").write( """\ log.level = DEBUG directories.tokendir = %s/softhsm2/ objectstore.backend = file slots.removable = false """ % os.getcwd() ) if not os.path.exists(os.path.join(os.getcwd(), "softhsm2")): os.mkdir(os.path.join(os.getcwd(), "softhsm2")) # #!/bin/bash # SOFTHSM2_CONF=softhsm2.conf # softhsm2-util --label "endesive" --slot 1 --init-token --pin secret1 --so-pin secret2 # softhsm2-util --show-slots # if sys.platform == "win32": dllpath = r"W:\binw\SoftHSM2\lib\softhsm2-x64.dll" else: dllpath = os.path.join(sysconfig.get_config_var('LIBDIR'), "softhsm/libsofthsm2.so") import PyKCS11 as PK11 class Signer(hsm.HSM): def certificate(self): self.login("endesieve", "secret1") keyid = bytes((0x66, 0x66, 0x90)) try: pk11objects = self.session.findObjects( [(PK11.CKA_CLASS, PK11.CKO_CERTIFICATE)] ) all_attributes = [ # PK11.CKA_SUBJECT, PK11.CKA_VALUE, # PK11.CKA_ISSUER, # PK11.CKA_CERTIFICATE_CATEGORY, # PK11.CKA_END_DATE, PK11.CKA_ID, ] for pk11object in pk11objects: try: attributes = self.session.getAttributeValue( pk11object, all_attributes ) except PK11.PyKCS11Error as e: continue attrDict = dict(list(zip(all_attributes, attributes))) cert = bytes(attrDict[PK11.CKA_VALUE]) if keyid == bytes(attrDict[PK11.CKA_ID]): return keyid, cert finally: self.logout() return None, None def sign(self, keyid, data, mech): self.login("endesieve", "secret1") try: privKey = self.session.findObjects( [(PK11.CKA_CLASS, PK11.CKO_PRIVATE_KEY), (PK11.CKA_ID, keyid)] )[0] mech = getattr(PK11, "CKM_%s_RSA_PKCS" % mech.upper()) sig = self.session.sign(privKey, data, PK11.Mechanism(mech, None)) return bytes(sig) finally: self.logout() def main(): pdfname = 'pdf.pdf' if len (sys.argv) > 1: pdfname = sys.argv[1] config = open(pdfname + ".json", "rt").read() config = json.loads(config) tosign = base64.decodebytes(config['tosign'].encode('ascii')) clshsm = Signer(dllpath) keyid, cert = clshsm.certificate() signed_bytes = clshsm.sign(keyid, tosign, "sha256") config['signed_bytes'] = b"".join(base64.encodebytes(signed_bytes).split()).decode('ascii') config['certificate'] = asn1pem.armor("CERTIFICATE", cert).decode('ascii') json.dump(config, open(pdfname + ".json", "wt"), indent=4) main() endesive-2.19.1/examples/pdf-sign-cms-hash.py000077500000000000000000000066231504236674500210340ustar00rootroot00000000000000#!/usr/bin/env vpython3 # *-* coding: utf-8 *-* import sys import datetime import base64 import json import hashlib from asn1crypto import cms, core, util from endesive import pdf class Signer: def __init__(self, cert, sig, tosign): self.cert = cert self.sig = sig self.tosign = tosign self.mech = None def certificate(self): return 1, self.cert def sign(self, keyid, data, mech): if self.tosign: assert self.tosign == data self.tosign = data self.mech = mech if self.sig is None: sig = None if mech == "sha256": sig = b"\0" * 256 return sig return self.sig def main(): def attrs(signed_value): result = [ cms.CMSAttribute( {"type": cms.CMSAttributeType("content_type"), "values": ("data",)} ), cms.CMSAttribute( { "type": cms.CMSAttributeType("message_digest"), "values": (signed_value,), } ), cms.CMSAttribute( { "type": cms.CMSAttributeType("signing_time"), "values": (cms.Time({"utc_time": core.UTCTime(signed_time)}),), } ), ] return result dct = { "sigflags": 3, "sigpage": 0, "sigbutton": True, "contact": "mak@trisoft.com.pl", "location": "Szczecin", "reason": "Dokument podpisany cyfrowo", "signature": "Dokument podpisany cyfrowo", "signaturebox": (0, 0, 100, 100), "aligned": 16384, "attrs": attrs, "newid": "1", } pdfname = 'pdf.pdf' if len (sys.argv) > 1: pdfname = sys.argv[1] try: config = open(pdfname + ".json", "rt").read() config = json.loads(config) except FileNotFoundError: when = datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S") config = { 'when': when, 'certificate': open("cert-hsm-user1.pem", "rt").read(), 'signed_bytes': None, 'tosign': None, 'id': hashlib.md5(when.encode()).hexdigest() } dct['id'] = config['id'].encode() when = datetime.datetime.strptime(config['when'], "%Y-%m-%d %H:%M:%S") dct["signingdate"] = when.strftime("%Y%m%d%H%M%S+00'00'").encode() signed_time = datetime.datetime( when.year, when.month, when.day, when.hour, when.minute, when.second, 0, util.timezone.utc ) cert = config['certificate'].encode('ascii') signed_bytes = config['signed_bytes'] if signed_bytes is not None: signed_bytes = base64.decodebytes(signed_bytes.encode('ascii')) tosign = config['tosign'] if tosign is not None: tosign = base64.decodebytes(tosign.encode('ascii')) clshsm = Signer(cert, signed_bytes, tosign) datau = open(pdfname, "rb").read() cls = pdf.cms.SignedData() datas = cls.sign(datau, dct, None, None, [], "sha256", clshsm, mode="sign") if signed_bytes is None: config['tosign'] = b"".join(base64.encodebytes(clshsm.tosign).split()).decode('ascii') json.dump(config, open(pdfname + ".json", "wt"), indent=4) else: fname = pdfname.replace(".pdf", "-signed-cms-hash.pdf") with open(fname, "wb") as fp: fp.write(datau) fp.write(datas) main() endesive-2.19.1/examples/pdf-sign-cms-hsm-certum.py000077500000000000000000000061511504236674500221710ustar00rootroot00000000000000#!/usr/bin/env vpython3 # *-* coding: utf-8 *-* import sys import datetime from certum import dllpath from cryptography import x509 from cryptography.hazmat import backends import PyKCS11 as PK11 from endesive import pdf, hsm class Signer(hsm.HSM): def certificate(self): self.login("profil bezpieczny", "9593") keyid = [0x5e, 0x9a, 0x33, 0x44, 0x8b, 0xc3, 0xa1, 0x35, 0x33, 0xc7, 0xc2, 0x02, 0xf6, 0x9b, 0xde, 0x55, 0xfe, 0x83, 0x7b, 0xde] #keyid = [0x3f, 0xa6, 0x63, 0xdb, 0x75, 0x97, 0x5d, 0xa6, 0xb0, 0x32, 0xef, 0x2d, 0xdc, 0xc4, 0x8d, 0xe8] keyid = bytes(keyid) try: pk11objects = self.session.findObjects([(PK11.CKA_CLASS, PK11.CKO_CERTIFICATE)]) all_attributes = [ #PK11.CKA_SUBJECT, PK11.CKA_VALUE, #PK11.CKA_ISSUER, #PK11.CKA_CERTIFICATE_CATEGORY, #PK11.CKA_END_DATE, PK11.CKA_ID, ] for pk11object in pk11objects: try: attributes = self.session.getAttributeValue(pk11object, all_attributes) except PK11.PyKCS11Error as e: continue attrDict = dict(list(zip(all_attributes, attributes))) cert = bytes(attrDict[PK11.CKA_VALUE]) if keyid == bytes(attrDict[PK11.CKA_ID]): return keyid, cert finally: self.logout() return None, None def sign(self, keyid, data, mech): self.login("profil bezpieczny", "9593") try: privKey = self.session.findObjects([(PK11.CKA_CLASS, PK11.CKO_PRIVATE_KEY), (PK11.CKA_ID, keyid)])[0] mech = getattr(PK11, 'CKM_%s_RSA_PKCS' % mech.upper()) sig = self.session.sign(privKey, data, PK11.Mechanism(mech, None)) return bytes(sig) finally: self.logout() def main(): tspurl = "http://time.certum.pl" tspurl = "http://public-qlts.certum.pl/qts-17" date = datetime.datetime.utcnow() - datetime.timedelta(hours=12) date = date.strftime('%Y%m%d%H%M%S+00\'00\'') dct = { 'sigflags': 3, 'sigpage': 0, 'sigbutton': True, 'contact': 'mak@trisoft.com.pl', 'location': 'Szczecin', 'signingdate': date.encode(), 'reason': 'Dokument podpisany cyfrowo', 'signature': 'Dokument podpisany cyfrowo', 'signaturebox': (0, 0, 100, 100), } ocspurl = 'https://ocsp.certum.pl/' ocspissuer = open('CertumDigitalIdentificationCASHA2.crt', 'rb').read() ocspissuer = x509.load_pem_x509_certificate(ocspissuer, backends.default_backend()) clshsm = Signer(dllpath) fname = 'pdf.pdf' if len (sys.argv) > 1: fname = sys.argv[1] datau = open(fname, 'rb').read() datas = pdf.cms.sign(datau, dct, None, None, [], 'sha256', clshsm, tspurl, ocspurl=ocspurl, ocspissuer=ocspissuer ) fname = fname.replace('.pdf', '-signed-cms-hsm-certum.pdf') with open(fname, 'wb') as fp: fp.write(datau) fp.write(datas) main() endesive-2.19.1/examples/pdf-sign-cms-hsm-google.py000066400000000000000000000045271504236674500221500ustar00rootroot00000000000000import datetime from endesive import hsm, pdf from google.cloud import kms import hashlib #fill out these variables based on your project project_id = "" location_id = "" key_ring_id = "" key_id = "" version_id = "" filepath = "" class GoogleHSM(hsm.BaseHSM): def __init__(self, project_id, location_id, key_ring_id, key_id, version_id): self.project_id = project_id self.location_id = location_id self.key_ring_id = key_ring_id self.key_id = key_id self.version_id = version_id def certificate(self): """ See my gist to find out how to create x509 certificates for Google HSM-hosted keys: https://gist.github.com/Arbitrage0/de4e0defb20bc539d6db27e4334e0e67 """ cert = open('path/to/certificate.crt.pem', 'rb').read() return 1, cert def sign(self, keyid, data, mech): """ Following the example here: https://github.com/googleapis/python-kms/blob/master/samples/snippets/sign_asymmetric.py """ client = kms.KeyManagementServiceClient() key_version_name = client.crypto_key_version_path( self.project_id, self.location_id, self.key_ring_id, self.key_id, self.version_id ) hash_ = getattr(hashlib, mech.lower())(data).digest() digest = {mech.lower(): hash_} sign_response = client.asymmetric_sign(request={'name': key_version_name, 'digest': digest}) return sign_response.signature def main(project_id, location_id, key_ring_id, key_id, version_id, fname): date = datetime.datetime.utcnow() - datetime.timedelta(hours=12) date = date.strftime('D:%Y%m%d%H%M%S+00\'00\'') dct = { 'sigflags': 3, 'contact': 'user@example.com', 'location': 'England', 'signingdate': date.encode(), 'reason': 'Test', } Ghsm = GoogleHSM(project_id, location_id, key_ring_id, key_id, version_id) datau = open(fname, 'rb').read() datas = pdf.cms.sign(datau, dct, None, None, [], 'sha256', Ghsm, ) fname = fname.replace('.pdf', '-signed-cms-hsm-Google.pdf') with open(fname, 'wb') as fp: fp.write(datau) fp.write(datas) main(project_id, location_id, key_ring_id, key_id, version_id, filepath) endesive-2.19.1/examples/pdf-sign-cms-hsm-kir.py000077500000000000000000000061501504236674500214560ustar00rootroot00000000000000#!/usr/bin/env vpython3 # *-* coding: utf-8 *-* import sys import datetime from kir import dllpath from cryptography import x509 from cryptography.hazmat import backends import PyKCS11 as PK11 from endesive import pdf, hsm class Signer(hsm.HSM): def certificate(self): self.login("profil bezpieczny", "232212") keyid = [0x5e, 0x9a, 0x33, 0x44, 0x8b, 0xc3, 0xa1, 0x35, 0x33, 0xc7, 0xc2, 0x02, 0xf6, 0x9b, 0xde, 0x55, 0xfe, 0x83, 0x7b, 0xde] #keyid = [0x3f, 0xa6, 0x63, 0xdb, 0x75, 0x97, 0x5d, 0xa6, 0xb0, 0x32, 0xef, 0x2d, 0xdc, 0xc4, 0x8d, 0xe8] keyid = bytes(keyid) try: pk11objects = self.session.findObjects([(PK11.CKA_CLASS, PK11.CKO_CERTIFICATE)]) all_attributes = [ #PK11.CKA_SUBJECT, PK11.CKA_VALUE, #PK11.CKA_ISSUER, #PK11.CKA_CERTIFICATE_CATEGORY, #PK11.CKA_END_DATE, PK11.CKA_ID, ] for pk11object in pk11objects: try: attributes = self.session.getAttributeValue(pk11object, all_attributes) except PK11.PyKCS11Error as e: continue attrDict = dict(list(zip(all_attributes, attributes))) cert = bytes(attrDict[PK11.CKA_VALUE]) if keyid == bytes(attrDict[PK11.CKA_ID]): return keyid, cert finally: self.logout() return None, None def sign(self, keyid, data, mech): self.login("profil bezpieczny", "9593") try: privKey = self.session.findObjects([(PK11.CKA_CLASS, PK11.CKO_PRIVATE_KEY), (PK11.CKA_ID, keyid)])[0] mech = getattr(PK11, 'CKM_%s_RSA_PKCS' % mech.upper()) sig = self.session.sign(privKey, data, PK11.Mechanism(mech, None)) return bytes(sig) finally: self.logout() def main(): tspurl = "http://time.certum.pl" tspurl = "http://public-qlts.certum.pl/qts-17" date = datetime.datetime.utcnow() - datetime.timedelta(hours=12) date = date.strftime('%Y%m%d%H%M%S+00\'00\'') dct = { 'sigflags': 3, 'sigpage': 0, 'sigbutton': True, 'contact': 'mak@trisoft.com.pl', 'location': 'Szczecin', 'signingdate': date.encode(), 'reason': 'Dokument podpisany cyfrowo', 'signature': 'Dokument podpisany cyfrowo', 'signaturebox': (0, 0, 100, 100), } ocspurl = 'https://ocsp.certum.pl/' ocspissuer = open('CertumDigitalIdentificationCASHA2.crt', 'rb').read() ocspissuer = x509.load_pem_x509_certificate(ocspissuer, backends.default_backend()) clshsm = Signer(dllpath) fname = 'pdf.pdf' if len (sys.argv) > 1: fname = sys.argv[1] datau = open(fname, 'rb').read() datas = pdf.cms.sign(datau, dct, None, None, [], 'sha256', clshsm, tspurl, ocspurl=ocspurl, ocspissuer=ocspissuer ) fname = fname.replace('.pdf', '-signed-cms-hsm-certum.pdf') with open(fname, 'wb') as fp: fp.write(datau) fp.write(datas) main() endesive-2.19.1/examples/pdf-sign-cms-hsm-signature_appearance.py000077500000000000000000000074271504236674500250610ustar00rootroot00000000000000#!/usr/bin/env vpython3 # *-* coding: utf-8 *-* import sys from endesive import pdf, hsm import os import sys import sysconfig import datetime os.environ['SOFTHSM2_CONF'] = 'softhsm2.conf' if not os.path.exists(os.path.join(os.getcwd(), 'softhsm2.conf')): open('softhsm2.conf', 'wt').write('''\ log.level = DEBUG directories.tokendir = %s/softhsm2/ objectstore.backend = file slots.removable = false ''' % os.getcwd()) if not os.path.exists(os.path.join(os.getcwd(), 'softhsm2')): os.mkdir(os.path.join(os.getcwd(), 'softhsm2')) # #!/bin/bash #SOFTHSM2_CONF=softhsm2.conf #softhsm2-util --label "endesive" --slot 1 --init-token --pin secret1 --so-pin secret2 #softhsm2-util --show-slots # if sys.platform == 'win32': dllpath = r'W:\binw\SoftHSM2\lib\softhsm2-x64.dll' else: dllpath = os.path.join(sysconfig.get_config_var('LIBDIR'), "softhsm/libsofthsm2.so") import PyKCS11 as PK11 class Signer(hsm.HSM): def certificate(self): self.login("endesieve", "secret1") keyid = bytes((0x66,0x66,0x90)) try: pk11objects = self.session.findObjects([(PK11.CKA_CLASS, PK11.CKO_CERTIFICATE)]) all_attributes = [ #PK11.CKA_SUBJECT, PK11.CKA_VALUE, #PK11.CKA_ISSUER, #PK11.CKA_CERTIFICATE_CATEGORY, #PK11.CKA_END_DATE, PK11.CKA_ID, ] for pk11object in pk11objects: try: attributes = self.session.getAttributeValue(pk11object, all_attributes) except PK11.PyKCS11Error as e: continue attrDict = dict(list(zip(all_attributes, attributes))) cert = bytes(attrDict[PK11.CKA_VALUE]) if keyid == bytes(attrDict[PK11.CKA_ID]): return keyid, cert finally: self.logout() return None, None def sign(self, keyid, data, mech): self.login("endesieve", "secret1") try: privKey = self.session.findObjects([(PK11.CKA_CLASS, PK11.CKO_PRIVATE_KEY), (PK11.CKA_ID, keyid)])[0] mech = getattr(PK11, 'CKM_%s_RSA_PKCS' % mech.upper()) sig = self.session.sign(privKey, data, PK11.Mechanism(mech, None)) return bytes(sig) finally: self.logout() def main(): date = datetime.datetime.utcnow() - datetime.timedelta(hours=12) date = date.strftime('D:%Y%m%d%H%M%S+00\'00\'') class User: full_name = 'u.full: ąćęłńóśżź' email = 'u.email: zażółcić gęślą jaźń' company = 'u.comp: ĄĆĘŁŃÓŚŻŹ' company_full_name = 'u.comp_full: ZAŻÓŁCIĆ GĘŚLĄ JAŹŃ' user = User() dct = { 'aligned': 0, 'sigflags': 3, 'sigflagsft': 132, 'sigpage': 0, 'sigbutton': False, 'sigfield': 'Signature-1667820612.078739', 'auto_sigfield': False, 'sigandcertify': False, 'signaturebox': [175.79446979865773, 294.7236779911374, 447.47683221476507, 573.2810782865583], 'contact': '', 'location': '', 'reason': '', 'signingdate': "D:20221107123012+00'00'", 'signature_appearance': { 'background': [0.75, 0.8, 0.95], 'outline': [0.2, 0.3, 0.5], 'border': 1, 'labels': True, 'display': ['date'] } } clshsm = Signer(dllpath) fname = 'pdf.pdf' if len (sys.argv) > 1: fname = sys.argv[1] datau = open(fname, 'rb').read() datas = pdf.cms.sign(datau, dct, None, None, [], 'sha256', clshsm, ) fname = fname.replace('.pdf', '-signed-cms-hsm-signature_appearance.pdf') with open(fname, 'wb') as fp: fp.write(datau) fp.write(datas) main() endesive-2.19.1/examples/pdf-sign-cms-hsm-signature_manual.py000077500000000000000000000103311504236674500242230ustar00rootroot00000000000000#!/usr/bin/env vpython3 # *-* coding: utf-8 *-* import sys from endesive import pdf, hsm import os import sys import sysconfig import datetime os.environ['SOFTHSM2_CONF'] = 'softhsm2.conf' if not os.path.exists(os.path.join(os.getcwd(), 'softhsm2.conf')): open('softhsm2.conf', 'wt').write('''\ log.level = DEBUG directories.tokendir = %s/softhsm2/ objectstore.backend = file slots.removable = false ''' % os.getcwd()) if not os.path.exists(os.path.join(os.getcwd(), 'softhsm2')): os.mkdir(os.path.join(os.getcwd(), 'softhsm2')) # #!/bin/bash #SOFTHSM2_CONF=softhsm2.conf #softhsm2-util --label "endesive" --slot 1 --init-token --pin secret1 --so-pin secret2 #softhsm2-util --show-slots # if sys.platform == 'win32': dllpath = r'W:\binw\SoftHSM2\lib\softhsm2-x64.dll' else: dllpath = os.path.join(sysconfig.get_config_var('LIBDIR'), "softhsm/libsofthsm2.so") import PyKCS11 as PK11 class Signer(hsm.HSM): def certificate(self): self.login("endesieve", "secret1") keyid = bytes((0x66,0x66,0x90)) try: pk11objects = self.session.findObjects([(PK11.CKA_CLASS, PK11.CKO_CERTIFICATE)]) all_attributes = [ #PK11.CKA_SUBJECT, PK11.CKA_VALUE, #PK11.CKA_ISSUER, #PK11.CKA_CERTIFICATE_CATEGORY, #PK11.CKA_END_DATE, PK11.CKA_ID, ] for pk11object in pk11objects: try: attributes = self.session.getAttributeValue(pk11object, all_attributes) except PK11.PyKCS11Error as e: continue attrDict = dict(list(zip(all_attributes, attributes))) cert = bytes(attrDict[PK11.CKA_VALUE]) if keyid == bytes(attrDict[PK11.CKA_ID]): return keyid, cert finally: self.logout() return None, None def sign(self, keyid, data, mech): self.login("endesieve", "secret1") try: privKey = self.session.findObjects([(PK11.CKA_CLASS, PK11.CKO_PRIVATE_KEY), (PK11.CKA_ID, keyid)])[0] mech = getattr(PK11, 'CKM_%s_RSA_PKCS' % mech.upper()) sig = self.session.sign(privKey, data, PK11.Mechanism(mech, None)) return bytes(sig) finally: self.logout() def main(): date = datetime.datetime.utcnow() - datetime.timedelta(hours=12) date = date.strftime('D:%Y%m%d%H%M%S+00\'00\'') class User: full_name = 'u.full: ąćęłńóśżź' email = 'u.email: zażółcić gęślą jaźń' company = 'u.comp: ĄĆĘŁŃÓŚŻŹ' company_full_name = 'u.comp_full: ZAŻÓŁCIĆ GĘŚLĄ JAŹŃ' user = User() dct = { "aligned": 0, "sigflags": 3, "sigflagsft": 132, "sigpage": 0, "sigfield": "Signature1", "auto_sigfield": True, "signform": False, "signaturebox": (40, 110, 260, 190), "signature_manual": [ ['text_box', f'Investor Name: {user.full_name}\nEmail: {user.email}\nDate: {date}\nLocation: Szczecin', # font *[bounding box], size, wrap, align, baseline, spacing 'default', 5, 10, 270, 40, 7, True, 'left', 'top'], ['fill_colour', 0.4, 0.4, 0.4], ['rect_fill', 0, 50, 250, 1], ['fill_colour', 0, 0, 0], ['text_box', user.company_full_name, 'DancingScript', 7, 25, 270, 50, 12, True, 'left', 'top', 1.2], ], "manual_fonts": { 'DancingScript': '/usr/share/fonts/truetype/dejavu/DejaVuSansCondensed-Bold.ttf' }, "contact": user.email, "location": "Szczecin", "signingdate": date, "reason": f"Investment in {user.company} by {user.company_full_name}", } clshsm = Signer(dllpath) fname = 'pdf.pdf' if len (sys.argv) > 1: fname = sys.argv[1] datau = open(fname, 'rb').read() datas = pdf.cms.sign(datau, dct, None, None, [], 'sha256', clshsm, ) fname = fname.replace('.pdf', '-signed-cms-hsm-signature_manual.pdf') with open(fname, 'wb') as fp: fp.write(datau) fp.write(datas) main() endesive-2.19.1/examples/pdf-sign-cms-hsm-windows.py000066400000000000000000000033541504236674500223630ustar00rootroot00000000000000import sys import datetime from win32 import win32crypt from win32.lib import win32cryptcon from endesive import hsm, pdf class WindowsHSM(hsm.BaseHSM): def __init__(self, subject, certstore='MY'): self.derdata = None self.cert = None st = win32crypt.CertOpenSystemStore(certstore, None) try: certs = st.CertEnumCertificatesInStore() for cert in certs: if win32crypt.CertNameToStr(cert.Subject) == subject: self.derdata = cert.CertEncoded self.cert = cert break finally: st.CertCloseStore() def certificate(self): return 1, self.derdata def sign(self, keyid, data, mech): keyspec, cryptprov = self.cert.CryptAcquireCertificatePrivateKey(win32cryptcon.CRYPT_ACQUIRE_COMPARE_KEY_FLAG) chash = cryptprov.CryptCreateHash(win32cryptcon.CALG_SHA1, None, 0) chash.CryptHashData(data, 0) res = chash.CryptSignHash(keyspec, 0) return res[::-1] def main(): clshsm = WindowsHSM('USER 1') date = datetime.datetime.utcnow() - datetime.timedelta(hours=12) date = date.strftime('D:%Y%m%d%H%M%S+00\'00\'') dct = { 'sigflags': 3, 'contact': 'user@example.com', 'location': 'England', 'signingdate': date.encode(), 'reason': 'Test', } fname = 'pdf.pdf' if len (sys.argv) > 1: fname = sys.argv[1] datau = open(fname, 'rb').read() datas = pdf.cms.sign(datau, dct, None, None, [], 'sha1', clshsm, ) fname = fname.replace('.pdf', '-signed-cms-hsm-windows.pdf') with open(fname, 'wb') as fp: fp.write(datau) fp.write(datas) main() endesive-2.19.1/examples/pdf-sign-cms-hsm.py000077500000000000000000000067541504236674500207050ustar00rootroot00000000000000#!/usr/bin/env vpython3 # *-* coding: utf-8 *-* import sys from endesive import pdf, hsm import os import sys import sysconfig import datetime from cryptography import x509 from cryptography.hazmat import backends os.environ['SOFTHSM2_CONF'] = 'softhsm2.conf' if not os.path.exists(os.path.join(os.getcwd(), 'softhsm2.conf')): open('softhsm2.conf', 'wt').write('''\ log.level = DEBUG directories.tokendir = %s/softhsm2/ objectstore.backend = file slots.removable = false ''' % os.getcwd()) if not os.path.exists(os.path.join(os.getcwd(), 'softhsm2')): os.mkdir(os.path.join(os.getcwd(), 'softhsm2')) # #!/bin/bash #SOFTHSM2_CONF=softhsm2.conf #softhsm2-util --label "endesive" --slot 1 --init-token --pin secret1 --so-pin secret2 #softhsm2-util --show-slots # if sys.platform == 'win32': dllpath = r'W:\binw\SoftHSM2\lib\softhsm2-x64.dll' else: dllpath = os.path.join(sysconfig.get_config_var('LIBDIR'), "softhsm/libsofthsm2.so") import PyKCS11 as PK11 class Signer(hsm.HSM): def certificate(self): self.login("endesieve", "secret1") keyid = bytes((0x66,0x66,0x90)) try: pk11objects = self.session.findObjects([(PK11.CKA_CLASS, PK11.CKO_CERTIFICATE)]) all_attributes = [ #PK11.CKA_SUBJECT, PK11.CKA_VALUE, #PK11.CKA_ISSUER, #PK11.CKA_CERTIFICATE_CATEGORY, #PK11.CKA_END_DATE, PK11.CKA_ID, ] for pk11object in pk11objects: try: attributes = self.session.getAttributeValue(pk11object, all_attributes) except PK11.PyKCS11Error as e: continue attrDict = dict(list(zip(all_attributes, attributes))) cert = bytes(attrDict[PK11.CKA_VALUE]) if keyid == bytes(attrDict[PK11.CKA_ID]): return keyid, cert finally: self.logout() return None, None def sign(self, keyid, data, mech): self.login("endesieve", "secret1") try: privKey = self.session.findObjects([(PK11.CKA_CLASS, PK11.CKO_PRIVATE_KEY), (PK11.CKA_ID, keyid)])[0] mech = getattr(PK11, 'CKM_%s_RSA_PKCS' % mech.upper()) sig = self.session.sign(privKey, data, PK11.Mechanism(mech, None)) return bytes(sig) finally: self.logout() def main(): tspurl = "http://time.certum.pl" tspurl = "http://public-qlts.certum.pl/qts-17" ocspurl = 'https://ocsp.certum.pl/' ocspissuer = open('CertumDigitalIdentificationCASHA2.crt', 'rb').read() ocspissuer = x509.load_pem_x509_certificate(ocspissuer, backends.default_backend()) date = datetime.datetime.utcnow() - datetime.timedelta(hours=12) date = date.strftime('D:%Y%m%d%H%M%S+00\'00\'') dct = { 'sigflags': 3, 'contact': 'mak@trisoft.com.pl', 'location': 'Szczecin', 'signingdate': date.encode(), 'reason': 'Dokument podpisany cyfrowo', 'application': 'app:xyz', } clshsm = Signer(dllpath) fname = 'pdf.pdf' if len (sys.argv) > 1: fname = sys.argv[1] datau = open(fname, 'rb').read() datas = pdf.cms.sign(datau, dct, None, None, [], 'sha256', clshsm, tspurl, ocspurl=ocspurl, ocspissuer=ocspissuer ) fname = fname.replace('.pdf', '-signed-cms-hsm.pdf') with open(fname, 'wb') as fp: fp.write(datau) fp.write(datas) main() endesive-2.19.1/examples/pdf-sign-cms-ltv.py000077500000000000000000000042301504236674500207060ustar00rootroot00000000000000#!/usr/bin/env vpython3 # *-* coding: utf-8 *-* import sys import datetime from cryptography.hazmat import backends from cryptography.hazmat.primitives.serialization import pkcs12 from cryptography import x509 from endesive.pdf import cms def main(): date = datetime.datetime.now() date = date.strftime("D:%Y%m%d%H%M%S+00'00'") dct = { "aligned": 16384, "sigflags": 3, "sigflagsft": 132, "sigpage": 0, # "sigbutton": True, # "sigfield": "Signature1", # "auto_sigfield": True, # "sigandcertify": True, # "signaturebox": (470, 840, 570, 640), "signature": "Dokument podpisany cyfrowo ąćęłńóśżź", # "signature_img": "signature_test.png", "contact": "contact:mak@trisoft.com.pl", "location": "Szczecin", "signingdate": date, "reason": "Dokument podpisany cyfrowo aą cć eę lł nń oó sś zż zź", "password": "1234", 'tsa_url': 'http://timestamp.digicert.com', "ltv": True, } with open("ca/demo2_user1.p12", "rb") as fp: p12 = pkcs12.load_key_and_certificates( fp.read(), b"1234", backends.default_backend() ) fname = "pdf.pdf" if len(sys.argv) > 2: fname = sys.argv[2] datau = open(fname, "rb").read() print(f"Signing certificate subject: {p12[1].subject.rfc4514_string()}") print(f"Signing certificate issuer: {p12[1].issuer.rfc4514_string()}") print(f"Additional certificates in chain: {len(p12[2]) if p12[2] else 0}") issuer_cert = None if p12[2]: issuer_cert = p12[2][0] print( f"Using issuer certificate: {issuer_cert.subject.rfc4514_string()}") else: print("No additional certificates found in P12 file") # ocsp_url = "http://ca.trisoft.com.pl/ocsp" datas = cms.sign(datau, dct, p12[0], p12[1], p12[2], "sha256", # ocspurl=ocsp_url, ocspissuer=issuer_cert, timestampurl=dct['tsa_url']) fname = fname.replace(".pdf", "-signed-cms-ltv.pdf") with open(fname, "wb") as fp: fp.write(datau) fp.write(datas) main() endesive-2.19.1/examples/pdf-sign-cms-m32-actalis.py000077500000000000000000000027621504236674500221300ustar00rootroot00000000000000#!/usr/bin/env vpython3 # *-* coding: utf-8 *-* import sys import datetime from cryptography import x509 from cryptography.hazmat import backends from cryptography.hazmat.primitives.serialization import pkcs12 from endesive import pdf # import logging # logging.basicConfig(level=logging.DEBUG) def main(): date = datetime.datetime.utcnow() - datetime.timedelta() date = date.strftime("%Y%m%d%H%M%S+00'00'") dct = { "sigflags": 3, "sigpage": 0, "sigbutton": True, "contact": "mak@trisoft.com.pl", "location": "Szczecin", "signingdate": date.encode(), "reason": "Dokument podpisany cyfrowo", "signature": "Dokument podpisany cyfrowo", "signaturebox": (0, 0, 100, 100), "sigandcertify": True, "text": { "fontsize": 10, }, } pk12fname = "/home/mak/Dokumenty/m32/ssl/actalis/actalis.p12" pk12pass = sys.argv[1].encode() with open(pk12fname, "rb") as fp: p12 = pkcs12.load_key_and_certificates( fp.read(), pk12pass, backends.default_backend() ) fname = "pdf.pdf" if len(sys.argv) > 2: fname = sys.argv[2] datau = open(fname, "rb").read() datas = pdf.cms.sign( datau, dct, p12[0], p12[1], p12[2][:3], "sha256", None, ) fname = fname.replace(".pdf", "-signed-cms-m32-actalis.pdf") with open(fname, "wb") as fp: fp.write(datau) fp.write(datas) main() endesive-2.19.1/examples/pdf-sign-cms-m32-unizeto.py000077500000000000000000000033551504236674500222040ustar00rootroot00000000000000#!/usr/bin/env vpython3 # *-* coding: utf-8 *-* import sys import datetime from cryptography import x509 from cryptography.hazmat import backends from cryptography.hazmat.primitives.serialization import pkcs12 from endesive import pdf # import logging # logging.basicConfig(level=logging.DEBUG) def main(): tspurl = "http://time.certum.pl" #tspurl = "http://public-qlts.certum.pl/qts-17" date = datetime.datetime.utcnow() date = date.strftime("D:%Y%m%d%H%M%S+00'00'") dct = { "sigflags": 3, "sigpage": 0, "sigbutton": False, "name": "Grzegorz Makarewicz", "contact": "mak@trisoft.com.pl", "location": "Szczecin", "signingdate": date.encode(), "reason": "Dokument podpisany cyfrowo", "sigandcertify": False, } pk12fname = "/home/mak/Dokumenty/m32/ssl/unizeto/unizeto.p12" pk12pass = sys.argv[1].encode() with open(pk12fname, "rb") as fp: p12 = pkcs12.load_key_and_certificates( fp.read(), pk12pass, backends.default_backend() ) ocspurl = "https://ocsp.certum.pl/" ocspissuer = open("csmimersaca.cer", "rb").read() ocspissuer = x509.load_der_x509_certificate(ocspissuer, backends.default_backend()) #tspurl=ocspurl=ocspissuer=None fname = "pdf.pdf" if len(sys.argv) > 2: fname = sys.argv[2] datau = open(fname, "rb").read() datas = pdf.cms.sign( datau, dct, p12[0], p12[1], p12[2][:3], "sha256", None, tspurl, ocspurl=ocspurl, ocspissuer=ocspissuer, ) fname = fname.replace(".pdf", "-signed-cms-m32-unizeto.pdf") with open(fname, "wb") as fp: fp.write(datau) fp.write(datas) main() endesive-2.19.1/examples/pdf-sign-cms-pfx000077500000000000000000000002001504236674500202400ustar00rootroot00000000000000./pdf-sign-cms-pfx.py -d pdf-signed-cms-pfx.pdf ~/Dokumenty/m32/ssl/actalis/certificate_s_mime.p12 "1AR0uaCd=vqaQww12&" pdf.pdf endesive-2.19.1/examples/pdf-sign-cms-pfx.py000077500000000000000000000117271504236674500207070ustar00rootroot00000000000000#!/usr/bin/env vpython3 """ A tool which takes in pdf, pfx file, password as input and gives out a corresponding signed pdf """ import argparse import pytz import re import sys import datetime from cryptography.hazmat import backends from cryptography.hazmat.primitives.serialization import pkcs12 from cryptography.x509.oid import NameOID from endesive import pdf signature_string = lambda organization, date, country : (organization + '\nDATE: '+ date) def eprint(error): print(error, file=sys.stderr) def load_pfx(file_path, password): """ Function to load pkcs12 object from the given password protected pfx file.""" with open(file_path, 'rb') as fp: return pkcs12.load_key_and_certificates(fp.read(), password.encode(), backends.default_backend()) def create_args(): """Creates CLI arguments for the pdfSigner script.""" parser = argparse.ArgumentParser(description='Script for digitally signing a pdf') parser.add_argument('pfx_certificate', type=str, help='Specify keystore file in .pfx format (Mandatory)') parser.add_argument('password', type=str, help=' Specify password for keystore file (mandatory)') parser.add_argument('src', type=str, help='Specify the source file (.pdf) that needs to be digitally signed. Only 1 file at a time can be signed. (Mandatory) ') parser.add_argument('-d', '--dest', type=str, help='Specify the destination file where digitally signed content will be stored.When not specified, by default it will ' 'digitally sign the source file.(Mandatory) \n' 'E.g. Given source file /var/hp/some.pdf will be digitally signed') parser.add_argument('-c', '--coords', type=str, help='Specify the co-ordinates of where you want the digital signature to be placed on the PDF file page.(Optional)\n' 'Format: Accepts 4 comma-separated float values (without spaces). E.g. 1,2,3,4 ') parser.add_argument('-p', '--page', type=int, help='You can specify the page number of PDF file where digital signature(Optional)') return parser.parse_args() def validate_args(args): """Validating commandline arguments raises valueError exception with if any command line arguments are not valid.""" IS_PFX = lambda pfx_certificate: re.match( r'^(.[^,]+)(.pfx|.PFX|.p12|.P12){1}$', pfx_certificate) if not IS_PFX(args.pfx_certificate): raise ValueError('Not a proper pfx file with .pfx or .PFX extension') if args.coords: for num in args.coords.split(','): if not num.isdigit(): raise ValueError('Coords are not integers') OID_NAMES = { NameOID.COMMON_NAME: 'CN', NameOID.COUNTRY_NAME: 'C', NameOID.DOMAIN_COMPONENT: 'DC', NameOID.EMAIL_ADDRESS: 'E', NameOID.GIVEN_NAME: 'G', NameOID.LOCALITY_NAME: 'L', NameOID.ORGANIZATION_NAME: 'O', NameOID.ORGANIZATIONAL_UNIT_NAME: 'OU', NameOID.SURNAME: 'SN' } def get_rdns_names(rdns): names = {} for oid in OID_NAMES: names[OID_NAMES[oid]] = '' for rdn in rdns: for attr in rdn._attributes: if attr.oid in OID_NAMES: names[OID_NAMES[attr.oid]] = attr.value return names def run(): args = create_args() try: validate_args(args) except ValueError as e: import traceback; traceback.print_exc() sys.exit(1) try: # Load the PKCS12 object from the pfx file p12pk, p12pc, p12oc = load_pfx(args.pfx_certificate, args.password) names = get_rdns_names(p12pc.subject.rdns) timezone = pytz.timezone('Asia/Calcutta') #default coords of bottom right corner in a pdf page coords = [350, 50, 550, 150] if args.coords: coords = [int(coord) for coord in args.coords.split(',') if coord] page = args.page if args.page else 1 dest = args.dest if args.dest else args.src date = datetime.datetime.utcnow() - datetime.timedelta(hours=12) date = date.strftime('%Y%m%d%H%M%S+00\'00\'') signature = signature_string(names['CN'], date, names['C']) dct = { 'sigflags': 3, 'sigpage': page - 1, 'contact': 'finacctind@endurance.com', #'location': subject.C.encode(), 'location': 'Szczecin', 'signingdate': date, 'signingdate': '20201119195200+02\'00\'', 'reason': 'Signed by endurance', 'signature': signature, 'signaturebox': tuple(coords[:4]), } input_file = args.src datau = open(input_file, 'rb').read() datas = pdf.cms.sign(datau, dct, p12pk, p12pc, p12oc, 'sha256' ) output_file = input_file.replace(input_file, dest) with open(output_file, 'wb') as fp: fp.write(datau) fp.write(datas) except Exception as e: import traceback; traceback.print_exc() eprint(e) sys.exit() if __name__ == '__main__': run() endesive-2.19.1/examples/pdf-sign-cms-pil.py000077500000000000000000000025071504236674500206720ustar00rootroot00000000000000#!/usr/bin/env vpython3 # *-* coding: utf-8 *-* import sys import datetime from cryptography.hazmat import backends from cryptography.hazmat.primitives.serialization import pkcs12 from PIL import Image from endesive import pdf #import logging #logging.basicConfig(level=logging.DEBUG) def main(): date = datetime.datetime.utcnow() - datetime.timedelta(hours=12) date = date.strftime('%Y%m%d%H%M%S+00\'00\'') img = Image.open('signature_test.png') dct = { 'sigflags': 3, # 'sigpage': 0, 'sigbutton': True, 'signature_img': img, 'contact': 'mak@trisoft.com.pl', 'location': 'Szczecin', 'signingdate': date.encode(), 'reason': 'Dokument podpisany cyfrowo', 'signature': 'Dokument podpisany cyfrowo', 'signaturebox': (470, 0, 570, 100), } with open('ca/demo2_user1.p12', 'rb') as fp: p12 = pkcs12.load_key_and_certificates(fp.read(), b'1234', backends.default_backend()) fname = 'pdf.pdf' if len (sys.argv) > 1: fname = sys.argv[1] datau = open(fname, 'rb').read() datas = pdf.cms.sign(datau, dct, p12[0], p12[1], p12[2], 'sha256' ) fname = fname.replace('.pdf', '-signed-cms-pil.pdf') with open(fname, 'wb') as fp: fp.write(datau) fp.write(datas) main() endesive-2.19.1/examples/pdf-sign-cms-pypdf.py000077500000000000000000000414221504236674500212270ustar00rootroot00000000000000#!/usr/bin/env vpython3 import sys import time import random import io import struct import datetime import hashlib import codecs import struct from cryptography.hazmat import backends from cryptography.hazmat.primitives.serialization import pkcs12 from endesive import signer from endesive.pdf.PyPDF2 import pdf, generic as po def EncodedString(s): return po.createStringObject(codecs.BOM_UTF16_BE + s.encode("utf-16be")) class UnencryptedBytes(po.utils.bytes_type, po.PdfObject): original_bytes = property(lambda self: self) def writeToStream(self, stream, encryption_key): stream.write(b"<") stream.write(self) stream.write(b">") class WNumberObject(po.NumberObject): Format = b"%08d" def writeToStream(self, stream, encryption_key): stream.write(self.Format % self) class Main(pdf.PdfFileWriter): annottext = True annotbutton = True def encrypt(self, prev, password, rc): encrypt = prev.trailer["/Encrypt"].getObject() if encrypt["/V"] == 2: rev = 3 keylen = int(128 / 8) else: rev = 2 keylen = int(40 / 8) P = encrypt["/P"] O = encrypt["/O"] ID_1 = prev.trailer["/ID"][0] if rev == 2: U, key = pdf._alg34(password, O, P, ID_1) else: assert rev == 3 U, key = pdf._alg35(password, rev, keylen, O, P, ID_1, False) self._encrypt_key = key def write(self, stream, prev, startdata): stream.write(pdf.b_("\r\n")) positions = {2: 0} for i in range(2, len(self._objects)): idnum = i + 1 obj = self._objects[i] if obj is None: positions[idnum] = 0 continue positions[idnum] = startdata + stream.tell() stream.write(pdf.b_(str(idnum) + " 0 obj\n")) key = None if self._encrypt_key is not None: pack1 = struct.pack("q", offset) dataindex = ["0 1"] dataxref = [b"\x00" + pack(0)] keys = sorted(positions.keys()) i = 0 while i < len(keys): off = positions[keys[i]] if off != 0: start = i while i < len(keys) and positions[keys[i]] != 0: dataxref.append(b"\x01" + pack(positions[keys[i]])) i += 1 stop = i dataindex.append("%d %d" % (keys[start], stop - start)) else: i += 1 dataindex = " ".join(dataindex) dataxref = b"".join(dataxref) trailer[po.NameObject("/Type")] = po.NameObject("/XRef") trailer[po.NameObject("/W")] = po.NameObject("[1 8 0]") trailer[po.NameObject("/Index")] = po.NameObject("[%s]" % dataindex) trailer._data = dataxref retval = trailer.flateEncode() trailer.update(retval) trailer._data = retval._data stream.write(pdf.b_("%d 0 obj\n" % (len(self._objects)))) trailer.writeToStream(stream, None) stream.write(pdf.b_("\nendobj")) # eof stream.write(pdf.b_("\nstartxref\n%s\n%%%%EOF\n" % (xref_location))) def _extend(self, obj): stream = getattr(obj, "stream", None) if stream is not None: d = {"__streamdata__": stream, "/Length": len(stream)} d.update(obj) dct = pdf.StreamObject.initializeFromDictionary(d) else: dct = pdf.DictionaryObject() for k, v in obj.items(): if isinstance(v, pdf.DictionaryObject): if v.indirect: v = self._extend(v) v = self._addObject(v) else: v = self._extend(v) elif isinstance(v, list): v = pdf.ArrayObject(v) dct[k] = v return dct def makepdf(self, prev, algomd, zeros): catalog = prev.trailer["/Root"] size = prev.trailer["/Size"] pages = catalog["/Pages"].getObject() page0ref = pages["/Kids"][0] while len(self._objects) < size - 1: self._objects.append(None) obj13 = po.DictionaryObject() obj13ref = self._addObject(obj13) obj12 = po.DictionaryObject() obj12ref = self._addObject(obj12) obj12.update( { po.NameObject("/Type"): po.NameObject("/Sig"), po.NameObject("/Filter"): po.NameObject("/Adobe.PPKLite"), po.NameObject("/SubFilter"): po.NameObject("/adbe.pkcs7.detached"), po.NameObject("/Name"): EncodedString("Example User"), po.NameObject("/Location"): EncodedString("Los Angeles, CA"), po.NameObject("/Reason"): EncodedString("Testing"), po.NameObject("/M"): EncodedString("D:20200317214832+01'00'"), po.NameObject("/Contents"): UnencryptedBytes(zeros), po.NameObject("/ByteRange"): po.ArrayObject( [ WNumberObject(0), WNumberObject(0), WNumberObject(0), WNumberObject(0), ] ), } ) obj13.update( { po.NameObject("/FT"): po.NameObject("/Sig"), po.NameObject("/Type"): po.NameObject("/Annot"), po.NameObject("/Subtype"): po.NameObject("/Widget"), po.NameObject("/F"): po.NumberObject(132), po.NameObject("/T"): EncodedString("Signature1"), po.NameObject("/V"): obj12ref, po.NameObject("/P"): page0ref, po.NameObject("/Rect"): po.ArrayObject( [ po.FloatObject(0.0), po.FloatObject(0.0), po.FloatObject(0.0), po.FloatObject(0.0), ] ), } ) if self.annottext: from endesive.pdf.PyPDF2_annotate.annotations.text import FreeText from endesive.pdf.PyPDF2_annotate.annotations.image import Image from endesive.pdf.PyPDF2_annotate.config.appearance import Appearance from endesive.pdf.PyPDF2_annotate.config.location import Location from endesive.pdf.PyPDF2_annotate.util.geometry import identity annotationtext = None #annotationtext = "User signature text" x1, y1, x2, y2 = (470, 0, 570, 100) if annotationtext is not None: annotation = FreeText( Location(x1=x1, y1=y1, x2=x2, y2=y2, page=0), Appearance( fill=[0, 0, 0], stroke_width=1, wrap_text=True, font_size=12, content=annotationtext, ), ) names = ("BS", "C", "Contents", "DA") if not self.annotbutton: obj13[po.NameObject("/Subtype")] = po.NameObject("/FreeText") else: from PIL import Image as PILImage image = PILImage.open("signature_test.png") ap = Appearance() ap.image = image annotation = Image(Location(x1=x1, y1=y1, x2=x2, y2=y2, page=0), ap) if not self.annotbutton: names = ( # "Subtype", ) else: names = () pdfa = annotation.as_pdf_object(identity(), page=page0ref) objapn = self._extend(pdfa["/AP"]["/N"]) objapnref = self._addObject(objapn) for name in names + ( "Rect", # "Subtype", ): key = po.NameObject("/" + name) v = pdfa[key] obj13[key] = v objap = po.DictionaryObject() objap[po.NameObject("/N")] = objapnref obj13.update( { po.NameObject("/AP"): objap, po.NameObject("/SM"): po.createStringObject("TabletPOSinline"), } ) page0 = page0ref.getObject() annots = po.ArrayObject([obj13ref]) if "/Annots" in page0: page0annots = page0["/Annots"] if isinstance(page0annots, po.IndirectObject): annots.insert(0, page0annots) elif isinstance(page0annots, po.ArrayObject): annots = page0annots annots.append(obj13ref) page0.update({po.NameObject("/Annots"): annots}) self._objects[page0ref.idnum - 1] = page0 if "/Perms" not in catalog: obj10 = po.DictionaryObject() obj10ref = self._addObject(obj10) obj11 = po.DictionaryObject() obj11ref = self._addObject(obj11) obj14 = po.DictionaryObject() obj14ref = self._addObject(obj14) obj14.update({po.NameObject("/DocMDP"): obj12ref}) obj10.update( { po.NameObject("/Type"): po.NameObject("/TransformParams"), po.NameObject("/P"): po.NumberObject(2), po.NameObject("/V"): po.NameObject("/1.2"), } ) obj11.update( { po.NameObject("/Type"): po.NameObject("/SigRef"), po.NameObject("/TransformMethod"): po.NameObject("/DocMDP"), po.NameObject("/DigestMethod"): po.NameObject("/" + algomd.upper()), po.NameObject("/TransformParams"): obj10ref, } ) obj12[po.NameObject("/Reference")] = po.ArrayObject([obj11ref]) catalog[po.NameObject("/Perms")] = obj14ref if "/AcroForm" in catalog: form = catalog["/AcroForm"].getObject() if "/Fields" in form: fields = form["/Fields"] else: fields = po.ArrayObject() fields.append(obj13ref) form.update( { po.NameObject("/Fields"): fields, po.NameObject("/SigFlags"): po.NumberObject(3), } ) formref = catalog.raw_get("/AcroForm") if isinstance(formref, po.IndirectObject): self._objects[formref.idnum - 1] = form form = formref else: form = po.DictionaryObject() form.update( { po.NameObject("/Fields"): po.ArrayObject([obj13ref]), po.NameObject("/SigFlags"): po.NumberObject(3), } ) catalog[po.NameObject("/AcroForm")] = form if "/Metadata" in catalog: catalog[po.NameObject("/Metadata")] = catalog.raw_get("/Metadata") x_root = prev.trailer.raw_get("/Root") self._objects[x_root.idnum - 1] = catalog self.x_root = po.IndirectObject(x_root.idnum, 0, self) self.x_info = prev.trailer.raw_get("/Info") def sign(self, md, algomd): tspurl = "http://public-qlts.certum.pl/qts-17" tspurl = None with open("ca/demo2_user1.p12", "rb") as fp: p12 = pkcs12.load_key_and_certificates( fp.read(), b"1234", backends.default_backend() ) contents = signer.sign( None, p12[0], p12[1], p12[2], algomd, True, md, None, False, tspurl ) return contents def main(self, fname, password): with open(fname, "rb") as fi: datau = fi.read() startdata = len(datau) fi = io.BytesIO(datau) prev = pdf.PdfFileReader(fi) if prev.isEncrypted: rc = prev.decrypt(password) else: rc = 0 algomd = "sha1" aligned = False obj = prev.trailer for k in ("/Root", "/Perms", "/DocMDP", "/Reference"): if k in obj: obj = obj[k] if isinstance(obj, po.ArrayObject): obj = obj[0] obj = obj.getObject() else: obj = None break if obj is not None: algomd = obj["/DigestMethod"][1:].lower() if aligned: zeros = b"0" * 37888 else: md = getattr(hashlib, algomd)().digest() contents = self.sign(md, algomd) zeros = contents.hex().encode("utf-8") self.makepdf(prev, algomd, zeros) if prev.isEncrypted: self.encrypt(prev, password, rc) else: self._encrypt_key = None ID = prev.trailer.get("/ID", None) if ID is None: ID = po.ByteStringObject(hashlib.md5(repr(time.time()).encode()).digest()) else: ID = ID[0] self._ID = po.ArrayObject( [ ID, po.ByteStringObject( hashlib.md5(repr(random.random()).encode()).digest() ), ] ) fo = io.BytesIO() self.write(fo, prev, startdata) datas = fo.getvalue() br = [0, 0, 0, 0] bfrom = (b"[ " + b" ".join([WNumberObject.Format] * 4) + b" ]") % tuple(br) pdfbr1 = datas.find(zeros) pdfbr2 = pdfbr1 + len(zeros) br = [ 0, startdata + pdfbr1 - 1, startdata + pdfbr2 + 1, len(datas) - pdfbr2 - 1, ] bto = b"[%d %d %d %d]" % tuple(br) bto += b" " * (len(bfrom) - len(bto)) assert len(bfrom) == len(bto) datas = datas.replace(bfrom, bto, 1) md = getattr(hashlib, algomd)() md.update(datau) b1 = datas[: br[1] - startdata] b2 = datas[br[2] - startdata :] md.update(b1) md.update(b2) md = md.digest() contents = self.sign(md, algomd) contents = contents.hex().encode("utf-8") if aligned: nb = len(zeros) - len(contents) contents += b"0" * nb datas = datas.replace(zeros, contents, 1) fname = fname.replace(".pdf", "-signed-cms-pypdf.pdf") with open(fname, "wb") as fp: fp.write(datau) fp.write(datas) def main(): if len(sys.argv) > 1: cls = Main() cls.main(sys.argv[1], sys.argv[2] if len(sys.argv) > 2 else "") else: cls = Main() cls.main("pdf.pdf", "") cls = Main() cls.main("pdf-encrypted.pdf", "1234") main() endesive-2.19.1/examples/pdf-sign-cms-twice-1.py000077500000000000000000000027251504236674500213610ustar00rootroot00000000000000#!/usr/bin/env vpython3 # *-* coding: utf-8 *-* import sys import datetime from cryptography.hazmat import backends from cryptography.hazmat.primitives.serialization import pkcs12 from endesive.pdf import cms # from endesive.pdf import cmsn as cms # import logging # logging.basicConfig(level=logging.DEBUG) def main(): date = datetime.datetime.utcnow() date = date.strftime("D:%Y%m%d%H%M%S+00'00'") dct = { "aligned": 8192, "sigflags": 3, "sigflagsft": 132, "sigpage": 0, # "sigbutton": True, "sigfield": "Signature1", "auto_sigfield": True, "sigandcertify": True, "signaturebox": (470, 840, 570, 640), "signature": "Podpis 1", # "signature_img": "signature_test.png", "contact": "demo1@demot.com.pl", "location": "Szczecin", "signingdate": date, "reason": "Dokument podpisany cyfrowo aą cć eę lł nń oó sś zż zź", "password": "1234", } with open("ca/demo2_user1.p12", "rb") as fp: p12 = pkcs12.load_key_and_certificates( fp.read(), b"1234", backends.default_backend() ) fname = "pdf.pdf" if len(sys.argv) > 1: fname = sys.argv[1] datau = open(fname, "rb").read() datas = cms.sign(datau, dct, p12[0], p12[1], p12[2], "sha256") fname = fname.replace(".pdf", "-signed-cms-twice-1.pdf") with open(fname, "wb") as fp: fp.write(datau) fp.write(datas) main() endesive-2.19.1/examples/pdf-sign-cms-twice-2.py000077500000000000000000000027271504236674500213640ustar00rootroot00000000000000#!/usr/bin/env vpython3 # *-* coding: utf-8 *-* import sys import datetime from cryptography.hazmat import backends from cryptography.hazmat.primitives.serialization import pkcs12 from endesive.pdf import cms # from endesive.pdf import cmsn as cms # import logging # logging.basicConfig(level=logging.DEBUG) def main(): date = datetime.datetime.utcnow() date = date.strftime("D:%Y%m%d%H%M%S+00'00'") dct = { "aligned": 8192, "sigflags": 3, "sigflagsft": 132, "sigpage": 0, # "sigbutton": True, "sigfield": "Signature1", "auto_sigfield": True, "sigandcertify": True, "signaturebox": (470, 640, 570, 440), "signature": "Podpis 2", # "signature_img": "signature_test.png", "contact": "contact:demo2@demot.com.pl", "location": "Szczecin", "signingdate": date, "reason": "Dokument podpisany cyfrowo aą cć eę lł nń oó sś zż zź", "password": "1234", } with open("ca/demo2_user2.p12", "rb") as fp: p12 = pkcs12.load_key_and_certificates( fp.read(), b"1234", backends.default_backend() ) fname = "pdf-signed-cms-twice-1.pdf" if len(sys.argv) > 1: fname = sys.argv[1] datau = open(fname, "rb").read() datas = cms.sign(datau, dct, p12[0], p12[1], p12[2], "sha256") fname = fname.replace("1", "2") with open(fname, "wb") as fp: fp.write(datau) fp.write(datas) main() endesive-2.19.1/examples/pdf-sign-cms-twice-end.py000077500000000000000000000027311504236674500217640ustar00rootroot00000000000000#!/usr/bin/env vpython3 # *-* coding: utf-8 *-* import sys import datetime from cryptography.hazmat import backends from cryptography.hazmat.primitives.serialization import pkcs12 from endesive.pdf import cms # from endesive.pdf import cmsn as cms # import logging # logging.basicConfig(level=logging.DEBUG) def main(): date = datetime.datetime.utcnow() date = date.strftime("D:%Y%m%d%H%M%S+00'00'") dct = { "aligned": 8192, "sigflags": 1, "sigflagsft": 132, "sigpage": 0, # "sigbutton": True, "sigfield": "Signature1", "auto_sigfield": True, "sigandcertify": True, "signaturebox": (470, 440, 570, 240), "signature": "Podpis 3", # "signature_img": "signature_test.png", "contact": "contact:demo3@demot.com.pl", "location": "Szczecin", "signingdate": date, "reason": "Dokument podpisany cyfrowo aą cć eę lł nń oó sś zż zź", "password": "1234", } with open("ca/demo2_user3.p12", "rb") as fp: p12 = pkcs12.load_key_and_certificates( fp.read(), b"1234", backends.default_backend() ) fname = "pdf-signed-cms-twice-2.pdf" if len(sys.argv) > 1: fname = sys.argv[1] datau = open(fname, "rb").read() datas = cms.sign(datau, dct, p12[0], p12[1], p12[2], "sha256") fname = fname.replace("2", "end") with open(fname, "wb") as fp: fp.write(datau) fp.write(datas) main() endesive-2.19.1/examples/pdf-sign-cms.py000077500000000000000000000030021504236674500200770ustar00rootroot00000000000000#!/usr/bin/env vpython3 # *-* coding: utf-8 *-* import sys import datetime from cryptography.hazmat import backends from cryptography.hazmat.primitives.serialization import pkcs12 from endesive.pdf import cms # from endesive.pdf import cmsn as cms # import logging # logging.basicConfig(level=logging.DEBUG) def main(): date = datetime.datetime.utcnow() date = date.strftime("D:%Y%m%d%H%M%S+00'00'") dct = { "aligned": 8192, "sigflags": 3, "sigflagsft": 132, "sigpage": 0, # "sigbutton": True, # "sigfield": "Signature1", # "auto_sigfield": True, # "sigandcertify": True, # "signaturebox": (470, 840, 570, 640), "signature": "Dokument podpisany cyfrowo ąćęłńóśżź", # "signature_img": "signature_test.png", "contact": "contact:mak@trisoft.com.pl", "location": "Szczecin", "signingdate": date, "reason": "Dokument podpisany cyfrowo aą cć eę lł nń oó sś zż zź", "password": "1234", } with open("ca/demo2_user1.p12", "rb") as fp: p12 = pkcs12.load_key_and_certificates( fp.read(), b"1234", backends.default_backend() ) fname = "pdf.pdf" if len(sys.argv) > 1: fname = sys.argv[1] datau = open(fname, "rb").read() datas = cms.sign(datau, dct, p12[0], p12[1], p12[2], "sha256") fname = fname.replace(".pdf", "-signed-cms.pdf") with open(fname, "wb") as fp: fp.write(datau) fp.write(datas) main() endesive-2.19.1/examples/pdf-sign-fpdf.py000077500000000000000000000017531504236674500202470ustar00rootroot00000000000000#!/usr/bin/env vpython3 # *-* coding: utf-8 *-* import datetime from cryptography.hazmat import backends from cryptography.hazmat.primitives.serialization import pkcs12 from endesive.pdf import pdf def main(): date = datetime.datetime.utcnow() - datetime.timedelta(hours=12) date = date.strftime('%Y%m%d%H%M%S+00\'00\'') dct = { 'sigflags': 3, 'contact': 'mak@trisoft.com.pl', 'location': 'Szczecin', 'signingdate': date, 'reason': 'Dokument podpisany cyfrowo', } with open('ca/demo2_user1.p12', 'rb') as fp: p12 = pkcs12.load_key_and_certificates(fp.read(), b'1234', backends.default_backend()) doc = pdf.FPDF() doc.pkcs11_setup(dct, p12[0], p12[1], p12[2], 'sha256' ) for i in range(2): doc.add_page() doc.set_font('helvetica', '', 13.0) doc.cell(w=75.0, h=22.0, align='C', txt='Hello, world page=%d.' % i, border=0, ln=0) doc.output('pdf-signed-fpdf.pdf', "F") main() endesive-2.19.1/examples/pdf-timestamp-cms.py000077500000000000000000000022351504236674500211510ustar00rootroot00000000000000#!/usr/bin/env vpython3 # *-* coding: utf-8 *-* import sys import datetime from cryptography.hazmat import backends from cryptography.hazmat.primitives.serialization import pkcs12 from endesive.pdf import cms # from endesive.pdf import cmsn as cms # import logging # logging.basicConfig(level=logging.DEBUG) def main(): dct = { "aligned": 0, "sigflags": 3, "sigflagsft": 132, "sigpage": 0, "sigfield": "Signature1", "auto_sigfield": True, "password": "1234", "signingdate": "2025-06-11", } fname = "pdf.pdf" if len(sys.argv) > 1: fname = sys.argv[1] datau = open(fname, "rb").read() datas = cms.timestamp( datau, # PDF data dct, # config "sha256", # hash 'https://freetsa.org/tsr' # Timestamp server URL # { # Timestamp server credentials # 'username': 'user', # 'password': 'hunter2' # }, # {}, Timestamp server options ) fname = fname.replace(".pdf", "-timestamped-cms.pdf") with open(fname, "wb") as fp: fp.write(datau) fp.write(datas) main() endesive-2.19.1/examples/pdf-verifier-pyhanko000077500000000000000000000002501504236674500212140ustar00rootroot00000000000000#!/bin/bash one() { vpy3 pyhanko --verbose sign validate --no-revocation-check --pretty-print $* } #one pdf-signed-cms.pdf #one pdf-signed-cms-m32-unizeto.pdf one $* endesive-2.19.1/examples/pdf-verifier.py000077500000000000000000000036421504236674500202040ustar00rootroot00000000000000#!/usr/bin/env python3 import sys from endesive.pdf import PDFVerifier def main(): trustedcerts = [] with open("nccert2016.crt", "rb") as fp: trustedcerts.append(fp.read()) with open("ca/demo2_ca.root.crt.pem", "rb") as fp: trustedcerts.append(fp.read()) if len(sys.argv) > 1: fname = sys.argv[1] else: fname = "pdf-signed-cms-m32-unizeto.pdf" with open(fname, "rb") as fp: pdf_data = fp.read() v = PDFVerifier(pdf_data, trustedcerts) if not v.is_valid_pdf(): print(f"{fname} is not a pdf file") return if not v.is_signed(): if v.modified: print(f"file {fname} is modified") else: print(f"file {fname} is unsigned") if not v.wholefile: print("the signature does not cover the entire pdf file") return (signed_data, tspdata, crldata, cert, othercerts, hashok, signatureok) = v.decompose_signature() if not hashok or not signatureok: print(f"file {fname} is modified") return certok = v.validate_certificate(cert, othercerts) if not certok: print(f"signing certificate is invalid") return print(f"signed with cert serial_number: {cert['tbs_certificate']['serial_number'].native}") print("other certificates:") for ocert in othercerts: print(f" serial_number: {ocert['tbs_certificate']['serial_number'].native}") if crldata.native is not None: ok, info = v.verify_ocsp_data(cert, othercerts, crldata) if ok: print(f'ocsp issued at: {info[0]}, next check at: {info[1]}') else: print(f'ocsp is invalid') if tspdata is not None: ok, info = v.verify_tsp_data(signed_data, tspdata, othercerts) if ok: print(f'tsp issued at: {info}') else: print(f'tsp is invalid') if __name__ == '__main__': main() endesive-2.19.1/examples/pdf-verify-hsm.py000077500000000000000000000041711504236674500204600ustar00rootroot00000000000000#!/usr/bin/env vpython3 # coding: utf-8 import os import sys import sysconfig os.environ['SOFTHSM2_CONF'] = 'softhsm2.conf' if not os.path.exists(os.path.join(os.getcwd(), 'softhsm2.conf')): open('softhsm2.conf', 'wt').write('''\ log.level = DEBUG directories.tokendir = %s/softhsm2/ objectstore.backend = file slots.removable = false ''' % os.getcwd()) if not os.path.exists(os.path.join(os.getcwd(), 'softhsm2')): os.mkdir(os.path.join(os.getcwd(), 'softhsm2')) # #!/bin/bash #SOFTHSM2_CONF=softhsm2.conf #softhsm2-util --label "endesive" --slot 1 --init-token --pin secret1 --so-pin secret2 #softhsm2-util --show-slots # if sys.platform == 'win32': dllpath = r'W:\binw\SoftHSM2\lib\softhsm2-x64.dll' else: dllpath = os.path.join(sysconfig.get_config_var('LIBDIR'), "softhsm/libsofthsm2.so") from endesive import hsm, pdf import PyKCS11 as PK11 from asn1crypto import pem as asn1pem ''' Create two certificates: 1. self signed CA certificate with serial equal to HSM keyID=0x01 2. USER 1 certificate with serial equal to HSM keyID=0x666690 ''' class HSM(hsm.HSM): def main(self): cakeyID = bytes((0x1,)) ca_cert_pem = asn1pem.armor('CERTIFICATE', self.cert_load(cakeyID)) trusted_cert_pems = [ca_cert_pem] for fname in ( 'pdf-signed-cms-hsm.pdf', 'pdf-signed-cms-hsm-signed-cms-hsm.pdf', "pdf-signed-cms-hsm-signature_appearance.pdf", "pdf-signed-cms-hsm-signature_manual.pdf", ): print('*' * 20, fname) try: data = open(fname, 'rb').read() except: print('skip') continue results = pdf.verify(data, trusted_cert_pems) for i in range(len(results)): print('*'*10, 'signature #{}'.format(i+1)) (hashok, signatureok, certok) = results[i] print('signature ok?', signatureok) print('hash ok?', hashok) print('cert ok?', certok) def main(): cls = HSM(dllpath) cls.login("endesieve", "secret1") try: cls.main() finally: cls.logout() main() endesive-2.19.1/examples/pdf-verify-rsa_sha1.py000077500000000000000000000043551504236674500213760ustar00rootroot00000000000000#!/usr/bin/env vpython3 # *-* coding: utf-8 *-* import hashlib from endesive.pdf.PyPDF2 import PdfFileReader from cryptography import x509 from cryptography.exceptions import InvalidSignature from cryptography.hazmat.backends import default_backend from cryptography.hazmat.primitives import hashes from cryptography.hazmat.primitives.asymmetric import padding def main(): fname = "pdf-adobe-webcapture-x509.rsa_sha1.pdf" pdf = PdfFileReader(fname) catalog = pdf.trailer["/Root"] docmdp = catalog["/Perms"]["/DocMDP"] if 0: print(catalog) for k, v in catalog.items(): print(k, "=", v) if 0: print(docmdp) for k, v in docmdp.items(): print(k, "=", v) dtype = docmdp["/Type"] dcert = docmdp["/Cert"] dbyterange = docmdp["/ByteRange"] dcontents = docmdp["/Contents"] dfilter = docmdp["/Filter"] dsubfilter = docmdp["/SubFilter"] dmethod = docmdp["/Reference"][0]["/DigestMethod"] try: dl = docmdp["/Reference"][0]["/DigestLocation"] dv = docmdp["/Reference"][0]["/DigestValue"] except: dl = [0, 0] dv = 'aa' assert dl[0] == 0 and dl[1] == 0 and dv == 'aa' print(dfilter, dsubfilter, dmethod, dbyterange) assert dfilter == '/Adobe.PPKLite' assert dsubfilter == '/adbe.x509.rsa_sha1' assert dmethod == '/MD5' del pdf data = open(fname, "rb").read() data1 = data[dbyterange[0] : dbyterange[1]] data2 = data[dbyterange[2] : dbyterange[2] + dbyterange[3]] if 1: data = data1 + data2 else: # dirty games with dl and dv ? dig = hashlib.md5() dig.update(data1) if data2: dig.update(data2) data = dig.digest() if 0: open("a-cert.der", "wb").write(dcert) open("a-sig.der", "wb").write(signature) open("a-data-1.der", "wb").write(data1) open("a-data-2.der", "wb").write(data2) cert = x509.load_der_x509_certificate(dcert, default_backend()) signature = dcontents[3:] # ASN1 STRING pubkey = cert.public_key() try: pubkey.verify(signature, data, padding.PKCS1v15(), hashes.SHA1()) print('signature ok') except InvalidSignature: print('invalid signature') main() endesive-2.19.1/examples/pdf-verify.py000077500000000000000000000033161504236674500176730ustar00rootroot00000000000000#!/usr/bin/env vpython3 # *-* coding: utf-8 *-* from endesive import pdf def main(): trusted_cert_pems = ( # demo ca chain open("ca/demo2_ca.root.crt.pem", "rb").read(), # demo hsm ca chain #open("cert-hsm-ca.pem", "rb").read(), ) for fname in ( #"test-PDFXRef-signed-cms.pdf", #"test-PDFXRefStream-signed-cms.pdf", #"test-SHA256_RSA-signed-cms.pdf", #"pdf-acrobat.pdf", #"pdf-signed-cms-hsm-certum.pdf", #"pdf-signed-cms-hsm.pdf", "pdf-signed-cms.pdf", "pdf-signed-cms-hash.pdf", "pdf-signed-cms-ltv.pdf", "pdf-signed-cms-m32-actalis.pdf", "pdf-signed-cms-m32-unizeto.pdf", "pdf-signed-cms-pfx.pdf", "pdf-signed-cms-pil.pdf", "pdf-signed-cms-pypdf.pdf", "pdf-signed-cms-twice-1.pdf", "pdf-signed-cms-twice-2.pdf", "pdf-signed-cms-twice-end.pdf", "pdf-signed-fpdf.pdf", #"pdf-signed-java.pdf", #"pdf-signed-pypdf.pdf", #"pdf-encrypted-signed-java.pdf", #"pdf-encrypted-signed-pypdf.pdf", #"pdf-link-signed-java.pdf", #"pdf-link-signed-pypdf.pdf", ): print("*" * 20, fname) try: data = open(fname, "rb").read() except: print('skip') continue no = 0 try: for (hashok, signatureok, certok) in pdf.verify( data, trusted_cert_pems ): print("*" * 10, "signature no:", no) print("signature ok?", signatureok) print("hash ok?", hashok) print("cert ok?", certok) except Exception as exc: print(exc) main() endesive-2.19.1/examples/pdf_forms/000077500000000000000000000000001504236674500172175ustar00rootroot00000000000000endesive-2.19.1/examples/pdf_forms/blank_form.pdf000066400000000000000000000107111504236674500220240ustar00rootroot00000000000000%PDF-1.3 % ReportLab Generated PDF document http://www.reportlab.com 1 0 obj << /F1 2 0 R /F2 3 0 R >> endobj 2 0 obj << /BaseFont /Helvetica /Encoding /WinAnsiEncoding /Name /F1 /Subtype /Type1 /Type /Font >> endobj 3 0 obj << /BaseFont /Courier /Encoding /WinAnsiEncoding /Name /F2 /Subtype /Type1 /Type /Font >> endobj 4 0 obj <> endobj 5 0 obj << /BaseFont /Helvetica /Subtype /Type1 /Name /Helv /Type /Font /Encoding 4 0 R >> endobj 6 0 obj << /BBox [ 0 0 270 18 ] /Filter [ /FlateDecode ] /FormType 1 /Length 112 /Matrix [ 1 0 0 1 0 0 ] /Resources << /ProcSet [/PDF /Text] /Font <> >> /Subtype /Form /Type /XObject >> stream x%1 @Dw)I.q6!& "㻫 o7rAoڨӮ2meIc'DTt'@R ;_fYWz@?v|TVendstream endobj 7 0 obj << /AP << /N 6 0 R >> /BS << /S /S /W 1 >> /DA (/Helv 12 Tf 0 0 0 rg) /DV () /F 0 /FT /Tx /Ff 0 /MK << /BC [ 0 0 0 ] /BG [ ] >> /P 11 0 R /Rect [ 306 504 576 522 ] /Subtype /Widget /T (Name) /Type /Annot /V () >> endobj 8 0 obj << /BaseFont /Helvetica /Subtype /Type1 /Name /Helv /Type /Font /Encoding 4 0 R >> endobj 9 0 obj << /BBox [ 0 0 270 18 ] /Filter [ /FlateDecode ] /FormType 1 /Length 112 /Matrix [ 1 0 0 1 0 0 ] /Resources << /ProcSet [/PDF /Text] /Font <> >> /Subtype /Form /Type /XObject >> stream x%1 @Dw)I.q6!& "㻫 o7rAoڨӮ2meIc'DTt'@R ;_fYWz@?v|TVendstream endobj 10 0 obj << /FT /Sig /Type /Annot /Subtype /Widget /F 4 /T (Signature) /Rect [ 306 486 576 504 ] /P 11 0 R /AP << /N 9 0 R >> >> endobj 11 0 obj << /Annots [ 7 0 R 10 0 R ] /Contents 15 0 R /MediaBox [ 0 0 612 792 ] /Parent 14 0 R /Resources << /Font 1 0 R /ProcSet [ /PDF /Text /ImageB /ImageC /ImageI ] >> /Rotate 0 /Trans << >> /Type /Page >> endobj 12 0 obj << /AcroForm 16 0 R /PageMode /UseNone /Pages 14 0 R /Type /Catalog >> endobj 13 0 obj << /Author (anonymous) /CreationDate (D:20210307160844+05'00') /Creator (ReportLab PDF Library - www.reportlab.com) /Keywords () /ModDate (D:20210307160844+05'00') /Producer (ReportLab PDF Library - www.reportlab.com) /Subject (unspecified) /Title (untitled) /Trapped /False >> endobj 14 0 obj << /Count 1 /Kids [ 11 0 R ] /Type /Pages >> endobj 15 0 obj << /Filter [ /ASCII85Decode /FlateDecode ] /Length 184 >> stream Gat&EYmu@>&-h'`Vt`c)W4gVWAeT8@%!jQlZku>k$)#Tt\Mu9VP[&7Hjo<(85u0kR0+lhk[X/&nE"0+qJr_<>Oh:F6V`/%3W\QQ#K-OD:L(X*lO)&\BhY`@XA`0X*V!+siBV&Y3+cg:e7Tm^,rR=VkRqL/62n,q.+8m2,Ousc!C-Mek?DC4n1&~>endstream endobj 16 0 obj << /DA (/Helv 0 Tf 0 g) /DR << /Encoding << /RLAFencoding 4 0 R >> /Font << /Helv 5 0 R >> >> /Fields [ 7 0 R 10 0 R ] /SigFlags 1 >> endobj xref 0 17 0000000000 65535 f 0000000073 00000 n 0000000114 00000 n 0000000221 00000 n 0000000326 00000 n 0000001648 00000 n 0000001746 00000 n 0000002084 00000 n 0000002319 00000 n 0000002417 00000 n 0000002755 00000 n 0000002893 00000 n 0000003114 00000 n 0000003201 00000 n 0000003498 00000 n 0000003559 00000 n 0000003834 00000 n trailer << /ID [] % ReportLab generated PDF document -- digest (http://www.reportlab.com) /Info 13 0 R /Root 12 0 R /Size 17 >> startxref 3984 %%EOF endesive-2.19.1/examples/pdfbox.py000077500000000000000000000010471504236674500171010ustar00rootroot00000000000000#!/usr/bin/env vpython3 import os jars = [ 'java/debugger-app-2.0.14.jar', 'java/fontbox-2.0.14.jar', 'java/java.activation-1.1.1.jar', 'java/javax.xml.bind-2.2.3.jar', 'java/pdfbox-2.0.14.jar', 'java/pdfbox-app-2.0.14.jar', 'java/pdfbox-debugger-2.0.14.jar', 'java/pdfbox-showsignature.jar', 'java/pdfbox-tools-2.0.14.jar', 'java/preflight-2.0.14.jar', 'java/preflight-app-2.0.14.jar', 'java/xades4j-1.5.1.jar', 'java/xmpbox-2.0.14.jar', ] os.environ['CLASSPATH'] = ':'.join(jars) os.environ['JAVA_HOME'] = '/usr/lib/jvm/default-java' import jnius endesive-2.19.1/examples/pdfboxValidate.py000077500000000000000000000012271504236674500205530ustar00rootroot00000000000000#!/usr/bin/env vpython3 import sys import pdfbox from jnius import autoclass pdfname = 'pdf.pdf' if len(sys.argv) > 1: pdfname = sys.argv[1] parser = autoclass('org.apache.pdfbox.preflight.parser.PreflightParser')(pdfname) parser.parse() #org.apache.pdfbox.preflight.PreflightDocument document = parser.getPreflightDocument() document.validate() result = document.getResult() document.close() if result.isValid(): print("The file:{} is a valid PDF/A-1b file".format(pdfname)) else: print("The file: {} is not valid, error(s) :".format(pdfname)) for error in result.getErrorsList(): print(error.getErrorCode(), " : ", error.getDetails()) endesive-2.19.1/examples/pdfviewer.py000077500000000000000000000022051504236674500176070ustar00rootroot00000000000000#!/usr/bin/env vpython3 import wx import wx.lib.sized_controls as sc import sys from wx.lib.pdfviewer import pdfViewer, pdfButtonPanel class PDFViewer(sc.SizedFrame): def __init__(self, parent, **kwds): super(PDFViewer, self).__init__(parent, **kwds) paneCont = self.GetContentsPane() self.buttonpanel = pdfButtonPanel(paneCont, wx.NewId(), wx.DefaultPosition, wx.DefaultSize, 0) self.buttonpanel.SetSizerProps(expand=True) self.viewer = pdfViewer(paneCont, wx.NewId(), wx.DefaultPosition, wx.DefaultSize, wx.HSCROLL|wx.VSCROLL|wx.SUNKEN_BORDER) self.viewer.SetSizerProps(expand=True, proportion=1) # introduce buttonpanel and viewer to each other self.buttonpanel.viewer = self.viewer self.viewer.buttonpanel = self.buttonpanel if __name__ == '__main__': import wx.lib.mixins.inspection as WIT app = WIT.InspectableApp(redirect=False) fname = sys.argv[1] pdfV = PDFViewer(None, size=(800, 600)) pdfV.viewer.LoadFile(fname) pdfV.Show() app.MainLoop()endesive-2.19.1/examples/plain-make.py000077500000000000000000000005661504236674500176420ustar00rootroot00000000000000#!/usr/bin/env vpython3 # *-* coding: utf-8 *-* import io def main(): io.open('plain-unsigned.txt', 'wt', encoding='utf-8').write('''\ Witam, Fantastycznie, że zechciałeś popatrzeć na tę bibliotekę. Mam nadzieję, że będzie dla Ciebie użyteczna. Pozdrawiam, Grzegorz Makarewicz ''' ) main() endesive-2.19.1/examples/plain-openssl.sh000077500000000000000000000022761504236674500203720ustar00rootroot00000000000000#!/bin/bash # http://qistoph.blogspot.com/2012/01/manual-verify-pkcs7-signed-data-with.html # https://security.stackexchange.com/questions/176329/verify-s-mime-signature-with-no-certificate-included sign1() { openssl smime -sign \ -md sha256 \ -binary \ -CAfile ca/demo2_ca.sub.crt.pem \ -in $1 -out $2 -outform der \ -inkey ca/demo2_user1.key.pem -passin pass:1234 \ -signer ca/demo2_user1.crt.pem } sign2() { cat ca/demo2_user1.crt.pem ca/demo2_ca.sub.crt.pem >x-cert.tmp openssl smime -sign \ -md sha256 \ -binary -noattr \ -CAfile ca/demo2_ca.root.crt.pem \ -in $1 -out $2 -outform der \ -inkey ca/demo2_user1.key.pem -passin pass:1234 \ -signer x-cert.tmp rm x-cert.tmp } verify() { openssl smime -verify \ -CAfile ca/root.pem \ -content $1 \ -in $2 -inform der } if [ -z "$1" ]; then echo "************************** attr" sign1 plain-unsigned.txt plain-ssl-signed-attr.txt verify plain-unsigned.txt plain-ssl-signed-attr.txt echo "************************** noattr" sign2 plain-unsigned.txt plain-ssl-signed-noattr.txt verify plain-unsigned.txt plain-ssl-signed-noattr.txt else echo "************************** verify" verify plain-unsigned.txt $1 fi endesive-2.19.1/examples/plain-sign-attr.py000077500000000000000000000010551504236674500206270ustar00rootroot00000000000000#!/usr/bin/env vpython3 # *-* coding: utf-8 *-* from cryptography.hazmat import backends from cryptography.hazmat.primitives.serialization import pkcs12 from endesive import plain def main(): with open('ca/demo2_user1.p12', 'rb') as fp: p12 = pkcs12.load_key_and_certificates(fp.read(), b'1234', backends.default_backend()) datau = open('plain-unsigned.txt', 'rb').read() datas = plain.sign(datau, p12[0], p12[1], p12[2], 'sha256', attrs=True ) open('plain-signed-attr.txt', 'wb').write(datas) main() endesive-2.19.1/examples/plain-sign-noattr.py000077500000000000000000000010601504236674500211600ustar00rootroot00000000000000#!/usr/bin/env vpython3 # *-* coding: utf-8 *-* from cryptography.hazmat import backends from cryptography.hazmat.primitives.serialization import pkcs12 from endesive import plain def main(): with open('ca/demo2_user1.p12', 'rb') as fp: p12 = pkcs12.load_key_and_certificates(fp.read(), b'1234', backends.default_backend()) datau = open('plain-unsigned.txt', 'rb').read() datas = plain.sign(datau, p12[0], p12[1], p12[2], 'sha256', attrs=False ) open('plain-signed-noattr.txt', 'wb').write(datas) main() endesive-2.19.1/examples/plain-sign-pss.py000077500000000000000000000010761504236674500204650ustar00rootroot00000000000000#!/usr/bin/env vpython3 # *-* coding: utf-8 *-* from cryptography.hazmat import backends from cryptography.hazmat.primitives.serialization import pkcs12 from endesive import plain def main(): with open('ca/demo2_user1.p12', 'rb') as fp: p12 = pkcs12.load_key_and_certificates(fp.read(), b'1234', backends.default_backend()) datau = open('plain-unsigned.txt', 'rb').read() datas = plain.sign(datau, p12[0], p12[1], p12[2], 'sha512', attrs=True, pss=True ) open('plain-signed-pss.txt', 'wb').write(datas) main() endesive-2.19.1/examples/plain-verify.py000077500000000000000000000015711504236674500202260ustar00rootroot00000000000000#!/usr/bin/env vpython3 # *-* coding: utf-8 *-* from endesive import plain def main(): #trusted_cert_pems = (open('ca/demo2_ca.root.crt.pem', 'rb').read(),) trusted_cert_pems = (open('ca/root.pem', 'rb').read(),) datau = open('plain-unsigned.txt', 'rb').read() for fname in ( 'plain-ssl-signed-attr.txt', 'plain-ssl-signed-noattr.txt', 'plain-signed-attr.txt', 'plain-signed-noattr.txt', 'plain-signed-pss.txt', ): print('*' * 20, fname) try: datas = open(fname, 'rb').read() except FileNotFoundError: print("no such file", fname) continue (hashok, signatureok, certok) = plain.verify(datas, datau, trusted_cert_pems) print('signature ok?', signatureok) print('hash ok?', hashok) print('cert ok?', certok) main() endesive-2.19.1/examples/signature_appearances/000077500000000000000000000000001504236674500216035ustar00rootroot00000000000000endesive-2.19.1/examples/signature_appearances/signature-existing-field.py000077500000000000000000000050251504236674500270740ustar00rootroot00000000000000#!/usr/bin/env vpython3 # *-* coding: utf-8 *-* import sys import datetime from cryptography.hazmat import backends from cryptography.hazmat.primitives.serialization import pkcs12 from endesive.pdf import cms # from endesive.pdf import cmsn as cms # import logging # logging.basicConfig(level=logging.DEBUG) def main(): date = datetime.datetime.utcnow() - datetime.timedelta(hours=12) date = date.strftime("D:%Y%m%d%H%M%S+00'00'") dct = { "aligned": 0, "sigflags": 3, "sigflagsft": 132, "sigpage": 0, #"auto_sigfield": False, #"sigandcertify": False, #"signaturebox": (0, 0, 590, 155), "signform": True, "sigfield": "Signature", "signature_manual": [ # R G B ['fill_colour', 0.95, 0.95, 0.95], # *[bounding box] ['rect_fill', 0, 0, 270, 18], # R G B ['stroke_colour', 0.8, 0.8, 0.8], # key *[bounding box] ['image', 'sig0', 0, 0, 59, 15], # inset ['border', 2], # font fs ['font', 'default', 7], # R G B ['fill_colour', 0, 0, 0], # text ['text_box', 'signed using endesive\ndate: {}'.format(date), # font *[bounding box], fs, wrap, align, baseline 'default', 0, 2, 270, 18, 7, True, 'right', 'top'], ], # key: name used in image directives # value: PIL Image object or path to image file "manual_images": {'sig0': '../signature_test.png'}, # key: name used in font directives # value: path to TTF Font file "manual_fonts": {}, "contact": "mak@trisoft.com.pl", "location": "Szczecin", "signingdate": date, "reason": "Dokument podpisany cyfrowo aą cć eę lł nń oó sś zż zź", "password": "1234", } with open("../ca/demo2_user1.p12", "rb") as fp: p12 = pkcs12.load_key_and_certificates( fp.read(), b"1234", backends.default_backend() ) fname = "../pdf_forms/blank_form.pdf" if len(sys.argv) > 1: fname = sys.argv[1] datau = open(fname, "rb").read() datas = cms.sign(datau, dct, p12[0], p12[1], p12[2], "sha256") fname = fname.replace(".pdf", "-signature-existing-field.pdf") with open(fname, "wb") as fp: fp.write(datau) fp.write(datas) main() endesive-2.19.1/examples/signature_appearances/signature.py000077500000000000000000000033351504236674500241650ustar00rootroot00000000000000#!/usr/bin/env vpython3 # *-* coding: utf-8 *-* import sys import datetime from cryptography.hazmat import backends from cryptography.hazmat.primitives.serialization import pkcs12 from endesive.pdf import cms # from endesive.pdf import cmsn as cms # import logging # logging.basicConfig(level=logging.DEBUG) def main(): date = datetime.datetime.utcnow() - datetime.timedelta(hours=12) date = date.strftime("D:%Y%m%d%H%M%S+00'00'") dct = { "aligned": 0, "sigflags": 3, "sigflagsft": 132, "sigpage": 0, #"auto_sigfield": False, #"sigandcertify": False, #"signaturebox": (0, 0, 590, 155), "signform": True, "sigfield": "Signature", # Text will be in the default font "signature": 'Signed field!', # default configuration for the text appearance "text": { 'wraptext': True, 'fontsize': 12, 'textalign': 'left', 'linespacing': 1.2, }, "contact": "mak@trisoft.com.pl", "location": "Szczecin", "signingdate": date, "reason": "Dokument podpisany cyfrowo aą cć eę lł nń oó sś zż zź", "password": "1234", } with open("../ca/demo2_user1.p12", "rb") as fp: p12 = pkcs12.load_key_and_certificates( fp.read(), b"1234", backends.default_backend() ) fname = "../pdf_forms/blank_form.pdf" if len(sys.argv) > 1: fname = sys.argv[1] datau = open(fname, "rb").read() datas = cms.sign(datau, dct, p12[0], p12[1], p12[2], "sha256") fname = fname.replace(".pdf", "-signature.pdf") with open(fname, "wb") as fp: fp.write(datau) fp.write(datas) main() endesive-2.19.1/examples/signature_appearances/signature_appearance.py000077500000000000000000000041711504236674500263430ustar00rootroot00000000000000#!/usr/bin/env vpython3 # *-* coding: utf-8 *-* import sys import datetime from cryptography.hazmat import backends from cryptography.hazmat.primitives.serialization import pkcs12 from endesive.pdf import cms # from endesive.pdf import cmsn as cms # import logging # logging.basicConfig(level=logging.DEBUG) def main(): date = datetime.datetime.utcnow() - datetime.timedelta(hours=12) date = date.strftime("D:%Y%m%d%H%M%S+00'00'") dct = { "aligned": 0, "sigflags": 3, "sigflagsft": 132, "sigpage": 0, "auto_sigfield": True, #"sigandcertify": False, "signaturebox": (72, 396, 360, 468), "signform": False, "sigfield": "Signature", # Text will be in the default font # Fields in the list display will be included in the text listing # Icon and background can both be set to images by having their # value be a path to a file or a PIL Image object # If background is a list it is considered to be an opaque RGB colour # Outline is the colour used to draw both the border and the text "signature_appearance": { 'background': [0.75, 0.8, 0.95], 'icon': '../signature_test.png', 'outline': [0.2, 0.3, 0.5], 'border': 2, 'labels': True, 'display': 'CN,DN,date,contact,reason,location'.split(','), }, "contact": "mak@trisoft.com.pl", "location": "Szczecin", "signingdate": date, "reason": "Dokument podpisany cyfrowo aą cć eę lł nń oó sś zż zź", "password": "1234", } with open("../ca/demo2_user1.p12", "rb") as fp: p12 = pkcs12.load_key_and_certificates( fp.read(), b"1234", backends.default_backend() ) fname = "../pdf_forms/blank_form.pdf" if len(sys.argv) > 1: fname = sys.argv[1] datau = open(fname, "rb").read() datas = cms.sign(datau, dct, p12[0], p12[1], p12[2], "sha256") fname = fname.replace(".pdf", "-signature_appearance.pdf") with open(fname, "wb") as fp: fp.write(datau) fp.write(datas) main() endesive-2.19.1/examples/signature_appearances/signature_img.py000077500000000000000000000033221504236674500250150ustar00rootroot00000000000000#!/usr/bin/env vpython3 # *-* coding: utf-8 *-* import sys import datetime from cryptography.hazmat import backends from cryptography.hazmat.primitives.serialization import pkcs12 from endesive.pdf import cms # from endesive.pdf import cmsn as cms # import logging # logging.basicConfig(level=logging.DEBUG) def main(): date = datetime.datetime.utcnow() - datetime.timedelta(hours=12) date = date.strftime("D:%Y%m%d%H%M%S+00'00'") dct = { "aligned": 0, "sigflags": 3, "sigflagsft": 132, "sigpage": 0, #"auto_sigfield": False, #"sigandcertify": False, #"signaturebox": (0, 0, 590, 155), "signform": True, "sigfield": "Signature", # PIL Image object or path to image file # Image will be resized to fit bounding box "signature_img": '../signature_test.png', "signature_img_distort": False, # default True "signature_img_centred": False, # default True "contact": "mak@trisoft.com.pl", "location": "Szczecin", "signingdate": date, "reason": "Dokument podpisany cyfrowo aą cć eę lł nń oó sś zż zź", "password": "1234", } with open("../ca/demo2_user1.p12", "rb") as fp: p12 = pkcs12.load_key_and_certificates( fp.read(), b"1234", backends.default_backend() ) fname = "../pdf_forms/blank_form.pdf" if len(sys.argv) > 1: fname = sys.argv[1] datau = open(fname, "rb").read() datas = cms.sign(datau, dct, p12[0], p12[1], p12[2], "sha256") fname = fname.replace(".pdf", "-signature_img.pdf") with open(fname, "wb") as fp: fp.write(datau) fp.write(datas) main() endesive-2.19.1/examples/signature_appearances/signature_manual.py000077500000000000000000000050561504236674500255240ustar00rootroot00000000000000#!/usr/bin/env vpython3 # *-* coding: utf-8 *-* import sys import datetime from cryptography.hazmat import backends from cryptography.hazmat.primitives.serialization import pkcs12 from endesive.pdf import cms # from endesive.pdf import cmsn as cms # import logging # logging.basicConfig(level=logging.DEBUG) def main(): date = datetime.datetime.utcnow() - datetime.timedelta(hours=12) date = date.strftime("D:%Y%m%d%H%M%S+00'00'") dct = { "aligned": 0, "sigflags": 3, "sigflagsft": 132, "sigpage": 0, #"auto_sigfield": False, #"sigandcertify": False, #"signaturebox": (0, 0, 590, 155), "signform": True, "sigfield": "Signature", "signature_manual": [ # R G B ['fill_colour', 0.95, 0.95, 0.95], # *[bounding box] ['rect_fill', 0, 0, 270, 18], # R G B ['stroke_colour', 0.8, 0.8, 0.8], # inset ['border', 2], # key *[bounding box] distort centred ['image', 'sig0', 0, 0, 270, 18, False, False], # font fs ['font', 'default', 7], # R G B ['fill_colour', 0, 0, 0], # text ['text_box', 'signed using endesive\ndate: {}'.format(date), # font *[bounding box], fs, wrap, align, baseline 'default', 0, 2, 270, 18, 7, True, 'right', 'top'], ], # key: name used in image directives # value: PIL Image object or path to image file "manual_images": {'sig0': '../signature_test.png'}, # key: name used in font directives # value: path to TTF Font file "manual_fonts": {}, "contact": "mak@trisoft.com.pl", "location": "Szczecin", "signingdate": date, "reason": "Dokument podpisany cyfrowo aą cć eę lł nń oó sś zż zź", "password": "1234", } with open("../ca/demo2_user1.p12", "rb") as fp: p12 = pkcs12.load_key_and_certificates( fp.read(), b"1234", backends.default_backend() ) fname = "../pdf_forms/blank_form.pdf" if len(sys.argv) > 1: fname = sys.argv[1] datau = open(fname, "rb").read() datas = cms.sign(datau, dct, p12[0], p12[1], p12[2], "sha256") fname = fname.replace(".pdf", "-signature_manual.pdf") with open(fname, "wb") as fp: fp.write(datau) fp.write(datas) main() endesive-2.19.1/examples/signature_test.png000066400000000000000000000301301504236674500210030ustar00rootroot00000000000000PNG  IHDRN5@ IDATx^ 8UT*-*bV4<*ZADAL}^|$( "4 VP !RZX EQ hˣ""XZ (psϝݝݝ}77;s;39y #B@!P[TR!! B@q$B@! @%"N@B@! D4B@!PS%P*&B@'! B@T" T ! B@Is@! 8UbB@! qB@! @%"N@ةUf43b3{+36vHX! 8 "N hf~ NC$ʉԿZ^B@  + T$R! @@I3{yrH΄7ݽϻH ! nӍ]C/'z Q.:A#r"uA(%! A@ĩ%9"cf҄Vi0wF9  ?HLB@!"N+{jq~/3#*m.Ai DfNՑC4RhAG }#80"NAN7/0vm| 8k>h0 _Qޚà# Aswmw̞Em%>J&=x(Em5"jG!!"N}?@|3qErWEFM ! B`o#N/6g#j~`[:8 'F _z!%9/2w2gO u"N ѫhVp{;'p_nfx@\Qx1tb.~.W?# +֘ӗ٧"-xy(wv#8'!0rz=sn%zO7qQuH)fN#3xi~m8]{|[) X߽ecu}vG`:fO }wش0FwUfQ2\y.D0Ӻ^LXb>%H<@]r:&wvwеjoz8ბ1`t-6·@LQ5dĿ"rH\ AGF@i6t{1'O:} 5Z<ёs2ѝ h~IܯG+nX-h=Fb~~}&U ~NQ~;p<8gճfllnZwB&pocB<Y[3CgQFU:W="Nc~#A%Q5'ONiD}8?3-G]Kw'`IwMA*_r:f3BW{=/fƨ#qҤEqĹ&Zħ h(OUݝ:;9h:'|=B5'7Gd zl t:/Z6yE ]o @~xn?3Ɨ]úZܗbdH~b$fC+S!6>LZë ;bNy4YdB2Ijp珫l':/]|ݿ4gp Y2N@1Ζ7_2 HYK{2DN6`;f}6*ɗ:b qj*}7\fL'9A\y?3%i|fץ9ժ-q ƂTn hտ~WV^ )Cʁ֚9EKߋ+$軳nmD! 8/M7:ch]I3F9ʷ1x->7B/'yxaf0G5Nx=QTmyZ{jՇ)(nPVX̆iĖ4 %l%}9-gM5) hcG fȹ$$:+QBZ&=-9#/cAйGrBjl^_3r8s(>-oou9D.he|Ah#<"N;>dܤcqm2|UxNKs$T}u4sq 0}C@"KOl`FTD9LS[D ̾HO2W6Z=89yl5nՑkAkz.JDjPڦL&"[!9z~]шUѡ;熙fd|qKVΆ6lK`@By.i([~O53e2;FNoNafh>%l8fci?~_yӶF8g`_^~efAR#~ޮ}oSGm yh6)"F~#S1 Ҟ\?5.ıKZR,K;"N[Fq6WؼE3bjӻEUNKgm͌(4"zJO4֛Rnzk7um6%|GSCͩms:mR9,en]z[ĤEl2 oic^7]wtx%9EVvFQ f3{.1Gُ;`ò:!o(SM$d%D>P#L9E U"N'Z]"FƗHu>j}ZmTAo X5PWg4յΦ=U9gaghD7~ʳȑVےEHWCNKJS`.˹w#Qfy15!mn'|< IqLW&O:$8dlC@:΢SQNilCԎpLj o-jeciF0%Ny-|k}}c-59Rd>qlf6[ 2LTv9#O2qz6%63{fKv{l" *HZ ;t^nih)i$Ք QTؼ> ʐucos*Z|7kt*[y{s޹p(?{M:Y igNc'5L\y'o4}_Iri 򨔢(\ m$K|ҢDU ] f]Q3#re;x]co"^dұF %9b09QrS`vkӚ2޿bjL1MuLi75KrK\4[mP$1%RMT$`J|+1 WE^ޝ8+N|8}}YaUӷsq"s}Q55s,-I=ؘ礝cORdbo|O}m,UGX]L:{ٚy׷yh3{aW8'Wg<]j6Gc*^qq&uV(ñv4(s,/k_ɞrִ-p K35g-qN^aR XfKca:~Ӊ%7]&FE&vⵛU#ouyg354(AsXM:α&}su6G֘?Mj5PK1yof➲oGϩϾF>?JiJLƲ>WSRfI3:_G/.'U9X'Yѡd3~kW%۲\ԶiUSN͢Id @L%Mmcx=sLF/p =10`؇?o鑨b&Nq/!O5$ƻUs4KۜwR&ꯨY;:wW ̾x5Y1y21&:϶]{~|}E$rڼHw}7|A4/q}}kws<7odM4Q0Ҹ;̞ރU ?Ē.6WD)1\b>5-;Vի<<ՌU}~ܑ8p 0xf7윉 )fj&.C%mޔ3;OLZlhR}@40e!֟k.G~tBJ2DWm8~ɱ|Hq|+TM57 G67 j;[flMnKXgh##SyCɝ4&&PʉT]#1+c0C7NrЮrcI*2k"kDLUCf=]ƤܧQB'dc|Yc9GX` }iymQ[VGս-b6{ l4&|qfN8D5Ox>s]ܠ~.j43_84 $'ʑ}XsF4oUF3{|4NcC^FA],c~ ف&f#wR`6,5 {}KƩIsѐ "jN,Z޶Y9wC)BINEYx(S2wiv vфj\%,6GȼI_ 3d޲_k4l5\WQfj.ms~3ˉB[:>\s|vRm*Yqf|h={v@Jf1tĉkU {f+/ 6K$ jJ>o0OF&| 3$ĩ&mK:s{oMpRzkZS0 EL_F\8`KĩDP_= a#.opvN@@ǜ4p>>)h߶e蓋l>_p/N?xFH%VDSMoٟB|qwD"qqL[_ߣწP;Z0g^wf?A|el1>-y:Lr4F5q*&&ȔE42j(=/==ApYV7Gu]|S6B"!1zkSܾ^st<՚ /1_=BZͩ8e-k᜾ռ4s&FMr9ʔW3 =eJ7˚\n/Ţ}iˍ:G!YJ䣏<~o&{ZB՗oٻvi#ixeq7f;XM1-磿:4ɦ?ʗ|_spfM:!>7ի " 6jC&ShM[qmQ Їr~XE(Oz|6"QJ<,NQ6F2VS 95 jIDATwe 3{Ta.\>hSp?&IAQ76q~m-򨗵JcqQ>"$DRiIάs]B?Al966Ms4>\lj<[Yನ,[rsߞ >ל qœ٧@|'pJ;f{\(sXyD9&)m^pȗs^\ǡki/$Y['4tFvѹ& GCǸzyեsc~MCvnY++e6S$#7#kksjq J s!<j$3_WQju4uRD}j^$O95nH(^Zִi+˧17O?id4_и{T]6Sk)5tkB#3]yԣ a+`5n[u*^3֩kٯ9uȺVoU3}~ty,GLsg:F%Α,dْ1`(pOǝe*匚ݡo'W#p.4;M%CcyV_*NWzVE+aӲ/ĽTMPx¼\%mE.F<N<5~M;O5WOef:)oiMBt6m#Ϝo';Dlo,U9JE9zw)6;ϑTw&k ka+HμN5즺o3Tj2hfήwI*ޖ,o)"Ч%d*P ̞qA\Wa\#6 o"-Ө pݢ޾[}6%UG97 7-1ļnn9_杳h.Z6x"$δ}fjթf14fZFLq^-U "t bx&5LsM))`ȡz~Iٕ=3N\4 N8]NiOC)|68j ehf8>~'4P'H4ͱIv[9edX?&n\(Dȳ)Aڲ7ىSkgo џ'QQ_i1$&ډ\q8"6ƚe+7ׄ&Kny`["s aTJYp8,iIn8 /=4:R-.qj;JWKTm%^R2鍇W2P[FJ1}N)}LfΖ5Z"NAidF%~sV`Z8sҾztE,eoWmXrcL<4>>&~{}EVuJK&S$N y㎚l>Qhk7ORSyMo&7o0PԐ(?_q:pٳ?]+6 ޽N-cVuZK|<W(]|(!19r4n *0&ަ3A.o8]kKh (<*MwQ#\z`FJlL꘨پ>v1'/s9ˆW[\0AEEcbi)Ay뗹411fHVW̑MlF@ WNpI>)[LNdavŶ}]ZO\Nă7AtO/4S ̦&~S3O[E{ -^+@Rs5h0%"l5\4Nk ~:E6 +x6hU ʃ6P}Z3hέQ\^Ey_9YGxbqm|W}sz^D 4̞lf?>9C'|2b^(`R_tׅ<~H'@ '͋ ̆.9a$OGJ] sJR [# t켧݇HH}; 8݉c awh{|<@d|QPB@T! T a#dJhqj}ZX(RK [ taV'|XLz=`SUC# tpB`5p|O4AǤuZmUKqZF|g]K?mfID~+ q B>wyIT1h*"8mZGF}n[5Nlc ل80"N&vB'sBԵモNfG@ĩ+wCkdw MB8rX$8@#E'H+͌:#8$"N %/ j| Mh0} Jt κ(=! 6A@iՈ (yfQpK7kt_e:"5Uk#wy0 Z$ǘ{]_!0ɐ! 8/ D(~z1B`wDv NZ%9yًܷ:tB@z,D&~yEݚ2n! @5"NPB@!pwD>! BjTP! ;"NwB@!PS5T*(B@_! F@ĩ*B@! g/B@T# T ! wG@3@B@! qJB@# t ! 8UCB@! q PB@jDRA! B8}B@! @5"NPB@!pwD>! BjTP! ;"NwB@!PS5T*(B@_! F@ĩ*B@! g/B@T# T ! wG@3@B@! qJB@# t ! 8UCB@! q PB@jDRA! B8}B@! @5"NPB@!pwD>! B_Gn2AIENDB`endesive-2.19.1/examples/smime-decrypt.py000077500000000000000000000015631504236674500204040ustar00rootroot00000000000000#!/usr/bin/env vpython3 # *-* coding: utf-8 *-* import io from cryptography.hazmat import backends from cryptography.hazmat.primitives.serialization import pkcs12 from endesive import email def main(): with open('ca/demo2_user1.p12', 'rb') as fp: p12 = pkcs12.load_key_and_certificates(fp.read(), b'1234', backends.default_backend()) for fname in ( 'smime-ssl-encrypted.txt', 'smime-ssl-oaep-encrypted.txt', 'smime-encrypted.txt', 'smime-encrypted-oaep.txt', ): print('*' * 20, fname) try: datae = io.open(fname, 'rt', encoding='utf-8').read() except: print('no such file') continue datad = email.decrypt(datae, p12[0]) datad = datad.decode('utf-8') io.open(fname.replace('encrypted', 'decrypted'), 'wt', encoding='utf-8').write(datad) main() endesive-2.19.1/examples/smime-encrypt.py000077500000000000000000000012401504236674500204060ustar00rootroot00000000000000#!/usr/bin/env vpython3 # *-* coding: utf-8 *-* from cryptography import x509 from cryptography.hazmat import backends from endesive import email, signer def load_cert(relative_path): with open(relative_path, 'rb') as f: return x509.load_pem_x509_certificate(f.read(), backends.default_backend()) def main(): certs = ( load_cert('ca/demo2_user1.crt.pem'), ) datau = open('smime-unsigned.txt', 'rb').read() datae = email.encrypt(datau, certs, 'aes256_ofb') open('smime-encrypted.txt', 'wt').write(datae) datae = email.encrypt(datau, certs, 'aes256_ofb', True) open('smime-encrypted-oaep.txt', 'wt').write(datae) main() endesive-2.19.1/examples/smime-make.py000077500000000000000000000005661504236674500176510ustar00rootroot00000000000000#!/usr/bin/env vpython3 # *-* coding: utf-8 *-* import io def main(): io.open('smime-unsigned.txt', 'wt', encoding='utf-8').write('''\ Witam, Fantastycznie, że zechciałeś popatrzeć na tę bibliotekę. Mam nadzieję, że będzie dla Ciebie użyteczna. Pozdrawiam, Grzegorz Makarewicz ''' ) main() endesive-2.19.1/examples/smime-openssl.sh000077500000000000000000000050571504236674500204010ustar00rootroot00000000000000#!/bin/bash sign1() { openssl smime -sign -CAfile ca/root.pem -signer $1 -inkey $2 -passin pass:1234 -outform SMIME -in $3 -out $4 } sign2() { openssl smime -sign -noattr -CAfile ca/root.pem -signer $1 -inkey $2 -passin pass:1234 -outform SMIME -in $3 -out $4 } encrypt() { openssl smime -encrypt -aes256 -in $2 -out $3 $1 } decrypt() { openssl smime -decrypt -recip $1 -inkey $2 -passin pass:1234 -in $3 } verify() { openssl smime -verify -CAfile ca/root.pem -in $1 -inform SMIME } psssign() { openssl cms -sign -signer $1 -inkey $2 -passin pass:1234 -in $3 -out $4 -keyopt rsa_padding_mode:pss -md sha512 } pssverify() { openssl cms -verify -signer $1 -CAfile ca/root.pem -in $2 -keyopt rsa_padding_mode:pss -md sha512 } oaepencrypt() { openssl cms -encrypt -recip $1 -in $2 -out $3 -keyopt rsa_padding_mode:oaep -md sha512 } oaepdecrypt() { openssl cms -decrypt -recip $1 -inkey $2 -passin pass:1234 -in $3 } detached() { openssl smime -sign -in $3 -signer $1 -inkey $2 -passin pass:1234 -outform der -binary -out $4 } detachedverify() { openssl smime -verify -in $2 -inform der -content $1 -CAfile ca/root.pem } if [ -z "$1" ]; then echo "************************** attr" sign1 ca/demo2_user1.crt.pem ca/demo2_user1.key.pem smime-unsigned.txt smime-ssl-signed-attr.txt verify smime-ssl-signed-attr.txt echo "************************** noattr" sign2 ca/demo2_user1.crt.pem ca/demo2_user1.key.pem smime-unsigned.txt smime-ssl-signed-noattr.txt verify smime-ssl-signed-noattr.txt echo "************************** detached" detached ca/demo2_user1.crt.pem ca/demo2_user1.key.pem smime-unsigned.txt smime-ssl-signed-detached.p7s detachedverify smime-unsigned.txt smime-ssl-signed-detached.p7s echo "************************** encrypt" encrypt ca/demo2_user1.crt.pem smime-unsigned.txt smime-ssl-encrypted.txt decrypt ca/demo2_user1.crt.pem ca/demo2_user1.key.pem smime-ssl-encrypted.txt echo "************************** pss sign" psssign ca/demo2_user1.crt.pem ca/demo2_user1.key.pem smime-unsigned.txt smime-ssl-pss-signed.txt pssverify ca/demo2_user1.crt.pem smime-ssl-pss-signed.txt echo "************************** oaep encrypt" oaepencrypt ca/demo2_user1.crt.pem smime-unsigned.txt smime-ssl-oaep-encrypted.txt oaepdecrypt ca/demo2_user1.crt.pem ca/demo2_user1.key.pem smime-ssl-oaep-encrypted.txt else if [ -z "$2" ]; then echo "************************** $1" verify $1 else decrypt ca/demo2_user1.crt.pem ca/demo2_user1.key.pem $1 fi fi endesive-2.19.1/examples/smime-sign-attr-custom.py000077500000000000000000000020331504236674500221430ustar00rootroot00000000000000#!/usr/bin/env vpython3 # *-* coding: utf-8 *-* from cryptography.hazmat import backends from cryptography.hazmat.primitives.serialization import pkcs12 from endesive import email import hashlib from asn1crypto import cms, algos, core, pem, x509 def main(): with open('ca/demo2_user1.p12', 'rb') as fp: p12 = pkcs12.load_key_and_certificates(fp.read(), b'1234', backends.default_backend()) datau = open('smime-unsigned.txt', 'rb').read() datau1 = datau.replace(b'\n', b'\r\n') hashalgo = 'sha256' signed_value = getattr(hashlib, hashalgo)(datau1).digest() attrs = [ cms.CMSAttribute({ 'type': cms.CMSAttributeType('content_type'), 'values': ('data',), }), cms.CMSAttribute({ 'type': cms.CMSAttributeType('message_digest'), 'values': (signed_value,), }), ] datas = email.sign(datau, p12[0], p12[1], p12[2], 'sha256', attrs=attrs ) open('smime-signed-attr-custom.txt', 'wb').write(datas) main() endesive-2.19.1/examples/smime-sign-attr.py000077500000000000000000000010551504236674500206360ustar00rootroot00000000000000#!/usr/bin/env vpython3 # *-* coding: utf-8 *-* from cryptography.hazmat import backends from cryptography.hazmat.primitives.serialization import pkcs12 from endesive import email def main(): with open('ca/demo2_user1.p12', 'rb') as fp: p12 = pkcs12.load_key_and_certificates(fp.read(), b'1234', backends.default_backend()) datau = open('smime-unsigned.txt', 'rb').read() datas = email.sign(datau, p12[0], p12[1], p12[2], 'sha256', attrs=True ) open('smime-signed-attr.txt', 'wb').write(datas) main() endesive-2.19.1/examples/smime-sign-hsm.py000077500000000000000000000102501504236674500204500ustar00rootroot00000000000000#!/usr/bin/env vpython3 # *-* coding: utf-8 *-* import os import stat import subprocess import datetime import base64 import email from email.mime.multipart import MIMEMultipart from email.mime.application import MIMEApplication from email.mime.text import MIMEText from email.mime.base import MIMEBase from cryptography.hazmat import backends from cryptography.hazmat.primitives import serialization from cryptography.hazmat.primitives.serialization import pkcs12 from endesive.hsm import SSHAgentHSM from endesive import signer def compose(From, To, Subject, Body, Attachment, signer): # create message object instance msg = MIMEMultipart(_subtype="signed", micalg="SHA1", protocol="application/pkcs7-signature") # setup the parameters of the message msg['From'] = From msg['To'] = To msg['Subject'] = Subject msg['Date'] = email.utils.format_datetime(datetime.datetime.now()) msg.preamble = "This is a multipart message in MIME format." env = MIMEMultipart(_subtype='mixed') body = MIMEText(Body.decode()) del body['MIME-Version'] env.attach(body) app = MIMEApplication(open(Attachment, 'rb').read(), _subtype="pdf") app.add_header('content-disposition', 'attachment', filename=Attachment) env.attach(app) msg.attach(env) sig = MIMEBase(_maintype='application', _subtype='pkcs7-signature', name="smime.p7s") sig.add_header('Content-Disposition', 'attachment', filename='smime.p7s') sig.add_header('Content-Transfer-Encoding', 'base64') sig.set_payload(signer(env.as_string().encode())) del sig['MIME-Version'] msg.attach(sig) return msg, env, sig def sign(datau, key, cert, othercerts, hashalgo, hsm): datau = datau.replace(b'\n', b'\r\n') datas = signer.sign(datau, key, cert, othercerts, hashalgo, attrs=True, pss=False, hsm=hsm) return base64.encodebytes(datas) def main(): # split certificate # we need the key as seperate file with open('ca/demo2_user1.p12', 'rb') as fp: key, cert, othercerts = pkcs12.load_key_and_certificates(fp.read(), b'1234', backends.default_backend()) agent = SSHAgentHSM(cert) # lookup the ssh fingerprint for the certificates public key keyid, _ = agent.certificate() keyfile = None try: # is the public key known to the ssh-agent yet? agent.key(keyid) except ValueError: # set file permissions to something ssh-agent accepts def perms(path): if stat.S_IMODE(os.stat(path).st_mode) & ~stat.S_IRWXU: os.chmod(path, (stat.S_IRUSR | stat.S_IWUSR)) # we have to add the key to the ssh-agent # remove the key password, dump in traditional openssl so ssh-agent can add the key keyfile = 'ca/demo2_user1.key.nopass.pem' with open(keyfile, 'wb') as fp: # dump the key fp.write(key.private_bytes( encoding=serialization.Encoding.PEM, format=serialization.PrivateFormat.TraditionalOpenSSL, encryption_algorithm=serialization.NoEncryption() )) perms(keyfile) # pub file so ssh-add -d can be used pubfile = 'ca/demo2_user1.key.nopass.pem.pub' with open(pubfile, 'wb') as fp: # convert the public key of the certificate to ssh public key format fp.write(cert.public_key().public_bytes( encoding=serialization.Encoding.OpenSSH, format=serialization.PublicFormat.OpenSSH )) perms(pubfile) subprocess.call(["ssh-add", keyfile]) # reconnect the agent so the key is visible to paramiko agent = SSHAgentHSM(cert) datau = open('smime-unsigned.txt', 'rb').read() msg, env, sig = compose( From='root+from@localhost', To='root+to@localhost', Subject='this is the subject', Body=datau, Attachment='pdf-acrobat.pdf', signer=lambda data: sign(data, None, cert, othercerts, 'sha256', agent) ) datas = msg.as_bytes(unixfrom=True) open('smime-signed-hsm.txt', 'wb').write(datas) # we added, so we remove the key from ssh-agent if keyfile: subprocess.call(['ssh-add', '-d', keyfile]) main() endesive-2.19.1/examples/smime-sign-noattr.py000077500000000000000000000010601504236674500211670ustar00rootroot00000000000000#!/usr/bin/env vpython3 # *-* coding: utf-8 *-* from cryptography.hazmat import backends from cryptography.hazmat.primitives.serialization import pkcs12 from endesive import email def main(): with open('ca/demo2_user1.p12', 'rb') as fp: p12 = pkcs12.load_key_and_certificates(fp.read(), b'1234', backends.default_backend()) datau = open('smime-unsigned.txt', 'rb').read() datas = email.sign(datau, p12[0], p12[1], p12[2], 'sha256', attrs=False ) open('smime-signed-noattr.txt', 'wb').write(datas) main() endesive-2.19.1/examples/smime-sign-pss.py000077500000000000000000000010761504236674500204740ustar00rootroot00000000000000#!/usr/bin/env vpython3 # *-* coding: utf-8 *-* from cryptography.hazmat import backends from cryptography.hazmat.primitives.serialization import pkcs12 from endesive import email def main(): with open('ca/demo2_user1.p12', 'rb') as fp: p12 = pkcs12.load_key_and_certificates(fp.read(), b'1234', backends.default_backend()) datau = open('smime-unsigned.txt', 'rb').read() datas = email.sign(datau, p12[0], p12[1], p12[2], 'sha512', attrs=True, pss=True ) open('smime-signed-pss.txt', 'wb').write(datas) main() endesive-2.19.1/examples/smime-verify.py000077500000000000000000000015231504236674500202320ustar00rootroot00000000000000#!/usr/bin/env vpython3 # *-* coding: utf-8 *-* import io from endesive import email def main(): trusted_cert_pems = (open('ca/root.pem', 'rb').read(),) for fname in ( 'smime-signed-attr.txt', 'smime-signed-attr-custom.txt', 'smime-signed-hsm.txt', 'smime-signed-noattr.txt', 'smime-signed-pss.txt', 'smime-ssl-pss-signed.txt', 'smime-ssl-signed-attr.txt', 'smime-ssl-signed-noattr.txt', ): print('*' * 20, fname) try: datae = io.open(fname, 'rt', encoding='utf-8').read() except: print('no such file') continue (hashok, signatureok, certok) = email.verify(datae, trusted_cert_pems) print('signature ok?', signatureok) print('hash ok?', hashok) print('cert ok?', certok) main() endesive-2.19.1/examples/t-ocsp-get.py000077500000000000000000000043241504236674500176020ustar00rootroot00000000000000#!/usr/bin/env vpython3 # *-* coding: utf-8 *-* import requests from cryptography import x509 from cryptography.x509 import ocsp from cryptography.hazmat import backends from cryptography.hazmat.primitives import hashes, serialization from cryptography.hazmat.primitives.asymmetric import padding, utils from cryptography.hazmat.primitives.serialization import pkcs12 def get_from_cert(cert, what): try: aia = cert.extensions.get_extension_for_oid(x509.oid.ExtensionOID.AUTHORITY_INFORMATION_ACCESS) for access_description in aia.value: if access_description.access_method == what: return access_description.access_location.value except x509.ExtensionNotFound: return None return None def get_crl_from_cert(cert): try: cdp = cert.extensions.get_extension_for_oid(x509.oid.ExtensionOID.CRL_DISTRIBUTION_POINTS) return cdp.value[0].full_name[0].value except x509.ExtensionNotFound: return None return None def main(): with open("ca/demo2_user1.p12", "rb") as fp: p12 = pkcs12.load_key_and_certificates( fp.read(), b"1234", backends.default_backend() ) ocspurl = 'http://ca.trisoft.com.pl/' ocspissuerurl = get_from_cert(p12[1], x509.OID_OCSP) rootcerturl = get_from_cert(p12[1], x509.OID_CA_ISSUERS) crlurl = get_crl_from_cert(p12[1]) print('crlurl', crlurl) response = requests.get(crlurl) with open('t-ocsp-crl.der', 'wb') as fp: fp.write(response.content) print('ocspissuerurl', ocspissuerurl) response = requests.get(ocspissuerurl) ocspissuer = response.content with open('t-ocsp-issuer.der', 'wb') as fp: fp.write(ocspissuer) ocspissuer = x509.load_der_x509_certificate(ocspissuer, backends.default_backend()) builder = ocsp.OCSPRequestBuilder() builder = builder.add_certificate(p12[1], ocspissuer, hashes.SHA1()) req = builder.build() data = req.public_bytes(serialization.Encoding.DER) open("t-ocsp-req.bin", "wb").write(data) response = requests.post( ocspurl, headers={"Content-Type": "application/ocsp-request"}, data=data, ) open("t-ocsp-resp.bin", "wb").write(response.content) main() endesive-2.19.1/examples/t-ocsp-show.py000077500000000000000000000012401504236674500177750ustar00rootroot00000000000000#!/usr/bin/env vpython3 # *-* coding: utf-8 *-* from asn1crypto import ocsp as aocsp from cryptography.x509 import ocsp from cryptography.hazmat import backends from cryptography.hazmat.primitives import hashes, serialization from cryptography.hazmat.primitives.asymmetric import padding, utils from cryptography.hazmat.primitives.serialization import pkcs12 def main(): print("*" * 20, "req") data = open("t-ocsp-req.bin", "rb").read() ocspr = aocsp.OCSPRequest.load(data) print(ocspr.debug()) print("*" * 20, "resp") data = open("t-ocsp-resp.bin", "rb").read() ocspresp = aocsp.OCSPResponse.load(data) print(ocspresp.debug()) main() endesive-2.19.1/examples/t-ocspd.py000077500000000000000000000204241504236674500171700ustar00rootroot00000000000000#!/usr/bin/env vpython3 import os import io from datetime import datetime, timezone, timedelta from http import server, HTTPStatus import socketserver import logging from cryptography import x509 from cryptography.x509 import ocsp from cryptography.hazmat.backends import default_backend from cryptography.hazmat.primitives.asymmetric import rsa from cryptography.hazmat.primitives import serialization, hashes logging.basicConfig(level=logging.DEBUG) log = logging.getLogger(__name__) class HTTPError(Exception): def __init__(self, status: HTTPStatus): self.status = status class HTTPD(socketserver.TCPServer): allow_reuse_address = True def __init__(self, port): super().__init__(("0.0.0.0", port), Handler) class Handler(server.SimpleHTTPRequestHandler): def setup(self): super().setup() self.extensions_map.update( { ".wasm": "application/wasm", } ) self._root_cert = self.load_cert('demo2_ca.root.crt.pem') self._root_key = self.load_key('demo2_ca.root.key.pem', '1234') self._sub_cert = self.load_cert('demo2_ca.sub.crt.pem') self._sub_key = self.load_key('demo2_ca.sub.key.pem', '1234') def xguess_type(self, path): return super().guess_type(path) def load_cert(self, fname: str) -> x509.Certificate: with open(os.path.join("ca", fname), "rb") as f: return x509.load_pem_x509_certificate(f.read(), default_backend()) def load_key(self, fname: str, password: str) -> rsa.RSAPrivateKey: with open(os.path.join("ca", fname), "rb") as f: key = serialization.load_pem_private_key( f.read(), password.encode("utf-8"), default_backend() ) return key def do_ERROR(self, ispost=False): print("*" * 20, self.requestline) print(self.headers) if ispost: length = int(self.headers["Content-Length"]) data = self.rfile.read(length) print(data) self.send_response(404) self.send_header("Content-type", "text/html") self.end_headers() def validate(self, serial: int) -> tuple[x509.Certificate, ocsp.OCSPCertStatus, datetime|None, x509.ReasonFlags|None]: try: cert = self.load_cert(str(serial)) except Exception as e: print(f"Could not retrieve certificate with serial {serial}: {e}") raise HTTPError(HTTPStatus.INTERNAL_SERVER_ERROR) now = datetime.now(tz=timezone.utc) if now < cert.not_valid_before_utc: return (cert, ocsp.OCSPCertStatus.REVOKED, cert.not_valid_before, x509.ReasonFlags.certificate_hold) if cert.not_valid_after_utc < now: return (cert, ocsp.OCSPCertStatus.REVOKED, cert.not_valid_after, x509.ReasonFlags.certificate_hold) return (cert, ocsp.OCSPCertStatus.GOOD, None, None) def _build_ocsp_response(self, req: ocsp.OCSPRequest) -> ocsp.OCSPResponse: serial = req.serial_number try: cert, certificate_status, revocation_time, revocation_reason = self.validate(serial) except Exception as e: print(f"Could not determine certificate status: %{e}") raise HTTPError(HTTPStatus.INTERNAL_SERVER_ERROR) issuer = self.load_cert('demo2_ca.sub.crt.pem') if cert.issuer != issuer.subject: certificate_status=ocsp.OCSPCertStatus.UNKNOWN # Build the response time = datetime.now(tz=timezone.utc)-timedelta(days=3) builder = ocsp.OCSPResponseBuilder() builder = builder.add_response( cert=cert, issuer=issuer, algorithm=hashes.SHA256(), cert_status=certificate_status, this_update=time, next_update=time + timedelta(days=7), revocation_time=revocation_time, revocation_reason=revocation_reason ) for ext in req.extensions: if ext.oid == x509.OCSPNonce.oid: builder.add_extension(x509.OCSPNonce(ext.value.nonce), ext.critical) elif ext.critical: print(f"Could not parse unknown critical extension: {ext}") raise HTTPError(HTTPStatus.INTERNAL_SERVER_ERROR) builder = builder.responder_id( ocsp.OCSPResponderEncoding.HASH, self._sub_cert ).sign( self._sub_key, hashes.SHA256() ) result = builder.public_bytes(serialization.Encoding.DER) return result def do_POST_ocsp(self): ctype = self.headers["Content-Type"] assert ctype == "application/ocsp-request" length = int(self.headers["Content-Length"]) data = self.rfile.read(length) ocsprequest = ocsp.load_der_ocsp_request(data) ocspresponse = self._build_ocsp_response(ocsprequest) f = io.BytesIO(ocspresponse) self.send_response(HTTPStatus.OK) self.send_header("Content-type", "application/ocsp-response") self.send_header("Content-Length", str(len(ocspresponse))) self.send_header("Last-Modified", self.date_time_string()) self.end_headers() self.copyfile(f, self.wfile) def do_POST(self): print("*" * 20, self.requestline) print(self.headers) try: if self.path == "/": return self.do_POST_ocsp() elif self.path == "/ocsp": return self.do_POST_ocsp() except: import traceback traceback.print_exc() self.do_ERROR() # Extract and print the contents of the POST length = int(self.headers["Content-Length"]) data = self.rfile.read(length) print("*" * 10, "data") print(data) def do_GET_ocsp(self): f = open("ca/demo2_ca.root.crt.pem.cer", "rb") fs = os.fstat(f.fileno()) self.send_response(HTTPStatus.OK) self.send_header("Content-type", "application/pkix-cert") self.send_header("Content-Length", str(fs[6])) self.send_header("Last-Modified", self.date_time_string(fs.st_mtime)) self.end_headers() try: self.copyfile(f, self.wfile) finally: f.close() return def do_GET_crl(self): today = datetime.now(tz=timezone.utc)-timedelta(days=3) builder = ( x509.CertificateRevocationListBuilder() .last_update(today) .next_update(today + timedelta(days=7)) .issuer_name(self._root_cert.issuer) ) cert_revocation_list = builder.sign( private_key=self._root_key, algorithm=hashes.SHA256(), backend=default_backend(), ) crl = cert_revocation_list.public_bytes(encoding=serialization.Encoding.PEM) f = io.BytesIO(crl) self.send_response(HTTPStatus.OK) self.send_header("Content-type", "application/pkix-crl") self.send_header("Content-Length", str(len(crl))) self.send_header("Last-Modified", self.date_time_string()) self.end_headers() self.copyfile(f, self.wfile) def do_GET(self): print("*" * 20, self.requestline) print(self.headers) try: if self.path == "/ocsp": return self.do_GET_ocsp() if self.path == "/crl": return self.do_GET_crl() except: import traceback traceback.print_exc() self.do_ERROR() def xx(self): # import pdb; pdb.set_trace() DUMMY_RESPONSE = """\ Python Test Test page...success. """ self.send_response(200) self.send_header("Content-type", "text/html") self.send_header("Content-length", len(DUMMY_RESPONSE)) self.end_headers() self.wfile.write(DUMMY_RESPONSE) import threading import sys import getopt import ssl def main(): PORT = 33150 def done(): input("enter to stop") httpd.shutdown() print("serving at port", PORT) httpd = HTTPD(PORT) t = threading.Thread(target=done) t.start() try: httpd.serve_forever() except KeyboardInterrupt: pass except: import traceback traceback.print_exc() main() endesive-2.19.1/examples/t-rsa-sha256.py000066400000000000000000000061021504236674500176450ustar00rootroot00000000000000''' RSA-SHA-256: RSA signature condition using SHA-256. This RSA condition uses RSA-PSS padding with SHA-256. The salt length is set equal the digest length of 32 bytes. The public exponent is fixed at 65537 and the public modulus must be between 128 (1017 bits) and 512 bytes (4096 bits) long. RSA-SHA-256 is assigned the type ID 3. It relies on the SHA-256 and RSA-PSS feature suites which corresponds to a feature bitmask of 0x11. parameters = sigalgo["parameters"] salgo = parameters["hash_algorithm"].native["algorithm"].upper() mgf = getattr( padding, parameters["mask_gen_algorithm"].native["algorithm"].upper() )(getattr(hashes, salgo)()) salt_length = parameters["salt_length"].native try: public_key.verify( signature, signedData, padding.PSS(mgf, salt_length), getattr(hashes, salgo)(), ) signatureok = True except: signatureok = False ''' from cryptography.hazmat.backends import default_backend from cryptography.hazmat.primitives import hashes from cryptography.hazmat.primitives.asymmetric import padding, rsa def encrypt(message, public_key): # Hash the message digest = hashes.Hash(hashes.SHA256()) digest.update(message) hash_digest = digest.finalize() # Encrypt the hash with the public key encrypted = public_key.encrypt( hash_digest, padding.OAEP( mgf=padding.MGF1(algorithm=hashes.SHA256()), algorithm=hashes.SHA256(), label=None ) ) return encrypted def decrypt(encrypted, private_key): # Decrypt the encrypted hash decrypted = private_key.decrypt( encrypted, padding.OAEP( mgf=padding.MGF1(algorithm=hashes.SHA256()), algorithm=hashes.SHA256(), label=None ) ) return decrypted def main(): private_key = rsa.generate_private_key( public_exponent=65537, key_size=2048, backend=default_backend() ) public_key = private_key.public_key() # Data to encrypt message = b"Hello, world!" if 0: encrypted = encrypt(message, public_key) decrypted = decrypt(encrypted, private_key) digest = hashes.Hash(hashes.SHA256()) digest.update(message) hash_digest = digest.finalize() print('ok?', hash_digest == decrypted) salt_length = 32 # length(hash_digest) signature = private_key.sign( message, padding.PSS( mgf=padding.MGF1(algorithm=hashes.SHA256()), salt_length=salt_length, ), algorithm=hashes.SHA256(), ) try: public_key.verify( signature, message, padding.PSS( mgf=padding.MGF1(algorithm=hashes.SHA256()), salt_length=salt_length ), algorithm=hashes.SHA256(), ) ok = True except: ok = False print('ok=', ok) main() endesive-2.19.1/examples/t-ts-get.py000077500000000000000000000050401504236674500172600ustar00rootroot00000000000000#!/usr/bin/env vpython3 # *-* coding: utf-8 *-* import requests import hashlib import time from asn1crypto import cms, algos, core, keys, pem, tsp, x509, ocsp, util def timestamp(unhashed, hashalgo, url, credentials, req_options, prehashed=None): if prehashed: hashed_value = prehashed else: hashed_value = getattr(hashlib, hashalgo)(unhashed).digest() tspreq = tsp.TimeStampReq({ "version": 1, "message_imprint": tsp.MessageImprint({ "hash_algorithm": algos.DigestAlgorithm({'algorithm': hashalgo}), "hashed_message": hashed_value, }), #'req_policy', ObjectIdentifier, {'optional': True}), "nonce": int(time.time()*1000), "cert_req": True, #'extensions': tsp.Extensions() }) tspreq = tspreq.dump() open('t-ts-req.bin', 'wb').write(tspreq) tspheaders = {"Content-Type": "application/timestamp-query"} username = credentials.get("username", None) password = credentials.get("password", None) if username and password: auth_header_value = b64encode(bytes(username + ':' + password, "utf-8")).decode("ascii") tspheaders["Authorization"] = f"Basic {auth_header_value}" tspresp = requests.post(url, data=tspreq, headers=tspheaders, **req_options) if tspresp.headers.get('Content-Type', None) == 'application/timestamp-reply': open('t-ts-resp.bin','wb').write(tspresp.content) tspresp = tsp.TimeStampResp.load(tspresp.content) if tspresp['status']['status'].native == 'granted': attrs = [ cms.CMSAttribute({ 'type': cms.CMSAttributeType('signature_time_stamp_token'), 'values': cms.SetOfContentInfo([ cms.ContentInfo({ 'content_type': cms.ContentType('signed_data'), 'content': tspresp["time_stamp_token"]["content"], }) ]) }) ] return attrs else: raise ValueError("TimeStampResponse status is not granted") else: raise ValueError("TimeStampResponse has invalid content type") def main(): unhashed = b'ala ma kota' hashalgo = 'sha256' #url = "http://time.certum.pl" url = "http://public-qlts.certum.pl/qts-17" #url = 'https://freetsa.org/tsr' credentials = {} req_options = {} prehashed = None attrs = timestamp(unhashed, hashalgo, url, credentials, req_options, prehashed) main() endesive-2.19.1/examples/test-SHA256_RSA-signed-cms.pdf000066400000000000000000000457401504236674500223260ustar00rootroot00000000000000%PDF-1.3 % 3 0 obj <> endobj 4 0 obj <> stream 2 J 0.57 w BT /F1 13.00 Tf ET BT 75.22 778.46 Td (Hello, world page=0.) Tj ET endstream endobj 5 0 obj <> endobj 6 0 obj <> stream 2 J 0.57 w BT /F1 13.00 Tf ET BT 75.22 778.46 Td (Hello, world page=1.) Tj ET endstream endobj 1 0 obj <> endobj 7 0 obj <> endobj 2 0 obj << /ProcSet [/PDF /Text /ImageB /ImageC /ImageI] /Font << /F1 7 0 R >> /XObject << >> >> endobj 8 0 obj << /Producer (PyFPDF 1.7.2 http://pyfpdf.googlecode.com/) /CreationDate (D:20190824020534) >> endobj 9 0 obj << /Type /Catalog /Pages 1 0 R /OpenAction [3 0 R /FitH null] /PageLayout /OneColumn >> endobj xref 0 10 0000000000 65535 f 0000000423 00000 n 0000000612 00000 n 0000000015 00000 n 0000000093 00000 n 0000000219 00000 n 0000000297 00000 n 0000000516 00000 n 0000000716 00000 n 0000000825 00000 n trailer << /Size 10 /Root 9 0 R /Info 8 0 R /ID [] >> startxref 928 %%EOF 3 0 obj <> endobj 10 0 obj <> endobj 11 0 obj <> endobj 12 0 obj <> endobj 13 0 obj << /Type /Annot /Subtype /Widget /AP <> /BS <> /C [] /Contents (Dokument podpisany cyfrowo) /DA (0 0 0 rg //PDFANNOTATORFONT1 12 Tf) /Rect [0 0 100 100] /F 704 /P 3 0 R /FT /Sig /SM(TabletPOSinline) /T(Signature1) /V 18 0 R >> endobj 14 0 obj <> stream q BT 0 0 0 rg /PDFANNOTATORFONT1 12 Tf 1 0 0 1 1 54.8 Tm (Dokument) Tj 1 0 0 1 1 40.4 Tm (podpisany cyfrowo) Tj ET Q endstream endobj 15 0 obj <> endobj 16 0 obj <> endobj 17 0 obj <> endobj 18 0 obj <>>>/Reason(Dokument podpisany cyfrowo)/SubFilter/adbe.pkcs7.detached/Type/Sig/Contents <308213d406092a864886f70d010702a08213c5308213c1020101310f300d06096086480165030402010500300b06092a864886f70d010701a08205513082054d30820435a003020102021001f65ef8078f875d06f655698a1728ce300d06092a864886f70d01010b0500308182310b3009060355040613024954310f300d06035504080c064d696c616e6f310f300d06035504070c064d696c616e6f31233021060355040a0c1a416374616c697320532e702e412e2f3033333538353230393637312c302a06035504030c23416374616c697320436c69656e742041757468656e7469636174696f6e204341204731301e170d3139303531383230353330305a170d3230303531383230353330305a301d311b301906035504030c126d616b40747269736f66742e636f6d2e706c30820122300d06092a864886f70d01010105000382010f003082010a0282010100ea8da6bc059e23f050d3f8ea92bf87c4907761f1361d7a59b2601fe29de9bab4b93dd57d0199f306272286e71c31d43fe41bd123e779c4cc662de8e7eb9699faffb32a887e0cf24ccb489b4ca09113c798fb2378cae1a61322c61aa1ae89c080ab28efa691c7f24bf2d3235322c12567fd67be6e5130c1666fc8eae3640cd8e9980559c7f7e1444a4846eebeb0eb6a0e4c7a73397ae8ea0d7fbd716f980df1d59cddf5bc8ca48aa4638659e3c837bdee469ce38f32ac58cfdd9b57758f50ddfedfeb9b1ad11bc052bb6f773d410c42b1f7480c37c71d75f837f122d1466dc878e1f583491db32f9a33dceb0f3a11a107745c57566d2004f1997bf98dc287a05f0203010001a38202213082021d300c0603551d130101ff04023000301f0603551d230418301680147e60fcf86ca73d3dd7ae93a179028fb374293bf5304b06082b06010505070101043f303d303b06082b06010505073002862f687474703a2f2f6361636572742e616374616c69732e69742f63657274732f616374616c69732d617574636c696731301d0603551d110416301481126d616b40747269736f66742e636f6d2e706c30470603551d200440303e303c06062b811f0118013032303006082b06010505070201162468747470733a2f2f7777772e616374616c69732e69742f617265612d646f776e6c6f6164301d0603551d250416301406082b0601050507030206082b060105050703043081e80603551d1f0481e03081dd30819ba08198a081958681926c6461703a2f2f6c64617030352e616374616c69732e69742f636e253364416374616c6973253230436c69656e7425323041757468656e7469636174696f6e253230434125323047312c6f253364416374616c6973253230532e702e412e2f30333335383532303936372c6325336449543f63657274696669636174655265766f636174696f6e4c6973743b62696e617279303da03ba0398637687474703a2f2f63726c30352e616374616c69732e69742f5265706f7369746f72792f41555448434c2d47312f6765744c61737443524c301d0603551d0e04160414c20ca9412e3278a73aee977f48517a44b488c143300e0603551d0f0101ff0404030205a0300d06092a864886f70d01010b05000382010100354ac7803a4f44c04f9895c666b20820242561c05367eac9906f63c3461da8ee743cfdda335c51f7311c82779c48b022b7f71be386bc503e8019d726eff8d6661220099ba854563835a98fa9bb9c4abcfe87374d89d1415d38580d45f7a9aede5dac8558f6b15f975c72190065a1c11563bdcdf7693cb3c0e841ac235f3841782e0662e83cafc8c31a8b3f071582125a5bd9733acf4c7d71e5791107c2f59d7f7b88cefe92e33a7a22022fb91d960ba5bdeb9cf914f31ffb1bf01d6a0d0d18d8425bc51c0c29fb555c15e4ffeb1000d62622a3082df26cf88107efc406e79da494dca8f3d5fbec0578f313a84db405b64d8c0b34d4f43feee9af60aba9d8fa5831820e4730820e43020101308197308182310b3009060355040613024954310f300d06035504080c064d696c616e6f310f300d06035504070c064d696c616e6f31233021060355040a0c1a416374616c697320532e702e412e2f3033333538353230393637312c302a06035504030c23416374616c697320436c69656e742041757468656e7469636174696f6e204341204731021001f65ef8078f875d06f655698a1728ce300d06096086480165030402010500a069301806092a864886f70d010903310b06092a864886f70d010701301c06092a864886f70d010905310f170d3230303230353233323831355a302f06092a864886f70d010904312204201a7766a2b9f07ca33bee08f7f8c0d4dacc4bdef0c63b69fe42613476ca95c19c300d06092a864886f70d0101010500048201000ed662317ef00310de0fbe55cef9ca1e058ff807279b17fe670f850930820db3c27bd72e06fdfb49647e3aa001d436e79c25e30a49089d73aa50226c4117b1fa5696e422fa5da9ffdf27dcb441935b4ab6920b559f14d1c42d616a66a332fb475a0657a496265713ed962a3c5cc8cb1eca7433c8e1b407bff49833ccf682d60cd0686f3ee188b8a1600db90cd348d16bc27e9a6cfdff3af78d1caeaeaa81cc21f1d0211033b517e4dbc39cf6a9de22f8df4e88ff0cc226f608a6e27f10e19d1a7c4f7bf2d2848f9952a7cb864fd124c2656adefdfd930c821698ce9af7d962b524324fbc592ace5e2b3de020c4b0c845bcf55a172bfd98418050bd557753f607a1820c1530820c11060b2a864886f70d010910020e31820c0030820bfc06092a864886f70d010702a0820bed30820be9020103310d300b06096086480165030402013082010c060b2a864886f70d0109100104a081fc0481f93081f6020101060b2a84680186f6770204010e3031300d060960864801650304020105000420bdec3bea815c241425ff21e9453cdf34e25bf796d503b7b51a3366e92b29ccd5020711c3793b008d2f180f32303230303230353233323831355a30030201010206017017aec8f6a06aa4683066310b300906035504061302504c3121301f060355040a0c1841737365636f20446174612053797374656d7320532e412e3119301706035504030c1043657274756d205154535420323031373119301706035504610c10564154504c2d35313730333539343538a11e301c06082b06010505070103010100040d300b30090607040081975e0101a08206a4308206a030820488a00302010202141193735f17c17e144d3f928f619bbfd5027db1e9300d06092a864886f70d01010d0500306f310b300906035504061302504c311d301b060355040a0c144e61726f646f77792042616e6b20506f6c736b693126302406035504030c1d4e61726f646f77652043656e7472756d20436572747966696b61636a693119301706035504610c10564154504c2d35323530303038313938301e170d3137303331353130323331385a170d3238303331353233353935395a3066310b300906035504061302504c3121301f060355040a0c1841737365636f20446174612053797374656d7320532e412e3119301706035504030c1043657274756d205154535420323031373119301706035504610c10564154504c2d3531373033353934353830820222300d06092a864886f70d01010105000382020f003082020a0282020100c854114d9ef337112b40b70dfb47f937087674fa8c177759f4ea1d4890b57f9a0e04e8f9aead48655c00268c57decdb1ec4ff233cd4366377876e6503c0bf17f971d000129635de4bc602745490f444cad4d8ecc84ab7c0f45568c16414d9acb848e236d8928b272e9ce055e01813e19e0d8f44c5b313b1948ec5d7c13c616d074fd0ab0cc52bb8c0cb03f3d6e4877a63251009f24ea2e20cdaea03c67398cbf1e7ef2f9da1615a1e6f2db14b23bbab7764b26c3ed871270a3561f5cd6fe9e9ad05b4c4f594ddc641b5c0231e47b375152d139b80ba6fdf3760928f6cc8e3a9724ad97fddc4073f795bd425ae47a494793ba907ea91b5216eff309e12a3068c7889fc46920303c641aded27ab2f303ac564b7ddfd2a4a60b2fa6e03471891c684cf36c70bba4b0dc3d873127bf8feb141320e4d915a6f9172ca2815a08bf35bee06e7ab85c069410a3e81f8ea7998ad5867855f5d44324f708b41851b53029eb2aced3d6ca2c35a168c7275f9a3ec8f086fa1ffd7007bf974e2562c70668bc042c25f0c45851f1c129dbb43984d04423303531e04acc5fbadba3e88fe6ffaca81db396f5a10149d097b41af101be8e000ed5fcb69d6d0e81a0ccdff3a24c228d9e5fce0b08bf716ba5c015237e8e7fce1b8e4ea4e233e36c913deae4723234e21d66de3ee3007c03b1d71600406f66563da5655e84e1650268a695f7ce42d9e30203010001a382013b3082013730160603551d250101ff040c300a06082b06010505070308300c0603551d130101ff040230003081ac0603551d230481a43081a1801429b3c8c4dfa387f866051258fd462ab8980d7987a173a471306f310b300906035504061302504c311d301b060355040a0c144e61726f646f77792042616e6b20506f6c736b693126302406035504030c1d4e61726f646f77652043656e7472756d20436572747966696b61636a693119301706035504610c10564154504c2d35323530303038313938821440f8f78ab0e364105691c8d9e02cf8c1c6400a4630310603551d200101ff0427302530230604551d2000301b301906082b06010505070201160d7777772e6e63636572742e706c300e0603551d0f0101ff0404030206c0301d0603551d0e04160414b2bd12cb0781e27ba3b0611d4a4379a887f4d076300d06092a864886f70d01010d05000382020100911e8dd41c1f2203b9f6df7c1deb6337ea423b534e957a11c6240c5119a2d509cf78a259620e133cf3b3b0ce65433a3db3dd57b982071a546f09a72d93c67614af433e9248ebbd177e124dfa33680030b4f49ba92a1f1835f15d2cd2270c78ebe562b5aa871f2a0c2fbe0307d52ce3a6e1020c0af63e8cf09e6752cddee133a4a51ba627d261166fc588ec49557406b99e8f51ee3949c1480f3292f74cce12ccf8df1d5665c276a7e64517bab4cb4d3ebd76e49cda1aa8b2b112bf0ee6eaf3be3b4f90883529575d04042d7b63c61e1b00d01728701cbe840b9d2e36d3b249e1b6cfb06706ba9a7a578fd949c99509a4831998ab3f75e496dc5fd7f6275dd353af47d3c7cabe81789f76dd9fd78497f453490fe502fea9ee432e0c633e3c0f7272fa3dafa9444be3de079202dbd251c4dfc2f9e69f37cfa6f5bd317d417c1a04973afab103a2887da0fe10c8695a1cc0636d3a29c0c79a8d9b0511560c9d99dfaa962bb8e170eab933f993e2663942ea1e4f16d330788c2aa67352e986f948441b78c93b147d755b61312f83c6b6d836c1f8cf697753ed03a7e53d287faa062a31cf8d8875b399024cf347974c65a87fe845d6e45b7b1054745605d41f7a40393c8afcdd4f028cfef52b90427ef5156fdb7f085e95a39e7d287afa39183bd4f3ad53c9010c3457640045de18f40eaa1765f0893ca3cdec0b1dd8fca6d311dd563182041b30820417020101308187306f310b300906035504061302504c311d301b060355040a0c144e61726f646f77792042616e6b20506f6c736b693126302406035504030c1d4e61726f646f77652043656e7472756d20436572747966696b61636a693119301706035504610c10564154504c2d3532353030303831393802141193735f17c17e144d3f928f619bbfd5027db1e9300d06096086480165030402010500a0820164301a06092a864886f70d010903310d060b2a864886f70d0109100104301c06092a864886f70d010905310f170d3230303230353233323831355a302f06092a864886f70d010904312204203114bd27a8700fefdf951cb1002c23c58d5e82ad1507a96196e2d30f3436e1ee3037060b2a864886f70d010910022f31283026302430220420673be8a1da927db63ccab7cb3e7ac352dc3aeb6a8da3e2a359ca158d0a440db83081bd060b2a864886f70d010910020c3181ad3081aa3081a73081a404146e23cdb967f06d3fda85316c5b47361cd55542ac30818b3073a471306f310b300906035504061302504c311d301b060355040a0c144e61726f646f77792042616e6b20506f6c736b693126302406035504030c1d4e61726f646f77652043656e7472756d20436572747966696b61636a693119301706035504610c10564154504c2d3532353030303831393802141193735f17c17e144d3f928f619bbfd5027db1e9300d06092a864886f70d01010b050004820200abb0c8d0434a147f8aab6bbf1a4ed2f5be3c1e5e077bff97d6f5d23a72511be78b35fd3aed60f40de7311e7a6f81c4cea20c921214eb26f4f07a1b9abb45157f9e0bd6fdd08078ca98fbdaf24561cfe5553612145fa56fbc071052f834548b6129dbf0377b688bd10ae96b88cd69ae322010f7af67f986b6f366817fa9388506b4b777260f7b75fbcc5879f5f618048757bd7496816c0f0e4b1ba2986b4c875f3021f86b109ddf10370eee1362d5421ee7221ca0c9a4ac84a8e9acd9e3ac5c33e234c612762662135e71c6027da447d8b95e4bc7385e1cfc2b4bd0d63a1b95294f36ce42d4afdb8f3649cef1acd86998d5baf5c0637533f3bb17d015dbea68cc27477a602e25d422c7425478fb3c1d8703fc2f3f4bc295ee6284d8fbb58794310f5e9f187f4f135fc7a5b0e8dfbb162609af34329ed4ab2201c18abfee737ddef86e7d1b211e01ee3ef82e6902f555ebf5bbc831773f365187dad33f7694c62a5fc44cda2f02e0aeef10e3ce48e23bb61aa524d5892364d17039a8566f51e0ab311f313e28e9733f8aee65a155fab3a2a425ca8ef95b0941c0577060524af31f6cf2d9ad970894c40e3d4bd14e4100bb46c5bc6fd6b25fc8e172b7611aad93eb2941dea9da6b60370a8f15af336c1cbd5061c809ded21ebb549773441256edf4bd19000a78dd3f7d4b87be338c73e172a17fbf398314d4873f1e49c8ae5ed04900000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000>>> endobj xref 3 1 0000001280 00000 n 10 9 0000001373 00000 n 0000001480 00000 n 0000001598 00000 n 0000001645 00000 n 0000001925 00000 n 0000002194 00000 n 0000002242 00000 n 0000002289 00000 n 0000002386 00000 n trailer <<754C45499EA727F815D23F8F2DDE300E>]/Info 10 0 R/Prev 928/Root 11 0 R/Size 9>> startxref 19061 %%EOF endesive-2.19.1/examples/test-certificate-googleHSM.crt.pem000066400000000000000000000023251504236674500236150ustar00rootroot00000000000000-----BEGIN CERTIFICATE----- MIIDZDCCAkygAwIBAgIUZytKw5S15LEbmWqF3dluaI/5pR4wDQYJKoZIhvcNAQEL BQAwajEQMA4GA1UEBhMHRW5nbGFuZDEXMBUGA1UECAwOR3JlYXRlciBMb25kb24x DzANBgNVBAcMBkxvbmRvbjEVMBMGA1UECgwMR29vZ2xlSFNNIENBMRUwEwYDVQQD DAxHb29nbGVIU00gQ0EwHhcNMjAwOTA2MTgwNDU3WhcNMjEwOTA3MTgwNDU3WjBq MRAwDgYDVQQGEwdFbmdsYW5kMRcwFQYDVQQIDA5HcmVhdGVyIExvbmRvbjEPMA0G A1UEBwwGTG9uZG9uMRUwEwYDVQQKDAxHb29nbGVIU00gQ0ExFTATBgNVBAMMDEdv b2dsZUhTTSBDQTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAJG8KDay zfTER4ldJYEddVam5k76GaGFGKIvG/r63+sIrXrMtoEdzAU8ZSpLGusE9CF5K7el tIt21JJwyFWEcD3w4wxtPJK8T0tfarfWOx6AWUkYhmGuO5nK8rI/lrbK3vvJBN1S ju1w6JyAY0ygHrgXMLbosUrDtSovMdsyHHiHmWOmxvPzZxXJrp4a92wN2E1cvp+1 oFff58OSGPNIJsR21xvAtdDNgiXd52Ltoc2MTObj258fvXRHXuSlkZiCkCDbgOTU ZoSsb3ysH7weUIGO24ZJ0rGz069ACUzumo82PeaBvFWg8LhVURmOpewRBv6ONh4+ Wv3PeSFtx48L+ikCAwEAAaMCMAAwDQYJKoZIhvcNAQELBQADggEBAGQ0Pem3z2fg wsNu9b45aAb/8zAVBSlHmLkdA1A8dUfCmm2kHR5yWlC/dTzt5zdfbNZq8T5OfJfa tiLiCza/3xs979H6+nVKUKCTJIbfFkBDKZmBjkNJbB4R5yxVPg1HjlSYWltEo4EZ u577G1ejxkTEZFQALPmar4PBggZEqLqJMxjxgNEwS3Z2DildFPF7JF2m2Jj3zq7y nJhI8TpimTzV+rChZYPasWqV/Dcv6aNrZcCcgb9pJsR8aCvtrEdo96LNlGZUVBuW wZA/QkgO/0LgftXXYLzPWzDFofLUCpNnppMMgpi0ybgzS/bi+1zdvgJZEVVUwKOe frp5mIvq49k= -----END CERTIFICATE----- endesive-2.19.1/examples/test-signed-cms-hsm-Google.pdf000066400000000000000000000710361504236674500227470ustar00rootroot00000000000000%PDF-1.7 % 1 0 obj <>/Metadata 20 0 R/ViewerPreferences 21 0 R>> endobj 2 0 obj <> endobj 3 0 obj <>/ExtGState<>/ProcSet[/PDF/Text/ImageB/ImageC/ImageI] >>/MediaBox[ 0 0 595 842] /Contents 4 0 R/Group<>/Tabs/S/StructParents 0>> endobj 4 0 obj <> stream x- @ Nfd+ySHRE80c(K14R"Y¶ӪB6x2L~q( av.x-LLb4IHBLjk\[{b}#֟Lݙ :!S endstream endobj 5 0 obj <> endobj 6 0 obj <> endobj 7 0 obj <> endobj 8 0 obj <> endobj 9 0 obj <> endobj 17 0 obj <> stream xmQj0}c ˜ʆXJ+] )/w_97眜$"DAubQ8B LY@9_ sgҭkjp[@pL+Y\N'%,+Sv i)Jv5R-QfԴWy>w.O8&cF ܖ &A^z47̩tADßVA:eS҃_ehq{g"%di͈:+%kSyN4xYeeUu&]ȆڢN~T endstream endobj 18 0 obj [ 226] endobj 19 0 obj <> stream x}|TU9N˔L$LL$R $)@BMH!h@PD( PWb e-X^wUlvHwvms>yOqƘ]93fƺa?Z5zbe-6S /;/?'26ykX۳6!y^9o6cNcVfw}?T{ў ivc%ҕHg,m[;r)Mj=3Xᬥk2g-mjڴ)D/m:{r-c]ˏ_a1sE+Y/񺏙 C^H #b)&&잏?%EC$}bdSX7{;~qh-2[ dF@+|!{9Su~.3~M%Vefb](NUtﰁ=̓&()J%xSNjD]gfxstMꟻ Y0]1ޔ'SgczkKb7rnѼ:?ٗ_%̟1Ybt;Yb,f1YbZ1Yb,f1Yb,f4zb,f1Yb,f1Yb,fMFW:RV3[tsc~lkd+؎2_\S=ڿ+zawԞ1xfh/ݴύ-8^;)S"+aSGwVpV8a˖w쒖M.?oښӧM2y ǍS]UY1zT|1#++:$?/wPNvVםtmshTAU:_8.+z8{9>,i|G dQ%T2x$wF|U~_JϙV_ $M벵 U[*}a^ Wn騪D{sɜ;u-py'5T T&^VSTUz22j5 *F-gvsЃgu9آX?&֣RZѱ% +ֽƐƒUM~¦^m98'zϏvJ U5U5Lb9,5 '>h.n_M~161N0mN]2R*2-J`u#UK҇c'_L[586<%P/ 3D?su5cf]j5s;zut˫Z\t5vgԌh^N;MfFS sj8mYQRQ73y5{|5")>-MG¤ 2֮4nL󙤏.|zQ n' ]: :Lk9&8DL-I)*6S*\xF8vY{:t;ゞ=ZKӣ%QRsQWCx [(#_usAqQCxY-Mъ7P=2g>fyuM̞h&R,6s8. GhK9,cm-u^Kma zk*0;'-(hfZ_):dDvؖ5_7o_*+DDK^sČ^!~b1TVq#<7;tצ;:L]d;ĚSj_p~UO|291׸c_%K'X+JSXxB35.S</>2r(Y-`V!0kW[3e"?/Z1uXCN_"lv4X]Q! i),pD8 ۧj}ui5FTLL]U;gzF|E}E tt;ڹFa4c7N~M ,nMZjtWњʏ68E!. gGB!x>YuT/O[zRq"U`\(HG@fis1G9>@MZTYD;OB+ɥ8q vG5U=r<7$z:֩M® z0Ȕ";Q3ǕGY)*EMVBʫD%/_?~~}{YY10PF:E@ώCKYPDaV 4meGuh3r87E$ũR"E'KQ R$)IqkX#j)VI&J)NbKLRJqJD)K,ER4HHz)X()K1OȒV)fK1K3!t)I1U)RLb x)I1V1RTKQ%ERbA)ʥ)1Rbä(TR Db)(bRK'EH1PRH_l)Ȕ/E?)2IᕢRI"U)R$K$KD)H S v)⥰Ia"Y8)LR0HB'*"E[R);))+)"şR/\ϤTR|"RIP?JKR+;R-[R)R.kR*+R,KRNxAxNgxF}R<-SR<)RVǥxLGxDRFxHx@O{G#EwIqwH[]RD",R&ŭR"N)nR$ōR R\'ŵR\#R*)WR\!R\&v).).").)Η<)Ε)ΖbgIqR!V)HYӥ.=\^{py嵇k.=\^{py嵇k.=|.?\py.?\py.?\py.?\py嵇k.o;\vpym^K.Hߑ^ܙ#}]S)uJ0P;N&kmzIZI!ZM(h9O-':hYJJt\$ t,D͑JP-$Z@Sj\9DD5Dff N4h*D&M #!x&"J є7ʩHcFPDèzQ)P!D%X1QRH4'ʣzDDL"?Q?j:GD}҉҈%O }L'r~D!>"S=JR'z{-rIDQW) ˑ٠"ɳ@#z/=OѳT}|)'"%z=J^Pɇ)уDPD^{&CE%ԝDw&I*E"IsADaۉn#D7Gn'Zk&At5v%++(rˈ]J.D]HyP+GyCt66䙔 :h+W=k4MW3TS"=B0'G\C@6PT$uW#Dh jUDmD+TWxjl\JJtѱDK^ bY3Uo"j D-Aϧ#KCMҋjfSwgыBLDӉED)D'G7&EsAD 8J%CHFPU$q 2x2"I" $ΏԈ4hX)FQi944 8J((*#N1S|> 1G{ߏo=.|D k+/{_}і}x9[, OmI' Xc%Gm-Gl{Q7ha! YOk]Ǻ{ͻNF."@'nͲ{eNF-נWA_ + ehk;ںK QyiXtpIPšPPCP}i]haЂCJ- FY3C3C3JR:94IBwN/slhLiu gi4_0] z|1OGMzS^1%rr9)[  '?vgɺ>y,ɑKR]blIfVk\^IsL>wT.oz2=\630ĦO 6'lf9sk:9?Vs DK۶3j"k'ۅ5#4CVj0;ϝ3nv{] y{7^x5?xh)cS6x[ά[%TnbQ%ƹKh[ǂmZJ$+~V!-~,F@ Wڤk_7swoyF(Fep*p  l6끓uZ` X+2`)  ,Z@34 " <`.0j, fӁiT` 0L&qX` P T@0r`$p 0 ʀR`(0(" @ @`,  x@:xT p@>@lf 0Fݨxxxx xxxx xxxx "<, xx xx-8( 0 p?pp/pp7v ہۀ[[kkU+ˁˀ%Ey96,L8 l6Qsq9?8sq9?8bG 1#p8bG 1#p8bG 1#p8bG 1#p8?8gs}q9>8gqn?w~Vu1^1f [#Sٱl%kǯl=^g&lCKUXz}Х>:aOӣ|v_2$0Vצ<EgH+[Z/Wv}Qs0as<6ձz%X+[ʖie[g3R Q EӇKϖ+Xrє;AKbkk-;c'lCFG:-NʜNՔdlbӱj[VvO8:ؙ,ێH_.d٥+^/cWgDE\){/{nc;lьyip9`=FWi[Gtk?Wy%7$B ZpL1><"J]Wfr-%_^U&u{czD͕r*326MfOl$a;\\(̇;q^]J T.ܸ oܗ ey}βw_|wp'jUKwm\ƵV4.  @ZpjHWD_R?{HQQH8/^|CT *jTDN9hP6gmN17kD^Q5Tɘ3tt U^3:]I &SBz+i<>/?TZP5 W^j6):;eq}:K3dLpZs*Jm\I[z70#KbփG*|s۝.|=6e]37sjva4QFmy02N9Ӽ>a e΢rb]_,rRβc򋊜E cfÍ`Ѳ8<^?;9Uyǒ 2Lޔ>&H]}-JnJ}}<-Lw_-씥vOkjVnFUg4DoiMw`%O [j'0/I{~XsN/nnakFVdak[T /[XFc,΃)vz`\~HLΎ6UsB[Z;ys {SGgeWg-vM}u&+z{+͹"dJs,jzvczE"S,滅 X2ǻβ21nsݒ\&c_r/t`ǩc/%ś`vze`x5%c@ZsJfbP8jU qu3y vXyT G F1#{Yq8O.ט -"a _|s񒶔 ZQWuk -T %Q_599)IW\Yi Ye,UX۾&js K&fe8jO\=rraJ#&A|92?{ʡx2#=zYUKFA0-@Jm)'W8^-xˇsLD2 @t(16z~;"GM~4hl-s'Rߣ(s{|q튟 Fh(…YVt[EݭZe8ѻdg4l-ܻ*bWi"Ž>9[8eSИucOPfhx֨cS0VӚI&m\vic*&bxj+Om:&a``ߨ>}Y;Kx=)@mXbnЉN ϶|\bExًfM΀Vz61^2:G.#hPnT q&Srz+dߔ@QԐ0fVnLT.J댋3%Mz0lt:xzў0lY[fgS޳t<OY2z@v6ӛt3g+%['szebĻ25ռ 쮾]+{Q_Wiu9Egԛ,vӞ'4?=0'>#ɨxޠsһo°tbl I6Ldps !,1;YIjt}FGS׫%jvt}(7i F'7ipC:ILV&nkUo:?e<'b8g?]Pa)}Fc.Nc |pu.;t:}q%y4LCKLONKNKL%BXfbw[,9)fsJ|ڬ\_{V=cc0Oj ji1O1$MGrBnH6'f$ǻ+V7iH=H'%ӟ峡aSl-װD ljKҵGY6Wטh;:+um++'6o5s_z6Vo,`Z\bޢ[ZVC Xs"X H~=֢l62N7a4=7] 2s2⒕{3Vi6;hVNn`Ѫs+dUfM{lWLzw[-Òڵ-M=7mhɴkbל%ZL 8=n0 ffbX`m! f0`3|3`3 f+f0`3 f0`3 f0`3Jm1VӝЈ^6s` c;f017Fն4†0^Smk#sնp͢mtThj;XZt} ߗY7IiTY3s f01;w[mi2nRmkYTsrSm-ňourϦvX3IT}1vB%/3lpMjMڙlv&ۤ63ٶ4'LI;md3&LI;m{7& cqW/h0s0B\D~@KqL&c|0I$Ug1A+H| ITp,P.tr$8B12X hu0:cl_(. HCQ@O Fȧ5꓊~H$<98 ` HQQ∋̊惵4Xbd5KX"2A:%k8Z/ALxB+3NIdѸTd1x^8RJ-BF4 Gxe"*xV!僖U6hˑLd /\R$U҉DJEC^#BM#^I_ȐN-(*W155nt>jJJ%Q $M-Tbm/Ҷr50TBXӡפH.^*dlY/Fjhus57@ .5!T$CIhP4bT| #WmԆ1тPhAzhKB#p(e<" Q9("_UGZSc@~!uE"gA8ORq6b%=;7eθ57H"|.q,E I eنá Q~)p Y`4*G2@ 1 >Zj;i:Ldy2"Km6.g#@<5yZ쪤IEBTN"Ce#9 ^n1G#9F_ Ȫ F6QՇܟ$_Oc ,O36˧4&G{!+mNtyNԠN6֠*6+$&.i+5Ɠ^%#jJƞAT@E=Zm=/d~:&r IbQ|Y\IyaLNRdaVGRB`8a03BcU|a&rګ"ꬭDL:kQlR2~޷-hX灷}Ml$6B0_M1`:e7Y# r՟wM}%2U/15xTXRl$Tz/Ms CZKF a,}UM+&3i`xa 8=i8>u+Q0T3CTNiJrlJO\g<1jEQD]Šd,2@A僙tЋ``yo T^q$ >xNLb1a7O/ &N 5ƒ+Hvʂ$$Q54F JC %Џf#mcQ;(g,%i iFP'@#ΤIHX0O$9$O:5}KPUA<~Q5HǁTT!hY/6"=V6D?h;>z&ePkh 4_EA=G!%(KElʗ|Gc(cVX`X$y$HB5I0Fyc@G @FΟ K;;ot>Pc7O4**GG4jF%0FtȴТ׫!@1heCNU  TI4$W/jqf`!8 m`zF((<r12spX+e-'A/j}8Jt0|°ujUFt9*NK" @zfZZ-s`*Szҫ R|d0A$-@ku HZ>2 J4pUJJ(nh=!i*Y@> %PM# - ]:DT-d DQELƳZ Ji'P Qrey2D,rT\YTNEa$$uHǠN4`/AbCn&)$J{-<@o` XBXFs4 -6b. x,U )Q(Q뵀 ZH&!V@Rd>Ɂe| *SEQ6$I>SCu޺ΊfgC fЬ-)Ev4eQCvVeG]OO&% |6=t\K=d;#4l6U8$ދf BKs> =WWDbK/iV`h F6NLZ:Yt\@!&#[yM!vTC ژcTҎ05]U[|455>q~Oy(a%+-4:9^UNw 7JKci KgzL4kgVP+)su*%׉pVV|XR8rn۽6Dk8oV?*SH:BDE\!D0 Pc([$'lἭ3#19&ړV(1И(@""ȯ3\ /R#Oj$ o%11#Yyw⑿AD:ޱH;=]?Ź [O5ٯ[sb0i]ij.ǧG/a&-,F޹.67Joc8>yS>DvjdLXm~[! {;v h?VPߟOqv{dz-έSO>༬猣u~9=f_oy%=;{=T6)-.愜8x׵Z{eyK->f,$^)]pKj# tՉYx3[FN_=g,wkض{_80<wvc<~~;X;7~%?u̟6<&| ֔^YƷf~3xTB9I&eշڔxy.fxW\Noߜee׎YZj&q.6%FO+xOb=Dp+v.E "_ 5BH_i_Cm{~xŬ 5$"K GIXk#⯔p u39df*JO*rqXY2gwo;^a fe^BoU+z/Yʙ#!RȔ#∘_00tjX"$3ERTlT6vEtȅV;T'V}_aaS6r7] 79QoKvm {8^~K^h; KH毵&ZmqB텑o۔eVs{{n8GךXMsd}: 7$BtYXGB݁ڵyjJͅ2塵^n7?Wwhf|탖32^q+xbѽ<쎡o#~vJq~eΛ]q9kF }wyCH`aI=<-fROxmKQ҃7b_dTmKM,H}Hpa1)$T/sN00[" u抂C)c%];wn^l>O&kZ AVXM\s^;0OͣO5-eTި/-|{}CcVxUB=ZKtK]E=hM{1*sE[om]-ڦ0\ny_wX-]M놎{照j*#Np=5 vm7Mןl[ڞ|wxցg7M}1Jάes_1fOl.^Ⱥä~v)eս'I~Է2o'ؤ»wtt ݕaSe޽{iVW?[I/^V7*O˥I*|]CZ|}栩0cbθqˌ}?jikyg87W;sjxrӰ oN߿5mԙak<ӽj[Gx\ymj7tpڢ[#.(b?KJ&}mx`ܽFx٢tҋG;&}ϯ}B+益ZK=aW|x ֵxM]3zxtdh^WWĮl]I/:WӬz[iovp1k;k5C/kn#vyd5^"Xb{U&ngY']E7gd}*;}|žҳs+Ge(ݬʗx_AuO}vX׋ ^5\>c'zxDݸΰknZ 52 sFmra&]t׸ Y;Ky{@`߂] 6eY}cRD dR" uD"(<(.#gӌFXc"NkjX%d Pr:HN =  n(=-Q1S7q9S [p嶝o;-SawY9~{[;~hG%e%vnwG[x5rwyW[q|r3V0FMzz=o㝶 n}k)gVyDmd~sf_fʓN߆P~J/yy<+,);`(jt̷&r!YEy ܦP :M[XC0Vi4xֿp}^Iy.| ڙވRll3«~! RoйE'./ݬz04,|>9ԏZWѡgwvjfF k;u؉2Dˆϒ]<<1Eʲa=~KE͊Y<~-ɜ bOm̵\yKR nt/ |<-wqK⇧x^/eFF M[oL" 3 endstream endobj 20 0 obj <> stream Khan6,I (ug) Microsoft Word2020-09-07T18:35:49+00:002020-09-07T18:35:49+00:00 uuid:8B706D72-90FE-4CF3-AECD-D6280931B403uuid:8B706D72-90FE-4CF3-AECD-D6280931B403 endstream endobj 21 0 obj <> endobj 22 0 obj <<726D708BFE90F34CAECDD6280931B403>] /Filter/FlateDecode/Length 85>> stream xc` Z)g` bS,Bڙ 3bPBAUA,b 7  endstream endobj xref 0 23 0000000010 65535 f 0000000017 00000 n 0000000166 00000 n 0000000222 00000 n 0000000486 00000 n 0000000705 00000 n 0000000872 00000 n 0000001111 00000 n 0000001164 00000 n 0000001217 00000 n 0000000011 65535 f 0000000012 65535 f 0000000013 65535 f 0000000014 65535 f 0000000015 65535 f 0000000016 65535 f 0000000017 65535 f 0000000000 65535 f 0000001758 00000 n 0000001785 00000 n 0000021212 00000 n 0000024300 00000 n 0000024345 00000 n trailer <<726D708BFE90F34CAECDD6280931B403>] >> startxref 24629 %%EOF xref 0 0 trailer <<726D708BFE90F34CAECDD6280931B403>] /Prev 24629/XRefStm 24345>> startxref 25245 %%EOF 1 0 obj << /Type /Catalog /Pages 2 0 R /Lang (en\055US) /StructTreeRoot 10 0 R /MarkInfo << /Marked true >> /Metadata 20 0 R /ViewerPreferences 21 0 R /AcroForm << /Fields [ 23 0 R ] /SigFlags 3 >> >> endobj 23 0 obj << /FT /Sig /Type /Annot /Subtype /Widget /F 132 /T (Signature1) /V 24 0 R /P 3 0 R /Rect [ 0 0 0 0 ] >> endobj 24 0 obj << /Type /Sig /Filter /Adobe.PPKLite /SubFilter /adbe.pkcs7.detached /Name (user\100example\056com) /Location (England) /Reason (Test) /M (D\07220200907064258\05300\04700\047) /Contents <308205bd06092a864886f70d010702a08205ae308205aa020101310f300d06096086480165030402010500300b06092a864886f70d010701a0820368308203643082024ca0030201020214672b4ac394b5e4b11b996a85ddd96e688ff9a51e300d06092a864886f70d01010b0500306a3110300e06035504061307456e676c616e643117301506035504080c0e47726561746572204c6f6e646f6e310f300d06035504070c064c6f6e646f6e31153013060355040a0c0c476f6f676c6548534d2043413115301306035504030c0c476f6f676c6548534d204341301e170d3230303930363138303435375a170d3231303930373138303435375a306a3110300e06035504061307456e676c616e643117301506035504080c0e47726561746572204c6f6e646f6e310f300d06035504070c064c6f6e646f6e31153013060355040a0c0c476f6f676c6548534d2043413115301306035504030c0c476f6f676c6548534d20434130820122300d06092a864886f70d01010105000382010f003082010a028201010091bc2836b2cdf4c447895d25811d7556a6e64efa19a18518a22f1bfafadfeb08ad7accb6811dcc053c652a4b1aeb04f421792bb7a5b48b76d49270c85584703df0e30c6d3c92bc4f4b5f6ab7d63b1e805949188661ae3b99caf2b23f96b6cadefbc904dd528eed70e89c80634ca01eb81730b6e8b14ac3b52a2f31db321c78879963a6c6f3f36715c9ae9e1af76c0dd84d5cbe9fb5a057dfe7c39218f34826c476d71bc0b5d0cd8225dde762eda1cd8c4ce6e3db9f1fbd74475ee4a59198829020db80e4d46684ac6f7cac1fbc1e50818edb8649d2b1b3d3af40094cee9a8f363de681bc55a0f0b85551198ea5ec1106fe8e361e3e5afdcf79216dc78f0bfa290203010001a3023000300d06092a864886f70d01010b0500038201010064343de9b7cf67e0c2c36ef5be396806fff3301505294798b91d03503c7547c29a6da41d1e725a50bf753cede7375f6cd66af13e4e7c97dab622e20b36bfdf1b3defd1fafa754a50a0932486df1640432999818e43496c1e11e72c553e0d478e54985a5b44a38119bb9efb1b57a3c644c46454002cf99aaf83c1820644a8ba893318f180d1304b76760e295d14f17b245da6d898f7ceaef29c9848f13a62993cd5fab0a16583dab16a95fc372fe9a36b65c09c81bf6926c47c682bedac4768f7a2cd946654541b96c1903f42480eff42e07ed5d760bccf5b30c5a1f2d40a9367a6930c8298b4c9b8334bf6e2fb5cddbe0259115554c0a39e7eba79988beae3d93182021930820215020101308182306a3110300e06035504061307456e676c616e643117301506035504080c0e47726561746572204c6f6e646f6e310f300d06035504070c064c6f6e646f6e31153013060355040a0c0c476f6f676c6548534d2043413115301306035504030c0c476f6f676c6548534d2043410214672b4ac394b5e4b11b996a85ddd96e688ff9a51e300d06096086480165030402010500a069301806092a864886f70d010903310b06092a864886f70d010701301c06092a864886f70d010905310f170d3230303930373138343235385a302f06092a864886f70d01090431220420d725923e7ece4aa49de07dae8adcf90e78f77cee341c392ecc585167c7402397300d06092a864886f70d0101010500048201001fbc808f736310a7163e56bed0f249dc14e28889360a619d4eb2e3ece05708653efb1d8ddbf12668d91936f3adddd6e0b3a6755a27af44a7f7cd4a7275fea3f01988bbab12de8f87832d9365924f4f002ace49bd44dbc2fdbac55f21ce2c1ea696c6359d5edbc50b3d786fe167500c17fa3d37b4326db8cb8d50a0da254457d48ac49623db8c136129ed1f434e137cfa52ea6cb139687796f6cf864b77c1056b2640904440b3ac88ab4037dba79f7501c409dba501d90901488cf5a62b77e53d16f9b54f2a1e5f4eb0cdcbaba9aa24c13cf319572c10fcf650d67cc5c2bb02ee79174b22664298b36fe601f0f4c17452bda480957dd74a6673ae4d5fb4833e13> /ByteRange [0 25949 28897 317] >> endobj xref 0 2 0000000000 65535 f 0000025425 00000 n 23 2 0000025633 00000 n 0000025754 00000 n trailer << /Size 25 /Root 1 0 R /Prev 25245 /ID [ <726d708bfe90f34caecdd6280931b403> ] /Info 9 0 R >> startxref 28959 %%EOF endesive-2.19.1/examples/xml-hsm-certum-enveloped.py000077500000000000000000000062701504236674500224630ustar00rootroot00000000000000#!/usr/bin/env vpython3 # *-* coding: utf-8 *-* from certum import dllpath import PyKCS11 as PK11 from lxml import etree from cryptography import x509 from cryptography.hazmat.backends import default_backend from cryptography.hazmat.primitives import serialization from endesive import xades, signer, hsm class Signer(hsm.HSM): def certificate(self): self.login("profil bezpieczny", "9593") keyid = [ 0x5E, 0x9A, 0x33, 0x44, 0x8B, 0xC3, 0xA1, 0x35, 0x33, 0xC7, 0xC2, 0x02, 0xF6, 0x9B, 0xDE, 0x55, 0xFE, 0x83, 0x7B, 0xDE, ] # keyid = [0x3f, 0xa6, 0x63, 0xdb, 0x75, 0x97, 0x5d, 0xa6, 0xb0, 0x32, 0xef, 0x2d, 0xdc, 0xc4, 0x8d, 0xe8] keyid = bytes(keyid) try: pk11objects = self.session.findObjects( [(PK11.CKA_CLASS, PK11.CKO_CERTIFICATE)] ) all_attributes = [ # PK11.CKA_SUBJECT, PK11.CKA_VALUE, # PK11.CKA_ISSUER, # PK11.CKA_CERTIFICATE_CATEGORY, # PK11.CKA_END_DATE, PK11.CKA_ID, ] for pk11object in pk11objects: try: attributes = self.session.getAttributeValue( pk11object, all_attributes ) except PK11.PyKCS11Error as e: continue attrDict = dict(list(zip(all_attributes, attributes))) cert = bytes(attrDict[PK11.CKA_VALUE]) if keyid == bytes(attrDict[PK11.CKA_ID]): return keyid, cert finally: self.logout() return None, None def sign(self, keyid, data, mech): self.login("profil bezpieczny", "9593") try: privKey = self.session.findObjects( [(PK11.CKA_CLASS, PK11.CKO_PRIVATE_KEY), (PK11.CKA_ID, keyid)] )[0] mech = getattr(PK11, "CKM_%s_RSA_PKCS" % mech.upper()) sig = self.session.sign(privKey, data, PK11.Mechanism(mech, None)) return bytes(sig) finally: self.logout() def main(): clshsm = Signer(dllpath) keyid, cert = clshsm.certificate() def signproc(tosign, algosig): return clshsm.sign(keyid, tosign, algosig) data = open("xml.xml", "rb").read() cert = x509.load_der_x509_certificate(cert, backend=default_backend()) certcontent = cert.public_bytes(serialization.Encoding.DER) for tspurl, tspcred in ( (None, None), ("http://public-qlts.certum.pl/qts-17", None) ): cls = xades.BES() doc = cls.enveloped(data, cert, certcontent, signproc, tspurl, tspcred) data = etree.tostring(doc, encoding="UTF-8", xml_declaration=True, standalone=False) if tspurl is not None: open("xml-hsm-certum-enveloped-t.xml", "wb").write(data) else: open("xml-hsm-certum-enveloped.xml", "wb").write(data) if __name__ == "__main__": main() endesive-2.19.1/examples/xml-hsm-certum-enveloping.py000077500000000000000000000065761504236674500226610ustar00rootroot00000000000000#!/usr/bin/env vpython3 # *-* coding: utf-8 *-* from certum import dllpath from lxml import etree import PyKCS11 as PK11 from cryptography import x509 from cryptography.hazmat.backends import default_backend from cryptography.hazmat.primitives import serialization from endesive import xades, signer, hsm class Signer(hsm.HSM): def certificate(self): self.login("profil bezpieczny", "9593") keyid = [ 0x5E, 0x9A, 0x33, 0x44, 0x8B, 0xC3, 0xA1, 0x35, 0x33, 0xC7, 0xC2, 0x02, 0xF6, 0x9B, 0xDE, 0x55, 0xFE, 0x83, 0x7B, 0xDE, ] # keyid = [0x3f, 0xa6, 0x63, 0xdb, 0x75, 0x97, 0x5d, 0xa6, 0xb0, 0x32, 0xef, 0x2d, 0xdc, 0xc4, 0x8d, 0xe8] keyid = bytes(keyid) try: pk11objects = self.session.findObjects( [(PK11.CKA_CLASS, PK11.CKO_CERTIFICATE)] ) all_attributes = [ # PK11.CKA_SUBJECT, PK11.CKA_VALUE, # PK11.CKA_ISSUER, # PK11.CKA_CERTIFICATE_CATEGORY, # PK11.CKA_END_DATE, PK11.CKA_ID, ] for pk11object in pk11objects: try: attributes = self.session.getAttributeValue( pk11object, all_attributes ) except PK11.PyKCS11Error as e: continue attrDict = dict(list(zip(all_attributes, attributes))) cert = bytes(attrDict[PK11.CKA_VALUE]) if keyid == bytes(attrDict[PK11.CKA_ID]): return keyid, cert finally: self.logout() return None, None def sign(self, keyid, data, mech): self.login("profil bezpieczny", "9593") try: privKey = self.session.findObjects( [(PK11.CKA_CLASS, PK11.CKO_PRIVATE_KEY), (PK11.CKA_ID, keyid)] )[0] mech = getattr(PK11, "CKM_%s_RSA_PKCS" % mech.upper()) sig = self.session.sign(privKey, data, PK11.Mechanism(mech, None)) return bytes(sig) finally: self.logout() def main(): clshsm = Signer(dllpath) keyid, cert = clshsm.certificate() def signproc(tosign, algosig): return clshsm.sign(keyid, tosign, algosig) data = open("xml.xml", "rb").read() cert = x509.load_der_x509_certificate(cert, backend=default_backend()) certcontent = cert.public_bytes(serialization.Encoding.DER) for tspurl, tspcred in ( (None, None), ("http://public-qlts.certum.pl/qts-17", None) ): cls = xades.BES() doc = cls.enveloping( "dokument.xml", data, "application/xml", cert, certcontent, signproc, False, False, False, tspurl, tspcred, ) data = etree.tostring(doc, encoding="UTF-8", xml_declaration=True, standalone=False) if tspurl is None: open("xml-hsm-certum-enveloping.xml", "wb").write(data) else: open("xml-hsm-certum-enveloping-t.xml", "wb").write(data) if __name__ == "__main__": main() endesive-2.19.1/examples/xml-hsm-softhsm2-enveloped.py000077500000000000000000000052721504236674500227320ustar00rootroot00000000000000#!/usr/bin/env vpython3 # *-* coding: utf-8 *-* from lxml import etree from cryptography import x509 from cryptography.hazmat.backends import default_backend from cryptography.hazmat.primitives import serialization from endesive import xades, signer, hsm import os import sys import sysconfig os.environ["SOFTHSM2_CONF"] = "softhsm2.conf" if sys.platform == "win32": dllpath = r"W:\binw\SoftHSM2\lib\softhsm2-x64.dll" else: dllpath = os.path.join(sysconfig.get_config_var('LIBDIR'), "softhsm/libsofthsm2.so") import PyKCS11 as PK11 class Signer(hsm.HSM): def certificate(self): self.login("endesieve", "secret1") keyid = bytes((0x66, 0x66, 0x90)) try: pk11objects = self.session.findObjects( [(PK11.CKA_CLASS, PK11.CKO_CERTIFICATE)] ) all_attributes = [ # PK11.CKA_SUBJECT, PK11.CKA_VALUE, # PK11.CKA_ISSUER, # PK11.CKA_CERTIFICATE_CATEGORY, # PK11.CKA_END_DATE, PK11.CKA_ID, ] for pk11object in pk11objects: try: attributes = self.session.getAttributeValue( pk11object, all_attributes ) except PK11.PyKCS11Error as e: continue attrDict = dict(list(zip(all_attributes, attributes))) cert = bytes(attrDict[PK11.CKA_VALUE]) if keyid == bytes(attrDict[PK11.CKA_ID]): return keyid, cert finally: self.logout() return None, None def sign(self, keyid, data, mech): self.login("endesieve", "secret1") try: privKey = self.session.findObjects( [(PK11.CKA_CLASS, PK11.CKO_PRIVATE_KEY), (PK11.CKA_ID, keyid)] )[0] mech = getattr(PK11, "CKM_%s_RSA_PKCS" % mech.upper()) sig = self.session.sign(privKey, data, PK11.Mechanism(mech, None)) return bytes(sig) finally: self.logout() def main(): clshsm = Signer(dllpath) keyid, cert = clshsm.certificate() def signproc(tosign, algosig): return clshsm.sign(keyid, tosign, algosig) data = open("xml.xml", "rb").read() cert = x509.load_der_x509_certificate(cert, backend=default_backend()) certcontent = cert.public_bytes(serialization.Encoding.DER) cls = xades.BES() doc = cls.enveloped(data, cert, certcontent, signproc, None, None) data = etree.tostring(doc, encoding="UTF-8", xml_declaration=True, standalone=False) open("xml-hsm-softhsm2-enveloped.xml", "wb").write(data) if __name__ == "__main__": main() endesive-2.19.1/examples/xml-hsm-softhsm2-enveloping.py000077500000000000000000000054461504236674500231220ustar00rootroot00000000000000#!/usr/bin/env vpython3 # *-* coding: utf-8 *-* from lxml import etree from cryptography import x509 from cryptography.hazmat.backends import default_backend from cryptography.hazmat.primitives import serialization from endesive import xades, signer, hsm import os import sys import sysconfig os.environ["SOFTHSM2_CONF"] = "softhsm2.conf" if sys.platform == "win32": dllpath = r"W:\binw\SoftHSM2\lib\softhsm2-x64.dll" else: dllpath = os.path.join(sysconfig.get_config_var('LIBDIR'), "softhsm/libsofthsm2.so") import PyKCS11 as PK11 class Signer(hsm.HSM): def certificate(self): self.login("endesieve", "secret1") keyid = bytes((0x66, 0x66, 0x90)) try: pk11objects = self.session.findObjects( [(PK11.CKA_CLASS, PK11.CKO_CERTIFICATE)] ) all_attributes = [ # PK11.CKA_SUBJECT, PK11.CKA_VALUE, # PK11.CKA_ISSUER, # PK11.CKA_CERTIFICATE_CATEGORY, # PK11.CKA_END_DATE, PK11.CKA_ID, ] for pk11object in pk11objects: try: attributes = self.session.getAttributeValue( pk11object, all_attributes ) except PK11.PyKCS11Error as e: continue attrDict = dict(list(zip(all_attributes, attributes))) cert = bytes(attrDict[PK11.CKA_VALUE]) if keyid == bytes(attrDict[PK11.CKA_ID]): return keyid, cert finally: self.logout() return None, None def sign(self, keyid, data, mech): self.login("endesieve", "secret1") try: privKey = self.session.findObjects( [(PK11.CKA_CLASS, PK11.CKO_PRIVATE_KEY), (PK11.CKA_ID, keyid)] )[0] mech = getattr(PK11, "CKM_%s_RSA_PKCS" % mech.upper()) sig = self.session.sign(privKey, data, PK11.Mechanism(mech, None)) return bytes(sig) finally: self.logout() def main(): clshsm = Signer(dllpath) keyid, cert = clshsm.certificate() def signproc(tosign, algosig): return clshsm.sign(keyid, tosign, algosig) data = open("xml.xml", "rb").read() cert = x509.load_der_x509_certificate(cert, backend=default_backend()) certcontent = cert.public_bytes(serialization.Encoding.DER) cls = xades.BES() doc = cls.enveloping( "dokument.xml", data, "application/xml", cert, certcontent, signproc, False, True, ) data = etree.tostring(doc, encoding="UTF-8", xml_declaration=True, standalone=False) open("xml-hsm-softhsm2-enveloping.xml", "wb").write(data) if __name__ == "__main__": main() endesive-2.19.1/examples/xml-make.py000077500000000000000000000050051504236674500173300ustar00rootroot00000000000000#!/usr/bin/env vpython3 # *-* coding: utf-8 *-* import io def main(): io.open('xml.xml', 'wt', encoding='utf-8').write('''\ VAT-7 17 1 2017 2 3215 7791011327 Nazwa firmy 630303023 0 3108 3108 0 0 998293 49915 901697 72135 3334214 766869 3177289 187401 44326 8864 0 0 0 0 66801 15364 0 0 0 0 0 0 0 0 0 8713129 913147 512089 54480 12531 8152972 1279013 0 0 -138 1380 1804875 0 0 0 0 891728 0 0 0 0 891728 2 2 2 914842496 2017-05-09 1 ''' ) main() endesive-2.19.1/examples/xml-time000077500000000000000000000103751504236674500167300ustar00rootroot00000000000000#!/bin/bash cat >xml-time.txt <<-EOF MIIL/gYJKoZIhvcNAQcCoIIL7zCCC+sCAQMxDTALBglghkgBZQMEAgEwggEOBgsq hkiG9w0BCRABBKCB/gSB+zCB+AIBAQYLKoRoAYb2dwIEAQ4wMTANBglghkgBZQME AgEFAAQgVSguaHYYcACxv0j4mVPwtXOLK385JKGLJxdOiBIxHbICBxHDeUu0XvMY DzIwMjAxMTIwMDAzMjMzWjADAgEBAgg8Y1+nFdWsQqBqpGgwZjELMAkGA1UEBhMC UEwxITAfBgNVBAoMGEFzc2VjbyBEYXRhIFN5c3RlbXMgUy5BLjEZMBcGA1UEAwwQ Q2VydHVtIFFUU1QgMjAxNzEZMBcGA1UEYQwQVkFUUEwtNTE3MDM1OTQ1OKEeMBwG CCsGAQUFBwEDAQEABA0wCzAJBgcEAIGXXgEBoIIGpDCCBqAwggSIoAMCAQICFBGT c18XwX4UTT+Sj2Gbv9UCfbHpMA0GCSqGSIb3DQEBDQUAMG8xCzAJBgNVBAYTAlBM MR0wGwYDVQQKDBROYXJvZG93eSBCYW5rIFBvbHNraTEmMCQGA1UEAwwdTmFyb2Rv d2UgQ2VudHJ1bSBDZXJ0eWZpa2FjamkxGTAXBgNVBGEMEFZBVFBMLTUyNTAwMDgx OTgwHhcNMTcwMzE1MTAyMzE4WhcNMjgwMzE1MjM1OTU5WjBmMQswCQYDVQQGEwJQ TDEhMB8GA1UECgwYQXNzZWNvIERhdGEgU3lzdGVtcyBTLkEuMRkwFwYDVQQDDBBD ZXJ0dW0gUVRTVCAyMDE3MRkwFwYDVQRhDBBWQVRQTC01MTcwMzU5NDU4MIICIjAN BgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAyFQRTZ7zNxErQLcN+0f5Nwh2dPqM F3dZ9OodSJC1f5oOBOj5rq1IZVwAJoxX3s2x7E/yM81DZjd4duZQPAvxf5cdAAEp Y13kvGAnRUkPREytTY7MhKt8D0VWjBZBTZrLhI4jbYkosnLpzgVeAYE+GeDY9Exb MTsZSOxdfBPGFtB0/QqwzFK7jAywPz1uSHemMlEAnyTqLiDNrqA8ZzmMvx5+8vna FhWh5vLbFLI7urd2SybD7YcScKNWH1zW/p6a0FtMT1lN3GQbXAIx5Hs3UVLRObgL pv3zdgko9syOOpckrZf93EBz95W9QlrkeklHk7qQfqkbUhbv8wnhKjBox4ifxGkg MDxkGt7SerLzA6xWS33f0qSmCy+m4DRxiRxoTPNscLuksNw9hzEnv4/rFBMg5NkV pvkXLKKBWgi/Nb7gbnq4XAaUEKPoH46nmYrVhnhV9dRDJPcItBhRtTAp6yrO09bK LDWhaMcnX5o+yPCG+h/9cAe/l04lYscGaLwELCXwxFhR8cEp27Q5hNBEIzA1MeBK zF+626Poj+b/rKgds5b1oQFJ0Je0GvEBvo4ADtX8tp1tDoGgzN/zokwijZ5fzgsI v3FrpcAVI36Of84bjk6k4jPjbJE96uRyMjTiHWbePuMAfAOx1xYAQG9mVj2lZV6E 4WUCaKaV985C2eMCAwEAAaOCATswggE3MBYGA1UdJQEB/wQMMAoGCCsGAQUFBwMI MAwGA1UdEwEB/wQCMAAwgawGA1UdIwSBpDCBoYAUKbPIxN+jh/hmBRJY/UYquJgN eYehc6RxMG8xCzAJBgNVBAYTAlBMMR0wGwYDVQQKDBROYXJvZG93eSBCYW5rIFBv bHNraTEmMCQGA1UEAwwdTmFyb2Rvd2UgQ2VudHJ1bSBDZXJ0eWZpa2FjamkxGTAX BgNVBGEMEFZBVFBMLTUyNTAwMDgxOTiCFED494qw42QQVpHI2eAs+MHGQApGMDEG A1UdIAEB/wQnMCUwIwYEVR0gADAbMBkGCCsGAQUFBwIBFg13d3cubmNjZXJ0LnBs MA4GA1UdDwEB/wQEAwIGwDAdBgNVHQ4EFgQUsr0SyweB4nujsGEdSkN5qIf00HYw DQYJKoZIhvcNAQENBQADggIBAJEejdQcHyIDufbffB3rYzfqQjtTTpV6EcYkDFEZ otUJz3iiWWIOEzzzs7DOZUM6PbPdV7mCBxpUbwmnLZPGdhSvQz6SSOu9F34STfoz aAAwtPSbqSofGDXxXSzSJwx46+VitaqHHyoML74DB9Us46bhAgwK9j6M8J5nUs3e 4TOkpRumJ9JhFm/FiOxJVXQGuZ6PUe45ScFIDzKS90zOEsz43x1WZcJ2p+ZFF7q0 y00+vXbknNoaqLKxEr8O5urzvjtPkIg1KVddBAQte2PGHhsA0BcocBy+hAudLjbT sknhts+wZwa6mnpXj9lJyZUJpIMZmKs/deSW3F/X9idd01OvR9PHyr6BeJ923Z/X hJf0U0kP5QL+qe5DLgxjPjwPcnL6Pa+pREvj3geSAtvSUcTfwvnmnzfPpvW9MX1B fBoElzr6sQOiiH2g/hDIaVocwGNtOinAx5qNmwURVgydmd+qliu44XDquTP5k+Jm OULqHk8W0zB4jCqmc1LphvlIRBt4yTsUfXVbYTEvg8a22DbB+M9pd1PtA6flPSh/ qgYqMc+NiHWzmQJM80eXTGWof+hF1uRbexBUdFYF1B96QDk8ivzdTwKM/vUrkEJ+ 9RVv238IXpWjnn0oevo5GDvU861TyQEMNFdkAEXeGPQOqhdl8Ik8o83sCx3Y/KbT Ed1WMYIEGzCCBBcCAQEwgYcwbzELMAkGA1UEBhMCUEwxHTAbBgNVBAoMFE5hcm9k b3d5IEJhbmsgUG9sc2tpMSYwJAYDVQQDDB1OYXJvZG93ZSBDZW50cnVtIENlcnR5 ZmlrYWNqaTEZMBcGA1UEYQwQVkFUUEwtNTI1MDAwODE5OAIUEZNzXxfBfhRNP5KP YZu/1QJ9sekwDQYJYIZIAWUDBAIBBQCgggFkMBoGCSqGSIb3DQEJAzENBgsqhkiG 9w0BCRABBDAcBgkqhkiG9w0BCQUxDxcNMjAxMTIwMDAzMjMzWjAvBgkqhkiG9w0B CQQxIgQgEqo4OCMN2RUxYPddYfSC0b8/N03K87zJ+dbMJTeCb1MwNwYLKoZIhvcN AQkQAi8xKDAmMCQwIgQgZzvoodqSfbY8yrfLPnrDUtw662qNo+KjWcoVjQpEDbgw gb0GCyqGSIb3DQEJEAIMMYGtMIGqMIGnMIGkBBRuI825Z/BtP9qFMWxbRzYc1VVC rDCBizBzpHEwbzELMAkGA1UEBhMCUEwxHTAbBgNVBAoMFE5hcm9kb3d5IEJhbmsg UG9sc2tpMSYwJAYDVQQDDB1OYXJvZG93ZSBDZW50cnVtIENlcnR5ZmlrYWNqaTEZ MBcGA1UEYQwQVkFUUEwtNTI1MDAwODE5OAIUEZNzXxfBfhRNP5KPYZu/1QJ9sekw DQYJKoZIhvcNAQELBQAEggIAYjZ1PVhl9tSvA5ZMk5meJrvX9KSW4AKTUeE1vVhk F1TnUbZe/yyxcUS3fPU3wbEAW9QqYmK/ecTLDp0Xr1yylQxnAJpaJXCg9t/5AUwc 7biv+vT50OmhzknQKS95nYNkWhRPqJ2ZjhWGxzo5jogt0qlJzQ7W2V34s554U1EQ BTWAR29+QeZ8NqAMuRE6AXNzZuRP9hmgw1k3JRd+Kz6E3zh82WsLimM9JQ/8sm6w GgDrbwLH5MuYFa49R6h/29i0QEtAoFsAkTMQYz4DRIcI7L6b8nov7ukU8jLC6xmG +9hGK38QMuqvxXOi6LSjeGg6fUwZZqN9VAWeebRvbIH67q00ePKKV5g5YlMkJxRT nm1haQFS15kubGqgfbB67+V+NhLHQW4oYMBAgInfzdPq5gt+Oz6iPuj728x4Haji EkXaPIvVQ/wnqS2mVIT3AfZUlR+unvJx0wiMDcH+Kvb+e4tJACh+1k7m2qTcAZjQ gtTufoThgkqVAVXKQBRMsTiOgqs6OYEfu/Mze2thZZewC5cyrAFDT+9VrfcJrnS5 A3BssrCatKdN5pkU1wnsnHmoWYFbEFLr/uC2RcNxitM4qBnWb+wn+4Idm2615uCj VOH0r21u1y+nWjOXHLjzz5QfxLsftLixUyPPI9mQm/0TgUtzMa16lxUXTR984GGW10A= EOF base64 --decode xml-time.raw openssl cms -in xml-time.raw -inform DER -cmsout -print >xml-time.txt #rm xml-time.txt xml-time.raw endesive-2.19.1/examples/xml-xmlsigner-enveloped.py000077500000000000000000000015621504236674500224060ustar00rootroot00000000000000#!/usr/bin/env vpython3 # *-* coding: utf-8 *-* from lxml import etree import signxml cert = open("ca/demo2_user1.crt.pem").read() key = open("ca/demo2_user1.key.pem").read() cert1 = open("ca/demo2_ca.sub.crt.pem").read() data = open("xml.xml", "rb").read() root = etree.fromstring(data) signed_root = signxml.XMLSigner(method=signxml.methods.enveloped).sign( root, key=key, cert=[cert, cert1], passphrase=b"1234" ) verified_data = ( signxml.XMLVerifier().verify(signed_root, ca_pem_file="ca/demo2_ca.root.crt.pem").signed_xml ) xml = etree.tostring( signed_root, encoding="UTF-8", xml_declaration=True, standalone=False ) open("xml-xmlsigner-enveloped.xml", "wb").write(xml) xml = etree.tostring( signed_root, encoding="UTF-8", xml_declaration=True, standalone=False, pretty_print=True, ) open("xml-xmlsigner-enveloped1.xml", "wb").write(xml) endesive-2.19.1/examples/xml-xmlsigner-enveloping.py000077500000000000000000000013571504236674500225750ustar00rootroot00000000000000#!/usr/bin/env vpython3 # *-* coding: utf-8 *-* from lxml import etree import signxml cert = open("ca/demo2_user1.crt.pem").read() key = open("ca/demo2_user1.key.pem").read() cert1 = open("ca/demo2_ca.sub.crt.pem").read() data = open('xml.xml', 'rb').read() root = etree.fromstring(data) signed_root = signxml.XMLSigner( method=signxml.methods.enveloping ).sign( root, key=key, cert=[cert, cert1], passphrase=b'1234' ) verified_data = signxml.XMLVerifier( ).verify( signed_root, ca_pem_file="ca/demo2_ca.root.crt.pem" ).signed_xml xml = etree.tostring( signed_root, encoding='UTF-8', xml_declaration=True, standalone=False, pretty_print=True ) open("xml-xmlsigner-enveloping.xml", "wb").write(xml) endesive-2.19.1/examples/xml-xmlsigner-verify.py000077500000000000000000000012251504236674500217250ustar00rootroot00000000000000#!/usr/bin/env vpython3 # *-* coding: utf-8 *-* import sys from lxml import etree import signxml if sys.argv[1:]: fname = sys.argv[1] else: fname = "xml-xmlsigner-enveloped.xml" #fname = "xml-xmlsigner-enveloping.xml" #fname = 'xml-xades-bes-enveloped.xml' data = open(fname, "rb").read() signed_root = etree.fromstring(data) verified_data = ( signxml.XMLVerifier().verify(signed_root, ca_pem_file="ca/demo2_ca.root.crt.pem").signed_xml ) xml = etree.tostring( verified_data, encoding="UTF-8", xml_declaration=True, standalone=False, pretty_print=True, ) # open(fname.replace('.xml', '-result.xml'), "wb").write(xml) endesive-2.19.1/examples/xpath-cheatsheet.js000066400000000000000000000317241504236674500210440ustar00rootroot00000000000000// XPath CheatSheet // To test XPath in your Chrome Debugger: $x('/html/body') // http://www.jittuu.com/2012/2/14/Testing-XPath-In-Chrome/ // 0. XPath Examples. // More: http://xpath.alephzarro.com/content/cheatsheet.html '//hr[@class="edge" and position()=1]' // every first hr of 'edge' class '//table[count(tr)=1 and count(tr/td)=2]' // all tables with 1 row and 2 cols '//div/form/parent::*' // all divs that have form './div/b' // a relative path '//table[parent::div[@class="pad"] and not(@id)]//a' // any anchor in a table without id, contained in a div of "pad" class '/html/body/div/*[preceding-sibling::h4]' // give me whatever after h4 '//tr/td[font[@class="head" and text()="TRACK"]]' // all td that has font of a "head" class and text "TRACK" './table/tr[last()]' // the last row of a table '//rdf:Seq/rdf:li/em:id' // using namespaces '//a/@href' // hrefs of all anchors '//*[count(*)=3]' // all nodes with 3 children '//var|//acronym' // all vars and acronyms // 1. General. '/html' // whole web page (css: html) '/html/body' // whole web page body (css: body) '//text()' // all text nodes of web page '/html/body/.../.../.../E' // element by absolute reference (css: body > … > … > … > E) // 2. Tag. '//E' // element by relative reference (css: E) '(//E)[2]' // second element anywhere on page '//img' // image element (css: img) '//E[@A]' // element with attribute A (css: E[A]) '//E[@A="t"]' // element with attribute A containing text 't' exactly (css: E[A='t']) '//E[contains(@A,"t")]' // element with attribute A containing text 't' (css: E[A*='t']) '//E[starts-with(@A, "t")]' // element whose attribute A begins with 't' (css: E[A^='t']) '//E[ends-with(@A, "t")]' // element whose attribute A ends with 't' (css: E[A$='t']) '//E[contains(concat(" ", @A, " "), " w ")' // element with attribute A containing word 'w' (css: E[A~='w']) '//E[matches(@A, "r")]' // element with attribute A matching regex ‘r’ '//E1[@id=I1] | //E2[@id=I2]' // element with id I1 or element with id I2 (css: E1#I1, E2#I2) '//E1[@id=I1 or @id=I2]' // element with id I1 or id I2 (css: E1#I1, E1#I2) // 3. Attribute. '//E/@A' // attribute A of element (css: E@A) '//*/@A' // attribute A of any element (css: *@A) '//E[@A2="t"]/@A1' // attribute A1 of element where attribute A2 is 't' exactly (css: E[A2='t']@A1) '//E[contains(@A,"t")]/@A' // attribute A of element where A contains 't' (css: E[A*='t']@A) // 4. ID & Name. '//*[@id="I"]' // element with id I (css: #I) '//E[@id="I"]' // element with id I (css: E#I) '//*[@name="N"]' // element with name (css: [name='N']) '//E[@name="N"]' // element with name (css: E[name='N']) '//*[@id="X" or @name="X"]' // element with id X or, failing that, a name X '//*[@name="N"][v+1]' // element with name N & specified 0-based index ‘v’ (css: [name='N']:nth-child(v+1)) '//*[@name="N"][@value="v"]' // element with name N & specified value ‘v’ (css: *[name='N'][value='v’]) // 5. Lang & Class. '//E[@lang="L" or starts-with(@lang, concat("L", "-"))]' // element is explicitly in language L or subcode (css: E[lang|=L]) '//*[contains(concat(" ", @class, " "), " C ")]' // element with a class C (css: .C) '//E[contains(concat(" ", @class, " "), " C ")]' // element with a class C (css: E.C) // 6. Text & Link. '//*[.="t"]' // element containing text 't' exactly '//E[contains(text(), "t")]' // element containing text 't' (css: E:contains('t')) '//a' // link element (css: a) '//a[.="t"]' // element containing text 't' exactly '//a[contains(text(), "t")]' // element containing text 't' (css: a:contains('t')) '//a[@href="url"]' // with target link 'url' (css: a[href='url']) '//a[.="t"]/@href' // link URL labeled with text 't' exactly // 7. Parent & Child. '//E/*[1]' // first child of element (css: E > *:first-child) '//E[1]' // first child (css: E:first-of-type) '//E/*[last()]' // last child of element E (css: E *:last-child) '//E[last()]' // last child (css: E:last-of-type) '//E[2]' // second child (css: E:nth-of-type(2)) '//*[2][name()="E"]' // second child that is an element (css: E:nth-child(2)) '//E[last()-1]' // second-to-last child (css: E:nth-last-of-type(2)) '//*[last()-1][name()="E"]' // second-to-last child that is an element (css: E:nth-last-child(2)) '//E1/[E2 and not( *[not(self::E2)])]' // element with only children '//E/..' // parent of element '//*[@id="I"]/.../.../.../E' // descendant of element with id I using specific path (css: #I > … > … > … > E) '//*[@id="I"]//E' // descendant of element with id I using unspecified path (css: #I E) '//E[count(*)=0]' // element with no children (E:empty) '//E[count(*)=1]' // element with an only child '//E[count(preceding-sibling::*)+count(following-sibling::*)=0]' // element that is an only child (css: E:only-child) '//E[count(../E) = 1]' // element with no siblings (css: E:only-of-type) '//E[position() mod N = M + 1]' // every Nth element starting with the (M+1)th (css: E:nth-child(Nn+M)) // 8. Sibling. '//E2/following-sibling::E1' // element following some sibling (css: E2 ~ E1) '//E2/following-sibling::*[1][name()="E1"]' // element immediately following sibling (css: E2 + E1) '//E2/following-sibling::*[2][name()="E1"]' // element following sibling with one intermediary (css: E2 + * + E1) '//E/following-sibling::*' // sibling element immediately following (css: E + *) '//E2/preceding-sibling::E1' // element preceding some sibling '//E2/preceding-sibling::*[1][name()="E1"]' // element immediately preceding sibling '//E2/preceding-sibling::*[2][name()="E1"]' // element preceding sibling with one intermediary '//E/preceding-sibling::*[1]' // sibling element immediately preceding // 9. Table Cell. '//*[@id="TestTable"]//tr[3]//td[2]' // cell by row and column (e.g. 3rd row, 2nd column) (css: #TestTable tr:nth-child(3) td:nth-child(2)) '//td[preceding-sibling::td="t"]' // cell immediately following cell containing 't' exactly 'td[preceding-sibling::td[contains(.,"t")]]' // cell immediately following cell containing 't' (css: td:contains('t') ~ td) // 10. Dynamic. '//E[@disabled]' // user interface element that is disabled (css: E:disabled) '//*[not(@disabled)]' // user interface element that is enabled (css: E:enabled) '//*[@checked]' // checkbox (or radio button) that is checked (css: *:checked) // 11. XPath Functions. // https://developer.mozilla.org/en-US/docs/Web/XPath/Functions // 11.1. Conversion. boolean(expression) // evaluates an expression and returns true or false. string([object]) // converts the given argument to a string. number([object]) // converts an object to a number and returns the number. // 11.2. Math. ceiling(number) // evaluates a decimal number and returns the smallest integer greater than or equal to the decimal number. floor(number) // evaluates a decimal number and returns the largest integer less than or equal to the decimal number. round(decimal) // returns a number that is the nearest integer to the given number. sum(node-set) // returns a number that is the sum of the numeric values of each node in a given node-set. // 11.3. Logic. true() // returns a boolean value of true. false() // returns boolean false. not(expression) // evaluates a boolean expression and returns the opposite value. // 11.4. Node. lang(string) // determines whether the context node matches the given language and returns boolean true or false. name([node-set]) // returns a string representing the QName of the first node in a given node-set. namespace-uri([node-set]) // returns a string representing the namespace URI of the first node in a given node-set. // 11.5. Context. count(node-set) // counts the number of nodes in a node-set and returns an integer. function-available(name) // determines if a given function is available and returns boolean true or false. last() // returns a number equal to the context size from the expression evaluation context. position() // returns a number equal to the context position from the expression evaluation context. // 11.6. String. contains(haystack-string, needle-string) // determines whether the first argument string contains the second argument string and returns boolean true or false. concat(string1, string2 [stringn]*) // concatenates two or more strings and returns the resulting string. normalize-space(string) // strips leading and trailing white-space from a string, replaces sequences of whitespace characters by a single space, and returns the resulting string. starts-with(haystack, needle) // checks whether the first string starts with the second string and returns true or false. string-length([string]) // returns a number equal to the number of characters in a given string. substring(string, start [length]) // returns a part of a given string. substring-after(haystack, needle) // returns a string that is the rest of a given string after a given substring. substring-before(haystack, needle) // returns a string that is the rest of a given string before a given substring. translate(string, abc, XYZ) // evaluates a string and a set of characters to translate and returns the translated string. // 12. XPath Axes. ancestor // indicates all the ancestors of the context node beginning with the parent node and traveling through to the root node. ancestor-or-self // indicates the context node and all of its ancestors, including the root node. attribute (@) // indicates the attributes of the context node. Only elements have attributes. This axis can be abbreviated with the at sign (@). child (/) // indicates the children of the context node. If an XPath expression does not specify an axis, this is understood by default. Since only the root node or element nodes have children, any other use will select nothing. descendant (//) // indicates all of the children of the context node, and all of their children, and so forth. Attribute and namespace nodes are not included - the parent of an attribute node is an element node, but attribute nodes are not the children of their parents. descendant-or-self // indicates the context node and all of its descendants. Attribute and namespace nodes are not included - the parent of an attribute node is an element node, but attribute nodes are not the children of their parents. following // indicates all the nodes that appear after the context node, except any descendant, attribute, and namespace nodes. following-sibling // indicates all the nodes that have the same parent as the context node and appear after the context node in the source document. parent(..) // indicates the single node that is the parent of the context node. It can be abbreviated as two periods (..). preceding // indicates all the nodes that precede the context node in the document except any ancestor, attribute and namespace nodes. preceding-sibling // indicates all the nodes that have the same parent as the context node and appear before the context node in the source document. self (.) // indicates the context node itself. It can be abbreviated as a single period (.). endesive-2.19.1/pyproject.toml000066400000000000000000000030561504236674500163420ustar00rootroot00000000000000[build-system] requires = ["setuptools"] build-backend = "setuptools.build_meta" [project] name = "endesive" description = "Library for digital signing and verification of digital signatures in mail, PDF and XML documents." authors = [{ name = "Grzegorz Makarewicz", email = "mak@trisoft.com.pl" }] maintainers = [{ name = "Grzegorz Makarewicz", email = "mak@trisoft.com.pl" }] readme = "README.rst" version = "2.19.0" license = "MIT" license-files = ["LICENSE", "LICENSE.pdf-annotate", "LICENSE.pyfpdf", "LICENSE.pypdf2"] requires-python = ">=3.0" classifiers = [ "Development Status :: 4 - Beta", "Development Status :: 5 - Production/Stable", "Operating System :: OS Independent", "Intended Audience :: Developers", "Programming Language :: Python :: 3", "Topic :: Software Development :: Libraries :: Python Modules", "Topic :: Communications :: Email", "Topic :: Security :: Cryptography", "Topic :: Office/Business", "Topic :: Text Processing", "Topic :: Multimedia :: Graphics", ] [project.urls] Source = "https://github.com/m32/endesive" "Bug Reports" = "https://github.com/m32/endesive/issues" [project.optional-dependencies] full = [ "cryptography", "asn1crypto", "certvalidator", "lxml", "pykcs11", "Pillow", "pytz", "requests", "paramiko", "attrs" ] dev = [ "pytest-cov", "wheel", "oscrypto" ] docs = [ "sphinx", "sphinx_rtd_theme" ] [tool.check-wheel-contents] package = "./endesive" [tool.pytest.ini_options] filterwarnings = ["error"] testpaths = ["tests"] endesive-2.19.1/tests/000077500000000000000000000000001504236674500145645ustar00rootroot00000000000000endesive-2.19.1/tests/__init__.py000066400000000000000000000000001504236674500166630ustar00rootroot00000000000000endesive-2.19.1/tests/fixtures/000077500000000000000000000000001504236674500164355ustar00rootroot00000000000000endesive-2.19.1/tests/fixtures/.gitignore000066400000000000000000000017751504236674500204370ustar00rootroot00000000000000cert-hsm-* demo2_* root.pem softhsm2/ softhsm2.conf pdf-signed-cms.pdf pdf-signed-cms-pss.pdf pdf-encrypted-signed.pdf pdf-signed-appearance.pdf pdf-signed-appearance-ec.pdf pdf-signed-appearance-manual.pdf pdf-signed-cms-aligned.pdf plain-signed-attr.txt plain-signed-noattr.txt plain-ssl-signed-attr.txt plain-ssl-signed-noattr.txt smime-encrypted.txt smime-signed-attr-custom.txt smime-signed-attr.txt smime-signed-noattr.txt smime-encrypted-aes128-cbc-False.txt smime-encrypted-aes128-cbc-True.txt smime-encrypted-aes128-ofb-False.txt smime-encrypted-aes128-ofb-True.txt smime-encrypted-aes192-cbc-False.txt smime-encrypted-aes192-cbc-True.txt smime-encrypted-aes192-ofb-False.txt smime-encrypted-aes192-ofb-True.txt smime-encrypted-aes256-cbc-False.txt smime-encrypted-aes256-cbc-True.txt smime-encrypted-aes256-ofb-False.txt smime-encrypted-aes256-ofb-True.txt smime-ssl-encrypted-cms-None.txt smime-ssl-encrypted-cms-oaep.txt smime-ssl-encrypted-smime-aes256.txt smime-signed-attr-pss.txt smime-signed-hsm-ssh.txt endesive-2.19.1/tests/fixtures/pdf-XRef.pdf000066400000000000000000000331501504236674500205450ustar00rootroot00000000000000%PDF-1.4 % 4 0 obj << /Type /Catalog /Names << /JavaScript 3 0 R >> /PageLabels << /Nums [ 0 << /S /D /St 1 >> ] >> /Outlines 2 0 R /Pages 1 0 R >> endobj 5 0 obj << /Creator (Google) >> endobj 6 0 obj << /Type /Page /Parent 1 0 R /MediaBox [ 0 0 720 405 ] /Contents 7 0 R /Resources 8 0 R /Annots 10 0 R /Group << /S /Transparency /CS /DeviceRGB >> >> endobj 7 0 obj << /Filter /FlateDecode /Length 9 0 R >> stream xQMK1LgL> W!gQڥխd]7-B;l&HޛBic%`T]`i-Jځqy)4e(=Ed]^6_?l.b`}cCN|zВ.(c,QUZ5Xn0" Wp܀Eքyˮs.J6Zy:0ȣ}zkpQ$sǎHʢa(`'Li%UwOK_CC(f3?oD[7,7e~3Ɗ?( endstream endobj 9 0 obj 272 endobj 10 0 obj [ ] endobj 11 0 obj << /CA 1.0 /ca 1.0 >> endobj 12 0 obj << /CA 0 /ca 0 >> endobj 8 0 obj << /Font << /Font2 13 0 R >> /Pattern << >> /XObject << >> /ExtGState << /Alpha0 11 0 R /Alpha1 12 0 R >> /ProcSet [ /PDF /Text /ImageB /ImageC /ImageI ] >> endobj 13 0 obj << /Type /Font /Subtype /Type0 /BaseFont /MUFUZY+ArialMT /Encoding /Identity-H /DescendantFonts [ 14 0 R ] /ToUnicode 15 0 R >> endobj 15 0 obj << /Filter /FlateDecode /Length 18 0 R >> stream x]Pn {LvZ'=XHUH> k70;XZNn XV@Q>(=$n)ޱJ:a9h y?OF('GlhM\x[<.rmF9 %> WHgyaԇ |b_,W\VuMSiNtjaD)xw> endstream endobj 17 0 obj << /Filter /FlateDecode /Length 19 0 R >> stream x} xEK6r'&ְC$$H dQYUT0]FQtĀ΀:8۸ 3TwpAyrj?uTu 0#<Ӯ\ۜ9nK.{p.ҫyj!j"Sj=w /?ke Mx_KLB7KT^3.hn:͝_;7_E{>JRSCID'Lfr&¸5ȠP+CH~#h\i4fz'z!2Qe 7^M O# JNt!ڳZөM1z#C=@ xZqD:5Gݩ})&)dzD{^/5 Vmz))ˎrܠ'7J쎧fBN訠 ^6O\G5b8/>ڇf?1UQ_B7Q>0+::.w:A9Smn#h]?%4G &i[t]Q6\?#f`\G+hvT诉KH)[? X3@@TA=0H$HErhx!A31'@q.q:DKMchm\BQg胕b丕>iXt-ͥt̜wERyQjt-9V;s|">[x:zMK44Gh(avz4;Rm.66"fHzt9h+cRc,jfnF/[W@ .7(P8ӫgݺv)/c9Y 7]ZjJrRbB|\OtȈ05)S̩9C;?SZT}*='Vl3909͜+Ν|%~_bQL]b/xL+-wFJfW,rF}Iu1>?6s'g\Dܝ"qPX$w*L\]2&8jtEIqjFFeNA1xjEԤ6Wm_lH pNtd{o?3CX!l7NfQCssYD\1@չӕhvJe 4`  Ws/:;9y\sE{ږ ?]kƗX+l>3os \J%S5 jffOEdP?FRB4j+32~fFRt2yg?z*l3 jfZO*2|TƁ`]6 f=1rW⇥sR(R~JQ7g3sKmi4ݘ,]S!cRH*F Uc'V`j\ErpuQ,UTPd=T&V{X](FA*m (0&a?ch)=jJVv4J lbwedd%pIIeƧz>`;!襴xYMrL +f;FvGE9caW4~}}ܷ)zO6:*yLڔR-r.V~&:*1qTBu-!-&xԴpHv{<\` m<gGqg4="Ҹ;2vGD(ǿDEj4Ad9_Z9ؕ@ }n`J·+;''=y7!P%O0O+*ttiHwEr!]Ixq.s}Fxγ~& ?};ÆË cN*85@ۯ{71'N?b<#b\ ={9LvN_鸈{6?|ް|ښSoё}ǯ^xn,M6}7Cܹb`"T I MTݡZA{ۑc;mGێLۑa;|pKό6,8k|fmⰛnzNhQa)I:HRzExR*****j{VجY"gE>}NV&WFtX_Uu{uM;=H+繜LYjnnn&&An 6Dwp=ŗGti(2;x G&ONޑ|8M^M9Y&Ncޑ)8f$ <v%Ts&]]NKw\ NvaGmt4\i]")"%+96g>'-˓7KlrKoS&8U[c1e|EOj29=L,z璛jX _|YB'R j/ͧЗ&GG9>UnGGrfN.9:=%%wfys/:gҼoU6;R.wIXIkuK'ϵtprxerŒⅤM9Pd=SiupY$z|XkG_@j N@9ȺbNa#OLxL\T0N7ܰuH߼3vF.mZ;(ӑKmL.ƝV-eҨ{q#IP)x5i ;CVxOT 3 A&]/xBW;1*J(6/ @6e?xrZ1QtMt{icq s@Ӂ po?~t ~ :6 "~6V*f\k))DxGs[_`T"a 1 (O["`xV-e(%|#_w 2Q')Юh 4&ߪ0X(w_3> kQP, Z +t~ ݎIc@.khM WX`Mq8ס5U:;i /6 O<8u'b\ǠxF X`ƥrMxOT@Y&9 G^ٖn9Mi x֢_@<3 {$Ne@M(WS aTp>Dݔ̚mؠӜ3 4BeuiseƦJg+2L1/hAAȖMyޡ<a)_regS5'-hnjjD~K֗f:@Ω)hjTk4}z`,Gw:"f9џG><ԏcAvyrEC!qL-~ic;tvs@{n9Bt|6ExP]٢sI50GPG`XCc. >j񖨣:yVi\m!Gg\,ԖP:ߒ)/,| |9*L&Y S^ =z-!r:;D>#C2ݞjYDZd=z-mcïDk^gZ:~`}ap;wc3?a{QZa4YiG{-5)^G=2K=WtZGǫ9wI;t&k?Qz5|=A;OX%kv'עL NۃbzQHP* k*SsL-/(_/=@5dqù\WRHwb>=NY<_~ ֢-hh;-6uw]LR%ś2Dm;Ѯ wݟ8!v2~> rMn [6 i ;ۯ?|L\m= 2ls$g,5`Q4s!wc4F~7%t|P~.:tM[yfs̍n?OyxxtY p;v'eDK~ <=4ManDK@#: ~Ą!Tdٕcu[5ӟ#_;'_A # Ϙ&%_)P-񠝀@,үc=r>?NϽ64g^C?yװ|řA5{`[}~jcSgSK)ؔlG--oʎEDq6eۙW~ݬ >W֍U|MjN7ADCm&Xہ~cin=KǞgMOo&mp!#t-8o?F\~{6je>;C_Kl(Ί=۞If̻_ [菟:fG%-=ZC@_7Xvw?F?`l:ZqZ>6Nk=+B9Tn>W!L[;=$~Kb}>F?؀祽hGC9c0ǃC>}gr^x4zr}PgzMTQa tِ%Fu>W avlq;*ΐd>م<9]bP7SVݵ}+6@5T^7euSWusYfJP@կ.ܥXKRP9yl@ֹ ky=gA+Cb~9cm=A{ mp?Su!# s8ثE̳G}φ -os2߮`C*ݥw3Xtۑ Z~Gz9+s5c3Η/oַd} Sg &Թu}?KݢH}!έ H-^T @^#Ա9_@ץaa\i}iC5 Qj_Rg7by>M'^Xr MdX +-w;Ӎ~Gc=3>N;PvF uA9/H3B!̱318H˴k(4;VxJ(δ(/:G=~c9@x??DB_PP <'1"Z'cQ?[gB7tg7F<+A`_m>i= v oi4Vle?C T٬{VVYͺ7~)lJ< C ti4=nx`ՋVpN^_QM:εͤtҹX*}!mU΀+|gZk>֏Cdr*.}2wzmm5 ԷJM,ổO {7Ǟm;]]fZ世q_F'P#499~MC2 sD..mFia+a׽Jg}첛ݻ(+JTQ_a:q$IұG'qRWl*,69E;SwVwOKc%{wGqnSgv۬Pbe4S;VGkD]cQ6uF|`[a)}OyORN;ȒeϺ0Mw藶4,źPg..5lѱlKC9oSYb`q}긙[l<4lqV ST+΢ݳ34|C3l?0GoCZPS7 >hY W~>Oر<^lzEs圇'sos3y&w:?jLHX߇|7'|א31 'V3a? H0:/5ac [^o _W&\M('> f;VQ'? X q 70 v? \g|+8o?{KXwlw7GM4ۨ'I`;+)|WI<ժiΒ؛2,ueJ21AW)f?{;1eݱn龬Qٺ'e݂uy7i~g58R|ɸq t ㏎%u6úT#-m:yPAf;vOu/$%Ğ~&%k_ oҦ ^3ް",= j" 2Jb~W;9xrp =BuQbYn:'Vwo {` oTn_C{zd?[oMLݟ6皲s]Ŵ jn~ T;R;ӎ=Tz0)icٲlA$5*(ܗ|^}g cߋw7|w5o*w7wo.^Ye~6OB>0i"0bz!eYg|NQg+-tSy6o`:O9K${)5pì[{=u-TfnӠojXȃC` qDXs"ԱHQ喹N)0m݄mT:4B~ϰb/59S}G'.sHh{0糗,r{}Ҧ 4ۭ4g[nUk ԑ6ﻈzSg䴝oqE辀{zܬt Ns?~,E 8gUOޟ$CNol{9{A4@@hwzT u =2" 5 < x<:K~h#hx^h>3 wllüb=oOn+~ hE+ZъVhE+ZъVhE+ZъVhE+ZъVhE+ZъVhE+ZъV}EtH?{rKr>u:6kxWl|~ΚuUos~@Z:=x/~UI79F(h3ɨcHȋwW`$08*&%6uOlQ].W)jPiMZ|d RdL_4<*-L@-(Z&-ԜVH@ݕqФ&M4D K9E(oHҠx@=]Oʊb~@!0 8~PE&Oҋng}CMY@`_9/ 92nxsmp+5p+皥p++WN,3q2\9.'{-|U襫KW"]^}siEuuO1nu׋@],D]KuQ苮gxD݋1Q@刺lQ%|OQf4\CEv Iz@hh̀g@'0`(_LL99iBߥACH,Yz1@BE&"h 8`Npg7w4]B`288UuXUܡ*ժHgdɐv4OgvsN#Ӎtه(6(3_Aa&y3@bћkmw5</~C:N ڗ(/Js3Iir;h~Cx$n'p=>~(4IF]4x di6TNS{z{Q.ELxK❝"j͈əӦz oa*\Tc*ԟ2,(f:ֹ*\#]]N ΕsǺ=6Hwvut;8T[oS_vKFZ,[$ʂQT_۱F>zb/2*WW2]~US*h-O KB,_ʴ򵕕peaRa~xU[|5/ wາm*0Uo뫪+'J0ث _pm`qeeY'>H? 3ϝn7|YLFي/;,Lv.*)ޙx}@,Hy1<ي'^T> /FontDescriptor 16 0 R /CIDToGIDMap /Identity /DW 556 /W [ 0 [ 750 ] 1 71 0 72 [ 556 ] 73 85 0 86 [ 500 277 ] ] >> endobj 16 0 obj << /Type /FontDescriptor /FontName /MUFUZY+ArialMT /Flags 4 /FontBBox [ -664 -324 2000 1005 ] /Ascent 728 /Descent -210 /ItalicAngle 0 /CapHeight 716 /StemV 80 /FontFile2 17 0 R >> endobj 18 0 obj 252 endobj 19 0 obj 11337 endobj 1 0 obj << /Type /Pages /Kids [ 6 0 R ] /Count 1 >> endobj xref 0 20 0000000002 65535 f 0000013390 00000 n 0000000003 00000 f 0000000000 00000 f 0000000016 00000 n 0000000160 00000 n 0000000207 00000 n 0000000373 00000 n 0000000830 00000 n 0000000719 00000 n 0000000738 00000 n 0000000758 00000 n 0000000796 00000 n 0000001002 00000 n 0000012887 00000 n 0000001146 00000 n 0000013151 00000 n 0000001474 00000 n 0000013348 00000 n 0000013368 00000 n trailer << /Size 20 /Root 4 0 R /Info 5 0 R >> startxref 13449 %%EOF endesive-2.19.1/tests/fixtures/pdf-XRefStream.pdf000066400000000000000000000357431504236674500217330ustar00rootroot00000000000000%PDF-1.5 % 2 0 obj << /Linearized 1 /L 15331 /H [ 687 125 ] /O 6 /E 15056 /N 1 /T 15055 >> endobj 3 0 obj << /Type /XRef /Length 50 /Filter /FlateDecode /DecodeParms << /Columns 4 /Predictor 12 >> /W [ 1 2 1 ] /Index [ 2 15 ] /Info 11 0 R /Root 4 0 R /Size 17 /Prev 15056 /ID [<412bfafd7a4014b83340131c55f808f4><412bfafd7a4014b83340131c55f808f4>] >> stream xcbdg`b`8 $XF@D<@rg`b<R 0 endstream endobj 4 0 obj << /Pages 14 0 R /Type /Catalog >> endobj 5 0 obj << /Filter /FlateDecode /S 36 /Length 48 >> stream xc```e``ZKfb(H-30<`JD002s endstream endobj 6 0 obj << /Contents 7 0 R /MediaBox [ 0 0 612 792 ] /Parent 14 0 R /Resources << /ExtGState << /G3 12 0 R >> /Font << /F4 13 0 R >> /ProcSets [ /PDF /Text /ImageB /ImageC /ImageI ] >> /StructParents 0 /Type /Page >> endobj 7 0 obj << /Filter /FlateDecode /Length 201 >> stream x 0 }k-i APJP'NN"l O)n>js1"HYvgU< z4U[&@ F-(} L%`i2Tu#jsA:`#6ĶPGY}xXrۂRw[" > stream x}{\EreW5EK 4YV)>i*]L+Wvi֓4/eOS{}33gfΜs|CHnTs/@g]W[MY]ZQ_zhܥg{X.*YJ|2VToCgDbYkN3mcyQ)XRaWA؎\iFJL :a9_aUqO_Htύ j~_'B!-ca~ђַ~izMO|d4@Ai0Pڅl~ 1'"FCf2L!`* 8`fρea9~'!N##&#Ժ1 b"/>Ǩꄩ>qP칊ռ3O } [[eZ6xv+=t 7!? nDrb}/u=נ?szZ q̛wGFH"w`9ydzۑ]82^UHg)gcD,߅|EG@ ^FEY7(kn]t-G @zANθFIPt6"1 v3:7 q`dr;BJ`, 9Q2bs=aݮ](A{A\45"\1 󼈇(SfoD ݍXs]ډˋѯ8W31"bQӸ͹䖁({eq`}$XF57Q،2Юg2D( g*m'EtG"AlFF Bs+xŘ)cCu1 OelRk*|E]vz{njcc؃[^Z: #]q|YrX6=֚.R ]^E+--8fsF\0R%ȕzA&p=(CAD_Nq2Ks׹yGai;N44@iӅv9qѾZDsv5=\|O'KQHI&&Iنbf1C; <{'ii`=:n](XZi8#nGbs,y7^;S՘Cs*.#~8z(sd,шx)xS3g w>E=Vx#q>5y8aϢL(Fa3<#" :ٱ($!Da "<-pLm(A3 n=IWpυV)7ynsr9 Iڎ뙇y!աCm8[=)9v?60Ѯ<k%Cv6ºU̓8=Xo:?Nۀsz7ej=K&&XqzyA0b}B+:BI;E}&|DI M D`>Ľz`; FXˬ+ܸxGa<acPfSډ1kYqqUa4_<=p[ktn7OQ_wumӫ'~\= 90*e]0LVL0p 1HAw"&ߏ,@~"b1)H_EPxw'Kqאt(@rKr'a]vefkd%1%rZw-w).v we-ː{-&_r Jc񭖻ϸѸrrZfuˑK咚MÚ7MniuSsmW<_c`t+R$}wDF&XmInIjp;̅r(aH'5|\y]#5oσ͋4ޜ tN*?grvZ,z̝gkN:=Sά>SkOm>uy|*TēO|r'3Ou2dn'ɉN|oN|{xāYNu;Nz"D≄'bFuV*^={\Qz:#CutN;Do]ҿSп)P$yR 43﷬F<7,!-nnCTxzXV>%m< K`tݰY؂Wz4] \a< u8  g 6<` ށCf‡p P ?1|X0 0*0z+a#T8\ӵpatχ;Na,PG֒ %aDML!z(\%:y$Ѓ$HoqNS)|I.KG<~"$?W/rFIi&WI Is (JQ Rԏ4.4i0 ]i7JCiI#4FHEi NciJOHA $&R#5'Eh2]NWh`zQZ,%-I+Uҽ҃i8OIJۥNiOzEzMzK:$t\\R:+}#}'].J?Og LWo6K~ EmaO3l+{mcsya)9`'ٗ;ΰ+5;Ǿac߲;w=~`%#~!_s2]a& =]ބk s8)_/M&I[)D~!҃l! ̧ 2܏Ńr0[̜R4UU&MgKX eK\v7ϖlgl{bٽx"/Gcxyo6uNmd~R')wD- vQb? K>8kаȨqr|!hѳWRrJԴ>}0p om:,7on}OȟX0i-S :mm3,Pl-,-Ϛ]^QYU=ṱ7;ܹpQܵd˖gw>fÏ[c?aOnyg>m/plص{W^=pxy?cG'~'N~yvw4䘳8Ad뛙'=-wJrR=LDCB=&:*2"<,[א`}P?_V$J %0Hvd97/,XaiWQ䖱jxG\$䎒fIҬH[%^ {y}$ 7 *P(/~| A΋(˕ݤHs[VWff;GnI‡A;)R(Cn;Ґ5pKEr)sP`M]MhIbPNk)nf"Ku>ʳ/>?{ MU=(cK03S:a)R F<LaL#980mF JZ ţwpLt zK "o4zmUF1@qLCC@܋؀ 9^SX8$ZRxF$kVy(Z颸BQ EO_:uB{(4ĘQǩ_`0CP'oB!Pp#UkRȮDSƆHqi zB @/(-®.rn_DYz3؀8839SJ} il E~O==xr>AI| \ |/~!k`>$LQe£U&$,~pW\#z1'~ n>?1QFhOqb#bO'0}'0##|m0 w z+mAߣo zi,8v>zziخJ h8|!3"Mh( A^> Of0ϊ3aat#r o0Qi:,iiJtbT>90B?LSg qᣑ>bbqDkJhZR-0Z?pqmHJB7'JO^&un3n1Ln#uɤ.Œ:3{ @SŁRw=OꜤDꌤ.$HFe 'Ȯ8$#uGcX?ϣ(QHNP#c9MؕSeT匤o`7 oiCal AEET^ g"1q\DPRU!KSK $'ƛcҽ1$(,o!>9t5#S W5GL/儒!aԑ`"F) ƇӾC#h݂L)qIkoܕsq4RdǼHCqپ7q}eS#A_b=X.Ɔ q 9wg̈14Ē9(.45n$Sgv{cnH}ƥ bŀI9EV7E7N_KtuѺn>!>z.>>~>>>ZC}[9V Lzʟ{< 748vb}y1 %0`{@F'ߝ<ڭ딝.Z7]Hk$^4_U!KWEssB2$xy䶯|wu/tgpӽpA~݇ϗr4)!䧼|^/ -,H& 9ɏ(ˁȭW9A9__0 9ct&LL2283\n/s؈2F BpXq"11(#DH%D&"+ZEV$&A649캡:l"=s"uŲZ eZlB-m5;o;x ܝ0-`if[n  ]#0׊ֹFdNsoseFG@);}`h!^;E0^ 髇!>ba~oFMsz&S S"lUXl ɮg DsUnpw_ؖmNhwl鰶/=[M2+JIjuy*xkT::.b%.pJSAzޏ%~<8 qNL1ڠ녫FT;T.N9Z*~DDiHfϷ=y;(ܨ`+)E=b gRVLo,`<πi H[rz'M57Xѷz !DSi1߃pkG Em4{-)%Kic#}FQ c4 {h_JdA%y;(K3x9Z9*L/YGR!"Yyc?su0d#oG`#>0hfC2;?Ǚƙ54I6R.HȋZ4H!D~g:>WM~N/>4>vm[5??glBw8e.P:I;&T}'z#so.G 2&*'fBȴKHE%fv^ez9Ba$(0<||XQXut~,:On35]c9s#;FaiԗSsXC8Oԙut.2oVD2Zwz$'_<d_z.B郯LC 'LdkCfwŇef'&CVmkHu{RoxTDxO5t 1g4i;oYM{0%H?q_JK|ﱀz>&}߳Os-SXF)sH>=~,J62Q1qّ"gD< <"/Ibz=1''pt ˩9Kp_BRu/NDŽXL\J4wHom%&1% ˄.8A32hrbPi 01שs|A1V?}ן/8зkq_Ot0~G/o6ktK1C]6!Pߞh鍏nXbC`O/hҳ6EC{4dmxb9tǜ]D#?̌pPh0nCL}}s$@az ?mXOb Oo^ZWO@'6ܺc:n?Ι"O^~l0L!|~~YnDTu%Kv5g !Ժ[V(̭0\⿭@xrhNܦ9򬝌"4?hcU^ojSTL* [Tޏ.f?wIU>^R.0_]޿ Q)BrT^ gd42J(oQytWy_ KTy?j PO] 3lJSC|H ; P&R/x-NH)#W|𬝌#W|^+>RxG H)#W|yvk!v]o%T] |v|kW).|K{;v|_#$?)ނyv+]}w-03V2<(2*DT)aɁ<Z.$d)zpVd-w'֍B'z\HO)q<'sY"t6Tjye3)v=x>b%YxEdUDz`ҳBWPWeb.nu:S*D{SSZ5 b6KUbZ.lZ1v:Mc)s{."V,),1m*vVFX-J_¢?הGG;UjWWkYa&Jє6UV+ QjSDlc»skmb18lU[jiY{JܥV_-vՇ\}H>KmjmelRC6 jϔh=n{kd>OLІǦ7[uu7N볪sjK:Ħ `ײ5+)b[10O)%Qu^JiMN5Z!UE2{V%[W᝛a :C]Wc"*DzM^k<ߕ'}AGڍ5㺭s+[}_JLhS[[RF ELb1sMv:Z*E<=#8?kyYaD|=01O@DwbZnW4V״im͡jD߶gSwPmZv57;Q*F^nBu6E9SteUۚmζS.5oTbvek+QrŪg*ՑC=Ī:ZJFŵ3{s(ϖq媵jwsدl_ zisS"4]?beꝗai{ƕ*hmw?׮B lMyM eF_9m6&FWZW+;m#U_չV oq}xʞw'wkXflc^tmVv۲ OH<K}/";$JςL LIq4ԊO8;x|\؝qv5rEVб=Jb϶sGiBU4|DJg %}"UwZqPdm+x:cm3-V\PfTUVJV娮rX\Jܚ*Z\?JkxSU rNyo/-s9|k+VUUAe;a}\bsK+SR.[QbƊ*M.Tڝ.ZfqX.t٭NUfm\5S,[js:NRY"[pklWWʮJ\kwawVޜ/߂x\J݆VdjSea6r, l5D'Y5*̬)/GVWT$ʒK,_nko '樰W Glւ[kpJYRZk2[y5ZJ.ϵ e\+lhJ-64cՆ(scɶy [|D'1*¼.5n|VQlkŚ95\+< #\.{e)_Æ~w9Sh2GXZnW65E1v/;-wYmFPUtٝ|`.^zcu|[iM1h2Q: C9nuTqRc *8l?|\K) MN(d\0F7sfPVՖXqS0jXypQN̓sF[WPZUZWUTv*/ϯ=qĕ«¶"#tR^a I\mcS lâc,X+0QtU|Y xB'5mq<ͩ94+6GvUՔ`εjwz҆Y--j1_Ez+Tn u &M̑{=%g;ozXާO߾̒o`_U=(-6xkUE=asZn ܂_U;t,*L)|:VEh{É'ր3vZ ߉},+H륝+>i\,b-c:e0Ų>l4n@W:RFdǿ 3>Lendstream endobj 9 0 obj << /Filter /FlateDecode /Length 256 >> stream x]j0EY ? c( /n?@Ʈ,/u .k{kt@߬:gX( MŗOnN4kOB@hycqB #M_陙6!Ј[}֣gA(S7\ hԙ? wJDb6Kβ"k*/QUNQXic 9A[:}>XG3i}F@;rendstream endobj 10 0 obj << /Type /ObjStm /Length 456 /Filter /FlateDecode /N 6 /First 38 >> stream x}RMo0 Wb}Xl(4 &[Cy˰`#6kwK(! )h B0xhR mSz~y˶x{6J B{o k+F;pxm*֕k=9;l;#|m=:(6ޅ`}EWKnx׉4Rm{I.9;L B )[.܋ET,S0KJ 7<eX OM"x椇WqK/<أ{:Ɨnư]toPX+}.?[/w(K_l>j? yݔu; 돕z߉SO$=d !3-iL4GGHeJ@ߧȏ?/endstream endobj 1 0 obj << /Type /XRef /Length 16 /Filter /FlateDecode /DecodeParms << /Columns 4 /Predictor 12 >> /W [ 1 2 1 ] /Size 2 /ID [<412bfafd7a4014b83340131c55f808f4><412bfafd7a4014b83340131c55f808f4>] >> stream xcb&F z endstream endobj startxref 216 %%EOF endesive-2.19.1/tests/fixtures/pdf-encrypted.pdf000066400000000000000000000026541504236674500217030ustar00rootroot00000000000000%PDF-1.3 1 0 obj << /Type /Pages /Count 2 /Kids [ 3 0 R 4 0 R ] >> endobj 2 0 obj << /Producer <6c227ea805ff> >> endobj 3 0 obj << /Type /Page /Parent 1 0 R /Resources 7 0 R /Contents 9 0 R /MediaBox [ 0 0 595.28 841.89 ] >> endobj 4 0 obj << /Type /Page /Parent 1 0 R /Resources 7 0 R /Contents 10 0 R /MediaBox [ 0 0 595.28 841.89 ] >> endobj 5 0 obj << /Filter /Standard /V 2 /Length 128 /R 3 /O /U <182110943eaf92ec71ef6b30a1307c4100000000000000000000000000000000> /P -1 >> endobj 6 0 obj << /Type /Catalog /Pages 1 0 R >> endobj 7 0 obj << /ProcSet [ /PDF /Text /ImageB /ImageC /ImageI ] /Font << /F1 8 0 R >> /XObject << >> >> endobj 8 0 obj << /Type /Font /BaseFont /Helvetica /Subtype /Type1 /Encoding /WinAnsiEncoding >> endobj 9 0 obj << /Length 78 >> stream (FIf2wJAP"D"K^N>8^!_jAY. 6HKk_-e\df` endstream endobj 10 0 obj << /Length 78 >> stream q&P8+~ExLy2jXEYIsإipPuۯ FѬy QwZ }MS endstream endobj xref 0 11 0000000000 65535 f 0000000009 00000 n 0000000074 00000 n 0000000120 00000 n 0000000232 00000 n 0000000345 00000 n 0000000552 00000 n 0000000601 00000 n 0000000707 00000 n 0000000804 00000 n 0000000932 00000 n trailer << /Size 11 /Root 6 0 R /Info 2 0 R /ID [ <464953470626f4fc013dab63e89c34dc> <1b1f3a7f23222b41936b89fbfa4cfcdd> ] /Encrypt 5 0 R >> startxref 1061 %%EOF endesive-2.19.1/tests/fixtures/pdf-true.pdf000066400000000000000000000145311504236674500206620ustar00rootroot00000000000000%PDF-1.4 %äüöß 2 0 obj <> stream x33T(*T0P0L-M,L ,Rµ r@Xej277*IQw3T04RI10310310510v!^\!\\ B endstream endobj 3 0 obj 106 endobj 5 0 obj <> stream xX}P[Wv?>IH|I€y6HclbHBlė#pHI&$q8^9^rҸ7ݦag[d&i$N٦'57m2Mlzk3;{{# kd"* oţ񱉍_YF ]4Px5lGACY1e=D/ 2%b#sA~/iya24yih;d* ek>?8E/2l"aހQʆ! ?Ygp ;?+a\~ O*1h(lA|m_ 좿Fyj7,B8kP忁n?qUa<Mp6ȋ\6_/5}C9Y>^x ?16W\@_oOws]mVjyWÎnvث*7n(-BAfi*ޠ %UU1^ t ( (򮴑l&tkْh< Y2@[-ӪrCbAS2$CAJ KmX*ۤ|-E4-R )DYpBK?1kA[nX H\}Ӝ'~\2ڤ -U<\yDPۻ I$ #.\]) )0ҋMMӡ`3+ z.I>/dXowk_@V0B ~E6ؿd&5`!XS-Ĭ ##Mw2MK44sK>^,E@ZRY¢k|"$M~mh?7YtQw˶f ˂^;`0Af?L & Pn,Ea8T>S% TUJ>[f{ˍ+gځ nQ-oRؼ,-O' (nRaKrx,Iݙx3[E'l~73.n*Q4 ErH?k4P<%hۻ۔D2 z j5qhh@EBlne׀U15!U[c P5k3Y-QUIQ-(Cˊ[RqV%@EYjYz^_$?#WY)\sezWp T/1fR/;mKj!{ \T3ok$~vEo1h6xJ[7Vpg8.d 53G 8$pLf Yݗ ;bpSm/W9/a\U/$ϭ"9NŦrՕ%%ϗ>sN*s+Ź-|lvdYx1)ժAe,R4.;cpfhnð )*,Κ(i햭ΚRȲN11Xܼs=? W{7lɓF|Xvl.6[Mo*s}ơ?&g{xhJw*9~*U=QD*~8]R;V'װckXZr}VgBPGK-κu\wmNUUM~˖rw9-/ ~wΏr8!䨱*6<Ě 7|t6Wl 0lu.%Κ[-;dūp vPC!Ǿ=67F6w{'q?شfշ'DAWTavrߙX]wwT {X fU&wn}* 9o"s&h4V_,Y8㴜*ׯs}} X78jch)fp0zЦ^_^kk VH4bYO=G6~}j8Ԝi.ggԸSXG\}R6`mACAGzIE .f5eP*`ٹ2B-x{Tr@&_MVkeȇ{pm7nЉ2zj62]Ajwk+.*WeYS_sX(;?L^xj虣SO>r\_#B '>vfb͹7 >s?x }^"B,MܽlDxCЫV Is렗C JA+\⩁ 6*GSw8&]K.c *4;a\90 B'Z Bk@BgpIPHZdB`Sc'Ky#bt!7G(4|F9ʹZ6S ܳ RBgq)6ThU]Uئ*t.ܣ^σg:<JDSƑ N莄_(U)M؅ )$"Hb* m͞޶=B4ȩD(%b+;#P*z"hwdP)9 GBpŝH"ɘ:[;#~,LE(N }")!4z;GG#Y8IBhKcLD/%ǔR;JET*x!xm# ǷRp$ĕS:0$&~P^5ol7@ƦRHF"O"h${##){,1x z_ԑN9n0% -3x1Fƿ:!a}BJ`HBR"8Gp}ez5њN؃Ҩlo Ch pb0;ih?YE_91C؄FP2)GIe׷c|~L%51/V7;+w!~~LFI˨݇=_dH&eޯ؉GџU刌B>Cz\XAX[Z[#uX& cwTe7%-SrO1ݸa;ux`vY~_s_拝\/早 Y?k>8v3n0?{Yk3z!G<$>v7KS40&mMfYҗ4ܢy[7z.06VW9 Ԙ k:wei.λB5kV}Vsr'Z5íEx{/y9uyK-޵>S_Q} }#zN@̒3=6[lbwqîIs\}B~ɓм] HuR #0)d2eclH+h(mI $I&!$6I@L|z%]&[1*,x endstream endobj 6 0 obj 4395 endobj 7 0 obj <> endobj 8 0 obj <> stream x]j0 E -yLM0 S胦VRCcYk+9BJKYkp:֠eeڨxW'o-ΎmK% gc%h NpWpF`B1yYutjOyrKA Y[U0_è>eH2)9}&~3v&MC\W46%ogIj !%[QX=w>}Hv endstream endobj 9 0 obj <> endobj 10 0 obj <> endobj 11 0 obj <> endobj 1 0 obj <>/Contents 2 0 R>> endobj 4 0 obj <> endobj 12 0 obj <> endobj 13 0 obj < /Producer /CreationDate(D:20180714015843+03'00')>> endobj xref 0 14 0000000000 65535 f 0000005492 00000 n 0000000019 00000 n 0000000196 00000 n 0000005635 00000 n 0000000216 00000 n 0000004695 00000 n 0000004716 00000 n 0000004911 00000 n 0000005226 00000 n 0000005405 00000 n 0000005437 00000 n 0000005734 00000 n 0000005831 00000 n trailer < ] /DocChecksum /480D3AA5308AEFDD0CF596B4C6BF8839 >> startxref 6006 %%EOF endesive-2.19.1/tests/fixtures/pdf.pdf000066400000000000000000000023411504236674500177010ustar00rootroot00000000000000%PDF-1.3 3 0 obj <> endobj 4 0 obj <> stream x3R235W(r Qw3T0430PISp  )[虘)(hx(($i*d endstream endobj 5 0 obj <> endobj 6 0 obj <> stream x3R235W(r Qw3T0430PISp  )[虘)(hx(($i*d endstream endobj 1 0 obj <> endobj 7 0 obj <> endobj 2 0 obj << /ProcSet [/PDF /Text /ImageB /ImageC /ImageI] /Font << /F1 7 0 R >> /XObject << >> >> endobj 8 0 obj << /Producer (PyFPDF 1.7.2 http://pyfpdf.googlecode.com/) /CreationDate (D:20190328061943) >> endobj 9 0 obj << /Type /Catalog /Pages 1 0 R /OpenAction [3 0 R /FitH null] /PageLayout /OneColumn >> endobj xref 0 10 0000000000 65535 f 0000000467 00000 n 0000000656 00000 n 0000000009 00000 n 0000000087 00000 n 0000000238 00000 n 0000000316 00000 n 0000000560 00000 n 0000000760 00000 n 0000000869 00000 n trailer << /Size 10 /Root 9 0 R /Info 8 0 R >> startxref 972 %%EOF endesive-2.19.1/tests/fixtures/plain-unsigned.txt000066400000000000000000000002321504236674500221100ustar00rootroot00000000000000Witam, Fantastycznie, że zechciałeś popatrzeć na tę bibliotekę. Mam nadzieję, że będzie dla Ciebie użyteczna. Pozdrawiam, Grzegorz Makarewicz endesive-2.19.1/tests/fixtures/smime-unsigned.txt000066400000000000000000000002321504236674500221170ustar00rootroot00000000000000Witam, Fantastycznie, że zechciałeś popatrzeć na tę bibliotekę. Mam nadzieję, że będzie dla Ciebie użyteczna. Pozdrawiam, Grzegorz Makarewicz endesive-2.19.1/tests/test_cert.py000066400000000000000000000512011504236674500171310ustar00rootroot00000000000000#!/usr/bin/env vpython3 # *-* coding: utf-8 *-* import unittest import typing import datetime import os, os.path import sys import glob import uuid from cryptography import x509 from cryptography.hazmat.backends import default_backend from cryptography.hazmat.primitives import serialization, hashes from cryptography.hazmat.primitives.asymmetric import rsa, ec from cryptography.hazmat.primitives.serialization import pkcs12 from cryptography.x509.oid import NameOID tests_root = os.path.dirname(__file__) fixtures_dir = os.path.join(tests_root, 'fixtures') def fixture(fname): return os.path.join(fixtures_dir, fname) ( ca_root_cert, ca_root_key, ca_sub_cert, ca_sub_key, cert1_csr, cert1_cert, cert1_key, cert1_pub, cert1_p12, cert2_csr, cert2_cert, cert2_key, cert2_pub, cert2_p12, cert3_csr, cert3_cert, cert3_key, cert3_pub, cert3_p12, ) = ( fixture("demo2_ca.root.crt.pem"), fixture("demo2_ca.root.key.pem"), fixture("demo2_ca.sub.crt.pem"), fixture("demo2_ca.sub.key.pem"), fixture("demo2_user1.csr.pem"), fixture("demo2_user1.crt.pem"), fixture("demo2_user1.key.pem"), fixture("demo2_user1.pub.pem"), fixture("demo2_user1.p12"), fixture("demo2_user2.csr.pem"), fixture("demo2_user2.crt.pem"), fixture("demo2_user2.key.pem"), fixture("demo2_user2.pub.pem"), fixture("demo2_user2.p12"), fixture("demo2_user3.csr.pem"), fixture("demo2_user3.crt.pem"), fixture("demo2_user3.key.pem"), fixture("demo2_user3.pub.pem"), fixture("demo2_user3.p12"), ) class CA(object): def __init__(self): self.CreateCA() def key_create_rsa(self) -> rsa.RSAPrivateKey: return rsa.generate_private_key( public_exponent=65537, key_size=2048, backend=default_backend() ) def key_create_ec(self) -> ec.EllipticCurvePrivateKey: return ec.generate_private_key( ec.SECP256R1(), default_backend() ) def key_create(self) -> rsa.RSAPrivateKey: return rsa.generate_private_key( public_exponent=65537, key_size=2048, backend=default_backend() ) def key_save(self, fname: str, key: rsa.RSAPrivateKey, password: str) -> None: # Write our key to disk for safe keeping with open(os.path.join("ca", fname), "wb") as f: if not password: f.write( key.public_key().public_bytes( encoding=serialization.Encoding.PEM, format=serialization.PublicFormat.SubjectPublicKeyInfo, ) ) else: f.write( key.private_bytes( encoding=serialization.Encoding.PEM, format=serialization.PrivateFormat.TraditionalOpenSSL, encryption_algorithm=serialization.BestAvailableEncryption( password.encode("utf-8") ), ) ) def key_load(self, fname: str, password: str) -> rsa.RSAPrivateKey: with open(os.path.join("ca", fname), "rb") as f: private_key = serialization.load_pem_private_key( f.read(), password.encode("utf-8"), default_backend() ) return private_key def cert_save(self, fname: str, data: x509.Certificate) -> None: with open(os.path.join("ca", fname), "wb") as f: f.write(data.public_bytes(serialization.Encoding.PEM)) with open(os.path.join("ca", fname) + ".cer", "wb") as f: f.write(data.public_bytes(serialization.Encoding.DER)) def cert_load(self, fname: str) -> x509.Certificate: with open(os.path.join("ca", fname), "rb") as f: return x509.load_pem_x509_certificate(f.read(), default_backend()) def csr_save(self, fname: str, csr: x509.CertificateSigningRequest) -> None: with open(fname, "wb") as f: f.write(csr.public_bytes(serialization.Encoding.PEM)) def csr_load(self, fname: str) -> x509.CertificateSigningRequest: with open(os.path.join("ca", fname), "rb") as f: return x509.load_pem_x509_csr(data=f.read(), backend=default_backend()) def csr_create( self, email: str, key: rsa.RSAPrivateKey, country: typing.Union[str, None] = None, state: typing.Union[str, None] = None, locality: typing.Union[str, None] = None, organization: typing.Union[str, None] = None, commonname: typing.Union[str, None] = None, ) -> x509.CertificateSigningRequest: names = [] for t, v in ( (NameOID.COUNTRY_NAME, country), (NameOID.STATE_OR_PROVINCE_NAME, state), (NameOID.LOCALITY_NAME, locality), (NameOID.ORGANIZATION_NAME, organization), (NameOID.COMMON_NAME, commonname), ): if v: names.append(x509.NameAttribute(t, v)) names.append(x509.NameAttribute(NameOID.EMAIL_ADDRESS, email)) return ( x509.CertificateSigningRequestBuilder() .subject_name(x509.Name(names)) .sign( # Sign the CSR with our private key. key, hashes.SHA256(), default_backend(), ) ) def csr_sign(self, fname: str) -> x509.Certificate: csr = self.csr_load(fname) emails = csr.subject.get_attributes_for_oid(NameOID.EMAIL_ADDRESS) names = [ x509.RFC822Name(emails[0].value), #x509.OtherName( # x509.ObjectIdentifier('1.3.6.1.4.1.311.20.2.3'), # #'john.doe@domain.tld'.encode("utf-8") # UTF8String('john.doe@domain.tld').dump() #), #x509.DNSName('trisoft.com.pl'), ] return ( x509.CertificateBuilder() .subject_name(csr.subject) .issuer_name(self.ca_sub_cert.subject) .public_key(csr.public_key()) .serial_number(uuid.uuid4().int) # pylint: disable=no-member .not_valid_before(datetime.datetime.utcnow()) .not_valid_after(datetime.datetime.utcnow() + datetime.timedelta(days=365)) .add_extension( x509.BasicConstraints(ca=False, path_length=None), critical=True ).add_extension( x509.AuthorityKeyIdentifier.from_issuer_public_key( self.ca_sub_pk.public_key() ), critical=False, ).add_extension( x509.CRLDistributionPoints( [ x509.DistributionPoint( full_name=[ x509.UniformResourceIdentifier( "http://ca.trisoft.com.pl/crl" ) ], relative_name=None, reasons=None, crl_issuer=None, ) ] ), critical=False, ).add_extension( x509.AuthorityInformationAccess( [ x509.AccessDescription( x509.OID_CA_ISSUERS, x509.UniformResourceIdentifier( "http://ca.trisoft.com.pl/cacert" ), ), x509.AccessDescription( x509.OID_OCSP, x509.UniformResourceIdentifier( "http://ca.trisoft.com.pl/ocsp" ), ), ] ), critical=False, ).add_extension( x509.SubjectAlternativeName(names), critical=False, ).add_extension( # certificate_policies x509.ExtendedKeyUsage([ x509.OID_CLIENT_AUTH, # 1.3.6.1.5.5.7.3.2 #x509.OID_SERVER_AUTH, x509.OID_EMAIL_PROTECTION, x509.ObjectIdentifier("1.3.6.1.4.1.311.10.3.12"), # document signing x509.ObjectIdentifier("1.3.6.1.5.5.7.3.36"), # document signing #x509.ObjectIdentifier("1.3.6.1.5.5.7.3.21"), # ssh client #x509.ObjectIdentifier("1.3.6.1.5.5.7.3.22"), # ssh server #1.2.840.113583.1.1.7.1.0 .. 11 # https://www.adobe.com/devnet-docs/acrobatetk/tools/DigSigDC/oids.html ]), critical=False, ).add_extension( x509.SubjectKeyIdentifier.from_public_key(csr.public_key()), critical=False, ).add_extension( x509.KeyUsage( # Digital Signature: Indicates that the key can be used for digital signatures to verify the authenticity and integrity of data. digital_signature=True, # Non-Repudiation: Used in conjunction with digital signatures to provide an additional layer of protection against denial of signature. content_commitment=True, # nonRepudiation # Key Encipherment: Specifies that the key can be used for encrypting other keys, typically for key transport. key_encipherment=True, # Data Encipherment: Indicates that the key can be used for data encryption and decryption. data_encipherment=True, # Key Agreement: Used when the key is involved in key exchange agreements, such as Diffie-Hellman. key_agreement=True, # Encipher Only: Specifies that the key can only be used for encryption, not decryption. encipher_only=False, # Decipher Only: Specifies that the key can only be used for decryption, not encryption. decipher_only=False, # ca # Certificate Signing: Specifies that the key can be used to sign other certificates, typically used by Certificate Authorities. key_cert_sign=False, # CRL Signing: Indicates that the key can be used to sign Certificate Revocation Lists (CRLs). crl_sign=False, ), critical=True, ).sign( private_key=self.ca_sub_pk, algorithm=hashes.SHA256(), backend=default_backend(), ) ) def pk12_save( self, name: bytes, cert: x509.Certificate, key: rsa.RSAPrivateKey, fname: str, password: str, ) -> None: data = pkcs12.serialize_key_and_certificates( name=name, key=key, cert=cert, cas=[self.ca_sub_cert], encryption_algorithm=serialization.BestAvailableEncryption( password.encode("utf8") ), ) with open(os.path.join("ca", fname), "wb") as f: f.write(data) def pk12_load(self, fname: str, password: str) -> pkcs12.PKCS12KeyAndCertificates: with open(os.path.join("ca", fname), "rb") as fp: return pkcs12.load_key_and_certificates( fp.read(), password.encode("utf-8"), default_backend() ) def ca_createroot(self, key: rsa.RSAPrivateKey) -> x509.Certificate: subject = issuer = x509.Name( [ x509.NameAttribute(NameOID.COMMON_NAME, "AA TriSoft Root CA"), ] ) return ( x509.CertificateBuilder() .subject_name(subject) .issuer_name(issuer) .public_key(key.public_key()) .serial_number(x509.random_serial_number()) .not_valid_before(datetime.datetime.utcnow()) .not_valid_after( # Our certificate will be valid for 40 years datetime.datetime.utcnow() + datetime.timedelta(days=40 * 365) ).add_extension( x509.BasicConstraints( ca=True, path_length=None, # pathlen: is equal to the number of CAs/ICAs it can sign ), critical=True, ).add_extension( x509.AuthorityKeyIdentifier.from_issuer_public_key(key.public_key()), critical=False, ).add_extension( x509.SubjectKeyIdentifier.from_public_key(key.public_key()), critical=False, ).add_extension( x509.KeyUsage( digital_signature=True, content_commitment=False, # nonRepudiation key_encipherment=False, data_encipherment=False, key_agreement=False, encipher_only=False, decipher_only=False, # ca key_cert_sign=True, crl_sign=True, ), critical=True, ).sign( # Sign our certificate with our private key key, hashes.SHA256(), default_backend(), ) ) def ca_createsub(self, key: rsa.RSAPrivateKey, rootcert: x509.Certificate, rootkey: rsa.RSAPrivateKey) -> x509.Certificate: subject = x509.Name( [ x509.NameAttribute(NameOID.COMMON_NAME, "AA TriSoft Intermediate CA"), ] ) return ( x509.CertificateBuilder() .subject_name(subject) .issuer_name(rootcert.subject) .public_key(key.public_key()) .serial_number(x509.random_serial_number()) .not_valid_before(datetime.datetime.utcnow()) .not_valid_after( # Our certificate will be valid for 10 years datetime.datetime.utcnow() + datetime.timedelta(days=10 * 365) ).add_extension( x509.BasicConstraints( ca=True, path_length=0, # pathlen: is equal to the number of CAs/ICAs it can sign ), critical=True, ).add_extension( x509.CRLDistributionPoints( [ x509.DistributionPoint( full_name=[ x509.UniformResourceIdentifier( "http://ca.trisoft.com.pl/crl" ) ], relative_name=None, reasons=None, crl_issuer=None, ) ] ), critical=False, ).add_extension( x509.AuthorityInformationAccess( [ x509.AccessDescription( x509.OID_CA_ISSUERS, x509.UniformResourceIdentifier( "http://ca.trisoft.com.pl/cacert" ), ), x509.AccessDescription( x509.OID_OCSP, x509.UniformResourceIdentifier( "http://ca.trisoft.com.pl/ocsp" ), ), ] ), critical=False, ).add_extension( x509.AuthorityKeyIdentifier.from_issuer_subject_key_identifier( rootcert.extensions.get_extension_for_class(x509.SubjectKeyIdentifier).value ), critical=False, ).add_extension( x509.SubjectKeyIdentifier.from_public_key(key.public_key()), critical=False, ).add_extension( x509.KeyUsage( digital_signature=True, content_commitment=False, # nonRepudiation key_encipherment=False, data_encipherment=False, key_agreement=False, encipher_only=False, decipher_only=False, # ca key_cert_sign=True, crl_sign=True, ), critical=True, ).sign( # Sign our certificate with our private key rootkey, hashes.SHA256(), default_backend(), ) ) def CreateCA(self) -> None: create = not ( os.path.exists(os.path.join("ca", ca_sub_cert)) and os.path.exists(os.path.join("ca", ca_sub_key)) ) if create: for fqname in glob.glob("ca/*"): os.unlink(fqname) ca_root_pk = self.key_create() ca_root_cr = self.ca_createroot(ca_root_pk) self.key_save(ca_root_key, ca_root_pk, "1234") self.cert_save(ca_root_cert, ca_root_cr) ca_sub_pk = self.key_create() ca_sub_cr = self.ca_createsub(ca_sub_pk, ca_root_cr, ca_root_pk) self.key_save(ca_sub_key, ca_sub_pk, "1234") self.cert_save(ca_sub_cert, ca_sub_cr) with open(ca_sub_cert, 'rb') as fp: data = fp.read() with open(ca_root_cert, 'rb') as fp: data += fp.read() with open(fixture('root.pem'), 'wb') as fp: fp.write(data) else: ca_root_pk = self.key_load(ca_root_key, "1234") ca_root_cr = self.cert_load(ca_root_cert) ca_sub_pk = self.key_load(ca_sub_key, "1234") ca_sub_cr = self.cert_load(ca_sub_cert) self.ca_root_cert = ca_root_cr self.ca_root_pk = ca_root_pk self.ca_sub_cert = ca_sub_cr self.ca_sub_pk = ca_sub_pk def USER(self, no, cert, cert_key, cert_pub, cert_p12) -> None: create = not ( os.path.exists(os.path.join("ca", cert)) and os.path.exists(os.path.join("ca", cert_key)) and os.path.exists(os.path.join("ca", cert_pub)) and os.path.exists(os.path.join("ca", cert_p12)) ) if create: client_pk = self.key_create() client_csr = self.csr_create( "demo%d@trisoft.com.pl" % no, client_pk, commonname='trisoft.com.pl', ) client_cert = self.csr_sign(client_csr) self.cert_save(cert, client_cert) self.key_save(cert_key, client_pk, "1234") self.key_save(cert_pub, client_pk, None) self.pk12_save( "USER cert".encode("utf-8"), client_cert, client_pk, cert_p12, "1234" ) # os.chmod(pkcs12 % user, stat.S_IRUSR | stat.S_IWUSR) # 0o600 perms def USERs(self): self.USER(1, cert1, cert1_key, cert1_pub, cert1_p12) self.USER(2, cert2, cert2_key, cert2_pub, cert2_p12) self.USER(3, cert3, cert3_key, cert3_pub, cert3_p12) def USER(self, no, cert, cert_key, cert_pub, cert_p12) -> None: if no == 1: client_pk = self.key_create_rsa() fname = cert1_csr elif no == 2: client_pk = self.key_create_rsa() fname = cert2_csr else: client_pk = self.key_create_ec() fname = cert3_csr client_csr = self.csr_create("demo%d@trisoft.com.pl" % no, client_pk, commonname="USER %s"%no) self.csr_save(fname, client_csr) client_cert = self.csr_sign(fname) self.cert_save(cert, client_cert) self.key_save(cert_key, client_pk, "1234") self.key_save(cert_pub, client_pk, None) self.pk12_save( "USER cert".encode("utf-8"), client_cert, client_pk, cert_p12, "1234" ) def createUSERS(self): self.USER(1, cert1_cert, cert1_key, cert1_pub, cert1_p12) self.USER(2, cert2_cert, cert2_key, cert2_pub, cert2_p12) self.USER(3, cert3_cert, cert3_key, cert3_pub, cert3_p12) class CATests(unittest.TestCase): def test_create_ca(self): cls = CA() def test_create_user(self): cls = CA() cls.createUSERS() if __name__ == '__main__': cls = CATests() for n in dir(cls): if n.split('_')[0] == 'test': print(n) try: getattr(cls, n)() except Exception as exc: pass endesive-2.19.1/tests/test_email.py000066400000000000000000000247131504236674500172730ustar00rootroot00000000000000#!/usr/bin/env vpython3 # coding: utf-8 import unittest import os import sys import io from subprocess import PIPE, Popen from datetime import datetime from cryptography import x509 from cryptography.hazmat import backends from cryptography.hazmat.primitives.serialization import pkcs12, load_pem_private_key from endesive import email import hashlib from asn1crypto import cms, algos, core, pem import test_cert tests_root = os.path.dirname(__file__) fixtures_dir = os.path.join(tests_root, 'fixtures') def fixture(fname): return os.path.join(fixtures_dir, fname) class EMAILTests(unittest.TestCase): def test_email_signed_attr(self): p12 = test_cert.CA().pk12_load(test_cert.cert1_p12, '1234') with open(fixture('smime-unsigned.txt'), 'rb') as fh: datau = fh.read() datas = email.sign(datau, p12[0], p12[1], p12[2], 'sha256', attrs=True ) fname = fixture('smime-signed-attr.txt') with open(fname, 'wb') as fh: fh.write(datas) with io.open(fname, 'rt', encoding='utf-8') as fp: datas = fp.read() with open(test_cert.ca_sub_cert, 'rb') as fp: cert = fp.read() (hashok, signatureok, certok) = email.verify(datas, [cert,]) assert hashok and signatureok and certok cmd = [ 'openssl', 'smime', '-verify', '-CAfile', fixture('root.pem'), '-in', fname, '-inform', 'SMIME', ] process = Popen(cmd, stdout=PIPE, stderr=PIPE) stdout, stderr = process.communicate() assert stderr == b'Verification successful\n' assert datau.replace(b'\n', b'\r\n') == stdout def test_email_signed_attr_pss(self): p12 = test_cert.CA().pk12_load(test_cert.cert1_p12, '1234') with open(fixture('smime-unsigned.txt'), 'rb') as fh: datau = fh.read() datas = email.sign(datau, p12[0], p12[1], p12[2], 'sha512', attrs=True, pss=True ) fname = fixture('smime-signed-attr-pss.txt') with open(fname, 'wb') as fh: fh.write(datas) with io.open(fname, 'rt', encoding='utf-8') as fp: datas = fp.read() with open(test_cert.ca_sub_cert, 'rb') as fp: cert = fp.read() (hashok, signatureok, certok) = email.verify(datas, [cert,]) assert hashok and signatureok and certok cmd = [ 'openssl', 'cms', '-verify', '-signer', test_cert.cert1_cert, '-keyopt', 'rsa_padding_mode:pss', '-md', 'sha512', '-CAfile', fixture('root.pem'), '-in', fname ] process = Popen(cmd, stdout=PIPE, stderr=PIPE) stdout, stderr = process.communicate() # OpenSSL <= 1.1.1 outputs 'Verification successful' # OpenSSL >= 3.0.0 outputs 'CMS Verification successful' assert stderr == b'Verification successful\n' or stderr == b'CMS Verification successful\n' assert datau.replace(b'\n', b'\r\n') == stdout def test_email_signed_attr_custom(self): p12 = test_cert.CA().pk12_load(test_cert.cert1_p12, '1234') with open(fixture('smime-unsigned.txt'), 'rb') as fh: datau = fh.read() datau1 = datau.replace(b'\n', b'\r\n') hashalgo = 'sha256' signed_value = getattr(hashlib, hashalgo)(datau1).digest() attrs = [ cms.CMSAttribute({ 'type': cms.CMSAttributeType('content_type'), 'values': ('data',), }), cms.CMSAttribute({ 'type': cms.CMSAttributeType('message_digest'), 'values': (signed_value,), }), ] datas = email.sign(datau, p12[0], p12[1], p12[2], 'sha256', attrs=attrs ) fname = fixture('smime-signed-attr-custom.txt') with open(fname, 'wb') as fh: fh.write(datas) cmd = [ 'openssl', 'smime', '-verify', '-CAfile', fixture('root.pem'), '-in', fname, '-inform', 'SMIME', ] process = Popen(cmd, stdout=PIPE, stderr=PIPE) stdout, stderr = process.communicate() assert stderr == b'Verification successful\n' assert datau.replace(b'\n', b'\r\n') == stdout def test_email_signed_noattr(self): p12 = test_cert.CA().pk12_load(test_cert.cert1_p12, '1234') with open(fixture('smime-unsigned.txt'), 'rb') as fh: datau = fh.read() datas = email.sign(datau, p12[0], p12[1], p12[2], 'sha256', attrs=False ) fname = fixture('smime-signed-noattr.txt') with open(fname, 'wb') as fh: fh.write(datas) cmd = [ 'openssl', 'smime', '-verify', '-CAfile', fixture('root.pem'), '-in', fname, '-inform', 'SMIME', ] process = Popen(cmd, stdout=PIPE, stderr=PIPE) stdout, stderr = process.communicate() assert stderr == b'Verification successful\n' assert datau.replace(b'\n', b'\r\n') == stdout def test_email_crypt(self): certs = ( test_cert.CA().cert_load(test_cert.cert1_cert), ) with open(fixture('smime-unsigned.txt'), 'rb') as fh: datau = fh.read() datae = email.encrypt(datau, certs, 'aes256_ofb') fname = fixture('smime-encrypted.txt') with open(fname, 'wt') as fh: fh.write(datae) key = test_cert.CA().key_load(test_cert.cert1_key, '1234') with io.open(fname, 'rt', encoding='utf-8') as fh: datae = fh.read() datad = email.decrypt(datae, key) assert datau == datad def _test_email_ssl_decrypt(self, algo, mode, oaep): certs = ( test_cert.CA().cert_load(test_cert.cert1_cert), ) with open(fixture('smime-unsigned.txt'), 'rb') as fh: datau = fh.read() datae = email.encrypt(datau, certs, algo+'_'+mode, oaep) fname = fixture('smime-encrypted-{}-{}-{}.txt'.format(algo, mode, oaep)) with open(fname, 'wt') as fh: fh.write(datae) if 0: key = test_cert.CA().key_load(test_cert.cert1_key, '1234') datau = email.decrypt(datae, key) if not oaep: cmd = [ 'openssl', 'smime', '-decrypt', '-recip', test_cert.cert1_cert, '-inkey', test_cert.cert1_key, '-passin', 'pass:1234', '-in', fname, ] else: cmd = [ 'openssl', 'cms', '-decrypt', '-recip', test_cert.cert1_cert, '-inkey', test_cert.cert1_key, '-passin', 'pass:1234', '-in', fname, ] process = Popen(cmd, stdout=PIPE, stderr=PIPE) stdout, stderr = process.communicate() assert stderr == b'' if stdout != datau: lastbyte = stdout[-1] stdout = stdout[:len(stdout)-lastbyte] assert stdout == datau def test_email_ssl_decrypt_aes128_cbc_False(self): self._test_email_ssl_decrypt('aes128', 'cbc', False) def test_email_ssl_decrypt_aes192_cbc_False(self): self._test_email_ssl_decrypt('aes192', 'cbc', False) def test_email_ssl_decrypt_aes256_cbc_False(self): self._test_email_ssl_decrypt('aes256', 'cbc', False) def test_email_ssl_decrypt_aes128_ofb_False(self): self._test_email_ssl_decrypt('aes128', 'ofb', False) def test_email_ssl_decrypt_aes192_ofb_False(self): self._test_email_ssl_decrypt('aes192', 'ofb', False) def test_email_ssl_decrypt_aes256_ofb_False(self): self._test_email_ssl_decrypt('aes256', 'ofb', False) def test_email_ssl_decrypt_aes128_cbc_True(self): self._test_email_ssl_decrypt('aes128', 'cbc', True) def test_email_ssl_decrypt_aes192_cbc_True(self): self._test_email_ssl_decrypt('aes192', 'cbc', True) def test_email_ssl_decrypt_aes256_cbc_True(self): self._test_email_ssl_decrypt('aes256', 'cbc', True) def test_email_ssl_decrypt_aes128_ofb_True(self): self._test_email_ssl_decrypt('aes128', 'ofb', True) def test_email_ssl_decrypt_aes192_ofb_True(self): self._test_email_ssl_decrypt('aes192', 'ofb', True) def test_email_ssl_decrypt_aes256_ofb_True(self): self._test_email_ssl_decrypt('aes256', 'ofb', True) def _test_email_ssl_encrypt_smime(self, algo): fname = fixture('smime-ssl-encrypted-smime-{}.txt'.format(algo)) cmd = [ 'openssl', 'smime', '-encrypt', '-'+algo, '-in', fixture('smime-unsigned.txt'), '-out', fname, test_cert.cert1_cert, ] process = Popen(cmd, stdout=PIPE, stderr=PIPE) stdout, stderr = process.communicate() assert stderr == b'' assert stdout == b'' key = test_cert.CA().key_load(test_cert.cert1_key, '1234') with io.open(fname, 'rt', encoding='utf-8') as fh: datae = fh.read() datad = email.decrypt(datae, key) with open(fixture('smime-unsigned.txt'), 'rb') as fh: datau = fh.read() assert datau == datad.replace(b'\r\n', b'\n') def test_email_ssl_encrypt_aes256(self): self._test_email_ssl_encrypt_smime('aes256') def _test_email_ssl_encrypt_cms(self, mode): fname = fixture('smime-ssl-encrypted-cms-{}.txt'.format(mode)) cmd = [ 'openssl', 'cms', '-encrypt', '-recip', test_cert.cert1_cert, '-in', fixture('smime-unsigned.txt'), '-out', fname, '-md', 'sha512' ] if mode is not None: cmd.extend([ '-keyopt', 'rsa_padding_mode:{}'.format(mode), ]) process = Popen(cmd, stdout=PIPE, stderr=PIPE) stdout, stderr = process.communicate() assert stderr == b'' assert stdout == b'' key = test_cert.CA().key_load(test_cert.cert1_key, '1234') with io.open(fname, 'rt', encoding='utf-8') as fh: datae = fh.read() datad = email.decrypt(datae, key) with open(fixture('smime-unsigned.txt'), 'rb') as fh: datau = fh.read() assert datau == datad.replace(b'\r\n', b'\n') def test_email_ssl_encrypt_cms_oaep(self): self._test_email_ssl_encrypt_cms('oaep') def test_email_ssl_encrypt_cms(self): self._test_email_ssl_encrypt_cms(None) endesive-2.19.1/tests/test_hsm.py000066400000000000000000000166121504236674500167720ustar00rootroot00000000000000#!/usr/bin/env vpython3 # coding: utf-8 import unittest import os import stat import subprocess import sysconfig import datetime import base64 import email from email.mime.multipart import MIMEMultipart from email.mime.application import MIMEApplication from email.mime.text import MIMEText from email.mime.base import MIMEBase from asn1crypto import pem as asn1pem from cryptography.hazmat import backends from cryptography.hazmat.primitives import serialization from cryptography.hazmat.primitives.serialization import pkcs12 from endesive import hsm, signer, verifier import PyKCS11 as PK11 import test_cert tests_root = os.path.dirname(__file__) fixtures_dir = os.path.join(tests_root, 'fixtures') def fixture(fname): return os.path.join(fixtures_dir, fname) dllpath = os.path.join(sysconfig.get_config_var('LIBDIR'), 'softhsm/libsofthsm2.so') os.makedirs(os.path.join(fixtures_dir, 'softhsm2'), exist_ok=True) os.environ['SOFTHSM2_CONF'] = fixture('softhsm2.conf') open(fixture('softhsm2.conf'), 'wt').write('''\ log.level = DEBUG directories.tokendir = %s/softhsm2/ objectstore.backend = file slots.removable = false ''' % fixtures_dir) class HSM(hsm.HSM): def main(self): cakeyID = bytes((0x1,)) rec = self.session.findObjects([(PK11.CKA_CLASS, PK11.CKO_PRIVATE_KEY), (PK11.CKA_ID, cakeyID)]) if len(rec) == 0: label = 'hsm CA' self.gen_privkey(label, cakeyID) self.ca_gen(label, cakeyID, 'hsm CA') keyID = bytes((0x66,0x66,0x90)) rec = self.session.findObjects([(PK11.CKA_CLASS, PK11.CKO_PRIVATE_KEY), (PK11.CKA_ID, keyID)]) if len(rec) == 0: label = 'hsm USER 1' self.gen_privkey(label, keyID) self.ca_sign(keyID, label, 0x666690, "hsm USER 1", 365, cakeyID) self.cert_export(fixture('cert-hsm-ca'), cakeyID) self.cert_export(fixture('cert-hsm-user1'), keyID) def compose(From, To, Subject, Body, Attachment, signer): # create message object instance msg = MIMEMultipart(_subtype="signed", micalg="SHA1", protocol="application/pkcs7-signature") # setup the parameters of the message msg['From'] = From msg['To'] = To msg['Subject'] = Subject msg['Date'] = email.utils.format_datetime(datetime.datetime.now()) msg.preamble = "This is a multipart message in MIME format." env = MIMEMultipart(_subtype='mixed') body = MIMEText(Body.decode()) #del body['MIME-Version'] env.attach(body) with open(Attachment, 'rb') as fp: app = MIMEApplication(fp.read(), _subtype="txt") app.add_header('content-disposition', 'attachment', filename=Attachment) env.attach(app) msg.attach(env) sig = MIMEBase(_maintype='application', _subtype='pkcs7-signature', name="smime.p7s") sig.add_header('Content-Disposition', 'attachment', filename='smime.p7s') sig.add_header('Content-Transfer-Encoding', 'base64') datau = env.as_string().encode() #open(fixture('test_ssh_sign-sign.txt'),'wb').write(datau) sig.set_payload(signer(datau)) #del sig['MIME-Version'] msg.attach(sig) return msg, env, sig def sign(datau, key, cert, othercerts, hashalgo, hsm): datau = datau.replace(b'\n', b'\r\n') datas = signer.sign(datau, key, cert, othercerts, hashalgo, attrs=True, pss=False, hsm=hsm) return base64.encodebytes(datas) class HSMTests(unittest.TestCase): def test_base(self): cls = hsm.BaseHSM() try: cls.certificate() except NotImplementedError: pass try: cls.sign(None, None, None) except NotImplementedError: pass def test_create(self): cls = HSM(dllpath) cls.create("endesieve", "secret1", "secret2") cls.login("endesieve", "secret1") try: cls.main() finally: cls.logout() def test_load(self): cls = HSM(dllpath) cls.login("endesieve", "secret1") cakeyID = bytes((0x1,)) cls.cert_load(cakeyID) keyID = bytes((0x66,0x66,0x90)) cls.cert_load(keyID) cls.logout() def test_ssh_sign(self): key, cert, othercerts = test_cert.CA().pk12_load(test_cert.cert1_p12, '1234') agent = hsm.SSHAgentHSM(cert) # lookup the ssh fingerprint for the certificates public key keyid, _ = agent.certificate() keyfile = None try: # is the public key known to the ssh-agent yet? agent.key(keyid) except ValueError: agent.close() # we have to add the key to the ssh-agent # remove the key password, dump in traditional openssl so ssh-agent can add the key keyfile = fixture('demo2_user1.key.nopass.pem') with open(keyfile, 'wb') as fp: # dump the key fp.write(key.private_bytes( encoding=serialization.Encoding.PEM, format=serialization.PrivateFormat.TraditionalOpenSSL, encryption_algorithm=serialization.NoEncryption() )) os.chmod(keyfile, 0o600) # pub file so ssh-add -d can be used pubfile = fixture('demo2_user1.key.nopass.pem.pub') with open(pubfile, 'wb') as fp: # convert the public key of the certificate to ssh public key format fp.write(cert.public_key().public_bytes( encoding=serialization.Encoding.OpenSSH, format=serialization.PublicFormat.OpenSSH )) subprocess.call(["ssh-add", keyfile]) # reconnect the agent so the key is visible to paramiko agent = hsm.SSHAgentHSM(cert) with open(fixture('smime-unsigned.txt'), 'rb') as fp: datau = fp.read() msg, env, sig = compose( From='root+from@localhost', To='root+to@localhost', Subject='this is the subject', Body=datau, Attachment=fixture('smime-unsigned.txt'), signer=lambda data: sign(data, None, cert, othercerts, 'sha256', agent) ) datas = msg.as_bytes(unixfrom=True) with open(fixture('smime-signed-hsm-ssh.txt'), 'wb') as fp: fp.write(datas) # we added, so we remove the key from ssh-agent keyfile = fixture('demo2_user1.key.nopass.pem') if keyfile: subprocess.call(['ssh-add', '-d', keyfile]) agent.close() def test_ssh_verify(self): with open(test_cert.cert1_cert, 'rb') as fp: cert = fp.read() with open(fixture('smime-signed-hsm-ssh.txt'), 'rt') as fp: datas = fp.read() msg = email.message_from_string(datas) sig = None plain = msg.get_payload(0, False) for part in msg.walk(): ct = part.get_content_type() #if ct == 'application/x-pkcs7-signature': # sig = part.get_payload(decode=True) # break if ct == 'application/pkcs7-signature': sig = part.get_payload(decode=True) break #if sig is None: # raise ValueError('not signed email') datau = plain.as_string().encode() #open(fixture('test_ssh_sign-plain.txt'),'wb').write(datau) datau = datau.replace(b'\n', b'\r\n') (hashok, signatureok, certok) = verifier.verify(sig, datau, [cert,]) assert hashok and signatureok and certok endesive-2.19.1/tests/test_pdf.py000066400000000000000000000265261504236674500167610ustar00rootroot00000000000000#!/usr/bin/env vpython3 # coding: utf-8 import unittest import datetime import os from cryptography.hazmat import backends from cryptography.hazmat.primitives.serialization import pkcs12 from endesive import pdf tests_root = os.path.dirname(__file__) fixtures_dir = os.path.join(tests_root, 'fixtures') import test_cert def fixture(fname): return os.path.join(fixtures_dir, fname) class PDFTests(unittest.TestCase): def test_pdf(self): dct = { 'sigflags': 3, 'contact': 'mak@trisoft.com.pl', 'location': 'Szczecin', 'signingdate': '20180731082642+02\'00\'', 'reason': 'Dokument podpisany cyfrowo', } p12 = test_cert.CA().pk12_load(test_cert.cert1_p12, '1234') fname = fixture('pdf.pdf') with open(fname, 'rb') as fh: datau = fh.read() datas = pdf.cms.sign(datau, dct, p12[0], p12[1], p12[2], 'sha256' ) fname = fname.replace('.pdf', '-signed-cms.pdf') with open(fname, 'wb') as fp: fp.write(datau) fp.write(datas) with open(test_cert.ca_root_cert, 'rb') as fh: trusted_cert_pems = (fh.read(),) with open(fname, 'rb') as fh: data = fh.read() results = pdf.verify( data, trusted_cert_pems ) for (hashok, signatureok, certok) in results: assert signatureok and hashok and certok def test_pdf_pss(self): dct = { 'sigflags': 3, 'contact': 'mak@trisoft.com.pl', 'location': 'Szczecin', 'signingdate': '20180731082642+02\'00\'', 'reason': 'Dokument podpisany cyfrowo', 'pss': True, } p12 = test_cert.CA().pk12_load(test_cert.cert1_p12, '1234') fname = fixture('pdf.pdf') with open(fname, 'rb') as fh: datau = fh.read() datas = pdf.cms.sign(datau, dct, p12[0], p12[1], p12[2], 'sha256' ) fname = fname.replace('.pdf', '-signed-cms-pss.pdf') with open(fname, 'wb') as fp: fp.write(datau) fp.write(datas) with open(test_cert.ca_root_cert, 'rb') as fh: trusted_cert_pems = (fh.read(),) with open(fname, 'rb') as fh: data = fh.read() results = pdf.verify( data, trusted_cert_pems ) for (hashok, signatureok, certok) in results: assert signatureok and hashok and certok def test_pdf_aligned(self): dct = { 'sigflags': 3, 'contact': 'mak@trisoft.com.pl', 'location': 'Szczecin', 'signingdate': '20180731082642+02\'00\'', 'reason': 'Dokument podpisany cyfrowo', 'aligned': 0, } p12 = test_cert.CA().pk12_load(test_cert.cert1_p12, '1234') fname = fixture('pdf.pdf') with open(fname, 'rb') as fh: datau = fh.read() datas = pdf.cms.sign(datau, dct, p12[0], p12[1], p12[2], 'sha256' ) fname = fname.replace('.pdf', '-signed-cms-aligned.pdf') with open(fname, 'wb') as fp: fp.write(datau) fp.write(datas) with open(test_cert.ca_root_cert, 'rb') as fh: trusted_cert_pems = (fh.read(),) with open(fname, 'rb') as fh: data = fh.read() results = pdf.verify( data, trusted_cert_pems ) for (hashok, signatureok, certok) in results: assert signatureok and hashok and certok def test_pdf_encrypted(self): dct = { 'sigflags': 3, 'contact': 'mak@trisoft.com.pl', 'location': 'Szczecin', 'signingdate': '20180731082642+02\'00\'', 'reason': 'Dokument podpisany cyfrowo', 'aligned': 0, 'password': '1234', } p12 = test_cert.CA().pk12_load(test_cert.cert1_p12, '1234') fname = fixture('pdf-encrypted.pdf') with open(fname, 'rb') as fh: datau = fh.read() datas = pdf.cms.sign(datau, dct, p12[0], p12[1], p12[2], 'sha256' ) fname = fname.replace('.pdf', '-signed.pdf') with open(fname, 'wb') as fp: fp.write(datau) fp.write(datas) with open(test_cert.ca_root_cert, 'rb') as fh: trusted_cert_pems = (fh.read(),) with open(fname, 'rb') as fh: data = fh.read() results = pdf.verify( data, trusted_cert_pems ) for (hashok, signatureok, certok) in results: assert signatureok and hashok and certok def test_pdf_signature_appearance(self): dct = { 'aligned': 0, 'sigflags': 3, 'sigflagsft': 132, 'sigpage': 0, 'sigbutton': False, 'sigfield': 'Signature-1667820612.078739', 'auto_sigfield': False, 'sigandcertify': False, 'signaturebox': [175.79446979865773, 294.7236779911374, 447.47683221476507, 573.2810782865583], 'contact': '', 'location': '', 'reason': '', 'signingdate': "D:20221107123012+00'00'", 'signature_appearance': { 'background': [0.75, 0.8, 0.95], 'outline': [0.2, 0.3, 0.5], 'border': 1, 'labels': True, 'display': ['date'] } } p12 = test_cert.CA().pk12_load(test_cert.cert1_p12, '1234') fname = fixture('pdf.pdf') with open(fname, 'rb') as fh: datau = fh.read() datas = pdf.cms.sign(datau, dct, p12[0], p12[1], p12[2], 'sha256' ) fname = fname.replace('.pdf', '-signed-appearance.pdf') with open(fname, 'wb') as fp: fp.write(datau) fp.write(datas) with open(test_cert.ca_root_cert, 'rb') as fh: trusted_cert_pems = (fh.read(),) with open(fname, 'rb') as fh: data = fh.read() results = pdf.verify( data, trusted_cert_pems ) for (hashok, signatureok, certok) in results: assert signatureok and hashok and certok def test_pdf_signature_appearance_ec(self): dct = { 'aligned': 4096, 'sigflags': 3, 'sigflagsft': 132, 'sigpage': 0, 'sigbutton': False, 'sigfield': 'Signature-1667820612.078739', 'auto_sigfield': False, 'sigandcertify': False, 'signaturebox': [175.79446979865773, 294.7236779911374, 447.47683221476507, 573.2810782865583], 'contact': '', 'location': '', 'reason': '', 'signingdate': "D:20221107123012+00'00'", 'signature_appearance': { 'background': [0.75, 0.8, 0.95], 'outline': [0.2, 0.3, 0.5], 'border': 1, 'labels': True, 'display': ['date'] } } p12 = test_cert.CA().pk12_load(test_cert.cert3_p12, '1234') fname = fixture('pdf.pdf') with open(fname, 'rb') as fh: datau = fh.read() datas = pdf.cms.sign(datau, dct, p12[0], p12[1], p12[2], 'sha256' ) fname = fname.replace('.pdf', '-signed-appearance-ec.pdf') with open(fname, 'wb') as fp: fp.write(datau) fp.write(datas) with open(test_cert.ca_root_cert, 'rb') as fh: trusted_cert_pems = (fh.read(),) with open(fname, 'rb') as fh: data = fh.read() results = pdf.verify( data, trusted_cert_pems ) for (hashok, signatureok, certok) in results: assert signatureok and hashok and certok def test_pdf_signature_manual(self): date = datetime.datetime.utcnow() - datetime.timedelta(hours=12) date = date.strftime('D:%Y%m%d%H%M%S+00\'00\'') class User: full_name = 'u.full: ąćęłńóśżź' email = 'u.email: zażółcić gęślą jaźń' company = 'u.comp: ĄĆĘŁŃÓŚŻŹ' company_full_name = 'u.comp_full: ZAŻÓŁCIĆ GĘŚLĄ JAŹŃ' user = User() dct = { "aligned": 0, "sigflags": 3, "sigflagsft": 132, "sigpage": 0, "sigfield": "Signature1", "auto_sigfield": True, "signform": False, "signaturebox": (40, 110, 260, 190), "signature_manual": [ ['text_box', f'Investor Name: {user.full_name}\nEmail: {user.email}\nDate: {date}\nLocation: Szczecin', # font *[bounding box], size, wrap, align, baseline, spacing 'default', 5, 10, 270, 40, 7, True, 'left', 'top'], ['fill_colour', 0.4, 0.4, 0.4], ['rect_fill', 0, 50, 250, 1], ['fill_colour', 0, 0, 0], ['text_box', user.company_full_name, 'DancingScript', 7, 25, 270, 50, 12, True, 'left', 'top', 1.2], ], "manual_fonts": { 'DancingScript': '/usr/share/fonts/truetype/dejavu/DejaVuSansCondensed-Bold.ttf' }, "contact": user.email, "location": "Szczecin", "signingdate": date, "reason": f"Investment in {user.company} by {user.company_full_name}", } p12 = test_cert.CA().pk12_load(test_cert.cert1_p12, '1234') fname = fixture('pdf.pdf') with open(fname, 'rb') as fh: datau = fh.read() datas = pdf.cms.sign(datau, dct, p12[0], p12[1], p12[2], 'sha256' ) fname = fname.replace('.pdf', '-signed-appearance-manual.pdf') with open(fname, 'wb') as fp: fp.write(datau) fp.write(datas) with open(test_cert.ca_root_cert, 'rb') as fh: trusted_cert_pems = (fh.read(),) with open(fname, 'rb') as fh: data = fh.read() results = pdf.verify( data, trusted_cert_pems ) for (hashok, signatureok, certok) in results: assert signatureok and hashok and certok def test_pdf_timestamp(self): tspurl = "http://public-qlts.certum.pl/qts-17" dct = { 'sigflags': 3, 'contact': 'mak@trisoft.com.pl', 'location': 'Szczecin', 'signingdate': '20180731082642+02\'00\'', 'reason': 'Dokument podpisany cyfrowo', } p12 = test_cert.CA().pk12_load(test_cert.cert1_p12, '1234') fname = fixture('pdf.pdf') with open(fname, 'rb') as fh: datau = fh.read() datas = pdf.cms.sign(datau, dct, p12[0], p12[1], p12[2], 'sha256', None, tspurl, ) fname = fname.replace('.pdf', '-signed-cms.pdf') with open(fname, 'wb') as fp: fp.write(datau) fp.write(datas) with open(test_cert.ca_root_cert, 'rb') as fh: trusted_cert_pems = (fh.read(),) with open(fname, 'rb') as fh: data = fh.read() results = pdf.verify( data, trusted_cert_pems ) for (hashok, signatureok, certok) in results: assert signatureok and hashok and certok endesive-2.19.1/tests/test_plain.py000066400000000000000000000110101504236674500172710ustar00rootroot00000000000000#!/usr/bin/env vpython3 # coding: utf-8 import unittest import os from subprocess import PIPE, Popen import sys from datetime import datetime from cryptography.hazmat import backends from cryptography.hazmat.primitives.serialization import pkcs12 from endesive import plain import test_cert tests_root = os.path.dirname(__file__) fixtures_dir = os.path.join(tests_root, 'fixtures') def fixture(fname): return os.path.join(fixtures_dir, fname) class PLAINTests(unittest.TestCase): def test_plain_signed_attr(self): p12 = test_cert.CA().pk12_load(test_cert.cert1_p12, '1234') with open(fixture('plain-unsigned.txt'), 'rb') as fh: datau = fh.read() datas = plain.sign(datau, p12[0], p12[1], p12[2], 'sha256', attrs=True ) fname = fixture('plain-signed-attr.txt') with open(fname, 'wb') as fh: fh.write(datas) cmd = [ 'openssl', 'smime', '-verify', '-CAfile', fixture('root.pem'), '-content', fixture('plain-unsigned.txt'), '-in', fname, '-inform', 'der', ] process = Popen(cmd, stdout=PIPE, stderr=PIPE) stdout, stderr = process.communicate() assert stderr == b'Verification successful\n' assert datau == stdout def test_plain_signed_noattr(self): p12 = test_cert.CA().pk12_load(test_cert.cert1_p12, '1234') with open(fixture('plain-unsigned.txt'), 'rb') as fh: datau = fh.read() datas = plain.sign(datau, p12[0], p12[1], p12[2], 'sha256', attrs=False ) fname = fixture('plain-signed-noattr.txt') with open(fname, 'wb') as fh: fh.write(datas) cmd = [ 'openssl', 'smime', '-verify', '-CAfile', fixture('root.pem'), '-content', fixture('plain-unsigned.txt'), '-in', fname, '-inform', 'der', ] process = Popen(cmd, stdout=PIPE, stderr=PIPE) stdout, stderr = process.communicate() assert stderr == b'Verification successful\n' assert datau == stdout def test_plain_ssl_attr(self): cmd = [ 'openssl', 'smime', '-sign', '-md', 'sha256', '-binary', '-CAfile', fixture('root.pem'), '-in', fixture('plain-unsigned.txt'), '-out', fixture('plain-ssl-signed-attr.txt'), '-outform', 'der', '-inkey', test_cert.cert1_key, '-passin', 'pass:1234', '-signer', test_cert.cert1_cert, ] process = Popen(cmd, stdout=PIPE, stderr=PIPE) stdout, stderr = process.communicate() assert b'' == stdout assert b'' == stderr trusted_cert_pems = [] with open(fixture('root.pem'), 'rb') as fp: trusted_cert_pems.append(fp.read()) with open(fixture('plain-unsigned.txt'), 'rb') as fh: datau = fh.read() with open(fixture('plain-ssl-signed-attr.txt'), 'rb') as fh: datas = fh.read() (hashok, signatureok, certok) = plain.verify(datas, datau, trusted_cert_pems) assert signatureok and hashok and certok def test_plain_ssl_noattr(self): cmd = [ 'openssl', 'smime', '-sign', '-md', 'sha256', '-binary', '-noattr', '-CAfile', fixture('root.pem'), '-in', fixture('plain-unsigned.txt'), '-out', fixture('plain-ssl-signed-noattr.txt'), '-outform', 'der', '-inkey', test_cert.cert1_key, '-passin', 'pass:1234', '-signer', test_cert.cert1_cert, ] process = Popen(cmd, stdout=PIPE, stderr=PIPE) stdout, stderr = process.communicate() assert b'' == stdout assert b'' == stderr trusted_cert_pems = [] with open(fixture('root.pem'), 'rb') as fp: trusted_cert_pems.append(fp.read()) with open(fixture('plain-unsigned.txt'), 'rb') as fh: datau = fh.read() with open(fixture('plain-ssl-signed-noattr.txt'), 'rb') as fh: datas = fh.read() (hashok, signatureok, certok) = plain.verify(datas, datau, trusted_cert_pems) assert signatureok and hashok and certok if __name__ == '__main__': cls = PLAINTests() for n in dir(cls): if n.split('_')[0] == 'test': print(n) try: getattr(cls, n)() except Exception as exc: pass