Commit ef14676bfb0b4674facc305e1df8ac00af84f5b2

Authored by m-holger
Committed by GitHub
2 parents f4e29052 023a0027

Merge pull request #1529 from m-holger/nnt

Add stricter name/number tree validation
include/qpdf/QPDFEmbeddedFileDocumentHelper.hh
@@ -67,19 +67,7 @@ class QPDFEmbeddedFileDocumentHelper: public QPDFDocumentHelper @@ -67,19 +67,7 @@ class QPDFEmbeddedFileDocumentHelper: public QPDFDocumentHelper
67 private: 67 private:
68 void initEmbeddedFiles(); 68 void initEmbeddedFiles();
69 69
70 - class Members  
71 - {  
72 - friend class QPDFEmbeddedFileDocumentHelper;  
73 -  
74 - public:  
75 - ~Members() = default;  
76 -  
77 - private:  
78 - Members() = default;  
79 - Members(Members const&) = delete;  
80 -  
81 - std::shared_ptr<QPDFNameTreeObjectHelper> embedded_files;  
82 - }; 70 + class Members;
83 71
84 std::shared_ptr<Members> m; 72 std::shared_ptr<Members> m;
85 }; 73 };
include/qpdf/QPDFNameTreeObjectHelper.hh
@@ -45,6 +45,19 @@ class QPDF_DLL_CLASS QPDFNameTreeObjectHelper: public QPDFObjectHelper @@ -45,6 +45,19 @@ class QPDF_DLL_CLASS QPDFNameTreeObjectHelper: public QPDFObjectHelper
45 QPDF_DLL 45 QPDF_DLL
46 QPDFNameTreeObjectHelper(QPDFObjectHandle, QPDF&, bool auto_repair = true); 46 QPDFNameTreeObjectHelper(QPDFObjectHandle, QPDF&, bool auto_repair = true);
47 47
  48 + QPDF_DLL
  49 + QPDFNameTreeObjectHelper(
  50 + QPDFObjectHandle,
  51 + QPDF&,
  52 + std::function<bool(QPDFObjectHandle const&)> value_validator,
  53 + bool auto_repair);
  54 +
  55 + // Validate the name tree. Returns true if the tree is valid.
  56 + //
  57 + // If the tree is not valid and auto_repair is true, attempt to repair the tree.
  58 + QPDF_DLL
  59 + bool validate(bool repair = true);
  60 +
48 // Create an empty name tree 61 // Create an empty name tree
49 QPDF_DLL 62 QPDF_DLL
50 static QPDFNameTreeObjectHelper newEmpty(QPDF&, bool auto_repair = true); 63 static QPDFNameTreeObjectHelper newEmpty(QPDF&, bool auto_repair = true);
@@ -171,7 +184,11 @@ class QPDF_DLL_CLASS QPDFNameTreeObjectHelper: public QPDFObjectHelper @@ -171,7 +184,11 @@ class QPDF_DLL_CLASS QPDFNameTreeObjectHelper: public QPDFObjectHelper
171 ~Members() = default; 184 ~Members() = default;
172 185
173 private: 186 private:
174 - Members(QPDFObjectHandle& oh, QPDF&, bool auto_repair); 187 + Members(
  188 + QPDFObjectHandle& oh,
  189 + QPDF&,
  190 + std::function<bool(QPDFObjectHandle const&)> value_validator,
  191 + bool auto_repair);
175 Members(Members const&) = delete; 192 Members(Members const&) = delete;
176 193
177 std::shared_ptr<NNTreeImpl> impl; 194 std::shared_ptr<NNTreeImpl> impl;
include/qpdf/QPDFNumberTreeObjectHelper.hh
@@ -44,6 +44,13 @@ class QPDF_DLL_CLASS QPDFNumberTreeObjectHelper: public QPDFObjectHelper @@ -44,6 +44,13 @@ class QPDF_DLL_CLASS QPDFNumberTreeObjectHelper: public QPDFObjectHelper
44 QPDFNumberTreeObjectHelper(QPDFObjectHandle, QPDF&, bool auto_repair = true); 44 QPDFNumberTreeObjectHelper(QPDFObjectHandle, QPDF&, bool auto_repair = true);
45 45
46 QPDF_DLL 46 QPDF_DLL
  47 + QPDFNumberTreeObjectHelper(
  48 + QPDFObjectHandle,
  49 + QPDF&,
  50 + std::function<bool(QPDFObjectHandle const&)> value_validator,
  51 + bool auto_repair);
  52 +
  53 + QPDF_DLL
47 ~QPDFNumberTreeObjectHelper() override; 54 ~QPDFNumberTreeObjectHelper() override;
48 55
49 // Create an empty number tree 56 // Create an empty number tree
@@ -52,6 +59,12 @@ class QPDF_DLL_CLASS QPDFNumberTreeObjectHelper: public QPDFObjectHelper @@ -52,6 +59,12 @@ class QPDF_DLL_CLASS QPDFNumberTreeObjectHelper: public QPDFObjectHelper
52 59
53 typedef long long int numtree_number; 60 typedef long long int numtree_number;
54 61
  62 + // Validate the name tree. Returns true if the tree is valid.
  63 + //
  64 + // If the tree is not valid and auto_repair is true, attempt to repair the tree.
  65 + QPDF_DLL
  66 + bool validate(bool repair = true);
  67 +
55 // Return overall minimum and maximum indices 68 // Return overall minimum and maximum indices
56 QPDF_DLL 69 QPDF_DLL
57 numtree_number getMin(); 70 numtree_number getMin();
@@ -188,7 +201,11 @@ class QPDF_DLL_CLASS QPDFNumberTreeObjectHelper: public QPDFObjectHelper @@ -188,7 +201,11 @@ class QPDF_DLL_CLASS QPDFNumberTreeObjectHelper: public QPDFObjectHelper
188 ~Members() = default; 201 ~Members() = default;
189 202
190 private: 203 private:
191 - Members(QPDFObjectHandle& oh, QPDF&, bool auto_repair); 204 + Members(
  205 + QPDFObjectHandle& oh,
  206 + QPDF&,
  207 + std::function<bool(QPDFObjectHandle const&)> value_validator,
  208 + bool auto_repair);
192 Members(Members const&) = delete; 209 Members(Members const&) = delete;
193 210
194 std::shared_ptr<NNTreeImpl> impl; 211 std::shared_ptr<NNTreeImpl> impl;
include/qpdf/QPDFOutlineDocumentHelper.hh
@@ -63,33 +63,13 @@ class QPDFOutlineDocumentHelper: public QPDFDocumentHelper @@ -63,33 +63,13 @@ class QPDFOutlineDocumentHelper: public QPDFDocumentHelper
63 { 63 {
64 friend class QPDFOutlineObjectHelper; 64 friend class QPDFOutlineObjectHelper;
65 65
66 - static bool  
67 - checkSeen(QPDFOutlineDocumentHelper& dh, QPDFObjGen og)  
68 - {  
69 - return !dh.m->seen.add(og);  
70 - } 66 + static bool checkSeen(QPDFOutlineDocumentHelper& dh, QPDFObjGen og);
71 }; 67 };
72 68
73 private: 69 private:
74 void initializeByPage(); 70 void initializeByPage();
75 71
76 - class Members  
77 - {  
78 - friend class QPDFOutlineDocumentHelper;  
79 -  
80 - public:  
81 - ~Members() = default;  
82 -  
83 - private:  
84 - Members() = default;  
85 - Members(Members const&) = delete;  
86 -  
87 - std::vector<QPDFOutlineObjectHelper> outlines;  
88 - QPDFObjGen::set seen;  
89 - QPDFObjectHandle dest_dict;  
90 - std::shared_ptr<QPDFNameTreeObjectHelper> names_dest;  
91 - std::map<QPDFObjGen, std::vector<QPDFOutlineObjectHelper>> by_page;  
92 - }; 72 + class Members;
93 73
94 std::shared_ptr<Members> m; 74 std::shared_ptr<Members> m;
95 }; 75 };
include/qpdf/QPDFPageLabelDocumentHelper.hh
@@ -77,19 +77,7 @@ class QPDFPageLabelDocumentHelper: public QPDFDocumentHelper @@ -77,19 +77,7 @@ class QPDFPageLabelDocumentHelper: public QPDFDocumentHelper
77 std::vector<QPDFObjectHandle>& new_labels); 77 std::vector<QPDFObjectHandle>& new_labels);
78 78
79 private: 79 private:
80 - class Members  
81 - {  
82 - friend class QPDFPageLabelDocumentHelper;  
83 -  
84 - public:  
85 - ~Members() = default;  
86 -  
87 - private:  
88 - Members() = default;  
89 - Members(Members const&) = delete;  
90 -  
91 - std::shared_ptr<QPDFNumberTreeObjectHelper> labels;  
92 - }; 80 + class Members;
93 81
94 std::shared_ptr<Members> m; 82 std::shared_ptr<Members> m;
95 }; 83 };
libqpdf/NNTree.cc
@@ -141,8 +141,8 @@ NNTreeIterator::increment(bool backward) @@ -141,8 +141,8 @@ NNTreeIterator::increment(bool backward)
141 impl.warn(node, "items array doesn't have enough elements"); 141 impl.warn(node, "items array doesn't have enough elements");
142 } else if (!impl.details.keyValid(items[item_number])) { 142 } else if (!impl.details.keyValid(items[item_number])) {
143 impl.warn(node, ("item " + std::to_string(item_number) + " has the wrong type")); 143 impl.warn(node, ("item " + std::to_string(item_number) + " has the wrong type"));
144 - } else if (!items[item_number + 1]) {  
145 - impl.warn(node, "item " + std::to_string(item_number) + " is null"); 144 + } else if (!impl.value_valid(items[item_number + 1])) {
  145 + impl.warn(node, "item " + std::to_string(item_number + 1) + " is invalid");
146 } else { 146 } else {
147 return; 147 return;
148 } 148 }
@@ -386,6 +386,9 @@ NNTreeIterator::insertAfter(QPDFObjectHandle const&amp; key, QPDFObjectHandle const&amp; @@ -386,6 +386,9 @@ NNTreeIterator::insertAfter(QPDFObjectHandle const&amp; key, QPDFObjectHandle const&amp;
386 if (!(key && value)) { 386 if (!(key && value)) {
387 impl.error(node, "insert: key or value is null"); 387 impl.error(node, "insert: key or value is null");
388 } 388 }
  389 + if (!impl.value_valid(value)) {
  390 + impl.error(node, "insert: value is invalid");
  391 + }
389 items.insert(item_number + 2, key); 392 items.insert(item_number + 2, key);
390 items.insert(item_number + 3, value); 393 items.insert(item_number + 3, value);
391 resetLimits(node, lastPathElement()); 394 resetLimits(node, lastPathElement());
@@ -621,10 +624,15 @@ NNTreeIterator::deepen(QPDFObjectHandle a_node, bool first, bool allow_empty) @@ -621,10 +624,15 @@ NNTreeIterator::deepen(QPDFObjectHandle a_node, bool first, bool allow_empty)
621 } 624 }
622 625
623 NNTreeImpl::NNTreeImpl( 626 NNTreeImpl::NNTreeImpl(
624 - NNTreeDetails const& details, QPDF& qpdf, QPDFObjectHandle& oh, bool auto_repair) : 627 + NNTreeDetails const& details,
  628 + QPDF& qpdf,
  629 + QPDFObjectHandle& oh,
  630 + std::function<bool(QPDFObjectHandle const&)> value_validator,
  631 + bool auto_repair) :
