ruby-prof 0.6.0 → 0.7.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (62) hide show
  1. data/CHANGES +54 -1
  2. data/README +134 -7
  3. data/Rakefile +40 -58
  4. data/bin/ruby-prof +21 -6
  5. data/ext/extconf.rb +13 -0
  6. data/ext/measure_allocations.h +16 -1
  7. data/ext/measure_cpu_time.h +15 -3
  8. data/ext/measure_gc_runs.h +76 -0
  9. data/ext/measure_gc_time.h +57 -0
  10. data/ext/measure_memory.h +61 -2
  11. data/ext/measure_process_time.h +13 -2
  12. data/ext/measure_wall_time.h +12 -1
  13. data/ext/mingw/Rakefile +23 -0
  14. data/ext/mingw/build.rake +38 -0
  15. data/ext/ruby_prof.c +685 -633
  16. data/ext/ruby_prof.h +188 -0
  17. data/ext/vc/ruby_prof.sln +20 -0
  18. data/ext/vc/ruby_prof.vcproj +241 -0
  19. data/ext/version.h +4 -0
  20. data/lib/ruby-prof.rb +4 -0
  21. data/lib/ruby-prof/call_info.rb +47 -0
  22. data/lib/ruby-prof/call_tree_printer.rb +9 -1
  23. data/lib/ruby-prof/graph_html_printer.rb +6 -5
  24. data/lib/ruby-prof/graph_printer.rb +3 -2
  25. data/lib/ruby-prof/method_info.rb +85 -0
  26. data/lib/ruby-prof/task.rb +1 -2
  27. data/lib/ruby-prof/test.rb +148 -0
  28. data/rails/environment/profile.rb +24 -0
  29. data/rails/example/example_test.rb +9 -0
  30. data/rails/profile_test_helper.rb +21 -0
  31. data/test/basic_test.rb +173 -80
  32. data/test/duplicate_names_test.rb +2 -3
  33. data/test/exceptions_test.rb +15 -0
  34. data/test/exclude_threads_test.rb +54 -0
  35. data/test/line_number_test.rb +18 -14
  36. data/test/measurement_test.rb +121 -0
  37. data/test/module_test.rb +5 -8
  38. data/test/no_method_class_test.rb +4 -5
  39. data/test/prime.rb +3 -5
  40. data/test/prime_test.rb +1 -12
  41. data/test/printers_test.rb +10 -13
  42. data/test/profile_unit_test.rb +10 -12
  43. data/test/recursive_test.rb +202 -92
  44. data/test/singleton_test.rb +1 -2
  45. data/test/stack_test.rb +138 -0
  46. data/test/start_stop_test.rb +95 -0
  47. data/test/test_suite.rb +7 -3
  48. data/test/thread_test.rb +111 -87
  49. data/test/unique_call_path_test.rb +206 -0
  50. metadata +40 -42
  51. data/ext/extconf.rb.rej +0 -13
  52. data/lib/ruby-prof/call_tree_printer.rb.rej +0 -27
  53. data/lib/ruby-prof/profile_test_case.rb +0 -80
  54. data/rails_plugin/ruby-prof/init.rb +0 -8
  55. data/rails_plugin/ruby-prof/lib/profiling.rb +0 -57
  56. data/test/measure_mode_test.rb +0 -79
  57. data/test/prime1.rb +0 -17
  58. data/test/prime2.rb +0 -26
  59. data/test/prime3.rb +0 -17
  60. data/test/start_test.rb +0 -24
  61. data/test/test_helper.rb +0 -55
  62. data/test/timing_test.rb +0 -133
