rant 0.3.2 → 0.3.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/NEWS +22 -1
- data/README +9 -12
- data/Rantfile +32 -9
- data/devel-notes +16 -0
- data/doc/advanced.rdoc +55 -0
- data/doc/rant.rdoc +27 -2
- data/doc/rantfile.rdoc +104 -30
- data/install.rb +6 -0
- data/lib/rant.rb +5 -1
- data/lib/rant/import.rb +12 -4
- data/lib/rant/import/rubydoc.rb +1 -1
- data/lib/rant/import/rubypackage.rb +2 -2
- data/lib/rant/import/rubytest.rb +3 -2
- data/lib/rant/plugin/csharp.rb +5 -9
- data/lib/rant/rantenv.rb +1 -0
- data/lib/rant/rantfile.rb +184 -68
- data/lib/rant/rantlib.rb +203 -195
- data/lib/rant/rantsys.rb +87 -44
- data/lib/rant/rantvar.rb +236 -17
- data/rantmethods.rb +9 -4
- data/run_rant +1 -1
- data/test/Rantfile +16 -0
- data/test/plugin/csharp/test_csharp.rb +2 -1
- data/test/plugin/rantfile +1 -0
- data/test/project1/Rantfile +8 -4
- data/test/rule.rf +27 -0
- data/test/subdirs/Rantfile +2 -0
- data/test/subdirs/sub2/sub/rantfile +17 -0
- data/test/subdirs/test_subdirs.rb +46 -2
- data/test/test_dirtask.rb +33 -0
- data/test/test_filelist.rb +81 -0
- data/test/test_filetask.rb +6 -6
- data/test/test_rant_interface.rb +4 -3
- data/test/test_rule.rb +67 -0
- data/test/test_source.rb +26 -0
- data/test/test_task.rb +27 -6
- data/test/test_var.rb +102 -0
- data/test/toplevel.rf +1 -1
- data/test/var.rf +19 -0
- metadata +11 -2
data/rantmethods.rb
CHANGED
@@ -12,6 +12,11 @@ task :rant_methods do
|
|
12
12
|
puts "*** total: #{ml.size} methods ***"
|
13
13
|
end
|
14
14
|
|
15
|
+
desc "Print constants introduced by Rant."
|
16
|
+
task :constants do
|
17
|
+
puts ((self.class.constants - Object.constants).sort)
|
18
|
+
end
|
19
|
+
|
15
20
|
desc "Print all attribute writers of a Gem::Specification."
|
16
21
|
task :gem_attrs do
|
17
22
|
require 'rubygems'
|
@@ -24,8 +29,8 @@ end
|
|
24
29
|
|
25
30
|
file "bench-rant" do |t|
|
26
31
|
c = 500
|
27
|
-
if
|
28
|
-
c = Integer(
|
32
|
+
if var["TC"]
|
33
|
+
c = Integer(var["TC"])
|
29
34
|
end
|
30
35
|
File.open(t.name, "w") { |f|
|
31
36
|
f.puts "$tc_run = 0"
|
@@ -49,8 +54,8 @@ end
|
|
49
54
|
|
50
55
|
file "bench-depsearch" do |t|
|
51
56
|
c = 500
|
52
|
-
if
|
53
|
-
c = Integer
|
57
|
+
if var["TC"]
|
58
|
+
c = Integer var["TC"]
|
54
59
|
end
|
55
60
|
File.open(t.name, "w") { |f|
|
56
61
|
f.puts "$tc_run = 0"
|
data/run_rant
CHANGED
data/test/Rantfile
CHANGED
@@ -9,7 +9,8 @@ $have_csc ||= Rant::Env.find_bin("csc") ||
|
|
9
9
|
Rant::Env.find_bin("cscc") || Rant::Env.find_bin("mcs")
|
10
10
|
|
11
11
|
class TestPluginCsharp < Test::Unit::TestCase
|
12
|
-
|
12
|
+
Assembly = Rant::Generators::Assembly
|
13
|
+
Env = Rant::Env
|
13
14
|
|
14
15
|
def setup
|
15
16
|
# Ensure we run in test directory.
|
data/test/plugin/rantfile
CHANGED
data/test/project1/Rantfile
CHANGED
@@ -1,4 +1,6 @@
|
|
1
1
|
|
2
|
+
require 'tutil'
|
3
|
+
|
2
4
|
file "test_touch" do |t|
|
3
5
|
sys.touch t.name
|
4
6
|
end
|
@@ -68,12 +70,12 @@ end
|
|
68
70
|
|
69
71
|
file "tbe" => :dep1 do |t|
|
70
72
|
sys.touch t.name
|
71
|
-
|
73
|
+
timeout
|
72
74
|
end
|
73
75
|
|
74
76
|
enhance :tbe => "dep2" do |t|
|
75
77
|
sys.touch "tbe2"
|
76
|
-
|
78
|
+
timeout
|
77
79
|
end
|
78
80
|
|
79
81
|
# should generate warning because there is no existing task called
|
@@ -82,12 +84,12 @@ enhance :nothing
|
|
82
84
|
|
83
85
|
task :order do |t|
|
84
86
|
sys.touch t.name + "1"
|
85
|
-
|
87
|
+
timeout
|
86
88
|
end
|
87
89
|
|
88
90
|
task :order do |t|
|
89
91
|
sys.touch t.name + "2"
|
90
|
-
|
92
|
+
timeout
|
91
93
|
end
|
92
94
|
|
93
95
|
file "incdep" do |t|
|
@@ -129,3 +131,5 @@ task :force_clean do
|
|
129
131
|
).find_all { |e| test(?e, e) }
|
130
132
|
sys.rm_rf %w(dir)
|
131
133
|
end
|
134
|
+
|
135
|
+
# vim:ft=ruby
|
data/test/rule.rf
ADDED
@@ -0,0 +1,27 @@
|
|
1
|
+
gen Rule, '.o' => '.c' do |t|
|
2
|
+
sys "cc -c -o #{t.name} #{t.source}"
|
3
|
+
end
|
4
|
+
|
5
|
+
gen Rule, :tt => :t do |t|
|
6
|
+
t.source =~ /\.t$/ or t.fail
|
7
|
+
sys.touch t.name
|
8
|
+
end
|
9
|
+
|
10
|
+
gen Rule, :t do |t|
|
11
|
+
test(?e, t.name) && t.fail
|
12
|
+
sys.touch t.name
|
13
|
+
end
|
14
|
+
|
15
|
+
src = lambda { |target| [target.sub_ext("t"), target.sub_ext("tt")] }
|
16
|
+
gen Rule, :lt => src do |t|
|
17
|
+
t.prerequisites[0] =~ /\.t$/ or t.fail
|
18
|
+
t.prerequisites[1] =~ /\.tt$/ or t.fail
|
19
|
+
sys.touch t.name
|
20
|
+
end
|
21
|
+
|
22
|
+
src = lambda { |target| target + "t" }
|
23
|
+
gen Rule, :rt => src do |t|
|
24
|
+
t.prerequisites[0] =~ /\.rtt$/ or t.fail
|
25
|
+
t.source =~ /\.rtt$/ or t.fail
|
26
|
+
sys.touch t.name
|
27
|
+
end
|
data/test/subdirs/Rantfile
CHANGED
@@ -8,7 +8,24 @@ file "rootref.t" => "#t" do |t|
|
|
8
8
|
sys.touch t.name
|
9
9
|
end
|
10
10
|
|
11
|
+
gen Directory, "dt/dt"
|
12
|
+
|
13
|
+
gen Task, "gt" => "dt" do |t|
|
14
|
+
t.needed { !test(?f, t.name) }
|
15
|
+
t.act { sys.touch t.name }
|
16
|
+
end
|
17
|
+
|
18
|
+
gen LightTask, "lt" do |lt|
|
19
|
+
lt.needed { !test(?f, lt.name) }
|
20
|
+
lt.act { sys.touch lt.name }
|
21
|
+
end
|
22
|
+
|
23
|
+
task :create_param do
|
24
|
+
sys.touch var[:param]
|
25
|
+
end
|
26
|
+
|
11
27
|
task :clean do
|
28
|
+
sys.rm_rf %w(dt)
|
12
29
|
sys.rm_f Dir["*t"]
|
13
30
|
end
|
14
31
|
|
@@ -13,7 +13,7 @@ class TestSubdirs < Test::Unit::TestCase
|
|
13
13
|
end
|
14
14
|
def teardown
|
15
15
|
capture_std do
|
16
|
-
assert_equal(Rant.run("clean")
|
16
|
+
assert_equal(0, Rant.run("clean"))
|
17
17
|
end
|
18
18
|
created = Dir["**/*t"]
|
19
19
|
assert(created.empty?)
|
@@ -80,7 +80,7 @@ class TestSubdirs < Test::Unit::TestCase
|
|
80
80
|
assert(test(?f, "t"))
|
81
81
|
end
|
82
82
|
def test_import
|
83
|
-
run_import %w(--auto ant)
|
83
|
+
run_import %w(-q --auto ant)
|
84
84
|
assert_equal($?, 0)
|
85
85
|
capture_std do
|
86
86
|
assert_nothing_raised {
|
@@ -93,4 +93,48 @@ class TestSubdirs < Test::Unit::TestCase
|
|
93
93
|
ensure
|
94
94
|
File.delete "ant" if File.exist? "ant"
|
95
95
|
end
|
96
|
+
def test_directory
|
97
|
+
capture_std do
|
98
|
+
assert_equal(0, Rant.run("sub2/sub/dt/dt"))
|
99
|
+
end
|
100
|
+
assert(test(?d, "sub2/sub/dt"))
|
101
|
+
assert(test(?d, "sub2/sub/dt/dt"))
|
102
|
+
capture_std do
|
103
|
+
assert_equal(0, Rant.run("sub2/sub/dt/dt"))
|
104
|
+
end
|
105
|
+
end
|
106
|
+
def test_lighttask
|
107
|
+
capture_std do
|
108
|
+
assert_equal(0, Rant.run("sub2/sub/lt"))
|
109
|
+
end
|
110
|
+
assert(test(?f, "sub2/sub/lt"))
|
111
|
+
capture_std do
|
112
|
+
assert_equal(0, Rant.run("sub2/sub/lt"))
|
113
|
+
end
|
114
|
+
end
|
115
|
+
def test_gen_task
|
116
|
+
capture_std do
|
117
|
+
assert_equal(0, Rant.run("sub2/sub/gt"))
|
118
|
+
end
|
119
|
+
assert(test(?f, "sub2/sub/gt"))
|
120
|
+
assert(test(?d, "sub2/sub/dt"))
|
121
|
+
assert(!test(?d, "sub2/sub/dt/dt"))
|
122
|
+
capture_std do
|
123
|
+
assert_equal(0, Rant.run("sub2/sub/gt"))
|
124
|
+
end
|
125
|
+
assert(!test(?d, "sub2/sub/dt/dt"))
|
126
|
+
end
|
127
|
+
def test_param_default
|
128
|
+
capture_std do
|
129
|
+
assert_equal(0, Rant.run("sub2/sub/create_param"))
|
130
|
+
end
|
131
|
+
assert(test(?f, "sub2/sub/param_default.t"))
|
132
|
+
end
|
133
|
+
def test_param_override
|
134
|
+
capture_std do
|
135
|
+
assert_equal(0, Rant.run(
|
136
|
+
%w(sub2/sub/create_param param=param.t)))
|
137
|
+
end
|
138
|
+
assert(test(?f, "sub2/sub/param.t"))
|
139
|
+
end
|
96
140
|
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
|
2
|
+
require 'test/unit'
|
3
|
+
require 'rant/rantlib'
|
4
|
+
require 'tutil'
|
5
|
+
require 'fileutils'
|
6
|
+
|
7
|
+
# Ensure we run in testproject directory.
|
8
|
+
$testDir ||= File.expand_path(File.dirname(__FILE__))
|
9
|
+
|
10
|
+
class TestDirTask < Test::Unit::TestCase
|
11
|
+
Directory = Rant::Generators::Directory
|
12
|
+
def setup
|
13
|
+
Dir.chdir($testDir) unless Dir.pwd == $testDir
|
14
|
+
@rac = Rant::RantApp.new
|
15
|
+
@cx = @rac.context
|
16
|
+
end
|
17
|
+
def teardown
|
18
|
+
FileUtils.rm_rf Dir["*.t"]
|
19
|
+
end
|
20
|
+
def args(*args)
|
21
|
+
@rac.args.replace(args.flatten)
|
22
|
+
end
|
23
|
+
def test_return
|
24
|
+
dt = @cx.gen Directory, "a.t/b.t"
|
25
|
+
assert(Rant::Worker === dt)
|
26
|
+
assert_equal("a.t/b.t", dt.name,
|
27
|
+
"`gen Directory' should return task for last directory")
|
28
|
+
args "--quiet", "a.t/b.t"
|
29
|
+
@rac.run
|
30
|
+
assert(test(?d, "a.t"))
|
31
|
+
assert(test(?d, "a.t/b.t"))
|
32
|
+
end
|
33
|
+
end
|
data/test/test_filelist.rb
CHANGED
@@ -52,6 +52,37 @@ class TestFileList < Test::Unit::TestCase
|
|
52
52
|
assert(!l.include?(f))
|
53
53
|
}
|
54
54
|
end
|
55
|
+
def test_ignore
|
56
|
+
l = fl
|
57
|
+
r = l.ignore "CVS"
|
58
|
+
assert_same(l, r)
|
59
|
+
inc_list = %w(
|
60
|
+
CVS_ a/b a
|
61
|
+
).map! { |f| f.tr "/", File::SEPARATOR }
|
62
|
+
not_inc_list = %w(
|
63
|
+
CVS a/CVS a/CVS/b CVS/CVS //CVS /CVS/ /a/b/CVS/c
|
64
|
+
).map! { |f| f.tr "/", File::SEPARATOR }
|
65
|
+
l.concat(not_inc_list + inc_list)
|
66
|
+
inc_list.each { |f|
|
67
|
+
assert(l.include?(f))
|
68
|
+
}
|
69
|
+
not_inc_list.each { |f|
|
70
|
+
assert(!l.include?(f))
|
71
|
+
}
|
72
|
+
end
|
73
|
+
def test_ignore_more
|
74
|
+
FileUtils.mkdir "fl.t"
|
75
|
+
l = fl "fl.t/*", "fl.t", "*.t"
|
76
|
+
touch_temp %w(a.t fl.t/CVS fl.t/a~) do
|
77
|
+
l.ignore(/\~$/, "CVS")
|
78
|
+
assert(l.include?("fl.t"))
|
79
|
+
assert(l.include?("a.t"))
|
80
|
+
assert(!l.include?("fl.t/a~"))
|
81
|
+
assert(!l.include?("fl.t/CVS"))
|
82
|
+
end
|
83
|
+
ensure
|
84
|
+
FileUtils.rm_rf "fl.t"
|
85
|
+
end
|
55
86
|
def test_initialize
|
56
87
|
touch_temp %w(1.t 2.tt) do
|
57
88
|
assert(fl("*.t").include?("1.t"),
|
@@ -121,6 +152,10 @@ class TestFileList < Test::Unit::TestCase
|
|
121
152
|
l = l1 + l2
|
122
153
|
assert(l.include?("1.ta"))
|
123
154
|
assert_equal(3, l.size)
|
155
|
+
assert(!l1.include?("1.tb"))
|
156
|
+
assert_equal(2, l1.size)
|
157
|
+
assert(!l2.include?("2.t"))
|
158
|
+
assert_equal(1, l2.size)
|
124
159
|
end
|
125
160
|
end
|
126
161
|
def test_glob
|
@@ -140,4 +175,50 @@ class TestFileList < Test::Unit::TestCase
|
|
140
175
|
assert(l.include?("t.t2"))
|
141
176
|
end
|
142
177
|
end
|
178
|
+
def test_rac_sys_glob
|
179
|
+
rac = Rant::RantApp.new
|
180
|
+
cx = rac.context
|
181
|
+
FileUtils.mkdir "fl.t"
|
182
|
+
l = cx.sys.glob "fl.t/*", "fl.t", "*.t"
|
183
|
+
touch_temp %w(a.t fl.t/CVS fl.t/a~) do
|
184
|
+
assert(l.include?("fl.t"))
|
185
|
+
assert(l.include?("a.t"))
|
186
|
+
assert(l.include?("fl.t/a~"))
|
187
|
+
assert(l.include?("fl.t/CVS"))
|
188
|
+
end
|
189
|
+
ensure
|
190
|
+
FileUtils.rm_rf "fl.t"
|
191
|
+
end
|
192
|
+
def test_rac_sys_glob_ignore
|
193
|
+
rac = Rant::RantApp.new
|
194
|
+
cx = rac.context
|
195
|
+
cx.var["ignore"] = ["CVS", /\~$/]
|
196
|
+
FileUtils.mkdir "fl.t"
|
197
|
+
l = cx.sys.glob "fl.t/*", "fl.t", "*.t"
|
198
|
+
touch_temp %w(a.t fl.t/CVS fl.t/a~) do
|
199
|
+
assert(l.include?("fl.t"))
|
200
|
+
assert(l.include?("a.t"))
|
201
|
+
assert(!l.include?("fl.t/a~"))
|
202
|
+
assert(!l.include?("fl.t/CVS"))
|
203
|
+
end
|
204
|
+
ensure
|
205
|
+
FileUtils.rm_rf "fl.t"
|
206
|
+
end
|
207
|
+
def test_sys_glob_late_ignore
|
208
|
+
rac = Rant::RantApp.new
|
209
|
+
cx = rac.context
|
210
|
+
FileUtils.mkdir "fl.t"
|
211
|
+
l = cx.sys["fl.t/*", "fl.t", "*.t"]
|
212
|
+
touch_temp %w(a.t fl.t/CVS fl.t/a~) do
|
213
|
+
cx.var["ignore"] = ["CVS", /\~$/]
|
214
|
+
assert(l.include?("fl.t"))
|
215
|
+
assert(l.include?("a.t"))
|
216
|
+
assert(!l.include?("fl.t/a~"))
|
217
|
+
assert(!l.include?("fl.t/CVS"))
|
218
|
+
end
|
219
|
+
l[0] = "CVS"
|
220
|
+
assert(!l.include?("CVS"))
|
221
|
+
ensure
|
222
|
+
FileUtils.rm_rf "fl.t"
|
223
|
+
end
|
143
224
|
end
|
data/test/test_filetask.rb
CHANGED
@@ -20,7 +20,7 @@ class TestFileTask < Test::Unit::TestCase
|
|
20
20
|
end
|
21
21
|
def test_needed_no_dep
|
22
22
|
run = false
|
23
|
-
t = Rant.file $test_filetask_file do
|
23
|
+
t = Rant.rac.file $test_filetask_file do
|
24
24
|
run = true
|
25
25
|
end
|
26
26
|
assert(!t.needed?,
|
@@ -29,11 +29,11 @@ class TestFileTask < Test::Unit::TestCase
|
|
29
29
|
end
|
30
30
|
def test_single_dep
|
31
31
|
tr = false
|
32
|
-
t = Rant.task :t do
|
32
|
+
t = Rant.rac.task :t do
|
33
33
|
tr = true
|
34
34
|
end
|
35
35
|
run = false
|
36
|
-
f = Rant.file "testfile" => :t do
|
36
|
+
f = Rant.rac.file "testfile" => :t do
|
37
37
|
run = true
|
38
38
|
end
|
39
39
|
f.invoke
|
@@ -41,13 +41,13 @@ class TestFileTask < Test::Unit::TestCase
|
|
41
41
|
assert(run)
|
42
42
|
end
|
43
43
|
def test_prerequisites
|
44
|
-
Rant.file "a" do
|
44
|
+
Rant.rac.file "a" do
|
45
45
|
true
|
46
46
|
end
|
47
|
-
Rant.file "b" do
|
47
|
+
Rant.rac.file "b" do
|
48
48
|
true
|
49
49
|
end
|
50
|
-
f = Rant.file "c" => %w(a b) do |t|
|
50
|
+
f = Rant.rac.file "c" => %w(a b) do |t|
|
51
51
|
assert_equal(t.prerequisites, %w(a b),
|
52
52
|
"prerequisites should always be an array of _strings_")
|
53
53
|
true
|
data/test/test_rant_interface.rb
CHANGED
@@ -29,15 +29,16 @@ class TestRantInterface < Test::Unit::TestCase
|
|
29
29
|
end
|
30
30
|
def test_envvar_on_cmdline
|
31
31
|
@app = Rant::RantApp.new("VAR=VAL")
|
32
|
+
@app.context.var.env "VAR"
|
32
33
|
assert_equal(@app.run, 0)
|
33
34
|
assert_equal(ENV["VAR"], "VAL",
|
34
|
-
"rant should set arguments of form VAR=VAL in
|
35
|
+
"rant should set arguments of form VAR=VAL in var")
|
35
36
|
end
|
36
37
|
def test_envvar_on_cmdline_lc
|
37
38
|
@app = Rant::RantApp.new("var2=val2")
|
38
39
|
assert_equal(@app.run, 0)
|
39
|
-
assert_equal(
|
40
|
-
"rant should set arguments of form var2=val2 in
|
40
|
+
assert_equal(@app.context.var["var2"], "val2",
|
41
|
+
"rant should set arguments of form var2=val2 in var")
|
41
42
|
end
|
42
43
|
def test_opt_targets
|
43
44
|
@app = Rant::RantApp.new("--tasks")
|
data/test/test_rule.rb
ADDED
@@ -0,0 +1,67 @@
|
|
1
|
+
|
2
|
+
require 'test/unit'
|
3
|
+
require 'rant/rantlib'
|
4
|
+
require 'tutil'
|
5
|
+
require 'fileutils'
|
6
|
+
|
7
|
+
# Ensure we run in testproject directory.
|
8
|
+
$testDir ||= File.expand_path(File.dirname(__FILE__))
|
9
|
+
|
10
|
+
class TestRule < Test::Unit::TestCase
|
11
|
+
def setup
|
12
|
+
Dir.chdir($testDir) unless Dir.pwd == $testDir
|
13
|
+
end
|
14
|
+
def teardown
|
15
|
+
FileUtils.rm_rf Dir["*.t*"]
|
16
|
+
FileUtils.rm_rf Dir["*.lt"]
|
17
|
+
FileUtils.rm_rf Dir["*.rt"]
|
18
|
+
FileUtils.rm_rf Dir["*.rtt"]
|
19
|
+
end
|
20
|
+
def test_target_and_source_as_symbol
|
21
|
+
FileUtils.touch "r.t"
|
22
|
+
FileUtils.touch "r2.t"
|
23
|
+
capture_std do
|
24
|
+
assert_equal(0, Rant.run("-frule.rf", "r.tt", "r2.tt"))
|
25
|
+
end
|
26
|
+
assert(test(?f, "r.t"))
|
27
|
+
assert(test(?f, "r2.t"))
|
28
|
+
end
|
29
|
+
def test_rule_depends_on_rule
|
30
|
+
capture_std do
|
31
|
+
assert_equal(0, Rant.run("-frule.rf", "r.tt", "r2.tt"))
|
32
|
+
end
|
33
|
+
assert(test(?f, "r.t"))
|
34
|
+
assert(test(?f, "r2.t"))
|
35
|
+
end
|
36
|
+
def test_src_block
|
37
|
+
FileUtils.touch "r.rtt"
|
38
|
+
capture_std do
|
39
|
+
assert_equal(0, Rant.run("-frule.rf", "r.rt"))
|
40
|
+
end
|
41
|
+
assert(test(?f, "r.rtt"))
|
42
|
+
assert(test(?f, "r.rt"))
|
43
|
+
end
|
44
|
+
def test_src_block_multiple_deps
|
45
|
+
capture_std do
|
46
|
+
assert_equal(0, Rant.run("-frule.rf", "r.lt"))
|
47
|
+
end
|
48
|
+
assert(test(?f, "r.t"))
|
49
|
+
assert(test(?f, "r.tt"))
|
50
|
+
assert(test(?f, "r.lt"))
|
51
|
+
end
|
52
|
+
if Rant::Env.find_bin("cc") && Rant::Env.find_bin("gcc")
|
53
|
+
# Note: we are assuming that "cc" invokes "gcc"!
|
54
|
+
def test_cc
|
55
|
+
FileUtils.touch "a.t.c"
|
56
|
+
capture_std do
|
57
|
+
assert_equal(0, Rant.run("a.t.o", "-frule.rf"))
|
58
|
+
end
|
59
|
+
assert(test(?f, "a.t.o"))
|
60
|
+
end
|
61
|
+
else
|
62
|
+
$stderr.puts "*** cc/gcc not available, less rule tests ***"
|
63
|
+
def test_dummy
|
64
|
+
assert(true)
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|