pdf_paradise 0.3.20

Sign up to get free protection for your applications and to get access to all the features.
Files changed (130) hide show
  1. checksums.yaml +7 -0
  2. data/README.md +933 -0
  3. data/bin/automatic_pdf_title +7 -0
  4. data/bin/burst_this_pdf_file +7 -0
  5. data/bin/combine_these_pdf_pages +7 -0
  6. data/bin/compress_via_hexapdf +7 -0
  7. data/bin/convert_markdown_to_pdf +7 -0
  8. data/bin/convert_pdf_to_text +7 -0
  9. data/bin/delete_first_page_of_this_pdf_file +7 -0
  10. data/bin/djvu_to_pdf +7 -0
  11. data/bin/merge_then_open +7 -0
  12. data/bin/n_pages +10 -0
  13. data/bin/open_main_pdf +7 -0
  14. data/bin/pdf_paradise +9 -0
  15. data/bin/rotate_pdf +7 -0
  16. data/bin/set_main_book +7 -0
  17. data/bin/set_title_of_this_pdf_file +15 -0
  18. data/doc/README.gen +871 -0
  19. data/doc/todo/todo.md +13 -0
  20. data/images/Logo_for_the_pdf_paradise_project.avif +0 -0
  21. data/lib/pdf_paradise/base/base.rb +344 -0
  22. data/lib/pdf_paradise/base/colours.rb +67 -0
  23. data/lib/pdf_paradise/colours/colours.rb +27 -0
  24. data/lib/pdf_paradise/commandline/commandline.rb +109 -0
  25. data/lib/pdf_paradise/commandline/help.rb +77 -0
  26. data/lib/pdf_paradise/commandline/menu.rb +173 -0
  27. data/lib/pdf_paradise/compress/compress_this_pdf_file.rb +108 -0
  28. data/lib/pdf_paradise/compress/compress_via_hexapdf.rb +27 -0
  29. data/lib/pdf_paradise/compress/compress_via_qpdf.rb +32 -0
  30. data/lib/pdf_paradise/constants/constants.rb +76 -0
  31. data/lib/pdf_paradise/convert_text_to_pdf.rb +94 -0
  32. data/lib/pdf_paradise/css/project.css +17 -0
  33. data/lib/pdf_paradise/fpdf/README.md +2 -0
  34. data/lib/pdf_paradise/fpdf/bookmark.rb +129 -0
  35. data/lib/pdf_paradise/fpdf/chinese.rb +454 -0
  36. data/lib/pdf_paradise/fpdf/fpdf.rb +1902 -0
  37. data/lib/pdf_paradise/fpdf/fpdf_eps.rb +138 -0
  38. data/lib/pdf_paradise/fpdf/makefont.rb +1794 -0
  39. data/lib/pdf_paradise/gui/README.md +6 -0
  40. data/lib/pdf_paradise/gui/fox/split_pdf_file.rb +77 -0
  41. data/lib/pdf_paradise/gui/gtk2/pdf_viewer/pdf_viewer.rb +34 -0
  42. data/lib/pdf_paradise/gui/gtk2/split_pdf_file/split_pdf_file.rb +34 -0
  43. data/lib/pdf_paradise/gui/gtk2/statistics_widget/statistics_widget.rb +34 -0
  44. data/lib/pdf_paradise/gui/gtk3/controller/controller.rb +214 -0
  45. data/lib/pdf_paradise/gui/gtk3/pdf_viewer/pdf_viewer.rb +34 -0
  46. data/lib/pdf_paradise/gui/gtk3/split_pdf_file/split_pdf_file.rb +34 -0
  47. data/lib/pdf_paradise/gui/jruby/delete_the_first_or_the_last_page_of_this_pdf_file/delete_the_first_or_the_last_page_of_this_pdf_file.rb +167 -0
  48. data/lib/pdf_paradise/gui/jruby/remove_the_first_page_of_this_pdf_file/remove_the_first_page_of_this_pdf_file.rb +103 -0
  49. data/lib/pdf_paradise/gui/libui/extract_all_images_from_this_pdf_file/extract_all_images_from_this_pdf_file.rb +223 -0
  50. data/lib/pdf_paradise/gui/libui/remove_the_first_page_of_this_pdf_file/remove_the_first_page_of_this_pdf_file.rb +267 -0
  51. data/lib/pdf_paradise/gui/libui/rotate_pdf_file/rotate_pdf_file.rb +219 -0
  52. data/lib/pdf_paradise/gui/libui/statistics_widget/statistics_widget.rb +233 -0
  53. data/lib/pdf_paradise/gui/shared_code/pdf_viewer/pdf_viewer.css +5 -0
  54. data/lib/pdf_paradise/gui/shared_code/pdf_viewer/pdf_viewer_module.rb +287 -0
  55. data/lib/pdf_paradise/gui/shared_code/remove_the_first_page_of_this_pdf_file_module/remove_the_first_page_of_this_pdf_file_module.rb +31 -0
  56. data/lib/pdf_paradise/gui/shared_code/split_pdf_file/split_pdf_file_module.rb +295 -0
  57. data/lib/pdf_paradise/gui/universal_widgets/convert_pdf_to_text/convert_pdf_to_text.rb +366 -0
  58. data/lib/pdf_paradise/gui/universal_widgets/delete_the_first_or_the_last_page_of_this_pdf_file/delete_the_first_or_the_last_page_of_this_pdf_file.rb +776 -0
  59. data/lib/pdf_paradise/gui/universal_widgets/statistics_widget/statistics_widget.rb +407 -0
  60. data/lib/pdf_paradise/gui/universal_widgets/to_pdf/to_pdf.rb +351 -0
  61. data/lib/pdf_paradise/hexapdf/001_rainbow_pattern_example.rb +0 -0
  62. data/lib/pdf_paradise/hexapdf/hexapdf.rb +123 -0
  63. data/lib/pdf_paradise/images/PDF_PARADISE_LOGO.png +0 -0
  64. data/lib/pdf_paradise/main_pdf/main_pdf.rb +474 -0
  65. data/lib/pdf_paradise/merge_pdf/menu.rb +63 -0
  66. data/lib/pdf_paradise/merge_pdf/merge_pdf.rb +307 -0
  67. data/lib/pdf_paradise/merge_pdf_namespace.rb +9 -0
  68. data/lib/pdf_paradise/merge_then_open/merge_then_open.rb +105 -0
  69. data/lib/pdf_paradise/prawn_addons/README.md +2 -0
  70. data/lib/pdf_paradise/prawn_addons/prawn_addons.rb +17 -0
  71. data/lib/pdf_paradise/project/project.rb +22 -0
  72. data/lib/pdf_paradise/remove_pdf_password.rb +391 -0
  73. data/lib/pdf_paradise/requires/batch_require_toplevel_files.rb +22 -0
  74. data/lib/pdf_paradise/requires/colours.rb +11 -0
  75. data/lib/pdf_paradise/requires/colours_and_esystem_and_save_file_and_fileutils_and_opn.rb +13 -0
  76. data/lib/pdf_paradise/requires/esystem_and_colours.rb +11 -0
  77. data/lib/pdf_paradise/requires/esystem_and_opn_and_colours.rb +10 -0
  78. data/lib/pdf_paradise/requires/require_the_whole_project.rb +30 -0
  79. data/lib/pdf_paradise/requires/require_utility_scripts.rb +9 -0
  80. data/lib/pdf_paradise/set_main_book.rb +156 -0
  81. data/lib/pdf_paradise/set_pdf_title.rb +220 -0
  82. data/lib/pdf_paradise/sinatra/embeddable_interface.rb +389 -0
  83. data/lib/pdf_paradise/toplevel_methods/convert_epub_to_pdf.rb +27 -0
  84. data/lib/pdf_paradise/toplevel_methods/convert_markdown_to_pdf.rb +45 -0
  85. data/lib/pdf_paradise/toplevel_methods/convert_ppt_to_pdf.rb +35 -0
  86. data/lib/pdf_paradise/toplevel_methods/e.rb +16 -0
  87. data/lib/pdf_paradise/toplevel_methods/esystem.rb +20 -0
  88. data/lib/pdf_paradise/toplevel_methods/misc.rb +228 -0
  89. data/lib/pdf_paradise/toplevel_methods/number_pages.rb +38 -0
  90. data/lib/pdf_paradise/toplevel_methods/opened_pdf_files.rb +221 -0
  91. data/lib/pdf_paradise/toplevel_methods/query_pdf_title.rb +201 -0
  92. data/lib/pdf_paradise/toplevel_methods/reduce_size_of_this_pdf_file.rb +46 -0
  93. data/lib/pdf_paradise/toplevel_methods/roebe.rb +17 -0
  94. data/lib/pdf_paradise/toplevel_methods/to_pdf.rb +12 -0
  95. data/lib/pdf_paradise/utility_scripts/README.md +3 -0
  96. data/lib/pdf_paradise/utility_scripts/automatic_pdf_title.rb +104 -0
  97. data/lib/pdf_paradise/utility_scripts/check_syntax_of_pdf_files.rb +106 -0
  98. data/lib/pdf_paradise/utility_scripts/combine_these_pdf_pages.rb +118 -0
  99. data/lib/pdf_paradise/utility_scripts/convert_pdf_to_text.rb +179 -0
  100. data/lib/pdf_paradise/utility_scripts/delete_last_page_of_this_pdf_file.rb +180 -0
  101. data/lib/pdf_paradise/utility_scripts/delete_the_first_page_of_this_pdf_file/delete_the_first_page_of_this_pdf_file.rb +429 -0
  102. data/lib/pdf_paradise/utility_scripts/delete_this_page_of_this_pdf_file.rb +356 -0
  103. data/lib/pdf_paradise/utility_scripts/djvu_to_pdf.rb +87 -0
  104. data/lib/pdf_paradise/utility_scripts/extract_all_images_from_this_pdf_file.rb +129 -0
  105. data/lib/pdf_paradise/utility_scripts/extract_pdf_page.rb +283 -0
  106. data/lib/pdf_paradise/utility_scripts/pdf_file_n_total_pages.rb +348 -0
  107. data/lib/pdf_paradise/utility_scripts/pdf_optimizer.rb +111 -0
  108. data/lib/pdf_paradise/utility_scripts/pdf_statistics.rb +148 -0
  109. data/lib/pdf_paradise/utility_scripts/pdf_to_html.rb +75 -0
  110. data/lib/pdf_paradise/utility_scripts/remove_images.rb +110 -0
  111. data/lib/pdf_paradise/utility_scripts/rotate_pdf_file.rb +303 -0
  112. data/lib/pdf_paradise/utility_scripts/split_pdf.rb +364 -0
  113. data/lib/pdf_paradise/utility_scripts/to_pdf.rb +130 -0
  114. data/lib/pdf_paradise/utility_scripts/to_qdf.rb +66 -0
  115. data/lib/pdf_paradise/version/version.rb +19 -0
  116. data/lib/pdf_paradise/www/README.md +2 -0
  117. data/lib/pdf_paradise/www/sinatra/app.rb +304 -0
  118. data/lib/pdf_paradise/yaml/working_on_these_pdf_files.yml +4 -0
  119. data/lib/pdf_paradise.rb +5 -0
  120. data/pdf_paradise.gemspec +61 -0
  121. data/test/fpdf/001_minimal_example.rb +12 -0
  122. data/test/fpdf/002.pdf +0 -0
  123. data/test/fpdf/002_header_and_footer_example.rb +64 -0
  124. data/test/fpdf/003.pdf +98 -0
  125. data/test/fpdf/003_justified_paragraphs.rb +96 -0
  126. data/test/fpdf/file1.md +3 -0
  127. data/test/fpdf/file2.md +3 -0
  128. data/test/fpdf/test.pdf +0 -0
  129. data/test/testing_pdf_paradise.rb +12 -0
  130. metadata +239 -0