@@ -0,0 +1,95 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'test/unit'
4
+ require 'ruby-prof'
5
+
6
+ class StartStopTest < Test::Unit::TestCase
7
+ def setup
8
+ # Need to use wall time for this test due to the sleep calls
9
+ RubyProf::measure_mode = RubyProf::WALL_TIME
10
+ end
11
+
12
+ def method1
13
+ RubyProf.start
14
+ method2
15
+ end
16
+
17
+ def method2
18
+ method3
19
+ end
20
+
21
+ def method3
22
+ sleep(2)
23
+ @result = RubyProf.stop
24
+ end
25
+
26
+ def test_different_methods
27
+ method1
28
+
29
+ # Ruby prof should be stopped
30
+ assert_equal(false, RubyProf.running?)
31
+
32
+
33
+ # Length should be 4:
34
+ # StartStopTest#method1
35
+ # StartStopTest#method2
36
+ # StartStopTest#method3
37
+ # Kernel#sleep
38
+
39
+ methods = @result.threads.values.first.sort.reverse
40
+ assert_equal(4, methods.length)
41
+
42
+ # Check StackTest#test_call_sequence
43
+ method = methods[0]
44
+ assert_equal('StartStopTest#method1', method.full_name)
45
+ assert_equal(1, method.called)
46
+ assert_in_delta(2, method.total_time, 0.01)
47
+ assert_in_delta(0, method.wait_time, 0.01)
48
+ assert_in_delta(0, method.self_time, 0.01)
49
+ assert_in_delta(2, method.children_time, 0.01)
50
+ assert_equal(1, method.call_infos.length)
51
+
52
+ call_info = method.call_infos[0]
53
+ assert_equal('StartStopTest#method1', call_info.call_sequence)
54
+ assert_equal(1, call_info.children.length)
55
+
56
+ method = methods[1]
57
+ assert_equal('StartStopTest#method2', method.full_name)
58
+ assert_equal(1, method.called)
59
+ assert_in_delta(2, method.total_time, 0.01)
60
+ assert_in_delta(0, method.wait_time, 0.01)
61
+ assert_in_delta(0, method.self_time, 0.01)
62
+ assert_in_delta(2, method.children_time, 0.01)
63
+ assert_equal(1, method.call_infos.length)
64
+
65
+ call_info = method.call_infos[0]
66
+ assert_equal('StartStopTest#method1->StartStopTest#method2', call_info.call_sequence)
67
+ assert_equal(1, call_info.children.length)
68
+
69
+ method = methods[2]
70
+ assert_equal('StartStopTest#method3', method.full_name)
71
+ assert_equal(1, method.called)
72
+ assert_in_delta(2, method.total_time, 0.01)
73
+ assert_in_delta(0, method.wait_time, 0.01)
74
+ assert_in_delta(0, method.self_time, 0.01)
75
+ assert_in_delta(2, method.children_time, 0.01)
76
+ assert_equal(1, method.call_infos.length)
77
+
78
+ call_info = method.call_infos[0]
79
+ assert_equal('StartStopTest#method1->StartStopTest#method2->StartStopTest#method3', call_info.call_sequence)
80
+ assert_equal(1, call_info.children.length)
81
+
82
+ method = methods[3]
83
+ assert_equal('Kernel#sleep', method.full_name)
84
+ assert_equal(1, method.called)
85
+ assert_in_delta(2, method.total_time, 0.01)
86
+ assert_in_delta(0, method.wait_time, 0.01)
87
+ assert_in_delta(2, method.self_time, 0.01)
88
+ assert_in_delta(0, method.children_time, 0.01)
89
+ assert_equal(1, method.call_infos.length)
90
+
91
+ call_info = method.call_infos[0]
92
+ assert_equal('StartStopTest#method1->StartStopTest#method2->StartStopTest#method3->Kernel#sleep', call_info.call_sequence)
93
+ assert_equal(0, call_info.children.length)
94
+ end
95
+ end
@@ -1,17 +1,21 @@
1
- # file ts_dbaccess.rb
2
1
  require 'test/unit'
2
+
3
3
  require 'basic_test'
4
4
  require 'duplicate_names_test'
5
+ require 'exceptions_test'
5
6
  require 'line_number_test'
6
- require 'measure_mode_test'
7
+ require 'measurement_test'
7
8
  require 'module_test'
8
9
  require 'no_method_class_test'
9
10
  require 'prime_test'
10
11
  require 'printers_test'
12
+ require 'profile_unit_test'
11
13
  require 'recursive_test'
12
14
  require 'singleton_test'
15
+ require 'stack_test'
16
+ require 'start_stop_test'
13
17
  require 'thread_test'
14
- require 'timing_test'
18
+ require 'unique_call_path_test'
15
19
 
16
20
  # Can't use this one here cause it breaks
17
21
  # the rest of the unit tets (Ruby Prof gets
@@ -1,115 +1,151 @@
1
1
  #!/usr/bin/env ruby
