simple_deploy 0.7.2 → 0.7.3
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/.gitignore +3 -0
- data/CHANGELOG.md +6 -0
- data/lib/simple_deploy/aws/cloud_formation/error.rb +32 -0
- data/lib/simple_deploy/aws/cloud_formation.rb +76 -0
- data/lib/simple_deploy/aws/instance_reader.rb +59 -0
- data/lib/simple_deploy/aws/simpledb.rb +52 -0
- data/lib/simple_deploy/aws.rb +4 -0
- data/lib/simple_deploy/cli/attributes.rb +7 -18
- data/lib/simple_deploy/cli/clone.rb +9 -19
- data/lib/simple_deploy/cli/create.rb +5 -14
- data/lib/simple_deploy/cli/deploy.rb +8 -11
- data/lib/simple_deploy/cli/destroy.rb +4 -10
- data/lib/simple_deploy/cli/environments.rb +1 -1
- data/lib/simple_deploy/cli/events.rb +5 -11
- data/lib/simple_deploy/cli/execute.rb +6 -9
- data/lib/simple_deploy/cli/instances.rb +4 -9
- data/lib/simple_deploy/cli/list.rb +5 -10
- data/lib/simple_deploy/cli/outputs.rb +5 -11
- data/lib/simple_deploy/cli/parameters.rb +5 -11
- data/lib/simple_deploy/cli/protect.rb +5 -10
- data/lib/simple_deploy/cli/resources.rb +5 -11
- data/lib/simple_deploy/cli/shared.rb +6 -6
- data/lib/simple_deploy/cli/status.rb +5 -11
- data/lib/simple_deploy/cli/template.rb +8 -13
- data/lib/simple_deploy/cli/update.rb +6 -10
- data/lib/simple_deploy/configuration.rb +102 -0
- data/lib/simple_deploy/entry.rb +71 -0
- data/lib/simple_deploy/entry_lister.rb +30 -0
- data/lib/simple_deploy/exceptions.rb +8 -0
- data/lib/simple_deploy/misc/attribute_merger.rb +2 -5
- data/lib/simple_deploy/notifier/campfire.rb +15 -12
- data/lib/simple_deploy/notifier.rb +6 -11
- data/lib/simple_deploy/stack/deployment/status.rb +5 -3
- data/lib/simple_deploy/stack/deployment.rb +8 -10
- data/lib/simple_deploy/stack/execute.rb +2 -3
- data/lib/simple_deploy/stack/output_mapper.rb +1 -4
- data/lib/simple_deploy/stack/ssh.rb +4 -4
- data/lib/simple_deploy/stack/{stack_attribute_formater.rb → stack_attribute_formatter.rb} +4 -6
- data/lib/simple_deploy/stack/stack_creator.rb +46 -0
- data/lib/simple_deploy/stack/stack_destroyer.rb +19 -0
- data/lib/simple_deploy/stack/stack_formatter.rb +25 -0
- data/lib/simple_deploy/stack/stack_lister.rb +18 -0
- data/lib/simple_deploy/stack/stack_reader.rb +56 -0
- data/lib/simple_deploy/stack/stack_updater.rb +67 -0
- data/lib/simple_deploy/stack/status.rb +53 -0
- data/lib/simple_deploy/stack.rb +89 -37
- data/lib/simple_deploy/version.rb +1 -1
- data/lib/simple_deploy.rb +31 -1
- data/simple_deploy.gemspec +6 -3
- data/spec/aws/cloud_formation/error_spec.rb +50 -0
- data/spec/aws/cloud_formation_spec.rb +207 -0
- data/spec/aws/instance_reader_spec.rb +96 -0
- data/spec/aws/simpledb_spec.rb +89 -0
- data/spec/cli/attributes_spec.rb +5 -15
- data/spec/cli/clone_spec.rb +14 -27
- data/spec/cli/create_spec.rb +11 -18
- data/spec/cli/deploy_spec.rb +24 -63
- data/spec/cli/destroy_spec.rb +7 -25
- data/spec/cli/outputs_spec.rb +12 -17
- data/spec/cli/protect_spec.rb +68 -106
- data/spec/cli/shared_spec.rb +12 -15
- data/spec/cli/update_spec.rb +9 -27
- data/spec/config_spec.rb +47 -14
- data/spec/contexts/config_contexts.rb +28 -0
- data/spec/contexts/logger_contexts.rb +9 -0
- data/spec/contexts/stack_contexts.rb +40 -0
- data/spec/entry_lister_spec.rb +31 -0
- data/spec/entry_spec.rb +86 -0
- data/spec/misc/attribute_merger_spec.rb +3 -8
- data/spec/notifier/campfire_spec.rb +21 -61
- data/spec/notifier_spec.rb +18 -40
- data/spec/spec_helper.rb +10 -0
- data/spec/stack/deployment/status_spec.rb +13 -13
- data/spec/stack/deployment_spec.rb +26 -21
- data/spec/stack/execute_spec.rb +7 -3
- data/spec/stack/output_mapper_spec.rb +3 -15
- data/spec/stack/ssh_spec.rb +14 -13
- data/spec/stack/{stack_attribute_formater_spec.rb → stack_attribute_formatter_spec.rb} +19 -16
- data/spec/stack/stack_creator_spec.rb +46 -0
- data/spec/stack/stack_destroyer_spec.rb +18 -0
- data/spec/stack/stack_formatter_spec.rb +37 -0
- data/spec/stack/stack_lister_spec.rb +17 -0
- data/spec/stack/stack_reader_spec.rb +81 -0
- data/spec/stack/stack_updater_spec.rb +79 -0
- data/spec/stack/status_spec.rb +106 -0
- data/spec/stack_spec.rb +160 -133
- metadata +112 -19
- data/.rvmrc +0 -1
- data/lib/simple_deploy/config.rb +0 -87
@@ -26,22 +26,16 @@ EOS
|
|
26
26
|
valid_options? :provided => @opts,
|
27
27
|
:required => [:environment, :name]
|
28
28
|
|
29
|
-
|
29
|
+
SimpleDeploy.create_config @opts[:environment]
|
30
|
+
SimpleDeploy.logger @opts[:log_level]
|
31
|
+
stack = Stack.new :name => @opts[:name],
|
32
|
+
:environment => @opts[:environment]
|
30
33
|
|
31
|
-
|
32
|
-
:name => @opts[:name],
|
33
|
-
:config => config,
|
34
|
-
:logger => logger
|
35
|
-
|
36
|
-
rescue_stackster_exceptions_and_exit do
|
34
|
+
rescue_exceptions_and_exit do
|
37
35
|
jj stack.events @opts[:count]
|
38
36
|
end
|
39
37
|
end
|
40
38
|
|
41
|
-
def logger
|
42
|
-
@logger ||= SimpleDeployLogger.new :log_level => @opts[:log_level]
|
43
|
-
end
|
44
|
-
|
45
39
|
def command_summary
|
46
40
|
"Show events for a stack"
|
47
41
|
end
|
@@ -39,14 +39,15 @@ EOS
|
|
39
39
|
valid_options? :provided => @opts,
|
40
40
|
:required => [:environment, :name]
|
41
41
|
|
42
|
+
SimpleDeploy.create_config @opts[:environment]
|
43
|
+
logger = SimpleDeploy.logger @opts[:log_level]
|
44
|
+
|
42
45
|
@opts[:name].each do |name|
|
43
46
|
notifier = Notifier.new :stack_name => name,
|
44
|
-
:environment => @opts[:environment]
|
45
|
-
:logger => logger
|
47
|
+
:environment => @opts[:environment]
|
46
48
|
|
47
|
-
stack = Stack.new :
|
48
|
-
:
|
49
|
-
:logger => logger,
|
49
|
+
stack = Stack.new :name => name,
|
50
|
+
:environment => @opts[:environment],
|
50
51
|
:internal => @opts[:internal]
|
51
52
|
|
52
53
|
begin
|
@@ -61,10 +62,6 @@ EOS
|
|
61
62
|
end
|
62
63
|
end
|
63
64
|
|
64
|
-
def logger
|
65
|
-
@logger ||= SimpleDeployLogger.new :log_level => @opts[:log_level]
|
66
|
-
end
|
67
|
-
|
68
65
|
def command_summary
|
69
66
|
'Execute command on given stack(s)'
|
70
67
|
end
|
@@ -25,12 +25,11 @@ EOS
|
|
25
25
|
valid_options? :provided => @opts,
|
26
26
|
:required => [:environment, :name]
|
27
27
|
|
28
|
-
|
28
|
+
SimpleDeploy.create_config @opts[:environment]
|
29
|
+
logger = SimpleDeploy.logger @opts[:log_level]
|
29
30
|
|
30
|
-
stack = Stack.new :
|
31
|
-
:
|
32
|
-
:config => config,
|
33
|
-
:logger => logger,
|
31
|
+
stack = Stack.new :name => @opts[:name],
|
32
|
+
:environment => @opts[:environment],
|
34
33
|
:internal => @opts[:internal]
|
35
34
|
|
36
35
|
exit 1 unless stack.exists?
|
@@ -44,10 +43,6 @@ EOS
|
|
44
43
|
end
|
45
44
|
end
|
46
45
|
|
47
|
-
def logger
|
48
|
-
@logger ||= SimpleDeployLogger.new :log_level => @opts[:log_level]
|
49
|
-
end
|
50
|
-
|
51
46
|
def command_summary
|
52
47
|
'List instances for stack'
|
53
48
|
end
|
@@ -1,5 +1,7 @@
|
|
1
1
|
require 'trollop'
|
2
2
|
|
3
|
+
require 'simple_deploy/stack/stack_lister'
|
4
|
+
|
3
5
|
module SimpleDeploy
|
4
6
|
module CLI
|
5
7
|
|
@@ -25,20 +27,13 @@ EOS
|
|
25
27
|
valid_options? :provided => @opts,
|
26
28
|
:required => [:environment]
|
27
29
|
|
28
|
-
|
29
|
-
|
30
|
+
SimpleDeploy.create_config @opts[:environment]
|
31
|
+
SimpleDeploy.logger @opts[:log_level]
|
30
32
|
|
31
|
-
|
32
|
-
:name => @opts[:name],
|
33
|
-
:config => config,
|
34
|
-
:logger => logger
|
33
|
+
stacks = SimpleDeploy::StackLister.new.all.sort
|
35
34
|
puts stacks
|
36
35
|
end
|
37
36
|
|
38
|
-
def logger
|
39
|
-
@logger ||= SimpleDeployLogger.new :log_level => @opts[:log_level]
|
40
|
-
end
|
41
|
-
|
42
37
|
def command_summary
|
43
38
|
'List stacks in an environment'
|
44
39
|
end
|
@@ -28,14 +28,12 @@ EOS
|
|
28
28
|
valid_options? :provided => @opts,
|
29
29
|
:required => [:environment, :name]
|
30
30
|
|
31
|
-
|
31
|
+
SimpleDeploy.create_config @opts[:environment]
|
32
|
+
logger = SimpleDeploy.logger @opts[:log_level]
|
33
|
+
stack = Stack.new :name => @opts[:name],
|
34
|
+
:environment => @opts[:environment]
|
32
35
|
|
33
|
-
|
34
|
-
:name => @opts[:name],
|
35
|
-
:config => config,
|
36
|
-
:logger => logger
|
37
|
-
|
38
|
-
rescue_stackster_exceptions_and_exit do
|
36
|
+
rescue_exceptions_and_exit do
|
39
37
|
@outputs = stack.outputs
|
40
38
|
|
41
39
|
logger.info "No outputs." unless @outputs.any?
|
@@ -63,10 +61,6 @@ EOS
|
|
63
61
|
end
|
64
62
|
end
|
65
63
|
|
66
|
-
def logger
|
67
|
-
@logger ||= SimpleDeployLogger.new :log_level => @opts[:log_level]
|
68
|
-
end
|
69
|
-
|
70
64
|
end
|
71
65
|
end
|
72
66
|
end
|
@@ -26,22 +26,16 @@ EOS
|
|
26
26
|
valid_options? :provided => @opts,
|
27
27
|
:required => [:environment, :name]
|
28
28
|
|
29
|
-
|
29
|
+
SimpleDeploy.create_config @opts[:environment]
|
30
|
+
SimpleDeploy.logger @opts[:log_level]
|
31
|
+
stack = Stack.new :name => @opts[:name],
|
32
|
+
:environment => @opts[:environment]
|
30
33
|
|
31
|
-
|
32
|
-
:name => @opts[:name],
|
33
|
-
:config => config,
|
34
|
-
:logger => logger
|
35
|
-
|
36
|
-
rescue_stackster_exceptions_and_exit do
|
34
|
+
rescue_exceptions_and_exit do
|
37
35
|
puts stack.parameters.sort
|
38
36
|
end
|
39
37
|
end
|
40
38
|
|
41
|
-
def logger
|
42
|
-
@logger ||= SimpleDeployLogger.new :log_level => @opts[:log_level]
|
43
|
-
end
|
44
|
-
|
45
39
|
def command_summary
|
46
40
|
'Show parameters of a stack'
|
47
41
|
end
|
@@ -29,23 +29,18 @@ EOS
|
|
29
29
|
valid_options? :provided => @opts,
|
30
30
|
:required => [:environment, :name]
|
31
31
|
|
32
|
-
|
32
|
+
SimpleDeploy.create_config @opts[:environment]
|
33
|
+
SimpleDeploy.logger @opts[:log_level]
|
33
34
|
|
34
35
|
@opts[:name].each do |name|
|
35
|
-
stack = Stack.new :
|
36
|
-
:
|
37
|
-
|
38
|
-
:logger => logger
|
39
|
-
rescue_stackster_exceptions_and_exit do
|
36
|
+
stack = Stack.new :name => name,
|
37
|
+
:environment => @opts[:environment]
|
38
|
+
rescue_exceptions_and_exit do
|
40
39
|
stack.update :attributes => [{ 'protection' => @opts[:protection] }]
|
41
40
|
end
|
42
41
|
end
|
43
42
|
end
|
44
43
|
|
45
|
-
def logger
|
46
|
-
@logger ||= SimpleDeployLogger.new :log_level => @opts[:log_level]
|
47
|
-
end
|
48
|
-
|
49
44
|
def command_summary
|
50
45
|
'Protect/Unprotect one or more stacks'
|
51
46
|
end
|
@@ -27,22 +27,16 @@ EOS
|
|
27
27
|
valid_options? :provided => @opts,
|
28
28
|
:required => [:environment, :name]
|
29
29
|
|
30
|
-
|
30
|
+
SimpleDeploy.create_config @opts[:environment]
|
31
|
+
SimpleDeploy.logger @opts[:log_level]
|
32
|
+
stack = Stack.new :name => @opts[:name],
|
33
|
+
:environment => @opts[:environment]
|
31
34
|
|
32
|
-
|
33
|
-
:name => @opts[:name],
|
34
|
-
:config => config,
|
35
|
-
:logger => logger
|
36
|
-
|
37
|
-
rescue_stackster_exceptions_and_exit do
|
35
|
+
rescue_exceptions_and_exit do
|
38
36
|
jj stack.resources
|
39
37
|
end
|
40
38
|
end
|
41
39
|
|
42
|
-
def logger
|
43
|
-
@logger ||= SimpleDeployLogger.new :log_level => @opts[:log_level]
|
44
|
-
end
|
45
|
-
|
46
40
|
def command_summary
|
47
41
|
'Show resources of a stack'
|
48
42
|
end
|
@@ -10,7 +10,7 @@ module SimpleDeploy
|
|
10
10
|
attributes.each do |attribs|
|
11
11
|
key = attribs.split('=').first.gsub(/\s+/, "")
|
12
12
|
value = attribs.gsub(/^.+?=/, '')
|
13
|
-
logger.info "Read #{key}=#{value}"
|
13
|
+
SimpleDeploy.logger.info "Read #{key}=#{value}"
|
14
14
|
attrs << { key => value }
|
15
15
|
end
|
16
16
|
attrs
|
@@ -22,14 +22,14 @@ module SimpleDeploy
|
|
22
22
|
|
23
23
|
required.each do |opt|
|
24
24
|
unless provided[opt]
|
25
|
-
logger.error "Option '#{opt} (-#{opt[0]})' required but not specified."
|
25
|
+
SimpleDeploy.logger.error "Option '#{opt} (-#{opt[0]})' required but not specified."
|
26
26
|
exit 1
|
27
27
|
end
|
28
28
|
end
|
29
29
|
|
30
30
|
if required.include? :environment
|
31
|
-
unless
|
32
|
-
logger.error "Environment '#{provided[:environment]}' does not exist."
|
31
|
+
unless SimpleDeploy.environments.keys.include? provided[:environment]
|
32
|
+
SimpleDeploy.logger.error "Environment '#{provided[:environment]}' does not exist."
|
33
33
|
exit 1
|
34
34
|
end
|
35
35
|
end
|
@@ -39,9 +39,9 @@ module SimpleDeploy
|
|
39
39
|
self.class.name.split('::').last.downcase
|
40
40
|
end
|
41
41
|
|
42
|
-
def
|
42
|
+
def rescue_exceptions_and_exit
|
43
43
|
yield
|
44
|
-
rescue
|
44
|
+
rescue SimpleDeploy::Exceptions::Base
|
45
45
|
exit 1
|
46
46
|
end
|
47
47
|
|
@@ -24,22 +24,16 @@ EOS
|
|
24
24
|
valid_options? :provided => @opts,
|
25
25
|
:required => [:environment, :name]
|
26
26
|
|
27
|
-
|
27
|
+
SimpleDeploy.create_config @opts[:environment]
|
28
|
+
SimpleDeploy.logger @opts[:log_level]
|
29
|
+
stack = Stack.new :name => @opts[:name],
|
30
|
+
:environment => @opts[:environment]
|
28
31
|
|
29
|
-
|
30
|
-
:name => @opts[:name],
|
31
|
-
:config => config,
|
32
|
-
:logger => logger
|
33
|
-
|
34
|
-
rescue_stackster_exceptions_and_exit do
|
32
|
+
rescue_exceptions_and_exit do
|
35
33
|
puts stack.status
|
36
34
|
end
|
37
35
|
end
|
38
36
|
|
39
|
-
def logger
|
40
|
-
@logger ||= SimpleDeployLogger.new :log_level => @opts[:log_level]
|
41
|
-
end
|
42
|
-
|
43
37
|
def command_summary
|
44
38
|
'Show status of a stack'
|
45
39
|
end
|
@@ -24,22 +24,17 @@ EOS
|
|
24
24
|
valid_options? :provided => @opts,
|
25
25
|
:required => [:environment, :name]
|
26
26
|
|
27
|
-
|
28
|
-
|
29
|
-
stack = Stack.new :
|
30
|
-
:
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
jj stack.template
|
27
|
+
SimpleDeploy.create_config @opts[:environment]
|
28
|
+
SimpleDeploy.logger @opts[:log_level]
|
29
|
+
stack = Stack.new :name => @opts[:name],
|
30
|
+
:environment => @opts[:environment]
|
31
|
+
|
32
|
+
rescue_exceptions_and_exit do
|
33
|
+
raw_json = JSON.parse stack.template
|
34
|
+
puts JSON.pretty_generate raw_json
|
36
35
|
end
|
37
36
|
end
|
38
37
|
|
39
|
-
def logger
|
40
|
-
@logger ||= SimpleDeployLogger.new :log_level => @opts[:log_level]
|
41
|
-
end
|
42
|
-
|
43
38
|
def command_summary
|
44
39
|
'Show current template for stack'
|
45
40
|
end
|
@@ -30,25 +30,21 @@ EOS
|
|
30
30
|
valid_options? :provided => @opts,
|
31
31
|
:required => [:environment, :name]
|
32
32
|
|
33
|
-
|
33
|
+
SimpleDeploy.create_config @opts[:environment]
|
34
|
+
SimpleDeploy.logger @opts[:log_level]
|
34
35
|
|
35
36
|
attributes = parse_attributes :attributes => @opts[:attributes]
|
36
37
|
|
37
38
|
@opts[:name].each do |name|
|
38
|
-
stack = Stack.new :
|
39
|
-
:
|
40
|
-
|
41
|
-
|
42
|
-
rescue_stackster_exceptions_and_exit do
|
39
|
+
stack = Stack.new :name => name,
|
40
|
+
:environment => @opts[:environment]
|
41
|
+
|
42
|
+
rescue_exceptions_and_exit do
|
43
43
|
stack.update :force => @opts[:force], :attributes => attributes
|
44
44
|
end
|
45
45
|
end
|
46
46
|
end
|
47
47
|
|
48
|
-
def logger
|
49
|
-
@logger ||= SimpleDeployLogger.new :log_level => @opts[:log_level]
|
50
|
-
end
|
51
|
-
|
52
48
|
def command_summary
|
53
49
|
'Update the attributes for one more stacks'
|
54
50
|
end
|
@@ -0,0 +1,102 @@
|
|
1
|
+
|
2
|
+
module SimpleDeploy
|
3
|
+
module Configuration
|
4
|
+
extend self
|
5
|
+
|
6
|
+
def configure(environment, custom_config = {})
|
7
|
+
raw_config = custom_config.fetch(:config) { load_config_file }
|
8
|
+
Config.new raw_config['environments'][environment],
|
9
|
+
raw_config['notifications']
|
10
|
+
end
|
11
|
+
|
12
|
+
def environments(custom_config = {})
|
13
|
+
raw_config = custom_config.fetch(:config) { load_config_file }
|
14
|
+
raw_config['environments']
|
15
|
+
end
|
16
|
+
|
17
|
+
private
|
18
|
+
|
19
|
+
def load_config_file
|
20
|
+
begin
|
21
|
+
YAML::load File.open(config_file)
|
22
|
+
rescue Errno::ENOENT
|
23
|
+
raise "#{config_file} not found"
|
24
|
+
rescue ArgumentError, Psych::SyntaxError => e
|
25
|
+
raise "#{config_file} is corrupt"
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
def config_file
|
30
|
+
env_config_file || default_config_file
|
31
|
+
end
|
32
|
+
|
33
|
+
def env_config_file
|
34
|
+
env.load 'SIMPLE_DEPLOY_CONFIG_FILE'
|
35
|
+
end
|
36
|
+
|
37
|
+
def default_config_file
|
38
|
+
"#{env.load 'HOME'}/.simple_deploy.yml"
|
39
|
+
end
|
40
|
+
|
41
|
+
def env
|
42
|
+
@env ||= SimpleDeploy::Env.new
|
43
|
+
end
|
44
|
+
|
45
|
+
class Config
|
46
|
+
attr_reader :environment, :notifications
|
47
|
+
|
48
|
+
def initialize(environment, notifications)
|
49
|
+
raise ArgumentError.new("environment must be defined") unless environment
|
50
|
+
|
51
|
+
@environment = environment
|
52
|
+
@notifications = notifications
|
53
|
+
end
|
54
|
+
|
55
|
+
def artifacts
|
56
|
+
['chef_repo', 'cookbooks', 'app']
|
57
|
+
end
|
58
|
+
|
59
|
+
def artifact_deploy_variable(artifact)
|
60
|
+
name_to_variable_map = { 'chef_repo' => 'CHEF_REPO_URL',
|
61
|
+
'app' => 'APP_URL',
|
62
|
+
'cookbooks' => 'COOKBOOKS_URL' }
|
63
|
+
name_to_variable_map[artifact]
|
64
|
+
end
|
65
|
+
|
66
|
+
def artifact_cloud_formation_url(artifact)
|
67
|
+
name_to_url_map = { 'chef_repo' => 'ChefRepoURL',
|
68
|
+
'app' => 'AppArtifactURL',
|
69
|
+
'cookbooks' => 'CookbooksURL' }
|
70
|
+
name_to_url_map[artifact]
|
71
|
+
end
|
72
|
+
|
73
|
+
def deploy_script
|
74
|
+
'/opt/intu/admin/bin/configure.sh'
|
75
|
+
end
|
76
|
+
|
77
|
+
def access_key
|
78
|
+
@environment['access_key']
|
79
|
+
end
|
80
|
+
|
81
|
+
def secret_key
|
82
|
+
@environment['secret_key']
|
83
|
+
end
|
84
|
+
|
85
|
+
def region
|
86
|
+
@environment['region']
|
87
|
+
end
|
88
|
+
|
89
|
+
private
|
90
|
+
|
91
|
+
def env_home
|
92
|
+
env.load 'HOME'
|
93
|
+
end
|
94
|
+
|
95
|
+
def env_user
|
96
|
+
env.load 'USER'
|
97
|
+
end
|
98
|
+
|
99
|
+
|
100
|
+
end
|
101
|
+
end
|
102
|
+
end
|