functions_framework 0.4.0 → 0.6.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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +26 -0
- data/README.md +9 -9
- data/bin/functions-framework +1 -1
- data/bin/functions-framework-ruby +1 -1
- data/docs/deploying-functions.md +29 -14
- data/docs/overview.md +4 -4
- data/docs/testing-functions.md +9 -11
- data/docs/writing-functions.md +73 -13
- data/lib/functions_framework.rb +35 -7
- data/lib/functions_framework/cli.rb +97 -22
- data/lib/functions_framework/function.rb +3 -2
- data/lib/functions_framework/legacy_event_converter.rb +28 -29
- data/lib/functions_framework/registry.rb +40 -6
- data/lib/functions_framework/server.rb +14 -10
- data/lib/functions_framework/testing.rb +20 -8
- data/lib/functions_framework/version.rb +1 -1
- metadata +22 -108
- data/lib/functions_framework/cloud_events.rb +0 -45
- data/lib/functions_framework/cloud_events/content_type.rb +0 -216
- data/lib/functions_framework/cloud_events/errors.rb +0 -42
- data/lib/functions_framework/cloud_events/event.rb +0 -84
- data/lib/functions_framework/cloud_events/event/field_interpreter.rb +0 -150
- data/lib/functions_framework/cloud_events/event/v0.rb +0 -236
- data/lib/functions_framework/cloud_events/event/v1.rb +0 -223
- data/lib/functions_framework/cloud_events/http_binding.rb +0 -310
- data/lib/functions_framework/cloud_events/json_format.rb +0 -173
@@ -100,7 +100,7 @@ module FunctionsFramework
|
|
100
100
|
# be of type :cloud_event`.
|
101
101
|
#
|
102
102
|
# @param name [String] The name of the function to call
|
103
|
-
# @param event [
|
103
|
+
# @param event [::CloudEvents::Event] The event to send
|
104
104
|
# @return [nil]
|
105
105
|
#
|
106
106
|
def call_event name, event
|
@@ -174,23 +174,35 @@ module FunctionsFramework
|
|
174
174
|
# @param source [String,URI] Event source (optional)
|
175
175
|
# @param type [String] Event type (optional)
|
176
176
|
# @param spec_version [String] Spec version (optional)
|
177
|
-
# @param data_content_type [String
|
177
|
+
# @param data_content_type [String,::CloudEvents::ContentType]
|
178
178
|
# Content type for the data (optional)
|
179
179
|
# @param data_schema [String,URI] Data schema (optional)
|
180
180
|
# @param subject [String] Subject (optional)
|
181
181
|
# @param time [String,DateTime] Event timestamp (optional)
|
182
|
-
# @return [
|
182
|
+
# @return [::CloudEvents::Event]
|
183
183
|
#
|
184
184
|
def make_cloud_event data,
|
185
|
-
id: nil,
|
186
|
-
|
185
|
+
id: nil,
|
186
|
+
source: nil,
|
187
|
+
type: nil,
|
188
|
+
spec_version: nil,
|
189
|
+
data_content_type: nil,
|
190
|
+
data_schema: nil,
|
191
|
+
subject: nil,
|
192
|
+
time: nil
|
187
193
|
id ||= "random-id-#{rand 100_000_000}"
|
188
194
|
source ||= "functions-framework-testing"
|
189
195
|
type ||= "com.example.test"
|
190
196
|
spec_version ||= "1.0"
|
191
|
-
CloudEvents::Event.new id:
|
192
|
-
|
193
|
-
|
197
|
+
::CloudEvents::Event.new id: id,
|
198
|
+
source: source,
|
199
|
+
type: type,
|
200
|
+
spec_version: spec_version,
|
201
|
+
data_content_type: data_content_type,
|
202
|
+
data_schema: data_schema,
|
203
|
+
subject: subject,
|
204
|
+
time: time,
|
205
|
+
data: data
|
194
206
|
end
|
195
207
|
|
196
208
|
extend self
|
metadata
CHANGED
@@ -1,142 +1,61 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: functions_framework
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.6.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Daniel Azuma
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2020-
|
11
|
+
date: 2020-09-17 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
|
-
name:
|
14
|
+
name: cloud_events
|
15
15
|
requirement: !ruby/object:Gem::Requirement
|
16
16
|
requirements:
|
17
17
|
- - "~>"
|
18
18
|
- !ruby/object:Gem::Version
|
19
|
-
version: '
|
19
|
+
version: '0.1'
|
20
20
|
type: :runtime
|
21
21
|
prerelease: false
|
22
22
|
version_requirements: !ruby/object:Gem::Requirement
|
23
23
|
requirements:
|
24
24
|
- - "~>"
|
25
25
|
- !ruby/object:Gem::Version
|
26
|
-
version: '
|
26
|
+
version: '0.1'
|
27
27
|
- !ruby/object:Gem::Dependency
|
28
|
-
name:
|
28
|
+
name: puma
|
29
29
|
requirement: !ruby/object:Gem::Requirement
|
30
30
|
requirements:
|
31
31
|
- - "~>"
|
32
32
|
- !ruby/object:Gem::Version
|
33
|
-
version: '
|
33
|
+
version: '4.3'
|
34
34
|
type: :runtime
|
35
35
|
prerelease: false
|
36
36
|
version_requirements: !ruby/object:Gem::Requirement
|
37
37
|
requirements:
|
38
38
|
- - "~>"
|
39
39
|
- !ruby/object:Gem::Version
|
40
|
-
version: '
|
41
|
-
- !ruby/object:Gem::Dependency
|
42
|
-
name: google-style
|
43
|
-
requirement: !ruby/object:Gem::Requirement
|
44
|
-
requirements:
|
45
|
-
- - "~>"
|
46
|
-
- !ruby/object:Gem::Version
|
47
|
-
version: 1.24.0
|
48
|
-
type: :development
|
49
|
-
prerelease: false
|
50
|
-
version_requirements: !ruby/object:Gem::Requirement
|
51
|
-
requirements:
|
52
|
-
- - "~>"
|
53
|
-
- !ruby/object:Gem::Version
|
54
|
-
version: 1.24.0
|
55
|
-
- !ruby/object:Gem::Dependency
|
56
|
-
name: minitest
|
57
|
-
requirement: !ruby/object:Gem::Requirement
|
58
|
-
requirements:
|
59
|
-
- - "~>"
|
60
|
-
- !ruby/object:Gem::Version
|
61
|
-
version: '5.13'
|
62
|
-
type: :development
|
63
|
-
prerelease: false
|
64
|
-
version_requirements: !ruby/object:Gem::Requirement
|
65
|
-
requirements:
|
66
|
-
- - "~>"
|
67
|
-
- !ruby/object:Gem::Version
|
68
|
-
version: '5.13'
|
69
|
-
- !ruby/object:Gem::Dependency
|
70
|
-
name: minitest-focus
|
71
|
-
requirement: !ruby/object:Gem::Requirement
|
72
|
-
requirements:
|
73
|
-
- - "~>"
|
74
|
-
- !ruby/object:Gem::Version
|
75
|
-
version: '1.1'
|
76
|
-
type: :development
|
77
|
-
prerelease: false
|
78
|
-
version_requirements: !ruby/object:Gem::Requirement
|
79
|
-
requirements:
|
80
|
-
- - "~>"
|
81
|
-
- !ruby/object:Gem::Version
|
82
|
-
version: '1.1'
|
83
|
-
- !ruby/object:Gem::Dependency
|
84
|
-
name: minitest-rg
|
85
|
-
requirement: !ruby/object:Gem::Requirement
|
86
|
-
requirements:
|
87
|
-
- - "~>"
|
88
|
-
- !ruby/object:Gem::Version
|
89
|
-
version: '5.2'
|
90
|
-
type: :development
|
91
|
-
prerelease: false
|
92
|
-
version_requirements: !ruby/object:Gem::Requirement
|
93
|
-
requirements:
|
94
|
-
- - "~>"
|
95
|
-
- !ruby/object:Gem::Version
|
96
|
-
version: '5.2'
|
97
|
-
- !ruby/object:Gem::Dependency
|
98
|
-
name: redcarpet
|
99
|
-
requirement: !ruby/object:Gem::Requirement
|
100
|
-
requirements:
|
101
|
-
- - "~>"
|
102
|
-
- !ruby/object:Gem::Version
|
103
|
-
version: '3.5'
|
104
|
-
type: :development
|
105
|
-
prerelease: false
|
106
|
-
version_requirements: !ruby/object:Gem::Requirement
|
107
|
-
requirements:
|
108
|
-
- - "~>"
|
109
|
-
- !ruby/object:Gem::Version
|
110
|
-
version: '3.5'
|
111
|
-
- !ruby/object:Gem::Dependency
|
112
|
-
name: toys
|
113
|
-
requirement: !ruby/object:Gem::Requirement
|
114
|
-
requirements:
|
115
|
-
- - "~>"
|
116
|
-
- !ruby/object:Gem::Version
|
117
|
-
version: 0.10.0
|
118
|
-
type: :development
|
119
|
-
prerelease: false
|
120
|
-
version_requirements: !ruby/object:Gem::Requirement
|
121
|
-
requirements:
|
122
|
-
- - "~>"
|
123
|
-
- !ruby/object:Gem::Version
|
124
|
-
version: 0.10.0
|
40
|
+
version: '4.3'
|
125
41
|
- !ruby/object:Gem::Dependency
|
126
|
-
name:
|
42
|
+
name: rack
|
127
43
|
requirement: !ruby/object:Gem::Requirement
|
128
44
|
requirements:
|
129
45
|
- - "~>"
|
130
46
|
- !ruby/object:Gem::Version
|
131
|
-
version:
|
132
|
-
type: :
|
47
|
+
version: '2.1'
|
48
|
+
type: :runtime
|
133
49
|
prerelease: false
|
134
50
|
version_requirements: !ruby/object:Gem::Requirement
|
135
51
|
requirements:
|
136
52
|
- - "~>"
|
137
53
|
- !ruby/object:Gem::Version
|
138
|
-
version:
|
139
|
-
description: The Functions Framework
|
54
|
+
version: '2.1'
|
55
|
+
description: The Functions Framework is an open source framework for writing lightweight,
|
56
|
+
portable Ruby functions that run in a serverless environment. Functions written
|
57
|
+
to this Framework will run Google Cloud Google Cloud Functions, Google Cloud Run,
|
58
|
+
or any other Knative-based environment.
|
140
59
|
email:
|
141
60
|
- dazuma@google.com
|
142
61
|
executables:
|
@@ -158,15 +77,6 @@ files:
|
|
158
77
|
- docs/writing-functions.md
|
159
78
|
- lib/functions_framework.rb
|
160
79
|
- lib/functions_framework/cli.rb
|
161
|
-
- lib/functions_framework/cloud_events.rb
|
162
|
-
- lib/functions_framework/cloud_events/content_type.rb
|
163
|
-
- lib/functions_framework/cloud_events/errors.rb
|
164
|
-
- lib/functions_framework/cloud_events/event.rb
|
165
|
-
- lib/functions_framework/cloud_events/event/field_interpreter.rb
|
166
|
-
- lib/functions_framework/cloud_events/event/v0.rb
|
167
|
-
- lib/functions_framework/cloud_events/event/v1.rb
|
168
|
-
- lib/functions_framework/cloud_events/http_binding.rb
|
169
|
-
- lib/functions_framework/cloud_events/json_format.rb
|
170
80
|
- lib/functions_framework/function.rb
|
171
81
|
- lib/functions_framework/legacy_event_converter.rb
|
172
82
|
- lib/functions_framework/registry.rb
|
@@ -176,7 +86,11 @@ files:
|
|
176
86
|
homepage: https://github.com/GoogleCloudPlatform/functions-framework-ruby
|
177
87
|
licenses:
|
178
88
|
- Apache-2.0
|
179
|
-
metadata:
|
89
|
+
metadata:
|
90
|
+
changelog_uri: https://googlecloudplatform.github.io/functions-framework-ruby/v0.6.0/file.CHANGELOG.html
|
91
|
+
source_code_uri: https://github.com/GoogleCloudPlatform/functions-framework-ruby
|
92
|
+
bug_tracker_uri: https://github.com/GoogleCloudPlatform/functions-framework-ruby/issues
|
93
|
+
documentation_uri: https://googlecloudplatform.github.io/functions-framework-ruby/v0.6.0
|
180
94
|
post_install_message:
|
181
95
|
rdoc_options: []
|
182
96
|
require_paths:
|
@@ -192,7 +106,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
192
106
|
- !ruby/object:Gem::Version
|
193
107
|
version: '0'
|
194
108
|
requirements: []
|
195
|
-
rubygems_version: 3.
|
109
|
+
rubygems_version: 3.0.3
|
196
110
|
signing_key:
|
197
111
|
specification_version: 4
|
198
112
|
summary: Functions Framework for Ruby
|
@@ -1,45 +0,0 @@
|
|
1
|
-
# Copyright 2020 Google LLC
|
2
|
-
#
|
3
|
-
# Licensed under the Apache License, Version 2.0 (the "License");
|
4
|
-
# you may not use this file except in compliance with the License.
|
5
|
-
# You may obtain a copy of the License at
|
6
|
-
#
|
7
|
-
# https://www.apache.org/licenses/LICENSE-2.0
|
8
|
-
#
|
9
|
-
# Unless required by applicable law or agreed to in writing, software
|
10
|
-
# distributed under the License is distributed on an "AS IS" BASIS,
|
11
|
-
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
12
|
-
# See the License for the specific language governing permissions and
|
13
|
-
# limitations under the License.
|
14
|
-
|
15
|
-
require "functions_framework/cloud_events/content_type"
|
16
|
-
require "functions_framework/cloud_events/errors"
|
17
|
-
require "functions_framework/cloud_events/event"
|
18
|
-
require "functions_framework/cloud_events/http_binding"
|
19
|
-
require "functions_framework/cloud_events/json_format"
|
20
|
-
|
21
|
-
module FunctionsFramework
|
22
|
-
##
|
23
|
-
# CloudEvents implementation.
|
24
|
-
#
|
25
|
-
# This is a Ruby implementation of the [CloudEvents](https://cloudevents.io)
|
26
|
-
# specification. It supports both
|
27
|
-
# [CloudEvents 0.3](https://github.com/cloudevents/spec/blob/v0.3/spec.md) and
|
28
|
-
# [CloudEvents 1.0](https://github.com/cloudevents/spec/blob/v1.0/spec.md).
|
29
|
-
#
|
30
|
-
module CloudEvents
|
31
|
-
# @private
|
32
|
-
SUPPORTED_SPEC_VERSIONS = ["0.3", "1.0"].freeze
|
33
|
-
|
34
|
-
class << self
|
35
|
-
##
|
36
|
-
# The spec versions supported by this implementation.
|
37
|
-
#
|
38
|
-
# @return [Array<String>]
|
39
|
-
#
|
40
|
-
def supported_spec_versions
|
41
|
-
SUPPORTED_SPEC_VERSIONS
|
42
|
-
end
|
43
|
-
end
|
44
|
-
end
|
45
|
-
end
|
@@ -1,216 +0,0 @@
|
|
1
|
-
# Copyright 2020 Google LLC
|
2
|
-
#
|
3
|
-
# Licensed under the Apache License, Version 2.0 (the "License");
|
4
|
-
# you may not use this file except in compliance with the License.
|
5
|
-
# You may obtain a copy of the License at
|
6
|
-
#
|
7
|
-
# https://www.apache.org/licenses/LICENSE-2.0
|
8
|
-
#
|
9
|
-
# Unless required by applicable law or agreed to in writing, software
|
10
|
-
# distributed under the License is distributed on an "AS IS" BASIS,
|
11
|
-
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
12
|
-
# See the License for the specific language governing permissions and
|
13
|
-
# limitations under the License.
|
14
|
-
|
15
|
-
module FunctionsFramework
|
16
|
-
module CloudEvents
|
17
|
-
##
|
18
|
-
# A parsed content-type header.
|
19
|
-
#
|
20
|
-
# This object represents the information contained in a Content-Type,
|
21
|
-
# obtained by parsing the header according to RFC 2045.
|
22
|
-
#
|
23
|
-
# Case-insensitive fields, such as media_type and subtype, are normalized
|
24
|
-
# to lower case.
|
25
|
-
#
|
26
|
-
# If parsing fails, this class will try to get as much information as it
|
27
|
-
# can, and fill the rest with defaults as recommended in RFC 2045 sec 5.2.
|
28
|
-
# In case of a parsing error, the {#error_message} field will be set.
|
29
|
-
#
|
30
|
-
class ContentType
|
31
|
-
##
|
32
|
-
# Parse the given header value.
|
33
|
-
#
|
34
|
-
# @param string [String] Content-Type header value in RFC 2045 format
|
35
|
-
#
|
36
|
-
def initialize string
|
37
|
-
@string = string
|
38
|
-
@media_type = "text"
|
39
|
-
@subtype_base = @subtype = "plain"
|
40
|
-
@subtype_format = nil
|
41
|
-
@params = []
|
42
|
-
@charset = "us-ascii"
|
43
|
-
@error_message = nil
|
44
|
-
parse consume_comments string.strip
|
45
|
-
@canonical_string = "#{@media_type}/#{@subtype}" +
|
46
|
-
@params.map { |k, v| "; #{k}=#{v}" }.join
|
47
|
-
end
|
48
|
-
|
49
|
-
##
|
50
|
-
# The original header content string.
|
51
|
-
# @return [String]
|
52
|
-
#
|
53
|
-
attr_reader :string
|
54
|
-
alias to_s string
|
55
|
-
|
56
|
-
##
|
57
|
-
# A "canonical" header content string with spacing and capitalization
|
58
|
-
# normalized.
|
59
|
-
# @return [String]
|
60
|
-
#
|
61
|
-
attr_reader :canonical_string
|
62
|
-
|
63
|
-
##
|
64
|
-
# The media type.
|
65
|
-
# @return [String]
|
66
|
-
#
|
67
|
-
attr_reader :media_type
|
68
|
-
|
69
|
-
##
|
70
|
-
# The entire content subtype (which could include an extension delimited
|
71
|
-
# by a plus sign).
|
72
|
-
# @return [String]
|
73
|
-
#
|
74
|
-
attr_reader :subtype
|
75
|
-
|
76
|
-
##
|
77
|
-
# The portion of the content subtype before any plus sign.
|
78
|
-
# @return [String]
|
79
|
-
#
|
80
|
-
attr_reader :subtype_base
|
81
|
-
|
82
|
-
##
|
83
|
-
# The portion of the content subtype after any plus sign, or nil if there
|
84
|
-
# is no plus sign in the subtype.
|
85
|
-
# @return [String,nil]
|
86
|
-
#
|
87
|
-
attr_reader :subtype_format
|
88
|
-
|
89
|
-
##
|
90
|
-
# An array of parameters, each element as a two-element array of the
|
91
|
-
# parameter name and value.
|
92
|
-
# @return [Array<Array(String,String)>]
|
93
|
-
#
|
94
|
-
attr_reader :params
|
95
|
-
|
96
|
-
##
|
97
|
-
# The charset, defaulting to "us-ascii" if none is explicitly set.
|
98
|
-
# @return [String]
|
99
|
-
#
|
100
|
-
attr_reader :charset
|
101
|
-
|
102
|
-
##
|
103
|
-
# The error message when parsing, or `nil` if there was no error message.
|
104
|
-
# @return [String,nil]
|
105
|
-
#
|
106
|
-
attr_reader :error_message
|
107
|
-
|
108
|
-
##
|
109
|
-
# An array of values for the given parameter name
|
110
|
-
# @param key [String]
|
111
|
-
# @return [Array<String>]
|
112
|
-
#
|
113
|
-
def param_values key
|
114
|
-
key = key.downcase
|
115
|
-
@params.inject([]) { |a, (k, v)| key == k ? a << v : a }
|
116
|
-
end
|
117
|
-
|
118
|
-
## @private
|
119
|
-
def == other
|
120
|
-
other.is_a?(ContentType) && canonical_string == other.canonical_string
|
121
|
-
end
|
122
|
-
alias eql? ==
|
123
|
-
|
124
|
-
## @private
|
125
|
-
def hash
|
126
|
-
canonical_string.hash
|
127
|
-
end
|
128
|
-
|
129
|
-
## @private
|
130
|
-
class ParseError < ::StandardError
|
131
|
-
end
|
132
|
-
|
133
|
-
private
|
134
|
-
|
135
|
-
def parse str
|
136
|
-
@media_type, str = consume_token str, downcase: true, error_message: "Failed to parse media type"
|
137
|
-
str = consume_special str, "/"
|
138
|
-
@subtype, str = consume_token str, downcase: true, error_message: "Failed to parse subtype"
|
139
|
-
@subtype_base, @subtype_format = @subtype.split "+", 2
|
140
|
-
until str.empty?
|
141
|
-
str = consume_special str, ";"
|
142
|
-
name, str = consume_token str, downcase: true, error_message: "Faled to parse attribute name"
|
143
|
-
str = consume_special str, "=", error_message: "Failed to find value for attribute #{name}"
|
144
|
-
val, str = consume_token_or_quoted str, error_message: "Failed to parse value for attribute #{name}"
|
145
|
-
@params << [name, val]
|
146
|
-
@charset = val if name == "charset"
|
147
|
-
end
|
148
|
-
rescue ParseError => e
|
149
|
-
@error_message = e.message
|
150
|
-
end
|
151
|
-
|
152
|
-
def consume_token str, downcase: false, error_message: nil
|
153
|
-
match = /^([\w!#\$%&'\*\+\.\^`\{\|\}-]+)(.*)$/.match str
|
154
|
-
raise ParseError, error_message || "Expected token" unless match
|
155
|
-
token = match[1]
|
156
|
-
token.downcase! if downcase
|
157
|
-
str = consume_comments match[2].strip
|
158
|
-
[token, str]
|
159
|
-
end
|
160
|
-
|
161
|
-
def consume_special str, expected, error_message: nil
|
162
|
-
raise ParseError, error_message || "Expected #{expected.inspect}" unless str.start_with? expected
|
163
|
-
consume_comments str[1..-1].strip
|
164
|
-
end
|
165
|
-
|
166
|
-
def consume_token_or_quoted str, error_message: nil
|
167
|
-
return consume_token str unless str.start_with? '"'
|
168
|
-
arr = []
|
169
|
-
index = 1
|
170
|
-
loop do
|
171
|
-
char = str[index]
|
172
|
-
case char
|
173
|
-
when nil
|
174
|
-
raise ParseError, error_message || "Quoted-string never finished"
|
175
|
-
when "\""
|
176
|
-
break
|
177
|
-
when "\\"
|
178
|
-
char = str[index + 1]
|
179
|
-
raise ParseError, error_message || "Quoted-string never finished" unless char
|
180
|
-
arr << char
|
181
|
-
index += 2
|
182
|
-
else
|
183
|
-
arr << char
|
184
|
-
index += 1
|
185
|
-
end
|
186
|
-
end
|
187
|
-
index += 1
|
188
|
-
str = consume_comments str[index..-1].strip
|
189
|
-
[arr.join, str]
|
190
|
-
end
|
191
|
-
|
192
|
-
def consume_comments str
|
193
|
-
return str unless str.start_with? "("
|
194
|
-
index = 1
|
195
|
-
loop do
|
196
|
-
char = str[index]
|
197
|
-
case char
|
198
|
-
when nil
|
199
|
-
raise ParseError, "Comment never finished"
|
200
|
-
when ")"
|
201
|
-
break
|
202
|
-
when "\\"
|
203
|
-
index += 2
|
204
|
-
when "("
|
205
|
-
str = consume_comments str[index..-1]
|
206
|
-
index = 0
|
207
|
-
else
|
208
|
-
index += 1
|
209
|
-
end
|
210
|
-
end
|
211
|
-
index += 1
|
212
|
-
consume_comments str[index..-1].strip
|
213
|
-
end
|
214
|
-
end
|
215
|
-
end
|
216
|
-
end
|