2
-
3
2
  require 'test/unit'
4
3
  require 'ruby-prof'
5
4
  require 'timeout'
6
- require 'test_helper'
7
-
8
- # Need to use wall time for this test due to the sleep calls
9
- RubyProf::measure_mode = RubyProf::WALL_TIME
10
5
 
11
6
  # -- Tests ----
12
7
  class ThreadTest < Test::Unit::TestCase
13
- def test_thread_timings
8
+ def setup
9
+ # Need to use wall time for this test due to the sleep calls
10
+ RubyProf::measure_mode = RubyProf::WALL_TIME
11
+ end
12
+
13
+ def test_thread_count
14
14
  RubyProf.start
15
-
16
- sleep(2)
17
15
 
18
16
  thread = Thread.new do
19
- sleep(0.5)
20
- sleep(2)
17
+ sleep(1)
21
18
  end
22
-
19
+
23
20
  thread.join
24
-
25
21
  result = RubyProf.stop
26
22
 
27
- values = result.threads.values.sort do |value1, value2|
28
- value1.length <=> value2.length
23
+ assert_equal(2, result.threads.keys.length)
24
+ end
25
+
26
+ def test_thread_identity
27
+ RubyProf.start
28
+
29
+ thread = Thread.new do
30
+ sleep(1)
31
+ end
32
+
33
+ thread.join
34
+ result = RubyProf.stop
35
+
36
+ thread_ids = result.threads.keys.sort
37
+ threads = [Thread.current, thread].sort_by {|thread| thread.object_id}
38
+
39
+ assert_equal(threads[0].object_id, thread_ids[0])
40
+ assert_equal(threads[1].object_id, thread_ids[1])
41
+
42
+ assert_instance_of(Thread, ObjectSpace._id2ref(thread_ids[0]))
43
+ assert_equal(threads[0], ObjectSpace._id2ref(thread_ids[0]))
44
+
45
+ assert_instance_of(Thread, ObjectSpace._id2ref(thread_ids[1]))
46
+ assert_equal(threads[1], ObjectSpace._id2ref(thread_ids[1]))
47
+ end
48
+
49
+ def test_thread_timings
50
+ RubyProf.start
51
+
52
+ thread = Thread.new do
53
+ sleep(1)
29
54
  end
30
-
55
+
56
+ thread.join
57
+
58
+ result = RubyProf.stop
59
+
31
60
  # Check background thread
32
- methods = values.first.sort.reverse
61
+ methods = result.threads[thread.object_id].sort.reverse
33
62
  assert_equal(2, methods.length)
34
-
63
+
35
64
  method = methods[0]
36
65
  assert_equal('ThreadTest#test_thread_timings', method.full_name)
37
- assert_in_delta(2.5, method.total_time, 0.02)
38
- assert_in_delta(0, method.self_time, 0.02)
39
- assert_in_delta(0.5, method.wait_time, 0.02)
40
- assert_in_delta(2.0, method.children_time, 0.02)
41
- assert_equal(0, method.called)
42
- assert_equal(0, method.parents.length)
43
- assert_equal(1, method.children.length)
66
+ assert_equal(1, method.called)
67
+ assert_in_delta(1, method.total_time, 0.01)
68
+ assert_in_delta(0, method.self_time, 0.01)
69
+ assert_in_delta(1, method.wait_time, 0.01)
70
+ assert_in_delta(0, method.children_time, 0.01)
71
+ assert_equal(1, method.call_infos.length)
72
+ call_info = method.call_infos[0]
73
+ assert_equal('ThreadTest#test_thread_timings', call_info.call_sequence)
74
+ assert_equal(1, call_info.children.length)
44
75
 
45
76
  method = methods[1]
46
77
  assert_equal('Kernel#sleep', method.full_name)
