fog-aws 0.11.0 → 0.12.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (49) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +22 -1
  3. data/lib/fog/aws.rb +2 -0
  4. data/lib/fog/aws/cloud_formation.rb +14 -0
  5. data/lib/fog/aws/compute.rb +2 -0
  6. data/lib/fog/aws/models/compute/security_group.rb +49 -26
  7. data/lib/fog/aws/models/compute/vpc.rb +6 -0
  8. data/lib/fog/aws/models/support/flagged_resource.rb +14 -0
  9. data/lib/fog/aws/models/support/flagged_resources.rb +11 -0
  10. data/lib/fog/aws/models/support/trusted_advisor_check.rb +65 -0
  11. data/lib/fog/aws/models/support/trusted_advisor_checks.rb +21 -0
  12. data/lib/fog/aws/parsers/cloud_formation/basic.rb +8 -0
  13. data/lib/fog/aws/parsers/cloud_formation/create_change_set.rb +16 -0
  14. data/lib/fog/aws/parsers/cloud_formation/describe_account_limits.rb +26 -0
  15. data/lib/fog/aws/parsers/cloud_formation/describe_change_set.rb +135 -0
  16. data/lib/fog/aws/parsers/cloud_formation/describe_stack_resource.rb +28 -0
  17. data/lib/fog/aws/parsers/cloud_formation/estimate_template_cost.rb +16 -0
  18. data/lib/fog/aws/parsers/cloud_formation/get_stack_policy.rb +16 -0
  19. data/lib/fog/aws/parsers/cloud_formation/get_template_summary.rb +62 -0
  20. data/lib/fog/aws/parsers/cloud_formation/list_change_sets.rb +30 -0
  21. data/lib/fog/aws/parsers/compute/describe_vpcs.rb +3 -1
  22. data/lib/fog/aws/requests/cloud_formation/cancel_update_stack.rb +25 -0
  23. data/lib/fog/aws/requests/cloud_formation/continue_update_rollback.rb +26 -0
  24. data/lib/fog/aws/requests/cloud_formation/create_change_set.rb +70 -0
  25. data/lib/fog/aws/requests/cloud_formation/create_stack.rb +14 -0
  26. data/lib/fog/aws/requests/cloud_formation/delete_change_set.rb +26 -0
  27. data/lib/fog/aws/requests/cloud_formation/delete_stack.rb +1 -1
  28. data/lib/fog/aws/requests/cloud_formation/describe_account_limits.rb +27 -0
  29. data/lib/fog/aws/requests/cloud_formation/describe_change_set.rb +43 -0
  30. data/lib/fog/aws/requests/cloud_formation/describe_stack_resource.rb +40 -0
  31. data/lib/fog/aws/requests/cloud_formation/estimate_template_cost.rb +48 -0
  32. data/lib/fog/aws/requests/cloud_formation/execute_change_set.rb +26 -0
  33. data/lib/fog/aws/requests/cloud_formation/get_stack_policy.rb +27 -0
  34. data/lib/fog/aws/requests/cloud_formation/get_template_summary.rb +46 -0
  35. data/lib/fog/aws/requests/cloud_formation/list_change_sets.rb +40 -0
  36. data/lib/fog/aws/requests/cloud_formation/set_stack_policy.rb +38 -0
  37. data/lib/fog/aws/requests/cloud_formation/signal_resource.rb +32 -0
  38. data/lib/fog/aws/requests/cloud_formation/update_stack.rb +49 -0
  39. data/lib/fog/aws/requests/compute/authorize_security_group_egress.rb +112 -0
  40. data/lib/fog/aws/requests/compute/revoke_security_group_egress.rb +98 -0
  41. data/lib/fog/aws/requests/support/describe_trusted_advisor_check_result.rb +31 -0
  42. data/lib/fog/aws/requests/support/describe_trusted_advisor_checks.rb +29 -0
  43. data/lib/fog/aws/support.rb +170 -0
  44. data/lib/fog/aws/version.rb +1 -1
  45. data/tests/models/compute/security_group_tests.rb +24 -0
  46. data/tests/models/support/trusted_advisor_tests.rb +25 -0
  47. data/tests/requests/support/helper.rb +43 -0
  48. data/tests/requests/support/trusted_advisor_check_tests.rb +16 -0
  49. metadata +36 -3
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: b96d5e8e4defc964f4f383e3db8e5e933101ea78
4
- data.tar.gz: ee9929b2c953ecd1962311725a3ae17ed4396a0c
3
+ metadata.gz: 2cad9d793cac288d1f03fc73d7d531608f269b4c
4
+ data.tar.gz: 2dafa327b192217ba04f4a20b4adf7cddaa09be3
5
5
  SHA512:
