aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--.github/workflows/main.yml37
-rw-r--r--.idea/.gitignore1
-rw-r--r--.idea/dictionaries/ejb.xml7
-rw-r--r--CMakeLists.txt23
-rw-r--r--ChangeLog38
-rw-r--r--README-maintainer.md97
-rw-r--r--appimage/Dockerfile12
-rwxr-xr-xappimage/build-appimage4
-rwxr-xr-xbuild-scripts/build-doc2
-rwxr-xr-xbuild-scripts/test-alt-zlib39
-rwxr-xr-xbuild-scripts/test-c++-next14
-rwxr-xr-xbuild-scripts/test-pikepdf12
-rw-r--r--compare-for-test/CMakeLists.txt15
-rw-r--r--compare-for-test/compare.testcov9
-rw-r--r--compare-for-test/qpdf-test-compare.cc244
-rw-r--r--compare-for-test/qtest/compare.test109
-rw-r--r--compare-for-test/qtest/compare/diff-data-enc.pdfbin0 -> 1519 bytes
-rw-r--r--compare-for-test/qtest/compare/diff-data-size-unc.pdfbin0 -> 843 bytes
-rw-r--r--compare-for-test/qtest/compare/diff-data-size.pdfbin0 -> 847 bytes
-rw-r--r--compare-for-test/qtest/compare/diff-data-unc.pdfbin0 -> 844 bytes
-rw-r--r--compare-for-test/qtest/compare/diff-data.pdfbin0 -> 849 bytes
-rw-r--r--compare-for-test/qtest/compare/diff-id.pdfbin0 -> 844 bytes
-rw-r--r--compare-for-test/qtest/compare/diff-non-stream.pdfbin0 -> 844 bytes
-rw-r--r--compare-for-test/qtest/compare/diff-num-objects.pdfbin0 -> 882 bytes
-rw-r--r--compare-for-test/qtest/compare/diff-object-type.pdfbin0 -> 765 bytes
-rw-r--r--compare-for-test/qtest/compare/diff-stream-dict.pdfbin0 -> 844 bytes
-rw-r--r--compare-for-test/qtest/compare/enc1.pdf41
-rw-r--r--compare-for-test/qtest/compare/enc2.pdf41
-rw-r--r--compare-for-test/qtest/compare/ostream1.pdfbin0 -> 833 bytes
-rw-r--r--compare-for-test/qtest/compare/ostream2.pdfbin0 -> 843 bytes
-rw-r--r--compare-for-test/qtest/compare/start.pdf47
-rw-r--r--compare-for-test/qtest/compare/zlib-9.pdfbin0 -> 844 bytes
-rw-r--r--compare-for-test/qtest/compare/zlib-new-id.pdfbin0 -> 844 bytes
-rw-r--r--compare-for-test/qtest/compare/zlib-new-id1.pdfbin0 -> 844 bytes
-rw-r--r--compare-for-test/qtest/compare/zlib-new-id2.pdfbin0 -> 844 bytes
-rw-r--r--compare-for-test/qtest/compare/zlib-ng.pdfbin0 -> 848 bytes
-rw-r--r--compare-for-test/qtest/compare/zlib.pdfbin0 -> 844 bytes
-rw-r--r--examples/CMakeLists.txt8
-rw-r--r--examples/extend-c-api-impl.cc29
-rw-r--r--examples/extend-c-api.c67
-rw-r--r--examples/extend-c-api.h25
-rw-r--r--examples/qpdf-job.cc3
-rw-r--r--examples/qpdfjob-c.c5
-rw-r--r--examples/qtest/c-objects.test4
-rw-r--r--examples/qtest/custom-filter.test8
-rw-r--r--examples/qtest/extend-c-api.test30
-rw-r--r--examples/qtest/extend-c-api/bad.out5
-rw-r--r--examples/qtest/extend-c-api/bad.pdf1
-rw-r--r--examples/qtest/extend-c-api/good.out1
-rw-r--r--examples/qtest/extend-c-api/good.pdf64
-rw-r--r--examples/qtest/invert-images.test4
-rw-r--r--examples/qtest/overlay-page.test8
-rw-r--r--examples/qtest/qpdf-job/out.pdfbin1300 -> 1278 bytes
-rw-r--r--examples/qtest/qpdfjob-remove-annotations.test4
-rw-r--r--examples/qtest/set-form-values.test4
-rw-r--r--include/qpdf/Buffer.hh7
-rw-r--r--include/qpdf/DLL.h11
-rw-r--r--include/qpdf/Pl_Buffer.hh8
-rw-r--r--include/qpdf/QPDF.hh10
-rw-r--r--include/qpdf/QPDFObjectHandle.hh4
-rw-r--r--include/qpdf/qpdf-c.h33
-rw-r--r--job.sums2
-rw-r--r--libqpdf/Buffer.cc18
-rw-r--r--libqpdf/CMakeLists.txt2
-rw-r--r--libqpdf/Pl_Buffer.cc19
-rw-r--r--libqpdf/QPDF.cc25
-rw-r--r--libqpdf/QPDFAcroFormDocumentHelper.cc3
-rw-r--r--libqpdf/QPDFObjectHandle.cc3
-rw-r--r--libqpdf/QPDFPageObjectHelper.cc5
-rw-r--r--libqpdf/QPDFWriter.cc19
-rw-r--r--libqpdf/QPDF_Stream.cc25
-rw-r--r--libqpdf/QPDF_encryption.cc25
-rw-r--r--libqpdf/QPDF_linearization.cc21
-rw-r--r--libqpdf/SF_FlateLzwDecode.cc2
-rw-r--r--libqpdf/qpdf-c.cc12
-rw-r--r--libtests/buffer.cc59
-rw-r--r--libtests/logger_c.c5
-rw-r--r--libtests/qtest/flate.test10
-rw-r--r--libtests/qtest/logger/c-exp-savebin799 -> 774 bytes
-rwxr-xr-xmake_dist22
-rw-r--r--manual/cli.rst4
-rw-r--r--manual/conf.py8
-rw-r--r--manual/release-notes.rst37
-rw-r--r--qpdf/CMakeLists.txt1
-rw-r--r--qpdf/qpdf-ctest.c1
-rw-r--r--qpdf/qtest/attachments.test8
-rw-r--r--qpdf/qtest/c-api.test4
-rw-r--r--qpdf/qtest/coalesce-contents.test4
-rw-r--r--qpdf/qtest/copy-annotations.test4
-rw-r--r--qpdf/qtest/custom-pipeline.test4
-rw-r--r--qpdf/qtest/dangling-refs.test4
-rw-r--r--qpdf/qtest/decode-parameters.test4
-rw-r--r--qpdf/qtest/deterministic-id.test61
-rw-r--r--qpdf/qtest/encryption-parameters.test3
-rw-r--r--qpdf/qtest/encryption.test21
-rw-r--r--qpdf/qtest/error-condition.test8
-rw-r--r--qpdf/qtest/extensions-dictionary.test8
-rw-r--r--qpdf/qtest/filter-abbreviations.test4
-rw-r--r--qpdf/qtest/form-xobject.test4
-rw-r--r--qpdf/qtest/inline-images.test4
-rw-r--r--qpdf/qtest/linearize-pass1.test1
-rw-r--r--qpdf/qtest/many-nulls.test5
-rw-r--r--qpdf/qtest/merge-and-split.test28
-rw-r--r--qpdf/qtest/newline-before-endstream.test8
-rw-r--r--qpdf/qtest/page-errors.test8
-rw-r--r--qpdf/qtest/pages-tree.test14
-rw-r--r--qpdf/qtest/parsing.test8
-rw-r--r--qpdf/qtest/preserve-unref.test12
-rw-r--r--qpdf/qtest/qpdf-json.test16
-rw-r--r--qpdf/qtest/qpdf/c-linearized.pdfbin10729 -> 11325 bytes
-rw-r--r--qpdf/qtest/qpdf/deterministic-id-nn.pdf1852
-rw-r--r--qpdf/qtest/qpdf/deterministic-id-ny.pdfbin138231 -> 0 bytes
-rw-r--r--qpdf/qtest/qpdf/deterministic-id-yn.pdfbin176117 -> 0 bytes
-rw-r--r--qpdf/qtest/qpdf/deterministic-id-yy.pdfbin148511 -> 0 bytes
-rw-r--r--qpdf/qtest/qpdf/extra-header-lin-newline.pdfbin1334 -> 1312 bytes
-rw-r--r--qpdf/qtest/qpdf/extra-header-lin-no-newline.pdfbin1334 -> 1312 bytes
-rw-r--r--qpdf/qtest/qpdf/filter-xref-offsets.pl8
-rw-r--r--qpdf/qtest/qpdf/good17-not-recompressed.pdfbin9147 -> 10621 bytes
-rw-r--r--qpdf/qtest/qpdf/job-json-misc-options.pdfbin1285 -> 1288 bytes
-rw-r--r--qpdf/qtest/qpdf/lin-special.disable.expbin3092 -> 3085 bytes
-rw-r--r--qpdf/qtest/qpdf/lin-special.generate.expbin2849 -> 2849 bytes
-rw-r--r--qpdf/qtest/qpdf/lin-special.preserve.expbin3092 -> 3085 bytes
-rw-r--r--qpdf/qtest/qpdf/linearize-duplicate-page.pdfbin1899 -> 1843 bytes
-rw-r--r--qpdf/qtest/qpdf/long-id-linearized.pdfbin1338 -> 1316 bytes
-rw-r--r--qpdf/qtest/qpdf/minimal-linearize-pass1.pdfbin1274 -> 1249 bytes
-rw-r--r--qpdf/qtest/qpdf/minimal-linearized.pdfbin1310 -> 1288 bytes
-rw-r--r--qpdf/qtest/qpdf/newline-before-endstream-nl-objstm.pdfbin1203 -> 1730 bytes
-rw-r--r--qpdf/qtest/qpdf/object-stream.disable.expbin1285 -> 1288 bytes
-rw-r--r--qpdf/qtest/qpdf/object-stream.generate.expbin1373 -> 1373 bytes
-rw-r--r--qpdf/qtest/qpdf/object-stream.preserve.expbin1373 -> 1373 bytes
-rw-r--r--qpdf/qtest/qpdf/pages-is-page-out.pdfbin1310 -> 1288 bytes
-rw-r--r--qpdf/qtest/qpdf/png-filters-1-column.pdfbin0 -> 16827 bytes
-rw-r--r--qpdf/qtest/qpdf/png-filters-no-columns-decoded.pdfbin0 -> 26498 bytes
-rw-r--r--qpdf/qtest/qpdf/png-filters-no-columns.pdfbin0 -> 16827 bytes
-rw-r--r--qpdf/qtest/qpdf/replaced-stream-data-flate.pdfbin1419 -> 1422 bytes
-rw-r--r--qpdf/qtest/qpdf/short-id-linearized.pdfbin1294 -> 1272 bytes
-rw-r--r--qpdf/qtest/qpdf/xref-with-short-size-new.out8
-rw-r--r--qpdf/qtest/qpdf_test_helpers.pm4
-rw-r--r--qpdf/qtest/qpdfjob.test51
-rw-r--r--qpdf/qtest/replace-input.test12
-rw-r--r--qpdf/qtest/rotate-pages.test16
-rw-r--r--qpdf/qtest/specialized-filter.test16
-rw-r--r--qpdf/qtest/specific-file.test11
-rw-r--r--qpdf/qtest/split-pages.test12
-rw-r--r--qpdf/qtest/stream-replacements.test4
-rw-r--r--qpdf/qtest/type-checks.test4
-rw-r--r--qpdf/qtest/xref-streams.test3
-rw-r--r--qpdf/test_driver.cc3
-rw-r--r--zlib-flate/qtest/1.compressed-1bin193 -> 0 bytes
-rw-r--r--zlib-flate/qtest/1.compressed-9bin193 -> 0 bytes
-rw-r--r--zlib-flate/qtest/zf.test39
151 files changed, 1552 insertions, 2199 deletions
diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml
index 03d6b929..b86f3a28 100644
--- a/.github/workflows/main.yml
+++ b/.github/workflows/main.yml
@@ -104,27 +104,18 @@ jobs:
with:
name: distribution
path: distribution
- Linux32:
- runs-on: ubuntu-latest
- needs: Prebuild
- steps:
- - uses: actions/checkout@v3
- - name: 'Linux 32-bit'
- run: build-scripts/build-linux32
pikepdf:
+ strategy:
+ fail-fast: false
+ max-parallel: 1
+ matrix:
+ future: ['', 'future']
runs-on: ubuntu-latest
needs: Prebuild
steps:
- uses: actions/checkout@v3
- name: 'pikepdf'
- run: build-scripts/test-pikepdf
- Fuzzers:
- runs-on: ubuntu-latest
- needs: Prebuild
- steps:
- - uses: actions/checkout@v3
- - name: 'Build Fuzzer'
- run: build-scripts/build-fuzzer
+ run: build-scripts/test-pikepdf ${{ matrix.future }}
Sanitizers:
runs-on: ubuntu-latest
needs: Prebuild
@@ -132,10 +123,20 @@ jobs:
- uses: actions/checkout@v3
- name: 'Sanitizer Tests'
run: build-scripts/test-sanitizers
- UnsignedChar:
+ QuickJobs:
runs-on: ubuntu-latest
needs: Prebuild
+ strategy:
+ fail-fast: false
+ max-parallel: 3
+ matrix:
+ script:
+ - build-fuzzer
+ - build-linux32
+ - test-alt-zlib
+ - test-unsigned-char
+ - test-c++-next
steps:
- uses: actions/checkout@v3
- - name: 'Unsigned Char Tests'
- run: build-scripts/test-unsigned-char
+ - name: ${{ matrix.script }}
+ run: build-scripts/${{ matrix.script }}
diff --git a/.idea/.gitignore b/.idea/.gitignore
index 13566b81..55b97637 100644
--- a/.idea/.gitignore
+++ b/.idea/.gitignore
@@ -6,3 +6,4 @@
# Datasource local storage ignored files
/dataSources/
/dataSources.local.xml
+/inspectionProfiles
diff --git a/.idea/dictionaries/ejb.xml b/.idea/dictionaries/ejb.xml
new file mode 100644
index 00000000..0dcc3d1a
--- /dev/null
+++ b/.idea/dictionaries/ejb.xml
@@ -0,0 +1,7 @@
+<component name="ProjectDictionaryState">
+ <dictionary name="ejb">
+ <words>
+ <w>whoami</w>
+ </words>
+ </dictionary>
+</component> \ No newline at end of file
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 3e9f47a0..c264bfa3 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -3,9 +3,10 @@ cmake_minimum_required(VERSION 3.16)
# make_dist expects the version line to be on a line by itself after
# the project line. When updating the version, check make_dist for all
-# the places it has to be updated.
+# the places it has to be updated. The doc configuration and CI build
+# also find the version number here.
project(qpdf
- VERSION 11.6.3
+ VERSION 11.7.0
LANGUAGES C CXX)
# Enable correct rpath handling for MacOSX
@@ -105,6 +106,7 @@ option(INSTALL_CMAKE_PACKAGE "Install cmake package files" ON)
option(INSTALL_EXAMPLES "Install example files" ON)
option(FUTURE "Include ABI-breaking changes CONSIDERED for the next major release" OFF)
+option(CXX_NEXT "Build with next C++ standard version" OFF)
# *** END OPTIONS ***
@@ -147,8 +149,14 @@ endif()
# increment SOVERSION every time we increment the project major
# version. This works because qpdf uses semantic versioning. qpdf 10.x
# was libqpdf28, so start from there.
-math(EXPR qpdf_SOVERSION "${PROJECT_VERSION_MAJOR} + 18")
-set(qpdf_LIBVERSION ${qpdf_SOVERSION}.${PROJECT_VERSION_MINOR}.${PROJECT_VERSION_PATCH})
+
+if(FUTURE)
+ math(EXPR qpdf_SOVERSION 0)
+ set(qpdf_LIBVERSION 0)
+else()
+ math(EXPR qpdf_SOVERSION "${PROJECT_VERSION_MAJOR} + 18")
+ set(qpdf_LIBVERSION ${qpdf_SOVERSION}.${PROJECT_VERSION_MINOR}.${PROJECT_VERSION_PATCH})
+endif()
if(${CMAKE_SOURCE_DIR} STREQUAL ${CMAKE_BINARY_DIR})
message(FATAL_ERROR "
@@ -159,7 +167,11 @@ Please build with cmake in a subdirectory, e.g.
Please remove CMakeCache.txt and the CMakeFiles directories.")
endif()
-set(CMAKE_CXX_STANDARD 17)
+if(CXX_NEXT)
+ set(CMAKE_CXX_STANDARD 20)
+else()
+ set(CMAKE_CXX_STANDARD 17)
+endif()
set(CMAKE_CXX_EXTENSIONS OFF)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
set(CMAKE_C_VISIBILITY_PRESET hidden)
@@ -329,6 +341,7 @@ add_test(
# add_subdirectory order affects test order
add_subdirectory(include)
add_subdirectory(libqpdf)
+add_subdirectory(compare-for-test)
add_subdirectory(qpdf)
add_subdirectory(libtests)
add_subdirectory(examples)
diff --git a/ChangeLog b/ChangeLog
index 696a3567..c7bd1b2a 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,41 @@
+2023-12-20 Jay Berkenbilt <ejb@ql.org>
+
+ * Update code and tests so that qpdf's test suite no longer
+ depends on the output of any specific zlib implementation. This
+ makes it possible to get a fully passing test suite with any
+ API-compatible zlib library. CI tests with the default zlib as
+ well as zlib-ng (including verifying that zlib-ng is not the
+ default), but any zlib implementation should work. Fixes #774.
+
+ * Bug fix: with --compress-streams=n, don't compress object, XRef,
+ or linearization hint streams.
+
+2023-12-16 Jay Berkenbilt <ejb@ql.org>
+
+ * Add new C++ functions "qpdf_c_get_qpdf" and "qpdf_c_wrap" to
+ qpdf-c.h that make it possible to write your own extern "C"
+ functions in C++ that interoperate with the C API. See
+ examples/extend-c-api for more information.
+
+ * Bug fix from M. Holger: the default for /Columns in PNG filter
+ is 1, but libqpdf was acting like it was 0.
+
+ * Enhancement from M. Holger: add methods to Buffer to work more
+ easily with std::string.
+
+2023-12-10 Jay Berkenbilt <ejb@ql.org>
+
+ * 11.6.4: release
+
+2023-12-09 Jay Berkenbilt <ejb@ql.org>
+
+ * Install fix: include cmake files with the dev component.
+
+2023-11-20 Jay Berkenbilt <ejb@ql.org>
+
+ * Build AppImage with an older Linux distribution to support AWS
+ Lambda. Fixes #1086.
+
2023-10-15 Jay Berkenbilt <ejb@ql.org>
* 11.6.3: release
diff --git a/README-maintainer.md b/README-maintainer.md
index c7ae7296..4c8bd6e6 100644
--- a/README-maintainer.md
+++ b/README-maintainer.md
@@ -7,6 +7,7 @@
* [CHECKING DOCS ON readthedocs](#checking-docs-on-readthedocs)
* [GOOGLE OSS-FUZZ](#google-oss-fuzz)
* [CODING RULES](#coding-rules)
+* [ZLIB COMPATIBILITY](#zlib-compatibility)
* [HOW TO ADD A COMMAND-LINE ARGUMENT](#how-to-add-a-command-line-argument)
* [RELEASE PREPARATION](#release-preparation)
* [CREATING A RELEASE](#creating-a-release)
@@ -272,6 +273,102 @@ Building docs from pull requests is also enabled.
* Avoid attaching too much metadata to objects and object handles
since those have to get copied around a lot.
+## ZLIB COMPATIBILITY
+
+The qpdf test suite is designed to be independent of the output of any
+particular version of zlib. There are several strategies to make this
+work:
+
+* `build-scripts/test-alt-zlib` runs in CI and runs the test suite
+ with a non-default zlib. Please refer to that code for an example of
+ how to do this in case you want to test locally.
+
+* The test suite is full of cases that compare output PDF files with
+ expected PDF files in the test suite. If the file contains data that
+ was compressed by QPDFWriter, then the output file will depend on
+ the behavior of zlib. As such, using a simple comparison won't work.
+ There are several strategies used by the test suite.
+
+ * A new program called `qpdf-test-compare`, in most cases, is a drop
+ in replacement for a simple file comparison. This code make sure
+ the two files have exactly the same number of objects with the
+ same object and generation numbers, and that corresponding objects
+ are identical with the following allowances (consult its source
+ code for all the details details):
+ * The `/Length` key is not compared in stream dictionaries.
+ * The second element of `/ID` is not compared.
+ * If the first and second element of `/ID` are the same, then the
+ first element if `/ID` is also not compared.
+ * If a stream is compressed with `/FlateDecode`, the
+ _uncompressed_ stream data is compared. Otherwise, the raw
+ stream data is compared.
+ * Generated fields in the `/Encrypt` dictionary are not compared,
+ though password-protected files must have the same password.
+ * Differences in the contents of `/XRef` streams are ignored.
+
+ To use this, run `qpdf-test-compare actual.pdf expected.pdf`, and
+ expect the output to match `expected.pdf`. For example, if a test
+ used to be written like this;
+ ```perl
+ $td->runtest("check output",
+ {$td->FILE => "a.pdf"},
+ {$td->FILE => "out.pdf"});
+ ```
+ then write it like this instead:
+ ```perl
+ $td->runtest("check output",
+ {$td->COMMAND => "qpdf-test-compare a.pdf out.pdf"},
+ {$td->FILE => "out.pdf", $td->EXIT_STATUS => 0});
+ ```
+ You can look at `compare-for-test/qtest/compare.test` for
+ additional examples.
+
+ Here's what's going on:
+ * If the files "match" according to the rules of
+ `qpdf-test-compare`, the output of the program is the expected
+ file.
+ * If the files do not match, the output is the actual file. The
+ reason is that, if a change is made that results in an expected
+ change to the expected file, the output of the comparison can be
+ used to replace the expected file (as long as it is definitely
+ known to be correct—no shortcuts here!). That way, it doesn't
+ matter which zlib you use to generate test files.
+ * As a special debugging tool, you can set the `QPDF_COMPARE_WHY`
+ environment variable to any value. In this case, if the files
+ don't match, the output is a description of the first thing in
+ the file that doesn't match. This is mostly useful for debugging
+ `qpdf-test-compare` itself, but it can also be helpful as a
+ sanity check that the differences are expected. If you are
+ trying to find out the _real_ differences, a suggestion is to
+ convert both files to qdf and compare them lexically.
+
+ * There are some cases where `qpdf-test-compare` can't be used. For
+ example, if you need to actually test one of the things that
+ `qpdf-test-compare` ignores, you'll need some other mechanism.
+ There are tests for deterministic ID creation and xref streams
+ that have to implement other mechanisms. Also, linearization hint
+ streams and the linearization dictionary in a linearized file
+ contain file offsets. Rather than ignoring those, it can be
+ helpful to create linearized files using `--compress-streams=n`.
+ In that case, `QPDFWriter` won't compress any data, so the PDF
+ will be independent of the output of any particular zlib
+ implementation.
+
+You can find many examples of how tests were rewritten by looking at
+the commits preceding the one that added this section of this README
+file.
+
+Note about `/ID`: many test cases use `--static-id` to have a
+predictable `/ID` for testing. Many other test cases use
+`--deterministic-id`. While `--static-id` is unaffected by file
+contents, `--deterministic-id` is based on file contents and so is
+dependent on zlib output if there is any newly compressed data. By
+using `qpdf-test-compare`, it's actually not necessary to use either
+`--static-id` or `--deterministic-id`. It may still be necessary to
+use `--static-aes-iv` if comparing encrypted files, but since
+`qpdf-test-compare` ignores `/Perms`, a wider range of encrypted files
+can be compared using `qpdf-test-compare`.
+
## HOW TO ADD A COMMAND-LINE ARGUMENT
Quick reminder:
diff --git a/appimage/Dockerfile b/appimage/Dockerfile
index c1914144..24c9c672 100644
--- a/appimage/Dockerfile
+++ b/appimage/Dockerfile
@@ -1,13 +1,19 @@
-FROM ubuntu:20.04
+FROM ubuntu:18.04
ENV DEBIAN_FRONTEND=noninteractive
RUN apt-get update
RUN apt-get -y install screen git sudo \
- build-essential pkg-config cmake \
+ build-essential pkg-config \
zlib1g-dev libjpeg-dev libgnutls28-dev \
python3-pip texlive-latex-extra latexmk \
inkscape imagemagick busybox-static wget fuse && \
apt-get clean && rm -rf /var/lib/apt/lists/*
-RUN pip3 install sphinx sphinx_rtd_theme
+# Get cmake from pypi. We need to keep Ubuntu 18.04 for a while longer
+# since the glibc in Ubuntu 20.04 is too new (as of late 2023) for
+# Amazon Linux 2 in Lambda and for some supported CentOS versions.
+# When we are ready to update to 20.04 or newer, remove the version
+# constraint on sphinx, and install the OS package for cmake.
+RUN pip3 install --upgrade pip
+RUN pip3 install sphinx==4 sphinx_rtd_theme cmake
COPY entrypoint /entrypoint
RUN chmod +x /entrypoint
ENTRYPOINT [ "/entrypoint" ]
diff --git a/appimage/build-appimage b/appimage/build-appimage
index 0e86bff6..f970b7df 100755
--- a/appimage/build-appimage
+++ b/appimage/build-appimage
@@ -47,14 +47,14 @@ fi
_osversion=$(cat /etc/os-release | grep PRETTY_NAME | awk -F'=' '{print $2}' | sed 's#"##g')
# Warn users building the AppImage locally:
-if [[ ! $_osversion =~ Ubuntu\ 20.04.*\ LTS ]]; then
+if [[ ! $_osversion =~ Ubuntu\ 18.04.*\ LTS ]]; then
set +x
echo ""
# 0 1 2 3 4 5 6 7
# 01234567890123456789012345678901234567890123456789012345678901234567890123456789
echo "+===========================================================================+"
echo "|| WARNING: You are about to build a QPDF AppImage on a system which is ||"
- echo "|| NOT Ubuntu 20.04 LTS. ||"
+ echo "|| NOT Ubuntu 18.04 LTS. ||"
echo "|| ||"
echo "|| It is recommended that you use a distribution that is at least a ||"
echo "|| few years old to maximize the number of Linux distributions the ||"
diff --git a/build-scripts/build-doc b/build-scripts/build-doc
index e6c72757..7d45d4fa 100755
--- a/build-scripts/build-doc
+++ b/build-scripts/build-doc
@@ -10,7 +10,7 @@ pip3 install sphinx sphinx_rtd_theme
cmake -S . -B build -DBUILD_DOC=1
cmake --build build --verbose --target doc_dist
zip -r doc.zip build/manual/doc-dist
-version=$(grep -E '^release' manual/conf.py | cut -d"'" -f 2)
+version=$(grep -E '^ +VERSION [1-9]' CMakeLists.txt | awk '{print $2}')
mv build/manual/doc-dist qpdf-${version}-doc
mkdir distribution
zip -r distribution/qpdf-${version}-doc-ci.zip qpdf-${version}-doc
diff --git a/build-scripts/test-alt-zlib b/build-scripts/test-alt-zlib
new file mode 100755
index 00000000..41b3bb31
--- /dev/null
+++ b/build-scripts/test-alt-zlib
@@ -0,0 +1,39 @@
+#!/bin/bash
+set -eo pipefail
+sudo apt-get update
+sudo apt-get -y install \
+ build-essential cmake \
+ zlib1g-dev libjpeg-dev libgnutls28-dev libssl-dev
+
+# Build and install zlib-ng
+rm -rf /tmp/zlib-ng
+pushd /tmp
+git clone https://github.com/zlib-ng/zlib-ng
+cd zlib-ng
+cmake -B build -DCMAKE_BUILD_TYPE=Release -DCMAKE_INSTALL_PREFIX=/tmp/inst -DZLIB_COMPAT=ON
+cmake --build build -j$(nproc)
+(cd build; ctest --verbose)
+cmake --install build
+popd
+
+cmake -S . -B build \
+ -DCI_MODE=1 -DBUILD_STATIC_LIBS=0 -DCMAKE_BUILD_TYPE=Release \
+ -DREQUIRE_CRYPTO_OPENSSL=1 -DREQUIRE_CRYPTO_GNUTLS=1 \
+ -DENABLE_QTC=1
+cmake --build build --verbose -j$(nproc) -- -k
+
+# Make sure we can use zlib-ng
+sum1="$(./build/zlib-flate/zlib-flate -compress < README-maintainer.md | sha256sum -)"
+export LD_PRELOAD=/tmp/inst/lib/libz.so.1
+sum2="$(./build/zlib-flate/zlib-flate -compress < README-maintainer.md | sha256sum -)"
+if [ "$sum1" = "$sum2" ]; then
+ # If this happens, see if zlib-ng has become the default. If
+ # that's the case, rework this test to use some other alternaive
+ # zlib, such as the old one or any other API-compatible
+ # implementation.
+ echo "Using zlib-ng didn't change compression output"
+ exit 2
+fi
+
+# If this fails, please see ZLIB COMPATIBILITY in README-maintainer.md.
+(cd build; ctest --verbose)
diff --git a/build-scripts/test-c++-next b/build-scripts/test-c++-next
new file mode 100755
index 00000000..343a5a4d
--- /dev/null
+++ b/build-scripts/test-c++-next
@@ -0,0 +1,14 @@
+#!/bin/bash
+set -e
+sudo apt-get update
+sudo apt-get -y install \
+ build-essential cmake \
+ zlib1g-dev libjpeg-dev libgnutls28-dev libssl-dev
+cmake -S . -B build \
+ -DCXX_NEXT=ON \
+ -DCI_MODE=1 -DBUILD_STATIC_LIBS=0 -DCMAKE_BUILD_TYPE=Release \
+ -DREQUIRE_CRYPTO_OPENSSL=1 -DREQUIRE_CRYPTO_GNUTLS=1 \
+ -DENABLE_QTC=1
+cmake --build build --verbose -j$(nproc) -- -k
+cd build
+ctest --verbose
diff --git a/build-scripts/test-pikepdf b/build-scripts/test-pikepdf
index e6c8a9a4..cdab79cf 100755
--- a/build-scripts/test-pikepdf
+++ b/build-scripts/test-pikepdf
@@ -1,10 +1,20 @@
#!/bin/bash
set -ex
+cmake_extra=
+future=0
+if [ "$1" = "future" ]; then
+ future=1
+ cmake_extra=-DFUTURE=ON
+fi
sudo apt-get update
sudo apt-get -y install \
build-essential cmake zlib1g-dev libjpeg-dev libgnutls28-dev
-cmake -S . -B build -DBUILD_STATIC_LIBS=0 -DCMAKE_BUILD_TYPE=RelWithDebInfo
+cmake -S . -B build -DBUILD_STATIC_LIBS=0 -DCMAKE_BUILD_TYPE=RelWithDebInfo $cmake_extra
cmake --build build --verbose -j$(nproc) --target libqpdf -- -k
+if [ "$future" = "1" ]; then
+ # Run qpdf's test suite in FUTURE mode as well
+ ctest --verbose
+fi
export QPDF_SOURCE_TREE=$PWD
export QPDF_BUILD_LIBDIR=$QPDF_SOURCE_TREE/build/libqpdf
export LD_LIBRARY_PATH=$QPDF_BUILD_LIBDIR
diff --git a/compare-for-test/CMakeLists.txt b/compare-for-test/CMakeLists.txt
new file mode 100644
index 00000000..c5ebbbbc
--- /dev/null
+++ b/compare-for-test/CMakeLists.txt
@@ -0,0 +1,15 @@
+# This directory is called compare-for-test rather than
+# qpdf-test-compare to make shell completion easier.
+add_executable(qpdf-test-compare qpdf-test-compare.cc)
+target_link_libraries(qpdf-test-compare libqpdf)
+
+add_test(
+ NAME compare-for-test
+ COMMAND ${RUN_QTEST}
+ --top ${qpdf_SOURCE_DIR}
+ --bin $<TARGET_FILE_DIR:qpdf-test-compare>
+ --bin $<TARGET_FILE_DIR:libqpdf> # for Windows to find DLL
+ --code ${qpdf_SOURCE_DIR}/compare-for-test
+ --color ${QTEST_COLOR}
+ --show-on-failure ${SHOW_FAILED_TEST_OUTPUT}
+ --tc "${qpdf_SOURCE_DIR}/compare-for-test/*.cc")
diff --git a/compare-for-test/compare.testcov b/compare-for-test/compare.testcov
new file mode 100644
index 00000000..b58dd2c8
--- /dev/null
+++ b/compare-for-test/compare.testcov
@@ -0,0 +1,9 @@
+objects with different type 0
+different stream dictionaries 0
+uncompressing 0
+not uncompressing 0
+differing data size 1
+different data 1
+different non-stream 0
+different trailer 0
+ignore data for xref stream 0
diff --git a/compare-for-test/qpdf-test-compare.cc b/compare-for-test/qpdf-test-compare.cc
new file mode 100644
index 00000000..5d3e6e28
--- /dev/null
+++ b/compare-for-test/qpdf-test-compare.cc
@@ -0,0 +1,244 @@
+#include <qpdf/Pl_StdioFile.hh>
+#include <qpdf/QPDF.hh>
+#include <qpdf/QTC.hh>
+#include <qpdf/QUtil.hh>
+
+#include <cstdio>
+#include <cstdlib>
+#include <cstring>
+#include <iostream>
+
+static char const* whoami = nullptr;
+
+void
+usage()
+{
+ std::cerr << "Usage: " << whoami << " actual expected" << std::endl
+ << R"(Where "actual" is the actual output and "expected" is the expected)"
+ << std::endl
+ << "output of a test, compare the two PDF files. The files are considered"
+ << std::endl
+ << "to match if all their objects are identical except that, if a stream is"
+ << std::endl
+ << "compressed with FlateDecode, the uncompressed data must match." << std::endl
+ << std::endl
+ << "If the files match, the output is the expected file. Otherwise, it is"
+ << std::endl
+ << "the actual file. Read comments in the code for rationale." << std::endl;
+ exit(2);
+}
+
+void
+cleanEncryption(QPDF& q)
+{
+ auto enc = q.getTrailer().getKey("/Encrypt");
+ if (!enc.isDictionary()) {
+ return;
+ }
+ enc.removeKey("/O");
+ enc.removeKey("/OE");
+ enc.removeKey("/U");
+ enc.removeKey("/UE");
+ enc.removeKey("/Perms");
+}
+
+std::string
+compareObjects(std::string const& label, QPDFObjectHandle act, QPDFObjectHandle exp)
+{
+ if (act.getTypeCode() != exp.getTypeCode()) {
+ QTC::TC("compare", "objects with different type");
+ return label + ": different types";
+ }
+ if (act.isStream()) {
+ // Disregard stream lengths. The length of stream data is compared later, and we don't care
+ // about the length of compressed data as long as the uncompressed data matches.
+ auto act_dict = act.getDict();
+ auto exp_dict = exp.getDict();
+ act_dict.removeKey("/Length");
+ exp_dict.removeKey("/Length");
+ if (act_dict.unparse() != exp_dict.unparse()) {
+ QTC::TC("compare", "different stream dictionaries");
+ return label + ": stream dictionaries differ";
+ }
+ if (act_dict.getKey("/Type").isNameAndEquals("/XRef")) {
+ // Cross-reference streams will generally not match, but we have numerous tests that
+ // meaningfully ensure that xref streams are correct.
+ QTC::TC("compare", "ignore data for xref stream");
+ return "";
+ }
+ auto act_filters = act_dict.getKey("/Filter");
+ bool uncompress = false;
+ if (act_filters.isName()) {
+ act_filters = act_filters.wrapInArray();
+ }
+ if (act_filters.isArray()) {
+ for (auto& filter: act_filters.aitems()) {
+ if (filter.isNameAndEquals("/FlateDecode")) {
+ uncompress = true;
+ break;
+ }
+ }
+ }
+ std::shared_ptr<Buffer> act_data;
+ std::shared_ptr<Buffer> exp_data;
+ if (uncompress) {
+ QTC::TC("compare", "uncompressing");
+ act_data = act.getStreamData();
+ exp_data = exp.getStreamData();
+ } else {
+ QTC::TC("compare", "not uncompressing");
+ act_data = act.getRawStreamData();
+ exp_data = exp.getRawStreamData();
+ }
+ if (act_data->getSize() != exp_data->getSize()) {
+ QTC::TC("compare", "differing data size", uncompress ? 0 : 1);
+ return label + ": stream data size differs";
+ }
+ auto act_buf = act_data->getBuffer();
+ auto exp_buf = exp_data->getBuffer();
+ if (memcmp(act_buf, exp_buf, act_data->getSize()) != 0) {
+ QTC::TC("compare", "different data", uncompress ? 0 : 1);
+ return label + ": stream data differs";
+ }
+ } else if (act.unparseResolved() != exp.unparseResolved()) {
+ QTC::TC("compare", "different non-stream");
+ return label + ": object contents differ";
+ }
+ return "";
+}
+
+void
+cleanTrailer(QPDFObjectHandle& trailer)
+{
+ // If the trailer is an object stream, it will have /Length.
+ trailer.removeKey("/Length");
+ // Disregard the second half of /ID. This doesn't have anything directly to do with zlib, but
+ // lots of tests use --deterministic-id, and that is affected. The deterministic ID tests
+ // meaningfully exercise that deterministic IDs behave as expected, so for the rest of the
+ // tests, it's okay to ignore /ID[1]. If the two halves of /ID are the same, ignore both since
+ // this means qpdf completely generated the /ID rather than preserving the first half.
+ auto id = trailer.getKey("/ID");
+ if (id.isArray() && id.getArrayNItems() == 2) {
+ auto id0 = id.getArrayItem(0).unparse();
+ auto id1 = id.getArrayItem(1).unparse();
+ id.setArrayItem(1, "()"_qpdf);
+ if (id0 == id1) {
+ id.setArrayItem(0, "()"_qpdf);
+ }
+ }
+}
+
+std::string
+compare(char const* actual_filename, char const* expected_filename, char const* password)
+{
+ QPDF actual;
+ actual.processFile(actual_filename, password);
+ QPDF expected;
+ expected.processFile(expected_filename, password);
+ // The motivation behind this program is to compare files in a way that allows for
+ // differences in the exact bytes of zlib compression. If all zlib implementations produced
+ // exactly the same output, we would just be able to use straight comparison, but since they
+ // don't, we use this. As such, we are enforcing a standard of "sameness" that goes beyond
+ // showing semantic equivalence. The only difference we are allowing is compressed data.
+
+ auto act_trailer = actual.getTrailer();
+ auto exp_trailer = expected.getTrailer();
+ cleanTrailer(act_trailer);
+ cleanTrailer(exp_trailer);
+ auto trailer_diff = compareObjects("trailer", act_trailer, exp_trailer);
+ if (!trailer_diff.empty()) {
+ QTC::TC("compare", "different trailer");
+ return trailer_diff;
+ }
+
+ cleanEncryption(actual);
+ cleanEncryption(expected);
+
+ auto actual_objects = actual.getAllObjects();
+ auto expected_objects = expected.getAllObjects();
+ if (actual_objects.size() != expected_objects.size()) {
+ // Not exercised in the test suite since the trailers will differ in this case.
+ return "different number of objects";
+ }
+ for (size_t i = 0; i < actual_objects.size(); ++i) {
+ auto act = actual_objects[i];
+ auto exp = expected_objects[i];
+ auto act_og = act.getObjGen();
+ auto exp_og = exp.getObjGen();
+ if (act_og != exp_og) {
+ // not reproduced in the test suite
+ return "different object IDs";
+ }
+ auto ret = compareObjects(act_og.unparse(), act, exp);
+ if (!ret.empty()) {
+ return ret;
+ }
+ }
+ return "";
+}
+
+int
+main(int argc, char* argv[])
+{
+ if ((whoami = strrchr(argv[0], '/')) == nullptr) {
+ whoami = argv[0];
+ } else {
+ ++whoami;
+ }
+
+ if ((argc == 2) && (strcmp(argv[1], "--version") == 0)) {
+ std::cout << whoami << " from qpdf version " << QPDF::QPDFVersion() << std::endl;
+ exit(0);
+ }
+
+ if (argc < 3 || argc > 4) {
+ usage();
+ }
+
+ bool show_why = QUtil::get_env("QPDF_COMPARE_WHY");
+ try {
+ char const* to_output;
+ char const* actual = argv[1];
+ char const* expected = argv[2];
+ char const* password{nullptr};
+ if (argc == 4) {
+ password = argv[3];
+ }
+ auto difference = compare(actual, expected, password);
+ if (difference.empty()) {
+ // The files are identical; write the expected file. This way, tests can be written
+ // that compare the output of this program to the expected file.
+ to_output = expected;
+ } else {
+ if (show_why) {
+ std::cerr << difference << std::endl;
+ exit(2);
+ }
+ // The files differ; write the actual file. If it is determined that the actual file
+ // is correct because of changes that result in intended differences, this enables
+ // the output of this program to replace the expected file in the test suite.
+ to_output = actual;
+ }
+ auto f = QUtil::safe_fopen(to_output, "rb");
+ QUtil::FileCloser fc(f);
+ QUtil::binary_stdout();
+ auto out = std::make_unique<Pl_StdioFile>("stdout", stdout);
+ unsigned char buf[2048];
+ bool done = false;
+ while (!done) {
+ size_t len = fread(buf, 1, sizeof(buf), f);
+ if (len <= 0) {
+ done = true;
+ } else {
+ out->write(buf, len);
+ }
+ }
+ if (!difference.empty()) {
+ exit(2);
+ }
+ } catch (std::exception& e) {
+ std::cerr << whoami << ": " << e.what() << std::endl;
+ exit(2);
+ }
+ return 0;
+}
diff --git a/compare-for-test/qtest/compare.test b/compare-for-test/qtest/compare.test
new file mode 100644
index 00000000..198cdf6b
--- /dev/null
+++ b/compare-for-test/qtest/compare.test
@@ -0,0 +1,109 @@
+#!/usr/bin/env perl
+require 5.008;
+BEGIN { $^W = 1; }
+use strict;
+
+chdir("compare") or die "chdir testdir failed: $!\n";
+
+require TestDriver;
+
+my $td = new TestDriver('compare');
+
+# The comparison tool is designed so that you can write tests that run
+# `compare actual expected` and compare the result to expected. This
+# allows you to just replace the actual file in a comparison with the
+# comparison command. If the files match, the output is the expected
+# file, which means that if the actual file is the expected file with
+# different zlib compression, the test will pass. If the files differ,
+# the actual output shown will be the real actual output. If it is
+# determined to be correct and used to replace the expected output,
+# the test will pass next time regardless of whether the same zlib
+# implementation is used.
+
+# These files are the same file compressed with a different
+# compression level and/or a different zlib implementation.
+my @same = qw(zlib.pdf zlib-9.pdf zlib-ng.pdf);
+my $comparisons = (scalar(@same) * (scalar(@same) + 1))/2;
+my $n_tests = 2 * $comparisons;
+
+for (my $i = 0; $i < scalar(@same); $i++)
+{
+ for (my $j = $i; $j < scalar(@same); $j++)
+ {
+ # Make sure the files are byte-wise different (unless they are the same file).
+ $td->runtest("byte-wise compare $i and $j",
+ {$td->COMMAND => "cmp $same[$i] $same[$j]"},
+ {$td->REGEXP => ".*", $td->EXIT_STATUS => $i == $j ? 0 : "!0"});
+ # Make sure they match. This is how compare should be used:
+ # the expected output is the same file as the second argument
+ # to the command.
+ $td->runtest("compare $i and $j",
+ {$td->COMMAND => "qpdf-test-compare $same[$i] $same[$j]"},
+ {$td->FILE => $same[$j], $td->EXIT_STATUS => 0});
+ }
+}
+
+my @diff = (
+ ["diff-num-objects.pdf", "trailer: object contents differ"],
+ ["diff-non-stream.pdf", "3,0: object contents differ"],
+ ["diff-data-size.pdf", "4,0: stream data size differs"],
+ ["diff-data.pdf", "4,0: stream data differs"],
+ ["diff-data-size-unc.pdf", "5,0: stream data size differs"],
+ ["diff-data-unc.pdf", "5,0: stream data differs"],
+ ["diff-stream-dict.pdf", "4,0: stream dictionaries differ"],
+ ["diff-object-type.pdf", "6,0: different types"],
+ ["diff-id.pdf", "trailer: object contents differ"],
+ );
+$n_tests += 2 * scalar(@diff);
+
+foreach my $f (@diff)
+{
+ # In a real test, the expected output would be the expected file
+ # as above. Here, we are actually testing the comparison tool to
+ # verify that it returns a non-zero status and the actual file
+ # when there is mismatch. Don't copy this test.
+ $td->runtest("$f->[0] is different",
+ {$td->COMMAND => "qpdf-test-compare $f->[0] zlib.pdf"},
+ {$td->FILE => $f->[0], $td->EXIT_STATUS => 2});
+ $td->runtest("$f->[0] is different (why)",
+ {$td->COMMAND => "env QPDF_COMPARE_WHY=1" .
+ " qpdf-test-compare $f->[0] zlib.pdf"},
+ {$td->STRING => "$f->[1]\n", $td->EXIT_STATUS => 2},
+ $td->NORMALIZE_NEWLINES);
+}
+
+# Repeat for encrypted files.
+$n_tests += 5;
+$td->runtest("byte-wise compare encrypted files",
+ {$td->COMMAND => "cmp enc1.pdf enc2.pdf"},
+ {$td->REGEXP => ".*", $td->EXIT_STATUS => "!0"});
+$td->runtest("compare encrypted files (same)",
+ {$td->COMMAND => "env QPDF_COMPARE_WHY=1 qpdf-test-compare enc1.pdf enc2.pdf"},
+ {$td->FILE => "enc2.pdf", $td->EXIT_STATUS => 0});
+$td->runtest("compare encrypted files (different)",
+ {$td->COMMAND => "env QPDF_COMPARE_WHY=1 qpdf-test-compare enc1.pdf diff-data-enc.pdf"},
+ {$td->STRING => "4,0: stream data differs\n", $td->EXIT_STATUS => 2},
+ $td->NORMALIZE_NEWLINES);
+$td->runtest("with password (same)",
+ {$td->COMMAND => "env QPDF_COMPARE_WHY=1 qpdf-test-compare enc1.pdf enc2.pdf o"},
+ {$td->FILE => "enc2.pdf", $td->EXIT_STATUS => 0});
+$td->runtest("with password (different)",
+ {$td->COMMAND => "env QPDF_COMPARE_WHY=1 qpdf-test-compare enc1.pdf diff-data-enc.pdf o"},
+ {$td->STRING => "4,0: stream data differs\n", $td->EXIT_STATUS => 2},
+ $td->NORMALIZE_NEWLINES);
+
+# Object streams
+$n_tests += 1;
+$td->runtest("compare object stream files (same)",
+ {$td->COMMAND => "env QPDF_COMPARE_WHY=1 qpdf-test-compare ostream1.pdf ostream2.pdf"},
+ {$td->FILE => "ostream2.pdf", $td->EXIT_STATUS => 0});
+
+$n_tests += 2;
+$td->runtest("files identical except /ID[1]",
+ {$td->COMMAND => "env QPDF_COMPARE_WHY=1 qpdf-test-compare zlib.pdf zlib-new-id.pdf"},
+ {$td->FILE => "zlib-new-id.pdf", $td->EXIT_STATUS => 0});
+$td->runtest("/ID[0] = /ID[1]",
+ {$td->COMMAND => "env QPDF_COMPARE_WHY=1 qpdf-test-compare zlib-new-id1.pdf zlib-new-id2.pdf"},
+ {$td->FILE => "zlib-new-id2.pdf", $td->EXIT_STATUS => 0});
+
+$td->report($n_tests);
diff --git a/compare-for-test/qtest/compare/diff-data-enc.pdf b/compare-for-test/qtest/compare/diff-data-enc.pdf
new file mode 100644
index 00000000..ae2b23b0
--- /dev/null
+++ b/compare-for-test/qtest/compare/diff-data-enc.pdf
Binary files differ
diff --git a/compare-for-test/qtest/compare/diff-data-size-unc.pdf b/compare-for-test/qtest/compare/diff-data-size-unc.pdf
new file mode 100644
index 00000000..61444ee2
--- /dev/null
+++ b/compare-for-test/qtest/compare/diff-data-size-unc.pdf
Binary files differ
diff --git a/compare-for-test/qtest/compare/diff-data-size.pdf b/compare-for-test/qtest/compare/diff-data-size.pdf
new file mode 100644
index 00000000..5dc2f5d1
--- /dev/null
+++ b/compare-for-test/qtest/compare/diff-data-size.pdf
Binary files differ
diff --git a/compare-for-test/qtest/compare/diff-data-unc.pdf b/compare-for-test/qtest/compare/diff-data-unc.pdf
new file mode 100644
index 00000000..b79f7afb
--- /dev/null
+++ b/compare-for-test/qtest/compare/diff-data-unc.pdf
Binary files differ
diff --git a/compare-for-test/qtest/compare/diff-data.pdf b/compare-for-test/qtest/compare/diff-data.pdf
new file mode 100644
index 00000000..04216efa
--- /dev/null
+++ b/compare-for-test/qtest/compare/diff-data.pdf
Binary files differ
diff --git a/compare-for-test/qtest/compare/diff-id.pdf b/compare-for-test/qtest/compare/diff-id.pdf
new file mode 100644
index 00000000..58df0db7
--- /dev/null
+++ b/compare-for-test/qtest/compare/diff-id.pdf
Binary files differ
diff --git a/compare-for-test/qtest/compare/diff-non-stream.pdf b/compare-for-test/qtest/compare/diff-non-stream.pdf
new file mode 100644
index 00000000..2e7e6e80
--- /dev/null
+++ b/compare-for-test/qtest/compare/diff-non-stream.pdf
Binary files differ
diff --git a/compare-for-test/qtest/compare/diff-num-objects.pdf b/compare-for-test/qtest/compare/diff-num-objects.pdf
new file mode 100644
index 00000000..ec904d15
--- /dev/null
+++ b/compare-for-test/qtest/compare/diff-num-objects.pdf
Binary files differ
diff --git a/compare-for-test/qtest/compare/diff-object-type.pdf b/compare-for-test/qtest/compare/diff-object-type.pdf
new file mode 100644
index 00000000..8380e88d
--- /dev/null
+++ b/compare-for-test/qtest/compare/diff-object-type.pdf
Binary files differ
diff --git a/compare-for-test/qtest/compare/diff-stream-dict.pdf b/compare-for-test/qtest/compare/diff-stream-dict.pdf
new file mode 100644
index 00000000..cf40d323
--- /dev/null
+++ b/compare-for-test/qtest/compare/diff-stream-dict.pdf
Binary files differ
diff --git a/compare-for-test/qtest/compare/enc1.pdf b/compare-for-test/qtest/compare/enc1.pdf
new file mode 100644
index 00000000..50f4f1da
--- /dev/null
+++ b/compare-for-test/qtest/compare/enc1.pdf
@@ -0,0 +1,41 @@
+%PDF-2.0
+%
+1 0 obj
+<< /Pages 2 0 R /Type /Catalog >>
+endobj
+2 0 obj
+<< /Count 1 /Kids [ 3 0 R ] /Type /Pages >>
+endobj
+3 0 obj
+<< /Contents [ 4 0 R 5 0 R ] /MediaBox [ 0 0 612 792 ] /Parent 2 0 R /Resources << /Font << /F1 6 0 R >> >> /Type /Page >>
+endobj
+4 0 obj
+<< /Filter /FlateDecode /Length 64 >>
+stream
+*8FTbp~0(Ѣ#'őדp;ˆ*ZBjHU[gendstream
+endobj
+5 0 obj
+<< /Length 80 /Filter /FlateDecode >>
+stream
+*8FTbp~0(Ѣ#'őד́i4bzKST$ EzaI<@,w6edendstream
+endobj
+6 0 obj
+<< /BaseFont /Helvetica /Encoding /WinAnsiEncoding /Subtype /Type1 /Type /Font >>
+endobj
+7 0 obj
+<< /CF << /StdCF << /AuthEvent /DocOpen /CFM /AESV3 /Length 32 >> >> /Filter /Standard /Length 256 /O <b45814c26b7159b191abe2237afbcf1c0448ac23339f0916f754e3c99e4c67a3296960be084c567f03357be63fc0b335> /OE <9423f87d42392b07fc90b6a2329545a1c877ecec680adc8cbc80a5ad5c3abb6c> /P -4 /Perms <84770c5fdc078585b95e8592bb0b38a3> /R 6 /StmF /StdCF /StrF /StdCF /U <4165270c9c8795068aba2bae6f89673992c6ed0e0c2d2bfca6189293a5ba3c4817f0c7a4eb476c53ac29382cea765534> /UE <7991ebbe79a40d5dfb1a1bc87394a81dbefc6ab9a1b19ee7845099ed6e7de14b> /V 5 >>
+endobj
+xref
+0 8
+0000000000 65535 f
+0000000015 00000 n
+0000000064 00000 n
+0000000123 00000 n
+0000000261 00000 n
+0000000395 00000 n
+0000000545 00000 n
+0000000642 00000 n
+trailer << /Root 1 0 R /Size 8 /ID [<42841c13bbf709d79a200fa1691836f8><31415926535897932384626433832795>] /Encrypt 7 0 R >>
+startxref
+1189
+%%EOF
diff --git a/compare-for-test/qtest/compare/enc2.pdf b/compare-for-test/qtest/compare/enc2.pdf
new file mode 100644
index 00000000..5a025491
--- /dev/null
+++ b/compare-for-test/qtest/compare/enc2.pdf
@@ -0,0 +1,41 @@
+%PDF-2.0
+%
+1 0 obj
+<< /Pages 2 0 R /Type /Catalog >>
+endobj
+2 0 obj
+<< /Count 1 /Kids [ 3 0 R ] /Type /Pages >>
+endobj
+3 0 obj
+<< /Contents [ 4 0 R 5 0 R ] /MediaBox [ 0 0 612 792 ] /Parent 2 0 R /Resources << /Font << /F1 6 0 R >> >> /Type /Page >>
+endobj
+4 0 obj
+<< /Filter /FlateDecode /Length 80 >>
+stream
+*8FTbp~൐_7a7ҧ'\ }??OsvZ<NȋD$nN}bendstream
+endobj
+5 0 obj
+<< /Length 80 /Filter /FlateDecode >>
+stream
+*8FTbp~൐_7a7ҧ'\ߥR1"'GRrЭHY_&ˢ2 ߴs<HХ: endstream
+endobj
+6 0 obj
+<< /BaseFont /Helvetica /Encoding /WinAnsiEncoding /Subtype /Type1 /Type /Font >>
+endobj
+7 0 obj
+<< /CF << /StdCF << /AuthEvent /DocOpen /CFM /AESV3 /Length 32 >> >> /Filter /Standard /Length 256 /O <08cc676b1f1cc805ee97abf33aab0f77cb195093c52b65ebf04b1dce93531d8d11b6cd60da17599e4d3679513b957140> /OE <f0a631fa9024e58c72ec7a899aa137b5da0ec491849e433c7dca87a614a045e6> /P -4 /Perms <973bd88c774165b5e58f722b3ced7bf4> /R 6 /StmF /StdCF /StrF /StdCF /U <8203fcce3446c8747d515ac3368fb817e0b7a290e1298d2a0246cd3b559d4544aebba6df7a97f0c8e74f98638f658468> /UE <689a534cf6e2ea26b9a5f9073ccfcf268700cc129779a5d1bbabc9eae77c72f0> /V 5 >>
+endobj
+xref
+0 8
+0000000000 65535 f
+0000000015 00000 n
+0000000064 00000 n
+0000000123 00000 n
+0000000261 00000 n
+0000000411 00000 n
+0000000561 00000 n
+0000000658 00000 n
+trailer << /Root 1 0 R /Size 8 /ID [<42841c13bbf709d79a200fa1691836f8><31415926535897932384626433832795>] /Encrypt 7 0 R >>
+startxref
+1205
+%%EOF
diff --git a/compare-for-test/qtest/compare/ostream1.pdf b/compare-for-test/qtest/compare/ostream1.pdf
new file mode 100644
index 00000000..b340ae33
--- /dev/null
+++ b/compare-for-test/qtest/compare/ostream1.pdf
Binary files differ
diff --git a/compare-for-test/qtest/compare/ostream2.pdf b/compare-for-test/qtest/compare/ostream2.pdf
new file mode 100644
index 00000000..27d6b2c2
--- /dev/null
+++ b/compare-for-test/qtest/compare/ostream2.pdf
Binary files differ
diff --git a/compare-for-test/qtest/compare/start.pdf b/compare-for-test/qtest/compare/start.pdf
new file mode 100644
index 00000000..79001f24
--- /dev/null
+++ b/compare-for-test/qtest/compare/start.pdf
@@ -0,0 +1,47 @@
+%PDF-2.0
+%
+1 0 obj
+<< /Pages 2 0 R /Type /Catalog >>
+endobj
+2 0 obj
+<< /Count 1 /Kids [ 3 0 R ] /Type /Pages >>
+endobj
+3 0 obj
+<< /Contents [ 4 0 R 5 0 R ] /MediaBox [ 0 0 612 792 ] /Parent 2 0 R /Resources << /Font << /F1 6 0 R >> >> /Type /Page >>
+endobj
+4 0 obj
+<< /Length 48 /Filter /FlateDecode >>
+stream
+BT
+ /F1 24 Tf
+ 72 720 Td
+ (WWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWW) Tj
+ET
+endstream
+endobj
+5 0 obj
+<< /Length 43 >>
+stream
+BT
+ /F1 24 Tf
+ 72 681 Td
+ (Potato) Tj
+ET
+endstream
+endobj
+6 0 obj
+<< /BaseFont /Helvetica /Encoding /WinAnsiEncoding /Subtype /Type1 /Type /Font >>
+endobj
+xref
+0 7
+0000000000 65535 f
+0000000015 00000 n
+0000000064 00000 n
+0000000123 00000 n
+0000000261 00000 n
+0000000379 00000 n
+0000000471 00000 n
+trailer << /Root 1 0 R /Size 7 /ID [<42841c13bbf709d79a200fa1691836f8><31415926535897932384626433832795>] >>
+startxref
+568
+%%EOF
diff --git a/compare-for-test/qtest/compare/zlib-9.pdf b/compare-for-test/qtest/compare/zlib-9.pdf
new file mode 100644
index 00000000..16187f31
--- /dev/null
+++ b/compare-for-test/qtest/compare/zlib-9.pdf
Binary files differ
diff --git a/compare-for-test/qtest/compare/zlib-new-id.pdf b/compare-for-test/qtest/compare/zlib-new-id.pdf
new file mode 100644
index 00000000..8618f369
--- /dev/null
+++ b/compare-for-test/qtest/compare/zlib-new-id.pdf
Binary files differ
diff --git a/compare-for-test/qtest/compare/zlib-new-id1.pdf b/compare-for-test/qtest/compare/zlib-new-id1.pdf
new file mode 100644
index 00000000..5dd7a823
--- /dev/null
+++ b/compare-for-test/qtest/compare/zlib-new-id1.pdf
Binary files differ
diff --git a/compare-for-test/qtest/compare/zlib-new-id2.pdf b/compare-for-test/qtest/compare/zlib-new-id2.pdf
new file mode 100644
index 00000000..1dd13b89
--- /dev/null
+++ b/compare-for-test/qtest/compare/zlib-new-id2.pdf
Binary files differ
diff --git a/compare-for-test/qtest/compare/zlib-ng.pdf b/compare-for-test/qtest/compare/zlib-ng.pdf
new file mode 100644
index 00000000..9d8c4329
--- /dev/null
+++ b/compare-for-test/qtest/compare/zlib-ng.pdf
Binary files differ
diff --git a/compare-for-test/qtest/compare/zlib.pdf b/compare-for-test/qtest/compare/zlib.pdf
new file mode 100644
index 00000000..9a24beb4
--- /dev/null
+++ b/compare-for-test/qtest/compare/zlib.pdf
Binary files differ
diff --git a/examples/CMakeLists.txt b/examples/CMakeLists.txt
index 9af85fe2..6c1ca0f3 100644
--- a/examples/CMakeLists.txt
+++ b/examples/CMakeLists.txt
@@ -34,12 +34,18 @@ foreach(PROG ${EXAMPLE_C_PROGRAMS})
endforeach()
target_include_directories(pdf-create PRIVATE ${JPEG_INCLUDE})
+# extend-c-api contains a mixture of C and C++ files.
+add_executable(extend-c-api extend-c-api-impl.cc extend-c-api.c)
+set_property(TARGET extend-c-api PROPERTY LINKER_LANGUAGE CXX)
+target_link_libraries(extend-c-api libqpdf)
+
add_test(
NAME examples
COMMAND ${RUN_QTEST}
--top ${qpdf_SOURCE_DIR}
--bin $<TARGET_FILE_DIR:pdf-create>
--bin $<TARGET_FILE_DIR:qpdf>
+ --bin $<TARGET_FILE_DIR:qpdf-test-compare>
--bin $<TARGET_FILE_DIR:libqpdf> # for Windows to find DLL
--code ${qpdf_SOURCE_DIR}/examples
--color ${QTEST_COLOR}
@@ -47,7 +53,7 @@ add_test(
--tc "${qpdf_SOURCE_DIR}/examples/*.cc"
--tc "${qpdf_SOURCE_DIR}/examples/*.c")
-file(GLOB EXAMPLES_SRC "*.c" "*.cc")
+file(GLOB EXAMPLES_SRC "*.c" "*.cc" "*.h")
if(INSTALL_EXAMPLES)
install(FILES ${EXAMPLES_SRC}
DESTINATION ${CMAKE_INSTALL_DOCDIR}/examples
diff --git a/examples/extend-c-api-impl.cc b/examples/extend-c-api-impl.cc
new file mode 100644
index 00000000..680d957b
--- /dev/null
+++ b/examples/extend-c-api-impl.cc
@@ -0,0 +1,29 @@
+// This is an example of how to write C++ functions and make them usable with the qpdf C API. It
+// consists of three files:
+// - extend-c-api.h -- a plain C header file
+// - extend-c-api.c -- a C program that calls the function
+// - extend-c-api.cc -- a C++ file that implements the function
+
+#include "extend-c-api.h"
+
+// Here, we add a function to get the number of pages in a PDF file and make it callable through the
+// C API.
+
+// This is a normal C++ function that works with QPDF in a normal way. It doesn't do anything
+// special to be callable from C.
+int
+numPages(std::shared_ptr<QPDF> qpdf)
+{
+ return qpdf->getRoot().getKey("/Pages").getKey("/Count").getIntValueAsInt();
+}
+
+// Now we define the glue that makes our function callable using the C API.
+
+// This is the C++ implementation of the C function.
+QPDF_ERROR_CODE
+num_pages(qpdf_data qc, int* npages)
+{
+ // Call qpdf_c_wrap to convert any exception our function might through to a QPDF_ERROR_CODE
+ // and attach it to the qpdf_data object in the same way as other functions in the C API.
+ return qpdf_c_wrap(qc, [&qc, &npages]() { *npages = numPages(qpdf_c_get_qpdf(qc)); });
+}
diff --git a/examples/extend-c-api.c b/examples/extend-c-api.c
new file mode 100644
index 00000000..aa603845
--- /dev/null
+++ b/examples/extend-c-api.c
@@ -0,0 +1,67 @@
+/*
+ * This is an example of how to write C++ functions and make them usable with the qpdf C API. It
+ * consists of three files:
+ * - extend-c-api.h -- a plain C header file
+ * - extend-c-api.c -- a C program that calls the function
+ * - extend-c-api.cc -- a C++ file that implements the function
+ */
+
+#include "extend-c-api.h"
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+static char const* whoami = 0;
+
+static void
+usage()
+{
+ fprintf(stderr, "Usage: %s infile\n", whoami);
+ exit(2);
+}
+
+int
+main(int argc, char* argv[])
+{
+ char* infile = NULL;
+ qpdf_data qpdf = qpdf_init();
+ int warnings = 0;
+ int errors = 0;
+ char* p = NULL;
+
+ if ((p = strrchr(argv[0], '/')) != NULL) {
+ whoami = p + 1;
+ } else if ((p = strrchr(argv[0], '\\')) != NULL) {
+ whoami = p + 1;
+ } else {
+ whoami = argv[0];
+ }
+
+ if (argc != 2) {
+ usage();
+ }
+
+ infile = argv[1];
+
+ if ((qpdf_read(qpdf, infile, NULL) & QPDF_ERRORS) == 0) {
+ int npages;
+ if ((num_pages(qpdf, &npages) & QPDF_ERRORS) == 0) {
+ printf("num pages = %d\n", npages);
+ }
+ }
+ if (qpdf_more_warnings(qpdf)) {
+ warnings = 1;
+ }
+ if (qpdf_has_error(qpdf)) {
+ errors = 1;
+ printf("error: %s\n", qpdf_get_error_full_text(qpdf, qpdf_get_error(qpdf)));
+ }
+ qpdf_cleanup(&qpdf);
+ if (errors) {
+ return 2;
+ } else if (warnings) {
+ return 3;
+ }
+
+ return 0;
+}
diff --git a/examples/extend-c-api.h b/examples/extend-c-api.h
new file mode 100644
index 00000000..3b2d12d4
--- /dev/null
+++ b/examples/extend-c-api.h
@@ -0,0 +1,25 @@
+#ifndef EXAMPLE_C_EXTEND_H
+#define EXAMPLE_C_EXTEND_H
+
+/*
+ * This is an example of how to write C++ functions and make them usable with the qpdf C API. It
+ * consists of three files:
+ * - extend-c-api.h -- a plain C header file
+ * - extend-c-api.c -- a C program that calls the function
+ * - extend-c-api.cc -- a C++ file that implements the function
+ */
+#include <qpdf/qpdf-c.h>
+
+/* Declare your custom function to return QPDF_ERROR_CODE and take qpdf_data and anything else you
+ * need. Any errors are retrievable through the qpdf C APIs normal error-handling mechanism.
+ */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+ QPDF_ERROR_CODE num_pages(qpdf_data qc, int* npages);
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* EXAMPLE_C_EXTEND_H */
diff --git a/examples/qpdf-job.cc b/examples/qpdf-job.cc
index be868a17..99b853ea 100644
--- a/examples/qpdf-job.cc
+++ b/examples/qpdf-job.cc
@@ -44,6 +44,7 @@ main(int argc, char* argv[])
->endPages()
->linearize()
->staticId() // for testing only
+ ->compressStreams("n") // avoid dependency on zlib output
->checkConfiguration();
j.run();
std::cout << "out1 status: " << j.getExitCode() << std::endl;
@@ -63,6 +64,7 @@ main(int argc, char* argv[])
"1",
"--",
"--static-id",
+ "--compress-streams=n", // avoid dependency on zlib output
nullptr};
QPDFJob j;
j.initializeFromArgv(new_argv);
@@ -81,6 +83,7 @@ main(int argc, char* argv[])
"outputFile": "out3.pdf",
"staticId": "",
"linearize": "",
+ "compressStreams": "n",
"pages": [
{
"file": ".",
diff --git a/examples/qpdfjob-c.c b/examples/qpdfjob-c.c
index 62528392..6dd68283 100644
--- a/examples/qpdfjob-c.c
+++ b/examples/qpdfjob-c.c
@@ -19,7 +19,7 @@ main(int argc, char* argv[])
{
char* infile = NULL;
char* outfile = NULL;
- char const* new_argv[6];
+ char const* new_argv[7];
int r = 0;
char* p = 0;
@@ -43,7 +43,8 @@ main(int argc, char* argv[])
new_argv[2] = outfile;
new_argv[3] = "--linearize";
new_argv[4] = "--static-id"; /* for testing only */
- new_argv[5] = NULL;
+ new_argv[5] = "--compress-streams=n"; /* avoid dependency on zlib output */
+ new_argv[6] = NULL;
/* See qpdf-job.cc for a C++ example of using the json interface. To use that from C just like
* the argv one, call qpdfjob_run_from_json instead and pass the json string as a single char
diff --git a/examples/qtest/c-objects.test b/examples/qtest/c-objects.test
index 9cd496f6..f10f60c7 100644
--- a/examples/qtest/c-objects.test
+++ b/examples/qtest/c-objects.test
@@ -17,8 +17,8 @@ foreach my $i (qw(1 2))
{$td->COMMAND => "pdf-c-objects $i.pdf '' a.pdf"},
{$td->STRING => "", $td->EXIT_STATUS => 0});
$td->runtest("check output",
- {$td->FILE => "a.pdf"},
- {$td->FILE => "$i-out.pdf"});
+ {$td->COMMAND => "qpdf-test-compare a.pdf $i-out.pdf"},
+ {$td->FILE => "$i-out.pdf", $td->EXIT_STATUS => 0});
}
cleanup();
diff --git a/examples/qtest/custom-filter.test b/examples/qtest/custom-filter.test
index e674ea66..2d8acec6 100644
--- a/examples/qtest/custom-filter.test
+++ b/examples/qtest/custom-filter.test
@@ -24,8 +24,8 @@ $td->runtest("custom filter, decode generalized",
$td->EXIT_STATUS => 0},
$td->NORMALIZE_NEWLINES);
$td->runtest("check output",
- {$td->FILE => "a.pdf"},
- {$td->FILE => "generalized.pdf"});
+ {$td->COMMAND => "qpdf-test-compare a.pdf generalized.pdf"},
+ {$td->FILE => "generalized.pdf", $td->EXIT_STATUS => 0});
$td->runtest("custom filter, decode specialized",
{$td->COMMAND =>
@@ -34,8 +34,8 @@ $td->runtest("custom filter, decode specialized",
$td->EXIT_STATUS => 0},
$td->NORMALIZE_NEWLINES);
$td->runtest("check output",
- {$td->FILE => "a.pdf"},
- {$td->FILE => "specialized.pdf"});
+ {$td->COMMAND => "qpdf-test-compare a.pdf specialized.pdf"},
+ {$td->FILE => "specialized.pdf", $td->EXIT_STATUS => 0});
cleanup();
diff --git a/examples/qtest/extend-c-api.test b/examples/qtest/extend-c-api.test
new file mode 100644
index 00000000..3dd82193
--- /dev/null
+++ b/examples/qtest/extend-c-api.test
@@ -0,0 +1,30 @@
+#!/usr/bin/env perl
+require 5.008;
+use warnings;
+use strict;
+
+chdir("extend-c-api") or die "chdir testdir failed: $!\n";
+
+require TestDriver;
+
+cleanup();
+
+my $td = new TestDriver('extend-c-api');
+
+$td->runtest("extend C API (good)",
+ {$td->COMMAND => "extend-c-api good.pdf"},
+ {$td->FILE => "good.out", $td->EXIT_STATUS => 0},
+ $td->NORMALIZE_NEWLINES);
+$td->runtest("extend C API (bad)",
+ {$td->COMMAND => "extend-c-api bad.pdf"},
+ {$td->FILE => "bad.out", $td->EXIT_STATUS => 2},
+ $td->NORMALIZE_NEWLINES);
+
+cleanup();
+
+$td->report(2);
+
+sub cleanup
+{
+ unlink "a.pdf";
+}
diff --git a/examples/qtest/extend-c-api/bad.out b/examples/qtest/extend-c-api/bad.out
new file mode 100644
index 00000000..51f1d56b
--- /dev/null
+++ b/examples/qtest/extend-c-api/bad.out
@@ -0,0 +1,5 @@
+WARNING: bad.pdf: can't find PDF header
+WARNING: bad.pdf: file is damaged
+WARNING: bad.pdf: can't find startxref
+WARNING: bad.pdf: Attempting to reconstruct cross-reference table
+error: bad.pdf: unable to find trailer dictionary while recovering damaged file
diff --git a/examples/qtest/extend-c-api/bad.pdf b/examples/qtest/extend-c-api/bad.pdf
new file mode 100644
index 00000000..a3d2d925
--- /dev/null
+++ b/examples/qtest/extend-c-api/bad.pdf
@@ -0,0 +1 @@
+not even a pdf file
diff --git a/examples/qtest/extend-c-api/good.out b/examples/qtest/extend-c-api/good.out
new file mode 100644
index 00000000..98205fae
--- /dev/null
+++ b/examples/qtest/extend-c-api/good.out
@@ -0,0 +1 @@
+num pages = 1
diff --git a/examples/qtest/extend-c-api/good.pdf b/examples/qtest/extend-c-api/good.pdf
new file mode 100644
index 00000000..42867b96
--- /dev/null
+++ b/examples/qtest/extend-c-api/good.pdf
@@ -0,0 +1,64 @@
+%PDF-2.0
+1 0 obj
+<<
+ /Pages 2 0 R
+ /Type /Catalog
+>>
+endobj
+2 0 obj
+<<
+ /Count 1
+ /Kids [
+ 3 0 R
+ ]
+ /Type /Pages
+>>
+endobj
+3 0 obj
+<<
+ /Contents 4 0 R
+ /MediaBox [ 0 0 612 792 ]
+ /Parent 2 0 R
+ /Resources <<
+ /Font << /F1 5 0 R >>
+ >>
+ /Type /Page
+>>
+endobj
+4 0 obj
+<<
+ /Length 44
+>>
+stream
+BT
+ /F1 24 Tf
+ 72 720 Td
+ (Potato) Tj
+ET
+endstream
+endobj
+5 0 obj
+<<
+ /BaseFont /Helvetica
+ /Encoding /WinAnsiEncoding
+ /Subtype /Type1
+ /Type /Font
+>>
+endobj
+
+xref
+0 6
+0000000000 65535 f
+0000000009 00000 n
+0000000062 00000 n
+0000000133 00000 n
+0000000277 00000 n
+0000000372 00000 n
+trailer <<
+ /Root 1 0 R
+ /Size 6
+ /ID [<42841c13bbf709d79a200fa1691836f8><b1d8b5838eeafe16125317aa78e666aa>]
+>>
+startxref
+478
+%%EOF
diff --git a/examples/qtest/invert-images.test b/examples/qtest/invert-images.test
index d1e3c939..7986d0fd 100644
--- a/examples/qtest/invert-images.test
+++ b/examples/qtest/invert-images.test
@@ -20,8 +20,8 @@ $td->runtest("invert images",
$td->NORMALIZE_NEWLINES);
$td->runtest("check output",
- {$td->FILE => "a.pdf"},
- {$td->FILE => "out.pdf"});
+ {$td->COMMAND => "qpdf-test-compare a.pdf out.pdf"},
+ {$td->FILE => "out.pdf", $td->EXIT_STATUS => 0});
cleanup();
diff --git a/examples/qtest/overlay-page.test b/examples/qtest/overlay-page.test
index be9bcb10..6440a367 100644
--- a/examples/qtest/overlay-page.test
+++ b/examples/qtest/overlay-page.test
@@ -15,15 +15,15 @@ $td->runtest("overlay-page",
{$td->COMMAND => "pdf-overlay-page in.pdf stamp.pdf a.pdf"},
{$td->STRING => "", $td->EXIT_STATUS => 0});
$td->runtest("compare files",
- {$td->FILE => "a.pdf"},
- {$td->FILE => "out.pdf"});
+ {$td->COMMAND => "qpdf-test-compare a.pdf out.pdf"},
+ {$td->FILE => "out.pdf", $td->EXIT_STATUS => 0});
$td->runtest("overlay-page with fields/ annotations",
{$td->COMMAND => "pdf-overlay-page in.pdf annotations.pdf a.pdf"},
{$td->STRING => "", $td->EXIT_STATUS => 0});
$td->runtest("compare files",
- {$td->FILE => "a.pdf"},
- {$td->FILE => "annotations-out.pdf"});
+ {$td->COMMAND => "qpdf-test-compare a.pdf annotations-out.pdf"},
+ {$td->FILE => "annotations-out.pdf", $td->EXIT_STATUS => 0});
cleanup();
diff --git a/examples/qtest/qpdf-job/out.pdf b/examples/qtest/qpdf-job/out.pdf
index c432ac59..d8ac1509 100644
--- a/examples/qtest/qpdf-job/out.pdf
+++ b/examples/qtest/qpdf-job/out.pdf
Binary files differ
diff --git a/examples/qtest/qpdfjob-remove-annotations.test b/examples/qtest/qpdfjob-remove-annotations.test
index 32abf3ef..06f8f07a 100644
--- a/examples/qtest/qpdfjob-remove-annotations.test
+++ b/examples/qtest/qpdfjob-remove-annotations.test
@@ -15,8 +15,8 @@ $td->runtest("remove-annotations",
{$td->COMMAND => "qpdfjob-remove-annotations --static-id annotations.pdf out.pdf"},
{$td->STRING => "", $td->EXIT_STATUS => 0});
$td->runtest("compare files",
- {$td->FILE => "out.pdf"},
- {$td->FILE => "annotations-out.pdf"});
+ {$td->COMMAND => "qpdf-test-compare out.pdf annotations-out.pdf"},
+ {$td->FILE => "annotations-out.pdf", $td->EXIT_STATUS => 0});
cleanup();
diff --git a/examples/qtest/set-form-values.test b/examples/qtest/set-form-values.test
index 8c103379..8d2fd2c8 100644
--- a/examples/qtest/set-form-values.test
+++ b/examples/qtest/set-form-values.test
@@ -15,8 +15,8 @@ $td->runtest("set form values",
{$td->COMMAND => "pdf-set-form-values form-in.pdf a.pdf soup"},
{$td->STRING => "", $td->EXIT_STATUS => 0});
$td->runtest("compare files",
- {$td->FILE => "a.pdf"},
- {$td->FILE => "form-out.pdf"});
+ {$td->COMMAND => "qpdf-test-compare a.pdf form-out.pdf"},
+ {$td->FILE => "form-out.pdf", $td->EXIT_STATUS => 0});
cleanup();
diff --git a/include/qpdf/Buffer.hh b/include/qpdf/Buffer.hh
index c0669c6c..d0e6eda0 100644
--- a/include/qpdf/Buffer.hh
+++ b/include/qpdf/Buffer.hh
@@ -24,6 +24,7 @@
#include <cstddef>
#include <memory>
+#include <string>
class Buffer
{
@@ -35,11 +36,15 @@ class Buffer
// object is destroyed.
QPDF_DLL
Buffer(size_t size);
+ QPDF_DLL
+ Buffer(std::string&& content);
// Create a Buffer object whose memory is owned by the caller and will not be freed when the
// Buffer is destroyed.
QPDF_DLL
Buffer(unsigned char* buf, size_t size);
+ QPDF_DLL
+ Buffer(std::string& content);
[[deprecated("Move Buffer or use Buffer::copy instead")]] QPDF_DLL Buffer(Buffer const&);
[[deprecated("Move Buffer or use Buffer::copy instead")]] QPDF_DLL Buffer&
@@ -75,8 +80,10 @@ class Buffer
private:
Members(size_t size, unsigned char* buf, bool own_memory);
+ Members(std::string&& content);
Members(Members const&) = delete;
+ std::string str;
bool own_memory;
size_t size;
unsigned char* buf;
diff --git a/include/qpdf/DLL.h b/include/qpdf/DLL.h
index 74c3c62e..8279da03 100644
--- a/include/qpdf/DLL.h
+++ b/include/qpdf/DLL.h
@@ -25,9 +25,14 @@
/* The first version of qpdf to include the version constants is 10.6.0. */
#define QPDF_MAJOR_VERSION 11
-#define QPDF_MINOR_VERSION 6
-#define QPDF_PATCH_VERSION 3
-#define QPDF_VERSION "11.6.3"
+#define QPDF_MINOR_VERSION 7
+#define QPDF_PATCH_VERSION 0
+
+#ifdef QPDF_FUTURE
+# define QPDF_VERSION "11.7.0+future"
+#else
+# define QPDF_VERSION "11.7.0"
+#endif
/*
* This file defines symbols that control the which functions,
diff --git a/include/qpdf/Pl_Buffer.hh b/include/qpdf/Pl_Buffer.hh
index 5030e10e..5def8b4f 100644
--- a/include/qpdf/Pl_Buffer.hh
+++ b/include/qpdf/Pl_Buffer.hh
@@ -33,7 +33,7 @@
#include <qpdf/PointerHolder.hh> // unused -- remove in qpdf 12 (see #785)
#include <memory>
-#include <vector>
+#include <string>
class QPDF_DLL_CLASS Pl_Buffer: public Pipeline
{
@@ -64,6 +64,10 @@ class QPDF_DLL_CLASS Pl_Buffer: public Pipeline
QPDF_DLL
void getMallocBuffer(unsigned char** buf, size_t* len);
+ // Same as getBuffer but returns the result as a string.
+ QPDF_DLL
+ std::string getString();
+
private:
class QPDF_DLL_PRIVATE Members
{
@@ -78,7 +82,7 @@ class QPDF_DLL_CLASS Pl_Buffer: public Pipeline
Members(Members const&) = delete;
bool ready{true};
- std::vector<unsigned char> data;
+ std::string data;
};
std::shared_ptr<Members> m;
diff --git a/include/qpdf/QPDF.hh b/include/qpdf/QPDF.hh
index 2ca6005c..392a153a 100644
--- a/include/qpdf/QPDF.hh
+++ b/include/qpdf/QPDF.hh
@@ -745,9 +745,10 @@ class QPDF
std::map<int, int> const& obj_renumber,
std::shared_ptr<Buffer>& hint_stream,
int& S,
- int& O)
+ int& O,
+ bool compressed)
{
- return qpdf.generateHintStream(xref, lengths, obj_renumber, hint_stream, S, O);
+ return qpdf.generateHintStream(xref, lengths, obj_renumber, hint_stream, S, O, compressed);
}
static void
@@ -1094,7 +1095,8 @@ class QPDF
std::map<int, int> const& obj_renumber,
std::shared_ptr<Buffer>& hint_stream,
int& S,
- int& O);
+ int& O,
+ bool compressed);
// Map object to object stream that contains it
void getObjectStreamData(std::map<int, int>&);
@@ -1133,7 +1135,7 @@ class QPDF
Pipeline*& pipeline,
QPDFObjGen const& og,
QPDFObjectHandle& stream_dict,
- std::vector<std::shared_ptr<Pipeline>>& heap);
+ std::unique_ptr<Pipeline>& heap);
// Methods to support object copying
void reserveObjects(QPDFObjectHandle foreign, ObjCopier& obj_copier, bool top);
diff --git a/include/qpdf/QPDFObjectHandle.hh b/include/qpdf/QPDFObjectHandle.hh
index ca135125..270c28bb 100644
--- a/include/qpdf/QPDFObjectHandle.hh
+++ b/include/qpdf/QPDFObjectHandle.hh
@@ -1178,13 +1178,13 @@ class QPDFObjectHandle
// looks like a name or indirect object from an actual name or indirect object.
// * JSON v2:
// * Unicode strings and strings encoded with PDF Doc encoding that can be bidirectionally
- // mapped two Unicode (which is all strings without undefined characters) are represented
+ // mapped to Unicode (which is all strings without undefined characters) are represented
// as "u:" followed by the UTF-8 encoded string. Example:
// "u:potato".
// * All other strings are represented as "b:" followed by a hexadecimal encoding of the
// string. Example: "b:0102cacb"
// * Streams
- // * JSON v1: Only the stream's dictionary is encoded. There is no way tell a stream from a
+ // * JSON v1: Only the stream's dictionary is encoded. There is no way to tell a stream from a
// dictionary other than context.
// * JSON v2: A stream is encoded as {"dict": {...}} with the value being the encoding of the
// stream's dictionary. Since "dict" does not otherwise represent anything, this is
diff --git a/include/qpdf/qpdf-c.h b/include/qpdf/qpdf-c.h
index d4305602..f989ba15 100644
--- a/include/qpdf/qpdf-c.h
+++ b/include/qpdf/qpdf-c.h
@@ -21,21 +21,23 @@
#define QPDF_C_H
/*
- * This file defines a basic "C" API for qpdf. It provides access to a subset of the QPDF library's
+ * This file defines a basic "C" API for qpdf. It provides access to a subset of the QPDF library's
* capabilities to make them accessible to callers who can't handle calling C++ functions or working
- * with C++ classes. This may be especially useful to Windows users who are accessing the qpdf DLL
+ * with C++ classes. This may be especially useful to Windows users who are accessing the qpdf DLL
* directly or to other people programming in non-C/C++ languages that can call C code but not C++
- * code.
+ * code. Starting with qpdf 11.7, it is possible to write your own `extern "C"` functions that
+ * interoperate with the C API.
*
* There are several things to keep in mind when using the C API.
*
* Error handling is tricky because the underlying C++ API uses exception handling. See "ERROR
* HANDLING" below for a detailed explanation.
*
- * The C API is not as rich as the C++ API. For any operations that involve actually
- * manipulating PDF objects, you must use the C++ API. The C API is primarily useful for doing
- * basic transformations on PDF files similar to what you might do with the qpdf command-line
- * tool.
+ * The C API is not as rich as the C++ API. For many operations, you must use the C++ API. The C
+ * API is primarily useful for doing basic transformations on PDF files similar to what you
+ * might do with the qpdf command-line tool. You can write your own `extern "C"` functions in
+ * C++ that interoperate with the C API by using qpdf_c_get_qpdf and qpdf_c_wrap which were
+ * introduced in qpdf 11.7.0.
*
* These functions store their state in a qpdf_data object. Individual instances of qpdf_data
* are not thread-safe: although you may access different qpdf_data objects from different
@@ -990,6 +992,23 @@ extern "C" {
QPDF_ERROR_CODE qpdf_remove_page(qpdf_data qpdf, qpdf_oh page);
#ifdef __cplusplus
}
+
+// These C++ functions make it easier to write C++ code that interoperates with the C API.
+// See examples/extend-c-api.
+
+# include <functional>
+# include <memory>
+
+# include <qpdf/QPDF.hh>
+
+// Retrieve the real QPDF object attached to this qpdf_data.
+QPDF_DLL
+std::shared_ptr<QPDF> qpdf_c_get_qpdf(qpdf_data qpdf);
+
+// Wrap a C++ function that may throw an exception to translate the exception for retrieval using
+// the normal QPDF C API methods.
+QPDF_DLL
+QPDF_ERROR_CODE qpdf_c_wrap(qpdf_data qpdf, std::function<void()> fn);
#endif
#endif /* QPDF_C_H */
diff --git a/job.sums b/job.sums
index 1b718776..8ab0d576 100644
--- a/job.sums
+++ b/job.sums
@@ -14,4 +14,4 @@ libqpdf/qpdf/auto_job_json_decl.hh 06caa46eaf71db8a50c046f91866baa8087745a947431
libqpdf/qpdf/auto_job_json_init.hh 85ac7e5c66f14c767419823eac84bdea4bd72d690bfe12b533321e5708e644b7
libqpdf/qpdf/auto_job_schema.hh 5e0f5cb7d462716fe52548b2ae1a8eb6f3c900016e915140eea37f78cee45b2b
manual/_ext/qpdf.py 6add6321666031d55ed4aedf7c00e5662bba856dfcd66ccb526563bffefbb580
-manual/cli.rst 35d32800cee1871e74c85419c481cae1c544c8b0eb462df82cf373a32619ab73
+manual/cli.rst 4f2806f7cf77f167fd41b065a8916f02fdfaab35ad1a74587578bf2954228464
diff --git a/libqpdf/Buffer.cc b/libqpdf/Buffer.cc
index 3dddd5db..20453a40 100644
--- a/libqpdf/Buffer.cc
+++ b/libqpdf/Buffer.cc
@@ -27,6 +27,14 @@ Buffer::Members::Members(size_t size, unsigned char* buf, bool own_memory) :
}
}
+Buffer::Members::Members(std::string&& content) :
+ str(std::move(content)),
+ own_memory(false),
+ size(str.size()),
+ buf(reinterpret_cast<unsigned char*>(str.data()))
+{
+}
+
Buffer::Members::~Members()
{
if (this->own_memory) {
@@ -44,11 +52,21 @@ Buffer::Buffer(size_t size) :
{
}
+Buffer::Buffer(std::string&& content) :
+ m(new Members(std::move(content)))
+{
+}
+
Buffer::Buffer(unsigned char* buf, size_t size) :
m(new Members(size, buf, false))
{
}
+Buffer::Buffer(std::string& content) :
+ m(new Members(content.size(), reinterpret_cast<unsigned char*>(content.data()), false))
+{
+}
+
Buffer::Buffer(Buffer const& rhs)
{
assert(test_mode);
diff --git a/libqpdf/CMakeLists.txt b/libqpdf/CMakeLists.txt
index c6a122c6..eb30b622 100644
--- a/libqpdf/CMakeLists.txt
+++ b/libqpdf/CMakeLists.txt
@@ -590,10 +590,12 @@ if(INSTALL_CMAKE_PACKAGE)
install(EXPORT libqpdfTargets
NAMESPACE qpdf::
FILE libqpdfTargets.cmake
+ COMPONENT ${COMPONENT_DEV}
DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/qpdf)
install(FILES
${CMAKE_CURRENT_BINARY_DIR}/qpdfConfigVersion.cmake
${CMAKE_CURRENT_BINARY_DIR}/qpdfConfig.cmake
+ COMPONENT ${COMPONENT_DEV}
DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/qpdf)
endif()
diff --git a/libqpdf/Pl_Buffer.cc b/libqpdf/Pl_Buffer.cc
index 766c04b5..9994bedd 100644
--- a/libqpdf/Pl_Buffer.cc
+++ b/libqpdf/Pl_Buffer.cc
@@ -19,7 +19,7 @@ Pl_Buffer::~Pl_Buffer() // NOLINT (modernize-use-equals-default)
void
Pl_Buffer::write(unsigned char const* buf, size_t len)
{
- m->data.insert(m->data.end(), buf, buf + len);
+ m->data.append(reinterpret_cast<char const*>(buf), len);
m->ready = false;
if (getNext(true)) {
@@ -42,15 +42,20 @@ Pl_Buffer::getBuffer()
if (!m->ready) {
throw std::logic_error("Pl_Buffer::getBuffer() called when not ready");
}
+ auto* b = new Buffer(std::move(m->data));
+ m->data.clear();
+ return b;
+}
- auto size = m->data.size();
- auto* b = new Buffer(size);
- if (size > 0) {
- unsigned char* p = b->getBuffer();
- memcpy(p, m->data.data(), size);
+std::string
+Pl_Buffer::getString()
+{
+ if (!m->ready) {
+ throw std::logic_error("Pl_Buffer::getString() called when not ready");
}
+ auto s = std::move(m->data);
m->data.clear();
- return b;
+ return s;
}
std::shared_ptr<Buffer>
diff --git a/libqpdf/QPDF.cc b/libqpdf/QPDF.cc
index 473cf5f0..f6badc35 100644
--- a/libqpdf/QPDF.cc
+++ b/libqpdf/QPDF.cc
@@ -2413,29 +2413,23 @@ QPDF::pipeStreamData(
bool suppress_warnings,
bool will_retry)
{
- std::vector<std::shared_ptr<Pipeline>> to_delete;
+ std::unique_ptr<Pipeline> to_delete;
if (encp->encrypted) {
decryptStream(encp, file, qpdf_for_warning, pipeline, og, stream_dict, to_delete);
}
bool attempted_finish = false;
- bool success = false;
try {
file->seek(offset, SEEK_SET);
- char buf[10240];
- while (length > 0) {
- size_t to_read = (sizeof(buf) < length ? sizeof(buf) : length);
- size_t len = file->read(buf, to_read);
- if (len == 0) {
- throw damagedPDF(
- file, "", file->getLastOffset(), "unexpected EOF reading stream data");
- }
- length -= len;
- pipeline->write(buf, len);
+ auto buf = std::make_unique<char[]>(length);
+ if (auto read = file->read(buf.get(), length); read != length) {
+ throw damagedPDF(
+ file, "", offset + toO(read), "unexpected EOF reading stream data");
}
+ pipeline->write(buf.get(), length);
attempted_finish = true;
pipeline->finish();
- success = true;
+ return true;
} catch (QPDFExc& e) {
if (!suppress_warnings) {
qpdf_for_warning.warn(e);
@@ -2458,8 +2452,7 @@ QPDF::pipeStreamData(
file,
"",
file->getLastOffset(),
- "stream will be re-processed without"
- " filtering to avoid data loss"));
+ "stream will be re-processed without filtering to avoid data loss"));
}
}
}
@@ -2470,7 +2463,7 @@ QPDF::pipeStreamData(
// ignore
}
}
- return success;
+ return false ;
}
bool
diff --git a/libqpdf/QPDFAcroFormDocumentHelper.cc b/libqpdf/QPDFAcroFormDocumentHelper.cc
index 5a54bf75..f2daa0c7 100644
--- a/libqpdf/QPDFAcroFormDocumentHelper.cc
+++ b/libqpdf/QPDFAcroFormDocumentHelper.cc
@@ -584,8 +584,7 @@ QPDFAcroFormDocumentHelper::adjustDefaultAppearances(
ResourceReplacer rr(dr_map, rf.getNamesByResourceType());
Pl_Buffer buf_pl("filtered DA");
da_stream.filterAsContents(&rr, &buf_pl);
- auto buf = buf_pl.getBufferSharedPointer();
- std::string new_da(reinterpret_cast<char*>(buf->getBuffer()), buf->getSize());
+ std::string new_da = buf_pl.getString();
obj.replaceKey("/DA", QPDFObjectHandle::newString(new_da));
}
diff --git a/libqpdf/QPDFObjectHandle.cc b/libqpdf/QPDFObjectHandle.cc
index d5ac137a..d543f98e 100644
--- a/libqpdf/QPDFObjectHandle.cc
+++ b/libqpdf/QPDFObjectHandle.cc
@@ -1708,8 +1708,7 @@ QPDFObjectHandle::pipeContentStreams(
need_newline = (lc.getLastChar() != static_cast<unsigned char>('\n'));
QTC::TC("qpdf", "QPDFObjectHandle need_newline", need_newline ? 0 : 1);
}
- std::unique_ptr<Buffer> b(buf.getBuffer());
- p->write(b->getBuffer(), b->getSize());
+ p->writeString(buf.getString());
p->finish();
}
diff --git a/libqpdf/QPDFPageObjectHelper.cc b/libqpdf/QPDFPageObjectHelper.cc
index fd6e5215..54bb5cac 100644
--- a/libqpdf/QPDFPageObjectHelper.cc
+++ b/libqpdf/QPDFPageObjectHelper.cc
@@ -175,14 +175,11 @@ InlineImageTracker::handleToken(QPDFTokenizer::Token const& token)
size_t len = image_data.length();
if (len >= this->min_size) {
QTC::TC("qpdf", "QPDFPageObjectHelper externalize inline image");
- Pl_Buffer b("image_data");
- b.writeString(image_data);
- b.finish();
QPDFObjectHandle dict = convertIIDict(QPDFObjectHandle::parse(dict_str));
dict.replaceKey("/Length", QPDFObjectHandle::newInteger(QIntC::to_longlong(len)));
std::string name = resources.getUniqueResourceName("/IIm", this->min_suffix);
QPDFObjectHandle image =
- QPDFObjectHandle::newStream(this->qpdf, b.getBufferSharedPointer());
+ QPDFObjectHandle::newStream(this->qpdf, std::make_shared<Buffer>(std::move(image_data)));
image.replaceDict(dict);
resources.getKey("/XObject").replaceKey(name, image);
write(name);
diff --git a/libqpdf/QPDFWriter.cc b/libqpdf/QPDFWriter.cc
index db3b42e0..981fc755 100644
--- a/libqpdf/QPDFWriter.cc
+++ b/libqpdf/QPDFWriter.cc
@@ -1579,10 +1579,7 @@ QPDFWriter::unparseObject(
m->cur_data_key.length());
pl.writeString(val);
pl.finish();
- auto buf = bufpl.getBufferSharedPointer();
- val = QPDF_String(
- std::string(reinterpret_cast<char*>(buf->getBuffer()), buf->getSize()))
- .unparse(true);
+ val = QPDF_String(bufpl.getString()).unparse(true);
} else {
auto tmp_ph = QUtil::make_unique_cstr(val);
char* tmp = tmp_ph.get();
@@ -1661,8 +1658,7 @@ QPDFWriter::writeObjectStream(QPDFObjectHandle object)
// Set up a stream to write the stream data into a buffer.
Pipeline* next = pushPipeline(new Pl_Buffer("object stream"));
- if ((m->compress_streams || (m->stream_decode_level == qpdf_dl_none)) &&
- (!m->qdf_mode)) {
+ if (m->compress_streams && !m->qdf_mode) {
compressed = true;
next =
pushPipeline(new Pl_Flate("compress object stream", next, Pl_Flate::a_deflate));
@@ -2293,15 +2289,20 @@ QPDFWriter::writeHintStream(int hint_id)
std::shared_ptr<Buffer> hint_buffer;
int S = 0;
int O = 0;
+ bool compressed = (m->compress_streams && !m->qdf_mode);
QPDF::Writer::generateHintStream(
- m->pdf, m->xref, m->lengths, m->obj_renumber_no_gen, hint_buffer, S, O);
+ m->pdf, m->xref, m->lengths, m->obj_renumber_no_gen, hint_buffer, S, O, compressed);
openObject(hint_id);
setDataKey(hint_id);
size_t hlen = hint_buffer->getSize();
- writeString("<< /Filter /FlateDecode /S ");
+ writeString("<< ");
+ if (compressed) {
+ writeString("/Filter /FlateDecode ");
+ }
+ writeString("/S ");
writeString(std::to_string(S));
if (O) {
writeString(" /O ");
@@ -2420,7 +2421,7 @@ QPDFWriter::writeXRefStream(
Pipeline* p = pushPipeline(new Pl_Buffer("xref stream"));
bool compressed = false;
- if ((m->compress_streams || (m->stream_decode_level == qpdf_dl_none)) && (!m->qdf_mode)) {
+ if (m->compress_streams && !m->qdf_mode) {
compressed = true;
if (!skip_compression) {
// Write the stream dictionary for compression but don't actually compress. This helps
diff --git a/libqpdf/QPDF_Stream.cc b/libqpdf/QPDF_Stream.cc
index 45d6fb70..a43d91ff 100644
--- a/libqpdf/QPDF_Stream.cc
+++ b/libqpdf/QPDF_Stream.cc
@@ -216,29 +216,28 @@ QPDF_Stream::getStreamJSON(
auto dict = this->stream_dict;
JSON result = JSON::makeDictionary();
if (json_data != qpdf_sj_none) {
- std::shared_ptr<Buffer> buf;
+ Pl_Discard discard;
+ Pl_Buffer buf_pl{"stream data"};
+ // buf_pl contains valid data and is ready for retrieval of the data.
+ bool buf_pl_ready = false;
bool filtered = false;
bool filter = (decode_level != qpdf_dl_none);
for (int attempt = 1; attempt <= 2; ++attempt) {
- Pl_Discard discard;
- std::shared_ptr<Pl_Buffer> buf_pl;
- Pipeline* data_pipeline = nullptr;
+ Pipeline* data_pipeline = &discard;
if (json_data == qpdf_sj_file) {
// We need to capture the data to write
- buf_pl = std::make_shared<Pl_Buffer>("stream data");
- data_pipeline = buf_pl.get();
- } else {
- data_pipeline = &discard;
+ data_pipeline = &buf_pl;
}
bool succeeded =
pipeStreamData(data_pipeline, &filtered, 0, decode_level, false, (attempt == 1));
- if ((!succeeded) || (filter && (!filtered))) {
+ if (!succeeded || (filter && !filtered)) {
// Try again
filter = false;
decode_level = qpdf_dl_none;
+ buf_pl.getString(); // reset buf_pl
} else {
- if (buf_pl.get()) {
- buf = buf_pl->getBufferSharedPointer();
+ if (json_data == qpdf_sj_file) {
+ buf_pl_ready = true;
}
break;
}
@@ -252,10 +251,10 @@ QPDF_Stream::getStreamJSON(
}
if (json_data == qpdf_sj_file) {
result.addDictionaryMember("datafile", JSON::makeString(data_filename));
- if (!buf.get()) {
+ if (!buf_pl_ready) {
throw std::logic_error("QPDF_Stream: failed to get stream data in json file mode");
}
- p->write(buf->getBuffer(), buf->getSize());
+ p->writeString(buf_pl.getString());
} else if (json_data == qpdf_sj_inline) {
result.addDictionaryMember(
"data", JSON::makeBlob(StreamBlobProvider(this, decode_level)));
diff --git a/libqpdf/QPDF_encryption.cc b/libqpdf/QPDF_encryption.cc
index b5cc44ee..1dd7b963 100644
--- a/libqpdf/QPDF_encryption.cc
+++ b/libqpdf/QPDF_encryption.cc
@@ -229,13 +229,11 @@ process_with_aes(
aes.writeString(data);
}
aes.finish();
- auto bufp = buffer.getBufferSharedPointer();
if (outlength == 0) {
- outlength = bufp->getSize();
+ return buffer.getString();
} else {
- outlength = std::min(outlength, bufp->getSize());
+ return buffer.getString().substr(0, outlength);
}
- return {reinterpret_cast<char*>(bufp->getBuffer()), outlength};
}
static std::string
@@ -1021,8 +1019,7 @@ QPDF::decryptString(std::string& str, QPDFObjGen const& og)
key.length());
pl.writeString(str);
pl.finish();
- auto buf = bufpl.getBufferSharedPointer();
- str = std::string(reinterpret_cast<char*>(buf->getBuffer()), buf->getSize());
+ str = bufpl.getString();
} else {
QTC::TC("qpdf", "QPDF_encryption rc4 decode string");
size_t vlen = str.length();
@@ -1041,6 +1038,9 @@ QPDF::decryptString(std::string& str, QPDFObjGen const& og)
}
}
+// Prepend a decryption pipeline to 'pipeline'. The decryption pipeline (returned as
+// 'decrypt_pipeline' must be owned by the caller to ensure that it stays alive while the pipeline
+// is in use.
void
QPDF::decryptStream(
std::shared_ptr<EncryptionParameters> encp,
@@ -1049,7 +1049,7 @@ QPDF::decryptStream(
Pipeline*& pipeline,
QPDFObjGen const& og,
QPDFObjectHandle& stream_dict,
- std::vector<std::shared_ptr<Pipeline>>& heap)
+ std::unique_ptr<Pipeline>& decrypt_pipeline)
{
std::string type;
if (stream_dict.getKey("/Type").isName()) {
@@ -1085,8 +1085,7 @@ QPDF::decryptStream(
crypt_params.getKey("/Name").isName()) {
QTC::TC("qpdf", "QPDF_encrypt crypt array");
method = interpretCF(encp, crypt_params.getKey("/Name"));
- method_source = "stream's Crypt "
- "decode parameters (array)";
+ method_source = "stream's Crypt decode parameters (array)";
}
}
}
@@ -1135,10 +1134,9 @@ QPDF::decryptStream(
}
}
std::string key = getKeyForObject(encp, og, use_aes);
- std::shared_ptr<Pipeline> new_pipeline;
if (use_aes) {
QTC::TC("qpdf", "QPDF_encryption aes decode stream");
- new_pipeline = std::make_shared<Pl_AES_PDF>(
+ decrypt_pipeline = std::make_unique<Pl_AES_PDF>(
"AES stream decryption",
pipeline,
false,
@@ -1146,14 +1144,13 @@ QPDF::decryptStream(
key.length());
} else {
QTC::TC("qpdf", "QPDF_encryption rc4 decode stream");
- new_pipeline = std::make_shared<Pl_RC4>(
+ decrypt_pipeline = std::make_unique<Pl_RC4>(
"RC4 stream decryption",
pipeline,
QUtil::unsigned_char_pointer(key),
toI(key.length()));
}
- pipeline = new_pipeline.get();
- heap.push_back(new_pipeline);
+ pipeline = decrypt_pipeline.get();
}
void
diff --git a/libqpdf/QPDF_linearization.cc b/libqpdf/QPDF_linearization.cc
index 469b9933..1657d54a 100644
--- a/libqpdf/QPDF_linearization.cc
+++ b/libqpdf/QPDF_linearization.cc
@@ -1748,10 +1748,10 @@ QPDF::writeHSharedObject(BitWriter& w)
void
QPDF::writeHGeneric(BitWriter& w, HGeneric& t)
{
- w.writeBitsInt(t.first_object, 32); // 1
- w.writeBits(toULL(t.first_object_offset), 32); // 2
- w.writeBitsInt(t.nobjects, 32); // 3
- w.writeBitsInt(t.group_length, 32); // 4
+ w.writeBitsInt(t.first_object, 32); // 1
+ w.writeBits(toULL(t.first_object_offset), 32); // 2
+ w.writeBitsInt(t.nobjects, 32); // 3
+ w.writeBitsInt(t.group_length, 32); // 4
}
void
@@ -1761,7 +1761,8 @@ QPDF::generateHintStream(
std::map<int, int> const& obj_renumber,
std::shared_ptr<Buffer>& hint_buffer,
int& S,
- int& O)
+ int& O,
+ bool compressed)
{
// Populate actual hint table values
calculateHPageOffset(xref, lengths, obj_renumber);
@@ -1771,8 +1772,14 @@ QPDF::generateHintStream(
// Write the hint stream itself into a compressed memory buffer. Write through a counter so we
// can get offsets.
Pl_Buffer hint_stream("hint stream");
- Pl_Flate f("compress hint stream", &hint_stream, Pl_Flate::a_deflate);
- Pl_Count c("count", &f);
+ Pipeline* next = &hint_stream;
+ std::shared_ptr<Pipeline> flate;
+ if (compressed) {
+ flate =
+ std::make_shared<Pl_Flate>("compress hint stream", &hint_stream, Pl_Flate::a_deflate);
+ next = flate.get();
+ }
+ Pl_Count c("count", next);
BitWriter w(&c);
writeHPageOffset(w);
diff --git a/libqpdf/SF_FlateLzwDecode.cc b/libqpdf/SF_FlateLzwDecode.cc
index db663429..a291145f 100644
--- a/libqpdf/SF_FlateLzwDecode.cc
+++ b/libqpdf/SF_FlateLzwDecode.cc
@@ -11,7 +11,7 @@ SF_FlateLzwDecode::SF_FlateLzwDecode(bool lzw) :
lzw(lzw),
// Initialize values to their defaults as per the PDF spec
predictor(1),
- columns(0),
+ columns(1),
colors(1),
bits_per_component(8),
early_code_change(true)
diff --git a/libqpdf/qpdf-c.cc b/libqpdf/qpdf-c.cc
index 1f7b85cb..b45b564b 100644
--- a/libqpdf/qpdf-c.cc
+++ b/libqpdf/qpdf-c.cc
@@ -1949,3 +1949,15 @@ qpdf_write_json(
});
return status;
}
+
+std::shared_ptr<QPDF>
+qpdf_c_get_qpdf(qpdf_data qpdf)
+{
+ return qpdf->qpdf;
+}
+
+QPDF_ERROR_CODE
+qpdf_c_wrap(qpdf_data qpdf, std::function<void()> fn)
+{
+ return trap_errors(qpdf, [&fn](qpdf_data) { fn(); });
+}
diff --git a/libtests/buffer.cc b/libtests/buffer.cc
index e62a37ca..1b87bb7d 100644
--- a/libtests/buffer.cc
+++ b/libtests/buffer.cc
@@ -35,6 +35,21 @@ main()
assert(bc2p != bc1p);
assert(bc2p[0] == 'R');
assert(bc2p[1] == 'W');
+
+ // Test Buffer(std:string&&)
+ Buffer bc3("QW");
+ unsigned char* bc3p = bc3.getBuffer();
+ Buffer bc4(bc3.copy());
+ bc3p[0] = 'R';
+ unsigned char* bc4p = bc4.getBuffer();
+ assert(bc4p != bc3p);
+ assert(bc4p[0] == 'Q');
+ assert(bc4p[1] == 'W');
+ bc4 = bc3.copy();
+ bc4p = bc4.getBuffer();
+ assert(bc4p != bc3p);
+ assert(bc4p[0] == 'R');
+ assert(bc4p[1] == 'W');
}
#ifdef _MSC_VER
@@ -62,6 +77,37 @@ main()
assert(bc2p != bc1p);
assert(bc2p[0] == 'R');
assert(bc2p[1] == 'W');
+
+ // Test Buffer(std:string&&)
+ Buffer bc3("QW");
+ unsigned char* bc3p = bc3.getBuffer();
+ Buffer bc4(bc3);
+ bc3p[0] = 'R';
+ unsigned char* bc4p = bc4.getBuffer();
+ assert(bc4p != bc3p);
+ assert(bc4p[0] == 'Q');
+ assert(bc4p[1] == 'W');
+ bc4 = bc3;
+ bc4p = bc4.getBuffer();
+ assert(bc4p != bc3p);
+ assert(bc2p[0] == 'R');
+ assert(bc2p[1] == 'W');
+
+ // Test Buffer(std:string&)
+ std::string s{"QW"};
+ Buffer bc5(s);
+ unsigned char* bc5p = bc5.getBuffer();
+ Buffer bc6(bc5);
+ bc5p[0] = 'R';
+ unsigned char* bc6p = bc6.getBuffer();
+ assert(bc6p != bc5p);
+ assert(bc6p[0] == 'Q');
+ assert(bc6p[1] == 'W');
+ bc6 = bc5;
+ bc6p = bc6.getBuffer();
+ assert(bc6p != bc5p);
+ assert(bc2p[0] == 'R');
+ assert(bc2p[1] == 'W');
}
#if (defined(__GNUC__) || defined(__clang__))
# pragma GCC diagnostic pop
@@ -82,6 +128,19 @@ main()
Buffer bm3 = std::move(bm2);
unsigned char* bm3p = bm3.getBuffer();
assert(bm3p == bm2p);
+
+ // Test Buffer(dtd::string&&)
+ Buffer bm4("QW");
+ unsigned char* bm4p = bm4.getBuffer();
+ Buffer bm5(std::move(bm4));
+ bm4p[0] = 'R';
+ unsigned char* bm5p = bm5.getBuffer();
+ assert(bm5p == bm4p);
+ assert(bm5p[0] == 'R');
+
+ Buffer bm6 = std::move(bm5);
+ unsigned char* bm6p = bm6.getBuffer();
+ assert(bm6p == bm5p);
}
try {
diff --git a/libtests/logger_c.c b/libtests/logger_c.c
index 4e9883a7..8f44864d 100644
--- a/libtests/logger_c.c
+++ b/libtests/logger_c.c
@@ -60,6 +60,7 @@ main()
do_run(
"{\"inputFile\": \"normal.pdf\","
" \"staticId\": \"\","
+ " \"streamData\": \"uncompress\","
" \"outputFile\": \"-\"}",
qpdf_exit_success);
@@ -75,9 +76,7 @@ main()
do_run("{\"inputFile\": \"2pages.pdf\", \"showNpages\": \"\"}", qpdf_exit_success);
do_run("{\"inputFile\": \"warning.pdf\", \"showNpages\": \"\"}", qpdf_exit_warning);
- do_run(
-
- "{\"inputFile\": \"missing.pdf\", \"showNpages\": \"\"}", qpdf_exit_error);
+ do_run("{\"inputFile\": \"missing.pdf\", \"showNpages\": \"\"}", qpdf_exit_error);
do_run(
"{\"inputFile\": \"attach.pdf\","
" \"showAttachment\": \"a\"}",
diff --git a/libtests/qtest/flate.test b/libtests/qtest/flate.test
index 3d99bc3a..c32b15b1 100644
--- a/libtests/qtest/flate.test
+++ b/libtests/qtest/flate.test
@@ -39,9 +39,13 @@ $td->runtest("run driver",
check_file("farbage", "a6449c61db5b0645c0693b7560b77a60");
-$td->runtest("compressed file correct",
- {$td->FILE => "farbage.1"},
- {$td->FILE => "compressed"});
+my $size_uncompressed = (stat("farbage"))[7];
+my $size_compressed = (stat("farbage.1"))[7];
+$td->runtest("compressed is smaller",
+ {$td->STRING =>
+ ($size_compressed < $size_uncompressed
+ ? "YES\n" : "$size_compressed $size_uncompressed\n")},
+ {$td->STRING => "YES\n"});
$td->runtest("uncompress filter works",
{$td->FILE => "farbage"},
diff --git a/libtests/qtest/logger/c-exp-save b/libtests/qtest/logger/c-exp-save
index b8c692ed..2636d712 100644
--- a/libtests/qtest/logger/c-exp-save
+++ b/libtests/qtest/logger/c-exp-save
Binary files differ
diff --git a/make_dist b/make_dist
index acbf71e3..020852eb 100755
--- a/make_dist
+++ b/make_dist
@@ -59,7 +59,6 @@ cd($tmpdir);
# Check versions
my $cmakeversion = get_version_from_cmake();
my $code_version = get_version_from_source();
-my $doc_version = get_version_from_manual();
my $version_error = 0;
if ($version ne $cmakeversion)
@@ -72,11 +71,6 @@ if ($version ne $code_version)
print "$whoami: QPDF.cc version = $code_version\n";
$version_error = 1;
}
-if ($version ne $doc_version)
-{
- print "$whoami: doc version = $doc_version\n";
- $version_error = 1;
-}
if ($version_error)
{
die "$whoami: version numbers are not consistent\n";
@@ -157,22 +151,6 @@ sub get_version_from_source
$code_version;
}
-sub get_version_from_manual
-{
- my $fh = safe_open("manual/conf.py");
- my $doc_version = 'unknown';
- while (<$fh>)
- {
- if (m/release = '([^\']+)\'/)
- {
- $doc_version = $1;
- last;
- }
- }
- $fh->close();
- $doc_version;
-}
-
sub safe_open
{
my $file = shift;
diff --git a/manual/cli.rst b/manual/cli.rst
index 4e01b65f..482d65f9 100644
--- a/manual/cli.rst
+++ b/manual/cli.rst
@@ -749,7 +749,7 @@ Related Options
signature but leaves its visual appearance intact.
Remove security restrictions associated with digitally signed PDF
- files. This may be combined with :qpdf:option:--decrypt: to allow
+ files. This may be combined with :qpdf:ref:--decrypt: to allow
free editing of previously signed/encrypted files. This option
invalidates the signature but leaves its visual appearance intact.
@@ -2176,7 +2176,7 @@ Related Options
created in this way are insecure since they can be opened without a
password, and restrictions will not be enforced. Users would
ordinarily never want to create such files. If you are using qpdf
- to intentionally created strange files for testing (a valid use of
+ to intentionally create strange files for testing (a valid use of
qpdf!), this option allows you to create such insecure files. This
option is only available with 256-bit encryption.
diff --git a/manual/conf.py b/manual/conf.py
index f0fd45c5..9d4eb5ec 100644
--- a/manual/conf.py
+++ b/manual/conf.py
@@ -15,8 +15,12 @@ sys.path.append(os.path.abspath("./_ext"))
project = 'QPDF'
copyright = '2005-2023, Jay Berkenbilt'
author = 'Jay Berkenbilt'
-# make_dist and the CI build lexically find the release version from this file.
-release = '11.6.3'
+here = os.path.dirname(os.path.realpath(__file__))
+with open(f'{here}/../CMakeLists.txt') as f:
+ for line in f.readlines():
+ if line.strip().startswith('VERSION '):
+ release = line.replace('VERSION', '').strip()
+ break
version = release
extensions = [
'sphinx_rtd_theme',
diff --git a/manual/release-notes.rst b/manual/release-notes.rst
index a03ce499..5e41fef7 100644
--- a/manual/release-notes.rst
+++ b/manual/release-notes.rst
@@ -38,6 +38,41 @@ Planned changes for future 12.x (subject to change):
.. x.y.z: not yet released
+11.7.0: not yet released
+ - Bug fixes:
+
+ - With ``--compress-streams=n``, qpdf was still compressing cross
+ reference streams, linearization hint streams, and object
+ streams. This has been fixed.
+
+ - Build Enhancements:
+
+ - The qpdf test suite now passes when qpdf is linked with an
+ alternative ``zlib`` implementation. There are no dependencies
+ anywhere in the qpdf test suite on any particular ``zlib``
+ output. Consult the ``ZLIB COMPATIBILITY`` section of
+ ``README-maintainer.md`` for a detailed explanation of how to
+ maintain this.
+
+ - Library Enhancements:
+
+ - Add C++ functions ``qpdf_c_wrap`` and ``qpdf_c_get_qpdf`` to the
+ C API to enable custom C++ code to interoperate more easily with
+ the the C API. See ``examples/extend-c-api``.
+
+ - Add methods to ``Buffer`` to work more easily and efficiently
+ with ``std::string``.
+
+11.6.4: December 10, 2023
+ - Bug fixes:
+
+ - When running ``cmake --install --component dev``, install cmake
+ files, which were previously omitted from the ``dev`` component
+
+ - Fix the Linux binary build to use older libraries so it
+ continues to work in AWS Lambda and other older execution
+ environments.
+
11.6.3: October 15, 2023
- Bug fixes:
@@ -48,7 +83,7 @@ Planned changes for future 12.x (subject to change):
content streams with default settings.
- The linearization specification precludes linearized files that
- require offets past the 4 GB mark. A bug in qpdf was preventing
+ require offsets past the 4 GB mark. A bug in qpdf was preventing
it from working when offsets had to pass the 2 GB mark. This has
been corrected.
diff --git a/qpdf/CMakeLists.txt b/qpdf/CMakeLists.txt
index d089957b..ae3d07d5 100644
--- a/qpdf/CMakeLists.txt
+++ b/qpdf/CMakeLists.txt
@@ -55,6 +55,7 @@ add_test(
--top ${qpdf_SOURCE_DIR}
--bin $<TARGET_FILE_DIR:qpdf>
--bin $<TARGET_FILE_DIR:libqpdf> # for Windows to find DLL
+ --bin $<TARGET_FILE_DIR:qpdf-test-compare>
--code ${qpdf_SOURCE_DIR}/qpdf
--color ${QTEST_COLOR}
--show-on-failure ${SHOW_FAILED_TEST_OUTPUT}
diff --git a/qpdf/qpdf-ctest.c b/qpdf/qpdf-ctest.c
index ba177444..d0c60558 100644
--- a/qpdf/qpdf-ctest.c
+++ b/qpdf/qpdf-ctest.c
@@ -200,6 +200,7 @@ test05(char const* infile, char const* password, char const* outfile, char const
qpdf_register_progress_reporter(qpdf, count_progress, (void*)&count);
qpdf_set_static_ID(qpdf, QPDF_TRUE);
qpdf_set_linearization(qpdf, QPDF_TRUE);
+ qpdf_set_compress_streams(qpdf, QPDF_FALSE); // Don't depend on zlib
qpdf_write(qpdf);
/* make sure progress reporter was called */
assert(count > 0);
diff --git a/qpdf/qtest/attachments.test b/qpdf/qtest/attachments.test
index 0d32ea0b..ccb985e1 100644
--- a/qpdf/qtest/attachments.test
+++ b/qpdf/qtest/attachments.test
@@ -207,8 +207,8 @@ $td->runtest("remove multiple attachments",
$td->EXIT_STATUS => 0},
$td->NORMALIZE_NEWLINES);
$td->runtest("check output",
- {$td->FILE => "a.pdf"},
- {$td->FILE => "remove-multiple-attachments.pdf"});
+ {$td->COMMAND => "qpdf-test-compare a.pdf remove-multiple-attachments.pdf"},
+ {$td->FILE => "remove-multiple-attachments.pdf", $td->EXIT_STATUS => 0});
$td->runtest("remove multiple attachments (json)",
{$td->COMMAND =>
"qpdf --job-json-file=remove-multiple-attachments.json"},
@@ -216,8 +216,8 @@ $td->runtest("remove multiple attachments (json)",
$td->EXIT_STATUS => 0},
$td->NORMALIZE_NEWLINES);
$td->runtest("check output",
- {$td->FILE => "b.pdf"},
- {$td->FILE => "remove-multiple-attachments.pdf"});
+ {$td->COMMAND => "qpdf-test-compare b.pdf remove-multiple-attachments.pdf"},
+ {$td->FILE => "remove-multiple-attachments.pdf", $td->EXIT_STATUS => 0});
cleanup();
$td->report($n_tests);
diff --git a/qpdf/qtest/c-api.test b/qpdf/qtest/c-api.test
index d0776b16..21233c82 100644
--- a/qpdf/qtest/c-api.test
+++ b/qpdf/qtest/c-api.test
@@ -36,8 +36,8 @@ foreach my $d (@capi)
{$td->STRING => "C test $n done\n", $td->EXIT_STATUS => 0},
$td->NORMALIZE_NEWLINES);
$td->runtest("check $description",
- {$td->FILE => "a.pdf"},
- {$td->FILE => $outfile});
+ {$td->COMMAND => "qpdf-test-compare a.pdf $outfile"},
+ {$td->FILE => $outfile, $td->EXIT_STATUS => 0});
}
$td->runtest("write to bad file name",
{$td->COMMAND => "qpdf-ctest 2 hybrid-xref.pdf '' /:a:/:b:"},
diff --git a/qpdf/qtest/coalesce-contents.test b/qpdf/qtest/coalesce-contents.test
index 57890f28..bd02a97e 100644
--- a/qpdf/qtest/coalesce-contents.test
+++ b/qpdf/qtest/coalesce-contents.test
@@ -46,8 +46,8 @@ $td->runtest("coalesce contents without qdf",
" --coalesce-contents coalesce.pdf a.pdf"},
{$td->STRING => "", $td->EXIT_STATUS => 0});
$td->runtest("check output",
- {$td->FILE => "a.pdf"},
- {$td->FILE => "coalesce-out.pdf"});
+ {$td->COMMAND => "qpdf-test-compare a.pdf coalesce-out.pdf"},
+ {$td->FILE => "coalesce-out.pdf", $td->EXIT_STATUS => 0});
cleanup();
$td->report($n_tests);
diff --git a/qpdf/qtest/copy-annotations.test b/qpdf/qtest/copy-annotations.test
index 6279ca5a..582d3709 100644
--- a/qpdf/qtest/copy-annotations.test
+++ b/qpdf/qtest/copy-annotations.test
@@ -110,8 +110,8 @@ $td->runtest("keeping some fields",
{$td->STRING => "", $td->EXIT_STATUS => 0},
$td->NORMALIZE_NEWLINES);
$td->runtest("check output",
- {$td->FILE => "a.pdf"},
- {$td->FILE => "kept-some-fields.pdf"});
+ {$td->COMMAND => "qpdf-test-compare a.pdf kept-some-fields.pdf"},
+ {$td->FILE => "kept-some-fields.pdf", $td->EXIT_STATUS => 0});
$td->runtest("not keeping any fields",
{$td->COMMAND =>
"qpdf --static-id kept-some-fields.pdf" .
diff --git a/qpdf/qtest/custom-pipeline.test b/qpdf/qtest/custom-pipeline.test
index 7cf94784..ac5edd8e 100644
--- a/qpdf/qtest/custom-pipeline.test
+++ b/qpdf/qtest/custom-pipeline.test
@@ -21,8 +21,8 @@ $td->runtest("output to custom pipeline",
{$td->STRING => "test 33 done\n", $td->EXIT_STATUS => 0},
$td->NORMALIZE_NEWLINES);
$td->runtest("check output",
- {$td->FILE => "a.pdf"},
- {$td->FILE => "custom-pipeline.pdf"});
+ {$td->COMMAND => "qpdf-test-compare a.pdf custom-pipeline.pdf"},
+ {$td->FILE => "custom-pipeline.pdf", $td->EXIT_STATUS => 0});
cleanup();
$td->report($n_tests);
diff --git a/qpdf/qtest/dangling-refs.test b/qpdf/qtest/dangling-refs.test
index 18c2cf6b..5a431b83 100644
--- a/qpdf/qtest/dangling-refs.test
+++ b/qpdf/qtest/dangling-refs.test
@@ -24,8 +24,8 @@ foreach my $f (@dangling)
{$td->FILE => "$f-dangling.out", $td->EXIT_STATUS => 0},
$td->NORMALIZE_NEWLINES);
$td->runtest("check output",
- {$td->FILE => "a.pdf"},
- {$td->FILE => "$f-dangling-out.pdf"});
+ {$td->COMMAND => "qpdf-test-compare a.pdf $f-dangling-out.pdf"},
+ {$td->FILE => "$f-dangling-out.pdf", $td->EXIT_STATUS => 0});
}
cleanup();
$td->report($n_tests);
diff --git a/qpdf/qtest/decode-parameters.test b/qpdf/qtest/decode-parameters.test
index 8fed1a12..10ac64c1 100644
--- a/qpdf/qtest/decode-parameters.test
+++ b/qpdf/qtest/decode-parameters.test
@@ -34,8 +34,8 @@ $td->runtest("stream with indirect decode parms",
"qpdf --static-id indirect-decode-parms.pdf a.pdf"},
{$td->STRING => "", $td->EXIT_STATUS => 0});
$td->runtest("check file",
- {$td->FILE => "a.pdf"},
- {$td->FILE => "indirect-decode-parms-out.pdf"});
+ {$td->COMMAND => "qpdf-test-compare a.pdf indirect-decode-parms-out.pdf"},
+ {$td->FILE => "indirect-decode-parms-out.pdf", $td->EXIT_STATUS => 0});
$td->runtest("decode parameters empty list",
{$td->COMMAND => "qpdf --static-id empty-decode-parms.pdf a.pdf"},
diff --git a/qpdf/qtest/deterministic-id.test b/qpdf/qtest/deterministic-id.test
index 9aeb7f38..a975806a 100644
--- a/qpdf/qtest/deterministic-id.test
+++ b/qpdf/qtest/deterministic-id.test
@@ -2,6 +2,7 @@
require 5.008;
use warnings;
use strict;
+use File::Copy;
unshift(@INC, '.');
require qpdf_test_helpers;
@@ -14,23 +15,41 @@ cleanup();
my $td = new TestDriver('deterministic-id');
-my $n_tests = 11;
+my $n_tests = 19;
+
+# Do not use qpdf-test-compare in this test suite since it ignores
+# /ID[1].
foreach my $d ('nn', 'ny', 'yn', 'yy')
{
my $linearize = ($d =~ m/^y/);
my $ostream = ($d =~ m/y$/);
- $td->runtest("deterministic ID: linearize/ostream=$d",
- {$td->COMMAND =>
- "qpdf -deterministic-id" .
- ($linearize ? " -linearize" : "") .
- " -object-streams=" . ($ostream ? "generate" : "disable") .
- " deterministic-id-in.pdf a.pdf"},
- {$td->STRING => "",
- $td->EXIT_STATUS => 0});
+ # The deterministic ID is a function of all the data in the file.
+ # As such, it is affected by which zlib implementation is in use.
+ # The important thing is that the ID is the same if a file is
+ # generated the same way more than once, so rather than comparing
+ # the output file to a known output, compare subsequent outputs
+ # with each other.
+ foreach my $out ('a.pdf', 'b.pdf')
+ {
+ $td->runtest("deterministic ID: linearize/ostream=$d",
+ {$td->COMMAND =>
+ "qpdf -deterministic-id" .
+ ($linearize ? " -linearize" : "") .
+ " -object-streams=" . ($ostream ? "generate" : "disable") .
+ " deterministic-id-in.pdf $out"},
+ {$td->STRING => "",
+ $td->EXIT_STATUS => 0});
+ }
$td->runtest("compare files",
{$td->FILE => "a.pdf"},
- {$td->FILE => "deterministic-id-$d.pdf"});
+ {$td->FILE => "b.pdf"});
+ check_id('a.pdf');
+ if ($d eq 'nn')
+ {
+ # Save for the C API test
+ copy("a.pdf", 'c.pdf');
+ }
}
$td->runtest("deterministic ID with encryption",
@@ -49,7 +68,27 @@ $td->runtest("deterministic ID (C API)",
$td->NORMALIZE_NEWLINES);
$td->runtest("compare files",
{$td->FILE => "a.pdf"},
- {$td->FILE => "deterministic-id-nn.pdf"});
+ {$td->FILE => "c.pdf"});
cleanup();
$td->report($n_tests);
+
+sub check_id
+{
+ my $f = shift;
+ chomp(my $id = `qpdf --show-object=trailer $f`);
+ if ($id =~ m,.*/ID \[ <(9b1c69409fc9a5f50e44b9588e3e60f8)> <(.{32})>,)
+ {
+ my $id0 = $1;
+ my $id1 = $2;
+ $td->runtest("ID fields differ",
+ {$td->STRING => $id0 ne $id1 ? "YES\n" : "$id0 $id1\n"},
+ {$td->STRING => "YES\n"});
+ }
+ else
+ {
+ $td->runtest("checked ID",
+ {$td->STRING => "YES\n"},
+ {$td->STRING => "$id\n"});
+ }
+}
diff --git a/qpdf/qtest/encryption-parameters.test b/qpdf/qtest/encryption-parameters.test
index f6d852c0..eaf795f3 100644
--- a/qpdf/qtest/encryption-parameters.test
+++ b/qpdf/qtest/encryption-parameters.test
@@ -37,7 +37,8 @@ foreach my $file (qw(short-id long-id))
$td->runtest("linearize $file.pdf",
{$td->COMMAND =>
- "qpdf --deterministic-id --linearize $file.pdf a.pdf"},
+ "qpdf --deterministic-id --compress-streams=n" .
+ " --linearize $file.pdf a.pdf"},
{$td->STRING => "",
$td->EXIT_STATUS => 0},
$td->NORMALIZE_NEWLINES);
diff --git a/qpdf/qtest/encryption.test b/qpdf/qtest/encryption.test
index 672eb995..fb4f993b 100644
--- a/qpdf/qtest/encryption.test
+++ b/qpdf/qtest/encryption.test
@@ -373,9 +373,9 @@ $td->runtest("show-encryption works invalid password",
$td->NORMALIZE_NEWLINES);
my @cenc = (
- [11, 'hybrid-xref.pdf', "''", 'r2', "", ""],
- [12, 'hybrid-xref.pdf', "''", 'r3', "", ""],
- [15, 'hybrid-xref.pdf', "''", 'r4', "", ""],
+ [11, 'hybrid-xref.pdf', "''", 'r2', "", "user1"],
+ [12, 'hybrid-xref.pdf', "''", 'r3', "", "user2"],
+ [15, 'hybrid-xref.pdf', "''", 'r4', "", "user2"],
[17, 'hybrid-xref.pdf', "''", 'r5', "", "owner3"],
[18, 'hybrid-xref.pdf', "''", 'r6', "", "user4"],
[13, 'c-r2.pdf', 'user1', 'decrypt with user',
@@ -404,8 +404,8 @@ foreach my $d (@cenc)
if (-f $pdf_outfile)
{
$td->runtest("check $description content",
- {$td->FILE => "a.pdf"},
- {$td->FILE => $pdf_outfile});
+ {$td->COMMAND => "qpdf-test-compare a.pdf $pdf_outfile $checkpass"},
+ {$td->FILE => $pdf_outfile, $td->EXIT_STATUS => 0});
}
else
{
@@ -413,7 +413,8 @@ foreach my $d (@cenc)
# /Perms static, so we have no way to predictably create a
# /V=5 encrypted file. It's not worth adding this...the test
# suite is adequate without having a statically predictable
- # file.
+ # file. (qpdf-test-compare ignores /Perms, but it's not worth
+ # adding output files for these cases.)
$td->runtest("check $description",
{$td->COMMAND =>
"qpdf --check a.pdf --password=$checkpass"},
@@ -491,8 +492,8 @@ $td->runtest("convert encrypted to qdf",
" --qdf a.pdf b.qdf"},
{$td->STRING => "", $td->EXIT_STATUS => 0});
$td->runtest("compare files",
- {$td->FILE => 'a.qdf'},
- {$td->FILE => 'b.qdf'});
+ {$td->COMMAND => "qpdf-test-compare a.qdf b.qdf"},
+ {$td->FILE => 'b.qdf', $td->EXIT_STATUS => 0});
$td->runtest("linearize with AES and object streams",
{$td->COMMAND => "qpdf --encrypt '' o 128 --use-aes=y --" .
" --linearize --object-streams=generate enc-base.pdf a.pdf"},
@@ -564,8 +565,8 @@ foreach my $d (['--force-V4', 'V4'],
" enc-base.pdf a.pdf"},
{$td->STRING => "", $td->EXIT_STATUS => 0});
$td->runtest("check output",
- {$td->FILE => "a.pdf"},
- {$td->FILE => "$out.pdf"});
+ {$td->COMMAND => "qpdf-test-compare a.pdf $out.pdf"},
+ {$td->FILE => "$out.pdf", $td->EXIT_STATUS => 0});
$td->runtest("show encryption",
{$td->COMMAND => "qpdf --show-encryption a.pdf"},
{$td->FILE => "$out-encryption.out", $td->EXIT_STATUS => 0},
diff --git a/qpdf/qtest/error-condition.test b/qpdf/qtest/error-condition.test
index d9357a0f..097190e8 100644
--- a/qpdf/qtest/error-condition.test
+++ b/qpdf/qtest/error-condition.test
@@ -194,8 +194,8 @@ $td->runtest("xref loop with append",
$td->EXIT_STATUS => 3},
$td->NORMALIZE_NEWLINES);
$td->runtest("check output",
- {$td->FILE => "a.pdf"},
- {$td->FILE => "append-xref-loop-fixed.pdf"});
+ {$td->COMMAND => "qpdf-test-compare a.pdf append-xref-loop-fixed.pdf"},
+ {$td->FILE => "append-xref-loop-fixed.pdf", $td->EXIT_STATUS => 0});
$td->runtest("endobj not at newline",
{$td->COMMAND =>
@@ -204,8 +204,8 @@ $td->runtest("endobj not at newline",
$td->EXIT_STATUS => 3},
$td->NORMALIZE_NEWLINES);
$td->runtest("check output",
- {$td->FILE => "a.pdf"},
- {$td->FILE => "endobj-at-eol-fixed.pdf"});
+ {$td->COMMAND => "qpdf-test-compare a.pdf endobj-at-eol-fixed.pdf"},
+ {$td->FILE => "endobj-at-eol-fixed.pdf", $td->EXIT_STATUS => 0});
cleanup();
$td->report($n_tests);
diff --git a/qpdf/qtest/extensions-dictionary.test b/qpdf/qtest/extensions-dictionary.test
index b16cce33..d96b29f4 100644
--- a/qpdf/qtest/extensions-dictionary.test
+++ b/qpdf/qtest/extensions-dictionary.test
@@ -46,16 +46,16 @@ foreach my $input (@ext_inputs)
# Look at the actual file for a few cases to make sure
# qdf and non-qdf output are okay
$td->runtest("check file",
- {$td->FILE => "a.pdf"},
- {$td->FILE => "$base-$op-$version.pdf"});
+ {$td->COMMAND => "qpdf-test-compare a.pdf $base-$op-$version.pdf"},
+ {$td->FILE => "$base-$op-$version.pdf", $td->EXIT_STATUS => 0});
$td->runtest("$input: $op version to $version",
{$td->COMMAND =>
"qpdf --qdf --static-id" .
" --$op-version=$version $input a.qdf"},
{$td->STRING => "", $td->EXIT_STATUS => 0});
$td->runtest("check file",
- {$td->FILE => "a.qdf"},
- {$td->FILE => "$base-$op-$version.qdf"});
+ {$td->COMMAND => "qpdf-test-compare a.qdf $base-$op-$version.qdf"},
+ {$td->FILE => "$base-$op-$version.qdf", $td->EXIT_STATUS => 0});
}
}
}
diff --git a/qpdf/qtest/filter-abbreviations.test b/qpdf/qtest/filter-abbreviations.test
index cb552b87..82db5b1c 100644
--- a/qpdf/qtest/filter-abbreviations.test
+++ b/qpdf/qtest/filter-abbreviations.test
@@ -23,8 +23,8 @@ $td->runtest("stream filter abbreviations",
$td->EXIT_STATUS => 0},
$td->NORMALIZE_NEWLINES);
$td->runtest("check output",
- {$td->FILE => "a.pdf"},
- {$td->FILE => "filter-abbreviation.out"});
+ {$td->COMMAND => "qpdf-test-compare a.pdf filter-abbreviation.out"},
+ {$td->FILE => "filter-abbreviation.out", $td->EXIT_STATUS => 0});
cleanup();
$td->report($n_tests);
diff --git a/qpdf/qtest/form-xobject.test b/qpdf/qtest/form-xobject.test
index 3183a219..2a9bac83 100644
--- a/qpdf/qtest/form-xobject.test
+++ b/qpdf/qtest/form-xobject.test
@@ -94,8 +94,8 @@ $td->runtest("overlay on page with no resources",
{$td->STRING => "", $td->EXIT_STATUS => 0},
$td->NORMALIZE_NEWLINES);
$td->runtest("check overlay with no resources output",
- {$td->FILE => "a.pdf"},
- {$td->FILE => "overlay-no-resources.pdf"});
+ {$td->COMMAND => "qpdf-test-compare a.pdf overlay-no-resources.pdf"},
+ {$td->FILE => "overlay-no-resources.pdf", $td->EXIT_STATUS => 0});
cleanup();
$td->report($n_tests);
diff --git a/qpdf/qtest/inline-images.test b/qpdf/qtest/inline-images.test
index c8552ab3..20388da5 100644
--- a/qpdf/qtest/inline-images.test
+++ b/qpdf/qtest/inline-images.test
@@ -68,8 +68,8 @@ $td->runtest("named colorspace",
{$td->STRING => "", $td->EXIT_STATUS => 0},
$td->NORMALIZE_NEWLINES);
$td->runtest("check output",
- {$td->FILE => "a.pdf"},
- {$td->FILE => "inline-image-colorspace-lookup-out.pdf"});
+ {$td->COMMAND => "qpdf-test-compare a.pdf inline-image-colorspace-lookup-out.pdf"},
+ {$td->FILE => "inline-image-colorspace-lookup-out.pdf", $td->EXIT_STATUS => 0});
my @eii_tests = (
diff --git a/qpdf/qtest/linearize-pass1.test b/qpdf/qtest/linearize-pass1.test
index dfdd2d9b..c59dd55f 100644
--- a/qpdf/qtest/linearize-pass1.test
+++ b/qpdf/qtest/linearize-pass1.test
@@ -18,6 +18,7 @@ my $n_tests = 3;
$td->runtest("linearize pass 1 file",
{$td->COMMAND => "qpdf --linearize --static-id" .
+ " --compress-streams=n" .
" --linearize-pass1=b.pdf minimal.pdf a.pdf"},
{$td->STRING => "", $td->EXIT_STATUS => 0});
$td->runtest("check output",
diff --git a/qpdf/qtest/many-nulls.test b/qpdf/qtest/many-nulls.test
index c3eefa1f..744075f0 100644
--- a/qpdf/qtest/many-nulls.test
+++ b/qpdf/qtest/many-nulls.test
@@ -23,9 +23,8 @@ $td->runtest("create file with many nulls",
{$td->STRING => "", $td->EXIT_STATUS => 0},
$td->NORMALIZE_NEWLINES);
$td->runtest("compare output",
- {$td->FILE => "a.pdf"},
- {$td->FILE => "many-nulls.pdf"},
- $td->NORMALIZE_NEWLINES);
+ {$td->COMMAND => "qpdf-test-compare a.pdf many-nulls.pdf"},
+ {$td->FILE => "many-nulls.pdf", $td->EXIT_STATUS => 0});
$td->runtest("run check file",
{$td->COMMAND => "qpdf --check a.pdf"},
{$td->FILE => "many-nulls.out", $td->EXIT_STATUS => 0},
diff --git a/qpdf/qtest/merge-and-split.test b/qpdf/qtest/merge-and-split.test
index 8de1f9da..a0b72ead 100644
--- a/qpdf/qtest/merge-and-split.test
+++ b/qpdf/qtest/merge-and-split.test
@@ -39,8 +39,8 @@ $td->runtest("merge three files",
# as well as 20-pages have text on page n (from 1) that shows its page
# position from 0, so page 1 says it's page 0.
$td->runtest("check output",
- {$td->FILE => "a.pdf"},
- {$td->FILE => "merge-three-files-1.pdf"});
+ {$td->COMMAND => "qpdf-test-compare a.pdf merge-three-files-1.pdf"},
+ {$td->FILE => "merge-three-files-1.pdf", $td->EXIT_STATUS => 0});
# Select the same pages but add them to an empty file
$td->runtest("merge three files",
{$td->COMMAND => "qpdf --empty a.pdf" .
@@ -49,8 +49,8 @@ $td->runtest("merge three files",
# Manually verified about this file: it has the same pages but does
# not contain outlines or other things from the original file.
$td->runtest("check output",
- {$td->FILE => "a.pdf"},
- {$td->FILE => "merge-three-files-2.pdf"});
+ {$td->COMMAND => "qpdf-test-compare a.pdf merge-three-files-2.pdf"},
+ {$td->FILE => "merge-three-files-2.pdf", $td->EXIT_STATUS => 0});
$td->runtest("avoid respecification of password",
{$td->COMMAND =>
"qpdf --empty a.pdf --copy-encryption=20-pages.pdf" .
@@ -69,16 +69,16 @@ $td->runtest("merge with implicit ranges",
" --static-id"},
{$td->STRING => "", $td->EXIT_STATUS => 0});
$td->runtest("check output",
- {$td->FILE => "a.pdf"},
- {$td->FILE => "merge-implicit-ranges.pdf"});
+ {$td->COMMAND => "qpdf-test-compare a.pdf merge-implicit-ranges.pdf"},
+ {$td->FILE => "merge-implicit-ranges.pdf", $td->EXIT_STATUS => 0});
$td->runtest("merge with . and implicit ranges",
{$td->COMMAND =>
"qpdf minimal.pdf a.pdf --pages minimal.pdf . 1 --" .
" --static-id"},
{$td->STRING => "", $td->EXIT_STATUS => 0});
$td->runtest("check output",
- {$td->FILE => "a.pdf"},
- {$td->FILE => "merge-dot-implicit-ranges.pdf"});
+ {$td->COMMAND => "qpdf-test-compare a.pdf merge-dot-implicit-ranges.pdf"},
+ {$td->FILE => "merge-dot-implicit-ranges.pdf", $td->EXIT_STATUS => 0});
$td->runtest("merge with multiple labels",
{$td->COMMAND =>
"qpdf --empty a.pdf" .
@@ -88,8 +88,8 @@ $td->runtest("merge with multiple labels",
" --static-id"},
{$td->STRING => "", $td->EXIT_STATUS => 0});
$td->runtest("check output",
- {$td->FILE => "a.pdf"},
- {$td->FILE => "merge-multiple-labels.pdf"});
+ {$td->COMMAND => "qpdf-test-compare a.pdf merge-multiple-labels.pdf"},
+ {$td->FILE => "merge-multiple-labels.pdf", $td->EXIT_STATUS => 0});
$td->runtest("remove labels",
{$td->COMMAND =>
"qpdf --empty a.pdf" .
@@ -100,8 +100,8 @@ $td->runtest("remove labels",
" --static-id"},
{$td->STRING => "", $td->EXIT_STATUS => 0});
$td->runtest("check output",
- {$td->FILE => "a.pdf"},
- {$td->FILE => "remove-labels.pdf"});
+ {$td->COMMAND => "qpdf-test-compare a.pdf remove-labels.pdf"},
+ {$td->FILE => "remove-labels.pdf", $td->EXIT_STATUS => 0});
$td->runtest("split with shared resources",
{$td->COMMAND =>
@@ -178,8 +178,8 @@ $td->runtest("force full page duplication",
{$td->STRING => "", $td->EXIT_STATUS => 0},
$td->NORMALIZE_NEWLINES);
$td->runtest("check output",
- {$td->FILE => "a.pdf"},
- {$td->FILE => "deep-duplicate-pages.pdf"});
+ {$td->COMMAND => "qpdf-test-compare a.pdf deep-duplicate-pages.pdf"},
+ {$td->FILE => "deep-duplicate-pages.pdf", $td->EXIT_STATUS => 0});
cleanup();
diff --git a/qpdf/qtest/newline-before-endstream.test b/qpdf/qtest/newline-before-endstream.test
index 667a0dd6..2066375e 100644
--- a/qpdf/qtest/newline-before-endstream.test
+++ b/qpdf/qtest/newline-before-endstream.test
@@ -36,8 +36,8 @@ foreach my $d (
{$td->STRING => "", $td->EXIT_STATUS => 0},
$td->NORMALIZE_NEWLINES);
$td->runtest("check output ($description)",
- {$td->FILE => "a.pdf"},
- {$td->FILE => "newline-before-endstream-$suffix.pdf"});
+ {$td->COMMAND => "qpdf-test-compare a.pdf newline-before-endstream-$suffix.pdf"},
+ {$td->FILE => "newline-before-endstream-$suffix.pdf", $td->EXIT_STATUS => 0});
if ($flags =~ /qdf/)
{
$td->runtest("fix-qdf",
@@ -52,8 +52,8 @@ $td->runtest("newline before endstream (C)",
{$td->STRING => "C test 22 done\n", $td->EXIT_STATUS => 0},
$td->NORMALIZE_NEWLINES);
$td->runtest("check output",
- {$td->FILE => "a.pdf"},
- {$td->FILE => "newline-before-endstream-nl.pdf"});
+ {$td->COMMAND => "qpdf-test-compare a.pdf newline-before-endstream-nl.pdf"},
+ {$td->FILE => "newline-before-endstream-nl.pdf", $td->EXIT_STATUS => 0});
cleanup();
$td->report($n_tests);
diff --git a/qpdf/qtest/page-errors.test b/qpdf/qtest/page-errors.test
index 2eceb37f..fdda4bc1 100644
--- a/qpdf/qtest/page-errors.test
+++ b/qpdf/qtest/page-errors.test
@@ -32,8 +32,8 @@ $td->runtest("handle page with inherited MediaBox",
{$td->STRING => "", $td->EXIT_STATUS => 0},
$td->NORMALIZE_NEWLINES);
$td->runtest("check output",
- {$td->FILE => "a.pdf"},
- {$td->FILE => "page-inherit-mediabox-out.pdf"});
+ {$td->COMMAND => "qpdf-test-compare a.pdf page-inherit-mediabox-out.pdf"},
+ {$td->FILE => "page-inherit-mediabox-out.pdf", $td->EXIT_STATUS => 0});
$td->runtest("check no type key for page nodes",
{$td->COMMAND => "qpdf --check no-pages-types.pdf"},
{$td->FILE => "no-pages-types.out", $td->EXIT_STATUS => 3},
@@ -43,8 +43,8 @@ $td->runtest("no type key for page nodes",
{$td->FILE => "no-pages-types-fix.out", $td->EXIT_STATUS => 3},
$td->NORMALIZE_NEWLINES);
$td->runtest("check output",
- {$td->FILE => "a-split-out-1.pdf"},
- {$td->FILE => "no-pages-types-fixed.pdf"});
+ {$td->COMMAND => "qpdf-test-compare a-split-out-1.pdf no-pages-types-fixed.pdf"},
+ {$td->FILE => "no-pages-types-fixed.pdf", $td->EXIT_STATUS => 0});
$td->runtest("detect loops in pages structure",
{$td->COMMAND => "qpdf --check pages-loop.pdf"},
{$td->FILE => "pages-loop.out", $td->EXIT_STATUS => 2},
diff --git a/qpdf/qtest/pages-tree.test b/qpdf/qtest/pages-tree.test
index 9950b675..eb416fba 100644
--- a/qpdf/qtest/pages-tree.test
+++ b/qpdf/qtest/pages-tree.test
@@ -18,14 +18,14 @@ my $n_tests = 17;
$td->runtest("linearize duplicated pages",
{$td->COMMAND =>
- "qpdf --static-id --linearize" .
+ "qpdf --static-id --linearize --compress-streams=n" .
" page_api_2.pdf a.pdf"},
{$td->FILE => "duplicate-page-warning.out",
$td->EXIT_STATUS => 3},
$td->NORMALIZE_NEWLINES);
$td->runtest("compare files",
- {$td->FILE => "a.pdf"},
- {$td->FILE => "linearize-duplicate-page.pdf"});
+ {$td->COMMAND => "qpdf-test-compare a.pdf linearize-duplicate-page.pdf"},
+ {$td->FILE => "linearize-duplicate-page.pdf", $td->EXIT_STATUS => 0});
$td->runtest("extract duplicated pages",
{$td->COMMAND =>
"qpdf --static-id page_api_2.pdf" .
@@ -34,16 +34,16 @@ $td->runtest("extract duplicated pages",
$td->EXIT_STATUS => 3},
$td->NORMALIZE_NEWLINES);
$td->runtest("compare files",
- {$td->FILE => "a.pdf"},
- {$td->FILE => "extract-duplicate-page.pdf"});
+ {$td->COMMAND => "qpdf-test-compare a.pdf extract-duplicate-page.pdf"},
+ {$td->FILE => "extract-duplicate-page.pdf", $td->EXIT_STATUS => 0});
$td->runtest("direct pages",
{$td->COMMAND =>
"qpdf --static-id direct-pages.pdf --pages . -- a.pdf"},
{$td->FILE => "direct-page-warning.out", $td->EXIT_STATUS => 3},
$td->NORMALIZE_NEWLINES);
$td->runtest("check output",
- {$td->FILE => "a.pdf"},
- {$td->FILE => "direct-pages-fixed.pdf"});
+ {$td->COMMAND => "qpdf-test-compare a.pdf direct-pages-fixed.pdf"},
+ {$td->FILE => "direct-pages-fixed.pdf", $td->EXIT_STATUS => 0});
$td->runtest("show direct pages",
{$td->COMMAND =>
"qpdf --show-pages direct-pages.pdf"},
diff --git a/qpdf/qtest/parsing.test b/qpdf/qtest/parsing.test
index 97cf9edf..bd1a7c6b 100644
--- a/qpdf/qtest/parsing.test
+++ b/qpdf/qtest/parsing.test
@@ -33,14 +33,14 @@ $td->runtest("extra header text",
{$td->FILE => "test-32.out", $td->EXIT_STATUS => 0},
$td->NORMALIZE_NEWLINES);
$td->runtest("check output",
- {$td->FILE => "a.pdf"},
- {$td->FILE => "extra-header-no-newline.pdf"});
+ {$td->COMMAND => "qpdf-test-compare a.pdf extra-header-no-newline.pdf"},
+ {$td->FILE => "extra-header-no-newline.pdf", $td->EXIT_STATUS => 0});
$td->runtest("check output",
{$td->FILE => "b.pdf"},
{$td->FILE => "extra-header-lin-no-newline.pdf"});
$td->runtest("check output",
- {$td->FILE => "c.pdf"},
- {$td->FILE => "extra-header-newline.pdf"});
+ {$td->COMMAND => "qpdf-test-compare c.pdf extra-header-newline.pdf"},
+ {$td->FILE => "extra-header-newline.pdf", $td->EXIT_STATUS => 0});
$td->runtest("check output",
{$td->FILE => "d.pdf"},
{$td->FILE => "extra-header-lin-newline.pdf"});
diff --git a/qpdf/qtest/preserve-unref.test b/qpdf/qtest/preserve-unref.test
index 3a290841..f5620559 100644
--- a/qpdf/qtest/preserve-unref.test
+++ b/qpdf/qtest/preserve-unref.test
@@ -20,22 +20,22 @@ $td->runtest("drop unused objects",
{$td->COMMAND => "qpdf --static-id unreferenced-objects.pdf a.pdf"},
{$td->STRING => "", $td->EXIT_STATUS => 0});
$td->runtest("check output",
- {$td->FILE => "a.pdf"},
- {$td->FILE => "unreferenced-dropped.pdf"});
+ {$td->COMMAND => "qpdf-test-compare a.pdf unreferenced-dropped.pdf"},
+ {$td->FILE => "unreferenced-dropped.pdf", $td->EXIT_STATUS => 0});
$td->runtest("keep unused objects",
{$td->COMMAND => "qpdf --static-id --preserve-unreferenced" .
" unreferenced-objects.pdf a.pdf"},
{$td->STRING => "", $td->EXIT_STATUS => 0});
$td->runtest("check output",
- {$td->FILE => "a.pdf"},
- {$td->FILE => "unreferenced-preserved.pdf"});
+ {$td->COMMAND => "qpdf-test-compare a.pdf unreferenced-preserved.pdf"},
+ {$td->FILE => "unreferenced-preserved.pdf", $td->EXIT_STATUS => 0});
$td->runtest("keep unused objects (C)",
{$td->COMMAND =>
"qpdf-ctest 21 unreferenced-objects.pdf '' a.pdf"},
{$td->STRING => "C test 21 done\n", $td->EXIT_STATUS => 0},
$td->NORMALIZE_NEWLINES);
$td->runtest("check output",
- {$td->FILE => "a.pdf"},
- {$td->FILE => "unreferenced-preserved.pdf"});
+ {$td->COMMAND => "qpdf-test-compare a.pdf unreferenced-preserved.pdf"},
+ {$td->FILE => "unreferenced-preserved.pdf", $td->EXIT_STATUS => 0});
cleanup();
$td->report($n_tests);
diff --git a/qpdf/qtest/qpdf-json.test b/qpdf/qtest/qpdf-json.test
index 2867f8a7..961b507a 100644
--- a/qpdf/qtest/qpdf-json.test
+++ b/qpdf/qtest/qpdf-json.test
@@ -294,31 +294,31 @@ $td->runtest("C API create from json file",
{$td->STRING => "C test 42 done\n", $td->EXIT_STATUS => 0},
$td->NORMALIZE_NEWLINES);
$td->runtest("check C API create from file",
- {$td->FILE => "a.pdf"},
- {$td->FILE => "qpdf-ctest-42-43.pdf"});
+ {$td->COMMAND => "qpdf-test-compare a.pdf qpdf-ctest-42-43.pdf"},
+ {$td->FILE => "qpdf-ctest-42-43.pdf", $td->EXIT_STATUS => 0});
$td->runtest("C API create from json buffer",
{$td->COMMAND => "qpdf-ctest 43 minimal.json '' a.pdf"},
{$td->STRING => "C test 43 done\n", $td->EXIT_STATUS => 0},
$td->NORMALIZE_NEWLINES);
$td->runtest("check C API create from buffer",
- {$td->FILE => "a.pdf"},
- {$td->FILE => "qpdf-ctest-42-43.pdf"});
+ {$td->COMMAND => "qpdf-test-compare a.pdf qpdf-ctest-42-43.pdf"},
+ {$td->FILE => "qpdf-ctest-42-43.pdf", $td->EXIT_STATUS => 0});
$td->runtest("C API update from json file",
{$td->COMMAND =>
"qpdf-ctest 44 minimal.pdf '' a.pdf minimal-update.json"},
{$td->STRING => "C test 44 done\n", $td->EXIT_STATUS => 0},
$td->NORMALIZE_NEWLINES);
$td->runtest("check C API update from file",
- {$td->FILE => "a.pdf"},
- {$td->FILE => "qpdf-ctest-44-45.pdf"});
+ {$td->COMMAND => "qpdf-test-compare a.pdf qpdf-ctest-44-45.pdf"},
+ {$td->FILE => "qpdf-ctest-44-45.pdf", $td->EXIT_STATUS => 0});
$td->runtest("C API update from json buffer",
{$td->COMMAND =>
"qpdf-ctest 45 minimal.pdf '' a.pdf minimal-update.json"},
{$td->STRING => "C test 45 done\n", $td->EXIT_STATUS => 0},
$td->NORMALIZE_NEWLINES);
$td->runtest("check C API update from buffer",
- {$td->FILE => "a.pdf"},
- {$td->FILE => "qpdf-ctest-44-45.pdf"});
+ {$td->COMMAND => "qpdf-test-compare a.pdf qpdf-ctest-44-45.pdf"},
+ {$td->FILE => "qpdf-ctest-44-45.pdf", $td->EXIT_STATUS => 0});
$td->runtest("C API write to JSON 1",
{$td->COMMAND =>
"qpdf-ctest 46 minimal.pdf '' a.json"},
diff --git a/qpdf/qtest/qpdf/c-linearized.pdf b/qpdf/qtest/qpdf/c-linearized.pdf
index dbe62ffe..23c11901 100644
--- a/qpdf/qtest/qpdf/c-linearized.pdf
+++ b/qpdf/qtest/qpdf/c-linearized.pdf
Binary files differ
diff --git a/qpdf/qtest/qpdf/deterministic-id-nn.pdf b/qpdf/qtest/qpdf/deterministic-id-nn.pdf
deleted file mode 100644
index 0b71a444..00000000
--- a/qpdf/qtest/qpdf/deterministic-id-nn.pdf
+++ /dev/null
@@ -1,1852 +0,0 @@
-%PDF-1.4
-%
-1 0 obj
-<< /Lang (en) /Metadata 3 0 R /PageLabels 4 0 R /Pages 5 0 R /Type /Catalog >>
-endobj
-2 0 obj
-<< /CreationDate (D:20150524172830-04'00') /Creator (Apache FOP Version 1.1) /Producer (Apache FOP Version 1.1) >>
-endobj
-3 0 obj
-<< /Subtype /XML /Type /Metadata /Length 858 >>
-stream
-<?xpacket begin="" id="W5M0MpCehiHzreSzNTczkc9d"?><x:xmpmeta xmlns:x="adobe:ns:meta/">
-<rdf:RDF xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#">
-<rdf:Description xmlns:dc="http://purl.org/dc/elements/1.1/" rdf:about="">
-<dc:format>application/pdf</dc:format>
-<dc:language>en</dc:language>
-<dc:date>2015-05-24T17:28:30-04:00</dc:date>
-</rdf:Description>
-<rdf:Description xmlns:pdf="http://ns.adobe.com/pdf/1.3/" rdf:about="">
-<pdf:Producer>Apache FOP Version 1.1</pdf:Producer>
-<pdf:PDFVersion>1.4</pdf:PDFVersion>
-</rdf:Description>
-<rdf:Description xmlns:xmp="http://ns.adobe.com/xap/1.0/" rdf:about="">
-<xmp:CreatorTool>Apache FOP Version 1.1</xmp:CreatorTool>
-<xmp:MetadataDate>2015-05-24T17:28:30-04:00</xmp:MetadataDate>
-<xmp:CreateDate>2015-05-24T17:28:30-04:00</xmp:CreateDate>
-</rdf:Description>
-</rdf:RDF>
-</x:xmpmeta><?xpacket end="r"?>
-endstream
-endobj
-4 0 obj
-<< /Nums [ 0 << /P (i) >> 1 << /P (ii) >> 2 << /P (iii) >> 3 << /P (iv) >> 4 << /P (1) >> 5 << /P (2) >> 6 << /P (3) >> 7 << /P (4) >> 8 << /P (5) >> 9 << /P (6) >> 10 << /P (7) >> 11 << /P (8) >> 12 << /P (9) >> 13 << /P (10) >> 14 << /P (11) >> 15 << /P (12) >> 16 << /P (13) >> 17 << /P (14) >> 18 << /P (15) >> 19 << /P (16) >> 20 << /P (17) >> 21 << /P (18) >> 22 << /P (19) >> 23 << /P (20) >> 24 << /P (21) >> 25 << /P (22) >> 26 << /P (23) >> 27 << /P (24) >> 28 << /P (25) >> 29 << /P (26) >> 30 << /P (27) >> 31 << /P (28) >> 32 << /P (29) >> 33 << /P (30) >> 34 << /P (31) >> 35 << /P (32) >> 36 << /P (33) >> 37 << /P (34) >> 38 << /P (35) >> 39 << /P (36) >> 40 << /P (37) >> 41 << /P (38) >> 42 << /P (39) >> ] >>
-endobj
-5 0 obj
-<< /Count 43 /Kids [ 6 0 R 7 0 R 8 0 R 9 0 R 10 0 R 11 0 R 12 0 R 13 0 R 14 0 R 15 0 R 16 0 R 17 0 R 18 0 R 19 0 R 20 0 R 21 0 R 22 0 R 23 0 R 24 0 R 25 0 R 26 0 R 27 0 R 28 0 R 29 0 R 30 0 R 31 0 R 32 0 R 33 0 R 34 0 R 35 0 R 36 0 R 37 0 R 38 0 R 39 0 R 40 0 R 41 0 R 42 0 R 43 0 R 44 0 R 45 0 R 46 0 R 47 0 R 48 0 R ] /Type /Pages >>
-endobj
-6 0 obj
-<< /BleedBox [ 0 0 612 792 ] /Contents 49 0 R /CropBox [ 0 0 612 792 ] /MediaBox [ 0 0 612 792 ] /Parent 5 0 R /Resources 50 0 R /TrimBox [ 0 0 612 792 ] /Type /Page >>
-endobj
-7 0 obj
-<< /BleedBox [ 0 0 612 792 ] /Contents 51 0 R /CropBox [ 0 0 612 792 ] /MediaBox [ 0 0 612 792 ] /Parent 5 0 R /Resources 50 0 R /TrimBox [ 0 0 612 792 ] /Type /Page >>
-endobj
-8 0 obj
-<< /Annots 52 0 R /BleedBox [ 0 0 612 792 ] /Contents 53 0 R /CropBox [ 0 0 612 792 ] /MediaBox [ 0 0 612 792 ] /Parent 5 0 R /Resources 50 0 R /TrimBox [ 0 0 612 792 ] /Type /Page >>
-endobj
-9 0 obj
-<< /Annots 54 0 R /BleedBox [ 0 0 612 792 ] /Contents 55 0 R /CropBox [ 0 0 612 792 ] /MediaBox [ 0 0 612 792 ] /Parent 5 0 R /Resources 50 0 R /TrimBox [ 0 0 612 792 ] /Type /Page >>
-endobj
-10 0 obj
-<< /BleedBox [ 0 0 612 792 ] /Contents 56 0 R /CropBox [ 0 0 612 792 ] /MediaBox [ 0 0 612 792 ] /Parent 5 0 R /Resources 50 0 R /TrimBox [ 0 0 612 792 ] /Type /Page >>
-endobj
-11 0 obj
-<< /Annots 57 0 R /BleedBox [ 0 0 612 792 ] /Contents 58 0 R /CropBox [ 0 0 612 792 ] /MediaBox [ 0 0 612 792 ] /Parent 5 0 R /Resources 50 0 R /TrimBox [ 0 0 612 792 ] /Type /Page >>
-endobj
-12 0 obj
-<< /BleedBox [ 0 0 612 792 ] /Contents 59 0 R /CropBox [ 0 0 612 792 ] /MediaBox [ 0 0 612 792 ] /Parent 5 0 R /Resources 50 0 R /TrimBox [ 0 0 612 792 ] /Type /Page >>
-endobj
-13 0 obj
-<< /Annots 60 0 R /BleedBox [ 0 0 612 792 ] /Contents 61 0 R /CropBox [ 0 0 612 792 ] /MediaBox [ 0 0 612 792 ] /Parent 5 0 R /Resources 50 0 R /TrimBox [ 0 0 612 792 ] /Type /Page >>
-endobj
-14 0 obj
-<< /BleedBox [ 0 0 612 792 ] /Contents 62 0 R /CropBox [ 0 0 612 792 ] /MediaBox [ 0 0 612 792 ] /Parent 5 0 R /Resources 50 0 R /TrimBox [ 0 0 612 792 ] /Type /Page >>
-endobj
-15 0 obj
-<< /BleedBox [ 0 0 612 792 ] /Contents 63 0 R /CropBox [ 0 0 612 792 ] /MediaBox [ 0 0 612 792 ] /Parent 5 0 R /Resources 50 0 R /TrimBox [ 0 0 612 792 ] /Type /Page >>
-endobj
-16 0 obj
-<< /BleedBox [ 0 0 612 792 ] /Contents 64 0 R /CropBox [ 0 0 612 792 ] /MediaBox [ 0 0 612 792 ] /Parent 5 0 R /Resources 50 0 R /TrimBox [ 0 0 612 792 ] /Type /Page >>
-endobj
-17 0 obj
-<< /Annots 65 0 R /BleedBox [ 0 0 612 792 ] /Contents 66 0 R /CropBox [ 0 0 612 792 ] /MediaBox [ 0 0 612 792 ] /Parent 5 0 R /Resources 50 0 R /TrimBox [ 0 0 612 792 ] /Type /Page >>
-endobj
-18 0 obj
-<< /BleedBox [ 0 0 612 792 ] /Contents 67 0 R /CropBox [ 0 0 612 792 ] /MediaBox [ 0 0 612 792 ] /Parent 5 0 R /Resources 50 0 R /TrimBox [ 0 0 612 792 ] /Type /Page >>
-endobj
-19 0 obj
-<< /Annots 68 0 R /BleedBox [ 0 0 612 792 ] /Contents 69 0 R /CropBox [ 0 0 612 792 ] /MediaBox [ 0 0 612 792 ] /Parent 5 0 R /Resources 50 0 R /TrimBox [ 0 0 612 792 ] /Type /Page >>
-endobj
-20 0 obj
-<< /BleedBox [ 0 0 612 792 ] /Contents 70 0 R /CropBox [ 0 0 612 792 ] /MediaBox [ 0 0 612 792 ] /Parent 5 0 R /Resources 50 0 R /TrimBox [ 0 0 612 792 ] /Type /Page >>
-endobj
-21 0 obj
-<< /BleedBox [ 0 0 612 792 ] /Contents 71 0 R /CropBox [ 0 0 612 792 ] /MediaBox [ 0 0 612 792 ] /Parent 5 0 R /Resources 50 0 R /TrimBox [ 0 0 612 792 ] /Type /Page >>
-endobj
-22 0 obj
-<< /BleedBox [ 0 0 612 792 ] /Contents 72 0 R /CropBox [ 0 0 612 792 ] /MediaBox [ 0 0 612 792 ] /Parent 5 0 R /Resources 50 0 R /TrimBox [ 0 0 612 792 ] /Type /Page >>
-endobj
-23 0 obj
-<< /BleedBox [ 0 0 612 792 ] /Contents 73 0 R /CropBox [ 0 0 612 792 ] /MediaBox [ 0 0 612 792 ] /Parent 5 0 R /Resources 50 0 R /TrimBox [ 0 0 612 792 ] /Type /Page >>
-endobj
-24 0 obj
-<< /BleedBox [ 0 0 612 792 ] /Contents 74 0 R /CropBox [ 0 0 612 792 ] /MediaBox [ 0 0 612 792 ] /Parent 5 0 R /Resources 50 0 R /TrimBox [ 0 0 612 792 ] /Type /Page >>
-endobj
-25 0 obj
-<< /BleedBox [ 0 0 612 792 ] /Contents 75 0 R /CropBox [ 0 0 612 792 ] /MediaBox [ 0 0 612 792 ] /Parent 5 0 R /Resources 50 0 R /TrimBox [ 0 0 612 792 ] /Type /Page >>
-endobj
-26 0 obj
-<< /BleedBox [ 0 0 612 792 ] /Contents 76 0 R /CropBox [ 0 0 612 792 ] /MediaBox [ 0 0 612 792 ] /Parent 5 0 R /Resources 50 0 R /TrimBox [ 0 0 612 792 ] /Type /Page >>
-endobj
-27 0 obj
-<< /BleedBox [ 0 0 612 792 ] /Contents 77 0 R /CropBox [ 0 0 612 792 ] /MediaBox [ 0 0 612 792 ] /Parent 5 0 R /Resources 50 0 R /TrimBox [ 0 0 612 792 ] /Type /Page >>
-endobj
-28 0 obj
-<< /Annots 78 0 R /BleedBox [ 0 0 612 792 ] /Contents 79 0 R /CropBox [ 0 0 612 792 ] /MediaBox [ 0 0 612 792 ] /Parent 5 0 R /Resources 50 0 R /TrimBox [ 0 0 612 792 ] /Type /Page >>
-endobj
-29 0 obj
-<< /Annots 80 0 R /BleedBox [ 0 0 612 792 ] /Contents 81 0 R /CropBox [ 0 0 612 792 ] /MediaBox [ 0 0 612 792 ] /Parent 5 0 R /Resources 50 0 R /TrimBox [ 0 0 612 792 ] /Type /Page >>
-endobj
-30 0 obj
-<< /BleedBox [ 0 0 612 792 ] /Contents 82 0 R /CropBox [ 0 0 612 792 ] /MediaBox [ 0 0 612 792 ] /Parent 5 0 R /Resources 50 0 R /TrimBox [ 0 0 612 792 ] /Type /Page >>
-endobj
-31 0 obj
-<< /Annots 83 0 R /BleedBox [ 0 0 612 792 ] /Contents 84 0 R /CropBox [ 0 0 612 792 ] /MediaBox [ 0 0 612 792 ] /Parent 5 0 R /Resources 50 0 R /TrimBox [ 0 0 612 792 ] /Type /Page >>
-endobj
-32 0 obj
-<< /BleedBox [ 0 0 612 792 ] /Contents 85 0 R /CropBox [ 0 0 612 792 ] /MediaBox [ 0 0 612 792 ] /Parent 5 0 R /Resources 50 0 R /TrimBox [ 0 0 612 792 ] /Type /Page >>
-endobj
-33 0 obj
-<< /BleedBox [ 0 0 612 792 ] /Contents 86 0 R /CropBox [ 0 0 612 792 ] /MediaBox [ 0 0 612 792 ] /Parent 5 0 R /Resources 50 0 R /TrimBox [ 0 0 612 792 ] /Type /Page >>
-endobj
-34 0 obj
-<< /Annots 87 0 R /BleedBox [ 0 0 612 792 ] /Contents 88 0 R /CropBox [ 0 0 612 792 ] /MediaBox [ 0 0 612 792 ] /Parent 5 0 R /Resources 50 0 R /TrimBox [ 0 0 612 792 ] /Type /Page >>
-endobj
-35 0 obj
-<< /BleedBox [ 0 0 612 792 ] /Contents 89 0 R /CropBox [ 0 0 612 792 ] /MediaBox [ 0 0 612 792 ] /Parent 5 0 R /Resources 50 0 R /TrimBox [ 0 0 612 792 ] /Type /Page >>
-endobj
-36 0 obj
-<< /BleedBox [ 0 0 612 792 ] /Contents 90 0 R /CropBox [ 0 0 612 792 ] /MediaBox [ 0 0 612 792 ] /Parent 5 0 R /Resources 50 0 R /TrimBox [ 0 0 612 792 ] /Type /Page >>
-endobj
-37 0 obj
-<< /BleedBox [ 0 0 612 792 ] /Contents 91 0 R /CropBox [ 0 0 612 792 ] /MediaBox [ 0 0 612 792 ] /Parent 5 0 R /Resources 50 0 R /TrimBox [ 0 0 612 792 ] /Type /Page >>
-endobj
-38 0 obj
-<< /BleedBox [ 0 0 612 792 ] /Contents 92 0 R /CropBox [ 0 0 612 792 ] /MediaBox [ 0 0 612 792 ] /Parent 5 0 R /Resources 50 0 R /TrimBox [ 0 0 612 792 ] /Type /Page >>
-endobj
-39 0 obj
-<< /BleedBox [ 0 0 612 792 ] /Contents 93 0 R /CropBox [ 0 0 612 792 ] /MediaBox [ 0 0 612 792 ] /Parent 5 0 R /Resources 50 0 R /TrimBox [ 0 0 612 792 ] /Type /Page >>
-endobj
-40 0 obj
-<< /Annots 94 0 R /BleedBox [ 0 0 612 792 ] /Contents 95 0 R /CropBox [ 0 0 612 792 ] /MediaBox [ 0 0 612 792 ] /Parent 5 0 R /Resources 50 0 R /TrimBox [ 0 0 612 792 ] /Type /Page >>
-endobj
-41 0 obj
-<< /Annots 96 0 R /BleedBox [ 0 0 612 792 ] /Contents 97 0 R /CropBox [ 0 0 612 792 ] /MediaBox [ 0 0 612 792 ] /Parent 5 0 R /Resources 50 0 R /TrimBox [ 0 0 612 792 ] /Type /Page >>
-endobj
-42 0 obj
-<< /BleedBox [ 0 0 612 792 ] /Contents 98 0 R /CropBox [ 0 0 612 792 ] /MediaBox [ 0 0 612 792 ] /Parent 5 0 R /Resources 50 0 R /TrimBox [ 0 0 612 792 ] /Type /Page >>
-endobj
-43 0 obj
-<< /BleedBox [ 0 0 612 792 ] /Contents 99 0 R /CropBox [ 0 0 612 792 ] /MediaBox [ 0 0 612 792 ] /Parent 5 0 R /Resources 50 0 R /TrimBox [ 0 0 612 792 ] /Type /Page >>
-endobj
-44 0 obj
-<< /Annots 100 0 R /BleedBox [ 0 0 612 792 ] /Contents 101 0 R /CropBox [ 0 0 612 792 ] /MediaBox [ 0 0 612 792 ] /Parent 5 0 R /Resources 50 0 R /TrimBox [ 0 0 612 792 ] /Type /Page >>
-endobj
-45 0 obj
-<< /Annots 102 0 R /BleedBox [ 0 0 612 792 ] /Contents 103 0 R /CropBox [ 0 0 612 792 ] /MediaBox [ 0 0 612 792 ] /Parent 5 0 R /Resources 50 0 R /TrimBox [ 0 0 612 792 ] /Type /Page >>
-endobj
-46 0 obj
-<< /BleedBox [ 0 0 612 792 ] /Contents 104 0 R /CropBox [ 0 0 612 792 ] /MediaBox [ 0 0 612 792 ] /Parent 5 0 R /Resources 50 0 R /TrimBox [ 0 0 612 792 ] /Type /Page >>
-endobj
-47 0 obj
-<< /BleedBox [ 0 0 612 792 ] /Contents 105 0 R /CropBox [ 0 0 612 792 ] /MediaBox [ 0 0 612 792 ] /Parent 5 0 R /Resources 50 0 R /TrimBox [ 0 0 612 792 ] /Type /Page >>
-endobj
-48 0 obj
-<< /Annots 106 0 R /BleedBox [ 0 0 612 792 ] /Contents 107 0 R /CropBox [ 0 0 612 792 ] /MediaBox [ 0 0 612 792 ] /Parent 5 0 R /Resources 50 0 R /TrimBox [ 0 0 612 792 ] /Type /Page >>
-endobj
-49 0 obj
-<< /Filter /FlateDecode /Length 225 >>
-stream
-xuMKA +rT1̵
- Pebk{ofWh&I3;c+ ~5 **Mck$?r_"s8`9@<eK ls"l}~hi7(C% FruCT^T0^g!E7SQ=͔gÙn5_Lœ0(eZPм}OǢњPSUendstream
-endobj
-50 0 obj
-<< /ColorSpace << /DefaultRGB 108 0 R >> /Font << /F10 109 0 R /F11 110 0 R /F12 111 0 R /F3 112 0 R /F4 113 0 R /F5 114 0 R /F6 115 0 R /F7 116 0 R /F9 117 0 R >> /ProcSet [ /PDF /ImageB /ImageC /Text ] >>
-endobj
-51 0 obj
-<< /Filter /FlateDecode /Length 336 >>
-stream
-xSMO@ﯘ&vjƶHUJ+Mf2ͼHB{L%x)IJ) CƂ$( pcHIV& r·v9 }hEGBg 0n#7Q/C#AAyچF 9p3c=q,s 0Dk')Zu)`t2ݴ_Ti-J0RIa| uP $.o@a8iFB=-|2|Wu+hq#-2Qx7kLF5]~..@3&<NzIv
-endobj
-52 0 obj
-[ 118 0 R 119 0 R 120 0 R 121 0 R 122 0 R 123 0 R 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 140 0 R 141 0 R 142 0 R 143 0 R 144 0 R 145 0 R 146 0 R 147 0 R 148 0 R 149 0 R 150 0 R 151 0 R 152 0 R 153 0 R 154 0 R 155 0 R 156 0 R 157 0 R 158 0 R 159 0 R 160 0 R 161 0 R 162 0 R 163 0 R 164 0 R 165 0 R 166 0 R 167 0 R 168 0 R 169 0 R 170 0 R 171 0 R 172 0 R 173 0 R 174 0 R 175 0 R 176 0 R 177 0 R 178 0 R 179 0 R 180 0 R 181 0 R 182 0 R 183 0 R 184 0 R 185 0 R 186 0 R 187 0 R 188 0 R 189 0 R 190 0 R 191 0 R 192 0 R 193 0 R 194 0 R 195 0 R 196 0 R 197 0 R 198 0 R 199 0 R 200 0 R 201 0 R 202 0 R 203 0 R ]
-endobj
-53 0 obj
-<< /Filter /FlateDecode /Length 15258 >>
-stream
-xOsdy>i=}ϿՄ-Yز/:zQ"!:Ȣ\,١sO&HIc;ʬ,A2_{<×_+>D=|ͮ>EW~_|ͯsxpſ?|wO'ť7/8?O3qyL?\a?ޓ_qo=κԇ?x7:Ox:O>xᛧ>|zGxSs<xG?}7#>~>\>~5[>gzYlG9UvUhm9)B8$RT+
-;KUuzJ}*|{M,Yd9r$I,Y.LjLuj LLLldȲe'N,;Yd9r$I,Y.\by>B-"#by>B-#dddddddȲe#F,;Yvd9r$I,'Y.\d2}Z,/ǷE,/G2}|{]2},,i4I$}>IsO'iWmwqc}ޡ.:~v{_=yo{dz1n5qܮtoN{
-uPݩ^RonTe#F,;Yvdr A,'YN\drze=IJbYX"ebYX*eeeeeee#Fm[ [%uT7ԣPTAuPM,Y.\bX!qe"Q2XF˨b,,,,,,,,Y6ldɲe'A,Yd9r"EK,<2C,e"Y2Xf% $$$F,Y^3jerN~uyY^YzxAl{.~f8w^:f8%#k]q9*ՍjA,EKRıT,U$KReY+=JuzJzHN5Yvdr A,'YNdrze=IJbYX"e-bYX*eeeeeeee#F,;Yvd9r A,'YN\drebX!qe"Q2XF˨ddddddddȲe#N,;Yvd9r$I,Y.\d2C,,bE,eV*Y2i4I$}>IsO'i4Ykkn;r6l[}l_||3=ro~wmn\wJ+yX-_gY-Ii|_KW[nTvS:Lu4iT.S]Hul)'=RN{p+y%=TTTTTTTT6Sme7<-[(f.S]Hut)'=եT\rRݓ]+.Lj3nTvS:Lu4iT.S]HuO})'=jRBYI5+f%լLj3bSQǽFqd|5bso;|c~fD8ƽ7#N嗗7'嗗αV<,///;!oO//;!OTvS:Lu0iT.S]Luj=HZRTk!ZHVRTk%ZM5L5L5L5M5M5Mj3fTvS:Lu0iTNS]LujAQH5
-F!(TjTS S S SMSMSMSMSmLj7nTS:Lu4iT.R̓T <H5RBYH5 f%լTm6[J-͖fKiRl)m6[̰[[k{O/G3ܛ,ǝfر>*za}~d|_.c~f}L:;;f:=N%A~$yX-_Kj3nTS:Lu4iT.S]G9QNJxT(70000444fT륙G}Iwgq7'gq妺Lu2E:yRT('}<Iu_/rS S S SMSMSMSmLj3nTS:Lu4iT.S]/G9KI^Hu_LrRݗӓjVRjaaaiiiiTuC(Ǻ40505|/~맗[{'~fz~%~͘wë́<=
-?~>Kzyr}fPDy^L0 {Yw; ˻q}koϗF7'#A[nTvS:Lu4iT.S]Hu|I9/%/wTΗWRݛrPnaaaiiiiTyyMjA8,˻Y-o2eTޔrRݛrPN{S+M9(70000444fTvSM0aTNSLu2E{SIuo!y!ս)多TjVRݛrHLuOXK*ˈϣܹ>}\8_ͽ姏}ˎ=Ɲ1^kmi?o˾:Iz_t꠺S\Z(mMq v\,Or뒇EܺrSM0aTNS:Mu2E_IuK9#)'}Tjjjjjjjj3f2i1ޒ[(f|rS]Lu"} 0夺>rR݇SN`M5L5L5L5M5M5Mj3fTvS:Lu0iTNS]LujAYH5 f!,TjVS S S SMSMSMSMSm9zlJ<_-vv}1uϣ?|߽—C"qޣ|ݶβ{Shw nAy|RLj3nTS:Lu4iT.S]єFSN{M9iT4rS S S S SMSMSMSmLmz2[~XwZ,byZnT.S]єFK^HuO)'=T4rS S S SMSMSMSmLj3nTS:Lu4iT.S]AyjRBYH5 f%լTTTTTTTTit`gkuo.|w>? ϳ~}˛ ϗ!֝l8ΗLG)|B!yZ>(ߧPHw/8߯f
-ɛ]H)rSM0aTNS:Mu2E9$'Rl!9^瀼e{M5L5L5L5M5M5M5Mj3fTvS:Lu0iT.S]H=zٞCrRl!9^瀼e{M5L5L5L5L5M5M5Mj3fTvS:Lu0iT.S]Lue{I=T/sHN9$'͖fKiRl)m6[8X2 덒c>c<|7?ٝvuL;#Zw~G?rgmKNz)oOoZJ{ N9aaaiiiT6SmMj7aTNS:Mu2eT@rRq 8夺WRqM5L5L5L5M5M5M5Mj3նUۚXayX-_jyT.S]┓SN{ N9T@rS S S S SMSMSMSmLj7nTS:Lu4iT.S]AyjRBYH5+f%լTTTTTTT<̚/z<YX杁xܗbv=|>|ݷ/}ݝyyYZ;7u2T|Q$Y>)[J2E ս;Z B{k+J>D000444fTVu^vzI7$Q=޻BTVPd9r"%qebXF(bE,eT*Q2222222ɲe#F,;Yvd9r I,'Y.\d2C,<2Xf,bU,eV LLLld7xiHηqFY+ jބ?Q_} >|r_ۿ}gClʝ{Y|=ﻏ#.7ngLi|sAyX-_o0(7Ex)Iu/%y!}夺>^rS S S SMSMSMSMSmLmXsMEA8,˻Y-o2eTR>^rRKQNx)+(70000444fTvSM0aTNSLu2Ex)Iu/%y!}夺TRjjjjjjj3f~~&cPvݡ|eס|,{nWO/\݌γ,Yw~kG{n{f͒7'{fAޱYT.S]Hu('=WꞫQN{&y%=WTTTTTTTT6SmMj7aTS:Mu2eT\rRs5Iu('=WꞫQnaaaaiiiT6SMj7aTNS:Mu2eT\rRs5 夺jꞫQnaaaiiiTh̵ƔeNZ޳ܛ#_eNv~=/S)/w,ד7_VȰ)^yf|cuoыi|)yX-_7%ojjjj3f.c{OnEIi|_ET.S]HRHN/ ӿ('}T)`jjjjjjjj3fTvS:Lu0aTNS]Lu>7rRgQN0Iu!&y%}LåZy7w{`_|ktg]= ͍ /zypqoPKzoyůם_kU{9*W>+[(?)oOʛ6SmMj7nTS:Mu2eT('=UꞪRN{J9*Lj۪(QEy7'XayXnT.S]_SN{*y!]PN{*y%=UTTTTTTTT6SmMj7aTS:Mu2eTTrRSUIuOU)'=UjVRjaaaaiiiTw9sM{FY3gTnn8\榟>>}ݷ|<_<GcfnGayz-ߐwڒ7'i|Ӗ<,j7nTS:Mu4iT.RݧRNW _)'}T鯔jjjjjjjj3fTvS:Lu0aTNS]Lu>rRݧRNWIu*y%}+Lj3nTvS:Lu4iT.S]HuJ9_%/OTjVRJiRl)m6[J-͖fKkyo4sc?'$?\s=|xzw=l杇A^qG)wDo  -M fXϯSŰXQ,EK}7U$QReeeeeeee#F,;Yvdr A,'YN\dr},b䆺>[jGqK-n222222ɲe#?{|QޫI(yX4eT#)'}T1M>r[J{.@6SmLj7nTS:Mu4eTAyjf!,TjVRjaaaaiiiTwmh~:x,ls; kyCt'x,+\w߿>}|뿼>~p9:nAn|g֝ucE~Nɛ{:i)IZ BjZ+jaaaaiiiTo7~n|$y|R>i.S]LujAQH5
-F!ըTjTS S S SMSMSMSmLj3nTS:Lu4iT.S]AyjRBYH5 f%լTTTTTTTT uTF)Ӟ{<uwC^Cc_W"ƿ;jԹV{O 7c~{i|EEEyT.S]geꞕQN{VF9YTrS S S S SMSMSMSmLmչ-y?,˻Q-oOg<-7eT.Rݳ2Iu$/geꞕQN{VF6SmLj7nTS:Mu4iT.Rݳ2Iu$/geꞕI^Iu(70004444foސCՈGl+s< q>|JXk1^s#fw<-]$˻ zXo.p ay|QwYnTvS:Lu0iT.S]HuO)'=TԚrRSk+5Lj3nTvS:Lu4iT.S]HuO)'=ZSN{jM95Lj3fTvS:Lu4iT.S]H5R̓T ,TjRJYI5m6[J-͖fKiRl)mt9—S1zkt<enc<|Oz>zt^/ty>c~Y^߬kkβ!ߔz uR={ATw{?r$I,Y.\dbyu~Pe?dddddddȲe#F,;Yvd9r$I,'Y.\dibyٲuˆ}PeU,/AMAAAIIII,Y6dɲ A,YNd9r"%=ˎ|Pe?>*& $K$}>Krcܛj4:7ƝzMxlc_߼aw'gUwvc'y7cκMX-_P,_(C}夺T_>KJ/M5L5L5L5L5M5M5Mj3նUG?ayX-_jy|R>i.S]Lu>rRG|I^HuE9#('}Lj3fTvS:Lu4iT.S]HuE9#$/T_WRG|QnaaaiiiiTyʑk}5=FYkκ{#=}=rבӱݿ}x/~_a<rA޳<͈xl;Z;n'2ay|QY>%{+ Ay!ZHRTk%ZIVS S S SMSMSMSMSmLj7nTS:Lu4iT.RT 8H5RBQH5
-F%ըTTTTTTTT6SmMj7nTS:Mu2eTAyjTjRJYI5+f5000444f{sZOv\8Z
-endobj
-54 0 obj
-[ 204 0 R 205 0 R 206 0 R 207 0 R 208 0 R 209 0 R 210 0 R ]
-endobj
-55 0 obj
-<< /Filter /FlateDecode /Length 1224 >>
-stream
-xVr&߯`Ozg7yԤ+7,Ľ"#}=$'>}i
-}Ҝ9}tɤD"LcԠIQVy%@П'y
-ӧ0Y
-pFsCѹAnӛ qv|/QF8.@`.d =\}fc Pae
-cE(~$0$14}/
-=-.cx {ٮb 17QW:;2al+M"vТ܆X~j<+>BŞ,7\dȊpzqY1Ypw̬h%#dMQ Sp^/ړ=ϴWwfYljkNmW
-KԸ2kh<siT WB.3=<ZTg]P;#endstream
-endobj
-56 0 obj
-<< /Filter /FlateDecode /Length 1572 >>
-stream
-xXK6W `S>nO]tr%bV9IKC/iS4p/ge~9)>'cmw$$[Ҙ"")ɇEHaIRT{7On?`[['87IT8\kp<mqvGHEe-RR>oK/'/-D^\2+w٬ƶfMMr<K>M#fd PSM"' NbR9$
-Lm_V+-Vf(t
-f
-.W1ɺ"Fcc87z)ϳ'كDuh}o^hspL^{L51Ϳ[6n :u̳LSl;EEq[>D<lhOcpIn&I14ZA&%C7dn"&Y_<vpSJrBpaTl4
-bg[rӳJm\L7v928mlP#8v~߉gD{sƺ6o\{o.O]d;ݭwDCw
-
-?
-q8peS g-lSz;cf=-ꄪ/(Ƒ;7'"\ASA.gy~ɞ<vbP e %lDnYZ1XUhg@xSswc%߹Iv.;wrM''zv-B;(6@?
-<On8_6ڳ$wſ,endstream
-endobj
-57 0 obj
-[ 211 0 R 212 0 R 213 0 R 214 0 R 215 0 R 216 0 R 217 0 R 218 0 R 219 0 R 220 0 R 221 0 R ]
-endobj
-58 0 obj
-<< /Filter /FlateDecode /Length 2926 >>
-stream
-xZY6~_ĕ $N)cL8$(a"doK"ɛj5F/4
-I
-N٩?_}=7ߗ ReeT#Mpji@eW5 ߳2e=~k)4ZD/"wыoWf:QmW(hQByY+i]m'6wkx"Uߐ78U]HC&J<>~H𽜆qs&%[ 7I
-:XBz{&Rfp\#|6-uCǪ9<2TM3.tQ< 2?~gqE,(q 2-y۷e)#Zd&I\^o%ޟ(vCfT'>N`EOth&;0,ia!%6۰~/f@>A7YH3 UX\m{`]5',e{f}YBöoX_s6RK}ۦc DoE׉ (u5/g6
-F%h(s}'¥qK#
-2<'&diھT2=n ՑEF2,m=E4)A0+{I>T e I_Kś[;i1pI0i9+[<vڃʉ
-f2@mБ'6$Qn mȋځ9eNtqLbg<i
-X^r/+ǒ |dܭZT}ޑUFmmP7p]Md=XNj^Dl6VDćieɁug2 U?VW;(T}
-AL0# 3&b5I;̆j[MV pf{b Ɉ :޽0s-\[i6-6׬Z08U-n`Hxޗl{
-ٚ
-jAo
-F>ܠont޿|y4xQۮZQT6l:Sr8++E˄Xu3&5x~D;>NODoCX~A1 /u{<$hHݵ?AvA&|wↅÒ J5[BF,/
-=+Tzzr _w8霷 4uy!C}*^"+5un*1y=CêN*J\i.3/
-FbU#X7デn㻄4ǸXV Tp-9z2D0]ډ0f`dx+mPGSu|G٪+vy;/7Ҡ8Y8#:S!(=<dv4}f,..>8S#вHP*<)koџbp(_|q2
-@A딣2E$x D݈዇ø6li(: qo,58d_8ev$@m
-W՝
-NPx!]uGG:_=eww-A&yJӘFx~Z˃vMyNa|t#&(E (ll-X,vR0̛kr fw:T!_TW40G'E&՝zZDs"ƃm[ Du%$?DV)g8ǻ>5cG_O\GM5'#;Q5#wK&Q7sn/T2B|'\ۚ V}{˪HcgG6vtm!@^mgъ_٪j(OF>o:Z)!T/hhU|f߽gaI"26%$NKo!N E% !/]6hE6$B8w:"[yendstream
-endobj
-59 0 obj
-<< /Filter /FlateDecode /Length 1447 >>
-stream
-xXKo8W)ݤE[,ʢ#QPHZMx!9΃/("Yaqoyebe%)1t@NPwD4Pa6G?_8 cqO@^!\?AśQV[E4yE(,*OVMWV!^oM*^U~z+Z[\Nc4m0G>' ILNWp|2ѭ*Di 1|A$4I~y8? 6_|g0j1[,Y/ bj%aqF{Ҕ5p`%1EVHXaQ^sJȋP07_ }wĠA j!ymQa0e\18%-MMWkYo]x<%R]gҙv3١@k^W `ӅLDINT6/Էo(|vFT F͛>%Z+U;x1 w],1dƴ(V*X*[bYEԀ a^TY$iy<V6Nh<R-cpSB֎|s]C `3I?=fހVx& #up$IY
-yb)R\^zӾ= &wݐsK3(<M\.ux =N\e@ecx<`g+f-<>7-,_ ైbZdP$1͡( 3{N2hȦnzE#R=lٖ#W$d$iS):xrlt̍۽6[=7`(>UT%tW<Ʊ!U Yj:A{+˪1H ?)G VHIqFwC.7ڡ3tFC1
-r\:33]9v=ZJC[jf@(Iq288T qv82endstream
-endobj
-60 0 obj
-[ 222 0 R 223 0 R 224 0 R 225 0 R 226 0 R 227 0 R ]
-endobj
-61 0 obj
-<< /Filter /FlateDecode /Length 2796 >>
-stream
-xے۶]_3+ [g;IΤDB+6)j6_߃;xvnsuCPl埬Qy|58ԠY'ElWGoi7X\6ќ:q!/Dߜ(%E)u/1?r&MR-?5D/>U="FnGc͛$D~<K<.btD^_?7?/lqӆ\>Q*B1qEQZ~E(F۶nЇ?\KX8"PMP4t*1}:t4v?h<Tѩz~D;*lPS[ ~3)Sj
-*)ӌ)&C]wcW$InD Z)[Jx)@A>}4es a
-)"׭g=v(jݵJGoV,y
-> 頹ⓔepNW¼(ɍR8i_*
-]
-k#l0µ- U^7zc:y94.!z~hP6 A?HKs%Q13 fj>2N).b9:ծZ* F5 OSV}M8s5(މUz
-P3.49Ul者 H=}+$ 7ɋ5K;u1J6>Ai4CG)*7ۦE!B7XiيR~[aR7O@S-&s|H"J^֑:# M e F^V<L6 #VB}E1;Cu)F?yxp>Y Fx!@E
-E77ΗSJyʨ0^(jaY67a W0(7"LVf V!IV u8ufF0f[(aF,IV>$Hhn NHD>̪)gM=9NE
-endobj
-62 0 obj
-<< /Filter /FlateDecode /Length 2639 >>
-stream
-xَ6򽿂oiY ,x=FlaZKcf؏""{›.|xąO$6#OXxG"
-H)VY?Bp"nK> w.N2ؼ/添ͫw\rw0!
-c' ,KNgUӋ u]G7^~!w߼8xiL%C/V hJҀŧR%MECDE?\k{1-r=$#hN:bpi/{.juo,ٞ$N8%4VѳwLaų3,6HjZGS~3{vCh·fCQFN:{hm:oM_ڈ=Y1YP8ThO1r4v{ *y. K\ҥvϤ#"^8ifYGK~4y(FT<Gd<g}Ϫx5ز@2O }_|B?u8
-*
-0
-u<)шJ"{.7"57526`m @˖ѽ+w2ɘ74bo8n`:>FWSz1+-&w"xtYDt$$Z^ΓY+<eєMjP0ӲϚj-)rݳzn%`ۘ5g'!%,t9omq<dR *~O 6kâ%p}Yв(IAeխ Ժ 9d+3G3kU9 bʪ +
-K{ZԖ D.2l? wbHb|b,,D|[C6RK%{;¬61r=XKo[fvZݱoEGPo_g1D
-VMn 8o"RW<_0g:l0 h+A)JM~ߦi FQm->԰*Z,Mg = mvAc0E0@{> Fbr!bԂi[3tAYC jШCت/$B\_5fQãYWTX<?N1"{#ˇ3}_}~]'[tF &*]8&R8F#X1JWuFDbFa ƏcEtd~lqږ] ІxEv~>r/uL\dE<\ LWm L 8i{6Zյ~<Z_ g0;}C7CHeR!h:ya0FX̠} Ed&@C2*Ih֕kaa-}GF-Y{naMƂLq@g2qAMxv
-ypGC%!p5W%֏'qS؂qDž bq
-r!@ Jzt@;pXʎ-C3EIr|o8?NVݛJA%d*Qq9P8{hAj6g
-z5u_y[؟8ɧ+ċ~+.HW}sq ,JNmLϾ\4zn"
-6tŃ:CFmhrNjX:;"./A<\ݳU8՚[J'G\iBypvѻEI} *KϐE ϶g",+7A9fi<IWrP5 r|"p#D4˚]o!E+ β4to >0l⺕6+
-3Xq"@.)|9p0(v= ŞႸH<OsE_>/2%! >]n7~w|$R4\3)`,JѤi"o _6T^V4I؋i h {fO',I|-5Ȅ͘ab+C</[b.p/8&<, ^K^Kb{?_QBi/uu1<gI?<$IxF:&*
-ͮZGu3e{a{~lis*gx,t}HAMוir!~-Mt_roߖ- glӽM߹62B\|%Ђg^qTfendstream
-endobj
-63 0 obj
-<< /Filter /FlateDecode /Length 2200 >>
-stream
-xYɒ+pLUjUCx$g!&&µ
-މQL
-RC/صu3LQ/h{3wݟvf(ɻ(qUUV$}åmy?~F01
-BB8O&49RHhr6A3?5Mj{M;"oFZ1M|; 1\N2! w"R5qH%IyOO뗧'i"_A$7@[gI#`_p
-ȟժ}{ȚG[k㲔I"nTm$@pg_J]—nMrzQȓ5+l%?Ԍ} zުIvxO0
-0vBtlA
-VBfr%tPQf9ÃHZhq&rM߷-IY>YCf7ӁB xޮxɖ?eLkAt :K=F&ӁgZ_ض?ݩ-ۙ+H?cbp]sI:#zU\1rჩf- M+bped:_
-< \ ټ#ٷ^G=YDQ ܲ!/)Qi\i2x** -<YT]+~z*fьNTMZy_Α>hZ
-MkpxƔPp%mU0OVXySByWӾw
-<3WeXqQzb}b#EŊPo`QAP*Ӝm5Gps: =z(s~M@PW 4lx
-Là R OCx|6`E
-endobj
-64 0 obj
-<< /Filter /FlateDecode /Length 3843 >>
-stream
-x]}żu)r)@ۻd>d rl~}!Cywi. fP/7Rg?y Ӥ#gLJ3! JI0G9@!A
-YK<hiq {5_P,BY6qE
-mDSjTÃjQʽf2+S_ KAƆ'DLpjj=WÈ
-P ֍!|L5{wϸ;Gq^.6m;%X
-GG(3YRHߵ[Apf&d'0JUC2~K#ƕ9U2_ea-sv ̚˨V^-B9K1ic0XAk +湛(@J(l(ϗ2,keAf}F^OFvR&&L #i\]1-|U1m?}bVrP'wo$eɘa,
-,]Z;U#Yʡ*6]=:rv>gq>ĬGa:aks`„uͼq_ ~1&X?Y3A\@aaOj̓ +9l
-ZlLӠ 1Mi ;}jG 95F qlv(\mM';&+}80ֵVik^ [V{<a
-FѩPS)N!iP>tvO`d?A7 ٖ.ChoF2w3bdgtr4=>4#n2s5=v. XTߎu"הl5my7Ȳ(|su!ly2Zҟj&Πo2]`pʑhJ em
-#މ"kZCФã8 .dxSW DL&7ِQ2ʂ!U;os| *S{j|]|_v؋D.+҅˦~TGPb?>Qh
-lg
-!MRBpA;Y:Wg8"Vh<QUݏڿ <X22_طmD %3ՀzpeAebF^F/wiK`@PBEs_aQ{Йwmۭb\8&.Es1+VCHˈ_k ?1P= hBD*ѩ0=5Q,N{P~OY"Hvhzk3&ޤr#ӭ&¢X-܈h#H7"ۈ|#(7Px=ъ9!7'YFoq2[e3)P/'$tMBl[F}Vo r"|c"c'-4B`\C'!38by )q KD/``TLE#7dpH},W N~$ncXItIfT_uӕ(-ΉwD>?#5薮B-w,vOy}a'҅wJz.j շ _1S|!%3TxV1|1"PCLd"m6ZulGqLWգ8_t:r-X1K
-{ 6f~߲:Zj[#.M:Us8 8_xr궃[S0ɖ)~!Q'ky'VUE֌ㅢ%:+
-GH,`qHV?
-;^жjwv>Eo``;/_&I
-&B6߱G;!~+Nz
-ڔPvjoWSB;8PEůR2(`Ftd_7";?8XkmTϦZ"/[8zAǍ EY=^`0 ;5stt]@W[qiwV)+^KqYBC)hQ.cְWpd2㢜R/q졠ŖKݨ.~7X.KDk̥P'T.3Dl-+"Oi m^U _yBF07q FǑgr<wR],u{gt̋A hg߽ḭIռqHr_zc[,C
-j+0*c-*-."4b]X2[ JiP>;NV8X;n1nLsqt+L {G30sM_m("1pK׌Nbt1١cc"<9ćrzƞ&-"Њ6smJ{KL\
-Rf:C>.u
-iWCYpN0J=$_hPmx3UP42X"5 s$[Q6EF{R5ڵxEe
-endobj
-65 0 obj
-[ 228 0 R 229 0 R ]
-endobj
-66 0 obj
-<< /Filter /FlateDecode /Length 2661 >>
-stream
-x˒6-vAʇlJ6LU1C&_Iq7NYhD?Ax-D1'|Hĉv[AH<Ay@rҭ[΂+1/@F&yæZ?6p<my. #{k"H8O$yq򐓏s*x"~ǻןÿ6<=PC+C+}{h{Σ`' ve=1QZk1Kj0WSP!
-(Q9yfLjkf>~G^@W@]BVuY8^ʓΪhtbtC98>ƂG<,v
-ŮGi TOYyN
-dExGHEsNw,9Ww=t-sjA-<v\7*QOK/D,NK*K ]zm<2+]Y99}Ƙ'Y(<e 9zsFcX"X? J=ևH,I< fXx>}OQz#EtĦGJc I i>`s
-Oepm
- j_l2v.{N_\v+췣-FJomZq c`$ x&S#2P蛗ngܤ7aBb,"!4xM[<P(>m렳ҮޥKAs3ف[i}ڂz ؍KKkC7I4@0
-\w5#{rB&)u]Ԧ]螡
-X</T 8^Q,w+=^8Z 62@X.SQU5'$_ı-Ab_ۨKׇۡʣޟB
- /Գ&z<e}U`Zc܏"# ~J<+p<T sFzZIfOF9|B)!m7Z ˴h׻]ʳ:GB/h MXBڴpefaAVYHsĄG]&=rֆY#\`4KLm
-<'z' xq_Ã_D Ye'O !1B.p{ABFB[&`(V
-tt'‘g2vKsK2z*qt#.ГpI]cY)
-^WzA(^DZݨa<$-)DRϱI1mcwU"N{H7ENNŋVbaЛKWӇJj/-&|]4o?^k/f@Jڬ{Cu;k&gQ)80`GNV-:fUCB
-!2'ip # ͡K<, )*b,yJC_yN(/>cvh2T ,n ~s/ C?X
-_D'@8,$<q[1+GIO
-xAL¡zS+{Wq-FkvIs
-1Ey<X1Co0An/5ߊV~v㜚+@=:ؐj+\ : @9Sw+,XP ~nT[x(Îc[@f=X>ãY
-VuwY8a`irUsJ=P NN0
-}(,Sls#XNR~<2i(NKѨodwл/ I;m<;~"M"a?endstream
-endobj
-67 0 obj
-<< /Filter /FlateDecode /Length 4054 >>
-stream
-x[Y~_ovG
-~'.|˯P.7+{_{Ѫ(<Iʲ(cTEOc߿}w׻'0Z-}=ϓiL8k-Ww#8طФ/
-$o#QLWzS_bʛuFշM>MXQv{}]_[7oPuWt
- -:^{[ P|NIwLRdj'V*/~Q}}Ł<l>8Qxͧ1ucsueT=^h[PWq L1,B+&r݀SeJ5s&==*X4w3BVAtNܐ4WgC?Y4cP \c=%U$i%+dنW.g,IfyIg!+#.r{1sJ,zo,VLfA*G 2:Gڊ 京|•=D'-UfMВY[T7Ej읏/E(<҇vn;{ .SFTءBt:9ur?asϾjƲ4jg0Băǥz Kg ܥH7w3B?!隦`M[XX#ߋ`9?Ҹåǯ kf"iN\M+lA};i;5&h\B?oDpbPFZ9_boC'cP-V΍&<,%v *h Y+`H;!C $i v*!ZێbqKŅBdТ!clM>r!z wNuyԶA}[ԟZL5"JGVй>WNɽ<xzޟ'qmEUd/@{xΓ3\@/NW0`(Uf%{
-
-.YM#KovT{lǝ=Z mx{W.C+αM[ <j6yggxhC:EGY4Ց΅*f)DUZqnT' tWYk!E8M^H~%vB;M"ՅN+Z̓wpT^3hXJ5{rvqU[0쇹Y,7uwa4S%&qfXG*K>b*MΒ4ciY lezgP[&<ԈO j]N<,WpK5 8,tLW<$VXe)L
-I1ƃ0T? MߏgWK˽3um`}4BA*™
-J 8Q8f38`MkPeHq?g'ܬ[rR˥0(zϺ=ތ,WTmjYY*S39
-)9o,oBjp(ŠM 6j6uһrLUyс§tݟ ,FX#
-i; .1:b_؍ϵ?h?i1Q;Q|uH(Y. gSҡo,\$ـq-  jJ".'rJgw<
- 9Tz1۪\
-Ңd|sQPL]7=g>[Ô# i;p9p\f3v(T. /J=*c9#M 1Քf^l茸8= PۻZ/ =%A1E?i[~%H*-)yfQ
-FFT퇑#YÀ =]+,m>QL')io]==f[ E*Ț ;R>|eK3-i9earV&G(敇fx
-Qs 1aPHFukbjT .HLA`ap:@O|jސ6GdXh0\ 'SX'T4bk*' %p/IVUK5dL {ف8=Ii7`zw`oT.Ɖa/
-@`7Ar)s-4նq̼U@s{
-!>}w>a7F|r}Iع@)VKr~Gcc'"!ʷSK%`%.4n8RhMg NDt檎# _"My2J9TY8Ctz'ծ;!^Ԩ8YL3<Z4iYZ*7ep-&Eَe /Mi\BDd+Mjl +@smS}!"L٢нhH6e7+ m%EƔ9]{S0S*\(꥕~jWF57:jjpZTm&>8A5.RsSpV浀v=jTf`~֩+![W?-Q yQҘ~3t 9t"5V:C AЍen%Uكqd{o֯l1yi!J?M
-0qa"Nj2+յLV-g̀jo4d2y8|Ɯ<:it4r6 ,؍
-endobj
-68 0 obj
-[ 230 0 R 231 0 R ]
-endobj
-69 0 obj
-<< /Filter /FlateDecode /Length 2669 >>
-stream
-x]۸ݿoMK.E
-.p<m%q}R$P M0grԷUDBV?Eq"R$ *IqFČ3ҨU #E08?V*$[}5
-4ѓfŸ.?$կϫ72y\AUUV )$Կ<Wm=y/ߞ'$Q0Q렵!t'YNg& VS EEpM;BgF[1M*v> `rQx3?e(*ٷ )|`5)B|(TQTE-^wr!/L`ubw q?VZk;<v5{ lݳZvѲn7
-plG[7^X`Ҧ
-*K<q0ҍvOIjk{s!m'm
-6#*||Ty_ fzܻkU'ąI|pϨ Q{2/w-1 Pv3!Q;@1-6 ːvn_~6YYWNg ~-QX7.2}^1;.uTy%Q9A.P0j{qcb%^i ݮpLDchѵ' b۫jJo5劧t3N!u4+䭲 +0JSm@5`w.P ; )ᄗXeTaWmCg34Bǡ׹[;D1DF'
-
-lGeu9aiqeYK zDU>ݹKc" `/Ve$֡~]77'wZf3^[ SpHaȲIX4*gvJSC/
-endobj
-70 0 obj
-<< /Filter /FlateDecode /Length 1633 >>
-stream
-xXK6 W;c1zK>I39ds%zFZw iY61
-
-Wtϝg4?8FZ[ "30W]9Or.Z^D&֞{#̨Q8KE[hxL%Rt.DpZAKT,,[X9y-sY[3##;69O  4T
-l5>Xgn{,T .-^dr&fQb HX58 {jn((WqTZ}yRx^dW7
-}2}d:7{3 N*+@sđ#'|<1vG= >3ZhλQՍ(o+~ W9γl!Ae5 \&ˣuMCeycvqmZohD$0OpJU;;oќM_{feAYqe= L|M!LGH0BNyOНH42!NnLͼmuO'穨<^09\ t^^iEPI Ttr0Ik{F M}K9(09QXQM[WN
-
-P[Ұ9562 #5΂[5yh|h@Ŋkh7j$[<bSNL~ɾp:W%*^eΘ<= CQ邁,(pNR,XH*Rr1Q4I0+}km@B?=^ pe .wmY}(FwGnylX*񗧝/
-eendstream
-endobj
-71 0 obj
-<< /Filter /FlateDecode /Length 3350 >>
-stream
-x˒>_K* 
-&D{ln͘:'i8GlL" zgMs?zUFrs7{`:?wϠi6Sko3e
-(\@!R)Fv ;G33ӳc~Jj]v\Uƹ2v4jMP|``;TrS -մx#EA;)AV4 !HH+- k|oA/AstiZ:x..gO(g6GX̉j?jJ&:6;0}A\xR##![yL*S<HgKnWլ2Caa<q\a2^ȫh|)VT@5&AL>ϩ<2hf60qJ5=. |Tv`kEa^t4>
-5hu7vV_U0J[^xUU3vU1*v&J8&.2c2p:{[LEpfwW[pku>ka-9wFdg:;r`v`8C7$%26} iK\g4WHXX1ւ 8XlA7 CΊ4 HYv+QqSUa;miF$1`0D"r8ʪZIV\l<{y,IߥNҚhjW4Y~U(v^N@0tKv=ܚ}Zڃ88,<jEWqR?ѭc{=ncEWʦ& x`adMZqH7wlTC1ձk߸m@'ME.hPxYySٸJZzC-#R]W? r)]5jHyND2lUJemgulJOidY5f޸;1ݻ؛+dHX%\G+|H`SEDŽfk/!dd@bDoC}$S$8!Йj"̑Dԑӽ7K;
-vOYS4Uc/(0TNL}!DzϣGC+p ᰬ/~i>`3#z:zE0Ucc.h%c4OsF/ÅL{P4493,} 40jۚШfc+(e
-Gk* }6O?b`ᩆm!-;Ft~"ᕘ;8WrMd gCׂ%`
-'7J,jb`aZmb>+QLTPiq/`&x܏EvG;`mVɣj0]Y<؍xA@oU͋3QdM B r~vwA on/Ptipvb Auc:]y:bd:RZUr?}S~4z"fA*HE6!\"\;$ xAwe8ϫ_}dpI-h/J0EM]
-`P ?b%{>R<GL3^^f &XJZ{&FAm:{;J|$ \i+oaW/NyZa|o<s+\2[]'y~<dVEZo~}'bVM7NToяa?1endstream
-endobj
-72 0 obj
-<< /Filter /FlateDecode /Length 439 >>
-stream
-xSn0 +xu)ɪkѥ@ءI$-'YNbGpQD||"J({ -y|2fpi0`#D{@N\,G>Gؒے\/P>] iQCpVAӗ VNpeCy?^,g< '<ۇa` fYxcӅ(.dy|NWMsϋh2&#(R֮3|Hej \cR}JثX-֜Q#pTj&4Rm..-X9"ҜT:ykse-Tk Z5:Bw~;yp`;N{#فzQog1m[i>G]|kTfIf}endstream
-endobj
-73 0 obj
-<< /Filter /FlateDecode /Length 1402 >>
-stream
-xXݏ4߿\;N/ !PxoC󱍳=qijd)/3c{7va w'כNI0v(&\ "5qtD* HĞ4F~ؼyapi. #f}vAȃ0deK
-H!PM<۳(c1[F|=46CAϲm]Y!NVE{UQiiO+ϣ9=eM=ޫgV=viWr/q[9B@3d,I
-єP\'`<\ױ̒/^JH5ꚙ["M9eQOD?J]CF^3b,mFL:Q׈B:Ng2ĸup љcY<EW= f)x="F܂٬AE3&b
-pՔMbsMAu}Rx:LC/[[i.(t{5!@L͠l޻g*x7XNyceԽ{rmL}PyCK)UCn3j^|s$7cCi3OzδL+%vLEA>^x7&d\[B޷mu 1o/ؠ\4Dp :&mdHr5B5&B{
- Ӽ1]j:{OHQv4+Rxõj^櫤ֱ7
-endobj
-74 0 obj
-<< /Filter /FlateDecode /Length 3768 >>
-stream
-xk
-}KU(py_Q4IsE>b,/<lɋHspH?AJpiqP$AaR ,L0M`zEwM]tr} 8HeSsI"ùȳr;8KwT0%Pho=Ա/ B Co95u;Qxۻ/˃8
-)P2Iy=xo.NO6V4HD/t$h!ދ$`ȱ}7 s5ɑtFQXMdaXiaԪ0X8
-,,MII1x$$|'NC;MҍV Ƀ'qWVg86n( j35Q~alմV6k rׁd0LL8N7Gu({T`ʏN[N<AÝtlǮ}ܓ xA,Bf&X,:jDžY⨼N⌊>$ۈQCj<NԬ-ɟ9<8#$CG vw!pcrp^UR;OQOV+6ԗ҆D1
-mQ8mӗ=#ɥ „x' ɔ`ypȨvӉ=(FD]K7zv4|D _١ 䴼omy)* yŢ¢#]"ܸ##h 8ySU!>8Ԩ{JDVYjm']Fon6?{Y].ͥ<̀TG 1A1{]ۈ_7y;&yY֨B`1葌26ӧl
-kG:C\3k_FZߎTѦ `-zѰ+0٤PebQN W6;u^,ڒ3 C#ڕxHGDkPV98FS s PG^;T >Z*t,lNdЭ܋'*T3GHNLHc0Ăbv8_xbkp=[GjBzfReQgtC
-q\W<E"}" uINr25)LB0c(wsp! r>!Q\OSAdVb?vP-q]._OF(t,*aV4uAuZ>/% w4tԮ;h]zöZpM n5ZȈzN귆JEځB o<$eYYU{HSJt3iQ3<4Ӿ3Yמu77D!ρ-N1`.-Ns]QmmBǟ2B(>!zSO̓<ӝxtFO'=i\LmDžW%hg_'sq<Jwg}=
-T WyAun&r<Xk,?jkӶ<yV6a}j3FBG4uRRe˒2L+.ƃPSYFrCNGCvh2@P!R1g$OX{s)Tڃ6>N}$L(7
-+-OJd+l7c ;g)eѕ}
-5$-f;+r$}~fEc`ˇAchsxo|꽍Nb2髺=/m'WGRpvq%_MBvC b`cJo"ZBL-Ƣc5\qM!*bS_nMXR_WL_~tM՞y!Z믫EPfG?qH_aYEU'Ev֣qMfPy>rq&ti$ԥ?75@֖Y6"Y",
-mĪdY<ұteKL~ՕGl 3G<(/1}^81L-TՕR0OŵԜ޴tIFyQiv7m U.ib?wo*yrƴn16)?AELkd%p;j|w,M7!}kfp*k(78&cC|\>@TFId;m
-x/Uf4QXA݈(v+>K.DŭK-tt{#9z+4\fATX$6^G A(gm2J/V
--
-D'ɩ-oC}
-!>?!uozK^Kaۑ!CoɊ^`8.8Ί>Vf4} gel'LJA$t~CFۊ4ϗmX[DZWyЫg#l:rA9xjclBGy2367t|YCOU~!fR 6Q| S>+#<}cP$brCSz(0$ N/{'J,$% ơG" ]8ycTz_w,?ªȪx-?C8m"Cg$ݗB5  GPGq7kun'AM7IwYUI88š s
-PZᝎ/WG)hu T3M@v jz6llvK-Б{aAOKpF42ZK6`R9˻Ϣx~k~KH]B t?`'6C55k$XĠ-m~
-endobj
-75 0 obj
-<< /Filter /FlateDecode /Length 4504 >>
-stream
-x;]6+ (;0l6L\U._՝_HItٮE$@DER BQ;}& (3BY )v4kD4Ow]_>a]xM G6}. dLDaR¿((Dؼ??N CT>k%[7/}?,` F iN0{px5ƈ έ?5&ʃW!bj 붑ǀ&df^&ΊEycDY,Uw`
-@%+TeV1`_0O{՞aЩׇz2A+ccCrRs՜VuaSee$l1/9=lծA0Qbgt=T;2p|9szhD09g4k*.Q>V`36Xzyo=WpHaL95cŅD3HRʡN+cOI^{5Vi׮lp6!7qJѼaI*bmeKQ ` ;lPOzR;@jE ekv"$X@&٫A I \DI~:*\<,Z𚚖bXgl8 1pZzvm45/muwU4MrWsߝ:ֳZGqZ
--) z}Rdu]ַT!Zj0ͽ5Pz?aAsWη`nTA`{U7,D)SVf~ލJ)d*NtNFxF'i?d⊨ԏ k]v?[
-.SuCf;A+z
-R! N:mqo(T20(#MfyN\! D~ c<O>^A4:Q/a`aƽHeH F7/AfТ1=,;/ ڪxcÊe T 7Č p
-Ɏl]PvG{Xp$S2<(&Q7b4:\8xwG@b\800| d`uQJ-.Vhx
-'CX `k/^$.DH tu\lP^sQbjK4U;wݙu!jﱩ/[Ee8)]ط]SCGPMtr=C}% .6|lgu8sUC+[E` N%v~ p v7}8l]eh
-< Iۀ*0^>yH |@Ck wEq
-A7(/gqM&|fݰ/,pbU]V tER
-΃?_ꧪ1.<{w0_ Um+vNp@ Z%r
-7]^HkXA]< [ :XaU@I˸,ZQ B#/Uin6N8 mM6yNzcEk@̧W.#ivz&cs^?`%4_В^ʟhϴbW$ u=Q$EbxشmFx>2cni[}zڈh sƥ~2U?@Ixؚ% Ӆnn@ bvgh/^}#TYy&"f1tqF!uhg>a{w1Q_hdF{+bd<irACi$Y#=*utqw~ l,3o ~P~t{8y9iDfrfB7x2MWOo1⛃
-C󔙅; ) H@,YwPo^!c))ke+:}ZمG:IT m3@4 ʼ 8&Ow}TRQ)>IM!ҷ*6/G? (JC)`s<
-f
-]`R-Hҗ:R8\ܯ9DttV^Nɉ?݌"x2[W_}09X0ګ98^~(ڎʨꆇ0D/K7A[Amp'2_b9_1Gˮ<|da:+2S%Cԟ3H9ہC3=G3 o-lǂfcK8)qh;= ]r&k1~]/'b2UA5!HP-V ԹרCX7FYl
-t1Vt<yްU{a*OTawĵ: }z࠺O`&҂~W8@68!V4ڍ9%[z[sMendstream
-endobj
-76 0 obj
-<< /Filter /FlateDecode /Length 3952 >>
-stream
-xkܶ
-`Y
-T򨟫rNK15tuch!&|ucy(^&QG~`}0060+V^*=$-0#Wf[O]0jg>Mzlx'iݳJqH$KD[g"#Yf첶Es֩3vZti`wZϬѰK76CAGf]͡hYI|a
-I׫Dı]UaUk[:Zߋ)Q<_#s=E* cU'}}ম$&
-?D|֛'q~88 ''ޡU{aʊmE5(358Mp3j-u=6 hÄcDZ,!>v
-ʪG!ξ^@a6$ 3.
-o wE<cj}%M5X_klG{ʁFsia4+ "}O/m
-Cede#Dѳx+c@  i!n! lPJ</ -6`\A!ex)HL;-Y*t‹7={Xn9,^E Jk>*w,74Ǻq7gݷ `}F"47xY:p {vNfkvn:v24Ɍ}sGej$]Mq#|@*(ܜh.~
-A98lؚ-WHB9ΣRgA"LaxӔZq! x_L'El5,polb02~@?*a}9Wq SIQBbֽ(vs"_e=bO kٓD=?!,iLu+:|=.l^Hlree]:0_
-RUC&@$zϧaBv@7Q
-brF1@, '1ya6OnF)~ kxSݛj"$"Vq0,DJ$ژ0T/S&f@ :0r 9((+xJbqK>#75CZY5 ys,TsT,^^ ѼUe1dRiP'0Ӆn6|QO N哆)mO2[OtD8"]}qhyf<,aW:E,h8
-\_:xmܳIukya›qj[:{> j4bZ|kĠfc" T3j m
-L'W,d" }m;`fC|X\(!gtA-׶[!̈́[!,~MJE:fDӆeUR`N\/v11maMDlzPPJ3*y$1%i(bqа%c`ZƘiF)p@CglS:ߡS@`ΥD=EEdzw\z2Q䄆QYE J( ȗ(8Е53aeJ&;Ud3 cӽ[
-ŝU (R0K5Yٿ¯}cTjfQq0
- w͈)^Z$[Azy6uz=rXE1S@JJ#S
-k:K\CFv|[- k/4~>to"#s2rOVXV<U4ZjC'=}]c~tGe:CӲwψ;UdDBJ9*Aha
-<یz3NfI51],iVEeNL<k(q? "IUM BT4[mēRVVgF.`?PY"dR6y9rΖ9)y\F,z,d%"R^Yl-Żg'H'~w羺?UvXwNrT-8\΢]Rĵ;ZSuagLyDE\,tXj0JV^rǵ1rk'V_zG;a@GDsq;lc\t ƷTDԠ$ QQeMnUKn>[ay6O1\2Kڥ?Et((-3. Z!vԕL]ȌR}/?(uS}=Q]=(M#j`FΫ$\9 N~&{h1k1q-KTZ\E*
-`kuv w-jtIcJ ] m 3u`A8Ԍ9h1vʒQeK~
-v@WI\^qKY5m(
-(HB؂G:7oe͢,1]'אx^UmE/y8WS+J wM\W Lα^eڭqY+HO(G*H2 #>!Y|'7. TC*@lJIG']:a:WO`( 0 >e
-1 E;伶«)V?P(L eݠK /8aGلqq缹eHKXT֚ GQBOOԉ]nuRK@ r8)❉! U(&mք[|a0a^? ˥^ C=|g۴cSpJJx*DdV<-2yA?|IOxc]Z4~4y7
-ɭvm ]!P2kLI!>D(iNblĽy3GϹeQOK 1.09=8 _D:$aLҴܟ} 7fe0J{rG9EO}79[s%D
-endobj
-77 0 obj
-<< /Filter /FlateDecode /Length 5049 >>
-stream
-x\Y6~_ovodu>Dmz퇩 SԴNx~Q(A
-+b 8DR[9\qАkb]A>˂9[ 'lUW7ȫT%8Ys5 ޷Nå5mT?^mg:}Gdc鰛[yaS=BH^ `ue))bHڷH,Ƕʢ)( ^>&Mp~ q&h##(;-3eo`܆შ^ݮ;tk%A
-z'ZP: mA7j`98to#D=?TΫjr}៝'+) 8e\bP7=e!آ8r"3=[̑=͵ƤZZ4Jy'N&"z=ʦBӱMJnIBRG>p"GhP{O@T-3ѽy+APSV9@_0x,kMGla>ɦKCUԴ`z
-ЎP+Oz̥n#diJjcmߗ*[jC;MTfa)c P5&hMj=SҤ'
- @n̊uq,cnZ]!CsT;Bn%D]z1b{"IHJ?
-[l>gJ)CGu ÅP9˳̏j1$}&s+,X`ΐ/)^AcoD5uCZ΅aς oW}yom,m\ak@oY@7ƘU68OmG$:WqL,AwD:Gi %Dk7.1Ȍ{4?"y q Kl^N ҆2l}$LjwY`@CmOcU.\&+,7,&YdJD8ڂs8K.0דB(DWSm
-d!&j0^7sݍ1֑%r"y/lӂ:lFG*Z˝v9e^x:K
-2n}mW]ZydI0vneEyZ4E5j
-w1ÐyBmB9R$tXAuNyCBݜ%cn0XmiUv΄*ڗu rw,O>Lc<}o({I3/ }<sm
-CrCP{`ʹ2 HΝ+FwYyuq E1ڎm,0N0:AP]q8- TOԎ%tuImkMYѐ/D ~1V\d:Ŀ:mYw^gޡDG$
-M]ݯWeAK% beBL1k[)/DA01`Z+HAO-gfpjϓ!{[ՏVE]6GZ[B8;^im,ZeXk '$% ܻhkA;~gDԨ1 7]
--*ڙR`; q}$iq:xڎ03b!D mb&s:/]ׅN])A~_l-nCLE(4`ӳߞyV) 0(/īfڬsN*kT{`YLe#u
-3VRƠ;~-A]%n;MH$/wcjFd.*OkU)>;R~а&G@Aԉ^ߦ33N҄B@7l+fe+z~,GPvmx660;Cv2i3ڵz*mzSUU$R> Ad( CU. t^;^bP{Ԇh0*M
-MX2U'ߩ-`hΔ! 7$}W H4#09QE^;fـ-0e\ETZ*PjpP}{['ê~b?hYszHD*+U{[!!}tqji'8F9cr"{1%(@JT(+H@YgYF7'E03eSdNr)Z\;&B4>띲Ρ)Ԭ"%VĢ^iEmJ{[l52W&#ϮPljRj⇾F1wkVq0|ǹ
-$}xsSta"Tg}[ $|Ԧ!)ی/d
-_uM7?w<MTB2%H֐ӫ]a^&Sr$kNV|XN,W8qW
-8mendstream
-endobj
-78 0 obj
-[ 232 0 R 233 0 R ]
-endobj
-79 0 obj
-<< /Filter /FlateDecode /Length 4039 >>
-stream
-x[Y6~_$UcE&zks؞-ĞF-u~A$>dm( 1B//ԏtxG^+ͼ0;yD^bDd(quwϿ@aPrްUIxOwyUꅁpp&2?
-D^Q(:q}?_}XF:_1_I,a`l[4A?o#px/6~78~96ھݙ`_uP~}.I 72Pcy?F4u.d8yZATE;ݪ'QtMȞ3W_ 0 8_JO"?q|ׯC`jm!,(|[߻gr'FY [1(@( Eh,>F@C˼7h
-h jlpnȶ5y>ڊUw]i@8R<زA dW#QFP(M04']ttHHep
--Xz
-`+kA2-cMn{A@JG38N3zt7V,VT,"5A'Ru
-ʶu4t?)S$}UYOg/&yb+v3JnY\h X^Fc
-#UCwp[kZeȭQ-FC}8GT "l~O&0LH4~x쮐B<r(l6J t1I.u[˖|/˸_/U7Y^:woN ^z0}g4T磫Տ} ^;(QjZ0F@CV  7RMƅ|z+1$}/!`mv`;$@h
-sE+/#ɉÀCq!P"Q--i蛹LI<6"b:͸|QL,?c} D4;Y GAq$ $؀8u}wCR 9A<嗞Aֿv8b|UGu5R\$D43_kІ.f'H/-7  L<wyNA8]\bw1s#!%ILOw HN"#|'~jc?t> jw^Nh÷+YQy<agKfw
-ػt#80+:=Ai~?ò uюLu\$"/v*'̱0 8M$}H@vDi!THqѺ_njBtk
-ѴGUHx%!&ƅZW]h 8GvigڑC\͂{h
-=01 ]9/D/
-V$uB-3% Q9*XU" HwWfer#˨)8pNp6"A#Sr+icQvrwQ\5WcaZ@?<œ>ҏ3;`PÑ% =-Y#1n>;#ЎrlyGA ~h8+fny(sH%Vd[/A.n5wt V 6y#ԍ-8π>|![;2ǩoEܩ}S =2A/dmQVC3ifu4A;YS}:]xf]访Ke(2
-endobj
-80 0 obj
-[ 234 0 R 235 0 R 236 0 R 237 0 R 238 0 R ]
-endobj
-81 0 obj
-<< /Filter /FlateDecode /Length 2872 >>
-stream
-xْܶ}oV4^ت*Rr!v6_nf'k=@F(1Rp"rr҄gdO:#-
-ܭ妻7?ք $y_Ο>:#Go"'I.aO~}T]M6?IFq3i&_$g?d)=%ﱚ08SkhAcA4<@PQ$YLp?d /"YA8M
-B
-O yN#y={S5yݴ.#V$(c06}G'/A @ןu
-(/&3nRA
-/ḝ|`Pfj]T ]7^U]
-ymUMa`¥f%JW(Hay5%lˢz5xjBg%ORljTvw{_\f 
-%F֛^[=u쟗Aj[=3%h C'``d%'9hD"YS%ԕ
-kVI%~HT?odx
-<3C,3UI+=o]bU"LDhhL?غk̅C7AΝ#*o0u4 ìP6#uSFvx=S`&
-YatTG0=/p {_.=UVݑFS˳xR}A!S'D+r4DN7WX2G'C^R㨦~@:YE27pǣbySXONL D
-1Wy-Av߽F`! o+ LFsaL!NBq(Rpk^"mUUU{Ttr%.6^|5ڄd^ ~5=^|n55L:z
-qU*D;ТbV>]κߍqןSH,Bsqgiv \Gե0,}'{ITi60
-endobj
-82 0 obj
-<< /Filter /FlateDecode /Length 2662 >>
-stream
-xZY6~_
-7 ɧ{ڳK퐺pɎ^ߚ9O}xOBa
-*/<5@c[h5WEY5衩~i^ph^R n{\nzg!_=u),]PPve(W$f+b^7Cbuu@4Ŀw<;+ei&$w#+4!(Rkw2*"T B3{: OAKr3rg#M(q_L2ڃ
-K-%
-33U {I%[\Kq櫵&H+5л
-)imֿ=K퍠.)k>ԟ;xC14myа4u5>=B '"Y5|e%@<W
-2G٢nJbyf\Q>5qn&g*YGYeI/:Gp*Cbk]VoLx8@ bK< ckA#= YT"Y˩F:DkI'F*y\5'>)wT5ImENFO)+9ȏYƽ iIGTLHf2i_d~L8XhBTgݐbOҗd2Z\D yof][-̷ۆW͓,Bȳ@;y-ؖ ȐyAE/*M >]y^L\jWOVמTS&^
-ɾPW,~ XO3T#/:of{^_GI|k]RqMR:`~%pϊ=7 4r%qc~W%O]^lPgY 7[!QȜhRQSL[65SHe*w GA]lS@s?L-}z3b7 k!f!F!&!迲nf<fdM_4}ꚾ u_JG0#9{:h)܍^WU@ʂ0s&o<d7%)_g5g6;  D' 8ZRCcJ$b)<%w(k5jWKhtq\lOZ)tK ƴB*ɈHvM12tj(r}|oᮧ\ <dGVYC?P`ؙAgbꃰU%3_ǎv3='<Bߜy!7 \P;L{Pą˰(:qgQMDqYdmnpƊvmUcrhQxl%`+R`-XM7U BoIwhҝUdyE!~
-A#q,BbFRƂP$$=箟-4]QMW:õFX ohD0_ 3Z%F_N;DSBdA!Js4[QC$!Oga=B':|en
-b7y㗭-[@
-~fWF@'+J\>4#?l@,*>S-a5Wplp3`d zdwpdE]C,ga#
-endobj
-83 0 obj
-[ 239 0 R 240 0 R ]
-endobj
-84 0 obj
-<< /Filter /FlateDecode /Length 3013 >>
-stream
-xْܶ}ova&&QʩT,J^0cקn<fʃbj@_h7!7-`YȢHIʂ ;0֨U"
-ju Y]׸TK' <R8ɠHq J=֕e54)." AE_zIE!! V80H}Hy
-Q(+*)'! <K
-\]%;QF9[ߋ˘KO2wǠBP_m8-(jX@K-D08KPmFU ahR w}&:Re7]zՕֆ/+y'#A% :4%cWBϭ+Auar= ̠K:̈́Ɨ
-pBrAoT2g<i4>4ҝM/Uc7LviҁF<[~Kˈ*Ds89Mp+Tb34+h rƅ"|_sOfA^Kf˂u?4j\XnV,r$I/"7eCWqFcRY]6_n%V T*<C o
-B*b:<ş 6dl>iNhM <Ty뾍t;Za`aj-;Qq2sB8!: Ih򶎦]m߈6OM[֍@aia#v{H<|>_=fo"ۈ>5–9ܙd; `+'ܙ>1̑G&nkuau4[<Ir"3!}{∅?a!Rn+nu%(WPM}|5&pћulRWxm;
-/XcZXSKC7Oͳ\ZZ!Bk>jjbΒt?`6r`{$;(f&{!lՈF:$zͰShI-([VՕ0W?dk6Cw+9;5.`xY{\M| '^wiǾ>R` L}
-墕V㇀&1~5=[$u#}
-endobj
-85 0 obj
-<< /Filter /FlateDecode /Length 3384 >>
-stream
-xZKܸ ϯ-㪱VϖgSNj׵a֎mQ=ɯHR|.7>$
-> wQϻ~&]tݝiGo|]Gow?q<XEyY<(4$xj)bnM'|42'B/
-,ZxkL[uj ߛx?S!8aIzsdVQ&Ip ASY|ڹ ~l;p, "d9vIo`qpv$eݯWs>90ݫjN{:ƭ,'.irC|rGGGC
-q==ARsi =4,jF0$9=8,PtET
-~~㘏'NsG@swY$Wo82\#!Yy"{s=0JEݕLwo (C2$ 5 ^hĀN'mI*9!sObK1(P1zgFdk՗PHjBNJ{ fw
-t-G9ȉD@@ێNAR-Z*N9m~ļ-%Bm{PJ*_NOr*t[X/1Mk6B*5)w麓`ZeM;Geu̲0\~l$p'0g0ZGJ2uB7ܞ1\ !A7##eC;臍Jkј=c(az 7']qMj15Ȣ}s$gIvǼp`>Mxb<zEу:;Ʉ ׍V_<HOrL ~@,yFF 9<՛
-Vr1#Z\0gb9h^8eqH
-4/$'fJ wHeuE2~]sȰ"BH
-GM7a=P 8/Rl=p!<_w 0zt}ZyrUm`in1iT /3 kv&A}4m
-$:" :Inwe.IP<=|SZ&ϵw`[<<<j;uVQgwbj nql<ZLfbwK uLpeb^hH4tj#,4*q}0$
-sh.#ږ\gDg3~viBDiWg۵3I(̋2*E]GQT#z_Dp~r|}`&XGԸ\kdZ09[%&⎗l.,yoVTSlnI3z:ֺą.MUo-.$01aҍ4O*CCt؀{~!-ʰ(wUYl?Ӎ/ŋ%6ɇÆs|`ދW2Rq#.Q4 2ݶz3j2'mޏ=tF=zEh4hLElޒ#ӍƫDGxFoIP~SUOO
-0I8MLJWs? 鮵ѝ:tmm󛕦( t5QURts^ƸJn#İnD:^"&A 15]HЭN~Ax^ T
-i]AepH4(өW)ίZ:CZsY6io"mR+ZhO4[LZYfB>nNɚ,%ꓬx$:fylTH|)]+YIQC9c$)z]
-{\r{.yD<Y&t;SݏFߓzϫgR\EE7WtfrљP&֙nhMMQ]?( 6>H~e;&<i3>(cås\ QD-Jd!-"N"W+/t葼fH3$ј\h=4^oɛ>*z[-u$_ 8=)l]1}ϖ5ΣR-E3B%ݭo ҖylyD3!<wa'ٻ%l^j'e* (:avƽ
-MxqE.Zxv;ʼnAu3r؅˼wMx5MFXo$:%8
-Xc7_тqYcʚͲfάoE9 LU$1e!fʯ[Of&޽?0ʡ"I*FT&LQƤx;p XCFrT!?s lCJUM6Ui8J
-gc]+*o/ުdH&EP{W06\I1u{ew' xԆkßNͫo'NrZ台R~յqQWziyOA8z%/r1FTv)2J:Q$vxR(Ɓ ^- -u3WdSOHIqL{eޘy*D] ڎY˰+}ygz{}U7$QІֲJk|aU}8endstream
-endobj
-86 0 obj
-<< /Filter /FlateDecode /Length 972 >>
-stream
-xVYD~()bO>bE- ZixXwbajݾ-OCf$w}]WUEAPXO0྆<0
-kr5Z~N )bp3k?Xjz|'۝8ȣw [P
-9+E\g2'd}l3ѓ %ӝ|@ۀb\wM?Deǧ{Adb:@g;+lEېB
-KH_cɌZ/rhE<^\nMF$ވLQ)EpV$㴯.ei&Zo@ sv%jT)mUWj,U"4W1qBoes÷8S8]isPCl22a\ftOG5#5u"
-c࿦e61NgQ@KeuXd3>[s`>yd˸E3L"tȢ*%.߀N*eߠFݼY|1͔YY‡ݻ_1`۹2G뒙n1Z__1C69dzxؠh}֟/3 clw$Z5_q:(*ތZxendstream
-endobj
-87 0 obj
-[ 241 0 R 242 0 R ]
-endobj
-88 0 obj
-<< /Filter /FlateDecode /Length 2156 >>
-stream
-x˒ܶ>_WU+.&uHxSN(*,0$f1_"8}h
--MuDsjtVW'<8(O'
-/]2թ*X] xSB2ZZ,b0--e$-xj訳Zc
-K
-ljO^: 8Y#wA5j{V
-,yGSN|_׵fU,Ufc#Y0ԏ(ۆn6?M'‘2J#?^|9X[Ă`c;32do
-;b&|EY0M!Sƨz-q&K5 t"E\\n@5fC7ۋbsk=Z :P|xIK`;{OWQ
-*mKaV!\![B 1
-EkWE-5)vōC7-KchjAP|دa%aSsvZC܎kϧE5]qxD'mktBh Sb֒4^#f!&^p} 63/r]|Ȁ")fQ #3&>ɺsP`zc~9(&0=*0 {K⬸l/~TʑY^$׍lS kjjAg3hM^C>
-_2(zP}0([5{-D^A[ThAGaGnU,T8TDR~B?j1{01/ =7#/0_ OZ);nEj3!F*޼ *(k/P~5c](Mia۫nrs.>endstream
-endobj
-89 0 obj
-<< /Filter /FlateDecode /Length 3127 >>
-stream
-xrͻ ƒ
-d ۡn{q F&\o(xE~W/do?SEs I)C44<vb`Gm T1\p~߫!^F@S{'bd~|<jeYLJڰ8>gsB-/?|")7xfHRo+a?.rrZi)~?K=q|<VۈTռ9)>qyIe2o0; b׍څ:szד05 Q3޷c )d9dɌ2/zZ<m &ּ:.'D1?aXb9!'҄f+pGi i
- }
-drFV_TۨnTNλZFA-$XwBI>CUڍZ7 9Xj-p%Qy&,5 NBsD8Г2 P_ pEOJ2r8`ܩ3D suu}k/&h:u3iXkdB^ݥrK"Ki}aL,øyT?r\H8²lE@CdqW JPJЛ
-d.hWy@b֢keݨ37v7Bf?,Rֆ#Cl9fK/7T@Ԭ}^ƻ=um+?/qO]yBk*I]ĹĄAܠ.Ma^mZ$8gP$ĦC;&Ѧvb!^R7̺
-3;a ]Ff֎fTS>a_r AD{nQ5!ʁ
-
-fGNgfr+GMWhO|F9~trl
-[m'=W\+.7~͵͸9scFgmPQyR!j3+/5]Mvz</}U#Xjiub#I510^N_\;xs6'`[ G?paH4oIC(-b 3c_/<455S= *zQ$RN$qdJES$at?BGB+[`9/;3;KHXd}<"/͍ª\qP6'YaA\+L(#J,X N*k("
- *uDwlytXE8"s#s]0@7Qxm (R9!=
-h*d$GdfF6!%]m;|ȥV ̓k %Xuie@zbZ[a4h4s}lF<{Ci|$z!jнGr! \bhYf͉ Px7Mȋqz]³|1 k/k_z!\k\!Hv-{^`&x% ^E
- q~:&nTACwo+GY:X<vR@(sS
-3>Dkk <V(l "E6;#fJ5ɇ
-
-w03sPB } =Z)/5AB7 Υ?/L
-endobj
-90 0 obj
-<< /Filter /FlateDecode /Length 1415 >>
-stream
-xXr6+pWihKIı|%B"S\d4Drخ&zE#.~$ɮYHGdE1BǏHC$HWYW@IW%|qArѲ߸n%ՏCD<l&E(OJR'ɦ!_>ۂw/=mw<pl~[}\DxA$݇"
-7Vah
-򀃶Z|#1|.0\;JyWEqҋv^ƝU"gz^YgpD
-kqI': Ŋ>KjVJK<yOezuv-Cٍ%׃ݖ[I暼^%H\Z/3H#gSwm0 $WCr[Cle {w]s0`m,{^`?W %ҴL;g#
-':K*OU{0,ibm8y]buNk5Mo;VJf}̲ZzlUKvr_նl3fmOyx6DW OM^6Xʜa/w!#eɠ"k 9ִ-YյA)ү<8/ CԢK+{p"E^s_1NJ,$IxYq +b4IeazM|yqxMO7eiy7c$? l@[lٓ,A$&H[ dfUΞ$ѥvQĢj[
-ZpFLr   PL(I:^ˢ#Ep6e5jgn-#h0cL򨻓9JN6$N=û#CbUjD@#HH[7wRH\橋I\LHy#N
-Ǐ}#u֊m0M]U_=ވc x e ,guݝdtctxYwF`q_H\Oj:W 칮ØE?k50^bk64#OEBy45MxfYNFCۑSM'TBSW)^(Dv!p!c{q0-"~ps?˜8+`GW7mߛg
-endobj
-91 0 obj
-<< /Filter /FlateDecode /Length 2600 >>
-stream
-xYI۸W6}雗xxܶ;qf
-lMNxk| P(T_UA_7>VI
-R#K;wa(_s,';<O+SfWH]mv\ֲ}צWYWO2EF~&=up kK~\E5g|X1G9bϋÁHP% =Ӏ
-'D5c/ ɯ:`1-yψmVh{G>mrj mk^G'.xӃm KqY2pWw
-g b$0Xt>T*8LWp99AK֐@s8ji 8ϰ0bӾ?~|tڍ8tFlyEu.l]
-A6t<r@;Lw%YмYɄ3
-u|؎LHrr`-3sōA
-E1iS%-x U QO+Cm!ť2V'9dá\z9WbgII*&A[ M6. a&*0_VI%8| URQV+<nG
-mqU\X2P͒A1R(5?kX&$ z\:N W]'NO3Mp`)]X23ekXr0p,*$Yqwx {MLrdxڱMq j4L]{ uϿU4@\u`i;uWSW|pCW,x*x= -Qh՘cQ,}M<!v"@w~TL
-ʶOJGҎ$n+UP+YVߙ`Kwn'yfL\UPÝ'gpGW(.,uw\赑Lz* 6_?)-*,M>'RqP+HuY# aCtl m
-v'*o;XX .:f TaUU4UFi."ُzC ZO=MR 5e96xE VfG
-_'Kݗ"v P+vgv *Q"HNkg2q^fW_\֎=/'u g
-TMJܯCCB\iȝi*w^rچe$TEV=&$dμ\h2m4
-+ lri̋ҫX{EI\t$N]HaboߠC~D2!Hc ݢ%G4L<`<2?b2ȞalfW{ۃ9N4&[)L
-(ok3®
-EoeVW4w>X<gydyTX;' .3ߺ$|WlU`Ջ__VQ'hٗKMlGߐpIZf]lSP%ءofq濎endstream
-endobj
-92 0 obj
-<< /Filter /FlateDecode /Length 3288 >>
-stream
-x˒6>_=yR5IxM*Nxj}HrHHbL2Iy[|ȩ=dT 4FwCB
-FG IHjT0,!G ip7`f$. |H
-yr luS=1EAy1Y
-ù\vȽaUITh+bQ.nv3GU{~:5/ZsJh5yssx">ElTP9aXElvؒxDŜf#Z{S$lj˲`q<'G:0cO4@'ϳAkwXY!JR'x7F:!ؤ)-bTAZ܊6isSFsr*P4ˁxNڭFJq`MS;c5j'à>Շ\#tD,Mh)Xӆz[7x]\ ȄђU| XJT-xY>Q#[{@p<эv6*"TzQQ pL^Bx/Sns%=[vk;:Sݝf!D!U-#f !ڷcsW)$}bp),v㗨4dzرYÀM4s[=X~!BUA$9 }#V4 Ar+d}sV/0 2z?u2@ N )]T3N( L؉蚺ҋ0U.J_ן4O/>k<6:J!󶁛of9ޖ]18v!eANSr㡫U.A͉C
- <YbMP@|ꦨ,è((] l9S \A2m0HNidsCQK !}݂"FNC'ѝT*i
-\+(Uz{>p
-~X+mhҰ9vod
-IM7$5M$T06gDPMφ,(0-B;`yU5%EZv h=H}?L,U#hZoo&ҝ{ 吝xTҌ7;sˈ`0,@@$r<#e@pM!DJOxN}G Dw
-$w'C g~7j "a4/i3zFceyyGSỉi1U-@<;rٖ&k@a :V[EK+.l@<_g&1HK~L/;B.<iGlA ꈯ Ԣ[zI~IIO$3nNb|ў5yo)c7. 8]$NoJn1
- 9aU/s/oU|yNH_sXeJJ؄gu7flhgK5A|U]ď_eщtkN)`/Kɉ4k#5t 5Tai@uj{ՠS@Lla}@,PĨ?"xO?#d+ >\AɭÜyYQ^Y!K'"Ub{c!U8%EA;Ξ] K+tudH7 d%.5>X,kah*i2'TêSW9Ϧ4< }}} N{~%8\%FZ v%[Ϝ_; 9@JγGY
-+nvrԭtnL]&IB]:iWN ;^R
->mq)wvp,lg
-̗ D%'^y/h'+endstream
-endobj
-93 0 obj
-<< /Filter /FlateDecode /Length 2980 >>
-stream
-xZY6~_8Û&>Nʼn홬S"2!oٗ*
- /BN} ;ђlE'v=w8DP; Kr:+gnꚼ+xZޟ }뻵e|x޳irjf /^ a%A7v7x@TSJ`XӍ/,6v6Sڜ/iS]7e=TZ8i(cQ1B^t<֞Y1<NY?##[TmhjhѰe_{cp]˚p <i|M0*KYٽ|t`mEc@,Ԫ!Њ!vyo7jmq6G|5/(+OǞ-#J&ƀht;|Z dm0u)ƢM)Ɨc[~diqpej}tyڼui7;łlbc+[z8h?A8JJSI:Hͷ-mg[<tQԂhZ[F\%&F0>zJ,17"ЙɌ4o-,,e9=Sc$q>1.&'*@_lܑ` ={=XRg<g0d :2H)OrX9aX-s\l|QHdܼ~fuM%N]?
-i"<Ne*;1ccD&Y,o<@ϖ+{;ORCb(y'-+'Ӗ7+MC##V2à JUHԇi+I>9VQy{uGVzpk.t\ 4݅2fkX N1DzF7~p=#o{(P#)țiPѴ='Q4YDIŎXu/n ew\l Afǟ )і jyVUŘRS˫
-jO@M*83uc#w 267 ' ޞP[TX,(*#EMp T>@5Ҷ0A#znPu ҆XS(6 Q@- BdӇ{~in0#@f/l1 wuQypxQ ԢWdF[uW2/AߓV
-<VӊWt=Y/kV2$<9g4|{~MUE}P/WmZUޙ*D+s?+W
-ؔb6EoUan&FZ7U#uwJlx뉊pU `ګTo܍06NNRQ\= \i܎Ir,WMc[H>سoA$Tk Inv ^G
-HHUP;)8؈xRYZEH6ݯV(iDѾ<cVasd36'Fy7s'j^ߡ%WE]P$:0 N/YĉA6K^~i;<ń/T'ʛ[gS»]DN{̽Yϵюx4s|}L2~/f@o2-}l?XeO`Yvtmc{&ӄuP4-C[E_n4oq$T, /..n_S~X4U^y
-g3HW Q4id0Mٛ7I>&;տΜ$!n> 9z>Ǜi-<yo<cT䣳9ڧg94} XdM۞Oeoh[8
-"ԩH (Z5Z(Y`"O&h[GBo2ڍػGVWes7W<>^ endstream
-endobj
-94 0 obj
-[ 243 0 R 244 0 R 245 0 R ]
-endobj
-95 0 obj
-<< /Filter /FlateDecode /Length 4187 >>
-stream
-x;ْ6r|M>Mqi[ T7,. dHF#H$ׇ8ߓSI?=JmqP&AZPS^q&yp
-΃Vb@b!
-XkPrս(&Q]Țjdx9am/DӨ 谦(
-ۏR8L~?|x_~d7&[Klyc̏bAqsӱoXá(uQ4([]IvWko <:t.˰v5m3@`\@ AMra_UN4')YGi
-W)0lsa$048Cp{ey\9E܍bYCǐQa;,;H4޺I`S,p Z[/`nqDNxtk V&=EdߟN3bX`4l(FwX "LJ84.[,VP%I7<nԃ 0/V@-]daШxy̧QUpʪXN  a~xFۓå3xN.
-2Yj?-ȼ ڦ&q
-"s!ҀZ]ްqkС(Z6gm,VzWl(x/mѓxS8]zq+KbrڡayKAK#ѐ&t,:4 t49tbe48 Qt6]x'y}N1-;eBѷXSqO<܃Vf[ѽ\%FE#b$+[ӷ/7"* ENg/"}Y,ig]5[7T;%Bf~3vjEB-GP}A/ )^-
- CeR,:"deYiA߀ՒSBp#Kg1Ll&%3V-'6WW61Z%2.@3;,1cFհn Ҫ oP(C>uS@dڋGBW`9+_]:sɇuEm<@+VgJ*WrVĴrZEF̨sA{Ⰲ]v;(sa;?d'd(eDM[BtSR x,EXbԾJ0/vX=7scnhoC4 ~DDn@=gw)'FJh4S9 9y`@
-#f"n "k 2gfmyڣ1p"+;Y^m|=MC{KKiB9hhGk i5[cGܤd zFV4rm1g W٭۸"
-37<3u$&.aÊ^Z tQ]@Oh/%)"VV{|%EƱdenoŨd &gX<!**:ZQɘgTj,n7lJ#@9eRKAb‰Ӱs/I1fPJ@pJ8ۙlf;8%ʝ+e숳`(_9M[8IJ̊ m蠴W]=s!xԛ0-ᢝEUk׋bw3gQj݇Z4L*(E^0hPQFUğD
-0r"FE!G\-UzcI.{ OYyd\
-iFFmbq`.s \ B.⩪(lIû5<}E~Gp- FctM VuEy]=Mc"ՄV#V3~b3
-1D*Z!
-B&~e4ID\q ,3#L` ijQ >RI)x#(0*JYɦMA qR /4elm=ߌ!f lv Ɗ^Ro`r.<\1z_H",uU#kx"J,GlTH3x=:KI{F*.iWÙ
-moEPad&({
-} ~z*Rqx UUҸ% KLWaY-
--G߻fIULe%e%t =
-_P|c'L=Fߨm8Fl0gVM-,א)LSBVż Wy{m`bÀxmppk .Wu#M0Ugym޿!* })t1ѷЗ%ӗZ7pߖYX{ .Mvp%I5:#elߴ~bZ(M|[~%Qfz}hEqz G<q8N%cvtP(1 ԋ'͊i4< O/5&^vfQCxz!x磆k(] k&Oucz µocS=|%jCfmz)8V&1M BڃVJTvx(G~S""JߗbG/\Xh,tP NRח'Al'ZQ%Uh}[*7hjG
- |kUQ1a by=fE#>VpٷR{foM
-)cY;T.[?>7_#aendstream
-endobj
-96 0 obj
-[ 246 0 R 247 0 R 248 0 R 249 0 R 250 0 R 251 0 R 252 0 R 253 0 R 254 0 R 255 0 R 256 0 R 257 0 R 258 0 R ]
-endobj
-97 0 obj
-<< /Filter /FlateDecode /Length 3516 >>
-stream
-x˒6>_5ܜijVۙ! ;Ig
-׎qt<f>WCdzS;8xh<Q*RI2:v1;pf o4sa=J1[.M@Ca\JS8АjÁW᧭ɣ҉n}jCnv/wa ( gʂ&_l Lu1Voߙ$DX }5琁gM`H.0R\`,KA(2qu׏MT mAzgG*5TW*|E w="! <ขZ5zЮ*ូmۃh'o
-(ggP'i FX୴C`с,ժvz|h޾sCM"Fwlx#j|P"=eQ!Tݱ]@WIqNs&d+X{ʓɍ\X_m4D؋tc C׷_ zlj&Q *`t&{h
-v~- a6p^M
-<7S^4;y4$ g3c ,K@# 쇥{Pނ"} ^%(!APH{M)4hwHBf3cPv}
-afղٍʮ$ABܽ uWRD<PBRB{Ɠ eq%,PgpՑuH~A邧i
-j;xw,
-8$SY1Oy I cgJR|U[[U]nj
-xH4Uݜum}>qh<$H (!IO*丳uFX4
- pB0⒌(/ ^s@b$8Z:ڂ%a]Q0BKb<jioQ }ԛXS)Y\`
-
-rǺ~0\23g*Ӌ5|/Mҋ_AL"8@-(g|tb(Ӗ>Tks#G2WUj<E^9=n[?QD)>v3'_R
-%P_?e7&`6O2^Ju"4Ǐ>B= +=NJ?^<endstream
-endobj
-98 0 obj
-<< /Filter /FlateDecode /Length 3192 >>
-stream
-xَ6}o Ӳ[۳q`o| ,`KiՒc[Ţ$vcc͢b/Wo?apEq: 0YL}*c#E0س߮+?alp/ѩ/?fW?_=n[q,\'?>\Fl|;n+J-g?1`gՁ. r5KАE> *× "taƊ ulE<{MaȆ?ӪQ"g˴amZY2Λ `{WfE+<v;YG5!q]S_b(XQț$U;P_rydEMonΊEZ[FDd6օDANlH&x׶"Rʼn}6Ng
-y4,e"lqf/[) i*SܙgZԧki 031/N9kw/~G&OHsTwh,rL ,b{ϣ/xoeS=+@}F<ngf<gyִ3\ b=).S.'ThC{㦫n~nx5BL+~8l?М2!!MVj8BlsN 'ʝb{yR`+Y5
-h%pr۷<8#6lMIj#,^|"1Y!ZRӭs]~1HlrM.?q[FEpv/Udn/A0EFEhZAڌW+t'8r
-#!eFŽ{}+"kȳiOYPv#=c3q
-rd]_ǁG8 ֌b~Fp\à{c6ht&JJc& !+TCib&P 3!IKfEzvab@wB~*g<:=
-`:T جi:(5kB|h%\ϷbC_壅7{VΗ˅rva;Yc”`5
-cTQ5_=)DN=̙c\'}hSC%AImv:@ME+0|*ei4D87 `EF!(ȳt
--8 <Yܽ% kT"9= 'kWPթZ3sѓ
-P2퇳U%Y^l*d,:G͹FNUU@<luF㙐A6<\ua׽*Gf<̮`rVırh9Ńt@xi`IL[Abh@.M[wIKMzkfuݣ88X LTLnaАk Re
-7@_{5}S'NNG8ۗu
-8Ch֛A,#\;FP@7Ch~Q\xr_8H ~qL8#0ʛ`=|EAE^t
-Bg
-WoVh^J!^t()"@s,V!R@<:*H =#V[98Zb˱:cS/mފj0x V.Q|7Z3pۺW9t A,:z0`t*D )H DQ@.'Cv]ɺVx.պBsb+r<*ßA'ŧؕ>dhmnZ Rzy0t~Ŷ@Y-wu%*eB4@OC/1F%CTh r194M_2XϞQ{__=.Pq}rkʫl49km˻(ud͜j
-Öz-9oOtX0K)Z0 E'wF*=]Oځ>>IW{=Y4ʯQP0"Wćjt#(0DNՙ:@l8@cޠa?wtxzKkL=lWJ8Ta+JֻȳԿ_ iendstream
-endobj
-99 0 obj
-<< /Filter /FlateDecode /Length 3175 >>
-stream
-xْ6}okWysJ|dI qM
-I2@
-tyCS}wWi
-~'spY~7eI4/4 սn Sɍ7s:}{62 "^1xC݈ǮC{pH-! O%vĸF*uH B[n={%a:Zx\7Xy~琩_
-P*q2/!c?;Wp#pY7]_i k GMgd@lÚ*rβI<a 9rz# IZ):C\r,@^NR eZSfŪ`wڎ8U ^g%ޙAL&!á=,ۡ>-"ݪ\8!-ڝM}O60`@h릜AڭoaюvLlx<Z1j.$De<Q1@!4uC"` *uXLWˋ4-*Al`+(VF3w8e2ePq[Ǎ1`}w=ansy
- i{QKO
-r`HyHtA+,<nWNhNL( m glH@y\j!-!)Vy=.z}|<SDWM(C)g=G Q
-|fnB_nu%I
-:(yJt W*m<@
-Lr[I xƇBrxY=|>ӘqNϊ^
-emϘ+{̀ihJtQ d{Ft̠T
-endobj
-100 0 obj
-[ 259 0 R 260 0 R ]
-endobj
-101 0 obj
-<< /Filter /FlateDecode /Length 2854 >>
-stream
-xr6REjOZ;N98~h+U!1CD| 5~6 3䬽t7~"`>wiȲ3Y"RbA  +(-?8~Q_짋?9a?eg&x_.g?\ܾNXೇ8(NtqA+6PW/~|8&
-5F}!]{f>$#}ҀV~Q=k?V*XG@6G!Jήwvl=zܱ% k֍ |/Mbgާ0LN >y슭e'TɬMf;Y;):z V}0~($ZdB)={4ēWV!X~к]1BFQ :۞# .Y[>Ⱦ 0(ep\7(/ 3.ӀeS=
-B" O| Qn9NCY{wflm]b|}ۂz0OJ^PN~azٓ&hBU\,΀W ^1HQvjD(+v %N}> $ 9ȆMVr_{ZXY6Mm6[횮R/e%{[S#ZN}1Z };B~#x7qñǫ^h ΏkE5+L$1V2^p> D*'ܚt@2p 4cj&M[:'C>(L!»W'p~tj\N\hF3ƍnjB֏?sAJ(踋د<&47lk+}_n=Ah %:K%WkNs$n6S($ս+5ۿDf?ajs@P'?榇~|bD&\vZ;p孿!ǽj(BƄHS%mI| O~?]9?:!KajmGWCK":"樴XbX›Zۯ)Ge S.QmNEElymUB%c?zЅN plzff0X@XpAج48Gt';ՏX݈ji?Z
- 2KY9 -\9%XM8i> Jn I6%d`U3[}!{|fle`%ӕ +(b-,.1K;֜ P("`|"jSADshMx%=쀬r̕.(vX)R
-z5mϲ U"_pUǮڜpAU `來fۮyeϛ`PKLK,{^hoYŎnŞH^jOyB#ƫm=<Q(S"b!˫qLOipZ-!Vg\ls@/¹ӕǞlP>Ҁi5p#kM 5𽰔wo,XԀ[[5
-J^(bȂfJoB/뛗?@d4&jv
-lgn( 5jj_{O|/3?Q !JT.E3Eǭ0 W,p2uVfgw7TLJ/]:9@[%4pHbG^dn!n:Y{@ >Bz^
-[x hdn[U~vP%>ѡa׆(Q;gH) &x&":P|mJ;H.qY 8ʼvG\ qt !n!l:MA,Qywy&=b } L&5h_x~qxBk&[m ceg)xBSf[C3g $S e)5^;+_MBL }펷ٝA(`r&9$%K4$OGnaXD'SHf4XDpW"l,RLTFPL $J!0|ΩhKAg
-n55עDdNK(<L:]z{  (Ktv'ӾOrjQhTՒ堍o'i+I
-[Kih݇(ϑimaB.T˓S+ F ۬N<G xQ:% "2X-x!֦H!_>--~tш}]CQͮ?NxIOظ' f M'蔏D!Sf 10Uxex8珁V0ٿG8-7Ľ
-endobj
-102 0 obj
-[ 261 0 R 262 0 R 263 0 R ]
-endobj
-103 0 obj
-<< /Filter /FlateDecode /Length 2081 >>
-stream
-xYKs6ϯ-vD_㛜XN%){%W6Dbf& )~hV'ok4~Ać?'݇$vFZ@Ґd$ "/IEqLJe i?}W|dA|Xj{I1Qb,&Gý/$?xYo?ϻ ?hYˠ>ӎ#r
-n@4j6 8D}wSߨZ\Fw=|; R
-/lz;:{[ s_a63Wr=%axyK ')
- jZu>ZԊ`=H]rVuE,HE{8 ܺ]k[gџ,(o-;{vM )E;oBRdiS+DL̑756
-(Ҕ[[fS2RSetEۦSVﯖ%K,h<+~i-+ HouheeP+΀"|?8}/UY48eE'>zw M'KZ&^\>lz;+;zwC6Tu!bDUºc6{6S8L7rcD0f0a-l1O K􁵥⹡:phʅAm4ȳʂh[n](%+!B}]t{^ ӁNhl804o[Tm)1 y]}^p|>QWA}+%ՓC7FxlڕV,VPhKҫ
-zՌ19|+y(F*3
-P;W"?<*$&Py^]VUV/g#>(E`8> ʤƴIT|:REf2Z[ GpNkb]hyN"/Z}Ct.-P:2ԝ/wA-ϮmhBey9xd+:qC\KS^=)*zA\LJ3~W& "f|7Al:GWG~/6Aٶ4Z8Z;Q7/^gS(=eN^{f|XD+6p%.dy?@֏N};^a^(c'U(&[2\8q4Aq|_?2>&vhX,H["նb>ʆ%h]#,.fe}bZכعd0apu > ԍܴ> r`^^=񩋴{n1o?:ģqi:&~aoaw +Gs̮D\u <_hY"TVOJWwiE mfF_we|w_7c)E9/w-0endstream
-endobj
-104 0 obj
-<< /Filter /FlateDecode /Length 2673 >>
-stream
-xkܶ
-~hzqE .v= DYz}ܕt>q
-LRvOӧ{2R!m2bG BUF٢2\`irxٟlvBO JyR[1qP5 ;גz-F3+[(TV
-!\?XPB-|T7kD0\HIzuGƒeԬK"XGcW޿}n=&NOTqeFvԋGlYlJuVb),YMNիWo(GP<IT>^ech:ͺSA'hgiA(76A4rPddtY>EeRoWg OuúΞ;# #$YW`ZN+{6 ZWvC#Zd%PmNbUY,1=I飪{rI#geΒgZ&"K=urI$DɊH6:u$A"
- /Mn?2+6d\r L6S%8@g4S=65%sXwF$o%
-`H;y)"̤Z݅Yl_BeW19K15Es
-D
-(D g؏m <PvW,2a*S/xT7v>#^-_Ou6}D:e3z *Vxyϧ*scHLpV
-4@Npf,ҕF &XLw{ j˵At*7`%^8x~IKb=DZ_4<X=?SW!Uv+HO5EP!Eȁ*-:l7M%Hy\r5% p12KTؕ-Jr5JͮFsX.8Q7!KSp2@Ԕ¥û n^ ȃ|sZx)0FYr2,SBI ݧNYMyv%J?4=s1țEA
-O b/=Moϑ4 bU\J%WÐA5;II)ջ~zendstream
-endobj
-105 0 obj
-<< /Filter /FlateDecode /Length 1604 >>
-stream
-xXK6W Q-m6n99m1+Z>$z4 p^i ?I<^Eablpjd.
-~& Jil|X,.*N+ZbAEE%s+NF*GKՆhRG÷hne>m'p4k.J_|A?7g.EQ/p;( 0M|ߏc}mK>_=w{⸠ "ח])R--z`(5E-~ew]OmqLxGYc` YbABE9H 8*,,ޗ; ąi:nsNZ!տmN4PFUn' w]ڶ`[5!kg ĂO$A}xxW?y9(8,jdLL`(#@ۙ8M\53-_54e BY7 TdÔm'B dŚ#QyD#{b5Y
-.Kl"In;GPRKf}**1 bD%>]B]-hX*w i-$sF(Fi ~<2hEU-\(u(w]uYNjv&etɚ&w݊2Gv fm˸sj붢w?'U%y.2r Y.HP6I,<z鵰 hm3_[Ɓ( }? ӅkG%E{50>v(A߽UC KP[])+in\`v˸[7h|7@k/
-M2tZ+ekk
-Plw$5YⳀ<NZԜ1J36OB+0|>g;jq5ϝ(qa.,)jy#bPP˧;捞x]s䥁z.Ffmtv&jxu$. ~?ucDendstream
-endobj
-106 0 obj
-[ 264 0 R 265 0 R 266 0 R ]
-endobj
-107 0 obj
-<< /Filter /FlateDecode /Length 712 >>
-stream
-xUKs0+dU
-J;~)i3R$1kz mF^$>w ǟA68v]r
-ya\\%RX{FNB8˚Ϣ_ϋ}3QOXHO)orf'vy)VP}
-1'!.~}ΝF^VI\@)JZ$^gę¼_۝(k-7p
-3v\XTmPX+\sQ7b/=9=Aum)]m
-+v'ʾf:<crdRhD|USf][7?cz ҋPZt=j5p` Z=<0nήMOz,<Fr/MLȳe=Wƽ>@YԮY/i)Jb]kȇnvѠP0HnW]Nb^\OyIFC-2> SME%1rll:qF¤Y<0~ܕ͂Ѳ=fF'yMݖp7UgJ q@endstream
-endobj
-108 0 obj
-[ /ICCBased 267 0 R ]
-endobj
-109 0 obj
-<< /BaseFont /Courier-Oblique /Encoding /WinAnsiEncoding /Subtype /Type1 /Type /Font >>
-endobj
-110 0 obj
-<< /BaseFont /Courier-Bold /Encoding /WinAnsiEncoding /Subtype /Type1 /Type /Font >>
-endobj
-111 0 obj
-<< /BaseFont /Courier-BoldOblique /Encoding /WinAnsiEncoding /Subtype /Type1 /Type /Font >>
-endobj
-112 0 obj
-<< /BaseFont /Helvetica-Bold /Encoding /WinAnsiEncoding /Subtype /Type1 /Type /Font >>
-endobj
-113 0 obj
-<< /BaseFont /Helvetica-BoldOblique /Encoding /WinAnsiEncoding /Subtype /Type1 /Type /Font >>
-endobj
-114 0 obj
-<< /BaseFont /Times-Roman /Encoding /WinAnsiEncoding /Subtype /Type1 /Type /Font >>
-endobj
-115 0 obj
-<< /BaseFont /Times-Italic /Encoding /WinAnsiEncoding /Subtype /Type1 /Type /Font >>
-endobj
-116 0 obj
-<< /BaseFont /Times-Bold /Encoding /WinAnsiEncoding /Subtype /Type1 /Type /Font >>
-endobj
-117 0 obj
-<< /BaseFont /Courier /Encoding /WinAnsiEncoding /Subtype /Type1 /Type /Font >>
-endobj
-118 0 obj
-<< /A 268 0 R /Border [ 0 0 0 ] /C [ 0 0 0 ] /H /I /Rect [ 72.0 680.124 154.961 689.124 ] /Subtype /Link /Type /Annot >>
-endobj
-119 0 obj
-<< /A 268 0 R /Border [ 0 0 0 ] /C [ 0 0 0 ] /H /I /Rect [ 534.3 680.124 542.08 689.124 ] /Subtype /Link /Type /Annot >>
-endobj
-120 0 obj
-<< /A 269 0 R /Border [ 0 0 0 ] /C [ 0 0 0 ] /H /I /Rect [ 72.0 668.124 148.536 677.124 ] /Subtype /Link /Type /Annot >>
-endobj
-121 0 obj
-<< /A 269 0 R /Border [ 0 0 0 ] /C [ 0 0 0 ] /H /I /Rect [ 537.134 668.124 542.134 677.124 ] /Subtype /Link /Type /Annot >>
-endobj
-122 0 obj
-<< /A 270 0 R /Border [ 0 0 0 ] /C [ 0 0 0 ] /H /I /Rect [ 72.0 656.124 205.901 665.124 ] /Subtype /Link /Type /Annot >>
-endobj
-123 0 obj
-<< /A 270 0 R /Border [ 0 0 0 ] /C [ 0 0 0 ] /H /I /Rect [ 536.802 656.124 541.802 665.124 ] /Subtype /Link /Type /Annot >>
-endobj
-124 0 obj
-<< /A 271 0 R /Border [ 0 0 0 ] /C [ 0 0 0 ] /H /I /Rect [ 96.0 644.124 202.929 653.124 ] /Subtype /Link /Type /Annot >>
-endobj
-125 0 obj
-<< /A 271 0 R /Border [ 0 0 0 ] /C [ 0 0 0 ] /H /I /Rect [ 536.926 644.124 541.926 653.124 ] /Subtype /Link /Type /Annot >>
-endobj
-126 0 obj
-<< /A 272 0 R /Border [ 0 0 0 ] /C [ 0 0 0 ] /H /I /Rect [ 96.0 632.124 187.474 641.124 ] /Subtype /Link /Type /Annot >>
-endobj
-127 0 obj
-<< /A 272 0 R /Border [ 0 0 0 ] /C [ 0 0 0 ] /H /I /Rect [ 537.019 632.124 542.019 641.124 ] /Subtype /Link /Type /Annot >>
-endobj
-128 0 obj
-<< /A 273 0 R /Border [ 0 0 0 ] /C [ 0 0 0 ] /H /I /Rect [ 72.0 620.124 146.658 629.124 ] /Subtype /Link /Type /Annot >>
-endobj
-129 0 obj
-<< /A 273 0 R /Border [ 0 0 0 ] /C [ 0 0 0 ] /H /I /Rect [ 537.146 620.124 542.146 629.124 ] /Subtype /Link /Type /Annot >>
-endobj
-130 0 obj
-<< /A 274 0 R /Border [ 0 0 0 ] /C [ 0 0 0 ] /H /I /Rect [ 96.0 608.124 183.041 617.124 ] /Subtype /Link /Type /Annot >>
-endobj
-131 0 obj
-<< /A 274 0 R /Border [ 0 0 0 ] /C [ 0 0 0 ] /H /I /Rect [ 537.047 608.124 542.047 617.124 ] /Subtype /Link /Type /Annot >>
-endobj
-132 0 obj
-<< /A 275 0 R /Border [ 0 0 0 ] /C [ 0 0 0 ] /H /I /Rect [ 96.0 596.124 172.009 605.124 ] /Subtype /Link /Type /Annot >>
-endobj
-133 0 obj
-<< /A 275 0 R /Border [ 0 0 0 ] /C [ 0 0 0 ] /H /I /Rect [ 537.115 596.124 542.115 605.124 ] /Subtype /Link /Type /Annot >>
-endobj
-134 0 obj
-<< /A 276 0 R /Border [ 0 0 0 ] /C [ 0 0 0 ] /H /I /Rect [ 96.0 584.124 194.093 593.124 ] /Subtype /Link /Type /Annot >>
-endobj
-135 0 obj
-<< /A 276 0 R /Border [ 0 0 0 ] /C [ 0 0 0 ] /H /I /Rect [ 536.98 584.124 541.98 593.124 ] /Subtype /Link /Type /Annot >>
-endobj
-136 0 obj
-<< /A 277 0 R /Border [ 0 0 0 ] /C [ 0 0 0 ] /H /I /Rect [ 96.0 572.124 209.663 581.124 ] /Subtype /Link /Type /Annot >>
-endobj
-137 0 obj
-<< /A 277 0 R /Border [ 0 0 0 ] /C [ 0 0 0 ] /H /I /Rect [ 536.884 572.124 541.884 581.124 ] /Subtype /Link /Type /Annot >>
-endobj
-138 0 obj
-<< /A 278 0 R /Border [ 0 0 0 ] /C [ 0 0 0 ] /H /I /Rect [ 96.0 560.124 255.333 569.124 ] /Subtype /Link /Type /Annot >>
-endobj
-139 0 obj
-<< /A 278 0 R /Border [ 0 0 0 ] /C [ 0 0 0 ] /H /I /Rect [ 536.604 560.124 541.604 569.124 ] /Subtype /Link /Type /Annot >>
-endobj
-140 0 obj
-<< /A 279 0 R /Border [ 0 0 0 ] /C [ 0 0 0 ] /H /I /Rect [ 96.0 548.124 294.063 557.124 ] /Subtype /Link /Type /Annot >>
-endobj
-141 0 obj
-<< /A 279 0 R /Border [ 0 0 0 ] /C [ 0 0 0 ] /H /I /Rect [ 531.338 548.124 541.338 557.124 ] /Subtype /Link /Type /Annot >>
-endobj
-142 0 obj
-<< /A 280 0 R /Border [ 0 0 0 ] /C [ 0 0 0 ] /H /I /Rect [ 72.0 536.124 130.045 545.124 ] /Subtype /Link /Type /Annot >>
-endobj
-143 0 obj
-<< /A 280 0 R /Border [ 0 0 0 ] /C [ 0 0 0 ] /H /I /Rect [ 532.212 536.124 542.212 545.124 ] /Subtype /Link /Type /Annot >>
-endobj
-144 0 obj
-<< /A 281 0 R /Border [ 0 0 0 ] /C [ 0 0 0 ] /H /I /Rect [ 72.0 524.124 184.956 533.124 ] /Subtype /Link /Type /Annot >>
-endobj
-145 0 obj
-<< /A 281 0 R /Border [ 0 0 0 ] /C [ 0 0 0 ] /H /I /Rect [ 531.894 524.124 541.894 533.124 ] /Subtype /Link /Type /Annot >>
-endobj
-146 0 obj
-<< /A 282 0 R /Border [ 0 0 0 ] /C [ 0 0 0 ] /H /I /Rect [ 72.0 512.124 189.335 521.124 ] /Subtype /Link /Type /Annot >>
-endobj
-147 0 obj
-<< /A 282 0 R /Border [ 0 0 0 ] /C [ 0 0 0 ] /H /I /Rect [ 531.868 512.124 541.868 521.124 ] /Subtype /Link /Type /Annot >>
-endobj
-148 0 obj
-<< /A 283 0 R /Border [ 0 0 0 ] /C [ 0 0 0 ] /H /I /Rect [ 96.0 500.124 164.008 509.124 ] /Subtype /Link /Type /Annot >>
-endobj
-149 0 obj
-<< /A 283 0 R /Border [ 0 0 0 ] /C [ 0 0 0 ] /H /I /Rect [ 532.134 500.124 542.134 509.124 ] /Subtype /Link /Type /Annot >>
-endobj
-150 0 obj
-<< /A 284 0 R /Border [ 0 0 0 ] /C [ 0 0 0 ] /H /I /Rect [ 96.0 488.124 169.762 497.124 ] /Subtype /Link /Type /Annot >>
-endobj
-151 0 obj
-<< /A 284 0 R /Border [ 0 0 0 ] /C [ 0 0 0 ] /H /I /Rect [ 532.098 488.124 542.098 497.124 ] /Subtype /Link /Type /Annot >>
-endobj
-152 0 obj
-<< /A 285 0 R /Border [ 0 0 0 ] /C [ 0 0 0 ] /H /I /Rect [ 96.0 476.124 174.195 485.124 ] /Subtype /Link /Type /Annot >>
-endobj
-153 0 obj
-<< /A 285 0 R /Border [ 0 0 0 ] /C [ 0 0 0 ] /H /I /Rect [ 532.072 476.124 542.072 485.124 ] /Subtype /Link /Type /Annot >>
-endobj
-154 0 obj
-<< /A 286 0 R /Border [ 0 0 0 ] /C [ 0 0 0 ] /H /I /Rect [ 96.0 464.124 159.023 473.124 ] /Subtype /Link /Type /Annot >>
-endobj
-155 0 obj
-<< /A 286 0 R /Border [ 0 0 0 ] /C [ 0 0 0 ] /H /I /Rect [ 532.164 464.124 542.164 473.124 ] /Subtype /Link /Type /Annot >>
-endobj
-156 0 obj
-<< /A 287 0 R /Border [ 0 0 0 ] /C [ 0 0 0 ] /H /I /Rect [ 96.0 452.124 232.17 461.124 ] /Subtype /Link /Type /Annot >>
-endobj
-157 0 obj
-<< /A 287 0 R /Border [ 0 0 0 ] /C [ 0 0 0 ] /H /I /Rect [ 531.716 452.124 541.716 461.124 ] /Subtype /Link /Type /Annot >>
-endobj
-158 0 obj
-<< /A 288 0 R /Border [ 0 0 0 ] /C [ 0 0 0 ] /H /I /Rect [ 96.0 440.124 233.86 449.124 ] /Subtype /Link /Type /Annot >>
-endobj
-159 0 obj
-<< /A 288 0 R /Border [ 0 0 0 ] /C [ 0 0 0 ] /H /I /Rect [ 531.706 440.124 541.706 449.124 ] /Subtype /Link /Type /Annot >>
-endobj
-160 0 obj
-<< /A 289 0 R /Border [ 0 0 0 ] /C [ 0 0 0 ] /H /I /Rect [ 96.0 428.124 225.016 437.124 ] /Subtype /Link /Type /Annot >>
-endobj
-161 0 obj
-<< /A 289 0 R /Border [ 0 0 0 ] /C [ 0 0 0 ] /H /I /Rect [ 531.76 428.124 541.76 437.124 ] /Subtype /Link /Type /Annot >>
-endobj
-162 0 obj
-<< /A 290 0 R /Border [ 0 0 0 ] /C [ 0 0 0 ] /H /I /Rect [ 96.0 416.124 277.557 425.124 ] /Subtype /Link /Type /Annot >>
-endobj
-163 0 obj
-<< /A 290 0 R /Border [ 0 0 0 ] /C [ 0 0 0 ] /H /I /Rect [ 531.44 416.124 541.44 425.124 ] /Subtype /Link /Type /Annot >>
-endobj
-164 0 obj
-<< /A 291 0 R /Border [ 0 0 0 ] /C [ 0 0 0 ] /H /I /Rect [ 96.0 404.124 190.364 413.124 ] /Subtype /Link /Type /Annot >>
-endobj
-165 0 obj
-<< /A 291 0 R /Border [ 0 0 0 ] /C [ 0 0 0 ] /H /I /Rect [ 531.972 404.124 541.972 413.124 ] /Subtype /Link /Type /Annot >>
-endobj
-166 0 obj
-<< /A 292 0 R /Border [ 0 0 0 ] /C [ 0 0 0 ] /H /I /Rect [ 96.0 392.124 186.331 401.124 ] /Subtype /Link /Type /Annot >>
-endobj
-167 0 obj
-<< /A 292 0 R /Border [ 0 0 0 ] /C [ 0 0 0 ] /H /I /Rect [ 531.998 392.124 541.998 401.124 ] /Subtype /Link /Type /Annot >>
-endobj
-168 0 obj
-<< /A 293 0 R /Border [ 0 0 0 ] /C [ 0 0 0 ] /H /I /Rect [ 72.0 380.124 136.409 389.124 ] /Subtype /Link /Type /Annot >>
-endobj
-169 0 obj
-<< /A 293 0 R /Border [ 0 0 0 ] /C [ 0 0 0 ] /H /I /Rect [ 532.176 380.124 542.176 389.124 ] /Subtype /Link /Type /Annot >>
-endobj
-170 0 obj
-<< /A 294 0 R /Border [ 0 0 0 ] /C [ 0 0 0 ] /H /I /Rect [ 96.0 368.124 244.815 377.124 ] /Subtype /Link /Type /Annot >>
-endobj
-171 0 obj
-<< /A 294 0 R /Border [ 0 0 0 ] /C [ 0 0 0 ] /H /I /Rect [ 531.64 368.124 541.64 377.124 ] /Subtype /Link /Type /Annot >>
-endobj
-172 0 obj
-<< /A 295 0 R /Border [ 0 0 0 ] /C [ 0 0 0 ] /H /I /Rect [ 96.0 356.124 227.215 365.124 ] /Subtype /Link /Type /Annot >>
-endobj
-173 0 obj
-<< /A 295 0 R /Border [ 0 0 0 ] /C [ 0 0 0 ] /H /I /Rect [ 531.746 356.124 541.746 365.124 ] /Subtype /Link /Type /Annot >>
-endobj
-174 0 obj
-<< /A 296 0 R /Border [ 0 0 0 ] /C [ 0 0 0 ] /H /I /Rect [ 96.0 344.124 167.338 353.124 ] /Subtype /Link /Type /Annot >>
-endobj
-175 0 obj
-<< /A 296 0 R /Border [ 0 0 0 ] /C [ 0 0 0 ] /H /I /Rect [ 532.114 344.124 542.114 353.124 ] /Subtype /Link /Type /Annot >>
-endobj
-176 0 obj
-<< /A 297 0 R /Border [ 0 0 0 ] /C [ 0 0 0 ] /H /I /Rect [ 96.0 332.124 214.562 341.124 ] /Subtype /Link /Type /Annot >>
-endobj
-177 0 obj
-<< /A 297 0 R /Border [ 0 0 0 ] /C [ 0 0 0 ] /H /I /Rect [ 531.824 332.124 541.824 341.124 ] /Subtype /Link /Type /Annot >>
-endobj
-178 0 obj
-<< /A 298 0 R /Border [ 0 0 0 ] /C [ 0 0 0 ] /H /I /Rect [ 96.0 320.124 239.324 329.124 ] /Subtype /Link /Type /Annot >>
-endobj
-179 0 obj
-<< /A 298 0 R /Border [ 0 0 0 ] /C [ 0 0 0 ] /H /I /Rect [ 531.672 320.124 541.672 329.124 ] /Subtype /Link /Type /Annot >>
-endobj
-180 0 obj
-<< /A 299 0 R /Border [ 0 0 0 ] /C [ 0 0 0 ] /H /I /Rect [ 96.0 308.124 249.211 317.124 ] /Subtype /Link /Type /Annot >>
-endobj
-181 0 obj
-<< /A 299 0 R /Border [ 0 0 0 ] /C [ 0 0 0 ] /H /I /Rect [ 531.612 308.124 541.612 317.124 ] /Subtype /Link /Type /Annot >>
-endobj
-182 0 obj
-<< /A 300 0 R /Border [ 0 0 0 ] /C [ 0 0 0 ] /H /I /Rect [ 96.0 296.124 181.908 305.124 ] /Subtype /Link /Type /Annot >>
-endobj
-183 0 obj
-<< /A 300 0 R /Border [ 0 0 0 ] /C [ 0 0 0 ] /H /I /Rect [ 532.024 296.124 542.024 305.124 ] /Subtype /Link /Type /Annot >>
-endobj
-184 0 obj
-<< /A 301 0 R /Border [ 0 0 0 ] /C [ 0 0 0 ] /H /I /Rect [ 72.0 284.124 232.703 293.124 ] /Subtype /Link /Type /Annot >>
-endobj
-185 0 obj
-<< /A 301 0 R /Border [ 0 0 0 ] /C [ 0 0 0 ] /H /I /Rect [ 531.618 284.124 541.618 293.124 ] /Subtype /Link /Type /Annot >>
-endobj
-186 0 obj
-<< /A 302 0 R /Border [ 0 0 0 ] /C [ 0 0 0 ] /H /I /Rect [ 96.0 272.124 176.938 281.124 ] /Subtype /Link /Type /Annot >>
-endobj
-187 0 obj
-<< /A 302 0 R /Border [ 0 0 0 ] /C [ 0 0 0 ] /H /I /Rect [ 532.054 272.124 542.054 281.124 ] /Subtype /Link /Type /Annot >>
-endobj
-188 0 obj
-<< /A 303 0 R /Border [ 0 0 0 ] /C [ 0 0 0 ] /H /I /Rect [ 96.0 260.124 216.675 269.124 ] /Subtype /Link /Type /Annot >>
-endobj
-189 0 obj
-<< /A 303 0 R /Border [ 0 0 0 ] /C [ 0 0 0 ] /H /I /Rect [ 531.812 260.124 541.812 269.124 ] /Subtype /Link /Type /Annot >>
-endobj
-190 0 obj
-<< /A 304 0 R /Border [ 0 0 0 ] /C [ 0 0 0 ] /H /I /Rect [ 120.0 248.124 266.259 257.124 ] /Subtype /Link /Type /Annot >>
-endobj
-191 0 obj
-<< /A 304 0 R /Border [ 0 0 0 ] /C [ 0 0 0 ] /H /I /Rect [ 531.602 248.124 541.602 257.124 ] /Subtype /Link /Type /Annot >>
-endobj
-192 0 obj
-<< /A 305 0 R /Border [ 0 0 0 ] /C [ 0 0 0 ] /H /I /Rect [ 96.0 236.124 248.115 245.124 ] /Subtype /Link /Type /Annot >>
-endobj
-193 0 obj
-<< /A 305 0 R /Border [ 0 0 0 ] /C [ 0 0 0 ] /H /I /Rect [ 531.62 236.124 541.62 245.124 ] /Subtype /Link /Type /Annot >>
-endobj
-194 0 obj
-<< /A 306 0 R /Border [ 0 0 0 ] /C [ 0 0 0 ] /H /I /Rect [ 96.0 224.124 204.549 233.124 ] /Subtype /Link /Type /Annot >>
-endobj
-195 0 obj
-<< /A 306 0 R /Border [ 0 0 0 ] /C [ 0 0 0 ] /H /I /Rect [ 531.886 224.124 541.886 233.124 ] /Subtype /Link /Type /Annot >>
-endobj
-196 0 obj
-<< /A 307 0 R /Border [ 0 0 0 ] /C [ 0 0 0 ] /H /I /Rect [ 72.0 212.124 143.288 221.124 ] /Subtype /Link /Type /Annot >>
-endobj
-197 0 obj
-<< /A 307 0 R /Border [ 0 0 0 ] /C [ 0 0 0 ] /H /I /Rect [ 532.134 212.124 542.134 221.124 ] /Subtype /Link /Type /Annot >>
-endobj
-198 0 obj
-<< /A 308 0 R /Border [ 0 0 0 ] /C [ 0 0 0 ] /H /I /Rect [ 72.0 200.124 193.284 209.124 ] /Subtype /Link /Type /Annot >>
-endobj
-199 0 obj
-<< /A 308 0 R /Border [ 0 0 0 ] /C [ 0 0 0 ] /H /I /Rect [ 531.846 200.124 541.846 209.124 ] /Subtype /Link /Type /Annot >>
-endobj
-200 0 obj
-<< /A 309 0 R /Border [ 0 0 0 ] /C [ 0 0 0 ] /H /I /Rect [ 72.0 188.124 154.828 197.124 ] /Subtype /Link /Type /Annot >>
-endobj
-201 0 obj
-<< /A 309 0 R /Border [ 0 0 0 ] /C [ 0 0 0 ] /H /I /Rect [ 532.068 188.124 542.068 197.124 ] /Subtype /Link /Type /Annot >>
-endobj
-202 0 obj
-<< /A 310 0 R /Border [ 0 0 0 ] /C [ 0 0 0 ] /H /I /Rect [ 72.0 176.124 155.373 185.124 ] /Subtype /Link /Type /Annot >>
-endobj
-203 0 obj
-<< /A 310 0 R /Border [ 0 0 0 ] /C [ 0 0 0 ] /H /I /Rect [ 532.064 176.124 542.064 185.124 ] /Subtype /Link /Type /Annot >>
-endobj
-204 0 obj
-<< /A 311 0 R /Border [ 0 0 0 ] /C [ 0 0 0 ] /H /I /Rect [ 81.72 657.641 191.15 666.641 ] /Subtype /Link /Type /Annot >>
-endobj
-205 0 obj
-<< /A 312 0 R /Border [ 0 0 0 ] /C [ 0 0 0 ] /H /I /Rect [ 367.94 657.641 483.23 666.641 ] /Subtype /Link /Type /Annot >>
-endobj
-206 0 obj
-<< /A 313 0 R /Border [ 0 0 0 ] /C [ 0 0 0 ] /H /I /Rect [ 248.721 635.641 387.438 644.641 ] /Subtype /Link /Type /Annot >>
-endobj
-207 0 obj
-<< /A 313 0 R /Border [ 0 0 0 ] /C [ 0 0 0 ] /H /I /Rect [ 393.349 635.641 539.999 644.641 ] /Subtype /Link /Type /Annot >>
-endobj
-208 0 obj
-<< /A 313 0 R /Border [ 0 0 0 ] /C [ 0 0 0 ] /H /I /Rect [ 72.0 623.641 163.65 632.641 ] /Subtype /Link /Type /Annot >>
-endobj
-209 0 obj
-<< /A 314 0 R /Border [ 0 0 0 ] /C [ 0 0 0 ] /H /I /Rect [ 72.0 589.641 141.053 598.641 ] /Subtype /Link /Type /Annot >>
-endobj
-210 0 obj
-<< /A 314 0 R /Border [ 0 0 0 ] /C [ 0 0 0 ] /H /I /Rect [ 146.786 589.641 273.986 598.641 ] /Subtype /Link /Type /Annot >>
-endobj
-211 0 obj
-<< /A 315 0 R /Border [ 0 0 0 ] /C [ 0 0 0 ] /H /I /Rect [ 102.28 552.539 182.84 561.539 ] /Subtype /Link /Type /Annot >>
-endobj
-212 0 obj
-<< /A 316 0 R /Border [ 0 0 0 ] /C [ 0 0 0 ] /H /I /Rect [ 104.49 531.449 188.37 540.449 ] /Subtype /Link /Type /Annot >>
-endobj
-213 0 obj
-<< /A 317 0 R /Border [ 0 0 0 ] /C [ 0 0 0 ] /H /I /Rect [ 184.2 510.359 324.74 519.359 ] /Subtype /Link /Type /Annot >>
-endobj
-214 0 obj
-<< /A 318 0 R /Border [ 0 0 0 ] /C [ 0 0 0 ] /H /I /Rect [ 187.53 489.269 269.75 498.269 ] /Subtype /Link /Type /Annot >>
-endobj
-215 0 obj
-<< /A 319 0 R /Border [ 0 0 0 ] /C [ 0 0 0 ] /H /I /Rect [ 197.68 468.179 351.01 477.179 ] /Subtype /Link /Type /Annot >>
-endobj
-216 0 obj
-<< /A 320 0 R /Border [ 0 0 0 ] /C [ 0 0 0 ] /H /I /Rect [ 110.06 284.909 260.06 293.909 ] /Subtype /Link /Type /Annot >>
-endobj
-217 0 obj
-<< /A 321 0 R /Border [ 0 0 0 ] /C [ 0 0 0 ] /H /I /Rect [ 224.76 263.819 336.43 272.819 ] /Subtype /Link /Type /Annot >>
-endobj
-218 0 obj
-<< /A 322 0 R /Border [ 0 0 0 ] /C [ 0 0 0 ] /H /I /Rect [ 516.1 152.549 540.0 161.549 ] /Subtype /Link /Type /Annot >>
-endobj
-219 0 obj
-<< /A 322 0 R /Border [ 0 0 0 ] /C [ 0 0 0 ] /H /I /Rect [ 72.0 140.549 219.75 149.549 ] /Subtype /Link /Type /Annot >>
-endobj
-220 0 obj
-<< /A 323 0 R /Border [ 0 0 0 ] /C [ 0 0 0 ] /H /I /Rect [ 516.1 140.549 540.0 149.549 ] /Subtype /Link /Type /Annot >>
-endobj
-221 0 obj
-<< /A 323 0 R /Border [ 0 0 0 ] /C [ 0 0 0 ] /H /I /Rect [ 72.0 128.549 152.54 137.549 ] /Subtype /Link /Type /Annot >>
-endobj
-222 0 obj
-<< /A 277 0 R /Border [ 0 0 0 ] /C [ 0 0 0 ] /H /I /Rect [ 333.717 519.578 484.943 528.578 ] /Subtype /Link /Type /Annot >>
-endobj
-223 0 obj
-<< /A 277 0 R /Border [ 0 0 0 ] /C [ 0 0 0 ] /H /I /Rect [ 484.943 519.578 515.831 528.578 ] /Subtype /Link /Type /Annot >>
-endobj
-224 0 obj
-<< /A 276 0 R /Border [ 0 0 0 ] /C [ 0 0 0 ] /H /I /Rect [ 319.381 163.171 460.719 172.171 ] /Subtype /Link /Type /Annot >>
-endobj
-225 0 obj
-<< /A 276 0 R /Border [ 0 0 0 ] /C [ 0 0 0 ] /H /I /Rect [ 460.719 163.171 494.664 172.171 ] /Subtype /Link /Type /Annot >>
-endobj
-226 0 obj
-<< /A 277 0 R /Border [ 0 0 0 ] /C [ 0 0 0 ] /H /I /Rect [ 329.293 85.499 488.903 94.499 ] /Subtype /Link /Type /Annot >>
-endobj
-227 0 obj
-<< /A 277 0 R /Border [ 0 0 0 ] /C [ 0 0 0 ] /H /I /Rect [ 488.903 85.499 523.981 94.499 ] /Subtype /Link /Type /Annot >>
-endobj
-228 0 obj
-<< /A 280 0 R /Border [ 0 0 0 ] /C [ 0 0 0 ] /H /I /Rect [ 366.92 188.609 456.9 197.609 ] /Subtype /Link /Type /Annot >>
-endobj
-229 0 obj
-<< /A 280 0 R /Border [ 0 0 0 ] /C [ 0 0 0 ] /H /I /Rect [ 456.9 188.609 493.28 197.609 ] /Subtype /Link /Type /Annot >>
-endobj
-230 0 obj
-<< /A 280 0 R /Border [ 0 0 0 ] /C [ 0 0 0 ] /H /I /Rect [ 208.09 637.5 298.07 646.5 ] /Subtype /Link /Type /Annot >>
-endobj
-231 0 obj
-<< /A 280 0 R /Border [ 0 0 0 ] /C [ 0 0 0 ] /H /I /Rect [ 298.07 637.5 334.45 646.5 ] /Subtype /Link /Type /Annot >>
-endobj
-232 0 obj
-<< /A 290 0 R /Border [ 0 0 0 ] /C [ 0 0 0 ] /H /I /Rect [ 160.538 85.505 386.813 94.505 ] /Subtype /Link /Type /Annot >>
-endobj
-233 0 obj
-<< /A 290 0 R /Border [ 0 0 0 ] /C [ 0 0 0 ] /H /I /Rect [ 386.813 85.505 425.379 94.505 ] /Subtype /Link /Type /Annot >>
-endobj
-234 0 obj
-<< /A 293 0 R /Border [ 0 0 0 ] /C [ 0 0 0 ] /H /I /Rect [ 497.962 450.438 539.999 459.438 ] /Subtype /Link /Type /Annot >>
-endobj
-235 0 obj
-<< /A 293 0 R /Border [ 0 0 0 ] /C [ 0 0 0 ] /H /I /Rect [ 72.0 438.558 125.9 447.438 ] /Subtype /Link /Type /Annot >>
-endobj
-236 0 obj
-<< /A 293 0 R /Border [ 0 0 0 ] /C [ 0 0 0 ] /H /I /Rect [ 125.9 438.438 163.703 447.438 ] /Subtype /Link /Type /Annot >>
-endobj
-237 0 obj
-<< /A 280 0 R /Border [ 0 0 0 ] /C [ 0 0 0 ] /H /I /Rect [ 295.01 426.438 384.99 435.438 ] /Subtype /Link /Type /Annot >>
-endobj
-238 0 obj
-<< /A 280 0 R /Border [ 0 0 0 ] /C [ 0 0 0 ] /H /I /Rect [ 384.99 426.438 421.37 435.438 ] /Subtype /Link /Type /Annot >>
-endobj
-239 0 obj
-<< /A 296 0 R /Border [ 0 0 0 ] /C [ 0 0 0 ] /H /I /Rect [ 334.947 468.365 448.053 477.365 ] /Subtype /Link /Type /Annot >>
-endobj
-240 0 obj
-<< /A 296 0 R /Border [ 0 0 0 ] /C [ 0 0 0 ] /H /I /Rect [ 448.053 468.365 485.879 477.365 ] /Subtype /Link /Type /Annot >>
-endobj
-241 0 obj
-<< /A 305 0 R /Border [ 0 0 0 ] /C [ 0 0 0 ] /H /I /Rect [ 299.614 431.318 491.36 440.318 ] /Subtype /Link /Type /Annot >>
-endobj
-242 0 obj
-<< /A 305 0 R /Border [ 0 0 0 ] /C [ 0 0 0 ] /H /I /Rect [ 491.36 431.318 528.338 440.318 ] /Subtype /Link /Type /Annot >>
-endobj
-243 0 obj
-<< /A 278 0 R /Border [ 0 0 0 ] /C [ 0 0 0 ] /H /I /Rect [ 378.272 673.5 539.999 682.5 ] /Subtype /Link /Type /Annot >>
-endobj
-244 0 obj
-<< /A 278 0 R /Border [ 0 0 0 ] /C [ 0 0 0 ] /H /I /Rect [ 100.0 661.5 136.11 670.5 ] /Subtype /Link /Type /Annot >>
-endobj
-245 0 obj
-<< /A 278 0 R /Border [ 0 0 0 ] /C [ 0 0 0 ] /H /I /Rect [ 136.11 661.5 167.49 670.5 ] /Subtype /Link /Type /Annot >>
-endobj
-246 0 obj
-<< /A 309 0 R /Border [ 0 0 0 ] /C [ 0 0 0 ] /H /I /Rect [ 429.325 422.206 539.998 431.206 ] /Subtype /Link /Type /Annot >>
-endobj
-247 0 obj
-<< /A 309 0 R /Border [ 0 0 0 ] /C [ 0 0 0 ] /H /I /Rect [ 100.0 410.326 112.5 419.206 ] /Subtype /Link /Type /Annot >>
-endobj
-248 0 obj
-<< /A 309 0 R /Border [ 0 0 0 ] /C [ 0 0 0 ] /H /I /Rect [ 112.5 410.206 151.668 419.206 ] /Subtype /Link /Type /Annot >>
-endobj
-249 0 obj
-<< /A 277 0 R /Border [ 0 0 0 ] /C [ 0 0 0 ] /H /I /Rect [ 116.94 305.47 269.15 314.47 ] /Subtype /Link /Type /Annot >>
-endobj
-250 0 obj
-<< /A 277 0 R /Border [ 0 0 0 ] /C [ 0 0 0 ] /H /I /Rect [ 269.15 305.47 300.53 314.47 ] /Subtype /Link /Type /Annot >>
-endobj
-251 0 obj
-<< /A 275 0 R /Border [ 0 0 0 ] /C [ 0 0 0 ] /H /I /Rect [ 116.94 271.102 232.21 280.102 ] /Subtype /Link /Type /Annot >>
-endobj
-252 0 obj
-<< /A 275 0 R /Border [ 0 0 0 ] /C [ 0 0 0 ] /H /I /Rect [ 232.21 271.102 263.59 280.102 ] /Subtype /Link /Type /Annot >>
-endobj
-253 0 obj
-<< /A 288 0 R /Border [ 0 0 0 ] /C [ 0 0 0 ] /H /I /Rect [ 455.55 248.384 539.998 257.384 ] /Subtype /Link /Type /Annot >>
-endobj
-254 0 obj
-<< /A 288 0 R /Border [ 0 0 0 ] /C [ 0 0 0 ] /H /I /Rect [ 100.0 236.384 188.88 245.384 ] /Subtype /Link /Type /Annot >>
-endobj
-255 0 obj
-<< /A 288 0 R /Border [ 0 0 0 ] /C [ 0 0 0 ] /H /I /Rect [ 188.88 236.384 225.26 245.384 ] /Subtype /Link /Type /Annot >>
-endobj
-256 0 obj
-<< /A 290 0 R /Border [ 0 0 0 ] /C [ 0 0 0 ] /H /I /Rect [ 492.575 213.666 540.002 222.666 ] /Subtype /Link /Type /Annot >>
-endobj
-257 0 obj
-<< /A 290 0 R /Border [ 0 0 0 ] /C [ 0 0 0 ] /H /I /Rect [ 100.0 201.666 268.61 210.666 ] /Subtype /Link /Type /Annot >>
-endobj
-258 0 obj
-<< /A 290 0 R /Border [ 0 0 0 ] /C [ 0 0 0 ] /H /I /Rect [ 268.61 201.666 304.99 210.666 ] /Subtype /Link /Type /Annot >>
-endobj
-259 0 obj
-<< /A 324 0 R /Border [ 0 0 0 ] /C [ 0 0 0 ] /H /I /Rect [ 359.15 295.375 455.27 304.375 ] /Subtype /Link /Type /Annot >>
-endobj
-260 0 obj
-<< /A 324 0 R /Border [ 0 0 0 ] /C [ 0 0 0 ] /H /I /Rect [ 321.485 190.125 417.605 199.125 ] /Subtype /Link /Type /Annot >>
-endobj
-261 0 obj
-<< /A 308 0 R /Border [ 0 0 0 ] /C [ 0 0 0 ] /H /I /Rect [ 405.397 573.15 539.999 582.15 ] /Subtype /Link /Type /Annot >>
-endobj
-262 0 obj
-<< /A 308 0 R /Border [ 0 0 0 ] /C [ 0 0 0 ] /H /I /Rect [ 100.0 561.27 122.78 570.15 ] /Subtype /Link /Type /Annot >>
-endobj
-263 0 obj
-<< /A 308 0 R /Border [ 0 0 0 ] /C [ 0 0 0 ] /H /I /Rect [ 122.78 561.15 159.16 570.15 ] /Subtype /Link /Type /Annot >>
-endobj
-264 0 obj
-<< /A 307 0 R /Border [ 0 0 0 ] /C [ 0 0 0 ] /H /I /Rect [ 455.792 645.641 540.001 654.641 ] /Subtype /Link /Type /Annot >>
-endobj
-265 0 obj
-<< /A 307 0 R /Border [ 0 0 0 ] /C [ 0 0 0 ] /H /I /Rect [ 72.0 633.761 94.78 642.641 ] /Subtype /Link /Type /Annot >>
-endobj
-266 0 obj
-<< /A 307 0 R /Border [ 0 0 0 ] /C [ 0 0 0 ] /H /I /Rect [ 94.78 633.641 131.16 642.641 ] /Subtype /Link /Type /Annot >>
-endobj
-267 0 obj
-<< /Filter /FlateDecode /N 3 /Length 2453 >>
-stream
-xgPTY{si249IЀ$Hn2-49AD$)8:EEyqpQQYU[[Ϗ:;羺Uz
-0D[oo+k?Q
-
-R
-se4=ơO$ĵmawGIp+z_o#
-zañ)|l%"v;#p8'\ŕq=an/Wś|&߀O bu%KE D%чCI &^'?$-=)JG:ADzHzK&6r
-y|A&+*!R-!2,򚂧Rl))YrYʬ(^TM^4\th91y1XXX i*Furyc+ BSشݴU$CWc9qxxxqa1\b(㓄WbDİĂ$W@MrDSQ*NjTSitҳ2t LGl1y9y9gDJ+r yX2BBELq-3Yc)*(*)*.*++*)=U&(#˔{TT<UrTZTUYѪTUuMKg? kXk$ikh44kՂh&1ڇ֠ט᭩_3CұIiezvS ۯׯUX?^A נOC-CaNkwZHۈkt1xqSIɌiifv7hnbb~ 8fuMX*Y[Y
-VaVG֊mm866Sl__r@
-UϜZ服/]]ʹ]\Lݶ7W?{t{žn<W][\x=VNS7ǷmÖ =O 4,:
-
-
-4otxpdqh~&Mnlʖ-gaaaý#\#j"CWNgk-NEZFFNGYF.y[w"n)>0-pGo:(H2O:4w7&CɛRTRӬҪ>e dje͜r:fg(fn;=b{y;&w:<+n\www̛||~=ߣ~pڽ{p
-n~.bE,6)>R)ᕌT4t灎2fYAٻ[(7*=D8zHPQURYR*jڮFfoa#6GZkj k?9ι^Xڱ  YǛ =d,\̜
-=uGZuZm/
-i޳?\Nk/:2;:;]]Cv[tˉ/_(!,]̺8)[z_ rϧoל]x7dercxA;wZ73l=|ýk]Y?24?`,tL`a7->gM`"00>|W%y2ETӴ/7|jq6wk^k?&,YVwFz矽OxPAɏ?M-~'K KKB. t ]@B. t ]V,r96_6
-7#edoMDEa&s|.7>s7
-endstream
-endobj
-268 0 obj
-<< /D [ 9 0 R /XYZ 72.0 720.0 null ] /S /GoTo /Type /Action >>
-endobj
-269 0 obj
-<< /D [ 10 0 R /XYZ 72.0 720.0 null ] /S /GoTo /Type /Action >>
-endobj
-270 0 obj
-<< /D [ 11 0 R /XYZ 72.0 720.0 null ] /S /GoTo /Type /Action >>
-endobj
-271 0 obj
-<< /D [ 11 0 R /XYZ 72.0 627.192 null ] /S /GoTo /Type /Action >>
-endobj
-272 0 obj
-<< /D [ 11 0 R /XYZ 72.0 127.049 null ] /S /GoTo /Type /Action >>
-endobj
-273 0 obj
-<< /D [ 13 0 R /XYZ 72.0 720.0 null ] /S /GoTo /Type /Action >>
-endobj
-274 0 obj
-<< /D [ 13 0 R /XYZ 72.0 669.305 null ] /S /GoTo /Type /Action >>
-endobj
-275 0 obj
-<< /D [ 13 0 R /XYZ 72.0 452.406 null ] /S /GoTo /Type /Action >>
-endobj
-276 0 obj
-<< /D [ 14 0 R /XYZ 72.0 519.752 null ] /S /GoTo /Type /Action >>
-endobj
-277 0 obj
-<< /D [ 15 0 R /XYZ 72.0 152.784 null ] /S /GoTo /Type /Action >>
-endobj
-278 0 obj
-<< /D [ 17 0 R /XYZ 72.0 585.874 null ] /S /GoTo /Type /Action >>
-endobj
-279 0 obj
-<< /D [ 19 0 R /XYZ 72.0 636.0 null ] /S /GoTo /Type /Action >>
-endobj
-280 0 obj
-<< /D [ 21 0 R /XYZ 72.0 720.0 null ] /S /GoTo /Type /Action >>
-endobj
-281 0 obj
-<< /D [ 23 0 R /XYZ 72.0 720.0 null ] /S /GoTo /Type /Action >>
-endobj
-282 0 obj
-<< /D [ 24 0 R /XYZ 72.0 720.0 null ] /S /GoTo /Type /Action >>
-endobj
-283 0 obj
-<< /D [ 24 0 R /XYZ 72.0 690.141 null ] /S /GoTo /Type /Action >>
-endobj
-284 0 obj
-<< /D [ 24 0 R /XYZ 72.0 464.807 null ] /S /GoTo /Type /Action >>
-endobj
-285 0 obj
-<< /D [ 26 0 R /XYZ 72.0 408.138 null ] /S /GoTo /Type /Action >>
-endobj
-286 0 obj
-<< /D [ 27 0 R /XYZ 72.0 187.938 null ] /S /GoTo /Type /Action >>
-endobj
-287 0 obj
-<< /D [ 28 0 R /XYZ 72.0 528.576 null ] /S /GoTo /Type /Action >>
-endobj
-288 0 obj
-<< /D [ 28 0 R /XYZ 72.0 360.619 null ] /S /GoTo /Type /Action >>
-endobj
-289 0 obj
-<< /D [ 28 0 R /XYZ 72.0 264.662 null ] /S /GoTo /Type /Action >>
-endobj
-290 0 obj
-<< /D [ 29 0 R /XYZ 72.0 720.0 null ] /S /GoTo /Type /Action >>
-endobj
-291 0 obj
-<< /D [ 29 0 R /XYZ 72.0 518.119 null ] /S /GoTo /Type /Action >>
-endobj
-292 0 obj
-<< /D [ 30 0 R /XYZ 72.0 410.0 null ] /S /GoTo /Type /Action >>
-endobj
-293 0 obj
-<< /D [ 31 0 R /XYZ 72.0 720.0 null ] /S /GoTo /Type /Action >>
-endobj
-294 0 obj
-<< /D [ 31 0 R /XYZ 72.0 667.229 null ] /S /GoTo /Type /Action >>
-endobj
-295 0 obj
-<< /D [ 31 0 R /XYZ 72.0 560.872 null ] /S /GoTo /Type /Action >>
-endobj
-296 0 obj
-<< /D [ 31 0 R /XYZ 72.0 340.617 null ] /S /GoTo /Type /Action >>
-endobj
-297 0 obj
-<< /D [ 32 0 R /XYZ 72.0 720.0 null ] /S /GoTo /Type /Action >>
-endobj
-298 0 obj
-<< /D [ 32 0 R /XYZ 72.0 393.752 null ] /S /GoTo /Type /Action >>
-endobj
-299 0 obj
-<< /D [ 32 0 R /XYZ 72.0 277.193 null ] /S /GoTo /Type /Action >>
-endobj
-300 0 obj
-<< /D [ 33 0 R /XYZ 72.0 720.0 null ] /S /GoTo /Type /Action >>
-endobj
-301 0 obj
-<< /D [ 34 0 R /XYZ 72.0 720.0 null ] /S /GoTo /Type /Action >>
-endobj
-302 0 obj
-<< /D [ 34 0 R /XYZ 72.0 626.773 null ] /S /GoTo /Type /Action >>
-endobj
-303 0 obj
-<< /D [ 34 0 R /XYZ 72.0 127.887 null ] /S /GoTo /Type /Action >>
-endobj
-304 0 obj
-<< /D [ 35 0 R /XYZ 72.0 408.866 null ] /S /GoTo /Type /Action >>
-endobj
-305 0 obj
-<< /D [ 35 0 R /XYZ 72.0 197.346 null ] /S /GoTo /Type /Action >>
-endobj
-306 0 obj
-<< /D [ 36 0 R /XYZ 72.0 650.0 null ] /S /GoTo /Type /Action >>
-endobj
-307 0 obj
-<< /D [ 37 0 R /XYZ 72.0 720.0 null ] /S /GoTo /Type /Action >>
-endobj
-308 0 obj
-<< /D [ 46 0 R /XYZ 72.0 720.0 null ] /S /GoTo /Type /Action >>
-endobj
-309 0 obj
-<< /D [ 47 0 R /XYZ 72.0 720.0 null ] /S /GoTo /Type /Action >>
-endobj
-310 0 obj
-<< /D [ 48 0 R /XYZ 72.0 720.0 null ] /S /GoTo /Type /Action >>
-endobj
-311 0 obj
-<< /S /URI /URI (http://qpdf.sourceforge.net/) >>
-endobj
-312 0 obj
-<< /S /URI /URI (https://github.com/qpdf/qpdf) >>
-endobj
-313 0 obj
-<< /S /URI /URI (http://www.opensource.org/licenses/artistic-license-2.0.php) >>
-endobj
-314 0 obj
-<< /S /URI /URI (http://www.apexcovantage.com) >>
-endobj
-315 0 obj
-<< /S /URI /URI (http://www.zlib.net/) >>
-endobj
-316 0 obj
-<< /S /URI /URI (http://www.pcre.org/) >>
-endobj
-317 0 obj
-<< /S /URI /URI (http://www.gnu.org/software/make) >>
-endobj
-318 0 obj
-<< /S /URI /URI (http://www.perl.org/) >>
-endobj
-319 0 obj
-<< /S /URI /URI (http://www.gnu.org/software/diffutils/) >>
-endobj
-320 0 obj
-<< /S /URI /URI (http://www.remotesensing.org/libtiff/) >>
-endobj
-321 0 obj
-<< /S /URI /URI (http://www.ghostscript.com) >>
-endobj
-322 0 obj
-<< /S /URI /URI (http://downloads.sourceforge.net/docbook/) >>
-endobj
-323 0 obj
-<< /S /URI /URI (http://xml.apache.org/fop/) >>
-endobj
-324 0 obj
-<< /S /URI /URI (http://delphi.about.com/) >>
-endobj
-xref
-0 325
-0000000000 65535 f
-0000000015 00000 n
-0000000109 00000 n
-0000000239 00000 n
-0000001177 00000 n
-0000001920 00000 n
-0000002271 00000 n
-0000002455 00000 n
-0000002639 00000 n
-0000002838 00000 n
-0000003037 00000 n
-0000003222 00000 n
-0000003422 00000 n
-0000003607 00000 n
-0000003807 00000 n
-0000003992 00000 n
-0000004177 00000 n
-0000004362 00000 n
-0000004562 00000 n
-0000004747 00000 n
-0000004947 00000 n
-0000005132 00000 n
-0000005317 00000 n
-0000005502 00000 n
-0000005687 00000 n
-0000005872 00000 n
-0000006057 00000 n
-0000006242 00000 n
-0000006427 00000 n
-0000006627 00000 n
-0000006827 00000 n
-0000007012 00000 n
-0000007212 00000 n
-0000007397 00000 n
-0000007582 00000 n
-0000007782 00000 n
-0000007967 00000 n
-0000008152 00000 n
-0000008337 00000 n
-0000008522 00000 n
-0000008707 00000 n
-0000008907 00000 n
-0000009107 00000 n
-0000009292 00000 n
-0000009477 00000 n
-0000009679 00000 n
-0000009881 00000 n
-0000010067 00000 n
-0000010253 00000 n
-0000010455 00000 n
-0000010752 00000 n
-0000010975 00000 n
-0000011383 00000 n
-0000012091 00000 n
-0000027423 00000 n
-0000027499 00000 n
-0000028796 00000 n
-0000030441 00000 n
-0000030549 00000 n
-0000033548 00000 n
-0000035068 00000 n
-0000035136 00000 n
-0000038005 00000 n
-0000040717 00000 n
-0000042990 00000 n
-0000046906 00000 n
-0000046942 00000 n
-0000049676 00000 n
-0000053803 00000 n
-0000053839 00000 n
-0000056581 00000 n
-0000058287 00000 n
-0000061710 00000 n
-0000062221 00000 n
-0000063696 00000 n
-0000067537 00000 n
-0000072114 00000 n
-0000076139 00000 n
-0000081261 00000 n
-0000081297 00000 n
-0000085409 00000 n
-0000085469 00000 n
-0000088414 00000 n
-0000091149 00000 n
-0000091185 00000 n
-0000094271 00000 n
-0000097728 00000 n
-0000098772 00000 n
-0000098808 00000 n
-0000101037 00000 n
-0000104237 00000 n
-0000105725 00000 n
-0000108398 00000 n
-0000111759 00000 n
-0000114812 00000 n
-0000114856 00000 n
-0000119116 00000 n
-0000119240 00000 n
-0000122829 00000 n
-0000126094 00000 n
-0000129342 00000 n
-0000129379 00000 n
-0000132307 00000 n
-0000132352 00000 n
-0000134507 00000 n
-0000137254 00000 n
-0000138932 00000 n
-0000138977 00000 n
-0000139762 00000 n
-0000139801 00000 n
-0000139906 00000 n
-0000140008 00000 n
-0000140117 00000 n
-0000140221 00000 n
-0000140332 00000 n
-0000140433 00000 n
-0000140535 00000 n
-0000140635 00000 n
-0000140732 00000 n
-0000140870 00000 n
-0000141008 00000 n
-0000141146 00000 n
-0000141287 00000 n
-0000141425 00000 n
-0000141566 00000 n
-0000141704 00000 n
-0000141845 00000 n
-0000141983 00000 n
-0000142124 00000 n
-0000142262 00000 n
-0000142403 00000 n
-0000142541 00000 n
-0000142682 00000 n
-0000142820 00000 n
-0000142961 00000 n
-0000143099 00000 n
-0000143238 00000 n
-0000143376 00000 n
-0000143517 00000 n
-0000143655 00000 n
-0000143796 00000 n
-0000143934 00000 n
-0000144075 00000 n
-0000144213 00000 n
-0000144354 00000 n
-0000144492 00000 n
-0000144633 00000 n
-0000144771 00000 n
-0000144912 00000 n
-0000145050 00000 n
-0000145191 00000 n
-0000145329 00000 n
-0000145470 00000 n
-0000145608 00000 n
-0000145749 00000 n
-0000145887 00000 n
-0000146028 00000 n
-0000146165 00000 n
-0000146306 00000 n
-0000146443 00000 n
-0000146584 00000 n
-0000146722 00000 n
-0000146861 00000 n
-0000146999 00000 n
-0000147138 00000 n
-0000147276 00000 n
-0000147417 00000 n
-0000147555 00000 n
-0000147696 00000 n
-0000147834 00000 n
-0000147975 00000 n
-0000148113 00000 n
-0000148252 00000 n
-0000148390 00000 n
-0000148531 00000 n
-0000148669 00000 n
-0000148810 00000 n
-0000148948 00000 n
-0000149089 00000 n
-0000149227 00000 n
-0000149368 00000 n
-0000149506 00000 n
-0000149647 00000 n
-0000149785 00000 n
-0000149926 00000 n
-0000150064 00000 n
-0000150205 00000 n
-0000150343 00000 n
-0000150484 00000 n
-0000150622 00000 n
-0000150763 00000 n
-0000150902 00000 n
-0000151043 00000 n
-0000151181 00000 n
-0000151320 00000 n
-0000151458 00000 n
-0000151599 00000 n
-0000151737 00000 n
-0000151878 00000 n
-0000152016 00000 n
-0000152157 00000 n
-0000152295 00000 n
-0000152436 00000 n
-0000152574 00000 n
-0000152715 00000 n
-0000152853 00000 n
-0000152992 00000 n
-0000153133 00000 n
-0000153274 00000 n
-0000153411 00000 n
-0000153549 00000 n
-0000153690 00000 n
-0000153829 00000 n
-0000153968 00000 n
-0000154106 00000 n
-0000154245 00000 n
-0000154384 00000 n
-0000154523 00000 n
-0000154662 00000 n
-0000154799 00000 n
-0000154936 00000 n
-0000155073 00000 n
-0000155210 00000 n
-0000155351 00000 n
-0000155492 00000 n
-0000155633 00000 n
-0000155774 00000 n
-0000155913 00000 n
-0000156052 00000 n
-0000156190 00000 n
-0000156328 00000 n
-0000156463 00000 n
-0000156598 00000 n
-0000156737 00000 n
-0000156876 00000 n
-0000157017 00000 n
-0000157153 00000 n
-0000157292 00000 n
-0000157431 00000 n
-0000157570 00000 n
-0000157711 00000 n
-0000157852 00000 n
-0000157992 00000 n
-0000158132 00000 n
-0000158269 00000 n
-0000158403 00000 n
-0000158538 00000 n
-0000158679 00000 n
-0000158816 00000 n
-0000158955 00000 n
-0000159092 00000 n
-0000159229 00000 n
-0000159368 00000 n
-0000159507 00000 n
-0000159647 00000 n
-0000159785 00000 n
-0000159924 00000 n
-0000160065 00000 n
-0000160203 00000 n
-0000160342 00000 n
-0000160481 00000 n
-0000160622 00000 n
-0000160761 00000 n
-0000160897 00000 n
-0000161034 00000 n
-0000161175 00000 n
-0000161311 00000 n
-0000161449 00000 n
-0000163981 00000 n
-0000164061 00000 n
-0000164142 00000 n
-0000164223 00000 n
-0000164306 00000 n
-0000164389 00000 n
-0000164470 00000 n
-0000164553 00000 n
-0000164636 00000 n
-0000164719 00000 n
-0000164802 00000 n
-0000164885 00000 n
-0000164966 00000 n
-0000165047 00000 n
-0000165128 00000 n
-0000165209 00000 n
-0000165292 00000 n
-0000165375 00000 n
-0000165458 00000 n
-0000165541 00000 n
-0000165624 00000 n
-0000165707 00000 n
-0000165790 00000 n
-0000165871 00000 n
-0000165954 00000 n
-0000166035 00000 n
-0000166116 00000 n
-0000166199 00000 n
-0000166282 00000 n
-0000166365 00000 n
-0000166446 00000 n
-0000166529 00000 n
-0000166612 00000 n
-0000166693 00000 n
-0000166774 00000 n
-0000166857 00000 n
-0000166940 00000 n
-0000167023 00000 n
-0000167106 00000 n
-0000167187 00000 n
-0000167268 00000 n
-0000167349 00000 n
-0000167430 00000 n
-0000167511 00000 n
-0000167578 00000 n
-0000167645 00000 n
-0000167743 00000 n
-0000167810 00000 n
-0000167869 00000 n
-0000167928 00000 n
-0000167999 00000 n
-0000168058 00000 n
-0000168135 00000 n
-0000168211 00000 n
-0000168276 00000 n
-0000168356 00000 n
-0000168421 00000 n
-trailer << /Info 2 0 R /Root 1 0 R /Size 325 /ID [<9b1c69409fc9a5f50e44b9588e3e60f8><47e08688d23013c99057cfe5d79bca32>] >>
-startxref
-168484
-%%EOF
diff --git a/qpdf/qtest/qpdf/deterministic-id-ny.pdf b/qpdf/qtest/qpdf/deterministic-id-ny.pdf
deleted file mode 100644
index 40c4b382..00000000
--- a/qpdf/qtest/qpdf/deterministic-id-ny.pdf
+++ /dev/null
Binary files differ
diff --git a/qpdf/qtest/qpdf/deterministic-id-yn.pdf b/qpdf/qtest/qpdf/deterministic-id-yn.pdf
deleted file mode 100644
index bc05571b..00000000
--- a/qpdf/qtest/qpdf/deterministic-id-yn.pdf
+++ /dev/null
Binary files differ
diff --git a/qpdf/qtest/qpdf/deterministic-id-yy.pdf b/qpdf/qtest/qpdf/deterministic-id-yy.pdf
deleted file mode 100644
index c0baa660..00000000
--- a/qpdf/qtest/qpdf/deterministic-id-yy.pdf
+++ /dev/null
Binary files differ
diff --git a/qpdf/qtest/qpdf/extra-header-lin-newline.pdf b/qpdf/qtest/qpdf/extra-header-lin-newline.pdf
index 7a5ff3e6..b23c5152 100644
--- a/qpdf/qtest/qpdf/extra-header-lin-newline.pdf
+++ b/qpdf/qtest/qpdf/extra-header-lin-newline.pdf
Binary files differ
diff --git a/qpdf/qtest/qpdf/extra-header-lin-no-newline.pdf b/qpdf/qtest/qpdf/extra-header-lin-no-newline.pdf
index e115c462..da3e3e88 100644
--- a/qpdf/qtest/qpdf/extra-header-lin-no-newline.pdf
+++ b/qpdf/qtest/qpdf/extra-header-lin-no-newline.pdf
Binary files differ
diff --git a/qpdf/qtest/qpdf/filter-xref-offsets.pl b/qpdf/qtest/qpdf/filter-xref-offsets.pl
new file mode 100644
index 00000000..fa4e95c8
--- /dev/null
+++ b/qpdf/qtest/qpdf/filter-xref-offsets.pl
@@ -0,0 +1,8 @@
+use warnings;
+use strict;
+
+while (<>)
+{
+ s/(uncompressed; offset =) \d+/$1 .../;
+ print;
+}
diff --git a/qpdf/qtest/qpdf/good17-not-recompressed.pdf b/qpdf/qtest/qpdf/good17-not-recompressed.pdf
index b6e3a530..1f4924f7 100644
--- a/qpdf/qtest/qpdf/good17-not-recompressed.pdf
+++ b/qpdf/qtest/qpdf/good17-not-recompressed.pdf
Binary files differ
diff --git a/qpdf/qtest/qpdf/job-json-misc-options.pdf b/qpdf/qtest/qpdf/job-json-misc-options.pdf
index be88f1e1..809f18d0 100644
--- a/qpdf/qtest/qpdf/job-json-misc-options.pdf
+++ b/qpdf/qtest/qpdf/job-json-misc-options.pdf
Binary files differ
diff --git a/qpdf/qtest/qpdf/lin-special.disable.exp b/qpdf/qtest/qpdf/lin-special.disable.exp
index 14c2eaef..727341b1 100644
--- a/qpdf/qtest/qpdf/lin-special.disable.exp
+++ b/qpdf/qtest/qpdf/lin-special.disable.exp
Binary files differ
diff --git a/qpdf/qtest/qpdf/lin-special.generate.exp b/qpdf/qtest/qpdf/lin-special.generate.exp
index af7cb061..545ce977 100644
--- a/qpdf/qtest/qpdf/lin-special.generate.exp
+++ b/qpdf/qtest/qpdf/lin-special.generate.exp
Binary files differ
diff --git a/qpdf/qtest/qpdf/lin-special.preserve.exp b/qpdf/qtest/qpdf/lin-special.preserve.exp
index 14c2eaef..727341b1 100644
--- a/qpdf/qtest/qpdf/lin-special.preserve.exp
+++ b/qpdf/qtest/qpdf/lin-special.preserve.exp
Binary files differ
diff --git a/qpdf/qtest/qpdf/linearize-duplicate-page.pdf b/qpdf/qtest/qpdf/linearize-duplicate-page.pdf
index 27a8898e..093149c1 100644
--- a/qpdf/qtest/qpdf/linearize-duplicate-page.pdf
+++ b/qpdf/qtest/qpdf/linearize-duplicate-page.pdf
Binary files differ
diff --git a/qpdf/qtest/qpdf/long-id-linearized.pdf b/qpdf/qtest/qpdf/long-id-linearized.pdf
index 2993fd30..e7bc709f 100644
--- a/qpdf/qtest/qpdf/long-id-linearized.pdf
+++ b/qpdf/qtest/qpdf/long-id-linearized.pdf
Binary files differ
diff --git a/qpdf/qtest/qpdf/minimal-linearize-pass1.pdf b/qpdf/qtest/qpdf/minimal-linearize-pass1.pdf
index e851063a..ac7d71ed 100644
--- a/qpdf/qtest/qpdf/minimal-linearize-pass1.pdf
+++ b/qpdf/qtest/qpdf/minimal-linearize-pass1.pdf
Binary files differ
diff --git a/qpdf/qtest/qpdf/minimal-linearized.pdf b/qpdf/qtest/qpdf/minimal-linearized.pdf
index 15f643d4..809f18d0 100644
--- a/qpdf/qtest/qpdf/minimal-linearized.pdf
+++ b/qpdf/qtest/qpdf/minimal-linearized.pdf
Binary files differ
diff --git a/qpdf/qtest/qpdf/newline-before-endstream-nl-objstm.pdf b/qpdf/qtest/qpdf/newline-before-endstream-nl-objstm.pdf
index f412feda..13752cba 100644
--- a/qpdf/qtest/qpdf/newline-before-endstream-nl-objstm.pdf
+++ b/qpdf/qtest/qpdf/newline-before-endstream-nl-objstm.pdf
Binary files differ
diff --git a/qpdf/qtest/qpdf/object-stream.disable.exp b/qpdf/qtest/qpdf/object-stream.disable.exp
index a05e0485..9633275f 100644
--- a/qpdf/qtest/qpdf/object-stream.disable.exp
+++ b/qpdf/qtest/qpdf/object-stream.disable.exp
Binary files differ
diff --git a/qpdf/qtest/qpdf/object-stream.generate.exp b/qpdf/qtest/qpdf/object-stream.generate.exp
index 3b16f121..a7b4a448 100644
--- a/qpdf/qtest/qpdf/object-stream.generate.exp
+++ b/qpdf/qtest/qpdf/object-stream.generate.exp
Binary files differ
diff --git a/qpdf/qtest/qpdf/object-stream.preserve.exp b/qpdf/qtest/qpdf/object-stream.preserve.exp
index 3b16f121..a7b4a448 100644
--- a/qpdf/qtest/qpdf/object-stream.preserve.exp
+++ b/qpdf/qtest/qpdf/object-stream.preserve.exp
Binary files differ
diff --git a/qpdf/qtest/qpdf/pages-is-page-out.pdf b/qpdf/qtest/qpdf/pages-is-page-out.pdf
index 15f643d4..809f18d0 100644
--- a/qpdf/qtest/qpdf/pages-is-page-out.pdf
+++ b/qpdf/qtest/qpdf/pages-is-page-out.pdf
Binary files differ
diff --git a/qpdf/qtest/qpdf/png-filters-1-column.pdf b/qpdf/qtest/qpdf/png-filters-1-column.pdf
new file mode 100644
index 00000000..5d9a8793
--- /dev/null
+++ b/qpdf/qtest/qpdf/png-filters-1-column.pdf
Binary files differ
diff --git a/qpdf/qtest/qpdf/png-filters-no-columns-decoded.pdf b/qpdf/qtest/qpdf/png-filters-no-columns-decoded.pdf
new file mode 100644
index 00000000..db597042
--- /dev/null
+++ b/qpdf/qtest/qpdf/png-filters-no-columns-decoded.pdf
Binary files differ
diff --git a/qpdf/qtest/qpdf/png-filters-no-columns.pdf b/qpdf/qtest/qpdf/png-filters-no-columns.pdf
new file mode 100644
index 00000000..83e9911a
--- /dev/null
+++ b/qpdf/qtest/qpdf/png-filters-no-columns.pdf
Binary files differ
diff --git a/qpdf/qtest/qpdf/replaced-stream-data-flate.pdf b/qpdf/qtest/qpdf/replaced-stream-data-flate.pdf
index 02931170..d51ffefe 100644
--- a/qpdf/qtest/qpdf/replaced-stream-data-flate.pdf
+++ b/qpdf/qtest/qpdf/replaced-stream-data-flate.pdf
Binary files differ
diff --git a/qpdf/qtest/qpdf/short-id-linearized.pdf b/qpdf/qtest/qpdf/short-id-linearized.pdf
index ec8829d7..10ef195b 100644
--- a/qpdf/qtest/qpdf/short-id-linearized.pdf
+++ b/qpdf/qtest/qpdf/short-id-linearized.pdf
Binary files differ
diff --git a/qpdf/qtest/qpdf/xref-with-short-size-new.out b/qpdf/qtest/qpdf/xref-with-short-size-new.out
index 9396e6c6..1c0f409a 100644
--- a/qpdf/qtest/qpdf/xref-with-short-size-new.out
+++ b/qpdf/qtest/qpdf/xref-with-short-size-new.out
@@ -1,4 +1,4 @@
-1/0: uncompressed; offset = 15
+1/0: uncompressed; offset = ...
2/0: compressed; stream = 1, index = 0
3/0: compressed; stream = 1, index = 1
4/0: compressed; stream = 1, index = 2
@@ -8,6 +8,6 @@
8/0: compressed; stream = 1, index = 6
9/0: compressed; stream = 1, index = 7
10/0: compressed; stream = 1, index = 8
-11/0: uncompressed; offset = 674
-12/0: uncompressed; offset = 801
-13/0: uncompressed; offset = 16194
+11/0: uncompressed; offset = ...
+12/0: uncompressed; offset = ...
+13/0: uncompressed; offset = ...
diff --git a/qpdf/qtest/qpdf_test_helpers.pm b/qpdf/qtest/qpdf_test_helpers.pm
index eca6b712..f1e4a93c 100644
--- a/qpdf/qtest/qpdf_test_helpers.pm
+++ b/qpdf/qtest/qpdf_test_helpers.pm
@@ -46,8 +46,8 @@ sub check_pdf
{$td->STRING => "",
$td->EXIT_STATUS => $status});
$td->runtest("check output",
- {$td->FILE => "a.pdf"},
- {$td->FILE => $output});
+ {$td->COMMAND => "qpdf-test-compare a.pdf $output"},
+ {$td->FILE => $output, $td->EXIT_STATUS => 0});
}
sub flush_tiff_cache
diff --git a/qpdf/qtest/qpdfjob.test b/qpdf/qtest/qpdfjob.test
index 2aea654b..57ad608a 100644
--- a/qpdf/qtest/qpdfjob.test
+++ b/qpdf/qtest/qpdfjob.test
@@ -30,18 +30,18 @@ my @bad_json = (
"json-error"
);
my @good_json = (
- "choice-match",
- "input-file-password",
- "empty-input",
- "replace-input",
- "encrypt-40",
- "encrypt-128",
- "encrypt-256-with-restrictions",
- "add-attachments",
- "copy-attachments",
- "underlay-overlay",
- "underlay-overlay-password",
- "misc-options",
+ ["choice-match", ""],
+ ["input-file-password", "user"],
+ ["empty-input", ""],
+ ["replace-input", ""],
+ ["encrypt-40", "u"],
+ ["encrypt-128", "u"],
+ ["encrypt-256-with-restrictions", "u"],
+ ["add-attachments", ""],
+ ["copy-attachments", ""],
+ ["underlay-overlay", ""],
+ ["underlay-overlay-password", ""],
+ ["misc-options", ""],
);
my $n_tests = 11 + scalar(@bad_json) + (2 * scalar(@good_json));
@@ -56,28 +56,29 @@ foreach my $i (@bad_json)
foreach my $i (@good_json)
{
- if ($i eq 'replace-input')
+ my ($base, $pass) = @$i;
+ if ($base eq 'replace-input')
{
copy("minimal.pdf", 'a.pdf');
}
- $td->runtest("QPDFJob good json: $i",
- {$td->COMMAND => "qpdf --job-json-file=job-json-$i.json"},
+ $td->runtest("QPDFJob good json: $base",
+ {$td->COMMAND => "qpdf --job-json-file=job-json-$base.json"},
{$td->STRING => "", $td->EXIT_STATUS => 0},
$td->NORMALIZE_NEWLINES);
- if ($i =~ m/encrypt-256/)
+ if ($base =~ m/encrypt-256/)
{
- $td->runtest("check encryption $i",
+ $td->runtest("check encryption $base",
{$td->COMMAND =>
"qpdf a.pdf --password=u" .
" --job-json-file=job-show-encryption.json"},
- {$td->FILE => "job-json-$i.out", $td->EXIT_STATUS => 0},
+ {$td->FILE => "job-json-$base.out", $td->EXIT_STATUS => 0},
$td->NORMALIZE_NEWLINES);
}
else
{
- $td->runtest("check good json $i output",
- {$td->FILE => "a.pdf"},
- {$td->FILE => "job-json-$i.pdf"});
+ $td->runtest("check good json $base output",
+ {$td->COMMAND => "qpdf-test-compare a.pdf job-json-$base.pdf $pass"},
+ {$td->FILE => "job-json-$base.pdf", $td->EXIT_STATUS => 0});
}
}
@@ -107,8 +108,8 @@ $td->runtest("C job API",
foreach my $i (['a.pdf', 1], ['b.pdf', 2], ['c.pdf', 3], ['d.pdf', 4])
{
$td->runtest("check output",
- {$td->FILE => $i->[0]},
- {$td->FILE => "qpdfjob-ctest$i->[1].pdf"});
+ {$td->COMMAND => "qpdf-test-compare $i->[0] qpdfjob-ctest$i->[1].pdf"},
+ {$td->FILE => "qpdfjob-ctest$i->[1].pdf", $td->EXIT_STATUS => 0});
}
my $wide_out = `qpdfjob-ctest wide`;
$td->runtest("qpdfjob-ctest wide",
@@ -124,8 +125,8 @@ if ($wide_out =~ m/skipped/)
else
{
$td->runtest("check output",
- {$td->FILE => "a.pdf"},
- {$td->FILE => "qpdfjob-ctest-wide.pdf"});
+ {$td->COMMAND => "qpdf-test-compare a.pdf qpdfjob-ctest-wide.pdf"},
+ {$td->FILE => "qpdfjob-ctest-wide.pdf", $td->EXIT_STATUS => 0});
}
cleanup();
diff --git a/qpdf/qtest/replace-input.test b/qpdf/qtest/replace-input.test
index 70a37cc2..5c1a9df2 100644
--- a/qpdf/qtest/replace-input.test
+++ b/qpdf/qtest/replace-input.test
@@ -32,10 +32,12 @@ foreach my $d (['auto-ü', 1], ['auto-öπ', 2])
" --object-streams=generate --replace-input ./$u.pdf"},
{$td->STRING => "", $td->EXIT_STATUS => 0},
$td->NORMALIZE_NEWLINES);
+ # qpdf handles Unicode filenames on Windows, but qpdf-test-compare
+ # doesn't.
+ rename("$u.pdf", "u.pdf") or die;
$td->runtest("check output ($u)",
- {$td->FILE => "$u.pdf"},
- {$td->FILE => "replace-input.pdf"},
- $td->NORMALIZE_NEWLINES);
+ {$td->COMMAND => "qpdf-test-compare u.pdf replace-input.pdf"},
+ {$td->FILE => "replace-input.pdf", $td->EXIT_STATUS => 0});
}
system("cp xref-with-short-size.pdf auto-warn.pdf") == 0 or die;
@@ -46,8 +48,8 @@ $td->runtest("replace input with warnings",
$td->NORMALIZE_NEWLINES);
$td->runtest("check output",
- {$td->FILE => "auto-warn.pdf"},
- {$td->FILE => "warn-replace.pdf"});
+ {$td->COMMAND => "qpdf-test-compare auto-warn.pdf warn-replace.pdf"},
+ {$td->FILE => "warn-replace.pdf", $td->EXIT_STATUS => 0});
$td->runtest("check orig output",
{$td->FILE => "auto-warn.pdf.~qpdf-orig"},
{$td->FILE => "xref-with-short-size.pdf"});
diff --git a/qpdf/qtest/rotate-pages.test b/qpdf/qtest/rotate-pages.test
index c5e293e8..2f43fed7 100644
--- a/qpdf/qtest/rotate-pages.test
+++ b/qpdf/qtest/rotate-pages.test
@@ -29,24 +29,24 @@ $td->runtest("page rotation",
" --rotate=-90:3,15,17,18"},
{$td->STRING => "", $td->EXIT_STATUS => 0});
$td->runtest("check output",
- {$td->FILE => "a.pdf"},
- {$td->FILE => "rotated.pdf"});
+ {$td->COMMAND => "qpdf-test-compare a.pdf rotated.pdf"},
+ {$td->FILE => "rotated.pdf", $td->EXIT_STATUS => 0});
$td->runtest("remove rotation",
{$td->COMMAND => "qpdf --static-id rotated.pdf a.pdf" .
" --qdf --no-original-object-ids --rotate=0"},
{$td->STRING => "", $td->EXIT_STATUS => 0});
$td->runtest("check output",
- {$td->FILE => "a.pdf"},
- {$td->FILE => "unrotated.pdf"});
+ {$td->COMMAND => "qpdf-test-compare a.pdf unrotated.pdf"},
+ {$td->FILE => "unrotated.pdf", $td->EXIT_STATUS => 0});
$td->runtest("rotate all pages",
{$td->COMMAND =>
"qpdf --static-id --rotate=180 minimal.pdf a.pdf"},
{$td->STRING => "", $td->EXIT_STATUS => 0});
$td->runtest("check output",
- {$td->FILE => "a.pdf"},
- {$td->FILE => "minimal-rotated.pdf"});
+ {$td->COMMAND => "qpdf-test-compare a.pdf minimal-rotated.pdf"},
+ {$td->FILE => "minimal-rotated.pdf", $td->EXIT_STATUS => 0});
$td->runtest("flatten with inherited rotate",
{$td->COMMAND =>
@@ -54,8 +54,8 @@ $td->runtest("flatten with inherited rotate",
" inherited-rotate.pdf a.pdf"},
{$td->STRING => "", $td->EXIT_STATUS => 0});
$td->runtest("check output",
- {$td->FILE => "a.pdf"},
- {$td->FILE => "inherited-flattened.pdf"});
+ {$td->COMMAND => "qpdf-test-compare a.pdf inherited-flattened.pdf"},
+ {$td->FILE => "inherited-flattened.pdf", $td->EXIT_STATUS => 0});
foreach my $angle (qw(90 180 270))
{
diff --git a/qpdf/qtest/specialized-filter.test b/qpdf/qtest/specialized-filter.test
index 284d5195..605dd7f2 100644
--- a/qpdf/qtest/specialized-filter.test
+++ b/qpdf/qtest/specialized-filter.test
@@ -16,7 +16,7 @@ cleanup();
my $td = new TestDriver('specialized-filter');
-my $n_tests = 3;
+my $n_tests = 5;
my $n_compare_pdfs = 1;
# The PDF file was submitted on bug #83 on github. All the PNG filters
@@ -39,6 +39,18 @@ $td->runtest("stream with tiff predictor",
{$td->FILE => "tiff-predictor.out",
$td->EXIT_STATUS => 0},
$td->NORMALIZE_NEWLINES);
-
+# TC:SF_FlateLzwDecode PNG filter
+# PDF:Table 8:Columns
+# The test file is invalid as it does not actually use one column (as is implied by the missing
+# key). However png-filters-1-column.pdf is the same file with /Columns explicitely set to 1,
+# and displays the same as png-filters-no-columns.pdf and png-filters-no-columns-decoded.pdf.
+$td->runtest("decode flate no /Columns",
+ {$td->COMMAND => "qpdf --static-id --compress-streams=n --decode-level=all" .
+ " png-filters-no-columns.pdf a.pdf"},
+ {$td->STRING => "", $td->EXIT_STATUS => 0},
+ $td->NORMALIZE_NEWLINES);
+$td->runtest("check output",
+ {$td->FILE => "a.pdf"},
+ {$td->FILE => "png-filters-no-columns-decoded.pdf"});
cleanup();
$td->report(calc_ntests($n_tests, $n_compare_pdfs));
diff --git a/qpdf/qtest/specific-file.test b/qpdf/qtest/specific-file.test
index 188f4dd5..5d77720a 100644
--- a/qpdf/qtest/specific-file.test
+++ b/qpdf/qtest/specific-file.test
@@ -33,21 +33,22 @@ $td->runtest("compress objstm and xref",
{$td->STRING => "", $td->EXIT_STATUS => 0},
$td->NORMALIZE_NEWLINES);
$td->runtest("check output",
- {$td->FILE => "a.pdf"},
- {$td->FILE => "compress-objstm-xref.pdf"});
+ {$td->COMMAND => "qpdf-test-compare a.pdf compress-objstm-xref.pdf"},
+ {$td->FILE => "compress-objstm-xref.pdf", $td->EXIT_STATUS => 0});
$td->runtest("qdf + preserved-unreferenced + xref streams",
{$td->COMMAND => "qpdf --qdf --preserve-unreferenced" .
" --static-id compress-objstm-xref.pdf a.pdf"},
{$td->STRING => "", $td->EXIT_STATUS => 0});
$td->runtest("check output",
- {$td->FILE => "a.pdf"},
- {$td->FILE => "compress-objstm-xref-qdf.pdf"});
+ {$td->COMMAND => "qpdf-test-compare a.pdf compress-objstm-xref-qdf.pdf"},
+ {$td->FILE => "compress-objstm-xref-qdf.pdf", $td->EXIT_STATUS => 0});
$td->runtest("check fix-qdf idempotency",
{$td->COMMAND => "fix-qdf a.pdf"},
{$td->FILE => "a.pdf", $td->EXIT_STATUS => 0});
$td->runtest("pages points to page",
{$td->COMMAND =>
- "qpdf --static-id --linearize pages-is-page.pdf a.pdf"},
+ "qpdf --static-id --linearize --compress-streams=n" .
+ " pages-is-page.pdf a.pdf"},
{$td->FILE => "pages-is-page.out", $td->EXIT_STATUS => 3},
$td->NORMALIZE_NEWLINES);
$td->runtest("check output",
diff --git a/qpdf/qtest/split-pages.test b/qpdf/qtest/split-pages.test
index 46515c4f..455a4ed3 100644
--- a/qpdf/qtest/split-pages.test
+++ b/qpdf/qtest/split-pages.test
@@ -70,8 +70,8 @@ $td->runtest("split page with labels",
foreach my $i (qw(01-06 07-11))
{
$td->runtest("check output ($i)",
- {$td->FILE => "split-out-labels-$i.pdf"},
- {$td->FILE => "labels-split-$i.pdf"});
+ {$td->COMMAND => "qpdf-test-compare split-out-labels-$i.pdf labels-split-$i.pdf"},
+ {$td->FILE => "labels-split-$i.pdf", $td->EXIT_STATUS => 0});
}
# See comments in TODO about these expected failures. Search for
@@ -121,8 +121,8 @@ foreach my $d (@sp_cases)
my $expected = $actual;
$expected =~ s/split-out/split-exp/;
$td->runtest("check output page $i ($description)",
- {$td->FILE => $actual},
- {$td->FILE => $expected});
+ {$td->COMMAND => "qpdf-test-compare $actual $expected u"},
+ {$td->FILE => $expected, $td->EXIT_STATUS => 0});
}
}
@@ -201,8 +201,8 @@ foreach my $d (@fo_resources)
{$td->STRING => "", $td->EXIT_STATUS => 0},
$td->NORMALIZE_NEWLINES);
$td->runtest("check output ($f)",
- {$td->FILE => "a.pdf"},
- {$td->FILE => "$f-out.pdf"});
+ {$td->COMMAND => "qpdf-test-compare a.pdf $f-out.pdf"},
+ {$td->FILE => "$f-out.pdf", $td->EXIT_STATUS => 0});
if ($compare)
{
compare_pdfs($td, "$f.pdf", "a.pdf");
diff --git a/qpdf/qtest/stream-replacements.test b/qpdf/qtest/stream-replacements.test
index 8a9874dc..547e928d 100644
--- a/qpdf/qtest/stream-replacements.test
+++ b/qpdf/qtest/stream-replacements.test
@@ -21,8 +21,8 @@ $td->runtest("replace stream data",
{$td->STRING => "test 7 done\n", $td->EXIT_STATUS => 0},
$td->NORMALIZE_NEWLINES);
$td->runtest("check output",
- {$td->FILE => "a.pdf"},
- {$td->FILE => "replaced-stream-data.pdf"});
+ {$td->COMMAND => "qpdf-test-compare a.pdf replaced-stream-data.pdf"},
+ {$td->FILE => "replaced-stream-data.pdf", $td->EXIT_STATUS => 0});
$td->runtest("replace stream data compressed",
{$td->COMMAND => "test_driver 8 qstream.pdf"},
{$td->FILE => "test8.out", $td->EXIT_STATUS => 0},
diff --git a/qpdf/qtest/type-checks.test b/qpdf/qtest/type-checks.test
index 17b3c994..73cb7fb6 100644
--- a/qpdf/qtest/type-checks.test
+++ b/qpdf/qtest/type-checks.test
@@ -27,8 +27,8 @@ $td->runtest("ensure object-types-os is up-to-date",
" object-types.pdf a.pdf"},
{$td->STRING => "", $td->EXIT_STATUS => 0});
$td->runtest("check file",
- {$td->FILE => "a.pdf"},
- {$td->FILE => "object-types-os.pdf"});
+ {$td->COMMAND => "qpdf-test-compare a.pdf object-types-os.pdf"},
+ {$td->FILE => "object-types-os.pdf", $td->EXIT_STATUS => 0});
$td->runtest("type checks",
{$td->COMMAND => "test_driver 42 object-types.pdf"},
{$td->FILE => "object-types.out",
diff --git a/qpdf/qtest/xref-streams.test b/qpdf/qtest/xref-streams.test
index 8d8e8bd9..68640bdf 100644
--- a/qpdf/qtest/xref-streams.test
+++ b/qpdf/qtest/xref-streams.test
@@ -28,7 +28,8 @@ $td->runtest("recover xref with short size",
$td->EXIT_STATUS => 3},
$td->NORMALIZE_NEWLINES);
$td->runtest("show new xref stream",
- {$td->COMMAND => "qpdf --show-xref a.pdf"},
+ {$td->COMMAND => "qpdf --show-xref a.pdf",
+ $td->FILTER => "perl filter-xref-offsets.pl"},
{$td->FILE => "xref-with-short-size-new.out",
$td->EXIT_STATUS => 0},
$td->NORMALIZE_NEWLINES);
diff --git a/qpdf/test_driver.cc b/qpdf/test_driver.cc
index 319c80d2..2b8eb761 100644
--- a/qpdf/test_driver.cc
+++ b/qpdf/test_driver.cc
@@ -1218,6 +1218,9 @@ test_32(QPDF& pdf, char const* arg2)
<< "linearized: " << (linearized ? "yes" : "no") << std::endl
<< "newline: " << (newline ? "yes" : "no") << std::endl;
w.setLinearization(linearized);
+ if (linearized) {
+ w.setCompressStreams(false); // avoid dependency on zlib's output
+ }
w.setExtraHeaderText(newline ? "%% Comment with newline\n" : "%% Comment\n% No newline");
w.write();
}
diff --git a/zlib-flate/qtest/1.compressed-1 b/zlib-flate/qtest/1.compressed-1
deleted file mode 100644
index 11150cf3..00000000
--- a/zlib-flate/qtest/1.compressed-1
+++ /dev/null
Binary files differ
diff --git a/zlib-flate/qtest/1.compressed-9 b/zlib-flate/qtest/1.compressed-9
deleted file mode 100644
index 25f4647b..00000000
--- a/zlib-flate/qtest/1.compressed-9
+++ /dev/null
Binary files differ
diff --git a/zlib-flate/qtest/zf.test b/zlib-flate/qtest/zf.test
index d864a130..2fa5c1eb 100644
--- a/zlib-flate/qtest/zf.test
+++ b/zlib-flate/qtest/zf.test
@@ -7,22 +7,40 @@ require TestDriver;
my $td = new TestDriver('zlib-flate');
+cleanup();
+
+open(F, "<1.uncompressed") or die;
+undef $/;
+my $unc = <F>;
+close(F);
+
+open(F, ">a.uncompressed") or die;
+for (my $i = 0; $i < 100; $i++)
+{
+ print F $unc;
+}
+close(F);
+
foreach my $level ('', '=1', '=9')
{
my $f = $level;
$f =~ s/=/-/;
$td->runtest("compress",
{$td->COMMAND =>
- "zlib-flate -compress$level < 1.uncompressed"},
- {$td->FILE => "1.compressed$f",
- $td->EXIT_STATUS => 0});
+ "zlib-flate -compress$level < a.uncompressed > a.$level"},
+ {$td->STRING => "", $td->EXIT_STATUS => 0});
$td->runtest("uncompress",
- {$td->COMMAND => "zlib-flate -uncompress < 1.compressed"},
- {$td->FILE => "1.uncompressed",
- $td->EXIT_STATUS => 0});
+ {$td->COMMAND => "zlib-flate -uncompress < a.$level"},
+ {$td->FILE => "a.uncompressed", $td->EXIT_STATUS => 0});
}
+my $size1 = (stat("a.=1"))[7];
+my $size9 = (stat("a.=9"))[7];
+$td->runtest("higher compression is smaller",
+ {$td->STRING => ($size9 < $size1 ? "YES\n" : "$size9 $size1\n")},
+ {$td->STRING => "YES\n"});
+
$td->runtest("error",
{$td->COMMAND => "zlib-flate -uncompress < 1.uncompressed"},
{$td->REGEXP => "flate: inflate: data: .*\n",
@@ -36,4 +54,11 @@ $td->runtest("corrupted input",
$td->EXIT_STATUS => 3},
$td->NORMALIZE_NEWLINES);
-$td->report(8);
+$td->report(9);
+
+cleanup();
+
+sub cleanup
+{
+ system("rm -f a.*");
+}