47
- assert_in_delta(2.5, method.total_time, 0.02)
48
- assert_in_delta(2.0, method.self_time, 0.02)
49
- assert_in_delta(0.5, method.wait_time, 0.02)
50
- assert_in_delta(0, method.children_time, 0.02)
51
- assert_equal(2, method.called)
52
- assert_equal(1, method.parents.length)
53
- assert_equal(0, method.children.length)
54
-
78
+ assert_equal(1, method.called)
79
+ assert_in_delta(1, method.total_time, 0.01)
80
+ assert_in_delta(1.0, method.self_time, 0.01)
81
+ assert_in_delta(0, method.wait_time, 0.01)
82
+ assert_in_delta(0, method.children_time, 0.01)
83
+
84
+ assert_equal(1, method.call_infos.length)
85
+ call_info = method.call_infos[0]
86
+ assert_equal('ThreadTest#test_thread_timings->Kernel#sleep', call_info.call_sequence)
87
+ assert_equal(0, call_info.children.length)
88
+
55
89
  # Check foreground thread
56
- methods = values.last.sort.reverse
57
- assert_equal(5, methods.length)
90
+ methods = result.threads[Thread.current.object_id].sort.reverse
91
+ assert_equal(4, methods.length)
58
92
  methods = methods.sort.reverse
59
-
93
+
60
94
  method = methods[0]
61
95
  assert_equal('ThreadTest#test_thread_timings', method.full_name)
62
- assert_in_delta(4.5, method.total_time, 0.02)
63
- assert_in_delta(0, method.self_time, 0.02)
64
- assert_in_delta(2.0, method.wait_time, 0.02)
65
- assert_in_delta(2.5, method.children_time, 0.02)
66
96
  assert_equal(0, method.called)
67
- assert_equal(0, method.parents.length)
68
- assert_equal(3, method.children.length)
97
+ assert_in_delta(1, method.total_time, 0.01)
98
+ assert_in_delta(0, method.self_time, 0.01)
99
+ assert_in_delta(1.0, method.wait_time, 0.01)
100
+ assert_in_delta(0, method.children_time, 0.01)
101
+
102
+ assert_equal(1, method.call_infos.length)
103
+ call_info = method.call_infos[0]
104
+ assert_equal('ThreadTest#test_thread_timings', call_info.call_sequence)
105
+ assert_equal(2, call_info.children.length)
69
106
 
70
107
  method = methods[1]
71
108
  assert_equal('Thread#join', method.full_name)
72
- assert_in_delta(2.5, method.total_time, 0.02)
73
- assert_in_delta(0.5, method.self_time, 0.02)
74
- assert_in_delta(2.0, method.wait_time, 0.02)
75
- assert_in_delta(0, method.children_time, 0.02)
76
109
  assert_equal(1, method.called)
77
- assert_equal(1, method.parents.length)
78
- assert_equal(0, method.children.length)
79
-
110
+ assert_in_delta(1, method.total_time, 0.01)
111
+ assert_in_delta(0, method.self_time, 0.01)
112
+ assert_in_delta(1.0, method.wait_time, 0.01)
113
+ assert_in_delta(0, method.children_time, 0.01)
114
+
115
+ assert_equal(1, method.call_infos.length)
116
+ call_info = method.call_infos[0]
117
+ assert_equal('ThreadTest#test_thread_timings->Thread#join', call_info.call_sequence)
118
+ assert_equal(0, call_info.children.length)
119
+
80
120
  method = methods[2]
81
- assert_equal('Kernel#sleep', method.full_name)
82
- assert_in_delta(2, method.total_time, 0.02)
83
- assert_in_delta(2.0, method.self_time, 0.02)
84
- assert_in_delta(0, method.wait_time, 0.02)
85
- assert_in_delta(0, method.children_time, 0.02)
86
- assert_equal(1, method.called)
87
- assert_equal(1, method.parents.length)
88
- assert_equal(0, method.children.length)
89
-
90
- method = methods[3]
91
121
  assert_equal('<Class::Thread>#new', method.full_name)
92
- assert_in_delta(0, method.total_time, 0.02)
93
- assert_in_delta(0, method.self_time, 0.02)
94
- assert_in_delta(0, method.wait_time, 0.02)
95
- assert_in_delta(0, method.children_time, 0.02)
96
122
  assert_equal(1, method.called)
97
- assert_equal(1, method.parents.length)
98
- assert_equal(1, method.children.length)
99
-
100
- method = methods[4]
123
+ assert_in_delta(0, method.total_time, 0.01)
124
+ assert_in_delta(0, method.self_time, 0.01)
125
+ assert_in_delta(0, method.wait_time, 0.01)
126
+ assert_in_delta(0, method.children_time, 0.01)
127
+
128
+ assert_equal(1, method.call_infos.length)
129
+ call_info = method.call_infos[0]
130
+ assert_equal('ThreadTest#test_thread_timings-><Class::Thread>#new', call_info.call_sequence)
131
+ assert_equal(1, call_info.children.length)
132
+
133
+ method = methods[3]
101
134
  assert_equal('Thread#initialize', method.full_name)