625 details(details), 632 details(details),
626 qpdf(qpdf), 633 qpdf(qpdf),
627 oh(oh), 634 oh(oh),
  635 + value_valid(value_validator),
628 auto_repair(auto_repair) 636 auto_repair(auto_repair)
629 { 637 {
630 } 638 }
@@ -740,7 +748,7 @@ NNTreeImpl::repair() @@ -740,7 +748,7 @@ NNTreeImpl::repair()
740 { 748 {
741 auto new_node = QPDFObjectHandle::newDictionary(); 749 auto new_node = QPDFObjectHandle::newDictionary();
742 new_node.replaceKey(details.itemsKey(), Array()); 750 new_node.replaceKey(details.itemsKey(), Array());
743 - NNTreeImpl repl(details, qpdf, new_node, false); 751 + NNTreeImpl repl(details, qpdf, new_node, value_valid, false);
744 for (auto const& [key, value]: *this) { 752 for (auto const& [key, value]: *this) {
745 if (key && value) { 753 if (key && value) {
746 repl.insert(key, value); 754 repl.insert(key, value);
@@ -774,10 +782,17 @@ NNTreeImpl::findInternal(QPDFObjectHandle const&amp; key, bool return_prev_if_not_fo @@ -774,10 +782,17 @@ NNTreeImpl::findInternal(QPDFObjectHandle const&amp; key, bool return_prev_if_not_fo
774 if (first_item == end()) { 782 if (first_item == end()) {
775 return end(); 783 return end();
776 } 784 }
777 - if (first_item.valid() && details.keyValid(first_item->first) &&  
778 - details.compareKeys(key, first_item->first) < 0) {  
779 - // Before the first key  
780 - return end(); 785 + if (first_item.valid()) {
  786 + if (!details.keyValid(first_item->first)) {
  787 + error(oh, "encountered invalid key in find");
  788 + }
  789 + if (!value_valid(first_item->second)) {
  790 + error(oh, "encountered invalid value in find");
  791 + }
  792 + if (details.compareKeys(key, first_item->first) < 0) {
  793 + // Before the first key
  794 + return end();
  795 + }
781 } 796 }
782 qpdf_assert_debug(!last_item.valid()); 797 qpdf_assert_debug(!last_item.valid());
783 798
@@ -797,6 +812,12 @@ NNTreeImpl::findInternal(QPDFObjectHandle const&amp; key, bool return_prev_if_not_fo @@ -797,6 +812,12 @@ NNTreeImpl::findInternal(QPDFObjectHandle const&amp; key, bool return_prev_if_not_fo
797 key, items, nitems / 2, return_prev_if_not_found, &NNTreeImpl::compareKeyItem); 812 key, items, nitems / 2, return_prev_if_not_found, &NNTreeImpl::compareKeyItem);
798 if (idx >= 0) { 813 if (idx >= 0) {
799 result.setItemNumber(node, 2 * idx); 814 result.setItemNumber(node, 2 * idx);
  815 + if (!result.impl.details.keyValid(result.ivalue.first)) {
  816 + error(node, "encountered invalid key in find");
  817 + }
  818 + if (!result.impl.value_valid(result.ivalue.second)) {
  819 + error(oh, "encountered invalid value in find");
  820 + }
800 } 821 }
801 return result; 822 return result;
802 } 823 }
@@ -830,6 +851,9 @@ NNTreeImpl::insertFirst(QPDFObjectHandle const&amp; key, QPDFObjectHandle const&amp; val @@ -830,6 +851,9 @@ NNTreeImpl::insertFirst(QPDFObjectHandle const&amp; key, QPDFObjectHandle const&amp; val
830 if (!(key && value)) { 851 if (!(key && value)) {
831 error(oh, "unable to insert null key or value"); 852 error(oh, "unable to insert null key or value");
832 } 853 }
  854 + if (!value_valid(value)) {
  855 + error(oh, "attempting to insert an invalid value");
  856 + }
833 items.insert(0, key); 857 items.insert(0, key);
834 items.insert(1, value); 858 items.insert(1, value);
835 iter.setItemNumber(iter.node, 0); 859 iter.setItemNumber(iter.node, 0);
@@ -867,3 +891,33 @@ NNTreeImpl::remove(QPDFObjectHandle const&amp; key, QPDFObjectHandle* value) @@ -867,3 +891,33 @@ NNTreeImpl::remove(QPDFObjectHandle const&amp; key, QPDFObjectHandle* value)
867 iter.remove(); 891 iter.remove();
868 return true; 892 return true;
869 } 893 }
  894 +
  895 +bool
  896 +NNTreeImpl::validate(bool a_repair)
  897 +{
  898 + bool first = true;
  899 + QPDFObjectHandle last_key;
  900 + try {
  901 + for (auto const& [key, value]: *this) {
  902 + if (!details.keyValid(key)) {
  903 + error(oh, "invalid key in validate");
  904 + }
  905 + if (!value_valid(value)) {
  906 + error(oh, "invalid value in validate");
  907 + }
  908 + if (first) {
  909 + first = false;
  910 + } else if (last_key && details.compareKeys(last_key, key) != -1) {
  911 + error(oh, "keys are not sorted in validate");
  912 + }
  913 + last_key = key;
  914 + }
  915 + } catch (QPDFExc& e) {
  916 + if (a_repair) {
  917 + warn(oh, std::string("attempting to repair after error: ") + e.what());
  918 + repair();
  919 + }
  920 + return false;
  921 + }
  922 + return true;
  923 +}
libqpdf/QPDFEmbeddedFileDocumentHelper.cc
@@ -30,16 +30,30 @@ @@ -30,16 +30,30 @@
30 // >> 30 // >>
31 // >> 31 // >>
32 32
  33 +class QPDFEmbeddedFileDocumentHelper::Members
  34 +{
  35 + public:
  36 + Members() = default;
  37 + Members(Members const&) = delete;
  38 + ~Members() = default;
  39 +
  40 + std::unique_ptr<QPDFNameTreeObjectHelper> embedded_files;
  41 +};
  42 +
33 QPDFEmbeddedFileDocumentHelper::QPDFEmbeddedFileDocumentHelper(QPDF& qpdf) : 43 QPDFEmbeddedFileDocumentHelper::QPDFEmbeddedFileDocumentHelper(QPDF& qpdf) :
34 QPDFDocumentHelper(qpdf), 44 QPDFDocumentHelper(qpdf),
35 - m(new Members()) 45 + m(std::make_shared<Members>())
36 { 46 {
37 - auto root = qpdf.getRoot();  
38 - auto names = root.getKey("/Names"); 47 + auto names = qpdf.getRoot().getKey("/Names");
39 if (names.isDictionary()) { 48 if (names.isDictionary()) {
40 auto embedded_files = names.getKey("/EmbeddedFiles"); 49 auto embedded_files = names.getKey("/EmbeddedFiles");
41 if (embedded_files.isDictionary()) { 50 if (embedded_files.isDictionary()) {
42 - m->embedded_files = std::make_shared<QPDFNameTreeObjectHelper>(embedded_files, qpdf); 51 + m->embedded_files = std::make_unique<QPDFNameTreeObjectHelper>(
  52 + embedded_files,
  53 + qpdf,
  54 + [](QPDFObjectHandle const& o) -> bool { return o.isDictionary(); },
  55 + true);
  56 + m->embedded_files->validate();
43 } 57 }
44 } 58 }
45 } 59 }
@@ -65,7 +79,8 @@ QPDFEmbeddedFileDocumentHelper::initEmbeddedFiles() @@ -65,7 +79,8 @@ QPDFEmbeddedFileDocumentHelper::initEmbeddedFiles()
65 if (!embedded_files.isDictionary()) { 79 if (!embedded_files.isDictionary()) {
66 auto nth = QPDFNameTreeObjectHelper::newEmpty(qpdf); 80 auto nth = QPDFNameTreeObjectHelper::newEmpty(qpdf);
67 names.replaceKey("/EmbeddedFiles", nth.getObjectHandle()); 81 names.replaceKey("/EmbeddedFiles", nth.getObjectHandle());
68 - m->embedded_files = std::make_shared<QPDFNameTreeObjectHelper>(nth); 82 + m->embedded_files = std::make_unique<QPDFNameTreeObjectHelper>(
  83 + nth, qpdf, [](QPDFObjectHandle const& o) -> bool { return o.isDictionary(); }, true);
69 } 84 }
70 } 85 }
71 86
libqpdf/QPDFNameTreeObjectHelper.cc
@@ -40,14 +40,29 @@ QPDFNameTreeObjectHelper::~QPDFNameTreeObjectHelper() // NOLINT (modernize-use-e @@ -40,14 +40,29 @@ QPDFNameTreeObjectHelper::~QPDFNameTreeObjectHelper() // NOLINT (modernize-use-e
40 // class, see github issue #745. 40 // class, see github issue #745.
41 } 41 }
42 42
43 -QPDFNameTreeObjectHelper::Members::Members(QPDFObjectHandle& oh, QPDF& q, bool auto_repair) :  
44 - impl(std::make_shared<NNTreeImpl>(name_tree_details, q, oh, auto_repair)) 43 +QPDFNameTreeObjectHelper::Members::Members(
  44 + QPDFObjectHandle& oh,
  45 + QPDF& q,
  46 + std::function<bool(QPDFObjectHandle const&)> value_validator,
  47 + bool auto_repair) :
  48 + impl(std::make_shared<NNTreeImpl>(name_tree_details, q, oh, value_validator, auto_repair))
45 { 49 {
46 } 50 }
47 51
48 QPDFNameTreeObjectHelper::QPDFNameTreeObjectHelper(QPDFObjectHandle oh, QPDF& q, bool auto_repair) : 52 QPDFNameTreeObjectHelper::QPDFNameTreeObjectHelper(QPDFObjectHandle oh, QPDF& q, bool auto_repair) :
49 QPDFObjectHelper(oh), 53 QPDFObjectHelper(oh),
50 - m(new Members(oh, q, auto_repair)) 54 + m(new Members(
  55 + oh, q, [](QPDFObjectHandle const& o) -> bool { return static_cast<bool>(o); }, auto_repair))
  56 +{
  57 +}
  58 +
  59 +QPDFNameTreeObjectHelper::QPDFNameTreeObjectHelper(
  60 + QPDFObjectHandle oh,
  61 + QPDF& q,
  62 + std::function<bool(QPDFObjectHandle const&)> value_validator,
  63 + bool auto_repair) :
  64 + QPDFObjectHelper(oh),
  65 + m(new Members(oh, q, value_validator, auto_repair))
51 { 66 {
52 } 67 }
53 68
@@ -200,3 +215,9 @@ QPDFNameTreeObjectHelper::getAsMap() const @@ -200,3 +215,9 @@ QPDFNameTreeObjectHelper::getAsMap() const
200 result.insert(begin(), end()); 215 result.insert(begin(), end());
201 return result; 216 return result;
202 } 217 }
  218 +
  219 +bool
  220 +QPDFNameTreeObjectHelper::validate(bool repair)
  221 +{
  222 + return m->impl->validate(repair);
  223 +}
