juno-report 0.1.2 → 0.1.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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