redcar 0.7 → 0.8

Sign up to get free protection for your applications and to get access to all the features.
Files changed (131) hide show
  1. data/CHANGES +42 -0
  2. data/README.md +5 -3
  3. data/Rakefile +39 -81
  4. data/bin/redcar +1 -1
  5. data/lib/redcar.rb +9 -6
  6. data/lib/redcar/installer.rb +1 -1
  7. data/lib/redcar/ruby_extensions.rb +19 -0
  8. data/lib/redcar/runner.rb +1 -1
  9. data/lib/redcar/usage.rb +3 -0
  10. data/lib/redcar_quick_start.rb +11 -11
  11. data/plugins/application/features/step_definitions/tree_steps.rb +22 -5
  12. data/plugins/application/features/step_definitions/window_steps.rb +9 -1
  13. data/plugins/application/features/support/env.rb +5 -2
  14. data/plugins/application/lib/application.rb +51 -46
  15. data/plugins/application/lib/application/window.rb +60 -30
  16. data/plugins/application_swt/lib/application_swt.rb +16 -16
  17. data/plugins/application_swt/lib/application_swt/window.rb +35 -7
  18. data/plugins/auto_completer/features/support/env.rb +0 -2
  19. data/plugins/auto_indenter/features/support/env.rb +0 -1
  20. data/plugins/auto_pairer/features/auto_pairer.feature +50 -45
  21. data/plugins/auto_pairer/features/support/env.rb +0 -1
  22. data/plugins/auto_pairer/lib/auto_pairer/document_controller.rb +11 -6
  23. data/plugins/clipboard-viewer/Screenshot.png +0 -0
  24. data/plugins/clipboard-viewer/lib/clipboard_viewer.rb +50 -0
  25. data/plugins/clipboard-viewer/lib/clipboard_viewer/browser_controller.rb +27 -0
  26. data/plugins/clipboard-viewer/lib/clipboard_viewer/clipboard_bar.rb +67 -0
  27. data/plugins/clipboard-viewer/plugin.rb +9 -0
  28. data/plugins/clipboard-viewer/views/clipboard.html.erb +15 -0
  29. data/plugins/clipboard-viewer/views/default.css +43 -0
  30. data/plugins/clipboard-viewer/views/redcar_small_icon.png +0 -0
  31. data/plugins/comment/features/line_comment.feature +137 -0
  32. data/plugins/comment/features/selection_comment.feature +21 -0
  33. data/plugins/comment/features/step_definitions/comment_steps.rb +7 -0
  34. data/plugins/comment/lib/comment.rb +266 -0
  35. data/plugins/comment/plugin.rb +7 -0
  36. data/plugins/comment/vendor/comment_lib.json +47 -0
  37. data/plugins/declarations/lib/declarations.rb +1 -1
  38. data/plugins/document_search/features/replace.feature +10 -2
  39. data/plugins/document_search/features/support/env.rb +0 -1
  40. data/plugins/document_search/lib/document_search.rb +4 -1
  41. data/plugins/document_search/lib/document_search/replace.rb +11 -3
  42. data/plugins/document_search/lib/document_search/search_and_replace.rb +5 -2
  43. data/plugins/edit_view/features/case_change.feature +9 -9
  44. data/plugins/edit_view/features/cursor_navigation.feature +36 -0
  45. data/plugins/edit_view/features/step_definitions/editing_steps.rb +63 -8
  46. data/plugins/edit_view/features/step_definitions/notebook_steps.rb +2 -0
  47. data/plugins/edit_view/features/step_definitions/tab_steps.rb +8 -5
  48. data/plugins/edit_view/features/support/env.rb +8 -2
  49. data/plugins/edit_view/lib/edit_view.rb +16 -1
  50. data/plugins/edit_view/lib/edit_view/actions/cmd_enter.rb +11 -0
  51. data/plugins/edit_view/lib/edit_view/document.rb +27 -10
  52. data/plugins/edit_view/lib/edit_view/edit_tab.rb +17 -4
  53. data/plugins/edit_view/spec/edit_view/document_spec.rb +3 -0
  54. data/plugins/edit_view_swt/lib/edit_view_swt.rb +42 -3
  55. data/plugins/edit_view_swt/lib/edit_view_swt/word_movement.rb +17 -15
  56. data/plugins/help/lib/help.rb +40 -0
  57. data/plugins/help/plugin.rb +8 -0
  58. data/plugins/html_view/features/step_definitions/html_view_steps.rb +6 -4
  59. data/plugins/line_tools/features/support/env.rb +0 -1
  60. data/plugins/macros/features/step_definitions/macro_steps.rb +0 -55
  61. data/plugins/macros/features/support/env.rb +0 -2
  62. data/plugins/open_default_app/lib/open_default_app.rb +35 -0
  63. data/plugins/open_default_app/plugin.rb +8 -0
  64. data/plugins/open_default_app/screenshot.png +0 -0
  65. data/plugins/plugin_manager_ui/lib/plugin_manager_ui.rb +17 -3
  66. data/plugins/project/features/find_file.feature +3 -2
  67. data/plugins/project/features/highlight_focussed_tab.feature +8 -0
  68. data/plugins/project/features/move_and_rename_files.feature +25 -0
  69. data/plugins/project/features/open_and_save_files.feature +10 -1
  70. data/plugins/project/features/open_directory_tree.feature +32 -2
  71. data/plugins/project/features/step_definitions/directory_steps.rb +17 -0
  72. data/plugins/project/features/step_definitions/project_tree_steps.rb +3 -0
  73. data/plugins/project/features/sub_project.feature +14 -0
  74. data/plugins/project/features/support/env.rb +22 -3
  75. data/plugins/project/features/watch_for_modified_files.feature +32 -9
  76. data/plugins/project/lib/project.rb +53 -21
  77. data/plugins/project/lib/project/adapters/local.rb +21 -16
  78. data/plugins/project/lib/project/adapters/remote.rb +15 -13
  79. data/plugins/project/lib/project/commands.rb +37 -16
  80. data/plugins/project/lib/project/dir_controller.rb +41 -42
  81. data/plugins/project/lib/project/drb_service.rb +35 -21
  82. data/plugins/project/lib/project/file_list.rb +7 -1
  83. data/plugins/project/lib/project/manager.rb +28 -3
  84. data/plugins/project/lib/project/sub_project.rb +17 -0
  85. data/plugins/project/lib/project/support/recycle.js +2 -0
  86. data/plugins/project/lib/project/support/trash.rb +72 -0
  87. data/plugins/project/spec/fixtures/multi-byte-files/a/341/204/200/341/205/247/341/206/274/341/204/205/341/205/251/foo +1 -0
  88. data/plugins/project/spec/fixtures/multi-byte-files//341/204/220/341/205/246/341/204/211/341/205/263/341/204/220/341/205/263.py +1 -0
  89. data/plugins/project/spec/project/file_list_spec.rb +4 -0
  90. data/plugins/redcar/features/goto_line_command.feature +20 -0
  91. data/plugins/redcar/redcar.rb +107 -47
  92. data/plugins/repl/lib/repl.rb +20 -20
  93. data/plugins/repl/lib/repl/clojure_mirror.rb +50 -58
  94. data/plugins/repl/lib/repl/groovy_mirror.rb +22 -41
  95. data/plugins/repl/lib/repl/repl_mirror.rb +85 -14
  96. data/plugins/repl/lib/repl/ruby_mirror.rb +12 -39
  97. data/plugins/repl/spec/repl/groovy_mirror_spec.rb +1 -1
  98. data/plugins/repl/spec/repl/ruby_mirror_spec.rb +12 -12
  99. data/plugins/ruby/README +6 -0
  100. data/plugins/ruby/lib/syntax_check/ruby.rb +28 -0
  101. data/plugins/ruby/plugin.rb +7 -0
  102. data/plugins/runnables/features/command_tree.feature +9 -0
  103. data/plugins/runnables/features/file_runner_input.feature +20 -0
  104. data/plugins/runnables/features/run_alternate_command.feature +14 -0
  105. data/plugins/runnables/features/support/env.rb +42 -5
  106. data/plugins/runnables/lib/runnables.rb +67 -21
  107. data/plugins/runnables/lib/runnables/commands.rb +35 -18
  108. data/plugins/runnables/lib/runnables/tree_mirror/nodes/runnable_group.rb +23 -37
  109. data/plugins/runnables/lib/runnables/tree_mirror/nodes/runnable_type_group.rb +16 -18
  110. data/plugins/scm_svn/features/support/env.rb +0 -3
  111. data/plugins/snippets/features/snippets.feature +17 -2
  112. data/plugins/snippets/features/support/env.rb +0 -1
  113. data/plugins/snippets/lib/snippets/tab_handler.rb +51 -18
  114. data/plugins/swt/lib/swt/cucumber_patches.rb +13 -68
  115. data/plugins/swt/lib/swt/cucumber_runner.rb +2 -3
  116. data/plugins/syntax_check/README +6 -0
  117. data/plugins/syntax_check/lib/syntax_check.rb +16 -0
  118. data/plugins/syntax_check/lib/syntax_check/checker.rb +47 -0
  119. data/plugins/syntax_check/lib/syntax_check/error.rb +23 -0
  120. data/plugins/syntax_check/plugin.rb +7 -0
  121. data/plugins/tree_view_swt/lib/tree_view_swt.rb +6 -0
  122. data/plugins/web_bookmarks/Screenshot.png +0 -0
  123. data/plugins/web_bookmarks/lib/web_bookmarks.rb +42 -0
  124. data/plugins/web_bookmarks/lib/web_bookmarks/bookmark.rb +43 -0
  125. data/plugins/web_bookmarks/lib/web_bookmarks/browser_bar.rb +70 -0
  126. data/plugins/web_bookmarks/lib/web_bookmarks/commands.rb +111 -0
  127. data/plugins/web_bookmarks/lib/web_bookmarks/tree.rb +67 -0
  128. data/plugins/web_bookmarks/lib/web_bookmarks/view_controller.rb +22 -0
  129. data/plugins/web_bookmarks/plugin.rb +11 -0
  130. data/plugins/web_bookmarks/views/index.html.erb +5 -0
  131. metadata +60 -10
