capistrano 3.6.1 → 3.7.0.beta1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.github/issue_template.md +19 -0
- data/.github/pull_request_template.md +26 -0
- data/.gitignore +1 -0
- data/.travis.yml +5 -1
- data/CHANGELOG.md +27 -1
- data/DEVELOPMENT.md +7 -1
- data/README.md +3 -4
- data/capistrano.gemspec +1 -1
- data/features/support/vagrant_helpers.rb +3 -5
- data/lib/capistrano/all.rb +1 -0
- data/lib/capistrano/configuration.rb +12 -2
- data/lib/capistrano/configuration/host_filter.rb +1 -1
- data/lib/capistrano/configuration/plugin_installer.rb +20 -2
- data/lib/capistrano/configuration/role_filter.rb +1 -1
- data/lib/capistrano/configuration/scm_resolver.rb +144 -0
- data/lib/capistrano/configuration/validated_variables.rb +3 -4
- data/lib/capistrano/defaults.rb +3 -1
- data/lib/capistrano/doctor/variables_doctor.rb +1 -1
- data/lib/capistrano/dsl/env.rb +2 -9
- data/lib/capistrano/dsl/paths.rb +1 -1
- data/lib/capistrano/dsl/task_enhancements.rb +0 -8
- data/lib/capistrano/scm/git.rb +73 -0
- data/lib/capistrano/scm/hg.rb +48 -0
- data/lib/capistrano/scm/plugin.rb +13 -0
- data/lib/capistrano/scm/svn.rb +47 -0
- data/lib/capistrano/{tasks → scm/tasks}/git.rake +9 -24
- data/lib/capistrano/{tasks → scm/tasks}/hg.rake +11 -10
- data/lib/capistrano/{tasks → scm/tasks}/svn.rake +11 -10
- data/lib/capistrano/setup.rb +1 -1
- data/lib/capistrano/tasks/deploy.rake +0 -3
- data/lib/capistrano/templates/Capfile +18 -7
- data/lib/capistrano/templates/deploy.rb.erb +7 -10
- data/lib/capistrano/templates/stage.rb.erb +7 -7
- data/lib/capistrano/version.rb +1 -1
- data/lib/capistrano/version_validator.rb +2 -5
- data/spec/lib/capistrano/configuration/host_filter_spec.rb +5 -0
- data/spec/lib/capistrano/configuration/plugin_installer_spec.rb +98 -0
- data/spec/lib/capistrano/configuration/role_filter_spec.rb +17 -1
- data/spec/lib/capistrano/doctor/variables_doctor_spec.rb +0 -7
- data/spec/lib/capistrano/dsl/task_enhancements_spec.rb +0 -15
- data/spec/lib/capistrano/scm/git_spec.rb +131 -0
- data/spec/lib/capistrano/scm/hg_spec.rb +104 -0
- data/spec/lib/capistrano/scm/svn_spec.rb +116 -0
- data/spec/lib/capistrano/scm_spec.rb +1 -1
- metadata +23 -20
- data/features/remote_file_task.feature +0 -14
- data/issue_template.md +0 -21
- data/lib/capistrano/git.rb +0 -54
- data/lib/capistrano/hg.rb +0 -43
- data/lib/capistrano/svn.rb +0 -42
- data/spec/lib/capistrano/git_spec.rb +0 -109
- data/spec/lib/capistrano/hg_spec.rb +0 -90
- data/spec/lib/capistrano/svn_spec.rb +0 -105
data/lib/capistrano/setup.rb
CHANGED
@@ -26,7 +26,6 @@ namespace :deploy do
|
|
26
26
|
end
|
27
27
|
|
28
28
|
task updating: :new_release_path do
|
29
|
-
invoke "#{scm}:create_release"
|
30
29
|
invoke "deploy:set_current_revision"
|
31
30
|
invoke "deploy:symlink:shared"
|
32
31
|
end
|
@@ -53,7 +52,6 @@ namespace :deploy do
|
|
53
52
|
|
54
53
|
desc "Check required files and directories exist"
|
55
54
|
task :check do
|
56
|
-
invoke "#{scm}:check"
|
57
55
|
invoke "deploy:check:directories"
|
58
56
|
invoke "deploy:check:linked_dirs"
|
59
57
|
invoke "deploy:check:make_linked_dirs"
|
@@ -225,7 +223,6 @@ namespace :deploy do
|
|
225
223
|
|
226
224
|
desc "Place a REVISION file with the current revision SHA in the current release path"
|
227
225
|
task :set_current_revision do
|
228
|
-
invoke "#{scm}:set_current_revision"
|
229
226
|
on release_roles(:all) do
|
230
227
|
within release_path do
|
231
228
|
execute :echo, "\"#{fetch(:current_revision)}\" >> REVISION"
|
@@ -4,6 +4,17 @@ require "capistrano/setup"
|
|
4
4
|
# Include default deployment tasks
|
5
5
|
require "capistrano/deploy"
|
6
6
|
|
7
|
+
# Load the SCM plugin appropriate to your project:
|
8
|
+
#
|
9
|
+
# require "capistrano/scm/hg"
|
10
|
+
# install_plugin Capistrano::SCM::Hg
|
11
|
+
# or
|
12
|
+
# require "capistrano/scm/svn"
|
13
|
+
# install_plugin Capistrano::SCM::Svn
|
14
|
+
# or
|
15
|
+
require "capistrano/scm/git"
|
16
|
+
install_plugin Capistrano::SCM::Git
|
17
|
+
|
7
18
|
# Include tasks from other gems included in your Gemfile
|
8
19
|
#
|
9
20
|
# For documentation on these, see for example:
|
@@ -15,13 +26,13 @@ require "capistrano/deploy"
|
|
15
26
|
# https://github.com/capistrano/rails
|
16
27
|
# https://github.com/capistrano/passenger
|
17
28
|
#
|
18
|
-
# require
|
19
|
-
# require
|
20
|
-
# require
|
21
|
-
# require
|
22
|
-
# require
|
23
|
-
# require
|
24
|
-
# require
|
29
|
+
# require "capistrano/rvm"
|
30
|
+
# require "capistrano/rbenv"
|
31
|
+
# require "capistrano/chruby"
|
32
|
+
# require "capistrano/bundler"
|
33
|
+
# require "capistrano/rails/assets"
|
34
|
+
# require "capistrano/rails/migrations"
|
35
|
+
# require "capistrano/passenger"
|
25
36
|
|
26
37
|
# Load custom tasks from `lib/capistrano/tasks` if you have any defined
|
27
38
|
Dir.glob("lib/capistrano/tasks/*.rake").each { |r| import r }
|
@@ -1,33 +1,30 @@
|
|
1
1
|
# config valid only for current version of Capistrano
|
2
|
-
lock
|
2
|
+
lock "<%= Capistrano::VERSION %>"
|
3
3
|
|
4
|
-
set :application,
|
5
|
-
set :repo_url,
|
4
|
+
set :application, "my_app_name"
|
5
|
+
set :repo_url, "git@example.com:me/my_repo.git"
|
6
6
|
|
7
7
|
# Default branch is :master
|
8
8
|
# ask :branch, `git rev-parse --abbrev-ref HEAD`.chomp
|
9
9
|
|
10
10
|
# Default deploy_to directory is /var/www/my_app_name
|
11
|
-
# set :deploy_to,
|
12
|
-
|
13
|
-
# Default value for :scm is :git
|
14
|
-
# set :scm, :git
|
11
|
+
# set :deploy_to, "/var/www/my_app_name"
|
15
12
|
|
16
13
|
# Default value for :format is :airbrussh.
|
17
14
|
# set :format, :airbrussh
|
18
15
|
|
19
16
|
# You can configure the Airbrussh format using :format_options.
|
20
17
|
# These are the defaults.
|
21
|
-
# set :format_options, command_output: true, log_file:
|
18
|
+
# set :format_options, command_output: true, log_file: "log/capistrano.log", color: :auto, truncate: :auto
|
22
19
|
|
23
20
|
# Default value for :pty is false
|
24
21
|
# set :pty, true
|
25
22
|
|
26
23
|
# Default value for :linked_files is []
|
27
|
-
# append :linked_files,
|
24
|
+
# append :linked_files, "config/database.yml", "config/secrets.yml"
|
28
25
|
|
29
26
|
# Default value for linked_dirs is []
|
30
|
-
# append :linked_dirs,
|
27
|
+
# append :linked_dirs, "log", "tmp/pids", "tmp/cache", "tmp/sockets", "public/system"
|
31
28
|
|
32
29
|
# Default value for default_env is {}
|
33
30
|
# set :default_env, { path: "/opt/ruby/bin:$PATH" }
|
@@ -3,9 +3,9 @@
|
|
3
3
|
# Defines a single server with a list of roles and multiple properties.
|
4
4
|
# You can define all roles on a single server, or split them:
|
5
5
|
|
6
|
-
# server
|
7
|
-
# server
|
8
|
-
# server
|
6
|
+
# server "example.com", user: "deploy", roles: %w{app db web}, my_property: :my_value
|
7
|
+
# server "example.com", user: "deploy", roles: %w{app web}, other_property: :other_value
|
8
|
+
# server "db.example.com", user: "deploy", roles: %w{db}
|
9
9
|
|
10
10
|
|
11
11
|
|
@@ -49,13 +49,13 @@
|
|
49
49
|
#
|
50
50
|
# The server-based syntax can be used to override options:
|
51
51
|
# ------------------------------------
|
52
|
-
# server
|
53
|
-
# user:
|
52
|
+
# server "example.com",
|
53
|
+
# user: "user_name",
|
54
54
|
# roles: %w{web app},
|
55
55
|
# ssh_options: {
|
56
|
-
# user:
|
56
|
+
# user: "user_name", # overrides user setting above
|
57
57
|
# keys: %w(/home/user_name/.ssh/id_rsa),
|
58
58
|
# forward_agent: false,
|
59
59
|
# auth_methods: %w(publickey password)
|
60
|
-
# # password:
|
60
|
+
# # password: "please use keys"
|
61
61
|
# }
|
data/lib/capistrano/version.rb
CHANGED
@@ -5,11 +5,8 @@ module Capistrano
|
|
5
5
|
end
|
6
6
|
|
7
7
|
def verify
|
8
|
-
if match?
|
9
|
-
|
10
|
-
else
|
11
|
-
raise "Capfile locked at #{version}, but #{current_version} is loaded"
|
12
|
-
end
|
8
|
+
return self if match?
|
9
|
+
raise "Capfile locked at #{version}, but #{current_version} is loaded"
|
13
10
|
end
|
14
11
|
|
15
12
|
private
|
@@ -55,6 +55,11 @@ module Capistrano
|
|
55
55
|
let(:values) { 'server\d{1,3}$' }
|
56
56
|
it_behaves_like "it filters hosts correctly", %w{server1 server2 server3 server4 server5}
|
57
57
|
end
|
58
|
+
|
59
|
+
context "without number" do
|
60
|
+
let(:values) { "server" }
|
61
|
+
it_behaves_like "it filters hosts correctly", %w{}
|
62
|
+
end
|
58
63
|
end
|
59
64
|
end
|
60
65
|
end
|
@@ -0,0 +1,98 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
require "capistrano/plugin"
|
3
|
+
require "capistrano/scm/plugin"
|
4
|
+
|
5
|
+
module Capistrano
|
6
|
+
class Configuration
|
7
|
+
class ExamplePlugin < Capistrano::Plugin
|
8
|
+
def set_defaults
|
9
|
+
set_if_empty :example_variable, "foo"
|
10
|
+
end
|
11
|
+
|
12
|
+
def define_tasks
|
13
|
+
task :example
|
14
|
+
task :example_prerequisite
|
15
|
+
end
|
16
|
+
|
17
|
+
def register_hooks
|
18
|
+
before :example, :example_prerequisite
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
class ExampleSCMPlugin < Capistrano::SCM::Plugin
|
23
|
+
end
|
24
|
+
|
25
|
+
describe PluginInstaller do
|
26
|
+
include Capistrano::DSL
|
27
|
+
|
28
|
+
let(:installer) { PluginInstaller.new }
|
29
|
+
let(:options) { {} }
|
30
|
+
let(:plugin) { ExamplePlugin.new }
|
31
|
+
|
32
|
+
before do
|
33
|
+
installer.install(plugin, **options)
|
34
|
+
end
|
35
|
+
|
36
|
+
after do
|
37
|
+
Rake::Task.clear
|
38
|
+
Capistrano::Configuration.reset!
|
39
|
+
end
|
40
|
+
|
41
|
+
context "installing plugin" do
|
42
|
+
it "defines tasks" do
|
43
|
+
expect(Rake::Task[:example]).to_not be_nil
|
44
|
+
expect(Rake::Task[:example_prerequisite]).to_not be_nil
|
45
|
+
end
|
46
|
+
|
47
|
+
it "registers hooks" do
|
48
|
+
task = Rake::Task[:example]
|
49
|
+
expect(task.prerequisites).to eq([:example_prerequisite])
|
50
|
+
end
|
51
|
+
|
52
|
+
it "sets defaults when load:defaults is invoked" do
|
53
|
+
expect(fetch(:example_variable)).to be_nil
|
54
|
+
invoke "load:defaults"
|
55
|
+
expect(fetch(:example_variable)).to eq("foo")
|
56
|
+
end
|
57
|
+
|
58
|
+
it "doesn't say an SCM is installed" do
|
59
|
+
expect(installer.scm_installed?).to be_falsey
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
context "installing plugin class" do
|
64
|
+
let(:plugin) { ExamplePlugin }
|
65
|
+
|
66
|
+
it "defines tasks" do
|
67
|
+
expect(Rake::Task[:example]).to_not be_nil
|
68
|
+
expect(Rake::Task[:example_prerequisite]).to_not be_nil
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
context "installing plugin without hooks" do
|
73
|
+
let(:options) { { load_hooks: false } }
|
74
|
+
|
75
|
+
it "doesn't register hooks" do
|
76
|
+
task = Rake::Task[:example]
|
77
|
+
expect(task.prerequisites).to be_empty
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
81
|
+
context "installing plugin and loading immediately" do
|
82
|
+
let(:options) { { load_immediately: true } }
|
83
|
+
|
84
|
+
it "sets defaults immediately" do
|
85
|
+
expect(fetch(:example_variable)).to eq("foo")
|
86
|
+
end
|
87
|
+
end
|
88
|
+
|
89
|
+
context "installing an SCM plugin" do
|
90
|
+
let(:plugin) { ExampleSCMPlugin }
|
91
|
+
|
92
|
+
it "says an SCM is installed" do
|
93
|
+
expect(installer.scm_installed?).to be_truthy
|
94
|
+
end
|
95
|
+
end
|
96
|
+
end
|
97
|
+
end
|
98
|
+
end
|
@@ -11,7 +11,8 @@ module Capistrano
|
|
11
11
|
Server.new("server2").add_role(:web),
|
12
12
|
Server.new("server3").add_role(:redis),
|
13
13
|
Server.new("server4").add_role(:db),
|
14
|
-
Server.new("server5").add_role(:stageweb)
|
14
|
+
Server.new("server5").add_role(:stageweb),
|
15
|
+
Server.new("server6").add_role(:"db.new")
|
15
16
|
]
|
16
17
|
end
|
17
18
|
|
@@ -58,6 +59,21 @@ module Capistrano
|
|
58
59
|
let(:values) { "db,/red/" }
|
59
60
|
it_behaves_like "it filters roles correctly", 3, %w{server1 server3 server4}
|
60
61
|
end
|
62
|
+
|
63
|
+
context "with a dot wildcard" do
|
64
|
+
let(:values) { "db.*" }
|
65
|
+
it_behaves_like "it filters roles correctly", 0, %w{}
|
66
|
+
end
|
67
|
+
|
68
|
+
context "with a dot" do
|
69
|
+
let(:values) { "db.new" }
|
70
|
+
it_behaves_like "it filters roles correctly", 1, %w{server6}
|
71
|
+
end
|
72
|
+
|
73
|
+
context "with a dot wildcard regex" do
|
74
|
+
let(:values) { "/db.*/" }
|
75
|
+
it_behaves_like "it filters roles correctly", 3, %w{server1 server4 server6}
|
76
|
+
end
|
61
77
|
end
|
62
78
|
end
|
63
79
|
end
|
@@ -15,7 +15,6 @@ module Capistrano
|
|
15
15
|
env.variables.untrusted! do
|
16
16
|
set :application, "my_app"
|
17
17
|
set :repo_url, ".git"
|
18
|
-
set :git_strategy, "Capistrano::Git::DefaultStrategy"
|
19
18
|
set :copy_strategy, :scp
|
20
19
|
set :custom_setting, "hello"
|
21
20
|
set "string_setting", "hello"
|
@@ -57,12 +56,6 @@ module Capistrano
|
|
57
56
|
.to_stdout
|
58
57
|
end
|
59
58
|
|
60
|
-
it "does not print warning for the whitelisted git_strategy variable" do
|
61
|
-
expect { doc.call }.not_to \
|
62
|
-
output(/:git_strategy is not a recognized Capistrano setting/)\
|
63
|
-
.to_stdout
|
64
|
-
end
|
65
|
-
|
66
59
|
describe "Rake" do
|
67
60
|
before do
|
68
61
|
load File.expand_path("../../../../../lib/capistrano/doctor.rb",
|
@@ -104,20 +104,5 @@ module Capistrano
|
|
104
104
|
expect { Rake::Task["task"].invoke order }.to raise_error(ArgumentError, 'Task "non_existent_task" not found')
|
105
105
|
end
|
106
106
|
end
|
107
|
-
|
108
|
-
describe "remote_file" do
|
109
|
-
subject(:remote_file) { task_enhancements.remote_file("source" => "destination") }
|
110
|
-
|
111
|
-
it { expect(remote_file.name).to eq("source") }
|
112
|
-
it { is_expected.to be_a(Capistrano::UploadTask) }
|
113
|
-
|
114
|
-
describe "namespaced" do
|
115
|
-
let(:app) { Rake.application }
|
116
|
-
around { |ex| app.in_namespace("namespace", &ex) }
|
117
|
-
|
118
|
-
it { expect(remote_file.name).to eq("source") }
|
119
|
-
it { is_expected.to be_a(Capistrano::UploadTask) }
|
120
|
-
end
|
121
|
-
end
|
122
107
|
end
|
123
108
|
end
|
@@ -0,0 +1,131 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
|
3
|
+
require "capistrano/scm/git"
|
4
|
+
|
5
|
+
module Capistrano
|
6
|
+
describe SCM::Git do
|
7
|
+
subject { Capistrano::SCM::Git.new }
|
8
|
+
|
9
|
+
# This allows us to easily use `set`, `fetch`, etc. in the examples.
|
10
|
+
let(:env) { Capistrano::Configuration.env }
|
11
|
+
|
12
|
+
# Stub the SSHKit backend so we can set up expectations without the plugin
|
13
|
+
# actually executing any commands.
|
14
|
+
let(:backend) { stub }
|
15
|
+
before { SSHKit::Backend.stubs(:current).returns(backend) }
|
16
|
+
|
17
|
+
# Mimic the deploy flow tasks so that the plugin can register its hooks.
|
18
|
+
before do
|
19
|
+
Rake::Task.define_task("deploy:new_release_path")
|
20
|
+
Rake::Task.define_task("deploy:check")
|
21
|
+
Rake::Task.define_task("deploy:set_current_revision")
|
22
|
+
end
|
23
|
+
|
24
|
+
# Clean up any tasks or variables that the plugin defined.
|
25
|
+
after do
|
26
|
+
Rake::Task.clear
|
27
|
+
Capistrano::Configuration.reset!
|
28
|
+
end
|
29
|
+
|
30
|
+
describe "#git" do
|
31
|
+
it "should call execute git in the context, with arguments" do
|
32
|
+
backend.expects(:execute).with(:git, :init)
|
33
|
+
subject.git(:init)
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
describe "#repo_mirror_exists?" do
|
38
|
+
it "should call test for repo HEAD" do
|
39
|
+
env.set(:repo_path, "/path/to/repo")
|
40
|
+
backend.expects(:test).with " [ -f /path/to/repo/HEAD ] "
|
41
|
+
|
42
|
+
subject.repo_mirror_exists?
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
describe "#check_repo_is_reachable" do
|
47
|
+
it "should test the repo url" do
|
48
|
+
env.set(:repo_url, "url")
|
49
|
+
backend.expects(:execute).with(:git, :'ls-remote --heads', "url").returns(true)
|
50
|
+
|
51
|
+
subject.check_repo_is_reachable
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
describe "#clone_repo" do
|
56
|
+
it "should run git clone" do
|
57
|
+
env.set(:repo_url, "url")
|
58
|
+
env.set(:repo_path, "path")
|
59
|
+
backend.expects(:execute).with(:git, :clone, "--mirror", "url", "path")
|
60
|
+
|
61
|
+
subject.clone_repo
|
62
|
+
end
|
63
|
+
|
64
|
+
it "should run git clone in shallow mode" do
|
65
|
+
env.set(:git_shallow_clone, "1")
|
66
|
+
env.set(:repo_url, "url")
|
67
|
+
env.set(:repo_path, "path")
|
68
|
+
|
69
|
+
backend.expects(:execute).with(:git, :clone, "--mirror", "--depth", "1", "--no-single-branch", "url", "path")
|
70
|
+
|
71
|
+
subject.clone_repo
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
describe "#update_mirror" do
|
76
|
+
it "should run git update" do
|
77
|
+
backend.expects(:execute).with(:git, :remote, :update, "--prune")
|
78
|
+
|
79
|
+
subject.update_mirror
|
80
|
+
end
|
81
|
+
|
82
|
+
it "should run git update in shallow mode" do
|
83
|
+
env.set(:git_shallow_clone, "1")
|
84
|
+
env.set(:branch, "branch")
|
85
|
+
backend.expects(:execute).with(:git, :fetch, "--depth", "1", "origin", "branch")
|
86
|
+
|
87
|
+
subject.update_mirror
|
88
|
+
end
|
89
|
+
end
|
90
|
+
|
91
|
+
describe "#archive_to_release_path" do
|
92
|
+
it "should run git archive without a subtree" do
|
93
|
+
env.set(:branch, "branch")
|
94
|
+
env.set(:release_path, "path")
|
95
|
+
|
96
|
+
backend.expects(:execute).with(:git, :archive, "branch", "| /usr/bin/env tar -x -f - -C", "path")
|
97
|
+
|
98
|
+
subject.archive_to_release_path
|
99
|
+
end
|
100
|
+
|
101
|
+
it "should run git archive with a subtree" do
|
102
|
+
env.set(:repo_tree, "tree")
|
103
|
+
env.set(:branch, "branch")
|
104
|
+
env.set(:release_path, "path")
|
105
|
+
|
106
|
+
backend.expects(:execute).with(:git, :archive, "branch", "tree", "| /usr/bin/env tar -x --strip-components 1 -f - -C", "path")
|
107
|
+
|
108
|
+
subject.archive_to_release_path
|
109
|
+
end
|
110
|
+
|
111
|
+
it "should run tar with an overridden name" do
|
112
|
+
env.set(:branch, "branch")
|
113
|
+
env.set(:release_path, "path")
|
114
|
+
SSHKit.config.command_map.expects(:[]).with(:tar).returns("/usr/bin/env gtar")
|
115
|
+
|
116
|
+
backend.expects(:execute).with(:git, :archive, "branch", "| /usr/bin/env gtar -x -f - -C", "path")
|
117
|
+
|
118
|
+
subject.archive_to_release_path
|
119
|
+
end
|
120
|
+
end
|
121
|
+
|
122
|
+
describe "#fetch_revision" do
|
123
|
+
it "should capture git rev-list" do
|
124
|
+
env.set(:branch, "branch")
|
125
|
+
backend.expects(:capture).with(:git, "rev-list --max-count=1 branch").returns("81cec13b777ff46348693d327fc8e7832f79bf43")
|
126
|
+
revision = subject.fetch_revision
|
127
|
+
expect(revision).to eq("81cec13b777ff46348693d327fc8e7832f79bf43")
|
128
|
+
end
|
129
|
+
end
|
130
|
+
end
|
131
|
+
end
|