juno-report 0.1.2 → 0.1.3

Sign up to get free protection for your applications and to get access to all the features.
data/README.md DELETED
@@ -1,197 +0,0 @@
1
- # Juno Report
2
-
3
- Cry with Report Generation? Nevermore!
4
-
5
- ## Installation
6
-
7
- Add this line to your application's Gemfile:
8
-
9
- gem 'juno-report'
10
-
11
- And then execute:
12
-
13
- $ bundle
14
-
15
- Or install it yourself as:
16
-
17
- $ gem install juno-report
18
-
19
- ## Usage
20
-
21
- The generating reports is based on a YAML file with all rules, with the fields and their settings, divided by sections.
22
-
23
- ### Body section
24
-
25
- Represents the records which will be iterated to report generating
26
-
27
- ```yaml
28
- # example.yml
29
- body:
30
- settings: {posY: 40, height: 25}
31
- fields:
32
- test_field1: [10]
33
- test_field2: [220]
34
- test_field3: [430, {column: "Named Test Field 3"}]
35
- footer:
36
- label_total: [10, {value: "Total"}]
37
- totalizer: [220, {behavior: count}]
38
- test_field3: [430, {behavior: sum}]
39
- ```
40
- The [body] section ***must*** have three rules:
41
-
42
- * `settings`: Defines some configurations for body, like their height and ypos.
43
- * `fields`: Describes each field of record to be iterated.
44
- * `footer`: Drawn at the end of all printed records and calculates fields according behavior parameter.
45
-
46
- Each of these rules receives a array, where the first position is an integer representing the field horizontal position and
47
- the second position is a hash with some configurations.
48
-
49
-
50
- ##### Settings
51
-
52
- * `height`: Set the of each row at report [Integer].
53
- * `posY`: Relative vertical position of last row at report [Integer].
54
- * `groups`: Describes which groups will be printed (More bellow) [Array].
55
-
56
- ##### Fields
57
-
58
- * `size`: Font size of the field [Integer].
59
- * `align`: Defines the text alignment for each value [left|center|right].
60
- * `font`: Supports all font type provided by Prawn gem (See more in http://rubydoc.info/gems/prawn/Prawn/Font/AFM).
61
- * `style`: Stylistic variations of a font [bold|italic].
62
- * `value`: Fixed text to be printed [string].
63
- * `column`: The header are "humanized" automatically, but you can set other value manually [string].
64
-
65
- ##### Footer
66
-
67
- * `behavior`: Specify a function to be performed, sending as parameter the fieldname value [string].
68
- * `label`: Preppends a text to fieldname value specified [string].
69
- * `value`: Fixed text to be printed (fieldname value will be ignored) [string].
70
-
71
- With theses configurations already is possible generate a basic report, without groups feature.
72
- For this we need call the generate method on JunoReport module:
73
-
74
- ```ruby
75
- # test.rb
76
- require 'juno-report'
77
-
78
- data = [
79
- {:test_field1 => 'Test Value 1', :test_field2 => "Test Value 2", :test_field3 => 50},
80
- {:test_field1 => 'Test Value 1', :test_field2 => "Test Value 2", :test_field3 => 7},
81
- {:test_field1 => 'Test Value 1', :test_field2 => "Test Value 2", :test_field3 => 10},
82
- {:test_field1 => 'Test Value 1', :test_field2 => "Test Value 2", :test_field3 => 5},
83
- {:test_field1 => 'Test Value 1', :test_field2 => "Test Value 2", :test_field3 => 2},
84
- {:test_field1 => 'Test Value 1', :test_field2 => "Test Value 2", :test_field3 => 4},
85
- {:test_field1 => 'Test Value 1', :test_field2 => "Test Value 2", :test_field3 => 24}
86
- ]
87
-
88
- JunoReport::generate(data, :report => 'example')
89
- ```
90
-
91
- The first parameter must be a set of hash or objects which represent the report data. And the second parameter is a hash
92
- with the report settings, that can be:
93
-
94
- * `report`: The source of all rules. Must be a YAML file [string].
95
- * `type`: Specify if the report will be writed on the disc or returned to the caller such a stream [:file|:stream]
96
- * `filename`: Defines the report name which will be writed on disc. If not specified, the default name is "report.pdf" [string].
97
-
98
- ### Page section
99
-
100
- You may want to print a title every time that a page is created. You simply insert a [page] section.
101
-
102
- ```yaml
103
- # example.yml
104
- page:
105
- fields:
106
- title1: [260, {size: 24, align: center, value: "Test Report"}]
107
- subtitle1: [260, {size: 20, posY: 20, align: center, value: "Generated by Juno Report"}]
108
- body:
109
- settings: {posY: 40, height: 25}
110
- fields:
111
- test_field1: [10]
112
- test_field2: [220]
113
- test_field3: [430, {column: "Named Test Field 3"}]
114
- footer:
115
- label_total: [10, {value: "Total"}]
116
- totalizer: [220, {behavior: count}]
117
- test_field3: [430, {behavior: sum}]
118
- ```
119
-
120
- ### Groups section
121
-
122
- For each item in groups parameter at body section you should create a section with same name.
123
- This section represents the header configurations to every time that the group is printed and behaves like [body] section.
124
-
125
- ```yaml
126
- # example.yml
127
- page:
128
- fields:
129
- title1: [260, {size: 24, align: center, value: "Test Report"}]
130
- subtitle1: [260, {size: 20, posY: 20, align: center, value: "Generated by Juno Report"}]
131
- body:
132
- settings: {posY: 40, height: 30, groups: [group_field1, group_field2]}
133
- fields:
134
- test_field1: [10]
135
- test_field2: [220]
136
- test_field3: [420, {column: "Named Test Field 3"}]
137
- footer:
138
- label_total: [10, {value: "Total"}]
139
- totalizer1: [220, {behavior: count}]
140
- test_field3: [420, {behavior: sum}]
141
- group_field1:
142
- settings: {posY: 30, height: 10}
143
- fields:
144
- group_field1: [10, size: 25]
145
- footer:
146
- group_field1: [10, {label: "Total "}]
147
- totalizer1: [220, {behavior: count}]
148
- test_field3: [420, {behavior: sum}]
149
- group_field2:
150
- settings: {posY: 30, height: 25}
151
- fields:
152
- group_field2: [10, size: 17]
153
- footer:
154
- group_field2: [10, {label: "Total "}]
155
- totalizer1: [220, {behavior: count}]
156
- test_field3: [420, {behavior: sum}]
157
- ```
158
-
159
- Every time that a "group field" value changes, the group will be printed.
160
-
161
- ```ruby
162
- # test.rb
163
- require 'juno-report'
164
-
165
- data = [
166
- {:test_field1 => 'Test Value 1', :test_field2 => "Test Value 1", :test_field3 => 50, :group_field1 => 'Group 1', :group_field2 => 'Subgroup 1'},
167
- {:test_field1 => 'Test Value 2', :test_field2 => "Test Value 2", :test_field3 => 16, :group_field1 => 'Group 1', :group_field2 => 'Subgroup 1'},
168
- {:test_field1 => 'Test Value 5', :test_field2 => "Test Value 3", :test_field3 => 7, :group_field1 => 'Group 1', :group_field2 => 'Subgroup 1'},
169
- {:test_field1 => 'Test Value 3', :test_field2 => "Test Value 9", :test_field3 => 10, :group_field1 => 'Group 1', :group_field2 => 'Subgroup 2'},
170
- {:test_field1 => 'Test Value 3', :test_field2 => "Test Value 2", :test_field3 => 4, :group_field1 => 'Group 1', :group_field2 => 'Subgroup 2'},
171
- {:test_field1 => 'Test Value 9', :test_field2 => "Test Value 4", :test_field3 => 10, :group_field1 => 'Group 1', :group_field2 => 'Subgroup 2'},
172
- {:test_field1 => 'Test Value 7', :test_field2 => "Test Value 5", :test_field3 => 5, :group_field1 => 'Group 1', :group_field2 => 'Subgroup 3'},
173
- {:test_field1 => 'Test Value 3', :test_field2 => "Test Value 5", :test_field3 => 2, :group_field1 => 'Group 1', :group_field2 => 'Subgroup 3'},
174
- {:test_field1 => 'Test Value 3', :test_field2 => "Test Value 2", :test_field3 => 27, :group_field1 => 'Group 2', :group_field2 => 'Subgroup 1'},
175
- {:test_field1 => 'Test Value 3', :test_field2 => "Test Value 5", :test_field3 => 2, :group_field1 => 'Group 2', :group_field2 => 'Subgroup 1'},
176
- {:test_field1 => 'Test Value 0', :test_field2 => "Test Value 4", :test_field3 => 13, :group_field1 => 'Group 2', :group_field2 => 'Subgroup 1'},
177
- {:test_field1 => 'Test Value 4', :test_field2 => "Test Value 7", :test_field3 => 7, :group_field1 => 'Group 2', :group_field2 => 'Subgroup 1'},
178
- {:test_field1 => 'Test Value 1', :test_field2 => "Test Value 3", :test_field3 => 28, :group_field1 => 'Group 2', :group_field2 => 'Subgroup 1'},
179
- {:test_field1 => 'Test Value 4', :test_field2 => "Test Value 5", :test_field3 => 4, :group_field1 => 'Group 2', :group_field2 => 'Subgroup 2'},
180
- {:test_field1 => 'Test Value 5', :test_field2 => "Test Value 6", :test_field3 => 24, :group_field1 => 'Group 2', :group_field2 => 'Subgroup 2'}
181
- ]
182
-
183
- JunoReport::generate(data, :report => 'example', :filename => 'juno-report.pdf')
184
- ```
185
-
186
- ## Contributors
187
-
188
- 2. Edson Júnior (http://github.com/ebfjunior)
189
-
190
- ## Contributing
191
-
192
- 1. Fork it
193
- 2. Create your feature branch (`git checkout -b my-new-feature`)
194
- 3. Commit your changes (`git commit -am 'Added some feature'`)
195
- 4. Push to the branch (`git push origin my-new-feature`)
196
- 5. Create new Pull Request
197
-
data/Rakefile DELETED
@@ -1,7 +0,0 @@
1
- require "bundler/gem_tasks"
2
- require "rspec/core/rake_task"
3
-
4
- RSpec::Core::RakeTask.new
5
-
6
- task :default => :spec
7
- task :test => :spec
data/juno-report.gemspec DELETED
@@ -1,24 +0,0 @@
1
- # -*- encoding: utf-8 -*-
2
- $:.push File.expand_path("../lib", __FILE__)
3
- require 'juno-report/version'
4
-
5
- Gem::Specification.new do |gem|
6
- gem.name = "juno-report"
7
- gem.version = JunoReport::VERSION
8
- gem.platform = Gem::Platform::RUBY
9
- gem.authors = ["Edson Júnior"]
10
- gem.email = ["ejunior.batista@gmail.com"]
11
- gem.description = "A simple, but efficient, report genarator yaml based"
12
- gem.summary = "Juno Reports generates reports with the minimum configuration and effort"
13
- gem.homepage = "http://github.com/ebfjunior/juno-report"
14
-
15
- gem.files = `git ls-files`.split("\n")
16
- gem.executables = gem.files.grep(%r{^bin/}).map { |f| File.basename(f) }
17
- gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
18
- gem.require_paths = ["lib"]
19
-
20
- gem.add_dependency "prawml"
21
-
22
- gem.add_development_dependency 'rake'
23
- gem.add_development_dependency 'rspec'
24
- end
@@ -1,18 +0,0 @@
1
- module JunoReport
2
- module Pdf
3
- module Behaviors
4
- def self.sum old_value, new_value
5
- value = (old_value.to_f + new_value.to_f).to_s
6
- (/^[0-9]+(?=\.)/.match value).nil? ? value : value[/^[0-9]+(?=\.)/]
7
- end
8
-
9
- def self.substract old_value, new_value
10
- old_value.to_f - new_value.to_f
11
- end
12
-
13
- def self.count old_value, new_value = nil
14
- old_value.to_i + 1
15
- end
16
- end
17
- end
18
- end
@@ -1,246 +0,0 @@
1
- module JunoReport
2
- module Pdf
3
-
4
- #Responsible for generate a report, based on rules passed as parameter in Juno::Report::generate.
5
- #Juno Reports has support groups, just by especifying them at the rules file.
6
- #Receives a collection as parameter, which should be a Array of records of the report.
7
- def generate(collection)
8
- @defaults = {
9
- :style => :normal,
10
- :size => 12,
11
- :align => :left,
12
- :format => false,
13
- :font => 'Times-Roman',
14
- :type => :text,
15
- :color => '000000',
16
- :fixed => false
17
- }
18
-
19
- get_sections
20
- set_pos_y
21
-
22
- @defaults.merge!(@sections[:defaults]) unless @sections[:defaults].nil?
23
-
24
- collection = [collection] unless collection.is_a?(Array) or collection.is_a?(ActiveRecord::Relation)
25
- print_section :page unless @sections[:page].nil?
26
- set_pos_y (@sections[:body][:settings][:posY] || 0)
27
- @current_groups = {}
28
- @footers = {}
29
- @count = 0
30
-
31
- unless @sections[:groups].empty?
32
- reset_groups_values
33
- else
34
- draw_columns
35
- end
36
-
37
- initialize_footer_values
38
- can_print_footer = false
39
-
40
- collection.each do |record|
41
- @record = record.is_a?(Hash) ? ReportObject.new(record) : record #Convert the hash on a Object to futurely extend a module
42
-
43
- headers_to_print, headers_height = calculate_header
44
-
45
- unless headers_to_print.empty?
46
- @count = 0
47
- draw_footer headers_to_print, @sections[:groups] if can_print_footer
48
- if @posY - headers_height < 2*@sections[:body][:settings][:height]
49
- new_page
50
- else
51
- headers_to_print.each { |group| print_section group, @record, true }
52
- draw_columns
53
- end
54
- end
55
- can_print_footer = true
56
-
57
- update_footer_values
58
- print_section :body, @record
59
- @count += 1
60
- end
61
-
62
- draw_footer(@sections[:body][:settings][:groups].collect {|group| group.to_sym}, @sections[:groups]) if has_groups?
63
- draw_footer [:body], @sections
64
-
65
- @pdf
66
- end
67
-
68
- protected
69
-
70
- #Creates a new page, restarting the vertical position of the pointer.
71
- #Print the whole header for the current groups and the columns of the report.
72
- def new_page
73
- @pdf.start_new_page
74
- set_pos_y
75
- print_section :page unless @sections[:page].nil?
76
- set_pos_y (@sections[:body][:settings][:posY] || 0)
77
- @current_groups.each do |field, value|
78
- print_section field.to_sym, @record, true
79
- end
80
- draw_columns
81
- end
82
-
83
- #Generic function to print a section like :body, :page or the group sections.
84
- def print_section(section_name, values = nil, group = false)
85
- section = !group ? @sections[section_name] : @sections[:groups][section_name]
86
- set_pos_y(section[:settings][:posY] || 0) unless section_name.eql?(:body) || section[:settings].nil?
87
- new_page if @posY < 30
88
-
89
- if section_name.eql? :body and @count % 2 != 0
90
- @pdf.fill_color "F7F7F7"
91
- width = @options[:page_layout] == :portrait ? 530 : 770
92
- @pdf.fill_rectangle [0, @posY+(section[:settings][:height]/2)], width, section[:settings][:height]
93
- end
94
-
95
- section[:fields].each do |field, settings|
96
- symbolize! settings[1] unless settings[1].nil?
97
- set_pos_y settings[1][:posY] unless settings[1].nil? || settings[1][:posY].nil?
98
- settings = [settings[0], @posY, (@defaults.merge (settings[1] || { }))]
99
- settings[2][:style] = settings[2][:style].to_sym
100
- set_options settings[2]
101
-
102
- value = settings[2][:value].nil? ? (values.respond_to?(field) ? values.send(field) : "") : settings[2][:value]
103
- string_cut = settings[2][:cut].nil? ? value : value[0..settings[2][:cut]]
104
- draw_text string_cut, settings
105
- end
106
- set_pos_y (section[:settings][:height]) unless section[:settings].nil? || section[:settings][:height].nil?
107
- end
108
-
109
- #Print a horizontal line with the whole width of the page.
110
- def draw_line(y)
111
- width = @options[:page_layout] == :portrait ? 530 : 770
112
- @pdf.stroke { @pdf.horizontal_line 0, width, :at => y }
113
- end
114
-
115
- #Update the pointer vertical position to the specified value or 'zero' if the parameter is nil.
116
- #Obs: Prawn pointer is decrescent, in other words, the left-top corner position is (0, 750). For
117
- #semantic purposes, we set the same corner as (0, 0).
118
- def set_pos_y(posY = nil)
119
- height = @options[:page_layout] == :portrait ? 750 : 520
120
- @posY = height if @posY.nil?
121
- @posY = posY.nil? ? height : @posY - posY
122
- end
123
-
124
- #Convert to symbol all hash keys, recursively.
125
- def symbolize! hash
126
- hash.symbolize_keys!
127
- hash.values.select{|v| v.is_a? Hash}.each{|h| symbolize!(h)}
128
- end
129
-
130
- #Convert the structure of the rules to facilitate the generating proccess.
131
- def get_sections
132
- symbolize! @rules
133
- raise "[body] section on YAML file is needed to generate the report." if @rules[:body].nil?
134
- @sections = {:page => @rules[:page], :body => @rules[:body], :defaults => @rules[:defaults], :groups => {}}
135
- @sections[:body][:settings][:groups].each { |group| @sections[:groups][group.to_sym] = @rules[group.to_sym] } if has_groups?
136
- end
137
-
138
- #@current_groups storages the value for all groups. When a value is changed, the header is printed.
139
- #This function set nil value for every item in @current_groups if the parameter is not passed. Otherwise,
140
- #only the forward groups will be cleaned to avoid conflict problems with others groups.
141
- def reset_groups_values current_group = nil
142
- groups = @sections[:body][:settings][:groups]
143
- groups.each_with_index do |group, idx|
144
- @current_groups[group] = nil if current_group.nil? || groups.index(current_group.to_s) <= idx
145
- end
146
- end
147
-
148
-
149
- #Calculates the headers which must be printed before print the current record.
150
- #The function also returns the current header height to create a new page if the
151
- #page remaining space is smaller than (header + a record height)
152
- def calculate_header
153
- headers = []
154
- height = 0
155
- @current_groups.each do |field, value|
156
- if @record.send(field) != value
157
- reset_groups_values field
158
-
159
- headers << field.to_sym
160
- height += @sections[:groups][field.to_sym][:settings][:height] + @sections[:groups][field.to_sym][:settings][:posY]
161
-
162
- @current_groups[field] = @record.send(field)
163
- end
164
- end unless @current_groups.empty?
165
- [headers, height]
166
- end
167
-
168
- #Create a structure to calculate the footer values for all groups. Appends the footer body to total values too.
169
- def initialize_footer_values
170
- @sections[:body][:settings][:groups].each do |group|
171
- current_footer = {}
172
- @sections[:groups][group.to_sym][:footer].each { |field, settings| current_footer[field] = nil } unless @sections[:groups][group.to_sym][:footer].nil?
173
- @footers[group.to_sym] = current_footer unless current_footer.empty?
174
- end if has_groups?
175
- raise "The report must have at least a footer on body section" if @sections[:body][:footer].nil?
176
- current_footer = {}
177
- @sections[:body][:footer].each { |field, settings| current_footer[field] = nil }
178
- @footers[:body] = current_footer unless current_footer.empty?
179
- end
180
-
181
- #Call the function that calculates the footer values for all groups and the total body footer, with
182
- #different source for each
183
- def update_footer_values
184
- @sections[:body][:settings][:groups].reverse_each do |group|
185
- calculate_footer_values group, @sections[:groups][group.to_sym][:footer]
186
- end if has_groups?
187
- calculate_footer_values :body, @sections[:body][:footer]
188
- end
189
-
190
- #Returns the values to the group passed as parameter. If :behavior setting is used, so a
191
- #function in [lib/pdf/behaviors.rb] calculates the value of current field, else the report
192
- #method is called
193
- def calculate_footer_values group, source
194
- @footers[group.to_sym].each do |field, value|
195
- footer_rule = source[field]
196
- symbolize! footer_rule[1]
197
- unless footer_rule[1][:behavior].nil?
198
- @footers[group.to_sym][field] = JunoReport::Pdf::Behaviors.send footer_rule[1][:behavior].to_sym, value, (@record.respond_to?(field) ? @record.send(field) : nil)
199
- else
200
- @footers[group.to_sym][field] = footer_rule[1][:value] || (footer_rule[1][:label].to_s + @record.send(field))
201
- end unless @footers[group.to_sym].nil? || footer_rule[1].nil?
202
- end
203
- end
204
-
205
- #Print the footers according to the groups and source specified
206
- def draw_footer footers_to_print, source
207
- footers_to_print.reverse_each do |group|
208
- draw_line(@posY + @sections[:body][:settings][:height]/2)
209
- source[group][:footer].each do |field, settings|
210
- settings = [settings[0], @posY, (@defaults.merge (settings[1] || { }).symbolize_keys!)]
211
- settings[2][:style] = settings[2][:style].to_sym
212
- set_options settings[2]
213
- draw_text @footers[group][field], settings
214
- end
215
- draw_line(@posY - @sections[:body][:settings][:height]/4)
216
- set_pos_y @sections[:body][:settings][:height]
217
-
218
- reset_footer group
219
- end
220
- end
221
-
222
- #Resets the footer to next groups
223
- def reset_footer(group); @footers[group].each { |field, value| @footers[group][field] = nil }; end
224
-
225
- #Based on the Key names of the :body section at the rules, the function draw columns with
226
- #baselines on the top and bottom of the header.
227
- def draw_columns
228
- @sections[:body][:fields].each do |field, settings|
229
- settings = [settings[0], @posY, (@defaults.merge (settings[1] || { }).symbolize_keys!)]
230
- settings[2][:style] = settings[2][:style].to_sym
231
- set_options settings[2]
232
- draw_line(@posY + @sections[:body][:settings][:height]/2)
233
- field = settings[2][:column] || field.to_s.split('_').inject('') do |str, part|
234
- str << part.camelize << " "
235
- end
236
- draw_text field, settings
237
- end
238
- draw_line(@posY - @sections[:body][:settings][:height]/2)
239
- set_pos_y @sections[:body][:settings][:height]
240
- end
241
-
242
- def has_groups?
243
- !@sections[:body][:settings][:groups].nil?
244
- end
245
- end
246
- end
@@ -1,9 +0,0 @@
1
- class ReportObject
2
- def initialize(hash)
3
- hash.each do |k,v|
4
- self.instance_variable_set("@#{k}", v)
5
- self.class.send(:define_method, k, proc{self.instance_variable_get("@#{k}")})
6
- self.class.send(:define_method, "#{k}=", proc{|v| self.instance_variable_set("@#{k}", v)})
7
- end
8
- end
9
- end
@@ -1,3 +0,0 @@
1
- module JunoReport
2
- VERSION = "0.1.2"
3
- end
data/lib/juno-report.rb DELETED
@@ -1,32 +0,0 @@
1
- require "juno-report/version"
2
- require "juno-report/pdf"
3
- require "juno-report/pdf/behaviors"
4
- require "prawml"
5
-
6
- module JunoReport
7
- autoload :ReportObject, 'juno-report/report_object'
8
-
9
- def self.generate(collection, options)
10
- rules = (File.open "#{options[:report]}.yml").read
11
-
12
- defaults = {
13
- :page_layout => :portrait
14
- }
15
-
16
- pdf = Prawml::PDF.new rules, defaults.merge(options)
17
-
18
- pdf.extend JunoReport::Pdf
19
- report = pdf.generate(collection)
20
-
21
- options[:type] ||= :file
22
-
23
- if options[:type].eql? :file
24
- report.render_file (options[:filename] || "report.pdf")
25
- elsif options[:type].eql? :stream
26
- return report.render
27
- else
28
- raise "Type options must be :file or :stream."
29
- end
30
-
31
- end
32
- end
data/report.pdf DELETED
@@ -1,153 +0,0 @@
1
- %PDF-1.3
2
- %����
3
- 1 0 obj
4
- << /Creator <feff0050007200610077006e>
5
- /Producer <feff0050007200610077006e>
6
- >>
7
- endobj
8
- 2 0 obj
9
- << /Type /Catalog
10
- /Pages 3 0 R
11
- >>
12
- endobj
13
- 3 0 obj
14
- << /Type /Pages
15
- /Count 1
16
- /Kids [5 0 R]
17
- >>
18
- endobj
19
- 4 0 obj
20
- << /Length 926
21
- >>
22
- stream
23
- q
24
- /DeviceRGB cs
25
- 0.000 0.000 0.000 scn
26
- 36.000 758.000 m
27
- 566.000 758.000 l
28
- S
29
-
30
- BT
31
- 46 746.0 Td
32
- /F1.0 12 Tf
33
- [<54> 70 <657374204669656c643120>] TJ
34
- ET
35
-
36
- 0.000 0.000 0.000 scn
37
- 36.000 758.000 m
38
- 566.000 758.000 l
39
- S
40
-
41
- BT
42
- 256 746.0 Td
43
- /F1.0 12 Tf
44
- [<54> 70 <657374204669656c643220>] TJ
45
- ET
46
-
47
- 0.000 0.000 0.000 scn
48
- 36.000 758.000 m
49
- 566.000 758.000 l
50
- S
51
-
52
- BT
53
- 466 746.0 Td
54
- /F1.0 12 Tf
55
- [<4e616d65642054> 70 <657374204669656c642033>] TJ
56
- ET
57
-
58
- 36.000 734.000 m
59
- 566.000 734.000 l
60
- S
61
- 0.000 0.000 0.000 scn
62
-
63
- BT
64
- 46 721.0 Td
65
- /F1.0 12 Tf
66
- [<>] TJ
67
- ET
68
-
69
- 0.000 0.000 0.000 scn
70
-
71
- BT
72
- 256 721.0 Td
73
- /F1.0 12 Tf
74
- [<>] TJ
75
- ET
76
-
77
- 0.000 0.000 0.000 scn
78
-
79
- BT
80
- 466 721.0 Td
81
- /F1.0 12 Tf
82
- [<>] TJ
83
- ET
84
-
85
- 36.000 708.000 m
86
- 566.000 708.000 l
87
- S
88
- 0.000 0.000 0.000 scn
89
-
90
- BT
91
- 46 696.0 Td
92
- /F1.0 12 Tf
93
- [<54> 80 <6f74616c>] TJ
94
- ET
95
-
96
- 0.000 0.000 0.000 scn
97
-
98
- BT
99
- 256 696.0 Td
100
- /F1.0 12 Tf
101
- [<31>] TJ
102
- ET
103
-
104
- 0.000 0.000 0.000 scn
105
-
106
- BT
107
- 466 696.0 Td
108
- /F1.0 12 Tf
109
- [<30>] TJ
110
- ET
111
-
112
- 36.000 690.000 m
113
- 566.000 690.000 l
114
- S
115
- Q
116
-
117
- endstream
118
- endobj
119
- 5 0 obj
120
- << /Type /Page
121
- /Parent 3 0 R
122
- /MediaBox [0 0 595.28 841.89]
123
- /Contents 4 0 R
124
- /Resources << /ProcSet [/PDF /Text /ImageB /ImageC /ImageI]
125
- /Font << /F1.0 6 0 R
126
- >>
127
- >>
128
- >>
129
- endobj
130
- 6 0 obj
131
- << /Type /Font
132
- /Subtype /Type1
133
- /BaseFont /Times-Roman
134
- /Encoding /WinAnsiEncoding
135
- >>
136
- endobj
137
- xref
138
- 0 7
139
- 0000000000 65535 f
140
- 0000000015 00000 n
141
- 0000000109 00000 n
142
- 0000000158 00000 n
143
- 0000000215 00000 n
144
- 0000001192 00000 n
145
- 0000001372 00000 n
146
- trailer
147
- << /Size 7
148
- /Root 2 0 R
149
- /Info 1 0 R
150
- >>
151
- startxref
152
- 1471
153
- %%EOF