railroady 1.3.0 → 1.3.1
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.
- checksums.yaml +4 -4
- data/Guardfile +0 -1
- data/Rakefile +5 -5
- data/bin/railroady +6 -7
- data/lib/railroady.rb +2 -2
- data/lib/railroady/aasm_diagram.rb +24 -29
- data/lib/railroady/app_diagram.rb +16 -23
- data/lib/railroady/controllers_diagram.rb +33 -40
- data/lib/railroady/diagram_graph.rb +45 -55
- data/lib/railroady/models_diagram.rb +37 -56
- data/lib/railroady/options_struct.rb +99 -103
- data/lib/railroady/railtie.rb +4 -5
- data/lib/railroady/version.rb +1 -1
- data/railroady.gemspec +12 -13
- data/tasks/railroady.rake +20 -29
- data/test/file_fixture/app/controllers/application_controller.rb +1 -1
- data/test/lib/railroady/aasm_diagram_spec.rb +14 -16
- data/test/lib/railroady/app_diagram_spec.rb +1 -2
- data/test/lib/railroady/controllers_diagram_spec.rb +16 -19
- data/test/lib/railroady/core_ext_spec.rb +2 -2
- data/test/lib/railroady/diagram_graph_spec.rb +6 -2
- data/test/lib/railroady/models_diagram_spec.rb +18 -20
- data/test/spec_helper.rb +1 -1
- metadata +4 -3
data/lib/railroady/railtie.rb
CHANGED
@@ -2,11 +2,10 @@ require 'railroady'
|
|
2
2
|
require 'rails'
|
3
3
|
module RailRoady
|
4
4
|
class Railtie < Rails::Railtie
|
5
|
-
|
6
5
|
rake_tasks do
|
7
|
-
|
8
|
-
|
9
|
-
|
6
|
+
f = File.join(File.dirname(__FILE__), '..', '..', 'tasks', 'railroady.rake')
|
7
|
+
load f
|
8
|
+
# load 'tasks/railroady.rake'
|
10
9
|
end
|
11
10
|
end
|
12
|
-
end
|
11
|
+
end
|
data/lib/railroady/version.rb
CHANGED
data/railroady.gemspec
CHANGED
@@ -4,23 +4,22 @@ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
|
4
4
|
require 'railroady/version'
|
5
5
|
|
6
6
|
Gem::Specification.new do |spec|
|
7
|
-
spec.name =
|
7
|
+
spec.name = 'railroady'
|
8
8
|
spec.version = RailRoady::VERSION
|
9
|
-
spec.authors = [
|
9
|
+
spec.authors = ['Preston Lee', 'Tobias Crawley', 'Peter Hoeg', 'Javier Smaldone']
|
10
10
|
spec.description = "Ruby on Rails 3/4 model and controller UML class diagram generator. Originally based on the 'railroad' plugin and contributions of many others. (`sudo port install graphviz` before use!)"
|
11
|
-
spec.email = [
|
12
|
-
spec.summary =
|
13
|
-
spec.homepage =
|
14
|
-
spec.license =
|
11
|
+
spec.email = ['preston.lee@prestonlee.com', 'tcrawley@gmail.com', 'peter@hoeg.com', 'p.hoeg@northwind.sg', 'javier@smaldone.com.ar']
|
12
|
+
spec.summary = 'Ruby on Rails 3/4 model and controller UML class diagram generator.'
|
13
|
+
spec.homepage = 'http://github.com/preston/railroady'
|
14
|
+
spec.license = 'GPLv2'
|
15
15
|
|
16
|
-
spec.files = `git ls-files`.split(
|
16
|
+
spec.files = `git ls-files`.split($INPUT_RECORD_SEPARATOR)
|
17
17
|
spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
|
18
18
|
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
19
|
-
spec.require_paths = [
|
20
|
-
|
21
|
-
spec.add_development_dependency "bundler"
|
22
|
-
spec.add_development_dependency "rake"
|
23
|
-
spec.add_development_dependency "minitest"
|
24
|
-
spec.add_development_dependency "activesupport"
|
19
|
+
spec.require_paths = ['lib']
|
25
20
|
|
21
|
+
spec.add_development_dependency 'bundler'
|
22
|
+
spec.add_development_dependency 'rake'
|
23
|
+
spec.add_development_dependency 'minitest'
|
24
|
+
spec.add_development_dependency 'activesupport'
|
26
25
|
end
|
data/tasks/railroady.rake
CHANGED
@@ -31,15 +31,13 @@ module RailRoady
|
|
31
31
|
when /mac|darwin|bsd/
|
32
32
|
return "sed -E '#{regex}'"
|
33
33
|
else
|
34
|
-
|
34
|
+
fail NotImplementedError
|
35
35
|
end
|
36
36
|
end
|
37
|
-
|
38
37
|
end
|
39
38
|
end
|
40
39
|
|
41
40
|
namespace :diagram do
|
42
|
-
|
43
41
|
@MODELS_ALL = RailRoady::RakeHelpers.full_path("models_complete.#{RailRoady::RakeHelpers.format}").freeze
|
44
42
|
@MODELS_BRIEF = RailRoady::RakeHelpers.full_path("models_brief.#{RailRoady::RakeHelpers.format}").freeze
|
45
43
|
@CONTROLLERS_ALL = RailRoady::RakeHelpers.full_path("controllers_complete.#{RailRoady::RakeHelpers.format}").freeze
|
@@ -49,14 +47,13 @@ namespace :diagram do
|
|
49
47
|
namespace :setup do
|
50
48
|
desc 'Perform any setup needed for the gem'
|
51
49
|
task :create_new_doc_folder_if_needed do
|
52
|
-
Dir.mkdir('doc') unless File.
|
50
|
+
Dir.mkdir('doc') unless File.exist?('doc')
|
53
51
|
end
|
54
52
|
end
|
55
53
|
|
56
54
|
namespace :models do
|
57
|
-
|
58
55
|
desc 'Generated brief and complete class diagrams for all models.'
|
59
|
-
task :
|
56
|
+
task all: ['diagram:setup:create_new_doc_folder_if_needed', 'diagram:models:complete', 'diagram:models:brief']
|
60
57
|
|
61
58
|
desc 'Generates an class diagram for all models.'
|
62
59
|
task :complete do
|
@@ -78,21 +75,18 @@ namespace :diagram do
|
|
78
75
|
puts "Generating #{f}"
|
79
76
|
sh "railroady -ilamzM | #{@SED} | dot -T#{RailRoady::RakeHelpers.format} > #{f}"
|
80
77
|
end
|
81
|
-
|
78
|
+
|
82
79
|
desc 'Generates an abbreviated class diagram for all models including those in engines'
|
83
80
|
task :brief_with_engines do
|
84
81
|
f = @MODELS_BRIEF
|
85
82
|
puts "Generating #{f}"
|
86
83
|
sh "railroady -bilamzM | #{@SED} | dot -T#{RailRoady::RakeHelpers.format} > #{f}"
|
87
84
|
end
|
88
|
-
|
89
|
-
|
90
85
|
end
|
91
86
|
|
92
87
|
namespace :controllers do
|
93
|
-
|
94
88
|
desc 'Generated brief and complete class diagrams for all controllers.'
|
95
|
-
task :
|
89
|
+
task all: ['diagram:setup:create_new_doc_folder_if_needed', 'diagram:controllers:complete', 'diagram:controllers:brief']
|
96
90
|
|
97
91
|
desc 'Generates an class diagram for all controllers.'
|
98
92
|
task :complete do
|
@@ -107,40 +101,37 @@ namespace :diagram do
|
|
107
101
|
puts "Generating #{f}"
|
108
102
|
sh "railroady -blC | #{@SED} | neato -T#{RailRoady::RakeHelpers.format} > #{f}"
|
109
103
|
end
|
110
|
-
|
104
|
+
|
111
105
|
desc 'Generates an class diagram for all controllers including those in engines'
|
112
|
-
task :complete_with_engines do
|
106
|
+
task :complete_with_engines do
|
113
107
|
f = @CONTROLLERS_ALL
|
114
108
|
puts "Generating #{f}"
|
115
109
|
sh "railroady -ilC --engine-controllers | #{@SED} | neato -T#{RailRoady::RakeHelpers.format} > #{f}"
|
116
110
|
end
|
117
|
-
|
111
|
+
|
118
112
|
desc 'Generates an abbreviated class diagram for all controllers including those in engines.'
|
119
113
|
task :brief_with_engines do
|
120
114
|
f = @CONTROLLERS_BRIEF
|
121
115
|
puts "Generating #{f}"
|
122
116
|
sh "railroady -bilC --engine-controllers | #{@SED} | neato -T#{RailRoady::RakeHelpers.format} > #{f}"
|
123
117
|
end
|
124
|
-
|
125
|
-
|
126
118
|
end
|
127
119
|
|
128
120
|
desc 'Generates all class diagrams.'
|
129
121
|
task all: [
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
122
|
+
'diagram:setup:create_new_doc_folder_if_needed',
|
123
|
+
'diagram:models:complete',
|
124
|
+
'diagram:models:brief',
|
125
|
+
'diagram:controllers:complete',
|
126
|
+
'diagram:controllers:brief'
|
127
|
+
]
|
136
128
|
|
137
129
|
desc 'Generates all class diagrams including those in engines'
|
138
130
|
task all_with_engines: [
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
|
131
|
+
'diagram:setup:create_new_doc_folder_if_needed',
|
132
|
+
'diagram:models:complete_with_engines',
|
133
|
+
'diagram:models:brief_with_engines',
|
134
|
+
'diagram:controllers:complete_with_engines',
|
135
|
+
'diagram:controllers:brief_with_engines'
|
136
|
+
]
|
146
137
|
end
|
@@ -1,2 +1,2 @@
|
|
1
1
|
class ApplicationController < ActionController::Base
|
2
|
-
end
|
2
|
+
end
|
@@ -2,55 +2,53 @@ require File.expand_path(File.dirname(__FILE__) + '../../../spec_helper')
|
|
2
2
|
|
3
3
|
describe AasmDiagram do
|
4
4
|
describe 'file processing' do
|
5
|
-
|
6
5
|
it 'should select all the files under the models dir' do
|
7
6
|
ad = AasmDiagram.new
|
8
|
-
files = ad.get_files(
|
7
|
+
files = ad.get_files('test/file_fixture/')
|
9
8
|
files.size.must_equal 3
|
10
9
|
end
|
11
10
|
|
12
11
|
it 'should include concerns if specified' do
|
13
|
-
options = OptionsStruct.new(:
|
12
|
+
options = OptionsStruct.new(include_concerns: true)
|
14
13
|
ad = AasmDiagram.new(options)
|
15
|
-
files = ad.get_files(
|
14
|
+
files = ad.get_files('test/file_fixture/')
|
16
15
|
files.size.must_equal 4
|
17
16
|
end
|
18
17
|
|
19
18
|
it 'should exclude a specific file' do
|
20
|
-
options = OptionsStruct.new(:
|
19
|
+
options = OptionsStruct.new(exclude: ['test/file_fixture/app/models/dummy1.rb'])
|
21
20
|
ad = AasmDiagram.new(options)
|
22
|
-
files = ad.get_files(
|
21
|
+
files = ad.get_files('test/file_fixture/')
|
23
22
|
files.size.must_equal 2
|
24
23
|
end
|
25
24
|
|
26
25
|
it 'should exclude a glob pattern of files' do
|
27
|
-
options = OptionsStruct.new(:
|
26
|
+
options = OptionsStruct.new(exclude: ['test/file_fixture/app/models/*/*.rb'])
|
28
27
|
ad = AasmDiagram.new(options)
|
29
|
-
files = ad.get_files(
|
28
|
+
files = ad.get_files('test/file_fixture/')
|
30
29
|
files.size.must_equal 2
|
31
30
|
end
|
32
31
|
|
33
32
|
it 'should include only specific file' do
|
34
|
-
options = OptionsStruct.new(:
|
33
|
+
options = OptionsStruct.new(specify: ['test/file_fixture/app/models/sub-dir/sub_dummy.rb'])
|
35
34
|
ad = AasmDiagram.new(options)
|
36
|
-
files = ad.get_files(
|
35
|
+
files = ad.get_files('test/file_fixture/')
|
37
36
|
files.size.must_equal 1
|
38
37
|
end
|
39
38
|
|
40
39
|
it 'should include only specified files' do
|
41
|
-
options = OptionsStruct.new(:
|
40
|
+
options = OptionsStruct.new(specify: ['test/file_fixture/app/models/{dummy1.rb,sub-dir/sub_dummy.rb}'])
|
42
41
|
ad = AasmDiagram.new(options)
|
43
|
-
files = ad.get_files(
|
42
|
+
files = ad.get_files('test/file_fixture/')
|
44
43
|
files.size.must_equal 2
|
45
44
|
end
|
46
45
|
|
47
46
|
it 'should include only specified files and exclude specified files' do
|
48
|
-
options = OptionsStruct.new(:
|
49
|
-
:
|
47
|
+
options = OptionsStruct.new(specify: ['test/file_fixture/app/models/{dummy1.rb,sub-dir/sub_dummy.rb}'],
|
48
|
+
exclude: ['test/file_fixture/app/models/sub-dir/sub_dummy.rb'])
|
50
49
|
ad = AasmDiagram.new(options)
|
51
|
-
files = ad.get_files(
|
50
|
+
files = ad.get_files('test/file_fixture/')
|
52
51
|
files.size.must_equal 1
|
53
52
|
end
|
54
|
-
|
55
53
|
end
|
56
54
|
end
|
@@ -4,12 +4,11 @@ describe AppDiagram do
|
|
4
4
|
describe 'file name processing' do
|
5
5
|
it 'should extract a simple name' do
|
6
6
|
ad = AppDiagram.new
|
7
|
-
name = ad.instance_eval {extract_class_name('app/models/test_this.rb')}
|
7
|
+
name = ad.instance_eval { extract_class_name('app/models/test_this.rb') }
|
8
8
|
name.must_equal 'TestThis'
|
9
9
|
end
|
10
10
|
it 'should constantize a name' do
|
11
11
|
'String'.constantize.must_equal String
|
12
12
|
end
|
13
|
-
|
14
13
|
end
|
15
14
|
end
|
@@ -2,58 +2,55 @@ require File.expand_path(File.dirname(__FILE__) + '../../../spec_helper')
|
|
2
2
|
|
3
3
|
describe ControllersDiagram do
|
4
4
|
describe 'file processing' do
|
5
|
-
|
6
5
|
it 'should select all the files under the controllers dir' do
|
7
6
|
cd = ControllersDiagram.new
|
8
|
-
files = cd.get_files(
|
7
|
+
files = cd.get_files('test/file_fixture/')
|
9
8
|
files.size.must_equal 4
|
10
9
|
end
|
11
10
|
|
12
11
|
it 'should exclude a specific file' do
|
13
|
-
options = OptionsStruct.new(:
|
12
|
+
options = OptionsStruct.new(exclude: ['test/file_fixture/app/controllers/dummy1_controller.rb'])
|
14
13
|
cd = ControllersDiagram.new(options)
|
15
|
-
files = cd.get_files(
|
14
|
+
files = cd.get_files('test/file_fixture/')
|
16
15
|
files.size.must_equal 3
|
17
16
|
end
|
18
17
|
|
19
18
|
it 'should exclude a glob pattern of files' do
|
20
|
-
options = OptionsStruct.new(:
|
19
|
+
options = OptionsStruct.new(exclude: ['test/file_fixture/app/controllers/sub-dir/*.rb'])
|
21
20
|
cd = ControllersDiagram.new(options)
|
22
|
-
files = cd.get_files(
|
21
|
+
files = cd.get_files('test/file_fixture/')
|
23
22
|
files.size.must_equal 3
|
24
23
|
end
|
25
24
|
|
26
25
|
it 'should include only specific file' do
|
27
|
-
options = OptionsStruct.new(:
|
26
|
+
options = OptionsStruct.new(specify: ['test/file_fixture/app/controllers/sub-dir/sub_dummy_controller.rb'])
|
28
27
|
cd = ControllersDiagram.new(options)
|
29
|
-
files = cd.get_files(
|
28
|
+
files = cd.get_files('test/file_fixture/')
|
30
29
|
files.size.must_equal 1
|
31
30
|
end
|
32
31
|
|
33
32
|
it 'should include only specified files' do
|
34
|
-
options = OptionsStruct.new(:
|
33
|
+
options = OptionsStruct.new(specify: ['test/file_fixture/app/controllers/{dummy1_*.rb,sub-dir/sub_dummy_controller.rb}'])
|
35
34
|
cd = ControllersDiagram.new(options)
|
36
|
-
files = cd.get_files(
|
35
|
+
files = cd.get_files('test/file_fixture/')
|
37
36
|
files.size.must_equal 2
|
38
37
|
end
|
39
38
|
|
40
39
|
it 'should include only specified files and exclude specified files' do
|
41
|
-
options = OptionsStruct.new(:
|
42
|
-
:
|
40
|
+
options = OptionsStruct.new(specify: ['test/file_fixture/app/controllers/{dummy1_*.rb,sub-dir/sub_dummy_controller.rb}'],
|
41
|
+
exclude: ['test/file_fixture/app/controllers/sub-dir/sub_dummy_controller.rb'])
|
43
42
|
cd = ControllersDiagram.new(options)
|
44
|
-
files = cd.get_files(
|
43
|
+
files = cd.get_files('test/file_fixture/')
|
45
44
|
files.size.must_equal 1
|
46
45
|
end
|
47
46
|
|
48
|
-
it
|
49
|
-
options = OptionsStruct.new(:
|
47
|
+
it 'should include engine files' do
|
48
|
+
options = OptionsStruct.new(engine_controllers: true)
|
50
49
|
md = ControllersDiagram.new(options)
|
51
|
-
engines = [OpenStruct.new(:
|
50
|
+
engines = [OpenStruct.new(root: 'test/file_fixture/lib')]
|
52
51
|
md.stub(:engines, engines) do
|
53
|
-
md.get_files.must_include(
|
52
|
+
md.get_files.must_include('test/file_fixture/lib/app/controllers/dummy/dummy_controller.rb')
|
54
53
|
end
|
55
54
|
end
|
56
|
-
|
57
|
-
|
58
55
|
end
|
59
56
|
end
|
@@ -2,11 +2,11 @@ require File.expand_path(File.dirname(__FILE__) + '../../../spec_helper')
|
|
2
2
|
|
3
3
|
describe String do
|
4
4
|
describe '#camelize' do
|
5
|
-
it
|
5
|
+
it 'should upper-camelcase a lower case and underscored word' do
|
6
6
|
'lower_case_and_underscored_word'.camelize.must_equal 'LowerCaseAndUnderscoredWord'
|
7
7
|
end
|
8
8
|
|
9
|
-
it
|
9
|
+
it 'should lower-camelcase a lower case and underscored word when the :lower parameter is passed' do
|
10
10
|
'lower_case_and_underscored_word'.camelize(:lower).must_equal 'lowerCaseAndUnderscoredWord'
|
11
11
|
end
|
12
12
|
end
|
@@ -5,20 +5,24 @@ module CustomDotMatchers
|
|
5
5
|
def initialize(expected)
|
6
6
|
@expected = expected
|
7
7
|
end
|
8
|
+
|
8
9
|
def matches?(target)
|
9
10
|
@target = target
|
10
11
|
return false unless @target =~ /\[(.*)\]/
|
11
|
-
@options =
|
12
|
+
@options = Regexp.last_match(1)
|
12
13
|
@options == @expected
|
13
14
|
end
|
15
|
+
|
14
16
|
def failure_message
|
15
17
|
"expected '#{@target.strip}' to have options '[#{@expected}]'"
|
16
18
|
end
|
19
|
+
|
17
20
|
def negative_failure_message
|
18
21
|
"expected '#{@target.strip}' to not have options '[#{@expected}]'"
|
19
22
|
end
|
23
|
+
|
20
24
|
def description
|
21
|
-
|
25
|
+
'have dot options'
|
22
26
|
end
|
23
27
|
end
|
24
28
|
def have_dot_options(expected)
|
@@ -2,64 +2,62 @@ require File.expand_path(File.dirname(__FILE__) + '../../../spec_helper')
|
|
2
2
|
|
3
3
|
describe ModelsDiagram do
|
4
4
|
describe 'file processing' do
|
5
|
-
|
6
5
|
it 'should select all the files under the models dir' do
|
7
6
|
md = ModelsDiagram.new
|
8
|
-
files = md.get_files(
|
7
|
+
files = md.get_files('test/file_fixture/')
|
9
8
|
files.size.must_equal 3
|
10
9
|
end
|
11
10
|
|
12
11
|
it 'should include concerns if specified' do
|
13
|
-
options = OptionsStruct.new(:
|
12
|
+
options = OptionsStruct.new(include_concerns: true)
|
14
13
|
ad = ModelsDiagram.new(options)
|
15
|
-
files = ad.get_files(
|
14
|
+
files = ad.get_files('test/file_fixture/')
|
16
15
|
files.size.must_equal 4
|
17
16
|
end
|
18
17
|
|
19
18
|
it 'should exclude a specific file' do
|
20
|
-
options = OptionsStruct.new(:
|
19
|
+
options = OptionsStruct.new(exclude: ['test/file_fixture/app/models/dummy1.rb'])
|
21
20
|
md = ModelsDiagram.new(options)
|
22
|
-
files = md.get_files(
|
21
|
+
files = md.get_files('test/file_fixture/')
|
23
22
|
files.size.must_equal 2
|
24
23
|
end
|
25
24
|
|
26
25
|
it 'should exclude a glob pattern of files' do
|
27
|
-
options = OptionsStruct.new(:
|
26
|
+
options = OptionsStruct.new(exclude: ['test/file_fixture/app/models/*/*.rb'])
|
28
27
|
md = ModelsDiagram.new(options)
|
29
|
-
files = md.get_files(
|
28
|
+
files = md.get_files('test/file_fixture/')
|
30
29
|
files.size.must_equal 2
|
31
30
|
end
|
32
31
|
|
33
32
|
it 'should include only specific file' do
|
34
|
-
options = OptionsStruct.new(:
|
33
|
+
options = OptionsStruct.new(specify: ['test/file_fixture/app/models/sub-dir/sub_dummy.rb'])
|
35
34
|
md = ModelsDiagram.new(options)
|
36
|
-
files = md.get_files(
|
35
|
+
files = md.get_files('test/file_fixture/')
|
37
36
|
files.size.must_equal 1
|
38
37
|
end
|
39
38
|
|
40
39
|
it 'should include only specified files' do
|
41
|
-
options = OptionsStruct.new(:
|
40
|
+
options = OptionsStruct.new(specify: ['test/file_fixture/app/models/{dummy1.rb,sub-dir/sub_dummy.rb}'])
|
42
41
|
md = ModelsDiagram.new(options)
|
43
|
-
files = md.get_files(
|
42
|
+
files = md.get_files('test/file_fixture/')
|
44
43
|
files.size.must_equal 2
|
45
44
|
end
|
46
45
|
|
47
46
|
it 'should include only specified files and exclude specified files' do
|
48
|
-
options = OptionsStruct.new(:
|
49
|
-
:
|
47
|
+
options = OptionsStruct.new(specify: ['test/file_fixture/app/models/{dummy1.rb,sub-dir/sub_dummy.rb}'],
|
48
|
+
exclude: ['test/file_fixture/app/models/sub-dir/sub_dummy.rb'])
|
50
49
|
md = ModelsDiagram.new(options)
|
51
|
-
files = md.get_files(
|
50
|
+
files = md.get_files('test/file_fixture/')
|
52
51
|
files.size.must_equal 1
|
53
52
|
end
|
54
53
|
|
55
|
-
it
|
56
|
-
options = OptionsStruct.new(:
|
54
|
+
it 'should include engine files' do
|
55
|
+
options = OptionsStruct.new(engine_models: true)
|
57
56
|
md = ModelsDiagram.new(options)
|
58
|
-
engines = [OpenStruct.new(:
|
57
|
+
engines = [OpenStruct.new(root: 'test/file_fixture/lib')]
|
59
58
|
md.stub(:engines, engines) do
|
60
|
-
md.get_files.must_include(
|
59
|
+
md.get_files.must_include('test/file_fixture/lib/app/models/dummy1.rb')
|
61
60
|
end
|
62
61
|
end
|
63
|
-
|
64
62
|
end
|
65
63
|
end
|