102
- assert_in_delta(0, method.total_time, 0.02)
103
- assert_in_delta(0, method.self_time, 0.02)
104
- assert_in_delta(0, method.wait_time, 0.02)
105
- assert_in_delta(0, method.children_time, 0.02)
106
135
  assert_equal(1, method.called)
107
- assert_equal(1, method.parents.length)
108
- assert_equal(0, method.children.length)
109
- end
136
+ assert_in_delta(0, method.total_time, 0.01)
137
+ assert_in_delta(0, method.self_time, 0.01)
138
+ assert_in_delta(0, method.wait_time, 0.01)
139
+ assert_in_delta(0, method.children_time, 0.01)
110
140
 
141
+ assert_equal(1, method.call_infos.length)
142
+ call_info = method.call_infos[0]
143
+ assert_equal('ThreadTest#test_thread_timings-><Class::Thread>#new->Thread#initialize', call_info.call_sequence)
144
+ assert_equal(0, call_info.children.length)
145
+ end
146
+
111
147
  def test_thread
112
- result = RubyProf.profile do
148
+ result = RubyProf.profile do
113
149
  begin
114
150
  status = Timeout::timeout(2) do
115
151
  while true
@@ -119,17 +155,5 @@ class ThreadTest < Test::Unit::TestCase
119
155
  rescue Timeout::Error
120
156
  end
121
157
  end
122
-
123
- printer = RubyProf::GraphPrinter.new(result)
124
- printer.print
125
-
126
- result.threads.each do |thread_id, methods|
127
- STDOUT << "thread: " << thread_id << "\n"
128
- methods.each do |method|
129
- check_parent_times(method)
130
- check_parent_calls(method)
131
- check_child_times(method)
132
- end
133
- end
134
158
  end