@@ -0,0 +1,179 @@
1
+ #!/usr/bin/ruby -w
2
+ # Encoding: UTF-8
3
+ # frozen_string_literal: true
4
+ # =========================================================================== #
5
+ # === PdfParadise::ConvertPdfToText
6
+ #
7
+ # This file can convert one or several .pdf files to text files.
8
+ #
9
+ # Usage examples:
10
+ #
11
+ # PdfParadise::ConvertPdfToText.new(ARGV)
12
+ #
13
+ # =========================================================================== #
14
+ # require 'pdf_paradise/utility_scripts/convert_pdf_to_text.rb'
15
+ # PdfParadise::ConvertPdfToText.new(ARGV)
16
+ # =========================================================================== #
17
+ require 'pdf_paradise/base/base.rb'
18
+
19
+ module PdfParadise
20
+
21
+ class ConvertPdfToText < ::PdfParadise::Base # === PdfParadise::ConvertPdfToText
22
+
23
+ # ========================================================================= #
24
+ # === NAMESPACE
25
+ # ========================================================================= #
26
+ NAMESPACE = inspect
27
+
28
+ # ========================================================================= #
29
+ # === initialize
30
+ # ========================================================================= #
31
+ def initialize(
32
+ i = ARGV,
33
+ run_already = true
34
+ )
35
+ reset
36
+ # ======================================================================= #
37
+ # Next designate which files are to be converted.
38
+ # ======================================================================= #
39
+ set_convert_these(i)
40
+ run if run_already
41
+ end
42
+
43
+ # ========================================================================= #
44
+ # === reset
45
+ # ========================================================================= #
46
+ def reset
47
+ super()
48
+ end
49
+
50
+ # ========================================================================= #
51
+ # === get_all_pdf_files_from_current_directory
52
+ #
53
+ # This method will obtain all pdf files from the current directory.
54
+ # ========================================================================= #
55
+ def get_all_pdf_files_from_current_directory
56
+ return Dir['*.pdf']
57
+ end
58
+
59
+ # ========================================================================= #
60
+ # === set_convert_these
61
+ #
62
+ # This method will preferentially try to work on only .pdf files.
63
+ # ========================================================================= #
64
+ def set_convert_these(
65
+ i = return_pwd
66
+ )
67
+ i = return_pwd if i.nil?
68
+ if i.is_a? String
69
+ if i.empty?
70
+ i = get_all_pdf_files_from_current_directory()
71
+ elsif File.directory? i
72
+ i = get_all_pdf_files_from_current_directory()
73
+ end
74
+ elsif i.is_a? Array
75
+ i = get_all_pdf_files_from_current_directory() if i.empty?
76
+ end
77
+ i = [i] unless i.is_a? Array
78
+ @convert_these = i # This must be an Array.
79
+ end
80
+
81
+ # ========================================================================= #
82
+ # === start_conversion
83
+ # ========================================================================= #
84
+ def start_conversion
85
+ @convert_these.each {|pdf| convert_this_pdf(pdf) }
86
+ end
87
+
88
+ # ========================================================================= #
89
+ # === opnn
90
+ # ========================================================================= #
91
+ def opnn
92
+ super(NAMESPACE)
93
+ end
94
+
95
+ # ========================================================================= #
96
+ # === convert_this_pdf
97
+ #
98
+ # This will make use of the binary called "pdftotext".
99
+ # ========================================================================= #
100
+ def convert_this_pdf(
101
+ i = @convert_these
102
+ )
103
+ if i.is_a? Array
104
+ i.each {|entry| convert_this_pdf(entry) }
105
+ else
106
+ if File.exist? i
107
+ opnn; e "Now converting `#{sfile(i)}#{rev}` via #{simp('pdftotext')}#{rev}."
108
+ # =================================================================== #
109
+ # Delegate towards pdftotext next; since as of January 2024 we will
110
+ # use -enc UTF-8 by default.
111
+ # =================================================================== #
112
+ cmdline_to_use = 'pdftotext -enc UTF-8 "'+i+'"' # We use "".
113
+ @output_file = i.gsub(/#{File.extname(i)}/, '')+'.txt'
114
+ system(cmdline_to_use)
115
+ opnn; e "Storing into the file `#{sfile(@output_file)}`."
116
+ else
117
+ unless i.start_with? '--'
118
+ opnn; e 'No file called '+sfile(i)+' could be found.'
119
+ end
120
+ end
121
+ end
122
+ end; alias do_convert convert_this_pdf # === do_convert
123
+
124
+ # ========================================================================= #
125
+ # === output_file?
126
+ # ========================================================================= #
127
+ def output_file?
128
+ @output_file
129
+ end
130
+
131
+ # ========================================================================= #
132
+ # === menu (menu tag)
133
+ # ========================================================================= #
134
+ def menu(
135
+ i = @convert_these
136
+ )
137
+ if i.is_a? Array
138
+ i.each {|entry| menu(entry) }
139
+ else
140
+ case i
141
+ # ===================================================================== #
142
+ # === cpdf --gui
143
+ # ===================================================================== #
144
+ when /^-?-?gui/i
145
+ do_start_the_GUI_interface
146
+ end
147
+ end
148
+ end
149
+
150
+ # ========================================================================= #
151
+ # === do_start_the_GUI_interface
152
+ # ========================================================================= #
153
+ def do_start_the_GUI_interface
154
+ require 'pdf_paradise/gui/gtk3/convert_pdf_to_text/convert_pdf_to_text.rb'
155
+ ::PdfParadise::GUI::Gtk::ConvertPdfToText.run
156
+ end
157
+
158
+ # ========================================================================= #
159
+ # === run (run tag)
160
+ # ========================================================================= #
161
+ def run
162
+ menu
163
+ start_conversion
164
+ end
165
+
166
+ end
167
+
168
+ # =========================================================================== #
169
+ # === PdfParadise.pdf_to_text
170
+ # =========================================================================== #
171
+ def self.pdf_to_text(i = ARGV)
172
+ PdfParadise::ConvertPdfToText.new(i)
173
+ end
174
+
175
+ end
176
+
177
+ if __FILE__ == $PROGRAM_NAME
178
+ PdfParadise::ConvertPdfToText.new(ARGV)
179
+ end # cpdf foobar.pdf
@@ -0,0 +1,180 @@
1
+ #!/usr/bin/ruby -w
2
+ # Encoding: UTF-8
3
+ # frozen_string_literal: true
4
+ # =========================================================================== #
5
+ # === PdfParadise::DeleteLastPageOfThisPdfFile
6
+ #
7
+ # This class will accept one (or several) .pdf files and then proceed
8
+ # to remove the very last .pdf page in that file. So if that pdf-file
9
+ # has had 100 pages, we will end up with 99 pages.
10
+ #
11
+ # By default, the class here will create a new output file and leave
12
+ # the original file untouched.
13
+ #
14
+ # Note that this functionality depends on either "qpdf" or "pdftk".
15
+ # =========================================================================== #
16
+ # require 'pdf_paradise/utility_scripts/delete_last_page_of_this_pdf_file.rb'
17
+ # =========================================================================== #
18
+ require 'pdf_paradise/base/base.rb'
19
+
20
+ module PdfParadise
21
+
22
+ class DeleteLastPageOfThisPdfFile < Base
23
+
24
+ require 'pdf_paradise/utility_scripts/pdf_file_n_total_pages.rb'
25
+
26
+ # ========================================================================= #
27
+ # === OVERWRITE_THE_OLD_PDF_FILE
28
+ #
29
+ # If the following constant is set to true then the given input
30
+ # file will be overwritten.
31
+ # ========================================================================= #
32
+ OVERWRITE_THE_OLD_PDF_FILE = true
33
+
34
+ # ========================================================================= #
35
+ # === initialize
36
+ # ========================================================================= #
37
+ def initialize(
38
+ input_files = ARGV,
39
+ run_already = true
40
+ )
41
+ reset
42
+ set_input_files(input_files)
43
+ run if run_already
44
+ end
45
+
46
+ # ========================================================================= #
47
+ # === reset
48
+ # ========================================================================= #
49
+ def reset
50
+ super()
51
+ infer_the_namespace
52
+ # ======================================================================= #
53
+ # === @overwrite_the_old_pdf_file
54
+ # ======================================================================= #
55
+ @overwrite_the_old_pdf_file = OVERWRITE_THE_OLD_PDF_FILE
56
+ end
57
+
58
+ # ========================================================================= #
59
+ # === set_input_files
60
+ # ========================================================================= #
61
+ def set_input_files(i)
62
+ i = [i] unless i.is_a? Array
63
+ if i.empty? and is_on_roebe?
64
+ # ===================================================================== #
65
+ # In this case we will use the main-pdf file, if it exists.
66
+ # ===================================================================== #
67
+ if ENV.has_key?('MAIN_BOOK') and
68
+ File.exist?(ENV['MAIN_BOOK'])
69
+ i << ENV['MAIN_BOOK'].dup
70
+ end
71
+ end
72
+ @input_files = i
73
+ sanitize_input_files
74
+ end
75
+
76
+ # ========================================================================= #
77
+ # === sanitize_input_files
78
+ # ========================================================================= #
79
+ def sanitize_input_files
80
+ unless @input_files.empty?
81
+ # ===================================================================== #
82
+ # Select only .pdf files next.
83
+ # ===================================================================== #
84
+ @input_files.select! {|entry|
85
+ entry.end_with? '.pdf'
86
+ }
87
+ end
88
+ end
89
+
90
+ # ========================================================================= #
91
+ # === process_each_pdf
92
+ # ========================================================================= #
93
+ def process_each_pdf
94
+ @input_files.each {|this_pdf_file|
95
+ # ===================================================================== #
96
+ # First, we must find out how many pdf pages are in the given
97
+ # pdf file at hand.
98
+ # ===================================================================== #
99
+ if File.exist? this_pdf_file
100
+ has_n_pages = ::PdfParadise.has_n_pages?(this_pdf_file)
101
+ opne 'Now working on the .pdf file '+sfancy(this_pdf_file)+
102
+ rev+' ('+steelblue(has_n_pages.to_s+' pages')+rev+')'
103
+ has_n_pages = PdfParadise.n_pages_in_this_pdf_file?(this_pdf_file) # This is also the last page.
104
+ if use_pdftk?
105
+ _ = 'pdftk '+this_pdf_file+' cat 1-'+(has_n_pages.to_i - 1).to_s+' '+
106
+ has_n_pages.to_s+'-end output '+
107
+ name_of_the_output_file?(this_pdf_file)
108
+ else # else we use qpdf
109
+ _ = 'qpdf'.dup
110
+ if @overwrite_the_old_pdf_file
111
+ _ << ' --replace-input'
112
+ end
113
+ if @overwrite_the_old_pdf_file
114
+ _ << ' --pages '+this_pdf_file+' 1-'+(has_n_pages.to_i - 1).to_s+' -- '+
115
+ this_pdf_file
116
+ else
117
+ _ << ' --pages '+this_pdf_file+' 1-'+(has_n_pages.to_i - 1).to_s+' -- '+
118
+ this_pdf_file+' '+name_of_the_output_file?(this_pdf_file)
119
+ end
120
+ end
121
+ begin
122
+ esystem _ # Need to rescue here, e. g. due to permission errors and what not.
123
+ rescue Exception => error
124
+ pp error
125
+ end
126
+ else
127
+ opne 'No file exists at `'+sfile(this_pdf_file)+'`.'
128
+ end
129
+ }
130
+ end
131
+
132
+ # ========================================================================= #
133
+ # === name_of_the_output_file?
134
+ # ========================================================================= #
135
+ def name_of_the_output_file?(i)
136
+ if @overwrite_the_old_pdf_file
137
+ i.sub(/\.pdf$/,'')+'.pdf'
138
+ else
139
+ i.sub(/\.pdf$/,'')+'_output_file.pdf'
140
+ end
141
+ end; alias output? name_of_the_output_file? # === output?
142
+
143
+ # ========================================================================= #
144
+ # === use_pdftk?
145
+ # ========================================================================= #
146
+ def use_pdftk?
147
+ false
148
+ end
149
+
150
+ # ========================================================================= #
151
+ # === input?
152
+ # ========================================================================= #
153
+ def input?
154
+ @input_files
155
+ end
156
+
157
+ # ========================================================================= #
158
+ # === run
159
+ # ========================================================================= #
160
+ def run
161
+ process_each_pdf
162
+ end
163
+
164
+ end
165
+
166
+ # =========================================================================== #
167
+ # === PdfParadise.delete_last_page_of_this_pdf_file
168
+ #
169
+ # Easier method-way to invoke the above class.
170
+ # =========================================================================== #
171
+ def self.delete_last_page_of_this_pdf_file(i = ARGV)
172
+ PdfParadise::DeleteLastPageOfThisPdfFile.new(i)
173
+ end; self.instance_eval { alias remove_the_last_page_of_this_pdf_file delete_last_page_of_this_pdf_file } # === PdfParadise.remove_the_last_page_of_this_pdf_file
174
+ self.instance_eval { alias remove_last_page_of_this_pdf_file delete_last_page_of_this_pdf_file } # === PdfParadise.remove_last_page_of_this_pdf_file
175
+
176
+ end
177
+
178
+ if __FILE__ == $PROGRAM_NAME
179
+ PdfParadise::DeleteLastPageOfThisPdfFile.new(ARGV)
180
+ end # delete_last_page_of_this_pdf_file