@@ -5,42 +5,42 @@ require 'repl/groovy_mirror'
5
5
 
6
6
  module Redcar
7
7
  class REPL
8
- def self.sensitivities
9
- [
10
- Sensitivity.new(:open_repl_tab, Redcar.app, false, [:tab_focussed]) do |tab|
11
- tab and
12
- tab.is_a?(EditTab) and
13
- tab.edit_view.document.mirror.is_a?(REPL::ReplMirror)
8
+ def self.menus
9
+ Menu::Builder.build do
10
+ sub_menu "Plugins" do
11
+ sub_menu "REPL", :priority => 180 do
12
+ item "Open Ruby REPL", REPL::RubyOpenREPL
13
+ item "Open Clojure REPL", REPL::ClojureOpenREPL
14
+ item "Open Groovy REPL", REPL::GroovyOpenREPL
15
+ item "Execute", REPL::CommitREPL
16
+ item "Clear History", REPL::ClearHistoryREPL
17
+ end
14
18
  end
15
- ]
19
+ end
16
20
  end
17
21
 
18
22
  def self.keymaps
19
23
  osx = Keymap.build("main", :osx) do
20
24
  link "Cmd+Shift+R", REPL::RubyOpenREPL
21
- link "Cmd+R", REPL::CommitREPL
25
+ link "Cmd+M", REPL::CommitREPL
22
26
  end