135
- end
159
+ end
@@ -0,0 +1,206 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'test/unit'
4
+ require 'ruby-prof'
5
+
6
+ class UniqueCallPath
7
+ def method_a(i)
8
+ if i==1
9
+ method_b
10
+ else
11
+ method_c
12
+ end
13
+ end
14
+
15
+ def method_b
16
+ method_c
17
+ end
18
+
19
+ def method_c
20
+ c = 3
21
+ end
22
+
23
+ def method_k(i)
24
+ method_a(i)
25
+ end
26
+ end
27
+
28
+
29
+ # -- Tests ----
30
+ class UniqueCallPathTest < Test::Unit::TestCase
31
+ def test_root_method
32
+ unique_call_path = UniqueCallPath.new
33
+
34
+ result = RubyProf.profile do
35
+ unique_call_path.method_a(1)
36
+ end
37
+
38
+ root_methods = Array.new
39
+ result.threads.each do | thread_id, methods |
40
+ methods.each do | m |
41
+ if m.root?
42
+ root_methods.push(m)
43
+ end
44
+ end
45
+ end
46
+
47
+ assert_equal(1, root_methods.length)
48
+ assert_equal("UniqueCallPathTest#test_root_method", root_methods[0].full_name)
49
+ end
50
+
51
+ def test_root_children
52
+ unique_call_path = UniqueCallPath.new
53
+
54
+ result = RubyProf.profile do
55
+ unique_call_path.method_a(1)
56
+ unique_call_path.method_k(2)
57
+ end
58
+
59
+ root_methods = Array.new
60
+ result.threads.each do | thread_id, methods |
61
+ methods.each do | m |
62
+ if m.root?
63
+ root_methods.push(m)
64
+ end
65
+ end
66
+ end
67
+
68
+ assert_equal(1, root_methods.length)
69
+
70
+ root_children = Array.new
71
+ root_methods[0].children.each do | c |
72
+ if c.parent.target.eql?(root_methods[0])
73
+ root_children.push(c)
74
+ end
75
+ end
76
+
77
+ children = root_children.sort do |c1, c2|
78
+ c1.target.full_name <=> c2.target.full_name
79
+ end
80
+
81
+ assert_equal(2, children.length)
82
+ assert_equal("UniqueCallPath#method_a", children[0].target.full_name)
83
+ assert_equal("UniqueCallPath#method_k", children[1].target.full_name)
84
+ end
85
+
86
+ def test_children_of
87
+ unique_call_path = UniqueCallPath.new
88
+
89
+ result = RubyProf.profile do
90
+ unique_call_path.method_a(1)
91
+ unique_call_path.method_k(2)
92
+ end
93
+
94
+ root_methods = Array.new
95
+ result.threads.each do | thread_id, methods |
96
+ methods.each do | m |
97
+ if m.root?
98
+ root_methods.push(m)
99
+ end
100
+ end
101
+ end
102
+
103
+ assert_equal(1, root_methods.length)
104
+ method = root_methods[0]
105
+ assert_equal('UniqueCallPathTest#test_children_of', method.full_name)
106
+
107
+ call_info_a = nil
108
+ root_methods[0].children.each do | c |
109
+ if c.target.full_name == "UniqueCallPath#method_a"
110
+ call_info_a = c
111
+ break
112
+ end
113
+ end
114
+
115
+ assert !call_info_a.nil?
116
+
117
+ children_of_a = Array.new
118
+
119
+ call_info_a.children.each do | c |
120
+ if c.parent.eql?(call_info_a)
121
+ children_of_a.push(c)
122
+ end
123
+ end
124
+
125
+ assert_equal(4, call_info_a.target.children.length)
126
+
127
+ children_of_a = children_of_a.sort do |c1, c2|
128
+ c1.target.full_name <=> c2.target.full_name
129
+ end
130
+
131
+ assert_equal(2, children_of_a.length)
132
+ assert_equal("Fixnum#==", children_of_a[0].target.full_name)
133
+ assert_equal("UniqueCallPath#method_b", children_of_a[1].target.full_name)
134
+ end
135
+
136
+ def test_id2ref
137
+ unique_call_path = UniqueCallPath.new
138
+
139
+ result = RubyProf.profile do
140
+ unique_call_path.method_a(1)
141
+ end
142
+
143
+ root_methods = Array.new
144
+ result.threads.each do | thread_id, methods |
145
+ methods.each do | m |
146
+ if m.root?
147
+ root_methods.push(m)
148
+ end
149
+ end
150
+ end
151
+
152
+ child = root_methods[0].children[0]
153
+
154
+ assert_not_equal(0, child.id)
155
+ #assert_equal(RubyProf::CallInfo.id2ref(child.id).target.full_name, child.target.full_name)
156
+ end
157
+
158
+ def test_unique_path
159
+ unique_call_path = UniqueCallPath.new
160
+
161
+ result = RubyProf.profile do
162
+ unique_call_path.method_a(1)
163
+ unique_call_path.method_k(1)
164
+ end
165
+
166
+ root_methods = Array.new
167
+ result.threads.each do | thread_id, methods |
168
+ methods.each do | m |
169
+ if m.root?
170
+ root_methods.push(m)
171
+ end
172
+ end
173
+ end
174
+
175
+ assert_equal(1, root_methods.length)
176
+
177
+ call_info_a = nil
178
+ root_methods[0].children.each do | c |
179
+ if c.target.full_name == "UniqueCallPath#method_a"
180
+ call_info_a = c
181
+ break
182
+ end
183
+ end
184
+
185
+ assert !call_info_a.nil?
186
+
187
+ children_of_a = Array.new
188
+ call_info_a.children.each do |c|
189
+ if c.parent.eql?(call_info_a)
190
+ children_of_a.push(c)
191
+ end
192
+ end
193
+
194
+ assert_equal(4, call_info_a.target.children.length)
195
+
196
+ children_of_a = children_of_a.sort do |c1, c2|
197
+ c1.target.full_name <=> c2.target.full_name
198
+ end
199
+
200
+ assert_equal(2, children_of_a.length)
201
+ assert_equal(1, children_of_a[0].called)
202
+ assert_equal("Fixnum#==", children_of_a[0].target.full_name)
203
+ assert_equal(1, children_of_a[1].called)
204
+ assert_equal("UniqueCallPath#method_b", children_of_a[1].target.full_name)
205
+ end
206
+ end