git-process 0.9.1.pre3

Sign up to get free protection for your applications and to get access to all the features.
Files changed (44) hide show
  1. data/.gitignore +16 -0
  2. data/.rspec +3 -0
  3. data/.travis.yml +4 -0
  4. data/Gemfile +22 -0
  5. data/Gemfile.lock +56 -0
  6. data/LICENSE +22 -0
  7. data/README.md +80 -0
  8. data/Rakefile +16 -0
  9. data/bin/git-new-fb +21 -0
  10. data/bin/git-pull-request +21 -0
  11. data/bin/git-sync +21 -0
  12. data/bin/git-to-master +21 -0
  13. data/git-process.gemspec +21 -0
  14. data/lib/git-process/abstract-error-builder.rb +46 -0
  15. data/lib/git-process/git-abstract-merge-error-builder.rb +115 -0
  16. data/lib/git-process/git-branch.rb +86 -0
  17. data/lib/git-process/git-branches.rb +53 -0
  18. data/lib/git-process/git-lib.rb +413 -0
  19. data/lib/git-process/git-merge-error.rb +31 -0
  20. data/lib/git-process/git-new-fb-options.rb +34 -0
  21. data/lib/git-process/git-process-error.rb +10 -0
  22. data/lib/git-process/git-process-options.rb +82 -0
  23. data/lib/git-process/git-process.rb +194 -0
  24. data/lib/git-process/git-pull-request-options.rb +42 -0
  25. data/lib/git-process/git-rebase-error.rb +31 -0
  26. data/lib/git-process/git-status.rb +72 -0
  27. data/lib/git-process/git-sync-options.rb +34 -0
  28. data/lib/git-process/git-to-master-options.rb +18 -0
  29. data/lib/git-process/github-client.rb +73 -0
  30. data/lib/git-process/github-service.rb +156 -0
  31. data/lib/git-process/parked-changes-error.rb +32 -0
  32. data/lib/git-process/pull-request.rb +38 -0
  33. data/lib/git-process/uncommitted-changes-error.rb +15 -0
  34. data/lib/git-process/version.rb +12 -0
  35. data/spec/FileHelpers.rb +18 -0
  36. data/spec/GitRepoHelper.rb +86 -0
  37. data/spec/git-abstract-merge-error-builder_spec.rb +113 -0
  38. data/spec/git-lib_spec.rb +118 -0
  39. data/spec/git-process_spec.rb +328 -0
  40. data/spec/git-status_spec.rb +101 -0
  41. data/spec/github-service_spec.rb +209 -0
  42. data/spec/pull-request_spec.rb +57 -0
  43. data/spec/spec_helper.rb +1 -0
  44. metadata +133 -0