libqpdf/QPDFNumberTreeObjectHelper.cc
@@ -41,15 +41,30 @@ QPDFNumberTreeObjectHelper::~QPDFNumberTreeObjectHelper() // NOLINT (modernize-u @@ -41,15 +41,30 @@ QPDFNumberTreeObjectHelper::~QPDFNumberTreeObjectHelper() // NOLINT (modernize-u
41 // class, see github issue #745. 41 // class, see github issue #745.
42 } 42 }
43 43
44 -QPDFNumberTreeObjectHelper::Members::Members(QPDFObjectHandle& oh, QPDF& q, bool auto_repair) :  
45 - impl(std::make_shared<NNTreeImpl>(number_tree_details, q, oh, auto_repair)) 44 +QPDFNumberTreeObjectHelper::Members::Members(
  45 + QPDFObjectHandle& oh,
  46 + QPDF& q,
  47 + std::function<bool(QPDFObjectHandle const&)> value_validator,
  48 + bool auto_repair) :
  49 + impl(std::make_shared<NNTreeImpl>(number_tree_details, q, oh, value_validator, auto_repair))
46 { 50 {
47 } 51 }
48 52
49 QPDFNumberTreeObjectHelper::QPDFNumberTreeObjectHelper( 53 QPDFNumberTreeObjectHelper::QPDFNumberTreeObjectHelper(
50 QPDFObjectHandle oh, QPDF& q, bool auto_repair) : 54 QPDFObjectHandle oh, QPDF& q, bool auto_repair) :
51 QPDFObjectHelper(oh), 55 QPDFObjectHelper(oh),
52 - m(new Members(oh, q, auto_repair)) 56 + m(new Members(
  57 + oh, q, [](QPDFObjectHandle const& o) -> bool { return static_cast<bool>(o); }, auto_repair))
  58 +{
  59 +}
  60 +
  61 +QPDFNumberTreeObjectHelper::QPDFNumberTreeObjectHelper(
  62 + QPDFObjectHandle oh,
  63 + QPDF& q,
  64 + std::function<bool(QPDFObjectHandle const&)> value_validator,
  65 + bool auto_repair) :
  66 + QPDFObjectHelper(oh),
  67 + m(new Members(oh, q, value_validator, auto_repair))
53 { 68 {
54 } 69 }
55 70
@@ -236,3 +251,9 @@ QPDFNumberTreeObjectHelper::getAsMap() const @@ -236,3 +251,9 @@ QPDFNumberTreeObjectHelper::getAsMap() const
236 result.insert(begin(), end()); 251 result.insert(begin(), end());
237 return result; 252 return result;
238 } 253 }
  254 +
  255 +bool
  256 +QPDFNumberTreeObjectHelper::validate(bool repair)
  257 +{
  258 + return m->impl->validate(repair);
  259 +}
libqpdf/QPDFOutlineDocumentHelper.cc
@@ -2,22 +2,42 @@ @@ -2,22 +2,42 @@
2 2
3 #include <qpdf/QTC.hh> 3 #include <qpdf/QTC.hh>
4 4
  5 +class QPDFOutlineDocumentHelper::Members
  6 +{
  7 + public:
  8 + Members() = default;
  9 + Members(Members const&) = delete;
  10 + ~Members() = default;
  11 +
  12 + std::vector<QPDFOutlineObjectHelper> outlines;
  13 + QPDFObjGen::set seen;
  14 + QPDFObjectHandle dest_dict;
  15 + std::unique_ptr<QPDFNameTreeObjectHelper> names_dest;
  16 + std::map<QPDFObjGen, std::vector<QPDFOutlineObjectHelper>> by_page;
  17 +};
  18 +
  19 +bool
  20 +QPDFOutlineDocumentHelper::Accessor::checkSeen(QPDFOutlineDocumentHelper& dh, QPDFObjGen og)
  21 +{
  22 + return !dh.m->seen.add(og);
  23 +}
  24 +