23
27
 
24
28
  linwin = Keymap.build("main", [:linux, :windows]) do
25
29
  link "Ctrl+Shift+R", REPL::RubyOpenREPL
26
- link "Ctrl+R", REPL::CommitREPL
30
+ link "Ctrl+M", REPL::CommitREPL
27
31
  end
28
32
 
29
33
  [linwin, osx]
30
34
  end
31
35
 
32
- def self.menus
33
- Menu::Builder.build do
34
- sub_menu "Plugins" do
35
- sub_menu "REPL", :priority => 180 do
36
- item "Open Ruby REPL", REPL::RubyOpenREPL
37
- item "Open Clojure REPL", REPL::ClojureOpenREPL
38
- item "Open Groovy REPL", REPL::GroovyOpenREPL
39
- item "Execute", REPL::CommitREPL
40
- item "Clear History", REPL::ClearHistoryREPL
41
- end
36
+ def self.sensitivities
37
+ [
38
+ Sensitivity.new(:open_repl_tab, Redcar.app, false, [:tab_focussed]) do |tab|
39
+ tab and
40
+ tab.is_a?(EditTab) and
41
+ tab.edit_view.document.mirror.is_a?(REPL::ReplMirror)
42
42
  end
43
- end
43
+ ]
44
44
  end
