prune 0.0.4
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/CHANGELOG.ja.txt +16 -0
- data/CHANGELOG.txt +16 -0
- data/MIT-LICENSE.ja.txt +24 -0
- data/MIT-LICENSE.txt +20 -0
- data/Manifest.txt +77 -0
- data/PostInstall.txt +4 -0
- data/README.ja.rdoc +39 -0
- data/README.rdoc +39 -0
- data/Rakefile +28 -0
- data/demo/english_fonts.rb +66 -0
- data/demo/japanese_encodings_euc_jp.rb +27 -0
- data/demo/japanese_encodings_shift_jis.rb +27 -0
- data/demo/japanese_fonts.rb +54 -0
- data/demo/tables.rb +52 -0
- data/demo/text_decoration.rb +55 -0
- data/lib/prune.rb +90 -0
- data/lib/prune/constants.rb +39 -0
- data/lib/prune/document.rb +101 -0
- data/lib/prune/elements/base.rb +55 -0
- data/lib/prune/elements/catalog.rb +51 -0
- data/lib/prune/elements/font.rb +38 -0
- data/lib/prune/elements/font_descriptor.rb +38 -0
- data/lib/prune/elements/info.rb +44 -0
- data/lib/prune/elements/outlines.rb +19 -0
- data/lib/prune/elements/page.rb +115 -0
- data/lib/prune/elements/pages.rb +29 -0
- data/lib/prune/elements/procedure_sets.rb +22 -0
- data/lib/prune/elements/stream.rb +34 -0
- data/lib/prune/errors.rb +73 -0
- data/lib/prune/fonts/base.rb +92 -0
- data/lib/prune/fonts/base_en.rb +38 -0
- data/lib/prune/fonts/base_ja.rb +129 -0
- data/lib/prune/fonts/en/courier.rb +37 -0
- data/lib/prune/fonts/en/helvetica.rb +168 -0
- data/lib/prune/fonts/en/symbol.rb +60 -0
- data/lib/prune/fonts/en/times_roman.rb +168 -0
- data/lib/prune/fonts/en/zapf_dingbats.rb +60 -0
- data/lib/prune/fonts/ja/ms_gothic.rb +55 -0
- data/lib/prune/fonts/ja/ms_mincho.rb +55 -0
- data/lib/prune/fonts/ja/ms_p_gothic.rb +55 -0
- data/lib/prune/fonts/ja/ms_p_mincho.rb +55 -0
- data/lib/prune/fonts/ja/ms_pr_gothic.rb +55 -0
- data/lib/prune/fonts/ja/ms_ui_gothic.rb +55 -0
- data/lib/prune/functions.rb +18 -0
- data/lib/prune/p_objects/aliases.rb +37 -0
- data/lib/prune/p_objects/base.rb +45 -0
- data/lib/prune/p_objects/p_array.rb +62 -0
- data/lib/prune/p_objects/p_dictionary.rb +83 -0
- data/lib/prune/p_objects/p_hexadecimal_string.rb +27 -0
- data/lib/prune/p_objects/p_literal_string.rb +25 -0
- data/lib/prune/p_objects/p_name.rb +45 -0
- data/lib/prune/p_objects/p_stream.rb +29 -0
- data/lib/prune/parsers/base.rb +13 -0
- data/lib/prune/parsers/document/page/table/tr_parser.rb +77 -0
- data/lib/prune/parsers/document/page/table_parser.rb +32 -0
- data/lib/prune/parsers/document/page_parser.rb +91 -0
- data/lib/prune/parsers/document/property_parser.rb +45 -0
- data/lib/prune/parsers/document_parser.rb +26 -0
- data/lib/prune/shapes/base.rb +52 -0
- data/lib/prune/shapes/line.rb +55 -0
- data/lib/prune/shapes/rectangle.rb +64 -0
- data/lib/prune/shapes/text_box.rb +223 -0
- data/prune.gemspec +37 -0
- data/script/console +10 -0
- data/script/console.cmd +1 -0
- data/script/destroy +14 -0
- data/script/destroy.cmd +1 -0
- data/script/generate +14 -0
- data/script/generate.cmd +1 -0
- data/spec/prune/p_objects/p_array_spec.rb +46 -0
- data/spec/prune/p_objects/p_dictionary_spec.rb +61 -0
- data/spec/prune/p_objects/p_stream_spec.rb +29 -0
- data/spec/prune_spec.rb +38 -0
- data/spec/spec.opts +1 -0
- data/spec/spec_helper.rb +11 -0
- data/tasks/prune.rake +38 -0
- data/tasks/rspec.rake +21 -0
- metadata +181 -0
data/demo/tables.rb
ADDED
@@ -0,0 +1,52 @@
|
|
1
|
+
# -*- coding:utf-8 -*-
|
2
|
+
require "prune"
|
3
|
+
|
4
|
+
Prune.pdf("tables.pdf"){
|
5
|
+
property{
|
6
|
+
title "Tables"
|
7
|
+
subject "Demonstration document for Prune."
|
8
|
+
author "Prune"
|
9
|
+
language "ja-JP"
|
10
|
+
}
|
11
|
+
|
12
|
+
page(:A4W, :font => {:name => :ms_gothic, :size => 12}){
|
13
|
+
table(:font => {:size => 20}, :border => {:style => :solid}){
|
14
|
+
tr{
|
15
|
+
text = []
|
16
|
+
5.times do
|
17
|
+
text << "num"
|
18
|
+
td text.join("\n")
|
19
|
+
end
|
20
|
+
}
|
21
|
+
tr{
|
22
|
+
text = []
|
23
|
+
4.times do
|
24
|
+
text << "num"
|
25
|
+
td text.join("\n"),
|
26
|
+
:border => {:style => :dashed, :color => "#FF0000", :width => 2.0}
|
27
|
+
end
|
28
|
+
}
|
29
|
+
}
|
30
|
+
|
31
|
+
br
|
32
|
+
|
33
|
+
table(:widths => [30, 40, 50, 60, 70], :font => {:size => 20}, :border => {:style => :solid}){
|
34
|
+
tr{
|
35
|
+
text = []
|
36
|
+
5.times do
|
37
|
+
text << "num"
|
38
|
+
td text.join("\n"), :text_align => :center
|
39
|
+
end
|
40
|
+
}
|
41
|
+
tr(:widths => [70, 50, 60, 70]){
|
42
|
+
text = []
|
43
|
+
4.times do
|
44
|
+
text << "num"
|
45
|
+
td text.join("\n"),
|
46
|
+
:border => {:style => :dashed, :color => "#FF0000", :width => 2.0},
|
47
|
+
:text_align => :right
|
48
|
+
end
|
49
|
+
}
|
50
|
+
}
|
51
|
+
}
|
52
|
+
}
|
@@ -0,0 +1,55 @@
|
|
1
|
+
# -*- coding:utf-8 -*-
|
2
|
+
require "prune"
|
3
|
+
|
4
|
+
Prune.pdf("text_decoration.pdf"){
|
5
|
+
property{
|
6
|
+
title "Text decoration"
|
7
|
+
subject "Demonstration document for Prune."
|
8
|
+
author "Prune"
|
9
|
+
language "ja-JP"
|
10
|
+
}
|
11
|
+
|
12
|
+
page(:A4W, :font => {:name => :ms_gothic, :size => 30}){
|
13
|
+
div "青色の文字",
|
14
|
+
:font => {:fill_color => "#0000FF"}
|
15
|
+
div "赤で縁取られた文字",
|
16
|
+
:font => {:mode => :stroke, :stroke_color => "#FF0000"}
|
17
|
+
div "緑で縁取られて\n内側が黄色の文字",
|
18
|
+
:font => {:mode => :fill_and_stroke,
|
19
|
+
:stroke_color => "#00FF00", :fill_color => "#FFFF00"}
|
20
|
+
div "赤で縁取られて\n内側が青で太字、斜体な文字",
|
21
|
+
:font => {:bold => true, :italic => true,
|
22
|
+
:font_mode => :fill_and_stroke,
|
23
|
+
:stroke_color => "#FF0000", :fill_color => "#0000FF"}
|
24
|
+
span "赤色の文字", :font => {:fill_color => "#FF0000"}
|
25
|
+
span "黄色の文字", :font => {:fill_color => "#FFFF00"}
|
26
|
+
span "青色の文字", :font => {:fill_color => "#0000FF"}
|
27
|
+
br
|
28
|
+
span "紫色の文字", :font => {:fill_color => "#800080"}
|
29
|
+
span "灰色の文字", :font => {:fill_color => "#808080"}
|
30
|
+
span "緑色の文字", :font => {:fill_color => "#008000"}
|
31
|
+
br
|
32
|
+
div "背景色が設定された文字列", :background_color => "#FFFF00"
|
33
|
+
br
|
34
|
+
div "左寄せ", :text_align => :left, :background_color => "#FF0000"
|
35
|
+
div "センタリング", :text_align => :center, :background_color => "#FFFF00"
|
36
|
+
div "右寄せ", :text_align => :right, :background_color => "#0000FF"
|
37
|
+
}
|
38
|
+
page(:A4W, :font => {:name => :ms_gothic, :size => 30}){
|
39
|
+
div "枠をつけてみる", :text_align => :center,
|
40
|
+
:border => {:style => :solid}
|
41
|
+
br
|
42
|
+
div "破線で\n枠をつけてみる", :text_align => :center,
|
43
|
+
:border => {:style => :dashed, :width => 2.0, :color => "#00FF00"}
|
44
|
+
br
|
45
|
+
div "全ての枠に\n違うスタイルを\n適用する", :text_align => :right,
|
46
|
+
:border_top => {:style => :solid, :width => 2.0, :color => "#FF0000"},
|
47
|
+
:border_left => {:style => :dashed, :width => 1.0, :color => "#00FF00"},
|
48
|
+
:border_right => {:style => :solid},
|
49
|
+
:border_bottom => {:style => :dashed, :color => "#0000FF"}
|
50
|
+
br
|
51
|
+
span "30mm", :width => 300, :border_bottom => {:style => :solid}
|
52
|
+
span "40mm", :width => 400
|
53
|
+
span "50mm", :width => 500, :border_bottom => {:style => :solid}
|
54
|
+
}
|
55
|
+
}
|
data/lib/prune.rb
ADDED
@@ -0,0 +1,90 @@
|
|
1
|
+
# -*- coding:utf-8 -*-
|
2
|
+
|
3
|
+
# Path of the library.
|
4
|
+
prune_path = File.join(File.dirname(__FILE__), "prune")
|
5
|
+
prune_fullpath = File.expand_path(prune_path)
|
6
|
+
|
7
|
+
# Add to the load path of ruby.
|
8
|
+
$:.unshift(prune_path) unless
|
9
|
+
$:.include?(prune_path) || $:.include?(prune_fullpath)
|
10
|
+
|
11
|
+
# Constants.
|
12
|
+
require "constants"
|
13
|
+
|
14
|
+
# Errors.
|
15
|
+
require "errors"
|
16
|
+
|
17
|
+
# PDF functions.
|
18
|
+
require "functions"
|
19
|
+
|
20
|
+
# PDF objects.
|
21
|
+
require "p_objects/base"
|
22
|
+
require "p_objects/p_hexadecimal_string"
|
23
|
+
require "p_objects/p_literal_string"
|
24
|
+
require "p_objects/p_name"
|
25
|
+
require "p_objects/p_stream"
|
26
|
+
require "p_objects/p_array"
|
27
|
+
require "p_objects/p_dictionary"
|
28
|
+
require "p_objects/aliases"
|
29
|
+
|
30
|
+
# PDF elements.
|
31
|
+
require "elements/base"
|
32
|
+
require "elements/catalog"
|
33
|
+
require "elements/font"
|
34
|
+
require "elements/font_descriptor"
|
35
|
+
require "elements/info"
|
36
|
+
require "elements/outlines"
|
37
|
+
require "elements/page"
|
38
|
+
require "elements/pages"
|
39
|
+
require "elements/procedure_sets"
|
40
|
+
require "elements/stream"
|
41
|
+
|
42
|
+
# fonts
|
43
|
+
require "fonts/base"
|
44
|
+
require "fonts/base_en"
|
45
|
+
require "fonts/en/courier"
|
46
|
+
require "fonts/en/helvetica"
|
47
|
+
require "fonts/en/symbol"
|
48
|
+
require "fonts/en/times_roman"
|
49
|
+
require "fonts/en/zapf_dingbats"
|
50
|
+
require "fonts/base_ja"
|
51
|
+
require "fonts/ja/ms_gothic"
|
52
|
+
require "fonts/ja/ms_mincho"
|
53
|
+
require "fonts/ja/ms_p_gothic"
|
54
|
+
require "fonts/ja/ms_p_mincho"
|
55
|
+
require "fonts/ja/ms_pr_gothic"
|
56
|
+
require "fonts/ja/ms_ui_gothic"
|
57
|
+
|
58
|
+
# PDF document.
|
59
|
+
require "document"
|
60
|
+
|
61
|
+
# Shapes.
|
62
|
+
require "shapes/base"
|
63
|
+
require "shapes/line"
|
64
|
+
require "shapes/rectangle"
|
65
|
+
require "shapes/text_box"
|
66
|
+
|
67
|
+
# DSL parser.
|
68
|
+
require "parsers/base"
|
69
|
+
require "parsers/document/property_parser"
|
70
|
+
require "parsers/document/page/table/tr_parser"
|
71
|
+
require "parsers/document/page/table_parser"
|
72
|
+
require "parsers/document/page_parser"
|
73
|
+
require "parsers/document_parser"
|
74
|
+
|
75
|
+
module Prune
|
76
|
+
def self.pdf(filename = nil, &block)
|
77
|
+
# Build document.
|
78
|
+
@document = Document.new
|
79
|
+
@document_parser = Parsers::DocumentParser.new(@document)
|
80
|
+
@document_parser.instance_eval(&block)
|
81
|
+
|
82
|
+
unless filename.nil?
|
83
|
+
filename << ".pdf" unless /\.[pP][dD][fF]\z/ === filename
|
84
|
+
@document.save_as(filename)
|
85
|
+
else
|
86
|
+
@document.to_s
|
87
|
+
end
|
88
|
+
end
|
89
|
+
end
|
90
|
+
|
@@ -0,0 +1,39 @@
|
|
1
|
+
# -*- coding:utf-8 -*-
|
2
|
+
|
3
|
+
module Prune
|
4
|
+
# Version of Prune.
|
5
|
+
VERSION = "0.0.4" unless const_defined?(:VERSION)
|
6
|
+
|
7
|
+
# Application name.
|
8
|
+
APPLICATION = self.name unless const_defined?(:APPLICATION)
|
9
|
+
|
10
|
+
# Line feed code.
|
11
|
+
LF = "\n" unless const_defined?(:LF)
|
12
|
+
|
13
|
+
# Document sizes(width and height in milli-meters).
|
14
|
+
DOCUMENT_SIZES = {
|
15
|
+
:A1 => [594.0, 841.0], :A1W => [ 841.0, 594.0],
|
16
|
+
:A2 => [420.0, 594.0], :A2W => [ 594.0, 420.0],
|
17
|
+
:A3 => [297.0, 420.0], :A3W => [ 420.0, 297.0],
|
18
|
+
:A4 => [210.0, 297.0], :A4W => [ 297.0, 210.0],
|
19
|
+
:A5 => [148.0, 210.0], :A5W => [ 210.0, 148.0],
|
20
|
+
:A6 => [105.0, 148.0], :A6W => [ 148.0, 105.0],
|
21
|
+
:A7 => [ 74.0, 105.0], :A7W => [ 105.0, 74.0],
|
22
|
+
:B1 => [728.0, 1030.0], :B1W => [1030.0, 728.0],
|
23
|
+
:B2 => [515.0, 728.0], :B2W => [ 728.0, 515.0],
|
24
|
+
:B3 => [364.0, 515.0], :B3W => [ 515.0, 364.0],
|
25
|
+
:B4 => [257.0, 364.0], :B4W => [ 364.0, 257.0],
|
26
|
+
:B5 => [182.0, 257.0], :B5W => [ 257.0, 182.0],
|
27
|
+
:B6 => [128.0, 182.0], :B6W => [ 182.0, 128.0],
|
28
|
+
:B7 => [ 91.0, 128.0], :B7W => [ 128.0, 91.0],
|
29
|
+
} unless const_defined?(:DOCUMENT_SIZES)
|
30
|
+
|
31
|
+
# Page layout
|
32
|
+
PAGE_LAYOUT = [
|
33
|
+
:SinglePage,
|
34
|
+
:OneColumn,
|
35
|
+
:TwoColumnLeft,
|
36
|
+
:TwoColumnRight
|
37
|
+
] unless const_defined?(:PAGE_LAYOUT)
|
38
|
+
end
|
39
|
+
|
@@ -0,0 +1,101 @@
|
|
1
|
+
# -*- coding:utf-8 -*-
|
2
|
+
require "digest/md5"
|
3
|
+
|
4
|
+
module Prune
|
5
|
+
class Document
|
6
|
+
include Errors
|
7
|
+
include PObjects
|
8
|
+
include Elements
|
9
|
+
|
10
|
+
attr_reader :catalog, :pages, :outlines, :info, :proc_set
|
11
|
+
attr_reader :fonts, :elements
|
12
|
+
attr_writer :version
|
13
|
+
|
14
|
+
# Initialize
|
15
|
+
def initialize
|
16
|
+
@elements = []
|
17
|
+
@fonts = {}
|
18
|
+
@version = "1.2"
|
19
|
+
|
20
|
+
# Initialize PDF infos.
|
21
|
+
@info = Info.new(self)
|
22
|
+
|
23
|
+
# Initialize catalog.
|
24
|
+
@catalog = Catalog.new(self)
|
25
|
+
@catalog.version = @version
|
26
|
+
|
27
|
+
# Initialize outlines.
|
28
|
+
outlines = Outlines.new(self)
|
29
|
+
@catalog.outlines = outlines.reference
|
30
|
+
|
31
|
+
# Initialize pages.
|
32
|
+
@pages = Pages.new(self)
|
33
|
+
@catalog.pages = @pages.reference
|
34
|
+
|
35
|
+
# Initialize ProcSet
|
36
|
+
@proc_set = Elements::ProcedureSets.new(self)
|
37
|
+
end
|
38
|
+
|
39
|
+
# Save pdf document to a file.
|
40
|
+
def save_as(filename)
|
41
|
+
raise DocumentEmptyError if @pages.empty?
|
42
|
+
# Write to a file
|
43
|
+
File.open(filename, "wb") do |file|
|
44
|
+
file.flock(File::LOCK_EX)
|
45
|
+
file.write(self.to_s)
|
46
|
+
file.flock(File::LOCK_UN)
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
# Convert to String.
|
51
|
+
def to_s
|
52
|
+
# Write header
|
53
|
+
out = []
|
54
|
+
out << "%PDF-#{@version}"
|
55
|
+
out << "%" + [0xE2, 0xE3, 0xCF, 0xD3].pack("c*")
|
56
|
+
# Write objects
|
57
|
+
out += @elements.collect{|element| element.to_s}
|
58
|
+
# Write cross-reference table
|
59
|
+
out += cross_reference_table(@elements.size, out.join(LF))
|
60
|
+
# Write trailer
|
61
|
+
out += trailer(out.join(LF))
|
62
|
+
out << "%%EOF"
|
63
|
+
out.join(LF)
|
64
|
+
end
|
65
|
+
|
66
|
+
private
|
67
|
+
def cross_reference_table(objects, source)
|
68
|
+
out = []
|
69
|
+
out << "xref"
|
70
|
+
out << "0 %d" % (objects + 1)
|
71
|
+
out << "0000000000 65535 f"
|
72
|
+
# オフセットの計算
|
73
|
+
pos = 0
|
74
|
+
while index = source.index(/^\d+ \d+ obj/, pos)
|
75
|
+
out << "%010d %05d %s" % [index, 0, "n"]
|
76
|
+
pos = index + 1
|
77
|
+
end
|
78
|
+
out
|
79
|
+
end
|
80
|
+
|
81
|
+
def trailer(source)
|
82
|
+
out = []
|
83
|
+
id = Digest::MD5.hexdigest(rand.to_s)
|
84
|
+
out << "trailer"
|
85
|
+
dict = pd(
|
86
|
+
pn(:Size) => (@elements.size + 1),
|
87
|
+
pn(:Root) => @catalog.reference,
|
88
|
+
pn(:Info) => @info.reference,
|
89
|
+
pn(:ID) => pa(ph(id), ph(id)))
|
90
|
+
out << dict.to_s
|
91
|
+
out << "startxref"
|
92
|
+
out << source.index("xref")
|
93
|
+
out
|
94
|
+
end
|
95
|
+
|
96
|
+
def inspect
|
97
|
+
self.to_s
|
98
|
+
end
|
99
|
+
end
|
100
|
+
end
|
101
|
+
|
@@ -0,0 +1,55 @@
|
|
1
|
+
# -*- coding:utf-8 -*-
|
2
|
+
|
3
|
+
module Prune
|
4
|
+
module Elements
|
5
|
+
class Base
|
6
|
+
include Errors
|
7
|
+
include PObjects
|
8
|
+
include Functions
|
9
|
+
|
10
|
+
attr_reader :document
|
11
|
+
|
12
|
+
# Initialize.
|
13
|
+
def initialize(document)
|
14
|
+
@document = document
|
15
|
+
@element_id = 0
|
16
|
+
@revision = 0
|
17
|
+
@content = nil
|
18
|
+
@stream = nil
|
19
|
+
@registered = false
|
20
|
+
end
|
21
|
+
|
22
|
+
# Convert element to String.
|
23
|
+
def to_s
|
24
|
+
raise ElementNotRegisteredError unless @registered
|
25
|
+
out = []
|
26
|
+
out << "%d %d obj" % [@element_id, @revision]
|
27
|
+
out << @content.to_s
|
28
|
+
out << "endobj"
|
29
|
+
return out.join(LF)
|
30
|
+
end
|
31
|
+
|
32
|
+
# Get reference id of the element.
|
33
|
+
def reference
|
34
|
+
raise ObjectNotRegisteredError unless @registered
|
35
|
+
"#{@element_id} #{@revision} R"
|
36
|
+
end
|
37
|
+
|
38
|
+
# Register element to document.
|
39
|
+
def register
|
40
|
+
unless @registered
|
41
|
+
@element_id = @document.elements.size + 1
|
42
|
+
@document.elements << self
|
43
|
+
@registered = true
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
private
|
48
|
+
# Set text for "p" method.
|
49
|
+
def inspect
|
50
|
+
self.to_s
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
@@ -0,0 +1,51 @@
|
|
1
|
+
# -*- coding:utf-8 -*-
|
2
|
+
|
3
|
+
module Prune
|
4
|
+
module Elements
|
5
|
+
class Catalog < Base
|
6
|
+
include Prune
|
7
|
+
|
8
|
+
# Initialize.
|
9
|
+
def initialize(document)
|
10
|
+
super(document)
|
11
|
+
# Set dictionary.
|
12
|
+
@content = pd(
|
13
|
+
pn(:Type) => pn(:Catalog),
|
14
|
+
pn(:PageLayout) => pn(:SinglePage),
|
15
|
+
pn(:Lang) => pl("ja-JP"),
|
16
|
+
pn(:ViewerPreferences) => pd(
|
17
|
+
pn(:FitWindow) => true))
|
18
|
+
# Register element to document.
|
19
|
+
register
|
20
|
+
end
|
21
|
+
|
22
|
+
# Set reference to outlines.
|
23
|
+
def outlines=(reference)
|
24
|
+
@content.update(pn(:Outlines) => reference)
|
25
|
+
end
|
26
|
+
|
27
|
+
# Set page layout.
|
28
|
+
def page_layout=(layout)
|
29
|
+
if PAGE_LAYOUTS.include?(layout)
|
30
|
+
@content.update(pn(:PageLayout) => layout)
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
# Set lang.
|
35
|
+
def lang=(lang)
|
36
|
+
@content[pn(:Lang)] = lang
|
37
|
+
end
|
38
|
+
|
39
|
+
# Set pdf version.
|
40
|
+
def version=(version)
|
41
|
+
@content[pn(:Version)] = version
|
42
|
+
end
|
43
|
+
|
44
|
+
# Set reference to pages.
|
45
|
+
def pages=(pages)
|
46
|
+
@content[pn(:Pages)] = pages
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|