5 QPDFOutlineDocumentHelper::QPDFOutlineDocumentHelper(QPDF& qpdf) : 25 QPDFOutlineDocumentHelper::QPDFOutlineDocumentHelper(QPDF& qpdf) :
6 QPDFDocumentHelper(qpdf), 26 QPDFDocumentHelper(qpdf),
7 - m(new Members()) 27 + m(std::make_shared<Members>())
8 { 28 {
9 QPDFObjectHandle root = qpdf.getRoot(); 29 QPDFObjectHandle root = qpdf.getRoot();
10 if (!root.hasKey("/Outlines")) { 30 if (!root.hasKey("/Outlines")) {
11 return; 31 return;
12 } 32 }
13 - QPDFObjectHandle outlines = root.getKey("/Outlines"); 33 + auto outlines = root.getKey("/Outlines");
14 if (!(outlines.isDictionary() && outlines.hasKey("/First"))) { 34 if (!(outlines.isDictionary() && outlines.hasKey("/First"))) {
15 return; 35 return;
16 } 36 }
17 QPDFObjectHandle cur = outlines.getKey("/First"); 37 QPDFObjectHandle cur = outlines.getKey("/First");
18 QPDFObjGen::set seen; 38 QPDFObjGen::set seen;
19 while (!cur.isNull() && seen.add(cur)) { 39 while (!cur.isNull() && seen.add(cur)) {
20 - m->outlines.push_back(QPDFOutlineObjectHelper::Accessor::create(cur, *this, 1)); 40 + m->outlines.emplace_back(QPDFOutlineObjectHelper::Accessor::create(cur, *this, 1));
21 cur = cur.getKey("/Next"); 41 cur = cur.getKey("/Next");
22 } 42 }
23 } 43 }
@@ -55,11 +75,10 @@ QPDFOutlineDocumentHelper::getOutlinesForPage(QPDFObjGen og) @@ -55,11 +75,10 @@ QPDFOutlineDocumentHelper::getOutlinesForPage(QPDFObjGen og)
55 if (m->by_page.empty()) { 75 if (m->by_page.empty()) {
56 initializeByPage(); 76 initializeByPage();
57 } 77 }
58 - std::vector<QPDFOutlineObjectHelper> result;  
59 if (m->by_page.contains(og)) { 78 if (m->by_page.contains(og)) {
60 - result = m->by_page[og]; 79 + return m->by_page[og];
61 } 80 }
62 - return result; 81 + return {};
63 } 82 }
64 83
65 QPDFObjectHandle 84 QPDFObjectHandle
@@ -70,13 +89,19 @@ QPDFOutlineDocumentHelper::resolveNamedDest(QPDFObjectHandle name) @@ -70,13 +89,19 @@ QPDFOutlineDocumentHelper::resolveNamedDest(QPDFObjectHandle name)
70 if (!m->dest_dict) { 89 if (!m->dest_dict) {
71 m->dest_dict = qpdf.getRoot().getKey("/Dests"); 90 m->dest_dict = qpdf.getRoot().getKey("/Dests");
72 } 91 }
73 - QTC::TC("qpdf", "QPDFOutlineDocumentHelper name named dest");  
74 result = m->dest_dict.getKeyIfDict(name.getName()); 92 result = m->dest_dict.getKeyIfDict(name.getName());
75 } else if (name.isString()) { 93 } else if (name.isString()) {
76 if (!m->names_dest) { 94 if (!m->names_dest) {
77 auto dests = qpdf.getRoot().getKey("/Names").getKeyIfDict("/Dests"); 95 auto dests = qpdf.getRoot().getKey("/Names").getKeyIfDict("/Dests");
78 if (dests.isDictionary()) { 96 if (dests.isDictionary()) {
79 - m->names_dest = std::make_shared<QPDFNameTreeObjectHelper>(dests, qpdf); 97 + m->names_dest = std::make_unique<QPDFNameTreeObjectHelper>(
  98 + dests,
  99 + qpdf,
  100 + [](QPDFObjectHandle const& o) -> bool {
  101 + return o.isArray() || o.isDictionary();
  102 + },
  103 + true);
  104 + m->names_dest->validate();
80 } 105 }
81 } 106 }
82 if (m->names_dest) { 107 if (m->names_dest) {
@@ -89,7 +114,6 @@ QPDFOutlineDocumentHelper::resolveNamedDest(QPDFObjectHandle name) @@ -89,7 +114,6 @@ QPDFOutlineDocumentHelper::resolveNamedDest(QPDFObjectHandle name)
89 return QPDFObjectHandle::newNull(); 114 return QPDFObjectHandle::newNull();
90 } 115 }
91 if (result.isDictionary()) { 116 if (result.isDictionary()) {
92 - QTC::TC("qpdf", "QPDFOutlineDocumentHelper named dest dictionary");  
93 return result.getKey("/D"); 117 return result.getKey("/D");
94 } 118 }
95 return result; 119 return result;
libqpdf/QPDFPageLabelDocumentHelper.cc
@@ -2,37 +2,47 @@ @@ -2,37 +2,47 @@
2 2
3 #include <qpdf/QTC.hh> 3 #include <qpdf/QTC.hh>
4 4
  5 +class QPDFPageLabelDocumentHelper::Members
  6 +{
  7 + public:
  8 + Members() = default;
  9 + Members(Members const&) = delete;
  10 + ~Members() = default;
  11 +
  12 + std::unique_ptr<QPDFNumberTreeObjectHelper> labels;
  13 +};
  14 +
5 QPDFPageLabelDocumentHelper::QPDFPageLabelDocumentHelper(QPDF& qpdf) : 15 QPDFPageLabelDocumentHelper::QPDFPageLabelDocumentHelper(QPDF& qpdf) :
6 QPDFDocumentHelper(qpdf), 16 QPDFDocumentHelper(qpdf),
7 - m(new Members()) 17 + m(std::make_shared<Members>())
8 { 18 {
9 QPDFObjectHandle root = qpdf.getRoot(); 19 QPDFObjectHandle root = qpdf.getRoot();
10 if (root.hasKey("/PageLabels")) { 20 if (root.hasKey("/PageLabels")) {
11 - m->labels =  
12 - std::make_shared<QPDFNumberTreeObjectHelper>(root.getKey("/PageLabels"), this->qpdf); 21 + m->labels = std::make_unique<QPDFNumberTreeObjectHelper>(
  22 + root.getKey("/PageLabels"),
  23 + this->qpdf,
  24 + [](QPDFObjectHandle const& o) -> bool { return o.isDictionary(); },
  25 + true);
  26 + m->labels->validate();
13 } 27 }
14 } 28 }
15 29
16 bool 30 bool
17 QPDFPageLabelDocumentHelper::hasPageLabels() 31 QPDFPageLabelDocumentHelper::hasPageLabels()
18 { 32 {
19 - return nullptr != m->labels; 33 + return m->labels != nullptr;
20 } 34 }
21 35
22 QPDFObjectHandle 36 QPDFObjectHandle
23 QPDFPageLabelDocumentHelper::getLabelForPage(long long page_idx) 37 QPDFPageLabelDocumentHelper::getLabelForPage(long long page_idx)
24 { 38 {
25 - QPDFObjectHandle result(QPDFObjectHandle::newNull());  
26 if (!hasPageLabels()) { 39 if (!hasPageLabels()) {
27 - return result; 40 + return QPDFObjectHandle::newNull();
28 } 41 }
29 QPDFNumberTreeObjectHelper::numtree_number offset = 0; 42 QPDFNumberTreeObjectHelper::numtree_number offset = 0;
30 QPDFObjectHandle label; 43 QPDFObjectHandle label;
31 if (!m->labels->findObjectAtOrBelow(page_idx, label, offset)) { 44 if (!m->labels->findObjectAtOrBelow(page_idx, label, offset)) {
32 - return result;  
33 - }  
34 - if (!label.isDictionary()) {  
35 - return result; 45 + return QPDFObjectHandle::newNull();
36 } 46 }
37 QPDFObjectHandle S = label.getKey("/S"); // type (D, R, r, A, a) 47 QPDFObjectHandle S = label.getKey("/S"); // type (D, R, r, A, a)
38 QPDFObjectHandle P = label.getKey("/P"); // prefix 48 QPDFObjectHandle P = label.getKey("/P"); // prefix
@@ -43,7 +53,7 @@ QPDFPageLabelDocumentHelper::getLabelForPage(long long page_idx) @@ -43,7 +53,7 @@ QPDFPageLabelDocumentHelper::getLabelForPage(long long page_idx)
43 } 53 }
44 QIntC::range_check(start, offset); 54 QIntC::range_check(start, offset);
45 start += offset; 55 start += offset;
46 - result = QPDFObjectHandle::newDictionary(); 56 + auto result = QPDFObjectHandle::newDictionary();
47 result.replaceKey("/S", S); 57 result.replaceKey("/S", S);
48 result.replaceKey("/P", P); 58 result.replaceKey("/P", P);
49 result.replaceKey("/St", QPDFObjectHandle::newInteger(start)); 59 result.replaceKey("/St", QPDFObjectHandle::newInteger(start));
@@ -81,21 +91,20 @@ QPDFPageLabelDocumentHelper::getLabelsForPageRange( @@ -81,21 +91,20 @@ QPDFPageLabelDocumentHelper::getLabelsForPageRange(
81 label.getKey("/St").getIntValue() - last.getKey("/St").getIntValue(); 91 label.getKey("/St").getIntValue() - last.getKey("/St").getIntValue();
82 long long int idx_delta = new_start_idx - last_idx.getIntValue(); 92 long long int idx_delta = new_start_idx - last_idx.getIntValue();
83 if (st_delta == idx_delta) { 93 if (st_delta == idx_delta) {
84 - QTC::TC("qpdf", "QPDFPageLabelDocumentHelper skip first");  
85 skip_first = true; 94 skip_first = true;
86 } 95 }
87 } 96 }
88 } 97 }
89 if (!skip_first) { 98 if (!skip_first) {
90 - new_labels.push_back(QPDFObjectHandle::newInteger(new_start_idx));  
91 - new_labels.push_back(label); 99 + new_labels.emplace_back(QPDFObjectHandle::newInteger(new_start_idx));
  100 + new_labels.emplace_back(label);
92 } 101 }
93 102
94 long long int idx_offset = new_start_idx - start_idx; 103 long long int idx_offset = new_start_idx - start_idx;
95 for (long long i = start_idx + 1; i <= end_idx; ++i) { 104 for (long long i = start_idx + 1; i <= end_idx; ++i) {
96 if (m->labels->hasIndex(i) && (label = getLabelForPage(i)).isDictionary()) { 105 if (m->labels->hasIndex(i) && (label = getLabelForPage(i)).isDictionary()) {
97 - new_labels.push_back(QPDFObjectHandle::newInteger(i + idx_offset));  
98 - new_labels.push_back(label); 106 + new_labels.emplace_back(QPDFObjectHandle::newInteger(i + idx_offset));
  107 + new_labels.emplace_back(label);
99 } 108 }
100 } 109 }
101 } 110 }
libqpdf/qpdf/NNTree.hh
@@ -95,7 +95,12 @@ class NNTreeImpl @@ -95,7 +95,12 @@ class NNTreeImpl
95 public: 95 public:
96 typedef NNTreeIterator iterator; 96 typedef NNTreeIterator iterator;
97 97
98 - NNTreeImpl(NNTreeDetails const&, QPDF&, QPDFObjectHandle&, bool auto_repair = true); 98 + NNTreeImpl(
  99 + NNTreeDetails const&,
  100 + QPDF&,
  101 + QPDFObjectHandle&,
  102 + std::function<bool(QPDFObjectHandle const&)> value_validator,
  103 + bool auto_repair = true);
99 iterator begin(); 104 iterator begin();
100 iterator end(); 105 iterator end();
101 iterator last(); 106 iterator last();
@@ -104,6 +109,8 @@ class NNTreeImpl @@ -104,6 +109,8 @@ class NNTreeImpl
104 iterator insert(QPDFObjectHandle const& key, QPDFObjectHandle const& value); 109 iterator insert(QPDFObjectHandle const& key, QPDFObjectHandle const& value);
105 bool remove(QPDFObjectHandle const& key, QPDFObjectHandle* value = nullptr); 110 bool remove(QPDFObjectHandle const& key, QPDFObjectHandle* value = nullptr);
106 111
  112 + bool validate(bool repair = true);
  113 +
107 // Change the split threshold for easier testing. There's no real reason to expose this to 114 // Change the split threshold for easier testing. There's no real reason to expose this to
108 // downstream tree helpers, but it has to be public so we can call it from the test suite. 115 // downstream tree helpers, but it has to be public so we can call it from the test suite.
109 void setSplitThreshold(int split_threshold); 116 void setSplitThreshold(int split_threshold);
@@ -127,6 +134,7 @@ class NNTreeImpl @@ -127,6 +134,7 @@ class NNTreeImpl
127 QPDF& qpdf; 134 QPDF& qpdf;
128 int split_threshold{32}; 135 int split_threshold{32};
129 QPDFObjectHandle oh; 136 QPDFObjectHandle oh;
  137 + const std::function<bool(QPDFObjectHandle const&)> value_valid;
130 bool auto_repair{true}; 138 bool auto_repair{true};
131 size_t error_count{0}; 139 size_t error_count{0};
132 }; 140 };
manual/release-notes.rst
@@ -23,6 +23,16 @@ more detail. @@ -23,6 +23,16 @@ more detail.
23 not work on some older Linux distributions. If you need support 23 not work on some older Linux distributions. If you need support
24 for an older distribution, please use version 12.2.0 or below. 24 for an older distribution, please use version 12.2.0 or below.
25 25
  26 + - Library Enhancements
  27 +
  28 + - Add ``QPDFNameTreeObjectHelper`` and ``QPDFNumberTreeObjectHelper``
  29 + constructor overloads that allow a function to ne passed to
  30 + validate the values in the tree.
  31 +
  32 + - Add new ``QPDFNameTreeObjectHelper`` and ``QPDFNumberTreeObjectHelper``
  33 + ``validate`` method to validate and optionally repair the name/number
  34 + tree.
  35 +