45
45
 
46
46
  class OpenREPL < Command
@@ -1,45 +1,8 @@
1
1
 
2
2
  module Redcar
3
3
  class REPL
4
- class ClojureMirror
5
- def self.load_clojure_dependencies
6
- unless @loaded
7
- require File.join(Redcar.asset_dir, "clojure.jar")
8
- require File.join(Redcar.asset_dir, "clojure-contrib.jar")
9
- require File.join(Redcar.asset_dir, "org-enclojure-repl-server.jar")
10
- require File.dirname(__FILE__) + "/../../vendor/enclojure-wrapper.jar"
11
-
12
- import 'redcar.repl.Wrapper'
13
- @loaded = true
14
- end
15
- end
4
+ class ClojureMirror < ReplMirror
16
5
 
17
- include Redcar::REPL::ReplMirror
18
-
19
- def initialize
20
- ClojureMirror.load_clojure_dependencies
21
- # required by ReplMirror
22
- @prompt = "=>"
23
-
24
- @repl_wrapper = Wrapper.new
25
- @mutex = Mutex.new
26
- @history = "# Clojure REPL\n"
27
-
28
- @thread = Thread.new do
29
- loop do
30
- str = @repl_wrapper.getResult
31
- @mutex.synchronize do
32
- @history += "\n" if @history != ""
33
- @history += str
34
- end
35
- Redcar.update_gui do
36
- notify_listeners(:change)
37
- end
38
- end
39
- end
40
-
41
- end
42
-
43
6
  def title
44
7
  "Clojure REPL"
45
8
  end
@@ -48,30 +11,59 @@ module Redcar
48
11
  "Clojure REPL"
49
12
  end
50
13
 
51
- # Get the complete history as a pretty formatted string.
52
- #
53
- # @return [String]
54
- def read
55
- @mutex.synchronize do
56
- @history
57
- end
14
+ def prompt
15
+ "user=>"
58
16
  end
59
-
60
- def clear_history
61
- @mutex.synchronize do
62
- @history = @history.split("\n").last
63
- end
64
- notify_listeners(:change)
17
+
18
+ def evaluator
19
+ @evaluator ||= ClojureMirror::Evaluator.new(self)
65
20
  end
66
-
67
- private
68
21
 
69
- def send_to_repl expr
70
- @mutex.synchronize do
71
- @history += expr
22
+ def format_error(e)
23
+ "ERROR: #{e.message}\n\n#{e.backtrace.join("\n")}"
24
+ end
25
+
26
+ class Evaluator
27
+ attr_reader :wrapper
28
+
29
+ def self.load_clojure_dependencies
30
+ unless @loaded
31
+ require File.join(Redcar.asset_dir, "clojure.jar")
32
+ require File.join(Redcar.asset_dir, "clojure-contrib.jar")
33
+ require File.join(Redcar.asset_dir, "org-enclojure-repl-server.jar")
34
+ require File.dirname(__FILE__) + "/../../vendor/enclojure-wrapper.jar"
35
+
36
+ import 'redcar.repl.Wrapper'
37
+ @loaded = true
38
+ end
39
+ end
40
+
41
+ def initialize(mirror)
42
+ ClojureMirror::Evaluator.load_clojure_dependencies
43
+ @mirror = mirror
44
+ @wrapper ||= begin
45
+ wrapper = Wrapper.new
46
+
47
+ @thread = Thread.new do
48
+ loop do
49
+ output = wrapper.getResult
50
+ output =~ /^(.*)\nuser=> /
51
+ @result = $1
52
+ end
53
+ end
54
+
55
+ wrapper
56
+ end
72
57
  end
73
- @repl_wrapper.sendToRepl(expr)
74
- end
58
+
59
+ def execute(expr)
60
+ wrapper.sendToRepl(expr)
61
+ true until @result
62
+ str = @result
63
+ @result = nil
64
+ str
65
+ end
66
+ end
75
67
  end
76
68
  end
77
69
  end
@@ -3,25 +3,7 @@ require 'java'
3
3
 
4
4
  module Redcar
5
5
  class REPL