data/.gitignore ADDED
@@ -0,0 +1,16 @@
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ .config
5
+ .yardoc
6
+ InstalledFiles
7
+ _yardoc
8
+ coverage
9
+ doc/
10
+ lib/bundler/man
11
+ pkg
12
+ rdoc
13
+ spec/reports
14
+ test/tmp
15
+ test/version_tmp
16
+ tmp
data/.rspec ADDED
@@ -0,0 +1,3 @@
1
+ --color
2
+ --format documentation
3
+ --require spec_helper
data/.travis.yml ADDED
@@ -0,0 +1,4 @@
1
+ language: ruby
2
+ rvm:
3
+ - 1.8.7
4
+
data/Gemfile ADDED
@@ -0,0 +1,22 @@
1
+ source "http://rubygems.org"
2
+
3
+ # gem "git", "~> 1.2.5"
4
+ # gem "rugged" # "git" bindings for libgit2
5
+ gem "launchy", "~> 2.1.0" # web browser interaction
6
+ gem "octokit", "~> 1.4.0" # GitHub API
7
+ gem "json", "~> 1.7.3"
8
+ gem "highline", "~> 1.6.12" # user CLI interaction
9
+ gem "termios", "~> 0.9.4" # used by highline to make things a little nicer
10
+ gem "system_timer", "~> 1.2.4" # Needed by faraday via octokit
11
+
12
+ group :test do
13
+ gem "rspec", "~> 2.10.0", :group => :test
14
+ gem "rspec-mocks", "~> 2.10.0", :group => :test
15
+ gem "webmock", "~> 1.8.7", :group => :test # network mocking
16
+ end
17
+
18
+ group :development do
19
+ gem "rake", "~> 0.9.2"
20
+ gem "yard", "~> 0.8.2.1"
21
+ gem "redcarpet", "~> 2.1.1"
22
+ end
data/Gemfile.lock ADDED
@@ -0,0 +1,56 @@
1
+ GEM
2
+ remote: http://rubygems.org/
3
+ specs:
4
+ addressable (2.2.8)
5
+ crack (0.3.1)
6
+ diff-lcs (1.1.3)
7
+ faraday (0.8.1)
8
+ multipart-post (~> 1.1)
9
+ faraday_middleware (0.8.7)
10
+ faraday (>= 0.7.4, < 0.9)
11
+ hashie (1.2.0)
12
+ highline (1.6.12)
13
+ json (1.7.3)
14
+ launchy (2.1.0)
15
+ addressable (~> 2.2.6)
16
+ multi_json (1.3.6)
17
+ multipart-post (1.1.5)
18
+ octokit (1.4.0)
19
+ addressable (~> 2.2)
20
+ faraday (~> 0.8)
21
+ faraday_middleware (~> 0.8)
22
+ hashie (~> 1.2)
23
+ multi_json (~> 1.3)
24
+ rake (0.9.2)
25
+ redcarpet (2.1.1)
26
+ rspec (2.10.0)
27
+ rspec-core (~> 2.10.0)
28
+ rspec-expectations (~> 2.10.0)
29
+ rspec-mocks (~> 2.10.0)
30
+ rspec-core (2.10.1)
31
+ rspec-expectations (2.10.0)
32
+ diff-lcs (~> 1.1.3)
33
+ rspec-mocks (2.10.1)
34
+ system_timer (1.2.4)
35
+ termios (0.9.4)
36
+ webmock (1.8.7)
37
+ addressable (>= 2.2.7)
38
+ crack (>= 0.1.7)
39
+ yard (0.8.2.1)
40
+
41
+ PLATFORMS
42
+ ruby
43
+
44
+ DEPENDENCIES
45
+ highline (~> 1.6.12)
46
+ json (~> 1.7.3)
47
+ launchy (~> 2.1.0)
48
+ octokit (~> 1.4.0)
49
+ rake (~> 0.9.2)
50
+ redcarpet (~> 2.1.1)
51
+ rspec (~> 2.10.0)
52
+ rspec-mocks (~> 2.10.0)
53
+ system_timer (~> 1.2.4)
54
+ termios (~> 0.9.4)
55
+ webmock (~> 1.8.7)
56
+ yard (~> 0.8.2.1)
data/LICENSE ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2012 Jim Moore
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,80 @@
1
+ [![Build Status](https://secure.travis-ci.org/jdigger/git-process.png)](http://travis-ci.org/jdigger/git-process)
2
+
3
+ # Purpose #
4
+
5
+ This provides an easy way to work with a sane git workflow process.
6
+
7
+
8
+ # Installation #
9
+
10
+ $ gem install git-process
11
+
12
+ # Overview #
13
+
14
+ * `git new-fb` - Create a new feature branch based on the integration branch.
15
+ * `git sync` - Gets the latest changes that have happened on the integration branch, then pushes your changes to a "private" branch on the server.
16
+ * `git pull-request` - Creates a Pull Request for the current branch.
17
+ * `git to-master` - Rebase against the integration branch, then pushes to it.
18
+
19
+ # Workflow #
20
+
21
+ _The following assumes that the integration branch is "origin/master"._
22
+
23
+ ## Code Review Using Pull Requests ##
24
+
25
+ 1. When starting work on a new feature, use "`git new-fb feature-name`".
26
+ * This creates a new branch called "`feature-name`" based on "`origin/master`".
27
+ 2. After making some changes, if you want to pick up any changes other people have made, as well
28
+ as save your work on the server, do "`git synch`".
29
+ * That will merge in the changes that have occurred in "`origin/master`" and then push the
30
+ result to the "`feature_branch`" branch to the server.
31
+ 3. When you feel your work is ready for others to look at, do another "`git sync`" to post your
32
+ changes to the server, and then "`git pull-request`" to ask someone to review your changes.
33
+ 4. If you get the thumbs up from the code-review, use "`git to-master`".
34
+ * This will merge and push your changes into "`origin/master`"
35
+ 5. If you still need to make changes, do so and use "`git sync`" to keep your branch on the
36
+ server for that feature updated with your work until all issues have been resolved.
37
+
38
+ ## Working Alone or When Pairing ##
39
+
40
+ 1. When starting work on a new feature, use "`git new-fb feature-name`".
41
+ * This creates a new branch called "`feature-name`" based on "`origin/master`".
42
+ 2. After making some changes, if you want to pick up any changes other people have made, as well
43
+ as save your work on the server, do "`git synch`".
44
+ * That will merge in the changes that have occurred in "`origin/master`" and then push the
45
+ result to the "`feature_branch`" branch to the server.
46
+ 3. When you are ready to merge your work into the mainline, "`git to-master`".
47
+ * This will merge and push your changes into "`origin/master`"
48
+
49
+ # Notes #
50
+
51
+ * It's assumed that you **_never_** do any work directly on "master": everything is done on a
52
+ feature branch. This is a much safer and more flexible practice, but may seem odd to
53
+ people used to old VCSs.
54
+ * After publishing changes to the main integration branch (i.e., "`git to-master`") the
55
+ old feature branch is removed as part of cleanup. Git is then "parked" on a "`_parking_`"
56
+ branch until a new feature branch is created. Work is not expected to be done on this
57
+ branch, but any that is done is brought over to a newly created feature branch (i.e.,
58
+ "`git new-fb`").
59
+ * The first time you use a GitHub feature (e.g., "`git pull-request`"), this will ask for your
60
+ username and password. It does not store them, but instead uses them to get an OAuth2 token,
61
+ which is stored in "`git config gitProcess.github.authToken`".
62
+
63
+ ## Misc ##
64
+
65
+ * http://git-scm.com/2010/03/08/rerere.html
66
+ * http://git.kernel.org/?p=git/git.git;a=blob;f=contrib/rerere-train.sh;hb=HEAD
67
+ * https://github.com/b4mboo/git-review
68
+
69
+
70
+ # Contributing #
71
+
72
+ ## Coding Setup ##
73
+
74
+ 1. Fork it
75
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
76
+ 3. Commit your changes (`git commit -am 'Added some feature'`)
77
+ 4. Push to the branch (`git push origin my-new-feature`)
78
+ 5. Create new Pull Request
79
+
80
+ The tests are written for RSpec 2.
data/Rakefile ADDED
@@ -0,0 +1,16 @@
1
+ #!/usr/bin/env rake
2
+ require 'bundler/gem_tasks'
3
+ require 'rspec/core/rake_task'
4
+ require 'yard'
5
+ require 'yard/rake/yardoc_task'
6
+
7
+ desc 'Default: run specs.'
8
+ task :default => :spec
9
+
10
+ desc "Run specs"
11
+ RSpec::Core::RakeTask.new do |t|
12
+ t.pattern = "./spec/**/*_spec.rb" # don't need this, it's default.
13
+ end
14
+
15
+ desc "Create docs"
16
+ YARD::Rake::YardocTask.new
data/bin/git-new-fb ADDED
@@ -0,0 +1,21 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require "rubygems"
4
+ require "bundler/setup"
5
+
6
+ require 'logger'
7
+
8
+ $LOAD_PATH.unshift File.join(File.dirname(__FILE__), '../lib/git-process')
9
+ require 'git-new-fb-options'
10
+ require 'git-process'
11
+
12
+ options = Git::Process::NewFeatureBranchOptions.new(File.basename(__FILE__), ARGV)
13
+
14
+ gp = Git::Process.new('.', nil, :log_level => options.log_level)
15
+
16
+ begin
17
+ gp.new_feature_branch(options.branch_name)
18
+ rescue Git::Process::GitProcessError => exp
19
+ puts exp.message
20
+ exit(-1)
21
+ end
@@ -0,0 +1,21 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require "rubygems"
4
+ require "bundler/setup"
5
+
6
+ require 'logger'
7
+
8
+ $LOAD_PATH.unshift File.join(File.dirname(__FILE__), '../lib/git-process')
9
+ require 'git-pull-request-options'
10
+ require 'git-process'
11
+
12
+ options = Git::Process::PullRequestOptions.new(File.basename(__FILE__), ARGV)
13
+
14
+ gp = Git::Process.new('.', nil, :log_level => options.log_level)
15
+
16
+ begin
17
+ gp.create(nil, nil, nil, options.title, options.description, :user => options.user, :password => options.password)
18
+ rescue Git::Process::GitProcessError => exp
19
+ puts exp.message
20
+ exit(-1)
21
+ end
data/bin/git-sync ADDED
@@ -0,0 +1,21 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require "rubygems"
4
+ require "bundler/setup"
5
+
6
+ require 'logger'
7
+
8
+ $LOAD_PATH.unshift File.join(File.dirname(__FILE__), '../lib/git-process')
9
+ require 'git-sync-options'
10
+ require 'git-process'
11
+
12
+ options = Git::Process::SyncOptions.new(File.basename(__FILE__), ARGV)
13
+
14
+ gp = Git::Process.new('.', nil, :log_level => options.log_level)
15
+
16
+ begin
17
+ gp.sync_with_server(options.rebase, options.force)
18
+ rescue Git::Process::GitProcessError => exp
19
+ puts exp.message
20
+ exit(-1)
21
+ end
data/bin/git-to-master ADDED
@@ -0,0 +1,21 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require "rubygems"
4
+ require "bundler/setup"
5
+
6
+ require 'logger'
7
+
8
+ $LOAD_PATH.unshift File.join(File.dirname(__FILE__), '../lib/git-process')
9
+ require 'git-to-master-options'
10
+ require 'git-process'
11
+
12
+ options = Git::Process::ToMasterOptions.new(File.basename(__FILE__), ARGV)
13
+
14
+ gp = Git::Process.new('.', nil, :log_level => options.log_level)
15
+
16
+ begin
17
+ gp.rebase_to_master
18
+ rescue Git::Process::GitProcessError => exp
19
+ puts exp.message
20
+ exit(-1)
21
+ end
@@ -0,0 +1,21 @@
1
+ # -*- encoding: utf-8 -*-
2
+ require File.expand_path('../lib/git-process/version', __FILE__)
3
+
4
+ Gem::Specification.new do |gem|
5
+ gem.authors = ["Jim Moore"]
6
+ gem.email = ["moore.jim@gmail.com"]
7
+ gem.description = %q{A set of scripts to make working with git easier and more consistent}
8
+ gem.summary = %q{A set of scripts for a good git process}
9
+ gem.homepage = "http://jdigger.github.com/git-process/"
10
+
11
+ gem.add_development_dependency "rspec"
12
+
13
+ gem.files = `git ls-files`.split($\)
14
+ gem.executables = gem.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
15
+ gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
16
+ gem.name = "git-process"
17
+ gem.require_paths = ["lib"]
18
+ gem.version = Git::Process::Version::STRING
19
+ gem.platform = Gem::Platform::RUBY
20
+ gem.required_ruby_version = '>= 1.8.7'
21
+ end
@@ -0,0 +1,46 @@
1
+ require 'git-lib'
2
+ require 'git-process-error'
3
+ require 'shellwords'
4
+
5
+ module Git
6
+
7
+ #
8
+ # Assumes that there are two attributes defined: error_message, lib
9
+ #
10
+ module AbstractErrorBuilder
11
+
12
+ def commands
13
+ @commands ||= build_commands
14
+ end
15
+
16
+
17
+ def build_message
18
+ msg = human_message
19
+
20
+ msg << append_commands
21
+ end
22
+
23
+
24
+ def append_commands
25
+ commands.empty? ? '' : "\n\nCommands:\n\n #{commands.join("\n ")}"
26
+ end
27
+
28
+
29
+ def human_message
30
+ ''
31
+ end
32
+
33
+
34
+ def build_commands
35
+ []
36
+ end
37
+
38
+
39
+ def shell_escaped_files(files)
40
+ shell_escaped_files = files.map{|f| f.shellescape}
41
+ shell_escaped_files.join(' ')
42
+ end
43
+
44
+ end
45
+
46
+ end
@@ -0,0 +1,115 @@
1
+ require 'git-lib'
2
+ require 'abstract-error-builder'
3
+ require 'git-process-error'
4
+ require 'shellwords'
5
+
6
+ module Git
7
+
8
+ #
9
+ # Assumes that there are three attributes defined: error_message, lib, continue_command
10
+ #
11
+ module AbstractMergeErrorBuilder
12
+ include AbstractErrorBuilder
13
+
14
+ def resolved_files
15
+ @resolved_files ||= find_resolved_files
16
+ end
17
+
18
+
19
+ def unresolved_files
20
+ @unresolved_files ||= (unmerged - resolved_files)
21
+ end
22
+
23
+
24
+ def find_resolved_files
25
+ resolved_files = []
26
+
27
+ unmerged.each do |file|
28
+ resolved_file = (/Resolved '#{file}' using previous resolution./m =~ error_message)
29
+ resolved_files << file if resolved_file
30
+ end
31
+
32
+ resolved_files.sort
33
+ end
34
+
35
+
36
+ def human_message
37
+ msg = 'There was a problem merging.'
38
+
39
+ resolved_files.each do |file|
40
+ if modified.include? file
41
+ msg << "\n'#{file}' was modified in both branches, and 'rerere' automatically resolved it."
42
+ end
43
+ end
44
+
45
+ unless lib.rerere_enabled?
46
+ msg << "\n\nConsider turning on 'rerere'.\nSee http://git-scm.com/2010/03/08/rerere.html for more information."
47
+ end
48
+
49
+ unresolved_files.each do |file|
50
+ if modified.include? file
51
+ msg << "\n'#{file}' was modified in both branches."
52
+ end
53
+ end
54
+
55
+ msg
56
+ end
57
+
58
+
59
+ def build_commands
60
+ commands = []
61
+
62
+ commands << 'git config --global rerere.enabled true' unless lib.rerere_enabled?
63
+
64
+ resolved_files.each do |file|
65
+ commands << "# Verify that 'rerere' did the right thing for '#{file}'."
66
+ end
67
+
68
+ unless resolved_files.empty? or lib.rerere_autoupdate?
69
+ escaped_files = shell_escaped_files(resolved_files)
70
+ commands << "git add #{escaped_files}"
71
+ end
72
+
73
+ unless unresolved_files.empty?
74
+ mergeable = unresolved_files & modified
75
+ commands << "git mergetool #{shell_escaped_files(mergeable)}" unless mergeable.empty?
76
+ mergeable.each do |f|
77
+ commands << "# Verify '#{f}' merged correctly."
78
+ end
79
+ (unresolved_files & added).each do |f|
80
+ commands << "# '#{f}' was added in both branches; Fix the conflict."
81
+ end
82
+ commands << "git add #{shell_escaped_files(unresolved_files)}"
83
+ end
84
+
85
+ commands << continue_command if continue_command
86
+
87
+ commands
88
+ end
89
+
90
+
91
+ attr_writer :unmerged, :added, :deleted, :modified
92
+
93
+
94
+ def unmerged
95
+ @unmerged ||= lib.status.unmerged
96
+ end
97
+
98
+
99
+ def added
100
+ @added ||= lib.status.added
101
+ end
102
+
103
+
104
+ def deleted
105
+ @deleted ||= lib.status.deleted
106
+ end
107
+
108
+
109
+ def modified
110
+ @modified ||= lib.status.modified
111
+ end
112
+
113
+ end
114
+
115
+ end
@@ -0,0 +1,86 @@
1
+ module Git
2
+
3
+ class GitBranch
4
+ include Comparable
5
+
6
+ attr_reader :name
7
+
8
+ def initialize(name, current, lib)
9
+ if (/^remotes\// =~ name)
10
+ @name = name[8..-1]
11
+ @remote = true
12
+ else
13
+ @name = name
14
+ @remote = false
15
+ end
16
+ @current = current
17
+ @lib = lib
18
+ end
19
+
20
+
21
+ def current?
22
+ @current
23
+ end
24
+
25
+
26
+ def remote?
27
+ @remote
28
+ end
29
+
30
+
31
+ def local?
32
+ !@remote
33
+ end
34
+
35
+
36
+ def to_s
37
+ name
38
+ end
39
+
40
+
41
+ def logger
42
+ @lib.logger
43
+ end
44
+
45
+
46
+ def sha
47
+ @sha ||= @lib.sha(name)
48
+ end
49
+
50
+
51
+ def <=>(other)
52
+ self.name <=> other.name
53
+ end
54
+
55
+
56
+ def is_ahead_of(base_branch_name)
57
+ @lib.rev_list(base_branch_name, @name, :oneline => true, :num_revs => 1) != ''
58
+ end
59
+
60
+
61
+ def delete(force = false)
62
+ if local?
63
+ @lib.branch(@name, :force => force, :delete => true)
64
+ else
65
+ @lib.push(Process.server_name, nil, nil, :delete => @name)
66
+ end
67
+ end
68
+
69
+
70
+ def rename(new_name)
71
+ @lib.branch(@name, :rename => new_name)
72
+ end
73
+
74
+
75
+ def contains_all_of(branch_name)
76
+ @lib.rev_list(@name, branch_name, :oneline => true, :num_revs => 1) == ''
77
+ end
78
+
79
+
80
+ def checkout_to_new(new_branch, opts = {})
81
+ @lib.checkout(new_branch, :new_branch => @name, :no_track => opts[:no_track])
82
+ end
83
+
84
+ end
85
+
86
+ end
@@ -0,0 +1,53 @@
1
+ require 'git-branch'
2
+
3
+ module Git
4
+
5
+ class GitBranches
6
+ include Enumerable
7
+
8
+ def initialize(lib)
9
+ branch_lines = lib.branch(nil, :all => true, :no_color => true).split("\n")
10
+ @items = SortedSet.new
11
+ branch_lines.each do |bl|
12
+ @items << GitBranch.new(bl[2..-1], bl[0..0] == '*', lib)
13
+ end
14
+ end
15
+
16
+
17
+ def <<(item)
18
+ @items << item
19
+ end
20
+
21
+
22
+ def each(&block)
23
+ @items.each {|b| block.call(b)}
24
+ end
25
+
26
+
27
+ def names
28
+ @items.map {|b| b.name}
29
+ end
30
+
31
+
32
+ def current
33
+ @items.find {|b| b.current? }
34
+ end
35
+
36
+
37
+ def parking
38
+ @items.find {|b| b.name == '_parking_' }
39
+ end
40
+
41
+
42
+ def include?(branch_name)
43
+ @items.find {|b| b.name == branch_name} != nil
44
+ end
45
+
46
+
47
+ def [](branch_name)
48
+ @items.find {|b| b.name == branch_name}
49
+ end
50
+
51
+ end
52
+
53
+ end