26 - CLI Enhancements 36 - CLI Enhancements
27 37
28 - Disallow option :qpdf:ref:`--deterministic-id` to be used together 38 - Disallow option :qpdf:ref:`--deterministic-id` to be used together
qpdf/qpdf.testcov
@@ -338,13 +338,10 @@ QPDFAcroFormDocumentHelper annotation found 1 @@ -338,13 +338,10 @@ QPDFAcroFormDocumentHelper annotation found 1
338 QPDFJob keep files open n 0 338 QPDFJob keep files open n 0
339 QPDFJob keep files open y 0 339 QPDFJob keep files open y 0
340 QPDFJob automatically set keep files open 1 340 QPDFJob automatically set keep files open 1
341 -QPDFPageLabelDocumentHelper skip first 0  
342 QPDFOutlineObjectHelper direct dest 0 341 QPDFOutlineObjectHelper direct dest 0
343 QPDFOutlineObjectHelper action dest 0 342 QPDFOutlineObjectHelper action dest 0
344 QPDFOutlineObjectHelper named dest 0 343 QPDFOutlineObjectHelper named dest 0
345 -QPDFOutlineDocumentHelper name named dest 0  
346 QPDFOutlineDocumentHelper string named dest 0 344 QPDFOutlineDocumentHelper string named dest 0
347 -QPDFOutlineDocumentHelper named dest dictionary 0  
348 QPDFOutlineObjectHelper loop 0 345 QPDFOutlineObjectHelper loop 0
349 QPDFObjectHandle merge top type mismatch 0 346 QPDFObjectHandle merge top type mismatch 0
350 QPDFObjectHandle merge shallow copy 0 347 QPDFObjectHandle merge shallow copy 0
qpdf/qtest/page-labels.test
@@ -14,7 +14,7 @@ cleanup(); @@ -14,7 +14,7 @@ cleanup();
14 14
15 my $td = new TestDriver('page-labels'); 15 my $td = new TestDriver('page-labels');
16 16
17 -my $n_tests = 3; 17 +my $n_tests = 4;
18 18
19 $td->runtest("complex page labels", 19 $td->runtest("complex page labels",
20 {$td->COMMAND => "test_driver 47 page-labels-num-tree.pdf"}, 20 {$td->COMMAND => "test_driver 47 page-labels-num-tree.pdf"},
@@ -29,6 +29,15 @@ $td-&gt;runtest(&quot;no page labels&quot;, @@ -29,6 +29,15 @@ $td-&gt;runtest(&quot;no page labels&quot;,
29 {$td->FILE => "no-page-labels.out", $td->EXIT_STATUS => 0}, 29 {$td->FILE => "no-page-labels.out", $td->EXIT_STATUS => 0},
30 $td->NORMALIZE_NEWLINES); 30 $td->NORMALIZE_NEWLINES);
31 31
  32 +# page-labels-num-tree-damaged.pdf has the following errors:
  33 +# - entry for page 29 preceedes entry for page 20
  34 +# - entry for page 3 follows entry for page 6
  35 +# - entry for page 12 is an integer rather than a dictionary
  36 +$td->runtest("damaged page labels",
  37 + {$td->COMMAND => "test_driver 47 page-labels-num-tree-damaged.pdf"},
  38 + {$td->FILE => "page-labels-num-tree-damaged.out", $td->EXIT_STATUS => 0},
  39 + $td->NORMALIZE_NEWLINES);
  40 +
32 # --set-page-labels 41 # --set-page-labels
33 my @errors = ( 42 my @errors = (
34 ["quack", ".*page label spec must be.*"], 43 ["quack", ".*page label spec must be.*"],
qpdf/qtest/qpdf/page-labels-num-tree-damaged.out 0 โ†’ 100644
  1 +WARNING: page-labels-num-tree-damaged.pdf (Name/Number tree node (object 2)): attempting to repair after error: page-labels-num-tree-damaged.pdf (Name/Number tree node (object 2)): keys are not sorted in validate
  2 +WARNING: page-labels-num-tree-damaged.pdf (Name/Number tree node (object 37)): item 1 is invalid
  3 +1 << /S /r /St 1 >>
  4 +3 << /P (blank) /St 1 >>
  5 +4 << /P (X-) /S /A /St 17 >>
  6 +6 << /P () /St 1 >>
  7 +7 << /S /R /St 3 >>
  8 +10 << /S /D /St 1 >>
  9 +13 << /S /a /St 3 >>
  10 +16 << /P (q.) /S /D /St 6 >>
  11 +20 << /P (www) /St 1 >>
  12 +21 << /S /D /St 12 >>
  13 +23 << /S /D /St 16059 >>
  14 +24 << /S /R /St 50 >>
  15 +30 << /S /r /St 54 >>
  16 +test 47 done
qpdf/qtest/qpdf/page-labels-num-tree-damaged.pdf 0 โ†’ 100644
  1 +%PDF-1.3
  2 +%ยฟรทยขรพ
  3 +%QDF-1.0
  4 +
  5 +1 0 obj
  6 +<<
  7 + /PageLabels 2 0 R
  8 + /Pages 3 0 R
  9 + /Type /Catalog
  10 +>>
  11 +endobj
  12 +
  13 +2 0 obj
  14 +<<
  15 + /Kids [
  16 + 4 0 R
  17 + 5 0 R
  18 + ]
  19 +>>
  20 +endobj
  21 +
  22 +3 0 obj
  23 +<<
  24 + /Count 30
  25 + /Kids [
  26 + 6 0 R
  27 + 7 0 R
  28 + 8 0 R
  29 + 9 0 R
  30 + 10 0 R
  31 + 11 0 R
  32 + 12 0 R
  33 + 13 0 R
  34 + 14 0 R
  35 + 15 0 R
  36 + 16 0 R
  37 + 17 0 R
  38 + 18 0 R
  39 + 19 0 R
  40 + 20 0 R
  41 + 21 0 R
  42 + 22 0 R
  43 + 23 0 R
  44 + 24 0 R
  45 + 25 0 R
  46 + 26 0 R
  47 + 27 0 R
  48 + 28 0 R
  49 + 29 0 R
  50 + 30 0 R
  51 + 31 0 R
  52 + 32 0 R
  53 + 33 0 R
  54 + 34 0 R
  55 + 35 0 R
  56 + ]
  57 + /Type /Pages
  58 +>>
  59 +endobj
  60 +
  61 +4 0 obj
  62 +<<
  63 + /Kids [
  64 + 36 0 R
  65 + 37 0 R
  66 + ]
  67 + /Limits [
  68 + 0
  69 + 19
  70 + ]
  71 +>>
  72 +endobj
  73 +
  74 +5 0 obj
  75 +<<
  76 + /Limits [
  77 + 20
  78 + 29
  79 + ]
  80 + /Nums [
  81 + 29 << /S /r /St 54 >>
  82 + 20 << /S /D /St 12 >>
  83 + 22 << /S /D /St 16059 >>
  84 + 23 << /S /R /St 50 >>
  85 + ]
  86 +>>
  87 +endobj
  88 +
  89 +%% Page 1
  90 +6 0 obj
  91 +<<
  92 + /Contents 38 0 R
  93 + /MediaBox [
  94 + 0
  95 + 0
  96 + 612
  97 + 792
  98 + ]
  99 + /Parent 3 0 R
  100 + /Resources <<
  101 + /Font <<
  102 + /F1 40 0 R
  103 + >>
  104 + /ProcSet 41 0 R
  105 + >>
  106 + /Type /Page
  107 +>>
  108 +endobj
  109 +
  110 +%% Page 2
  111 +7 0 obj
  112 +<<
  113 + /Contents 42 0 R
  114 + /MediaBox [
  115 + 0
  116 + 0
  117 + 612
  118 + 792
  119 + ]
  120 + /Parent 3 0 R
  121 + /Resources <<
  122 + /Font <<
  123 + /F1 40 0 R
  124 + >>
  125 + /ProcSet 41 0 R
  126 + >>
  127 + /Type /Page
  128 +>>
  129 +endobj
  130 +
  131 +%% Page 3
  132 +8 0 obj
  133 +<<
  134 + /Contents 44 0 R
  135 + /MediaBox [
  136 + 0
  137 + 0
  138 + 612
  139 + 792
  140 + ]
  141 + /Parent 3 0 R
  142 + /Resources <<
  143 + /Font <<
  144 + /F1 40 0 R
  145 + >>
  146 + /ProcSet 41 0 R
  147 + >>
  148 + /Type /Page
  149 +>>
  150 +endobj
  151 +
  152 +%% Page 4
  153 +9 0 obj
  154 +<<
  155 + /Contents 46 0 R
  156 + /MediaBox [
  157 + 0
  158 + 0
  159 + 612
  160 + 792
  161 + ]
  162 + /Parent 3 0 R
  163 + /Resources <<
  164 + /Font <<
  165 + /F1 40 0 R
  166 + >>
  167 + /ProcSet 41 0 R
  168 + >>
  169 + /Type /Page
  170 +>>
  171 +endobj
  172 +
  173 +%% Page 5
  174 +10 0 obj
  175 +<<
  176 + /Contents 48 0 R
  177 + /MediaBox [
  178 + 0
  179 + 0
  180 + 612
  181 + 792
  182 + ]
  183 + /Parent 3 0 R
  184 + /Resources <<
  185 + /Font <<
  186 + /F1 40 0 R
  187 + >>
  188 + /ProcSet 41 0 R
  189 + >>
  190 + /Type /Page
  191 +>>
  192 +endobj
  193 +
  194 +%% Page 6
  195 +11 0 obj
  196 +<<
  197 + /Contents 50 0 R
  198 + /MediaBox [
  199 + 0
  200 + 0
  201 + 612
  202 + 792
  203 + ]
  204 + /Parent 3 0 R
  205 + /Resources <<
  206 + /Font <<
  207 + /F1 40 0 R
  208 + >>
  209 + /ProcSet 41 0 R
  210 + >>
  211 + /Type /Page
  212 +>>
  213 +endobj
  214 +
  215 +%% Page 7
  216 +12 0 obj
  217 +<<
  218 + /Contents 52 0 R
  219 + /MediaBox [
  220 + 0
  221 + 0
  222 + 612
  223 + 792
  224 + ]
  225 + /Parent 3 0 R
  226 + /Resources <<
  227 + /Font <<
  228 + /F1 40 0 R
  229 + >>
  230 + /ProcSet 41 0 R
  231 + >>
  232 + /Type /Page
  233 +>>
  234 +endobj
  235 +
  236 +%% Page 8
  237 +13 0 obj
  238 +<<
  239 + /Contents 54 0 R
  240 + /MediaBox [
  241 + 0
  242 + 0
  243 + 612
  244 + 792
  245 + ]
  246 + /Parent 3 0 R
  247 + /Resources <<
  248 + /Font <<
  249 + /F1 40 0 R
  250 + >>
  251 + /ProcSet 41 0 R
  252 + >>
  253 + /Type /Page
  254 +>>
  255 +endobj
  256 +
  257 +%% Page 9
  258 +14 0 obj
  259 +<<
  260 + /Contents 56 0 R
  261 + /MediaBox [
  262 + 0
  263 + 0
  264 + 612
  265 + 792
  266 + ]
  267 + /Parent 3 0 R
  268 + /Resources <<
  269 + /Font <<
  270 + /F1 40 0 R
  271 + >>
  272 + /ProcSet 41 0 R
  273 + >>
  274 + /Type /Page
  275 +>>
  276 +endobj
  277 +
  278 +%% Page 10
  279 +15 0 obj
  280 +<<
  281 + /Contents 58 0 R
  282 + /MediaBox [
  283 + 0
  284 + 0
  285 + 612
  286 + 792
  287 + ]
  288 + /Parent 3 0 R
  289 + /Resources <<
  290 + /Font <<
  291 + /F1 40 0 R
  292 + >>
  293 + /ProcSet 41 0 R
  294 + >>
  295 + /Type /Page
  296 +>>
  297 +endobj
  298 +
  299 +%% Page 11
  300 +16 0 obj
  301 +<<
  302 + /Contents 60 0 R
  303 + /MediaBox [
  304 + 0
  305 + 0
  306 + 612
  307 + 792
  308 + ]
  309 + /Parent 3 0 R
  310 + /Resources <<
  311 + /Font <<
  312 + /F1 40 0 R
  313 + >>
  314 + /ProcSet 41 0 R
  315 + >>
  316 + /Type /Page
  317 +>>
  318 +endobj
  319 +
  320 +%% Page 12
  321 +17 0 obj
  322 +<<
  323 + /Contents 62 0 R
  324 + /MediaBox [
  325 + 0
  326 + 0
  327 + 612
  328 + 792
  329 + ]
  330 + /Parent 3 0 R
  331 + /Resources <<
  332 + /Font <<
  333 + /F1 40 0 R
  334 + >>
  335 + /ProcSet 41 0 R
  336 + >>
  337 + /Type /Page
  338 +>>
  339 +endobj
  340 +
  341 +%% Page 13
  342 +18 0 obj
  343 +<<
  344 + /Contents 64 0 R
  345 + /MediaBox [
  346 + 0
  347 + 0
  348 + 612
  349 + 792
  350 + ]
  351 + /Parent 3 0 R
  352 + /Resources <<
  353 + /Font <<
  354 + /F1 40 0 R
  355 + >>
  356 + /ProcSet 41 0 R
  357 + >>
  358 + /Type /Page
  359 +>>
  360 +endobj
  361 +
  362 +%% Page 14
  363 +19 0 obj
  364 +<<
  365 + /Contents 66 0 R
  366 + /MediaBox [
  367 + 0
  368 + 0
  369 + 612
  370 + 792
  371 + ]
  372 + /Parent 3 0 R
  373 + /Resources <<
  374 + /Font <<
  375 + /F1 40 0 R
  376 + >>
  377 + /ProcSet 41 0 R
  378 + >>
  379 + /Type /Page
  380 +>>
  381 +endobj
  382 +
  383 +%% Page 15
  384 +20 0 obj
  385 +<<
  386 + /Contents 68 0 R
  387 + /MediaBox [
  388 + 0
  389 + 0
  390 + 612
  391 + 792
  392 + ]
  393 + /Parent 3 0 R
  394 + /Resources <<
  395 + /Font <<
  396 + /F1 40 0 R
  397 + >>
  398 + /ProcSet 41 0 R
  399 + >>
  400 + /Type /Page
  401 +>>
  402 +endobj
  403 +
  404 +%% Page 16
  405 +21 0 obj
  406 +<<
  407 + /Contents 70 0 R
  408 + /MediaBox [
  409 + 0
  410 + 0
  411 + 612
  412 + 792
  413 + ]
  414 + /Parent 3 0 R
  415 + /Resources <<
  416 + /Font <<
  417 + /F1 40 0 R
  418 + >>
  419 + /ProcSet 41 0 R
  420 + >>
  421 + /Type /Page
  422 +>>
  423 +endobj
  424 +
  425 +%% Page 17
  426 +22 0 obj
  427 +<<
  428 + /Contents 72 0 R
  429 + /MediaBox [
  430 + 0
  431 + 0
  432 + 612
  433 + 792
  434 + ]
  435 + /Parent 3 0 R
  436 + /Resources <<
  437 + /Font <<
  438 + /F1 40 0 R
  439 + >>
  440 + /ProcSet 41 0 R
  441 + >>
  442 + /Type /Page
  443 +>>
  444 +endobj
  445 +
  446 +%% Page 18
  447 +23 0 obj
  448 +<<
  449 + /Contents 74 0 R
  450 + /MediaBox [
  451 + 0
  452 + 0
  453 + 612
  454 + 792
  455 + ]
  456 + /Parent 3 0 R
  457 + /Resources <<
  458 + /Font <<
  459 + /F1 40 0 R
  460 + >>
  461 + /ProcSet 41 0 R
  462 + >>
  463 + /Type /Page
  464 +>>
  465 +endobj
  466 +
  467 +%% Page 19
  468 +24 0 obj
  469 +<<
  470 + /Contents 76 0 R
  471 + /MediaBox [
  472 + 0
  473 + 0
  474 + 612
  475 + 792
  476 + ]
  477 + /Parent 3 0 R
  478 + /Resources <<
  479 + /Font <<
  480 + /F1 40 0 R
  481 + >>
  482 + /ProcSet 41 0 R
  483 + >>
  484 + /Type /Page
  485 +>>
  486 +endobj
  487 +
  488 +%% Page 20
  489 +25 0 obj
  490 +<<
  491 + /Contents 78 0 R
  492 + /MediaBox [
  493 + 0
  494 + 0
  495 + 612
  496 + 792
  497 + ]
  498 + /Parent 3 0 R
  499 + /Resources <<
  500 + /Font <<
  501 + /F1 40 0 R
  502 + >>
  503 + /ProcSet 41 0 R
  504 + >>
  505 + /Type /Page
  506 +>>
  507 +endobj
  508 +
  509 +%% Page 21
  510 +26 0 obj
  511 +<<
  512 + /Contents 80 0 R
  513 + /MediaBox [
  514 + 0
  515 + 0
  516 + 612
  517 + 792
  518 + ]
  519 + /Parent 3 0 R
  520 + /Resources <<
  521 + /Font <<
  522 + /F1 40 0 R
  523 + >>
  524 + /ProcSet 41 0 R
  525 + >>
  526 + /Type /Page
  527 +>>
  528 +endobj
  529 +
  530 +%% Page 22
  531 +27 0 obj
  532 +<<
  533 + /Contents 82 0 R
  534 + /MediaBox [
  535 + 0
  536 + 0
  537 + 612
  538 + 792
  539 + ]
  540 + /Parent 3 0 R
  541 + /Resources <<
  542 + /Font <<
  543 + /F1 40 0 R
  544 + >>
  545 + /ProcSet 41 0 R
  546 + >>
  547 + /Type /Page
  548 +>>
  549 +endobj
  550 +
  551 +%% Page 23
  552 +28 0 obj
  553 +<<
  554 + /Contents 84 0 R
  555 + /MediaBox [
  556 + 0
  557 + 0
  558 + 612
  559 + 792
  560 + ]
  561 + /Parent 3 0 R
  562 + /Resources <<
  563 + /Font <<
  564 + /F1 40 0 R
  565 + >>
  566 + /ProcSet 41 0 R
  567 + >>
  568 + /Type /Page
  569 +>>
  570 +endobj
  571 +
  572 +%% Page 24
  573 +29 0 obj
  574 +<<
  575 + /Contents 86 0 R
  576 + /MediaBox [
  577 + 0
  578 + 0
  579 + 612
  580 + 792
  581 + ]
  582 + /Parent 3 0 R
  583 + /Resources <<
  584 + /Font <<
  585 + /F1 40 0 R
  586 + >>
  587 + /ProcSet 41 0 R
  588 + >>
  589 + /Type /Page
  590 +>>
  591 +endobj
  592 +
  593 +%% Page 25
  594 +30 0 obj
  595 +<<
  596 + /Contents 88 0 R
  597 + /MediaBox [
  598 + 0
  599 + 0
  600 + 612
  601 + 792
  602 + ]
  603 + /Parent 3 0 R
  604 + /Resources <<
  605 + /Font <<
  606 + /F1 40 0 R
  607 + >>
  608 + /ProcSet 41 0 R
  609 + >>
  610 + /Type /Page
  611 +>>
  612 +endobj
  613 +
  614 +%% Page 26
  615 +31 0 obj
  616 +<<
  617 + /Contents 90 0 R
  618 + /MediaBox [
  619 + 0
  620 + 0
  621 + 612
  622 + 792
  623 + ]
  624 + /Parent 3 0 R
  625 + /Resources <<
  626 + /Font <<
  627 + /F1 40 0 R
  628 + >>
  629 + /ProcSet 41 0 R
  630 + >>
  631 + /Type /Page
  632 +>>
  633 +endobj
  634 +
  635 +%% Page 27
  636 +32 0 obj
  637 +<<
  638 + /Contents 92 0 R
  639 + /MediaBox [
  640 + 0
  641 + 0
  642 + 612
  643 + 792
  644 + ]
  645 + /Parent 3 0 R
  646 + /Resources <<
  647 + /Font <<
  648 + /F1 40 0 R
  649 + >>
  650 + /ProcSet 41 0 R
  651 + >>
  652 + /Type /Page
  653 +>>
  654 +endobj
  655 +
  656 +%% Page 28
  657 +33 0 obj
  658 +<<
  659 + /Contents 94 0 R
  660 + /MediaBox [
  661 + 0
  662 + 0
  663 + 612
  664 + 792
  665 + ]
  666 + /Parent 3 0 R
  667 + /Resources <<
  668 + /Font <<
  669 + /F1 40 0 R
  670 + >>
  671 + /ProcSet 41 0 R
  672 + >>
  673 + /Type /Page
  674 +>>
  675 +endobj
  676 +
  677 +%% Page 29
  678 +34 0 obj
  679 +<<
  680 + /Contents 96 0 R
  681 + /MediaBox [
  682 + 0
  683 + 0
  684 + 612
  685 + 792
  686 + ]
  687 + /Parent 3 0 R
  688 + /Resources <<
  689 + /Font <<
  690 + /F1 40 0 R
  691 + >>
  692 + /ProcSet 41 0 R
  693 + >>
  694 + /Type /Page
  695 +>>
  696 +endobj
  697 +
  698 +%% Page 30
  699 +35 0 obj
  700 +<<
  701 + /Contents 98 0 R
  702 + /MediaBox [
  703 + 0
  704 + 0
  705 + 612
  706 + 792
  707 + ]
  708 + /Parent 3 0 R
  709 + /Resources <<
  710 + /Font <<
  711 + /F1 40 0 R
  712 + >>
  713 + /ProcSet 41 0 R
  714 + >>
  715 + /Type /Page
  716 +>>
  717 +endobj
  718 +
  719 +36 0 obj
  720 +<<
  721 + /Limits [
  722 + 0
  723 + 9
  724 + ]
  725 + /Nums [
  726 + 0 << /S /r >>
  727 + 2 << /P (blank) >>
  728 + 5 << /P () >>
  729 + 6 << /S /R /St 3 >>
  730 + 3 << /P (X-) /S /A /St 17 >>
  731 + 9 << /S /D >>
  732 + ]
  733 +>>
  734 +endobj
  735 +
  736 +37 0 obj
  737 +<<
  738 + /Limits [
  739 + 11
  740 + 19
  741 + ]
  742 + /Nums [
  743 + 11 42
  744 + 12 << /S /a /St 3 >>
  745 + 15 << /P (q.) /S /D /St 6 >>
  746 + 19 << /P (www) >>
  747 + ]
  748 +>>
  749 +endobj
  750 +
  751 +%% Contents for page 1
  752 +38 0 obj
  753 +<<
  754 + /Length 39 0 R
  755 +>>
  756 +stream
  757 +BT
  758 + /F1 24 Tf
  759 + 72 720 Td
  760 + (Potato 0) Tj
  761 +ET
  762 +endstream
  763 +endobj
  764 +
  765 +39 0 obj
  766 +46
  767 +endobj
  768 +
  769 +40 0 obj
  770 +<<
  771 + /BaseFont /Helvetica
  772 + /Encoding /WinAnsiEncoding
  773 + /Name /F1
  774 + /Subtype /Type1
  775 + /Type /Font
  776 +>>
  777 +endobj
  778 +
  779 +41 0 obj
  780 +[
  781 + /PDF
  782 + /Text
  783 +]
  784 +endobj
  785 +
  786 +%% Contents for page 2
  787 +42 0 obj
  788 +<<
  789 + /Length 43 0 R
  790 +>>
  791 +stream
  792 +BT
  793 + /F1 24 Tf
  794 + 72 720 Td
  795 + (Potato 1) Tj
  796 +ET
  797 +endstream
  798 +endobj
  799 +
  800 +43 0 obj
  801 +46
  802 +endobj
  803 +
  804 +%% Contents for page 3
  805 +44 0 obj
  806 +<<
  807 + /Length 45 0 R
  808 +>>
  809 +stream
  810 +BT
  811 + /F1 24 Tf
  812 + 72 720 Td
  813 + (Potato 2) Tj
  814 +ET
  815 +endstream
  816 +endobj
  817 +
  818 +45 0 obj
  819 +46
  820 +endobj
  821 +
  822 +%% Contents for page 4
  823 +46 0 obj
  824 +<<
  825 + /Length 47 0 R
  826 +>>
  827 +stream
  828 +BT
  829 + /F1 24 Tf
  830 + 72 720 Td
  831 + (Potato 3) Tj
  832 +ET
  833 +endstream
  834 +endobj
  835 +
  836 +47 0 obj
  837 +46
  838 +endobj
  839 +
  840 +%% Contents for page 5
  841 +48 0 obj
  842 +<<
  843 + /Length 49 0 R
  844 +>>
  845 +stream
  846 +BT
  847 + /F1 24 Tf
  848 + 72 720 Td
  849 + (Potato 4) Tj
  850 +ET
  851 +endstream
  852 +endobj
  853 +
  854 +49 0 obj
  855 +46
  856 +endobj
  857 +
  858 +%% Contents for page 6
  859 +50 0 obj
  860 +<<
  861 + /Length 51 0 R
  862 +>>
  863 +stream
  864 +BT
  865 + /F1 24 Tf
  866 + 72 720 Td
  867 + (Potato 5) Tj
  868 +ET
  869 +endstream
  870 +endobj
  871 +
  872 +51 0 obj
  873 +46
  874 +endobj
  875 +
  876 +%% Contents for page 7
  877 +52 0 obj
  878 +<<
  879 + /Length 53 0 R
  880 +>>
  881 +stream
  882 +BT
  883 + /F1 24 Tf
  884 + 72 720 Td
  885 + (Potato 6) Tj
  886 +ET
  887 +endstream
  888 +endobj
  889 +
  890 +53 0 obj
  891 +46
  892 +endobj
  893 +
  894 +%% Contents for page 8
  895 +54 0 obj
  896 +<<
  897 + /Length 55 0 R
  898 +>>
  899 +stream
  900 +BT
  901 + /F1 24 Tf
  902 + 72 720 Td
  903 + (Potato 7) Tj
  904 +ET
  905 +endstream
  906 +endobj
  907 +
  908 +55 0 obj
  909 +46
  910 +endobj
  911 +
  912 +%% Contents for page 9
  913 +56 0 obj
  914 +<<
  915 + /Length 57 0 R
  916 +>>
  917 +stream
  918 +BT
  919 + /F1 24 Tf
  920 + 72 720 Td
  921 + (Potato 8) Tj
  922 +ET
  923 +endstream
  924 +endobj
  925 +
  926 +57 0 obj
  927 +46
  928 +endobj
  929 +
  930 +%% Contents for page 10
  931 +58 0 obj
  932 +<<
  933 + /Length 59 0 R
  934 +>>
  935 +stream
  936 +BT
  937 + /F1 24 Tf
  938 + 72 720 Td
  939 + (Potato 9) Tj
  940 +ET
  941 +endstream
  942 +endobj
  943 +
  944 +59 0 obj
  945 +46
  946 +endobj
  947 +
  948 +%% Contents for page 11
  949 +60 0 obj
  950 +<<
  951 + /Length 61 0 R
  952 +>>
  953 +stream
  954 +BT
  955 + /F1 24 Tf
  956 + 72 720 Td
  957 + (Potato 10) Tj
  958 +ET
  959 +endstream
  960 +endobj
  961 +
  962 +61 0 obj
  963 +47
  964 +endobj
  965 +
  966 +%% Contents for page 12
  967 +62 0 obj
  968 +<<
  969 + /Length 63 0 R
  970 +>>
  971 +stream
  972 +BT
  973 + /F1 24 Tf
  974 + 72 720 Td
  975 + (Potato 11) Tj
  976 +ET
  977 +endstream
  978 +endobj
  979 +
  980 +63 0 obj
  981 +47
  982 +endobj
  983 +
  984 +%% Contents for page 13
  985 +64 0 obj
  986 +<<
  987 + /Length 65 0 R
  988 +>>
  989 +stream
  990 +BT
  991 + /F1 24 Tf
  992 + 72 720 Td
  993 + (Potato 12) Tj
  994 +ET
  995 +endstream
  996 +endobj
  997 +
  998 +65 0 obj
  999 +47
  1000 +endobj
  1001 +
  1002 +%% Contents for page 14
  1003 +66 0 obj
  1004 +<<
  1005 + /Length 67 0 R
  1006 +>>
  1007 +stream
  1008 +BT
  1009 + /F1 24 Tf
  1010 + 72 720 Td
  1011 + (Potato 13) Tj
  1012 +ET
  1013 +endstream
  1014 +endobj
  1015 +
  1016 +67 0 obj
  1017 +47
  1018 +endobj
  1019 +
  1020 +%% Contents for page 15
  1021 +68 0 obj
  1022 +<<
  1023 + /Length 69 0 R
  1024 +>>
  1025 +stream
  1026 +BT
  1027 + /F1 24 Tf
  1028 + 72 720 Td
  1029 + (Potato 14) Tj
  1030 +ET
  1031 +endstream
  1032 +endobj
  1033 +
  1034 +69 0 obj
  1035 +47
  1036 +endobj
  1037 +
  1038 +%% Contents for page 16
  1039 +70 0 obj
  1040 +<<
  1041 + /Length 71 0 R
  1042 +>>
  1043 +stream
  1044 +BT
  1045 + /F1 24 Tf
  1046 + 72 720 Td
  1047 + (Potato 15) Tj
  1048 +ET
  1049 +endstream
  1050 +endobj
  1051 +
  1052 +71 0 obj
  1053 +47
  1054 +endobj
  1055 +
  1056 +%% Contents for page 17
  1057 +72 0 obj
  1058 +<<
  1059 + /Length 73 0 R
  1060 +>>
  1061 +stream
  1062 +BT
  1063 + /F1 24 Tf
  1064 + 72 720 Td
  1065 + (Potato 16) Tj
  1066 +ET
  1067 +endstream
  1068 +endobj
  1069 +
  1070 +73 0 obj
  1071 +47
  1072 +endobj
  1073 +
  1074 +%% Contents for page 18
  1075 +74 0 obj
  1076 +<<
  1077 + /Length 75 0 R
  1078 +>>
  1079 +stream
  1080 +BT
  1081 + /F1 24 Tf
  1082 + 72 720 Td
  1083 + (Potato 17) Tj
  1084 +ET
  1085 +endstream
  1086 +endobj
  1087 +
  1088 +75 0 obj
  1089 +47
  1090 +endobj
  1091 +
  1092 +%% Contents for page 19
  1093 +76 0 obj
  1094 +<<
  1095 + /Length 77 0 R
  1096 +>>
  1097 +stream
  1098 +BT
  1099 + /F1 24 Tf
  1100 + 72 720 Td
  1101 + (Potato 18) Tj
  1102 +ET
  1103 +endstream
  1104 +endobj
  1105 +
  1106 +77 0 obj
  1107 +47
  1108 +endobj
  1109 +
  1110 +%% Contents for page 20
  1111 +78 0 obj
  1112 +<<
  1113 + /Length 79 0 R
  1114 +>>
  1115 +stream
  1116 +BT
  1117 + /F1 24 Tf
  1118 + 72 720 Td
  1119 + (Potato 19) Tj
  1120 +ET
  1121 +endstream
  1122 +endobj
  1123 +
  1124 +79 0 obj
  1125 +47
  1126 +endobj
  1127 +
  1128 +%% Contents for page 21
  1129 +80 0 obj
  1130 +<<
  1131 + /Length 81 0 R
  1132 +>>
  1133 +stream
  1134 +BT
  1135 + /F1 24 Tf
  1136 + 72 720 Td
  1137 + (Potato 20) Tj
  1138 +ET
  1139 +endstream
  1140 +endobj
  1141 +
  1142 +81 0 obj
  1143 +47
  1144 +endobj
  1145 +
  1146 +%% Contents for page 22
  1147 +82 0 obj
  1148 +<<
  1149 + /Length 83 0 R
  1150 +>>
  1151 +stream
  1152 +BT
  1153 + /F1 24 Tf
  1154 + 72 720 Td
  1155 + (Potato 21) Tj
  1156 +ET
  1157 +endstream
  1158 +endobj
  1159 +
  1160 +83 0 obj
  1161 +47
  1162 +endobj
  1163 +
  1164 +%% Contents for page 23
  1165 +84 0 obj
  1166 +<<
  1167 + /Length 85 0 R
  1168 +>>
  1169 +stream
  1170 +BT
  1171 + /F1 24 Tf
  1172 + 72 720 Td
  1173 + (Potato 22) Tj
  1174 +ET
  1175 +endstream
  1176 +endobj
  1177 +
  1178 +85 0 obj
  1179 +47
  1180 +endobj
  1181 +
  1182 +%% Contents for page 24
  1183 +86 0 obj
  1184 +<<
  1185 + /Length 87 0 R
  1186 +>>
  1187 +stream
  1188 +BT
  1189 + /F1 24 Tf
  1190 + 72 720 Td
  1191 + (Potato 23) Tj
  1192 +ET
  1193 +endstream
  1194 +endobj
  1195 +
  1196 +87 0 obj
  1197 +47
  1198 +endobj
  1199 +
  1200 +%% Contents for page 25
  1201 +88 0 obj
  1202 +<<
  1203 + /Length 89 0 R
  1204 +>>
  1205 +stream
  1206 +BT
  1207 + /F1 24 Tf
  1208 + 72 720 Td
  1209 + (Potato 24) Tj
  1210 +ET
  1211 +endstream
  1212 +endobj
  1213 +
  1214 +89 0 obj
  1215 +47
  1216 +endobj
  1217 +
  1218 +%% Contents for page 26
  1219 +90 0 obj
  1220 +<<
  1221 + /Length 91 0 R
  1222 +>>
  1223 +stream
  1224 +BT
  1225 + /F1 24 Tf
  1226 + 72 720 Td
  1227 + (Potato 25) Tj
  1228 +ET
  1229 +endstream
  1230 +endobj
  1231 +
  1232 +91 0 obj
  1233 +47
  1234 +endobj
  1235 +
  1236 +%% Contents for page 27
  1237 +92 0 obj
  1238 +<<
  1239 + /Length 93 0 R
  1240 +>>
  1241 +stream
  1242 +BT
  1243 + /F1 24 Tf
  1244 + 72 720 Td
  1245 + (Potato 26) Tj
  1246 +ET
  1247 +endstream
  1248 +endobj
  1249 +
  1250 +93 0 obj
  1251 +47
  1252 +endobj
  1253 +
  1254 +%% Contents for page 28
  1255 +94 0 obj
  1256 +<<
  1257 + /Length 95 0 R
  1258 +>>
  1259 +stream
  1260 +BT
  1261 + /F1 24 Tf
  1262 + 72 720 Td
  1263 + (Potato 27) Tj
  1264 +ET
  1265 +endstream
  1266 +endobj
  1267 +
  1268 +95 0 obj
  1269 +47
  1270 +endobj
  1271 +
  1272 +%% Contents for page 29
  1273 +96 0 obj
  1274 +<<
  1275 + /Length 97 0 R
  1276 +>>
  1277 +stream
  1278 +BT
  1279 + /F1 24 Tf
  1280 + 72 720 Td
  1281 + (Potato 28) Tj
  1282 +ET
  1283 +endstream
  1284 +endobj
  1285 +
  1286 +97 0 obj
  1287 +47
  1288 +endobj
  1289 +
  1290 +%% Contents for page 30
  1291 +98 0 obj
  1292 +<<
  1293 + /Length 99 0 R
  1294 +>>
  1295 +stream
  1296 +BT
  1297 + /F1 24 Tf
  1298 + 72 720 Td
  1299 + (Potato 29) Tj
  1300 +ET
  1301 +endstream
  1302 +endobj
  1303 +
  1304 +99 0 obj
  1305 +47
  1306 +endobj
  1307 +
  1308 +xref
  1309 +0 100
  1310 +0000000000 65535 f
  1311 +0000000025 00000 n
  1312 +0000000099 00000 n
  1313 +0000000155 00000 n
  1314 +0000000544 00000 n
  1315 +0000000631 00000 n
  1316 +0000000814 00000 n
  1317 +0000001019 00000 n
  1318 +0000001224 00000 n
  1319 +0000001429 00000 n
  1320 +0000001634 00000 n
  1321 +0000001840 00000 n
  1322 +0000002046 00000 n
  1323 +0000002252 00000 n
  1324 +0000002458 00000 n
  1325 +0000002665 00000 n
  1326 +0000002872 00000 n
  1327 +0000003079 00000 n
  1328 +0000003286 00000 n
  1329 +0000003493 00000 n
  1330 +0000003700 00000 n
  1331 +0000003907 00000 n
  1332 +0000004114 00000 n
  1333 +0000004321 00000 n
  1334 +0000004528 00000 n
  1335 +0000004735 00000 n
  1336 +0000004942 00000 n
  1337 +0000005149 00000 n
  1338 +0000005356 00000 n
  1339 +0000005563 00000 n
  1340 +0000005770 00000 n
  1341 +0000005977 00000 n
  1342 +0000006184 00000 n
  1343 +0000006391 00000 n
  1344 +0000006598 00000 n
  1345 +0000006805 00000 n
  1346 +0000007001 00000 n
  1347 +0000007200 00000 n
  1348 +0000007389 00000 n
  1349 +0000007492 00000 n
  1350 +0000007512 00000 n
  1351 +0000007631 00000 n
  1352 +0000007690 00000 n
  1353 +0000007793 00000 n
  1354 +0000007836 00000 n
  1355 +0000007939 00000 n
  1356 +0000007982 00000 n
  1357 +0000008085 00000 n
  1358 +0000008128 00000 n
  1359 +0000008231 00000 n
  1360 +0000008274 00000 n
  1361 +0000008377 00000 n
  1362 +0000008420 00000 n
  1363 +0000008523 00000 n
  1364 +0000008566 00000 n
  1365 +0000008669 00000 n
  1366 +0000008712 00000 n
  1367 +0000008815 00000 n
  1368 +0000008859 00000 n
  1369 +0000008962 00000 n
  1370 +0000009006 00000 n
  1371 +0000009110 00000 n
  1372 +0000009154 00000 n
  1373 +0000009258 00000 n
  1374 +0000009302 00000 n
  1375 +0000009406 00000 n
  1376 +0000009450 00000 n
  1377 +0000009554 00000 n
  1378 +0000009598 00000 n
  1379 +0000009702 00000 n
  1380 +0000009746 00000 n
  1381 +0000009850 00000 n
  1382 +0000009894 00000 n
  1383 +0000009998 00000 n
  1384 +0000010042 00000 n
  1385 +0000010146 00000 n
  1386 +0000010190 00000 n
  1387 +0000010294 00000 n
  1388 +0000010338 00000 n
  1389 +0000010442 00000 n
  1390 +0000010486 00000 n
  1391 +0000010590 00000 n
  1392 +0000010634 00000 n
  1393 +0000010738 00000 n
  1394 +0000010782 00000 n
  1395 +0000010886 00000 n
  1396 +0000010930 00000 n
  1397 +0000011034 00000 n
  1398 +0000011078 00000 n
  1399 +0000011182 00000 n
  1400 +0000011226 00000 n
  1401 +0000011330 00000 n
  1402 +0000011374 00000 n
  1403 +0000011478 00000 n
  1404 +0000011522 00000 n
  1405 +0000011626 00000 n
  1406 +0000011670 00000 n
  1407 +0000011774 00000 n
  1408 +0000011818 00000 n
  1409 +0000011922 00000 n
  1410 +trailer <<
  1411 + /Root 1 0 R
  1412 + /Size 100
  1413 + /ID [<90f919de7874f3bc5cb7afbd1e9537bb><0dfe18a94cde0f4bfdc86c03af19010e>]
  1414 +>>
  1415 +startxref
  1416 +11942
  1417 +%%EOF