adzerk_decision_sdk 1.0.0.pre.beta.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (51) hide show
  1. checksums.yaml +7 -0
  2. data/Gemfile +9 -0
  3. data/Gemfile.lock +70 -0
  4. data/README.md +97 -0
  5. data/Rakefile +10 -0
  6. data/adzerk_decision_sdk.gemspec +39 -0
  7. data/docs/Consent.md +17 -0
  8. data/docs/ConsentRequest.md +19 -0
  9. data/docs/Content.md +25 -0
  10. data/docs/Decision.md +35 -0
  11. data/docs/DecisionApi.md +57 -0
  12. data/docs/DecisionData.md +25 -0
  13. data/docs/DecisionRequest.md +43 -0
  14. data/docs/DecisionResponse.md +21 -0
  15. data/docs/Event.md +19 -0
  16. data/docs/GdprConsent.md +19 -0
  17. data/docs/Placement.md +47 -0
  18. data/docs/PricingData.md +25 -0
  19. data/docs/Request.md +43 -0
  20. data/docs/RequestConsent.md +17 -0
  21. data/docs/Response.md +21 -0
  22. data/docs/User.md +17 -0
  23. data/docs/UserdbApi.md +536 -0
  24. data/git_push.sh +58 -0
  25. data/lib/adzerk_decision_sdk/api/decision_api.rb +80 -0
  26. data/lib/adzerk_decision_sdk/api/userdb_api.rb +731 -0
  27. data/lib/adzerk_decision_sdk/api_client.rb +386 -0
  28. data/lib/adzerk_decision_sdk/api_error.rb +57 -0
  29. data/lib/adzerk_decision_sdk/client.rb +43 -0
  30. data/lib/adzerk_decision_sdk/configuration.rb +262 -0
  31. data/lib/adzerk_decision_sdk/decision_client.rb +73 -0
  32. data/lib/adzerk_decision_sdk/event_type.rb +61 -0
  33. data/lib/adzerk_decision_sdk/models/consent_request.rb +215 -0
  34. data/lib/adzerk_decision_sdk/models/content.rb +242 -0
  35. data/lib/adzerk_decision_sdk/models/decision.rb +291 -0
  36. data/lib/adzerk_decision_sdk/models/decision_data.rb +242 -0
  37. data/lib/adzerk_decision_sdk/models/decision_request.rb +359 -0
  38. data/lib/adzerk_decision_sdk/models/decision_response.rb +224 -0
  39. data/lib/adzerk_decision_sdk/models/event.rb +215 -0
  40. data/lib/adzerk_decision_sdk/models/placement.rb +377 -0
  41. data/lib/adzerk_decision_sdk/models/pricing_data.rb +242 -0
  42. data/lib/adzerk_decision_sdk/models/user.rb +208 -0
  43. data/lib/adzerk_decision_sdk/pixel_client.rb +26 -0
  44. data/lib/adzerk_decision_sdk/rate_type.rb +8 -0
  45. data/lib/adzerk_decision_sdk/user_db_client.rb +64 -0
  46. data/lib/adzerk_decision_sdk/version.rb +15 -0
  47. data/lib/adzerk_decision_sdk.rb +58 -0
  48. data/pkg/adzerk_decision_sdk-1.0.0.gem +0 -0
  49. data/spec/.gitkeep +0 -0
  50. data/spec/placeholder_spec.rb +9 -0
  51. metadata +153 -0