6
- class GroovyMirror
7
- def self.load_groovy_dependencies
8
- unless @loaded
9
- require File.join(Redcar.asset_dir,"groovy-all")
10
- import 'groovy.lang.GroovyShell'
11
- import 'java.io.PrintWriter'
12
- import 'java.io.StringWriter'
13
- @loaded = true
14
- end
15
- end
16
- include Redcar::REPL::ReplMirror
17
-
18
- def initialize
19
- GroovyMirror.load_groovy_dependencies
20
- @prompt = "groovy>"
21
- @history = "// Groovy REPL\n\n#{@prompt} "
22
- @instance = Main.new
23
- end
24
-
6
+ class GroovyMirror < ReplMirror
25
7
  def title
26
8
  "Groovy REPL"
27
9
  end
@@ -29,18 +11,33 @@ module Redcar
29
11
  def grammar_name
30
12
  "Groovy REPL"
31
13
  end
14
+
15
+ def prompt
16
+ "groovy>"
17
+ end
32
18
 
33
- def read
34
- @history
19
+ def evaluator
20
+ @instance ||= GroovyMirror::Evaluator.new
35
21
  end
36
22
 
37
- def clear_history
38
- @history = @history.split("\n").last
39
- notify_listeners(:change)
23
+ def format_error(e)
24
+ backtrace = e.backtrace
25
+ "ERROR #{e.class}:\n #{e.message}\n #{backtrace.join("\n ")}"
40
26
  end
41
27
 
42
- class Main
28
+ class Evaluator
29
+ def self.load_groovy_dependencies
30
+ unless @loaded
31
+ require File.join(Redcar.asset_dir,"groovy-all")
32
+ import 'groovy.lang.GroovyShell'
33
+ import 'java.io.PrintWriter'
34
+ import 'java.io.StringWriter'
35
+ @loaded = true
36
+ end
37
+ end
38
+
43
39
  def initialize
40
+ GroovyMirror::Evaluator.load_groovy_dependencies
44
41
  @out = StringWriter.new
45
42
  @shell = GroovyShell.new
46
43
  @shell.setProperty('out',@out)
@@ -63,22 +60,6 @@ module Redcar
63
60
  console + "===> #{output}"
64
61
  end
65
62
  end
66
-
67
- def format_error(e)
68
- backtrace = e.backtrace
69
- "ERROR #{e.class}:\n #{e.message}\n #{backtrace.join("\n ")}"
70
- end
71
-
72
- def send_to_repl expr
73
- @history += expr + "\n"
74
- begin
75
- @history += @instance.execute(expr)
76
- rescue Object => e
77
- @history += format_error(e)
78
- end
79
- @history += "\n" + @prompt + " "
80
- notify_listeners(:change)
81
- end
82
63
  end
83
64
  end
84
65
  end
@@ -1,22 +1,101 @@
1
1
  module Redcar
2
2
  class REPL
3
- module ReplMirror
3
+ class ReplMirror
4
+ attr_reader :history
5
+
6
+ # A ReplMirror is a type of Document::Mirror
4
7
  include Redcar::Document::Mirror
5
-
8
+
9
+ def initialize
10
+ @history = initial_preamble
11
+ @mutex = Mutex.new
12
+ end
13
+
14
+ # What to display when the REPL is opened. Defaults to the title followed
15
+ # by a prompt
16
+ #
17
+ # @return [String]
18
+ def initial_preamble
19
+ "# #{title}\n\n#{prompt} "
20
+ end
21
+
22
+ # The name of the textmate grammar to apply to the repl history.
23
+ #
24
+ # @return [String]
25
+ def grammar_name
26
+ raise "implement the grammar_name method on your REPL"
27
+ end
28
+
29
+ # The prompt to display when the REPL is ready to accept input.
30
+ # Default: ">>"
31
+ #
32
+ # @return [String]
33
+ def prompt
34
+ ">>"
35
+ end
36
+
37
+ # This returns an object that implements:
38
+ # execute(str:String): String
39
+ def evaluator
40
+ raise "implement evaluator on your REPL"
41
+ end
42
+
43
+ # Format the language specific exception to be displayed in the Repl
44
+ #
45
+ # @param [Exception]
46
+ # @return [String]
47
+ def format_error(exception)
48
+ raise "implement format_error on your REPL"
49
+ end
50
+
6
51
  # Execute a new statement. Accepts the entire pretty formatted history,
7
52
  # within which it looks for the last statement and executes it.