6
- metadata.gz: bc2f7b1df08b2a0bf9fbd54a87db7d7b18c7d5360e7661f060a906e51685564d68f809521db01dfa40711389859fc2d69a6207d5d21024b5e9c0fdcb1ad91ea0
7
- data.tar.gz: 391f26896bb27d3fc601329a11d68aac5d865a3bd1c9fff1319f02cd789d8bad7ce91d1ad152e7607175ab80ff43baa196d153d35e2ec06d9f86c5aea73e6cfc
6
+ metadata.gz: 5aa5e8a00c298e743959011f936c5a4b6d8640c30501aaeb5e2593cb9ff6e69ca7cd5c6f9a3b35e247b382099d0ceabb5b21270a39364a265e1a1a84f769853d
7
+ data.tar.gz: 87e376f15aa50548604c98047f491ce81698c0807cb04993d343f4f7cb17a481893d8a9d0d81a99109c537665b4b8bbb9f0054d7d7bef4162b272ca9307eaa7f
@@ -2,7 +2,28 @@
2
2
 
3
3
  ## [Unreleased](https://github.com/fog/fog-aws/tree/HEAD)
4
4
 
5
- [Full Changelog](https://github.com/fog/fog-aws/compare/v0.10.0...HEAD)
5
+ [Full Changelog](https://github.com/fog/fog-aws/compare/v0.11.0...HEAD)
6
+
7
+ **Implemented enhancements:**
8
+
9
+ - Add gestion of egress security group rules [\#290](https://github.com/fog/fog-aws/pull/290) ([KevinLoiseau](https://github.com/KevinLoiseau))
10
+
11
+ **Closed issues:**
12
+
13
+ - Fog directory appends local system path with amazon url when i try to give dynamic fog directory [\#295](https://github.com/fog/fog-aws/issues/295)
14
+ - Getting OperationAborted error on file storage operation [\#288](https://github.com/fog/fog-aws/issues/288)
15
+ - AWS Elasticsearch API [\#286](https://github.com/fog/fog-aws/issues/286)
16
+ - Disable chunked encoding [\#285](https://github.com/fog/fog-aws/issues/285)
17
+
18
+ **Merged pull requests:**
19
+
20
+ - add support endpoint and models/requests for trusted advisor checks [\#300](https://github.com/fog/fog-aws/pull/300) ([ehowe](https://github.com/ehowe))
21
+ - Add attribute is\_default in vpc [\#299](https://github.com/fog/fog-aws/pull/299) ([zhitongLBN](https://github.com/zhitongLBN))
22
+ - Cloud Formation: additional parameters [\#298](https://github.com/fog/fog-aws/pull/298) ([neillturner](https://github.com/neillturner))
23
+ - Cloud Formation: support for change sets, stack policy and other missing calls. [\#297](https://github.com/fog/fog-aws/pull/297) ([neillturner](https://github.com/neillturner))
24
+
25
+ ## [v0.11.0](https://github.com/fog/fog-aws/tree/v0.11.0) (2016-08-04)
26
+ [Full Changelog](https://github.com/fog/fog-aws/compare/v0.10.0...v0.11.0)
6
27
 
7
28
  **Merged pull requests:**
8
29
 
@@ -52,6 +52,7 @@ module Fog
52
52
  autoload :SNS, File.expand_path('../aws/sns', __FILE__)
53
53
  autoload :SQS, File.expand_path('../aws/sqs', __FILE__)
54
54
  autoload :STS, File.expand_path('../aws/sts', __FILE__)
55
+ autoload :Support, File.expand_path('../aws/support', __FILE__)
55
56
  autoload :SimpleDB, File.expand_path('../aws/simpledb', __FILE__)
56
57
 
57
58
  service(:auto_scaling, 'AutoScaling')
@@ -81,6 +82,7 @@ module Fog
81
82
  service(:sqs, 'SQS')
82
83
  service(:storage, 'Storage')
83
84
  service(:sts, 'STS')
85
+ service(:support, 'Support')
84
86
 
85
87
  def self.indexed_param(key, values)
86
88
  params = {}
@@ -7,14 +7,28 @@ module Fog
7
7
  recognizes :host, :path, :port, :scheme, :persistent, :region, :use_iam_profile, :aws_session_token, :aws_credentials_expire_at, :instrumentor, :instrumentor_name
8
8
 
9
9
  request_path 'fog/aws/requests/cloud_formation'
10
+ request :cancel_update_stack
11
+ request :continue_update_rollback
12
+ request :create_change_set
10
13
  request :create_stack
11
14
  request :update_stack
15
+ request :delete_change_set
12
16
  request :delete_stack
17
+ request :describe_account_limits
18
+ request :describe_change_set
13
19
  request :describe_stack_events
20
+ request :describe_stack_resource
14
21
  request :describe_stack_resources
15
22
  request :describe_stacks
23
+ request :estimate_template_cost
24
+ request :execute_change_set
25
+ request :get_stack_policy
16
26
  request :get_template
27
+ request :get_template_summary
28
+ request :set_stack_policy
29
+ request :signal_resource
17
30
  request :validate_template
31
+ request :list_change_sets
18
32
  request :list_stacks
19
33
  request :list_stack_resources
20
34
 
@@ -54,6 +54,7 @@ module Fog
54
54
  request :attach_classic_link_vpc
55
55
  request :attach_internet_gateway
56
56
  request :attach_volume
57
+ request :authorize_security_group_egress
57
58
  request :authorize_security_group_ingress
58
59
  request :cancel_spot_instance_requests
59
60
  request :create_dhcp_options
@@ -150,6 +151,7 @@ module Fog
150
151
  request :register_image
151
152
  request :request_spot_instances
152
153
  request :reset_network_interface_attribute
154
+ request :revoke_security_group_egress
153
155
  request :revoke_security_group_ingress
154
156
  request :run_instances
155
157
  request :terminate_instances
@@ -82,22 +82,16 @@ module Fog
82
82
  def authorize_port_range(range, options = {})
83
83
  requires_one :name, :group_id
84
84
 
85
- ip_permission = {
86
- 'FromPort' => range.begin,
87
- 'ToPort' => range.end,
88
- 'IpProtocol' => options[:ip_protocol] || 'tcp'
89
- }
85
+ ip_permission = fetch_ip_permission(range, options)
90
86
 
91
- if options[:group].nil?
92
- ip_permission['IpRanges'] = [
93
- { 'CidrIp' => options[:cidr_ip] || '0.0.0.0/0' }
94
- ]
95
- else
96
- ip_permission['Groups'] = [
97
- group_info(options[:group])
98
- ]
87
+ if options[:direction].nil? || options[:direction] == 'ingress'
88
+ authorize_port_range_ingress group_id, ip_permission
89
+ elsif options[:direction] == 'egress'
90
+ authorize_port_range_egress group_id, ip_permission
99
91
  end
92
+ end
100
93
 
94
+ def authorize_port_range_ingress(group_id, ip_permission)
101
95
  service.authorize_security_group_ingress(
102
96
  name,
103
97
  'GroupId' => group_id,
@@ -105,6 +99,14 @@ module Fog
105
99
  )
106
100
  end
107
101
 
102
+ def authorize_port_range_egress(group_id, ip_permission)
103
+ service.authorize_security_group_egress(
104
+ name,
105
+ 'GroupId' => group_id,
106
+ 'IpPermissions' => [ ip_permission ]
107
+ )
108
+ end
109
+
108
110
  # Removes an existing security group
109
111
  #
110
112
  # security_group.destroy
@@ -196,22 +198,16 @@ module Fog
196
198
  def revoke_port_range(range, options = {})
197
199
  requires_one :name, :group_id
198
200
 
199
- ip_permission = {
200
- 'FromPort' => range.begin,
201
- 'ToPort' => range.end,
202
- 'IpProtocol' => options[:ip_protocol] || 'tcp'
203
- }
201
+ ip_permission = fetch_ip_permission(range, options)
204
202
 
205
- if options[:group].nil?
206
- ip_permission['IpRanges'] = [
207
- { 'CidrIp' => options[:cidr_ip] || '0.0.0.0/0' }
208
- ]
209
- else
210
- ip_permission['Groups'] = [
211
- group_info(options[:group])
212
- ]
203
+ if options[:direction].nil? || options[:direction] == 'ingress'
204
+ revoke_port_range_ingress group_id, ip_permission
205
+ elsif options[:direction] == 'egress'
206
+ revoke_port_range_egress group_id, ip_permission
213
207
  end
208
+ end
214
209
 
210
+ def revoke_port_range_ingress(group_id, ip_permission)
215
211
  service.revoke_security_group_ingress(
216
212
  name,
217
213
  'GroupId' => group_id,
@@ -219,6 +215,14 @@ module Fog
219
215
  )
220
216
  end
221
217
 
218
+ def revoke_port_range_egress(group_id, ip_permission)
219
+ service.revoke_security_group_egress(
220
+ name,
221
+ 'GroupId' => group_id,
222
+ 'IpPermissions' => [ ip_permission ]
223
+ )
224
+ end
225
+
222
226
  # Reload a security group
223
227
  #
224
228
  # >> g = AWS.security_groups.get(:name => "some_name")
@@ -314,6 +318,25 @@ module Fog
314
318
 
315
319
  info
316
320
  end
321
+
322
+ def fetch_ip_permission(range, options)
323
+ ip_permission = {
324
+ 'FromPort' => range.begin,
325
+ 'ToPort' => range.end,
326
+ 'IpProtocol' => options[:ip_protocol] || 'tcp'
327
+ }
328
+
329
+ if options[:group].nil?
330
+ ip_permission['IpRanges'] = [
331
+ { 'CidrIp' => options[:cidr_ip] || '0.0.0.0/0' }
332
+ ]
333
+ else
334
+ ip_permission['Groups'] = [
335
+ group_info(options[:group])
336
+ ]
337
+ end
338
+ ip_permission
339
+ end
317
340
  end
318
341
  end
319
342
  end
@@ -9,6 +9,7 @@ module Fog
9
9
  attribute :dhcp_options_id, :aliases => 'dhcpOptionsId'
10
10
  attribute :tags, :aliases => 'tagSet'
11
11
  attribute :tenancy, :aliases => 'instanceTenancy'
12
+ attribute :is_default, :aliases => 'isDefault'
12
13
 
13
14
  def initialize(attributes={})
14
15
  self.dhcp_options_id ||= "default"
@@ -21,6 +22,11 @@ module Fog
21
22
  state == 'available'
22
23
  end
23
24
 
25
+ def is_default?
26
+ require :is_default
27
+ is_default
28
+ end
29
+
24
30
  # Removes an existing vpc
25
31
  #
26
32
  # vpc.destroy
@@ -0,0 +1,14 @@
1
+ module Fog
2
+ module AWS
3
+ class Support
4
+ class FlaggedResource < Fog::Model
5
+ identity :resource_id, :aliases => "resourceId"
6
+
7
+ attribute :is_suppressed, :aliases => "isSuppressed", :type => :boolean
8
+ attribute :metadata
9
+ attribute :region
10
+ attribute :status
11
+ end
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,11 @@
1
+ require 'fog/aws/models/support/flagged_resource'
2
+
3
+ module Fog
4
+ module AWS
5
+ class Support
6
+ class FlaggedResources < Fog::Collection
7
+ model Fog::AWS::Support::FlaggedResource
8
+ end
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,65 @@
1
+ module Fog
2
+ module AWS
3
+ class Support
4
+ class TrustedAdvisorCheck < Fog::Model
5
+ identity :id, :aliases => 'checkId'
6
+
7
+ attribute :name
8
+ attribute :category
9
+ attribute :description
10
+ attribute :metadata
11
+ attribute :flagged_resources, :aliases => 'flaggedResources'
12
+ attribute :resources_summary, :aliases => 'resourcesSummary'
13
+ attribute :status
14
+ attribute :timestamp
15
+ attribute :category_specific_summary, :aliases => 'categorySpecificSummary'
16
+
17
+ def populate_extended_attributes(lazy=false)
18
+ return if lazy == true
19
+ data = service.describe_trusted_advisor_check_result(:id => self.identity).body["result"]
20
+ merge_attributes(data)
21
+ end
22
+
23
+ def flagged_resources(lazy=true)
24
+ if attributes[:flagged_resources].nil?
25
+ populate_extended_attributes(lazy)
26
+
27
+ if attributes[:flagged_resources]
28
+ map_flagged_resources!
29
+ service.flagged_resources.load(attributes[:flagged_resources])
30
+ else
31
+ nil
32
+ end
33
+ else
34
+ if attributes[:flagged_resources].first['metadata'].is_a?(Array)
35
+ map_flagged_resources!
36
+ end
37
+ service.flagged_resources.load(attributes[:flagged_resources])
38
+ end
39
+ end
40
+
41
+ def category_specific_summary(lazy=true)
42
+ populate_extended_attributes(lazy) if attributes[:category_specific_summary].nil?
43
+ attributes[:category_stecific_summary]
44
+ end
45
+
46
+ def resources_summary(lazy=true)
47
+ populate_extended_attributes(lazy) if attributes[:resources_summary].nil?
48
+ attributes[:resources_summary]
49
+ end
50
+
51
+ private
52
+
53
+ def map_flagged_resources!
54
+ attributes[:flagged_resources].map! do |fr|
55
+ fr['metadata'] = fr['metadata'].each_with_index.inject({}) do |hash,(data,index)|
56
+ hash[self.metadata[index]] = data
57
+ hash
58
+ end
59
+ fr
60
+ end
61
+ end
62
+ end
63
+ end
64
+ end
65
+ end
@@ -0,0 +1,21 @@
1
+ require 'fog/aws/models/support/trusted_advisor_check'
2
+
3
+ module Fog
4
+ module AWS
5
+ class Support
6
+ class TrustedAdvisorChecks < Fog::Collection
7
+ model Fog::AWS::Support::TrustedAdvisorCheck
8
+
9
+ def all
10
+ data = service.describe_trusted_advisor_checks.body['checks']
11
+ load(data)
12
+ end
13
+
14
+ def get(id)
15
+ data = service.describe_trusted_advisor_check_result(:id => id).body['result']
16
+ new(data).populate_extended_attributes
17
+ end
18
+ end
19
+ end
20
+ end
21
+ end
@@ -3,6 +3,14 @@ module Fog
3
3
  module AWS
4
4
  module CloudFormation
5
5
  class Basic < Fog::Parsers::Base
6
+ def end_element(name)
7
+ case name
8
+ when 'RequestId'
9
+ @response[name] = value
10
+ when 'NextToken'
11
+ @response[name] = value
12
+ end
13
+ end
6
14
  end
7
15
  end
8
16
  end
@@ -0,0 +1,16 @@
1
+ module Fog
2
+ module Parsers
3
+ module AWS
4
+ module CloudFormation
5
+ class CreateChangeSet < Fog::Parsers::Base
6
+ def end_element(name)
7
+ case name
8
+ when 'RequestId', 'Id'
9
+ @response[name] = value
10
+ end
11
+ end
12
+ end
13
+ end
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,26 @@
1
+ module Fog
2
+ module Parsers
3
+ module AWS
4
+ module CloudFormation
5
+ class DescribeAccountLimits < Fog::Parsers::Base
6
+ def reset
7
+ @limit = {}
8
+ @response = { 'AccountLimits' => [] }
9
+ end
10
+
11
+ def end_element(name)
12
+ case name
13
+ when 'Name', 'Value'
14
+ @limit[name] = value
15
+ when 'member'
16
+ @response['AccountLimits'] << @limit
17
+ @limit = {}
18
+ when 'RequestId'
19
+ @response[name] = value
20
+ end
21
+ end
22
+ end
23
+ end
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,135 @@
1
+ module Fog
2
+ module Parsers
3
+ module AWS
4
+ module CloudFormation
5
+ class DescribeChangeSet < Fog::Parsers::Base
6
+ def reset
7
+ @response = fresh_change_set
8
+ reset_parameter
9
+ reset_change
10
+ reset_resource_change
11
+ reset_resource_change_detail
12
+ reset_resource_target_definition
13
+ end
14
+
15
+ def reset_parameter
16
+ @parameter = {}
17
+ end
18
+
19
+ def reset_change
20
+ @change = {}
21
+ end
22
+
23
+ def reset_resource_change
24
+ @resource_change = {'Details' => [], 'Scope' => [] }
25
+ end
26
+
27
+ def reset_resource_change_detail
28
+ @resource_change_detail = {}
29
+ end
30
+
31
+ def reset_resource_target_definition
32
+ @resource_target_definition = {}
33
+ end
34
+
35
+ def fresh_change_set
36
+ {'Capabilities' => [], 'Changes' => [], 'NotificationARNs' => [], 'Parameters' => [], 'Tags' => []}
37
+ end
38
+
39
+ def start_element(name, attrs=[])
40
+ super
41
+ case name
42
+ when 'Capabilities'
43
+ @in_capabilities = true
44
+ when 'Changes'
45
+ @in_changes = true
46
+ when 'ResourceChange'
47
+ @in_resource_change = true
48
+ when 'Scope'
49
+ @in_scope = true
50
+ when 'Details'
51
+ @in_details = true
52
+ when 'Target'
53
+ @in_target = true
54
+ when 'NotificationARNs'
55
+ @in_notification_arns = true
56
+ when 'Parameters'
57
+ @in_parameters = true
58
+ when 'Tags'
59
+ @in_tags = true
60
+ end
61
+ end
62
+
63
+ def end_element(name)
64
+ case name
65
+ when 'ChangeSetId', 'ChangeSetName', 'Description', 'ExecutionStatus', 'StackId', 'StackName', 'StatusReason'
66
+ @response[name] = value
67
+ when 'CreationTime'
68
+ @response[name] = Time.parse(value)
69
+ when 'member'
70
+ if @in_capabilities
71
+ @response['Capabilities'] << value
72
+ elsif @in_scope
73
+ @resource_change['Scope'] << value
74
+ elsif @in_notification_arns
75
+ @response['NotificationARNs'] << value
76
+ elsif @in_parameters
77
+ @response['Parameters'] << @parameter
78
+ reset_parameter
79
+ elsif @in_tags
80
+ @response['Tags'] << @tag
81
+ reset_tag
82
+ elsif @in_details
83
+ @resource_change['Details'] << @resource_change_detail
84
+ reset_resource_change_detail
85
+ elsif @in_changes
86
+ @response['Changes'] << @change
87
+ reset_change
88
+ end
89
+ when 'ParameterValue', 'ParameterKey'
90
+ @parameter[name] = value if @in_parameters
91
+ when 'Parameters'
92
+ @in_parameters = false
93
+ when 'Value', 'Key'
94
+ @tag[name] = value if @in_tags
95
+ when 'Tags'
96
+ @in_tags = false
97
+ when 'Capabilities'
98
+ @in_capabilities = false
99
+ when 'Scope'
100
+ @in_scope = false
101
+ when 'NotificationARNs'
102
+ @in_notification_arns = false
103
+ when 'Type'
104
+ @change[name] = value if @in_changes
105
+ when 'Changes'
106
+ @in_changes = false
107
+ when 'ResourceChange'
108
+ if @in_resource_change
109
+ @change[name] = @resource_change
110
+ @in_resource_change = false
111
+ end
112
+ when 'Action','LogicalResourceId','PhysicalResourceId','Replacement','ResourceType'
113
+ @resource_change[name] = value if @in_resource_change
114
+ when 'Details'
115
+ @in_details = false
116
+ when 'CausingEntity','ChangeSource','Evaluation'
117
+ if @in_details
118
+ @resource_change_detail[name] = value
119
+ end
120
+ when 'Attribute','Name','RequiresRecreation'
121
+ if @in_target
122
+ @resource_target_definition[name] = value
123
+ end
124
+ when 'Target'
125
+ if @in_target
126
+ @resource_change_detail[name] = @resource_target_definition
127
+ @in_target = false
128
+ end
129
+ end
130
+ end
131
+ end
132
+ end
133
+ end
134
+ end
135
+ end