@@ -0,0 +1,242 @@
1
+ =begin
2
+ #Adzerk Decision API
3
+
4
+ #Adzerk Decision API
5
+
6
+ The version of the OpenAPI document: 1.0
7
+
8
+ Generated by: https://openapi-generator.tech
9
+ OpenAPI Generator version: 4.2.3
10
+
11
+ =end
12
+
13
+ require 'date'
14
+
15
+ module AdzerkDecisionSdk
16
+ class DecisionData
17
+ attr_accessor :image_url
18
+
19
+ attr_accessor :title
20
+
21
+ attr_accessor :width
22
+
23
+ attr_accessor :height
24
+
25
+ attr_accessor :custom_data
26
+
27
+ # Attribute mapping from ruby-style variable name to JSON key.
28
+ def self.attribute_map
29
+ {
30
+ :'image_url' => :'imageURL',
31
+ :'title' => :'title',
32
+ :'width' => :'width',
33
+ :'height' => :'height',
34
+ :'custom_data' => :'customData'
35
+ }
36
+ end
37
+
38
+ # Attribute type mapping.
39
+ def self.openapi_types
40
+ {
41
+ :'image_url' => :'String',
42
+ :'title' => :'String',
43
+ :'width' => :'Integer',
44
+ :'height' => :'Integer',
45
+ :'custom_data' => :'Object'
46
+ }
47
+ end
48
+
49
+ # List of attributes with nullable: true
50
+ def self.openapi_nullable
51
+ Set.new([
52
+ ])
53
+ end
54
+
55
+ # Initializes the object
56
+ # @param [Hash] attributes Model attributes in the form of hash
57
+ def initialize(attributes = {})
58
+ if (!attributes.is_a?(Hash))
59
+ fail ArgumentError, "The input argument (attributes) must be a hash in `AdzerkDecisionSdk::DecisionData` initialize method"
60
+ end
61
+
62
+ # check to see if the attribute exists and convert string to symbol for hash key
63
+ attributes = attributes.each_with_object({}) { |(k, v), h|
64
+ if (!self.class.attribute_map.key?(k.to_sym))
65
+ fail ArgumentError, "`#{k}` is not a valid attribute in `AdzerkDecisionSdk::DecisionData`. Please check the name to make sure it's valid. List of attributes: " + self.class.attribute_map.keys.inspect
66
+ end
67
+ h[k.to_sym] = v
68
+ }
69
+
70
+ if attributes.key?(:'image_url')
71
+ self.image_url = attributes[:'image_url']
72
+ end
73
+
74
+ if attributes.key?(:'title')
75
+ self.title = attributes[:'title']
76
+ end
77
+
78
+ if attributes.key?(:'width')
79
+ self.width = attributes[:'width']
80
+ end
81
+
82
+ if attributes.key?(:'height')
83
+ self.height = attributes[:'height']
84
+ end
85
+
86
+ if attributes.key?(:'custom_data')
87
+ self.custom_data = attributes[:'custom_data']
88
+ end
89
+ end
90
+
91
+ # Show invalid properties with the reasons. Usually used together with valid?
92
+ # @return Array for valid properties with the reasons
93
+ def list_invalid_properties
94
+ invalid_properties = Array.new
95
+ invalid_properties
96
+ end
97
+
98
+ # Check to see if the all the properties in the model are valid
99
+ # @return true if the model is valid
100
+ def valid?
101
+ true
102
+ end
103
+
104
+ # Checks equality by comparing each attribute.
105
+ # @param [Object] Object to be compared
106
+ def ==(o)
107
+ return true if self.equal?(o)
108
+ self.class == o.class &&
109
+ image_url == o.image_url &&
110
+ title == o.title &&
111
+ width == o.width &&
112
+ height == o.height &&
113
+ custom_data == o.custom_data
114
+ end
115
+
116
+ # @see the `==` method
117
+ # @param [Object] Object to be compared
118
+ def eql?(o)
119
+ self == o
120
+ end
121
+
122
+ # Calculates hash code according to all attributes.
123
+ # @return [Integer] Hash code
124
+ def hash
125
+ [image_url, title, width, height, custom_data].hash
126
+ end
127
+
128
+ # Builds the object from hash
129
+ # @param [Hash] attributes Model attributes in the form of hash
130
+ # @return [Object] Returns the model itself
131
+ def self.build_from_hash(attributes)
132
+ new.build_from_hash(attributes)
133
+ end
134
+
135
+ # Builds the object from hash
136
+ # @param [Hash] attributes Model attributes in the form of hash
137
+ # @return [Object] Returns the model itself
138
+ def build_from_hash(attributes)
139
+ return nil unless attributes.is_a?(Hash)
140
+ self.class.openapi_types.each_pair do |key, type|
141
+ if type =~ /\AArray<(.*)>/i
142
+ # check to ensure the input is an array given that the attribute
143
+ # is documented as an array but the input is not
144
+ if attributes[self.class.attribute_map[key]].is_a?(Array)
145
+ self.send("#{key}=", attributes[self.class.attribute_map[key]].map { |v| _deserialize($1, v) })
146
+ end
147
+ elsif !attributes[self.class.attribute_map[key]].nil?
148
+ self.send("#{key}=", _deserialize(type, attributes[self.class.attribute_map[key]]))
149
+ end # or else data not found in attributes(hash), not an issue as the data can be optional
150
+ end
151
+
152
+ self
153
+ end
154
+
155
+ # Deserializes the data based on type
156
+ # @param string type Data type
157
+ # @param string value Value to be deserialized
158
+ # @return [Object] Deserialized data
159
+ def _deserialize(type, value)
160
+ case type.to_sym
161
+ when :DateTime
162
+ DateTime.parse(value)
163
+ when :Date
164
+ Date.parse(value)
165
+ when :String
166
+ value.to_s
167
+ when :Integer
168
+ value.to_i
169
+ when :Float
170
+ value.to_f
171
+ when :Boolean
172
+ if value.to_s =~ /\A(true|t|yes|y|1)\z/i
173
+ true
174
+ else
175
+ false
176
+ end
177
+ when :Object
178
+ # generic object (usually a Hash), return directly
179
+ value
180
+ when /\AArray<(?<inner_type>.+)>\z/
181
+ inner_type = Regexp.last_match[:inner_type]
182
+ value.map { |v| _deserialize(inner_type, v) }
183
+ when /\AHash<(?<k_type>.+?), (?<v_type>.+)>\z/
184
+ k_type = Regexp.last_match[:k_type]
185
+ v_type = Regexp.last_match[:v_type]
186
+ {}.tap do |hash|
187
+ value.each do |k, v|
188
+ hash[_deserialize(k_type, k)] = _deserialize(v_type, v)
189
+ end
190
+ end
191
+ else # model
192
+ AdzerkDecisionSdk.const_get(type).build_from_hash(value)
193
+ end
194
+ end
195
+
196
+ # Returns the string representation of the object
197
+ # @return [String] String presentation of the object
198
+ def to_s
199
+ to_hash.to_s
200
+ end
201
+
202
+ # to_body is an alias to to_hash (backward compatibility)
203
+ # @return [Hash] Returns the object in the form of hash
204
+ def to_body
205
+ to_hash
206
+ end
207
+
208
+ # Returns the object in the form of hash
209
+ # @return [Hash] Returns the object in the form of hash
210
+ def to_hash
211
+ hash = {}
212
+ self.class.attribute_map.each_pair do |attr, param|
213
+ value = self.send(attr)
214
+ if value.nil?
215
+ is_nullable = self.class.openapi_nullable.include?(attr)
216
+ next if !is_nullable || (is_nullable && !instance_variable_defined?(:"@#{attr}"))
217
+ end
218
+
219
+ hash[param] = _to_hash(value)
220
+ end
221
+ hash
222
+ end
223
+
224
+ # Outputs non-array value in the form of hash
225
+ # For object, use to_hash. Otherwise, just return the value
226
+ # @param [Object] value Any valid value
227
+ # @return [Hash] Returns the value in the form of hash
228
+ def _to_hash(value)
229
+ if value.is_a?(Array)
230
+ value.compact.map { |v| _to_hash(v) }
231
+ elsif value.is_a?(Hash)
232
+ {}.tap do |hash|
233
+ value.each { |k, v| hash[k] = _to_hash(v) }
234
+ end
235
+ elsif value.respond_to? :to_hash
236
+ value.to_hash
237
+ else
238
+ value
239
+ end
240
+ end
241
+ end
242
+ end
@@ -0,0 +1,359 @@
1
+ =begin
2
+ #Adzerk Decision API
3
+
4
+ #Adzerk Decision API
5
+
6
+ The version of the OpenAPI document: 1.0
7
+
8
+ Generated by: https://openapi-generator.tech
9
+ OpenAPI Generator version: 4.2.3
10
+
11
+ =end
12
+
13
+ require 'date'
14
+
15
+ module AdzerkDecisionSdk
16
+ class DecisionRequest
17
+ # One or more Placement objects
18
+ attr_accessor :placements
19
+
20
+ attr_accessor :user
21
+
22
+ # Keywords for keyword Targeting. Such as `\"keywords\": [\"foo\", \"bar\", \"baz\"]`.
23
+ attr_accessor :keywords
24
+
25
+ # The current page URL
26
+ attr_accessor :url
27
+
28
+ # The referrer URL
29
+ attr_accessor :referrer
30
+
31
+ # The IP address. Required for [Geo-Targeting](https://dev.adzerk.com/docs/geo-location)
32
+ attr_accessor :ip
33
+
34
+ # Numeric creative ids to disregard for ad selection
35
+ attr_accessor :blocked_creatives
36
+
37
+ # If true, only ads containing a single image will be returned
38
+ attr_accessor :is_mobile
39
+
40
+ # If true, return pricing data for the decision in the response
41
+ attr_accessor :include_pricing_data
42
+
43
+ # If true, only return ads that are set to honor Do Not Track
44
+ attr_accessor :notrack
45
+
46
+ # If making a client-side request, set to true. Defaults to false to ensure a server isn't seen as a bot. See [here](https://dev.adzerk.com/docs/tracking-overview#section-bot-filtering) for more info
47
+ attr_accessor :enable_bot_filtering
48
+
49
+ # If true, override the IP address of the request with the IP address supplied on the UserKey. If no IP address is found on the UserKey, this will fall back to the IP address on the request. Requires UserDB
50
+ attr_accessor :enable_user_dbip
51
+
52
+ # Object that sets the data consent preferences. Other consent settings are available in the GDPR settings documentation.
53
+ attr_accessor :consent
54
+
55
+ # RTB requests only - sets an Identifier for Advertisers (IFA or IDFA)
56
+ attr_accessor :device_id
57
+
58
+ # Attribute mapping from ruby-style variable name to JSON key.
59
+ def self.attribute_map
60
+ {
61
+ :'placements' => :'placements',
62
+ :'user' => :'user',
63
+ :'keywords' => :'keywords',
64
+ :'url' => :'url',
65
+ :'referrer' => :'referrer',
66
+ :'ip' => :'ip',
67
+ :'blocked_creatives' => :'blockedCreatives',
68
+ :'is_mobile' => :'isMobile',
69
+ :'include_pricing_data' => :'includePricingData',
70
+ :'notrack' => :'notrack',
71
+ :'enable_bot_filtering' => :'enableBotFiltering',
72
+ :'enable_user_dbip' => :'enableUserDBIP',
73
+ :'consent' => :'consent',
74
+ :'device_id' => :'deviceID'
75
+ }
76
+ end
77
+
78
+ # Attribute type mapping.
79
+ def self.openapi_types
80
+ {
81
+ :'placements' => :'Array<Placement>',
82
+ :'user' => :'User',
83
+ :'keywords' => :'Array<String>',
84
+ :'url' => :'String',
85
+ :'referrer' => :'String',
86
+ :'ip' => :'String',
87
+ :'blocked_creatives' => :'Array<Integer>',
88
+ :'is_mobile' => :'Boolean',
89
+ :'include_pricing_data' => :'Boolean',
90
+ :'notrack' => :'Boolean',
91
+ :'enable_bot_filtering' => :'Boolean',
92
+ :'enable_user_dbip' => :'Boolean',
93
+ :'consent' => :'Object',
94
+ :'device_id' => :'String'
95
+ }
96
+ end
97
+
98
+ # List of attributes with nullable: true
99
+ def self.openapi_nullable
100
+ Set.new([
101
+ :'keywords',
102
+ :'url',
103
+ :'referrer',
104
+ :'ip',
105
+ :'blocked_creatives',
106
+ :'is_mobile',
107
+ :'include_pricing_data',
108
+ :'notrack',
109
+ :'enable_bot_filtering',
110
+ :'enable_user_dbip',
111
+ :'consent',
112
+ :'device_id'
113
+ ])
114
+ end
115
+
116
+ # Initializes the object
117
+ # @param [Hash] attributes Model attributes in the form of hash
118
+ def initialize(attributes = {})
119
+ if (!attributes.is_a?(Hash))
120
+ fail ArgumentError, "The input argument (attributes) must be a hash in `AdzerkDecisionSdk::DecisionRequest` initialize method"
121
+ end
122
+
123
+ # check to see if the attribute exists and convert string to symbol for hash key
124
+ attributes = attributes.each_with_object({}) { |(k, v), h|
125
+ if (!self.class.attribute_map.key?(k.to_sym))
126
+ fail ArgumentError, "`#{k}` is not a valid attribute in `AdzerkDecisionSdk::DecisionRequest`. Please check the name to make sure it's valid. List of attributes: " + self.class.attribute_map.keys.inspect
127
+ end
128
+ h[k.to_sym] = v
129
+ }
130
+
131
+ if attributes.key?(:'placements')
132
+ if (value = attributes[:'placements']).is_a?(Array)
133
+ self.placements = value
134
+ end
135
+ end
136
+
137
+ if attributes.key?(:'user')
138
+ self.user = attributes[:'user']
139
+ end
140
+
141
+ if attributes.key?(:'keywords')
142
+ if (value = attributes[:'keywords']).is_a?(Array)
143
+ self.keywords = value
144
+ end
145
+ end
146
+
147
+ if attributes.key?(:'url')
148
+ self.url = attributes[:'url']
149
+ end
150
+
151
+ if attributes.key?(:'referrer')
152
+ self.referrer = attributes[:'referrer']
153
+ end
154
+
155
+ if attributes.key?(:'ip')
156
+ self.ip = attributes[:'ip']
157
+ end
158
+
159
+ if attributes.key?(:'blocked_creatives')
160
+ if (value = attributes[:'blocked_creatives']).is_a?(Array)
161
+ self.blocked_creatives = value
162
+ end
163
+ end
164
+
165
+ if attributes.key?(:'is_mobile')
166
+ self.is_mobile = attributes[:'is_mobile']
167
+ end
168
+
169
+ if attributes.key?(:'include_pricing_data')
170
+ self.include_pricing_data = attributes[:'include_pricing_data']
171
+ end
172
+
173
+ if attributes.key?(:'notrack')
174
+ self.notrack = attributes[:'notrack']
175
+ end
176
+
177
+ if attributes.key?(:'enable_bot_filtering')
178
+ self.enable_bot_filtering = attributes[:'enable_bot_filtering']
179
+ end
180
+
181
+ if attributes.key?(:'enable_user_dbip')
182
+ self.enable_user_dbip = attributes[:'enable_user_dbip']
183
+ end
184
+
185
+ if attributes.key?(:'consent')
186
+ self.consent = attributes[:'consent']
187
+ end
188
+
189
+ if attributes.key?(:'device_id')
190
+ self.device_id = attributes[:'device_id']
191
+ end
192
+ end
193
+
194
+ # Show invalid properties with the reasons. Usually used together with valid?
195
+ # @return Array for valid properties with the reasons
196
+ def list_invalid_properties
197
+ invalid_properties = Array.new
198
+ if @placements.nil?
199
+ invalid_properties.push('invalid value for "placements", placements cannot be nil.')
200
+ end
201
+
202
+ invalid_properties
203
+ end
204
+
205
+ # Check to see if the all the properties in the model are valid
206
+ # @return true if the model is valid
207
+ def valid?
208
+ return false if @placements.nil?
209
+ true
210
+ end
211
+
212
+ # Checks equality by comparing each attribute.
213
+ # @param [Object] Object to be compared
214
+ def ==(o)
215
+ return true if self.equal?(o)
216
+ self.class == o.class &&
217
+ placements == o.placements &&
218
+ user == o.user &&
219
+ keywords == o.keywords &&
220
+ url == o.url &&
221
+ referrer == o.referrer &&
222
+ ip == o.ip &&
223
+ blocked_creatives == o.blocked_creatives &&
224
+ is_mobile == o.is_mobile &&
225
+ include_pricing_data == o.include_pricing_data &&
226
+ notrack == o.notrack &&
227
+ enable_bot_filtering == o.enable_bot_filtering &&
228
+ enable_user_dbip == o.enable_user_dbip &&
229
+ consent == o.consent &&
230
+ device_id == o.device_id
231
+ end
232
+
233
+ # @see the `==` method
234
+ # @param [Object] Object to be compared
235
+ def eql?(o)
236
+ self == o
237
+ end
238
+
239
+ # Calculates hash code according to all attributes.
240
+ # @return [Integer] Hash code
241
+ def hash
242
+ [placements, user, keywords, url, referrer, ip, blocked_creatives, is_mobile, include_pricing_data, notrack, enable_bot_filtering, enable_user_dbip, consent, device_id].hash
243
+ end
244
+
245
+ # Builds the object from hash
246
+ # @param [Hash] attributes Model attributes in the form of hash
247
+ # @return [Object] Returns the model itself
248
+ def self.build_from_hash(attributes)
249
+ new.build_from_hash(attributes)
250
+ end
251
+
252
+ # Builds the object from hash
253
+ # @param [Hash] attributes Model attributes in the form of hash
254
+ # @return [Object] Returns the model itself
255
+ def build_from_hash(attributes)
256
+ return nil unless attributes.is_a?(Hash)
257
+ self.class.openapi_types.each_pair do |key, type|
258
+ if type =~ /\AArray<(.*)>/i
259
+ # check to ensure the input is an array given that the attribute
260
+ # is documented as an array but the input is not
261
+ if attributes[self.class.attribute_map[key]].is_a?(Array)
262
+ self.send("#{key}=", attributes[self.class.attribute_map[key]].map { |v| _deserialize($1, v) })
263
+ end
264
+ elsif !attributes[self.class.attribute_map[key]].nil?
265
+ self.send("#{key}=", _deserialize(type, attributes[self.class.attribute_map[key]]))
266
+ end # or else data not found in attributes(hash), not an issue as the data can be optional
267
+ end
268
+
269
+ self
270
+ end
271
+
272
+ # Deserializes the data based on type
273
+ # @param string type Data type
274
+ # @param string value Value to be deserialized
275
+ # @return [Object] Deserialized data
276
+ def _deserialize(type, value)
277
+ case type.to_sym
278
+ when :DateTime
279
+ DateTime.parse(value)
280
+ when :Date
281
+ Date.parse(value)
282
+ when :String
283
+ value.to_s
284
+ when :Integer
285
+ value.to_i
286
+ when :Float
287
+ value.to_f
288
+ when :Boolean
289
+ if value.to_s =~ /\A(true|t|yes|y|1)\z/i
290
+ true
291
+ else
292
+ false
293
+ end
294
+ when :Object
295
+ # generic object (usually a Hash), return directly
296
+ value
297
+ when /\AArray<(?<inner_type>.+)>\z/
298
+ inner_type = Regexp.last_match[:inner_type]
299
+ value.map { |v| _deserialize(inner_type, v) }
300
+ when /\AHash<(?<k_type>.+?), (?<v_type>.+)>\z/
301
+ k_type = Regexp.last_match[:k_type]
302
+ v_type = Regexp.last_match[:v_type]
303
+ {}.tap do |hash|
304
+ value.each do |k, v|
305
+ hash[_deserialize(k_type, k)] = _deserialize(v_type, v)
306
+ end
307
+ end
308
+ else # model
309
+ AdzerkDecisionSdk.const_get(type).build_from_hash(value)
310
+ end
311
+ end
312
+
313
+ # Returns the string representation of the object
314
+ # @return [String] String presentation of the object
315
+ def to_s
316
+ to_hash.to_s
317
+ end
318
+
319
+ # to_body is an alias to to_hash (backward compatibility)
320
+ # @return [Hash] Returns the object in the form of hash
321
+ def to_body
322
+ to_hash
323
+ end
324
+
325
+ # Returns the object in the form of hash
326
+ # @return [Hash] Returns the object in the form of hash
327
+ def to_hash
328
+ hash = {}
329
+ self.class.attribute_map.each_pair do |attr, param|
330
+ value = self.send(attr)
331
+ if value.nil?
332
+ is_nullable = self.class.openapi_nullable.include?(attr)
333
+ next if !is_nullable || (is_nullable && !instance_variable_defined?(:"@#{attr}"))
334
+ end
335
+
336
+ hash[param] = _to_hash(value)
337
+ end
338
+ hash
339
+ end
340
+
341
+ # Outputs non-array value in the form of hash
342
+ # For object, use to_hash. Otherwise, just return the value
343
+ # @param [Object] value Any valid value
344
+ # @return [Hash] Returns the value in the form of hash
345
+ def _to_hash(value)
346
+ if value.is_a?(Array)
347
+ value.compact.map { |v| _to_hash(v) }
348
+ elsif value.is_a?(Hash)
349
+ {}.tap do |hash|
350
+ value.each { |k, v| hash[k] = _to_hash(v) }
351
+ end
352
+ elsif value.respond_to? :to_hash
353
+ value.to_hash
354
+ else
355
+ value
356
+ end
357
+ end
358
+ end
359
+ end