8
53
  #
54
+ # Do not override
55
+ #
9
56
  # @param [String] a string with at least one prompt and statement in it
10
57
  def commit(contents)
11
- if contents.split("\n").last =~ /#{@prompt}\s+$/
12
- command = ""
58
+ command = entered_expression(contents)
59
+ evaluate(command)
60
+ end
61
+
62
+ # What did the user just enter?
63
+ #
64
+ # @return [String]
65
+ def entered_expression(contents)
66
+ if contents.split("\n").last =~ /#{prompt}\s+$/
67
+ ""
13
68
  else
14
- command = contents.split(@prompt).last.strip
69
+ contents.split(prompt).last.strip
15
70
  end
16
- send_to_repl command
71
+ end
72
+
73
+ # Evaluate an expression. Calls execute on the return value of evaluator
74
+ def evaluate(expr)
75
+ @history += expr + "\n"
76
+ begin
77
+ @history += "=> " + evaluator.execute(expr)
78
+ rescue Object => e
79
+ @history += "x> " + format_error(e)
80
+ end
81
+ @history += "\n" + prompt + " "
82
+ notify_listeners(:change)
83
+ end
84
+
85
+ # Get the complete history as a pretty formatted string.
86
+ #
87
+ # @return [String]
88
+ def read
89
+ @history
90
+ end
91
+
92
+ def clear_history
93
+ @history = @history.split("\n").last
94
+ notify_listeners(:change)
17
95
  end
18
96
 
19
97
  # REPLs always exist because there is no external resource to represent.
98
+ # Therefore, this returns true.
20
99
  def exists?
21
100
  true
22
101
  end
@@ -25,14 +104,6 @@ module Redcar
25
104
  def changed?
26
105
  false
27
106
  end
28
-
29
- private
30
-
31
- # Language-specific method for evaluating statements
32
- def send_to_repl expr
33
- raise "not implemented"
34
- end
35
-
36
107
  end
37
108
  end
38
109
  end
@@ -1,17 +1,8 @@
1
1
 
2
2
  module Redcar
3
3
  class REPL
4
- class RubyMirror
5
- include Redcar::REPL::ReplMirror
4
+ class RubyMirror < ReplMirror
6
5
 
7
- def initialize
8
- # required by ReplMirror
9
- @prompt = ">>"
10
-
11
- @history = "# Redcar REPL\n\n#{@prompt} "
12
- @instance = Main.new
13
- end
14
-
15
6
  def title
16
7
  "Ruby REPL"
17
8
  end
@@ -20,21 +11,21 @@ module Redcar
20
11
  "Ruby REPL"
21
12
  end
22
13
 
23
- # Get the complete history as a pretty formatted string.
24
- #
25
- # @return [String]
26
- def read
27
- @history
14
+ def prompt
15
+ ">>"
28
16
  end
29
17
 
30
- def clear_history
31
- @history = @history.split("\n").last
32
- notify_listeners(:change)
18
+ def format_error(e)
19
+ backtrace = e.backtrace.reject{|l| l =~ /ruby_mirror/}
20
+ backtrace.unshift("(repl):1")
21
+ "#{e.class}: #{e.message}\n #{backtrace.join("\n ")}"
22
+ end
23
+
24
+ def evaluator
25
+ @evaluator ||= RubyMirror::Evaluator.new
33
26
  end
34
-
35
- private
36
27
 
37
- class Main
28
+ class Evaluator
38
29
  attr_reader :output
39
30
 
40
31
  def initialize
@@ -50,24 +41,6 @@ module Redcar
50
41
  eval(command, @binding).inspect
51
42
  end
52
43
  end
53
-
54
- def format_error(e)
55
- backtrace = e.backtrace.reject{|l| l =~ /ruby_mirror/}
56
- backtrace.unshift("(repl):1")
57
- "#{e.class}: #{e.message}\n #{backtrace.join("\n ")}"
58
- end
59
-
60
- def send_to_repl expr
61
- @history += expr + "\n"
62
- begin
63
- @history += "=> " + @instance.execute(expr)
64
- rescue Object => e
65
- @history += "x> " + format_error(e)
66
- end
67
- @history += "\n" + @prompt + " "
68
- notify_listeners(:change)
69
- end
70
-
71
44
  end
72
45
  end
73
46
  end