ori 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- data/MIT-LICENSE +20 -0
- data/README.html +158 -0
- data/README.md +160 -0
- data/Rakefile +60 -0
- data/VERSION.yml +5 -0
- data/lib/misc/method_aliases.rb +11 -0
- data/lib/ori.rb +47 -0
- data/lib/ori/auto_config.rb +78 -0
- data/lib/ori/colorize.rb +62 -0
- data/lib/ori/config.rb +27 -0
- data/lib/ori/extensions.rb +4 -0
- data/lib/ori/extensions/object/ri.rb +88 -0
- data/lib/ori/internals.rb +411 -0
- data/lib/ori/library.rb +59 -0
- data/lib/ori/list_method.rb +247 -0
- data/lib/ori/request.rb +118 -0
- data/lib/ori/tools.rb +142 -0
- data/ori.gemspec +82 -0
- data/samples/NOTES +3 -0
- data/samples/basic_extension.rb +27 -0
- data/samples/basic_inheritance.rb +99 -0
- data/samples/self_singletons.rb +36 -0
- data/samples/singleton_class_includes_module.rb +33 -0
- data/spec/auto_config_spec.rb +33 -0
- data/spec/colorize_spec.rb +26 -0
- data/spec/inspector_spec.rb +75 -0
- data/spec/internals_spec.rb +219 -0
- data/spec/list_method_spec.rb +118 -0
- data/spec/request_spec.rb +72 -0
- data/spec/site/NOTES +3 -0
- data/spec/site/library_spec.rb +33 -0
- data/spec/site/spec_helper.rb +1 -0
- data/spec/spec_helper.rb +26 -0
- data/spec/tools_spec.rb +109 -0
- metadata +107 -0
data/MIT-LICENSE
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Copyright (c) 2011 Alex Fortuna
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
4
|
+
a copy of this software and associated documentation files (the
|
5
|
+
"Software"), to deal in the Software without restriction, including
|
6
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
7
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
8
|
+
permit persons to whom the Software is furnished to do so, subject to
|
9
|
+
the following conditions:
|
10
|
+
|
11
|
+
The above copyright notice and this permission notice shall be
|
12
|
+
included in all copies or substantial portions of the Software.
|
13
|
+
|
14
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
15
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
16
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
17
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
18
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
19
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
20
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.html
ADDED
@@ -0,0 +1,158 @@
|
|
1
|
+
<head>
|
2
|
+
<meta content="text/html; charset=utf-8" http-equiv="Content-Type" />
|
3
|
+
<link href="dev/github.css" rel="stylesheet" type="text/css" />
|
4
|
+
</head>
|
5
|
+
<h1 id="object-oriented-ri-for-irb-console">Object-Oriented RI for IRB Console</h1>
|
6
|
+
|
7
|
+
<h2 id="introduction">Introduction</h2>
|
8
|
+
|
9
|
+
<p>Finding documentation for Ruby gems and libraries is often time-consuming.
|
10
|
+
ORI addresses this issue by bringing RI documentation right to your IRB console in a <strong>simple</strong>, <strong>consistent</strong> and truly <strong>object-oriented</strong> way.</p>
|
11
|
+
|
12
|
+
<p>If you’re too lazy to read this README, <a href="http://screecast">watch this screencast</a> instead.</p>
|
13
|
+
|
14
|
+
<h2 id="setup">Setup</h2>
|
15
|
+
|
16
|
+
<pre><code>$ gem sources --add http://rubygems.org
|
17
|
+
$ gem install ori
|
18
|
+
</code></pre>
|
19
|
+
|
20
|
+
<p>Add to your <code>~/.irbrc</code>:</p>
|
21
|
+
|
22
|
+
<pre><code>require "rubygems"
|
23
|
+
require "ori"
|
24
|
+
</code></pre>
|
25
|
+
|
26
|
+
<h2 id="setup-in-rvm">Setup in RVM</h2>
|
27
|
+
|
28
|
+
<p>If you’re using <a href="http://rvm.beginrescueend.com/">RVM</a> (Ruby Version Manager), install the gem into <code>global</code> gemset of Rubies you’re actively using:</p>
|
29
|
+
|
30
|
+
<pre><code>$ rvm 1.9.2
|
31
|
+
$ rvm gemset use global
|
32
|
+
$ gem install ori
|
33
|
+
</code></pre>
|
34
|
+
|
35
|
+
<h2 id="requirements">Requirements</h2>
|
36
|
+
|
37
|
+
<p>It is recommended that you have Ruby >= <strong>1.8.7</strong> and RDoc >= <strong>2.5.3</strong>. Issue reports for older versions will, most probably, be ignored.</p>
|
38
|
+
|
39
|
+
<h2 id="usage">Usage</h2>
|
40
|
+
|
41
|
+
<p>All commands listed below are assumed to be typed in IRB. Example:</p>
|
42
|
+
|
43
|
+
<pre><code>$ irb
|
44
|
+
irb> Array.ri
|
45
|
+
</code></pre>
|
46
|
+
|
47
|
+
<h3 id="request-ri-on-a-class">Request RI on a Class</h3>
|
48
|
+
|
49
|
+
<pre><code>Array.ri
|
50
|
+
String.ri
|
51
|
+
[].ri
|
52
|
+
"".ri
|
53
|
+
5.ri
|
54
|
+
</code></pre>
|
55
|
+
|
56
|
+
<p>So that’s fairly straightforward – grab a class or class instance and call <tt>ri</tt> on it:</p>
|
57
|
+
|
58
|
+
<pre><code>obj = SomeKlass.new
|
59
|
+
obj.ri
|
60
|
+
</code></pre>
|
61
|
+
|
62
|
+
<h3 id="request-ri-on-a-method">Request RI on a Method</h3>
|
63
|
+
|
64
|
+
<pre><code>String.ri :upcase
|
65
|
+
"".ri "upcase"
|
66
|
+
[].ri :sort
|
67
|
+
Hash.ri :[]
|
68
|
+
Hash.ri "::[]"
|
69
|
+
Hash.ri "#[]"
|
70
|
+
</code></pre>
|
71
|
+
|
72
|
+
<h3 id="request-interactive-method-list">Request Interactive Method List</h3>
|
73
|
+
|
74
|
+
<pre><code># Regular expression argument denotes list request.
|
75
|
+
String.ri //
|
76
|
+
"".ri //
|
77
|
+
|
78
|
+
# Show method names matching a regular expression.
|
79
|
+
"".ri /case/
|
80
|
+
"".ri /^to_/
|
81
|
+
[].ri /sort/
|
82
|
+
{}.ri /each/
|
83
|
+
|
84
|
+
# Show ALL methods, including those private of Kernel.
|
85
|
+
Hash.ri //, :all => true
|
86
|
+
Hash.ri //, :all
|
87
|
+
|
88
|
+
# Show class methods or instance methods only.
|
89
|
+
Module.ri //, :access => "::"
|
90
|
+
Module.ri //, :access => "#"
|
91
|
+
|
92
|
+
# Show own methods only.
|
93
|
+
Time.ri //, :own => true
|
94
|
+
Time.ri //, :own
|
95
|
+
|
96
|
+
# Specify visibility: public, protected or private.
|
97
|
+
Module.ri //, :visibility => :private
|
98
|
+
Module.ri //, :visibility => [:public, :protected]
|
99
|
+
|
100
|
+
# Filter fully formatted name by given regexp.
|
101
|
+
Module, //, :fullre => /\(Object\)::/
|
102
|
+
|
103
|
+
# Combine options.
|
104
|
+
Module.ri //, :fullre => /\(Object\)::/, :access => "::", :visibility => :private
|
105
|
+
</code></pre>
|
106
|
+
|
107
|
+
<h3 id="request-interactive-method-list-for-more-than-1-object-at-once">Request Interactive Method List for More Than 1 Object at Once</h3>
|
108
|
+
|
109
|
+
<p>By using the <tt>:join</tt> option it’s possible to fetch methods for more
|
110
|
+
than 1 object at once. Value of <tt>:join</tt> (which can be an object or an array)
|
111
|
+
is joined with the original receiver, and then a combined set is queried.</p>
|
112
|
+
|
113
|
+
<pre><code># List all division-related methods from numeric classes.
|
114
|
+
Fixnum.ri /div/, :join => [Float, Rational]
|
115
|
+
5.ri /div/, :join => [5.0, 5.to_r]
|
116
|
+
|
117
|
+
# List all ActiveSupport extensions to numeric classes.
|
118
|
+
5.ri //, :join => [5.0, 5.to_r], :fullre => /ActiveSupport/
|
119
|
+
|
120
|
+
# Query entire Rails family for methods having the word "javascript".
|
121
|
+
rails_modules = ObjectSpace.each_object(Module).select {|mod| mod.to_s.match /Active|Action/}
|
122
|
+
"".ri /javascript/, :join => rails_modules
|
123
|
+
</code></pre>
|
124
|
+
|
125
|
+
<h2 id="configuration">Configuration</h2>
|
126
|
+
|
127
|
+
<p>You can configure ORI via <code>ORI.conf</code> object. By default it’s autoconfigured based on your OS and environment.</p>
|
128
|
+
|
129
|
+
<pre><code># Enable color.
|
130
|
+
ORI.conf.color = true
|
131
|
+
|
132
|
+
# RI frontend command to use. <tt>%s</tt> is replaced with sought topic.
|
133
|
+
ORI.conf.frontend = "ri -T -f ansi %s"
|
134
|
+
|
135
|
+
# Paging program to use.
|
136
|
+
ORI.conf.pager = "less -R"
|
137
|
+
</code></pre>
|
138
|
+
|
139
|
+
<h2 id="compatibility">Compatibility</h2>
|
140
|
+
|
141
|
+
<p>Prior to publication, ORI gem has been thoroughly tested on:</p>
|
142
|
+
|
143
|
+
<ul>
|
144
|
+
<li>Ruby 1.9.2-p0 under Linux with RVM</li>
|
145
|
+
<li>Ruby 1.8.7-p302 under Linux with RVM</li>
|
146
|
+
<li>Ruby 1.8.7-p72 under Cygwin</li>
|
147
|
+
<li>Ruby 1.8.7-p72 under 32-bit Windows Vista</li>
|
148
|
+
</ul>
|
149
|
+
|
150
|
+
<h2 id="copyright">Copyright</h2>
|
151
|
+
|
152
|
+
<p>Copyright © 2011 Alex Fortuna.</p>
|
153
|
+
|
154
|
+
<p>Licensed under the MIT License.</p>
|
155
|
+
|
156
|
+
<h2 id="feedback">Feedback</h2>
|
157
|
+
|
158
|
+
<p>Send bug reports, suggestions and criticisms through <a href="http://github.com/dadooda/ori">project’s page on GitHub</a>.</p>
|
data/README.md
ADDED
@@ -0,0 +1,160 @@
|
|
1
|
+
Object-Oriented RI for IRB Console
|
2
|
+
==================================
|
3
|
+
|
4
|
+
Introduction
|
5
|
+
------------
|
6
|
+
|
7
|
+
Finding documentation for Ruby gems and libraries is often time-consuming.
|
8
|
+
ORI addresses this issue by bringing RI documentation right to your IRB console in a **simple**, **consistent** and truly **object-oriented** way.
|
9
|
+
|
10
|
+
If you're too lazy to read this README, [watch this screencast](http://www.screencast-o-matic.com/watch/cXVVYuXpH) instead.
|
11
|
+
|
12
|
+
|
13
|
+
Setup
|
14
|
+
-----
|
15
|
+
|
16
|
+
$ gem sources --add http://rubygems.org
|
17
|
+
$ gem install ori
|
18
|
+
|
19
|
+
Add to your `~/.irbrc`:
|
20
|
+
|
21
|
+
require "rubygems"
|
22
|
+
require "ori"
|
23
|
+
|
24
|
+
|
25
|
+
Setup in RVM
|
26
|
+
------------
|
27
|
+
|
28
|
+
If you're using [RVM](http://rvm.beginrescueend.com/) (Ruby Version Manager), install the gem into `global` gemset of Rubies you're actively using:
|
29
|
+
|
30
|
+
$ rvm 1.9.2
|
31
|
+
$ rvm gemset use global
|
32
|
+
$ gem install ori
|
33
|
+
|
34
|
+
|
35
|
+
Requirements
|
36
|
+
------------
|
37
|
+
|
38
|
+
It is recommended that you have Ruby >= **1.8.7** and RDoc >= **2.5.3**. Issue reports for older versions will, most probably, be ignored.
|
39
|
+
|
40
|
+
|
41
|
+
Usage
|
42
|
+
-----
|
43
|
+
|
44
|
+
All commands listed below are assumed to be typed in IRB. Example:
|
45
|
+
|
46
|
+
$ irb
|
47
|
+
irb> Array.ri
|
48
|
+
|
49
|
+
### Request RI on a Class ##
|
50
|
+
|
51
|
+
Array.ri
|
52
|
+
String.ri
|
53
|
+
[].ri
|
54
|
+
"".ri
|
55
|
+
5.ri
|
56
|
+
|
57
|
+
So that's fairly straightforward -- grab a class or class instance and call <tt>ri</tt> on it:
|
58
|
+
|
59
|
+
obj = SomeKlass.new
|
60
|
+
obj.ri
|
61
|
+
|
62
|
+
### Request RI on a Method ###
|
63
|
+
|
64
|
+
String.ri :upcase
|
65
|
+
"".ri :upcase
|
66
|
+
[].ri :sort
|
67
|
+
Hash.ri :[]
|
68
|
+
Hash.ri "::[]"
|
69
|
+
Hash.ri "#[]"
|
70
|
+
|
71
|
+
### Request Interactive Method List ###
|
72
|
+
|
73
|
+
# Regular expression argument denotes list request.
|
74
|
+
String.ri //
|
75
|
+
"".ri //
|
76
|
+
|
77
|
+
# Show method names matching a regular expression.
|
78
|
+
"".ri /case/
|
79
|
+
"".ri /^to_/
|
80
|
+
[].ri /sort/
|
81
|
+
{}.ri /each/
|
82
|
+
|
83
|
+
# Show ALL methods, including those private of Kernel.
|
84
|
+
Hash.ri //, :all => true
|
85
|
+
Hash.ri //, :all
|
86
|
+
|
87
|
+
# Show class methods or instance methods only.
|
88
|
+
Module.ri //, :access => "::"
|
89
|
+
Module.ri //, :access => "#"
|
90
|
+
|
91
|
+
# Show own methods only.
|
92
|
+
Time.ri //, :own => true
|
93
|
+
Time.ri //, :own
|
94
|
+
|
95
|
+
# Specify visibility: public, protected or private.
|
96
|
+
Module.ri //, :visibility => :private
|
97
|
+
Module.ri //, :visibility => [:public, :protected]
|
98
|
+
|
99
|
+
# Filter fully formatted name by given regexp.
|
100
|
+
Module, //, :fullre => /\(Object\)::/
|
101
|
+
|
102
|
+
# Combine options.
|
103
|
+
Module.ri //, :fullre => /\(Object\)::/, :access => "::", :visibility => :private
|
104
|
+
|
105
|
+
### Request Interactive Method List for More Than 1 Object at Once ###
|
106
|
+
|
107
|
+
By using the <tt>:join</tt> option it's possible to fetch methods for more
|
108
|
+
than 1 object at once. Value of <tt>:join</tt> (which can be an object or an array)
|
109
|
+
is joined with the original receiver, and then a combined set is queried.
|
110
|
+
|
111
|
+
# List all division-related methods from numeric classes.
|
112
|
+
Fixnum.ri /div/, :join => [Float, Rational]
|
113
|
+
5.ri /div/, :join => [5.0, 5.to_r]
|
114
|
+
|
115
|
+
# List all ActiveSupport extensions to numeric classes.
|
116
|
+
5.ri //, :join => [5.0, 5.to_r], :fullre => /ActiveSupport/
|
117
|
+
|
118
|
+
# Query entire Rails family for methods having the word "javascript".
|
119
|
+
rails_modules = ObjectSpace.each_object(Module).select {|mod| mod.to_s.match /Active|Action/}
|
120
|
+
"".ri /javascript/, :join => rails_modules
|
121
|
+
|
122
|
+
|
123
|
+
Configuration
|
124
|
+
-------------
|
125
|
+
|
126
|
+
You can configure ORI via `ORI.conf` object. By default it's autoconfigured based on your OS and environment.
|
127
|
+
|
128
|
+
# Enable color.
|
129
|
+
ORI.conf.color = true
|
130
|
+
|
131
|
+
# RI frontend command to use. <tt>%s</tt> is replaced with sought topic.
|
132
|
+
ORI.conf.frontend = "ri -T -f ansi %s"
|
133
|
+
|
134
|
+
# Paging program to use.
|
135
|
+
ORI.conf.pager = "less -R"
|
136
|
+
|
137
|
+
|
138
|
+
Compatibility
|
139
|
+
-------------
|
140
|
+
|
141
|
+
Prior to publication, ORI gem has been thoroughly tested on:
|
142
|
+
|
143
|
+
* Ruby 1.9.2-p0 under Linux with RVM
|
144
|
+
* Ruby 1.8.7-p302 under Linux with RVM
|
145
|
+
* Ruby 1.8.7-p72 under Cygwin
|
146
|
+
* Ruby 1.8.7-p72 under 32-bit Windows Vista
|
147
|
+
|
148
|
+
|
149
|
+
Copyright
|
150
|
+
---------
|
151
|
+
|
152
|
+
Copyright © 2011 Alex Fortuna.
|
153
|
+
|
154
|
+
Licensed under the MIT License.
|
155
|
+
|
156
|
+
|
157
|
+
Feedback
|
158
|
+
--------
|
159
|
+
|
160
|
+
Send bug reports, suggestions and criticisms through [project's page on GitHub](http://github.com/dadooda/ori).
|
data/Rakefile
ADDED
@@ -0,0 +1,60 @@
|
|
1
|
+
require "rake/rdoctask"
|
2
|
+
require "yaml"
|
3
|
+
|
4
|
+
GEM_NAME = "ori"
|
5
|
+
|
6
|
+
begin
|
7
|
+
require "jeweler"
|
8
|
+
Jeweler::Tasks.new do |gem|
|
9
|
+
gem.name = GEM_NAME
|
10
|
+
gem.summary = "Object-Oriented RI for IRB Console"
|
11
|
+
gem.description = "Object-Oriented RI for IRB Console"
|
12
|
+
gem.email = "alex.r@askit.org"
|
13
|
+
gem.homepage = "http://github.com/dadooda/ori"
|
14
|
+
gem.authors = ["Alex Fortuna"]
|
15
|
+
gem.files = FileList[
|
16
|
+
"[A-Z]*",
|
17
|
+
"*.gemspec",
|
18
|
+
"lib/**/*.rb",
|
19
|
+
"samples/**/*",
|
20
|
+
"spec/**/*",
|
21
|
+
]
|
22
|
+
end
|
23
|
+
rescue LoadError
|
24
|
+
STDERR.puts "This gem requires Jeweler to be built"
|
25
|
+
end
|
26
|
+
|
27
|
+
desc "Rebuild gemspec and package"
|
28
|
+
task :rebuild => [:gemspec, :build, :readme]
|
29
|
+
|
30
|
+
desc "Push (publish) gem to RubyGems.org"
|
31
|
+
task :push do
|
32
|
+
# Yet found no way to ask Jeweler forge a complete version string for us.
|
33
|
+
vh = YAML.load(File.read("VERSION.yml"))
|
34
|
+
version = [vh[:major], vh[:minor], vh[:patch], (if (v = vh[:build]); v; end)].compact.join(".")
|
35
|
+
pkgfile = File.join("pkg", [GEM_NAME, "-", version, ".gem"].join)
|
36
|
+
Kernel.system("gem", "push", pkgfile)
|
37
|
+
end
|
38
|
+
|
39
|
+
desc "Generate README.html"
|
40
|
+
task :readme do
|
41
|
+
require "kramdown"
|
42
|
+
|
43
|
+
doc = Kramdown::Document.new(File.read "README.md")
|
44
|
+
|
45
|
+
fn = "README.html"
|
46
|
+
puts "Writing '#{fn}'..."
|
47
|
+
File.open(fn, "w") do |f|
|
48
|
+
f.write(File.read "dev/head.html")
|
49
|
+
f.write(doc.to_html)
|
50
|
+
end
|
51
|
+
puts ": ok"
|
52
|
+
end
|
53
|
+
|
54
|
+
desc "Generate rdoc documentation"
|
55
|
+
Rake::RDocTask.new(:rdoc) do |rdoc|
|
56
|
+
rdoc.rdoc_dir = "doc"
|
57
|
+
#rdoc.title = "ORI"
|
58
|
+
#rdoc.options << "--line-numbers" # No longer supported.
|
59
|
+
rdoc.rdoc_files.include("lib/**/*.rb")
|
60
|
+
end
|
data/VERSION.yml
ADDED
@@ -0,0 +1,11 @@
|
|
1
|
+
# NOTE: RDoc looks ugly. Just remove it, that's internal stuff anyway.
|
2
|
+
|
3
|
+
# Retain access to <tt>instance_method</tt> by providing a prefixed alias to it.
|
4
|
+
class Module #:nodoc:
|
5
|
+
alias_method :_ori_instance_method, :instance_method
|
6
|
+
end
|
7
|
+
|
8
|
+
# Retain access to <tt>method</tt> by providing a prefixed alias to it.
|
9
|
+
class Object #:nodoc:
|
10
|
+
alias_method :_ori_method, :method
|
11
|
+
end
|
data/lib/ori.rb
ADDED
@@ -0,0 +1,47 @@
|
|
1
|
+
require "rbconfig"
|
2
|
+
|
3
|
+
Dir[File.join(File.dirname(__FILE__), "{ext,misc,ori}/**/*.rb")].each do |fn|
|
4
|
+
require File.expand_path(fn)
|
5
|
+
end
|
6
|
+
|
7
|
+
# == Object-Oriented RI for IRB Console
|
8
|
+
#
|
9
|
+
# ORI brings RI documentation right to your IRB console in a simple, consistent and truly object-oriented way.
|
10
|
+
#
|
11
|
+
# To enable ORI add to your `~/.irbrc`:
|
12
|
+
#
|
13
|
+
# require "rubygems"
|
14
|
+
# require "ori"
|
15
|
+
#
|
16
|
+
# Quick test:
|
17
|
+
#
|
18
|
+
# $ irb
|
19
|
+
# irb> Array.ri
|
20
|
+
#
|
21
|
+
# You should see RI page on <tt>Array</tt>.
|
22
|
+
#
|
23
|
+
# See also:
|
24
|
+
# * <tt>ORI::Extensions::Object#ri</tt>
|
25
|
+
# * <tt>ORI::conf</tt>
|
26
|
+
module ORI
|
27
|
+
# Get configuration object to query or set its values.
|
28
|
+
# Note that default values are set automatically based on your OS and environment.
|
29
|
+
#
|
30
|
+
# ORI.conf.color = true
|
31
|
+
# ORI.conf.frontend = "ri -T -f ansi %s"
|
32
|
+
# ORI.conf.pager = "less -R"
|
33
|
+
# ORI.conf.shell_escape = :unix
|
34
|
+
#
|
35
|
+
# See also: ORI::Config.
|
36
|
+
def self.conf
|
37
|
+
@conf ||= begin
|
38
|
+
autoconf = AutoConfig.new((k = "host_os") => RbConfig::CONFIG[k])
|
39
|
+
Config.new({
|
40
|
+
(k = :color) => autoconf.send(k),
|
41
|
+
(k = :frontend) => autoconf.send(k),
|
42
|
+
(k = :pager) => autoconf.send(k),
|
43
|
+
(k = :shell_escape) => autoconf.send(k),
|
44
|
+
})
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|