gemma 1.0.0 → 2.0.0
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/README.rdoc +73 -94
- data/bin/gemma +1 -1
- data/lib/gemma.rb +4 -2
- data/lib/gemma/conventions.rb +21 -26
- data/lib/gemma/gem_from_template.rb +4 -10
- data/lib/gemma/options.rb +8 -4
- data/lib/gemma/rake_tasks.rb +11 -10
- data/lib/gemma/rake_tasks/gem_tasks.rb +38 -0
- data/lib/gemma/rake_tasks/{test_unit_tasks.rb → minitest_tasks.rb} +11 -7
- data/lib/gemma/rake_tasks/plugin.rb +2 -0
- data/lib/gemma/rake_tasks/rdoc_tasks.rb +4 -26
- data/lib/gemma/rake_tasks/run_tasks.rb +7 -16
- data/lib/gemma/rake_tasks/yard_tasks.rb +2 -1
- data/lib/gemma/version.rb +4 -1
- data/template/base/Gemfile +3 -0
- data/template/base/Rakefile.rb.erb +4 -7
- data/template/base/gem_name.gemspec.erb +5 -6
- data/template/base/lib/gem_name/version.rb.erb +4 -1
- data/template/executable/bin/gem_name.erb +1 -1
- data/template/{test_unit/test/test_gem_name.rb.erb → minitest/test/gem_name/gem_name_test.rb.erb} +2 -2
- data/test/gemma/gem_from_template_test.rb +64 -0
- data/test/gemma/gemma_new_test.rb +121 -0
- data/test/{test_gemma.rb → gemma/gemma_test.rb} +10 -23
- data/test/{test_options.rb → gemma/options_test.rb} +2 -4
- metadata +131 -80
- data/lib/gemma/rake_tasks/rcov_tasks.rb +0 -85
data/README.rdoc
CHANGED
@@ -2,18 +2,27 @@
|
|
2
2
|
|
3
3
|
http://github.com/jdleesmiller/gemma
|
4
4
|
|
5
|
+
http://github.com/jdleesmiller/gemma/wiki
|
6
|
+
|
5
7
|
== SYNOPSIS
|
6
8
|
|
7
9
|
Gemma is a gem development helper like hoe and jeweler, but it keeps the
|
8
|
-
gemspec in a gemspec file,
|
9
|
-
|
10
|
-
|
10
|
+
+gemspec+ in a <tt>.gemspec</tt> file, instead of in a +Rakefile+. This helps
|
11
|
+
your gem to play nicely with commands like +gem+ and +bundle+, and it allows
|
12
|
+
gemma to provide +rake+ tasks with sensible defaults for many common gem
|
11
13
|
development tasks.
|
12
14
|
|
13
|
-
See
|
14
|
-
|
15
|
+
See http://yehudakatz.com/2010/04/02/using-gemspecs-as-intended for some reasons
|
16
|
+
why you probably want a <tt>.gemspec</tt> file in your gem's repository.
|
17
|
+
|
18
|
+
=== Usage
|
19
|
+
|
20
|
+
See the project wiki for tutorials and guides:
|
21
|
+
https://github.com/jdleesmiller/gemma/wiki
|
22
|
+
|
23
|
+
Briefly:
|
15
24
|
|
16
|
-
|
25
|
+
==== Create a New Gem
|
17
26
|
|
18
27
|
Gemma has a simple interactive gem scaffolding tool; run
|
19
28
|
gemma new
|
@@ -21,57 +30,59 @@ and follow the prompts. (Run with -h for help.)
|
|
21
30
|
|
22
31
|
This gives you a simple gem template like the following:
|
23
32
|
|
24
|
-
|
33
|
+
my_gem
|
25
34
|
|-- bin
|
26
|
-
|
|
27
|
-
|--
|
28
|
-
|-- lib
|
29
|
-
| |--
|
30
|
-
| |
|
31
|
-
|
|
32
|
-
|--
|
33
|
-
|-- Rakefile.rb
|
34
|
-
|-- README.rdoc
|
35
|
-
|
36
|
-
|
35
|
+
| `-- my_gem # executable (optional)
|
36
|
+
|-- Gemfile # for bundler (see below)
|
37
|
+
|-- lib
|
38
|
+
| |-- my_gem # most of your code goes here
|
39
|
+
| | `-- version.rb # the version constant
|
40
|
+
| `-- my_gem.rb # the main code file
|
41
|
+
|-- my_gem.gemspec # gem metadata
|
42
|
+
|-- Rakefile.rb # development tasks
|
43
|
+
|-- README.rdoc # documentation
|
44
|
+
`-- test # unit tests go here
|
45
|
+
`-- my_gem
|
46
|
+
`-- my_gem_test.rb
|
37
47
|
|
38
48
|
Things you need to change in the template are marked with a +TODO+ tag.
|
39
49
|
|
40
|
-
|
50
|
+
==== To Modify an Existing Gem to use Gemma
|
41
51
|
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
http://docs.rubygems.org/read/chapter/20
|
46
|
-
for reference material. If you have been using hoe or jeweler, you already
|
47
|
-
have all of the information in your Rakefile, so you just have to move it into
|
48
|
-
a <tt>.gemspec</tt> file.
|
52
|
+
The main thing you need is a <tt>.gemspec</tt> file. If you have been using hoe
|
53
|
+
or jeweler, you already have all of the information in your Rakefile, so you
|
54
|
+
just have to move it into a <tt>.gemspec</tt> file.
|
49
55
|
|
50
56
|
Gemma provides rake tasks with sensible defaults based on the contents of
|
51
57
|
your gemspec; to enable them, add the following to the top of your +Rakefile+:
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
end
|
58
|
+
|
59
|
+
require 'rubygems'
|
60
|
+
require 'bundler/setup'
|
61
|
+
require 'gemma'
|
62
|
+
|
63
|
+
Gemma::RakeTasks.with_gemspec_file 'my_gem.gemspec'
|
64
|
+
|
65
|
+
task :default => :test
|
61
66
|
|
62
67
|
This gives you some standard rake tasks, in addition to any that you define
|
63
|
-
yourself.
|
64
|
-
|
68
|
+
yourself.
|
69
|
+
|
70
|
+
==== The Standard Tasks
|
71
|
+
|
72
|
+
Run <tt>rake -T</tt> for a full list of tasks.
|
65
73
|
|
74
|
+
% rake -T
|
75
|
+
rake build # Build my_gem-0.0.1.gem into the pkg directory
|
66
76
|
rake clean # Remove any temporary products.
|
67
77
|
rake clobber # Remove any generated file.
|
68
|
-
rake
|
69
|
-
rake
|
78
|
+
rake clobber_rdoc # Remove RDoc HTML files
|
79
|
+
rake install # Build and install my_gem-0.0.1.gem into system gems
|
80
|
+
rake my_gem[args] # run my_gem
|
81
|
+
rake rdoc # Build RDoc HTML files
|
82
|
+
rake release # Create tag v0.0.1 and build and push my_gem-0.0.1.gem ...
|
83
|
+
rake rerdoc # Rebuild RDoc HTML files
|
70
84
|
rake test # Run tests
|
71
85
|
rake yard # Generate YARD Documentation
|
72
|
-
... and more!
|
73
|
-
|
74
|
-
Run <tt>rake -T</tt> for a full list of tasks.
|
75
86
|
|
76
87
|
You can customize the standard tasks by passing a block to +with_gemspec_file+:
|
77
88
|
|
@@ -83,68 +94,27 @@ See the gemma API docs for more information.
|
|
83
94
|
|
84
95
|
== REQUIREMENTS
|
85
96
|
|
86
|
-
You must have ruby, rubygems and rake installed. Tasks are also included for
|
87
|
-
rcov (http://eigenclass.org/hiki.rb?rcov) and yard (http://yardoc.org/), if you
|
88
|
-
have them installed. Other dependencies are handled automatically.
|
89
|
-
|
90
97
|
Gemma has been tested on:
|
91
|
-
*
|
92
|
-
*
|
93
|
-
|
94
|
-
|
95
|
-
* with rcov 0.9.7.1 and 0.9.9
|
96
|
-
Gemma has not yet been tested on Windows.
|
98
|
+
* ruby 1.9.2p290 (2011-07-09 revision 32553) [i686-linux] and [x86_64-linux]
|
99
|
+
* ruby 1.8.7 (2011-06-30 patchlevel 352) [i686-linux] and [x86_64-linux]
|
100
|
+
|
101
|
+
Gemma has not yet been tested on Windows or Mac OS X.
|
97
102
|
|
98
103
|
== INSTALLATION
|
99
104
|
|
100
|
-
On
|
105
|
+
On RVM:
|
106
|
+
gem install gemma
|
101
107
|
|
108
|
+
On a system ruby:
|
102
109
|
sudo gem install gemma
|
103
110
|
|
104
111
|
== DEVELOPMENT
|
105
112
|
|
106
|
-
|
113
|
+
gem install bundler
|
107
114
|
git clone git://github.com/jdleesmiller/gemma.git
|
108
115
|
cd gemma
|
109
|
-
|
110
|
-
|
111
|
-
where X.X.X is the current gemma version.
|
112
|
-
|
113
|
-
== RELATED PROJECTS
|
114
|
-
|
115
|
-
There are many projects that help to automate common gem development tasks.
|
116
|
-
Hoe and Jeweler are the most popular; they generate the gemspec and tasks using
|
117
|
-
a configuration specified in the Rakefile, which is the opposite to what gemma
|
118
|
-
does. Mr Bones is a gem template generator that appears to be similar to Hoe
|
119
|
-
and Jeweler, but I haven't used it myself.
|
120
|
-
|
121
|
-
* http://seattlerb.rubyforge.org/hoe/
|
122
|
-
* http://github.com/technicalpickles/jeweler
|
123
|
-
* http://codeforpeople.rubyforge.org/bones/
|
124
|
-
|
125
|
-
Bundler also provides some support for gem development. It includes a simple gem
|
126
|
-
scaffolding generator, and the results are compatible with gemma. It also
|
127
|
-
includes some rake extensions for building, installing and releasing gems
|
128
|
-
(Bundler::GemHelper). (As of version 1.0.7.)
|
129
|
-
* http://gembundler.com
|
130
|
-
* http://gembundler.com/rubygems.html
|
131
|
-
|
132
|
-
gemesis provides tasks for building, releasing and installing gems based on the
|
133
|
-
gemspec, but (at the time of writing) it doesn't provide tasks for tests and
|
134
|
-
documentation, etc.
|
135
|
-
|
136
|
-
* http://github.com/markryall/gemesis/tree/master/lib/gemesis
|
137
|
-
|
138
|
-
rake-compiler provides support for compiling native extensions from a
|
139
|
-
gemspec, and it looks like it should work fairly well with gemma.
|
140
|
-
|
141
|
-
* http://github.com/luislavena/rake-compiler
|
142
|
-
|
143
|
-
|
144
|
-
Other helpful articles:
|
145
|
-
|
146
|
-
* http://rubygems.rubyforge.org/rubygems-update/Gem/Version.html
|
147
|
-
* http://jeffkreeftmeijer.com/2010/why-arent-you-using-git-flow/
|
116
|
+
bundle
|
117
|
+
rake -T # list development tasks
|
148
118
|
|
149
119
|
== TODO
|
150
120
|
|
@@ -156,11 +126,20 @@ Other helpful articles:
|
|
156
126
|
g.yard_dev.options.push('--protected', '--private')
|
157
127
|
end
|
158
128
|
* more tasks (e.g. to publish docs)
|
159
|
-
* tasks
|
129
|
+
* more tasks to support C extensions
|
130
|
+
* hooks for the rcov and/or simplecov coverage tools
|
131
|
+
* tasks for version control? (e.g. based on http://github.com/nvie/gitflow)
|
160
132
|
* contributions welcome!
|
161
133
|
|
162
134
|
== HISTORY
|
163
135
|
|
136
|
+
<em>2.0.0</em>
|
137
|
+
* now relies on bundler
|
138
|
+
* now specifies particular gem version that must be used for rake, rdoc and
|
139
|
+
yard; the old approach was to try to work with whatever was already installed,
|
140
|
+
but this proved too fragile
|
141
|
+
* removed rcov support, because it doesn't work on 1.9.x (see simplecov)
|
142
|
+
|
164
143
|
<em>1.0.0</em>
|
165
144
|
* added templates
|
166
145
|
* changed rdoc and yard tasks to use +require_paths+ instead of +files+
|
data/bin/gemma
CHANGED
data/lib/gemma.rb
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
require 'shellwords'
|
2
|
+
|
1
3
|
require 'gemma/version'
|
2
4
|
require 'gemma/utility'
|
3
5
|
require 'gemma/options'
|
@@ -5,11 +7,11 @@ require 'gemma/rake_tasks'
|
|
5
7
|
|
6
8
|
# Load default Rakefile plugins:
|
7
9
|
require 'gemma/rake_tasks/plugin'
|
8
|
-
require 'gemma/rake_tasks/rcov_tasks'
|
9
10
|
require 'gemma/rake_tasks/rdoc_tasks'
|
10
11
|
require 'gemma/rake_tasks/run_tasks'
|
11
12
|
require 'gemma/rake_tasks/yard_tasks'
|
12
|
-
require 'gemma/rake_tasks/
|
13
|
+
require 'gemma/rake_tasks/minitest_tasks'
|
14
|
+
require 'gemma/rake_tasks/gem_tasks'
|
13
15
|
|
14
16
|
require 'gemma/conventions'
|
15
17
|
require 'gemma/gem_from_template'
|
data/lib/gemma/conventions.rb
CHANGED
@@ -1,37 +1,32 @@
|
|
1
1
|
module Gemma
|
2
2
|
#
|
3
|
-
#
|
3
|
+
# Methods to check input against accepted conventions.
|
4
|
+
#
|
5
|
+
# For help on extensions:
|
6
|
+
# * http://nokogiri.org/tutorials/installing_nokogiri.html explains how to
|
7
|
+
# prepare several unices to build native extensions.
|
8
|
+
#
|
9
|
+
# General objectives for gemma:
|
10
|
+
# * follow and promote accepted conventions where obvious
|
11
|
+
# * make the outputs from rdoc, test, etc. work like they do in rubygems
|
12
|
+
# * avoid load path noise ($: << ...)
|
13
|
+
# * make it easy to start hacking on an existing gem that uses gemma
|
14
|
+
# - git clone ...
|
15
|
+
# - gem install bundle
|
16
|
+
# - bundle # install both gemma dependencies and the gem's dependencies
|
17
|
+
# - rake -T # should now work
|
4
18
|
#
|
5
19
|
module Conventions
|
6
|
-
#
|
7
|
-
# References:
|
8
|
-
# http://stackoverflow.com/questions/221320/standard-file-naming-conventions-in-ruby
|
9
|
-
# http://containerdiv.wordpress.com/2009/05/24/ruby-gems-vs-rails-plugins/
|
10
|
-
#
|
11
|
-
# There is probably a required format (regex) for names, but I've never
|
12
|
-
# figured out what it is. It should be a valid file/directory name on
|
13
|
-
# Windows.
|
14
|
-
#
|
15
|
-
GOOD_GEM_NAME_TIPS = <<-STRING
|
16
|
-
Some tips for good gem names:
|
17
|
-
* use lower case
|
18
|
-
* separate words with _ (underscore)
|
19
|
-
* don't put 'ruby' in the name; this is implied, because it's a rubygem
|
20
|
-
|
21
|
-
It is also common to use a hyphen (-) to separate words.
|
22
|
-
|
23
|
-
If your gem name is my_new_gem, it can be installed with
|
24
|
-
sudo gem install my_new_gem
|
25
|
-
used in scripts with
|
26
|
-
require 'rubygems'
|
27
|
-
require 'my_new_gem'
|
28
|
-
and its contents should be contained in a module or class called MyNewGem.
|
29
|
-
STRING
|
30
|
-
|
31
20
|
#
|
32
21
|
# Check gem naming conventions; this is sufficient but not necessary for
|
33
22
|
# the gem name to be valid.
|
34
23
|
#
|
24
|
+
# References:
|
25
|
+
# * http://guides.rubygems.org/patterns/
|
26
|
+
# * http://blog.segment7.net/articles/2010/11/15/how-to-name-gems
|
27
|
+
# * http://stackoverflow.com/questions/221320/standard-file-naming-conventions-in-ruby
|
28
|
+
# * http://containerdiv.wordpress.com/2009/05/24/ruby-gems-vs-rails-plugins/
|
29
|
+
#
|
35
30
|
# @return [Boolean]
|
36
31
|
#
|
37
32
|
def self.good_gem_name? gem_name
|
@@ -17,7 +17,7 @@ module Gemma
|
|
17
17
|
# there are files that occur in multiple templates (files in earlier
|
18
18
|
# templates are overwritten by those in later templates, at present).
|
19
19
|
#
|
20
|
-
BUILTIN_TEMPLATES = %w(base executable
|
20
|
+
BUILTIN_TEMPLATES = %w(base executable minitest)
|
21
21
|
|
22
22
|
def initialize
|
23
23
|
@gem_name = nil
|
@@ -78,18 +78,12 @@ module Gemma
|
|
78
78
|
File.expand_path(File.join('.',self.dir_name))
|
79
79
|
end
|
80
80
|
|
81
|
-
#
|
82
|
-
# Gem version requirement for the development dependency on gemma.
|
83
|
-
#
|
84
|
-
# @return [String]
|
85
|
-
#
|
86
|
-
def gemma_version_requirement
|
87
|
-
"~> #{Gemma::VERSION.split(/\./).take(2).join('.')}"
|
88
|
-
end
|
89
|
-
|
90
81
|
#
|
91
82
|
# Copy given templates to +destination_path+ and run erb where needed.
|
92
83
|
#
|
84
|
+
# @param [Array<String>] template_paths absolute paths of the template
|
85
|
+
# directories to copy
|
86
|
+
#
|
93
87
|
def create_gem template_paths, destination_path=self.destination_path
|
94
88
|
raise "destination #{destination_path} exists" if File.exists?(
|
95
89
|
destination_path)
|
data/lib/gemma/options.rb
CHANGED
@@ -33,20 +33,24 @@ module Gemma
|
|
33
33
|
# Matching options that appear after a `--` terminator are not extracted;
|
34
34
|
# they remain in the {ExtractResult#remaining_options} list.
|
35
35
|
#
|
36
|
+
# The +options+ parameter takes an array of arguments; to split a string
|
37
|
+
# into the appropriate form, you can use the +Shellwords+ module in the ruby
|
38
|
+
# standard library.
|
39
|
+
#
|
36
40
|
# @example
|
37
41
|
# Gemma::Options.extract(%w(-a), %w(-a foo bar.txt))
|
38
42
|
# #=> #<struct Gemma::Options::ExtractResult argument="foo",
|
39
43
|
# # remaining_options=["bar.txt"]>
|
40
44
|
#
|
41
45
|
# @param [Array<String>] names one or more names for the option to extract
|
42
|
-
#
|
46
|
+
# (`['--file','-f']`, for example)
|
43
47
|
#
|
44
48
|
# @param [Array<String>] options to extract from; you should ensure that
|
45
|
-
#
|
46
|
-
# doesn't detect it
|
49
|
+
# there isn't leading/trailing whitespace (strip), because this
|
50
|
+
# method doesn't detect it
|
47
51
|
#
|
48
52
|
# @return [ExtractResult] contains the argument for the given option and the
|
49
|
-
#
|
53
|
+
# rest of the options
|
50
54
|
#
|
51
55
|
def self.extract names, options
|
52
56
|
options = options.dup
|
data/lib/gemma/rake_tasks.rb
CHANGED
@@ -8,6 +8,7 @@ module Gemma
|
|
8
8
|
# @example To create the default tasks based on your _mygem_.gemspec file:
|
9
9
|
# # At the top of Rakefile.rb.
|
10
10
|
# require 'rubygems'
|
11
|
+
# require 'bundler/setup'
|
11
12
|
# require 'gemma'
|
12
13
|
#
|
13
14
|
# Gemma::RakeTasks.with_gemspec_file 'mygem.gemspec'
|
@@ -22,7 +23,7 @@ module Gemma
|
|
22
23
|
end
|
23
24
|
|
24
25
|
#
|
25
|
-
# Constructor for internal use; you should usually use the
|
26
|
+
# Constructor mainly for internal use; you should usually use the
|
26
27
|
# `with_gemspec_file` alias (see examples in {RakeTasks}).
|
27
28
|
#
|
28
29
|
# @param [String, Gem::Specification] gemspec either the name of a gemspec
|
@@ -43,7 +44,7 @@ module Gemma
|
|
43
44
|
@gemspec_file_name = nil
|
44
45
|
@gemspec = gemspec
|
45
46
|
else
|
46
|
-
raise ArgumentError
|
47
|
+
raise ArgumentError, 'bad gemspec argument'
|
47
48
|
end
|
48
49
|
|
49
50
|
@plugins = {}
|
@@ -82,11 +83,6 @@ module Gemma
|
|
82
83
|
#
|
83
84
|
attr_reader :plugins
|
84
85
|
|
85
|
-
#
|
86
|
-
# @return [RcovTasks]
|
87
|
-
#
|
88
|
-
def rcov; @plugins[:rcov] end
|
89
|
-
|
90
86
|
#
|
91
87
|
# @return [RDocTasks]
|
92
88
|
#
|
@@ -98,7 +94,7 @@ module Gemma
|
|
98
94
|
def run; @plugins[:run] end
|
99
95
|
|
100
96
|
#
|
101
|
-
# @return [
|
97
|
+
# @return [MinitestTasks]
|
102
98
|
#
|
103
99
|
def test; @plugins[:test] end
|
104
100
|
|
@@ -107,14 +103,19 @@ module Gemma
|
|
107
103
|
#
|
108
104
|
def yard; @plugins[:yard] end
|
109
105
|
|
106
|
+
#
|
107
|
+
# @return [GemTasks]
|
108
|
+
#
|
109
|
+
def gem; @plugins[:gem] end
|
110
|
+
|
110
111
|
protected
|
111
112
|
|
112
113
|
def create_default_plugins
|
113
|
-
@plugins[:rcov] = Gemma::RakeTasks::RcovTasks.new(gemspec)
|
114
114
|
@plugins[:rdoc] = Gemma::RakeTasks::RDocTasks.new(gemspec)
|
115
115
|
@plugins[:run] = Gemma::RakeTasks::RunTasks.new(gemspec)
|
116
|
-
@plugins[:test] = Gemma::RakeTasks::
|
116
|
+
@plugins[:test] = Gemma::RakeTasks::MinitestTasks.new(gemspec)
|
117
117
|
@plugins[:yard] = Gemma::RakeTasks::YardTasks.new(gemspec)
|
118
|
+
@plugins[:gem] = Gemma::RakeTasks::GemTasks.new(gemspec,gemspec_file_name)
|
118
119
|
end
|
119
120
|
end
|
120
121
|
end
|
@@ -0,0 +1,38 @@
|
|
1
|
+
module Gemma
|
2
|
+
class RakeTasks
|
3
|
+
#
|
4
|
+
# Create tasks for building and releasing gems.
|
5
|
+
#
|
6
|
+
# Note that the +release+ task is git-specific, but the other tasks are not
|
7
|
+
# specific to any particular version control system.
|
8
|
+
#
|
9
|
+
# This plugin just calls <tt>Bundler::GemHelper</tt> with the given gemspec.
|
10
|
+
#
|
11
|
+
class GemTasks < Plugin
|
12
|
+
#
|
13
|
+
# @param [Gem::Specification] gemspec
|
14
|
+
# @param [String, nil] gemspec_file_name
|
15
|
+
#
|
16
|
+
def initialize gemspec, gemspec_file_name
|
17
|
+
super(gemspec)
|
18
|
+
@gemspec_file_name = gemspec_file_name
|
19
|
+
end
|
20
|
+
|
21
|
+
#
|
22
|
+
# Internal method; see {Plugin#create_rake_tasks}.
|
23
|
+
#
|
24
|
+
# @return [nil]
|
25
|
+
#
|
26
|
+
# @private
|
27
|
+
#
|
28
|
+
def create_rake_tasks
|
29
|
+
require 'bundler/gem_helper'
|
30
|
+
dir = File.dirname(@gemspec_file_name) if @gemspec_file_name
|
31
|
+
Bundler::GemHelper.install_tasks(:dir => dir,
|
32
|
+
:name => gemspec.name)
|
33
|
+
nil
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|