qpid_proton 0.0.1 → 0.3
Sign up to get free protection for your applications and to get access to all the features.
- data/ChangeLog +9 -0
- data/LICENSE +203 -0
- data/TODO +14 -0
- data/ext/cproton/cproton.c +9872 -1995
- data/lib/qpid_proton.rb +8 -2
- data/lib/qpid_proton/exception_handling.rb +69 -0
- data/lib/qpid_proton/exceptions.rb +69 -0
- data/lib/qpid_proton/message.rb +434 -0
- data/lib/qpid_proton/message_format.rb +75 -0
- data/lib/qpid_proton/messenger.rb +399 -0
- data/lib/qpid_proton/{version.rb → subscription.rb} +14 -2
- data/lib/qpid_proton/tracker.rb +46 -0
- data/lib/qpid_proton/tracker_status.rb +72 -0
- metadata +18 -9
data/lib/qpid_proton.rb
CHANGED
@@ -19,5 +19,11 @@
|
|
19
19
|
|
20
20
|
require "cproton"
|
21
21
|
|
22
|
-
require "qpid_proton/
|
23
|
-
|
22
|
+
require "qpid_proton/exceptions"
|
23
|
+
require "qpid_proton/exception_handling"
|
24
|
+
require "qpid_proton/message_format"
|
25
|
+
require "qpid_proton/message"
|
26
|
+
require "qpid_proton/subscription"
|
27
|
+
require "qpid_proton/tracker_status"
|
28
|
+
require "qpid_proton/tracker"
|
29
|
+
require "qpid_proton/messenger"
|
@@ -0,0 +1,69 @@
|
|
1
|
+
#
|
2
|
+
# Licensed to the Apache Software Foundation (ASF) under one
|
3
|
+
# or more contributor license agreements. See the NOTICE file
|
4
|
+
# distributed with this work for additional information
|
5
|
+
# regarding copyright ownership. The ASF licenses this file
|
6
|
+
# to you under the Apache License, Version 2.0 (the
|
7
|
+
# "License"); you may not use this file except in compliance
|
8
|
+
# with the License. You may obtain a copy of the License at
|
9
|
+
#
|
10
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
11
|
+
#
|
12
|
+
# Unless required by applicable law or agreed to in writing,
|
13
|
+
# software distributed under the License is distributed on an
|
14
|
+
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
15
|
+
# KIND, either express or implied. See the License for the
|
16
|
+
# specific language governing permissions and limitations
|
17
|
+
# under the License.
|
18
|
+
#
|
19
|
+
|
20
|
+
module Qpid
|
21
|
+
|
22
|
+
module Proton
|
23
|
+
|
24
|
+
# Provides mixin functionality for dealing with exception conditions.
|
25
|
+
#
|
26
|
+
module ExceptionHandling
|
27
|
+
|
28
|
+
# Raises an Proton-specific error if a return code is non-zero.
|
29
|
+
#
|
30
|
+
# Expects the class to provide an +error+ method.
|
31
|
+
def check_for_error(code)
|
32
|
+
raise ::ArgumentError.new("Invalid error code: #{code}") if code.nil?
|
33
|
+
|
34
|
+
case(code)
|
35
|
+
|
36
|
+
when Qpid::Proton::Error::NONE
|
37
|
+
return
|
38
|
+
|
39
|
+
when Qpid::Proton::Error::EOS
|
40
|
+
raise Qpid::Proton::EOSError.new(self.error)
|
41
|
+
|
42
|
+
when Qpid::Proton::Error::ERROR
|
43
|
+
raise Qpid::Proton::ProtonError.new(self.error)
|
44
|
+
|
45
|
+
when Qpid::Proton::Error::OVERFLOW
|
46
|
+
raise Qpid::Proton::OverflowError.new(self.error)
|
47
|
+
|
48
|
+
when Qpid::Proton::Error::UNDERFLOW
|
49
|
+
raise Qpid::Proton::UnderflowError.new(self.error)
|
50
|
+
|
51
|
+
when Qpid::Proton::Error::ARGUMENT
|
52
|
+
raise Qpid::Proton::ArgumentError.new(self.error)
|
53
|
+
|
54
|
+
when Qpid::Proton::Error::TIMEOUT
|
55
|
+
raise Qpid::Proton::TimeoutError.new(self.error)
|
56
|
+
|
57
|
+
else
|
58
|
+
|
59
|
+
raise ::ArgumentError.new("Unknown error code: #{code}")
|
60
|
+
|
61
|
+
end
|
62
|
+
|
63
|
+
end
|
64
|
+
|
65
|
+
end
|
66
|
+
|
67
|
+
end
|
68
|
+
|
69
|
+
end
|
@@ -0,0 +1,69 @@
|
|
1
|
+
#
|
2
|
+
# Licensed to the Apache Software Foundation (ASF) under one
|
3
|
+
# or more contributor license agreements. See the NOTICE file
|
4
|
+
# distributed with this work for additional information
|
5
|
+
# regarding copyright ownership. The ASF licenses this file
|
6
|
+
# to you under the Apache License, Version 2.0 (the
|
7
|
+
# "License"); you may not use this file except in compliance
|
8
|
+
# with the License. You may obtain a copy of the License at
|
9
|
+
#
|
10
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
11
|
+
#
|
12
|
+
# Unless required by applicable law or agreed to in writing,
|
13
|
+
# software distributed under the License is distributed on an
|
14
|
+
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
15
|
+
# KIND, either express or implied. See the License for the
|
16
|
+
# specific language governing permissions and limitations
|
17
|
+
# under the License.
|
18
|
+
#
|
19
|
+
|
20
|
+
module Qpid
|
21
|
+
|
22
|
+
module Proton
|
23
|
+
|
24
|
+
module Error
|
25
|
+
|
26
|
+
NONE = 0
|
27
|
+
EOS = Cproton::PN_EOS
|
28
|
+
ERROR = Cproton::PN_ERR
|
29
|
+
OVERFLOW = Cproton::PN_OVERFLOW
|
30
|
+
UNDERFLOW = Cproton::PN_UNDERFLOW
|
31
|
+
STATE = Cproton::PN_STATE_ERR
|
32
|
+
ARGUMENT = Cproton::PN_ARG_ERR
|
33
|
+
TIMEOUT = Cproton::PN_TIMEOUT
|
34
|
+
|
35
|
+
end
|
36
|
+
|
37
|
+
# Represents a generic error at the messaging level.
|
38
|
+
#
|
39
|
+
class ProtonError < RuntimeError
|
40
|
+
end
|
41
|
+
|
42
|
+
# Represents an end-of-stream error while messaging.
|
43
|
+
#
|
44
|
+
class EOSError < ProtonError
|
45
|
+
end
|
46
|
+
|
47
|
+
# Represents a data overflow exception while messaging.
|
48
|
+
#
|
49
|
+
class OverflowError < ProtonError
|
50
|
+
end
|
51
|
+
|
52
|
+
# Represents a data underflow exception while messaging.
|
53
|
+
#
|
54
|
+
class UnderflowError < ProtonError
|
55
|
+
end
|
56
|
+
|
57
|
+
# Represents an invalid, missing or illegal argument while messaging.
|
58
|
+
#
|
59
|
+
class ArgumentError < ProtonError
|
60
|
+
end
|
61
|
+
|
62
|
+
# Represents a timeout during messaging.
|
63
|
+
#
|
64
|
+
class TimeoutError < ProtonError
|
65
|
+
end
|
66
|
+
|
67
|
+
end
|
68
|
+
|
69
|
+
end
|
@@ -0,0 +1,434 @@
|
|
1
|
+
#
|
2
|
+
# Licensed to the Apache Software Foundation (ASF) under one
|
3
|
+
# or more contributor license agreements. See the NOTICE file
|
4
|
+
# distributed with this work for additional information
|
5
|
+
# regarding copyright ownership. The ASF licenses this file
|
6
|
+
# to you under the Apache License, Version 2.0 (the
|
7
|
+
# "License"); you may not use this file except in compliance
|
8
|
+
# with the License. You may obtain a copy of the License at
|
9
|
+
#
|
10
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
11
|
+
#
|
12
|
+
# Unless required by applicable law or agreed to in writing,
|
13
|
+
# software distributed under the License is distributed on an
|
14
|
+
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
15
|
+
# KIND, either express or implied. See the License for the
|
16
|
+
# specific language governing permissions and limitations
|
17
|
+
# under the License.
|
18
|
+
#
|
19
|
+
|
20
|
+
module Qpid
|
21
|
+
|
22
|
+
module Proton
|
23
|
+
|
24
|
+
# A Message represents an addressable quantity of data.
|
25
|
+
#
|
26
|
+
# ==== Examples
|
27
|
+
#
|
28
|
+
class Message
|
29
|
+
|
30
|
+
# Creates a new +Message+ instance.
|
31
|
+
def initialize
|
32
|
+
@impl = Cproton.pn_message
|
33
|
+
ObjectSpace.define_finalizer(self, self.class.finalize!(@impl))
|
34
|
+
end
|
35
|
+
|
36
|
+
# Invoked by garbage collection to clean up resources used
|
37
|
+
# by the underlying message implementation.
|
38
|
+
def self.finalize!(impl) # :nodoc:
|
39
|
+
proc {
|
40
|
+
Cproton.pn_message_free(impl)
|
41
|
+
}
|
42
|
+
end
|
43
|
+
|
44
|
+
# Returns the underlying message implementation.
|
45
|
+
def impl # :nodoc:
|
46
|
+
@impl
|
47
|
+
end
|
48
|
+
|
49
|
+
# Clears the state of the +Message+. This allows a single instance of
|
50
|
+
# +Message+ to be reused.
|
51
|
+
#
|
52
|
+
def clear
|
53
|
+
Cproton.pn_message_clear(@impl)
|
54
|
+
end
|
55
|
+
|
56
|
+
# Returns the most recent error number.
|
57
|
+
#
|
58
|
+
def errno
|
59
|
+
Cproton.pn_message_errno(@impl)
|
60
|
+
end
|
61
|
+
|
62
|
+
# Returns the most recent error message.
|
63
|
+
#
|
64
|
+
def error
|
65
|
+
Cproton.pn_message_error(@impl)
|
66
|
+
end
|
67
|
+
|
68
|
+
# Returns whether there is currently an error reported.
|
69
|
+
#
|
70
|
+
def error?
|
71
|
+
!Cproton.pn_message_errno(@impl).zero?
|
72
|
+
end
|
73
|
+
|
74
|
+
# Sets the durable flag.
|
75
|
+
#
|
76
|
+
# See ::durable for more details on message durability.
|
77
|
+
#
|
78
|
+
# ==== Options
|
79
|
+
#
|
80
|
+
# * state - the durable state
|
81
|
+
#
|
82
|
+
def durable=(state)
|
83
|
+
raise TypeError.new("state cannot be nil") if state.nil?
|
84
|
+
Cproton.pn_message_set_durable(@impl, state)
|
85
|
+
end
|
86
|
+
|
87
|
+
# Returns the durable property.
|
88
|
+
#
|
89
|
+
# The durable property indicates that the emessage should be held durably
|
90
|
+
# by any intermediaries taking responsibility for the message.
|
91
|
+
#
|
92
|
+
# ==== Examples
|
93
|
+
#
|
94
|
+
# msg = Qpid::Proton::Message.new
|
95
|
+
# msg.durable = true
|
96
|
+
#
|
97
|
+
def durable
|
98
|
+
Cproton.pn_message_is_durable(@impl)
|
99
|
+
end
|
100
|
+
|
101
|
+
# Sets the priority.
|
102
|
+
#
|
103
|
+
# +NOTE:+ Priority values are limited to the range [0,255].
|
104
|
+
#
|
105
|
+
# ==== Options
|
106
|
+
#
|
107
|
+
# * priority - the priority value
|
108
|
+
#
|
109
|
+
def priority=(priority)
|
110
|
+
raise TypeError.new("invalid priority: #{priority}") if priority.nil? || !([Float, Fixnum].include?(priority.class))
|
111
|
+
raise RangeError.new("priority out of range: #{priority}") if ((priority > 255) || (priority < 0))
|
112
|
+
Cproton.pn_message_set_priority(@impl, priority.floor)
|
113
|
+
end
|
114
|
+
|
115
|
+
# Returns the priority.
|
116
|
+
#
|
117
|
+
def priority
|
118
|
+
Cproton.pn_message_get_priority(@impl)
|
119
|
+
end
|
120
|
+
|
121
|
+
# Sets the time-to-live for the message.
|
122
|
+
#
|
123
|
+
# ==== Options
|
124
|
+
#
|
125
|
+
# * time - the time in milliseconds
|
126
|
+
#
|
127
|
+
def ttl=(time)
|
128
|
+
raise TypeError.new("invalid ttl: #{time}") if time.nil? || !([Float, Fixnum].include?(time.class))
|
129
|
+
raise RangeError.new("time out of range: #{time}") if ((time < 0))
|
130
|
+
Cproton.pn_message_set_ttl(@impl, time.floor)
|
131
|
+
end
|
132
|
+
|
133
|
+
# Returns the time-to-live, in milliseconds.
|
134
|
+
#
|
135
|
+
def ttl
|
136
|
+
Cproton.pn_message_get_ttl(@impl)
|
137
|
+
end
|
138
|
+
|
139
|
+
# Sets whether this is the first time the message was acquired.
|
140
|
+
#
|
141
|
+
# See ::first_acquirer? for more details.
|
142
|
+
#
|
143
|
+
# ==== Options
|
144
|
+
#
|
145
|
+
# * state - true if claiming the message
|
146
|
+
#
|
147
|
+
def first_acquirer=(state)
|
148
|
+
raise TypeError.new("invalid state: #{state}") if state.nil? || !([TrueClass, FalseClass].include?(state.class))
|
149
|
+
Cproton.pn_message_set_first_acquirer(@impl, state)
|
150
|
+
end
|
151
|
+
|
152
|
+
# Sets the delivery count for the message.
|
153
|
+
#
|
154
|
+
# See ::delivery_count for more details.
|
155
|
+
#
|
156
|
+
# ==== Options
|
157
|
+
#
|
158
|
+
# * count - the delivery count
|
159
|
+
#
|
160
|
+
def delivery_count=(count)
|
161
|
+
raise ArgumentError.new("invalid count: #{count}") if count.nil? || !([Float, Fixnum].include?(count.class))
|
162
|
+
raise RangeError.new("count out of range: #{count}") if count < 0
|
163
|
+
|
164
|
+
Cproton.pn_message_set_delivery_count(@impl, count.floor)
|
165
|
+
end
|
166
|
+
|
167
|
+
# Returns the delivery count for the message.
|
168
|
+
#
|
169
|
+
# This is the number of delivery attempts for the given message.
|
170
|
+
#
|
171
|
+
def delivery_count
|
172
|
+
Cproton.pn_message_get_delivery_count(@impl)
|
173
|
+
end
|
174
|
+
|
175
|
+
# Returns whether this is the first acquirer.
|
176
|
+
#
|
177
|
+
#
|
178
|
+
def first_acquirer?
|
179
|
+
Cproton.pn_message_is_first_acquirer(@impl)
|
180
|
+
end
|
181
|
+
|
182
|
+
# Sets the message id.
|
183
|
+
#
|
184
|
+
# ==== Options
|
185
|
+
#
|
186
|
+
# * id = the id
|
187
|
+
#
|
188
|
+
def id=(id)
|
189
|
+
Cproton.pn_message_set_id(@impl, id)
|
190
|
+
end
|
191
|
+
|
192
|
+
# Returns the message id.
|
193
|
+
#
|
194
|
+
def id
|
195
|
+
Cproton.pn_message_get_id(@impl)
|
196
|
+
end
|
197
|
+
|
198
|
+
# Sets the user id.
|
199
|
+
#
|
200
|
+
# ==== Options
|
201
|
+
#
|
202
|
+
# * id - the user id
|
203
|
+
#
|
204
|
+
def user_id=(id)
|
205
|
+
Cproton.pn_message_set_user_id(@impl, id)
|
206
|
+
end
|
207
|
+
|
208
|
+
# Returns the user id.
|
209
|
+
#
|
210
|
+
def user_id
|
211
|
+
Cproton.pn_message_get_user_id(@impl)
|
212
|
+
end
|
213
|
+
|
214
|
+
# Sets the destination address.
|
215
|
+
#
|
216
|
+
# ==== Options
|
217
|
+
#
|
218
|
+
# * address - the address
|
219
|
+
#
|
220
|
+
def address=(address)
|
221
|
+
Cproton.pn_message_set_address(@impl, address)
|
222
|
+
end
|
223
|
+
|
224
|
+
# Returns the destination address.
|
225
|
+
#
|
226
|
+
def address
|
227
|
+
Cproton.pn_message_get_address(@impl)
|
228
|
+
end
|
229
|
+
|
230
|
+
# Sets the subject.
|
231
|
+
#
|
232
|
+
# ==== Options
|
233
|
+
#
|
234
|
+
# * subject - the subject
|
235
|
+
#
|
236
|
+
def subject=(subject)
|
237
|
+
Cproton.pn_message_set_subject(@impl, subject)
|
238
|
+
end
|
239
|
+
|
240
|
+
# Returns the subject
|
241
|
+
#
|
242
|
+
def subject
|
243
|
+
Cproton.pn_message_get_subject(@impl)
|
244
|
+
end
|
245
|
+
|
246
|
+
# Sets the reply-to address.
|
247
|
+
#
|
248
|
+
# ==== Options
|
249
|
+
#
|
250
|
+
# * address - the reply-to address
|
251
|
+
#
|
252
|
+
def reply_to=(address)
|
253
|
+
Cproton.pn_message_set_reply_to(@impl, address)
|
254
|
+
end
|
255
|
+
|
256
|
+
# Returns the reply-to address
|
257
|
+
#
|
258
|
+
def reply_to
|
259
|
+
Cproton.pn_message_get_reply_to(@impl)
|
260
|
+
end
|
261
|
+
|
262
|
+
# Sets the correlation id.
|
263
|
+
#
|
264
|
+
# ==== Options
|
265
|
+
#
|
266
|
+
# * id - the correlation id
|
267
|
+
#
|
268
|
+
def correlation_id=(id)
|
269
|
+
Cproton.pn_message_set_correlation_id(@impl, id)
|
270
|
+
end
|
271
|
+
|
272
|
+
# Returns the correlation id.
|
273
|
+
#
|
274
|
+
def correlation_id
|
275
|
+
Cproton.pn_message_get_correlation_id(@impl)
|
276
|
+
end
|
277
|
+
|
278
|
+
# Sets the message format.
|
279
|
+
#
|
280
|
+
# See MessageFormat for more details on formats.
|
281
|
+
#
|
282
|
+
# ==== Options
|
283
|
+
#
|
284
|
+
# * format - the format
|
285
|
+
#
|
286
|
+
def format=(format)
|
287
|
+
raise TypeError.new("invalid message format: #{format}") if (format.nil? || !format.kind_of?(Qpid::Proton::MessageFormat))
|
288
|
+
Cproton.pn_message_set_format(@impl, format.value)
|
289
|
+
end
|
290
|
+
|
291
|
+
# Returns the message format
|
292
|
+
#
|
293
|
+
def format
|
294
|
+
Qpid::Proton::MessageFormat.by_value(Cproton.pn_message_get_format(@impl))
|
295
|
+
end
|
296
|
+
|
297
|
+
# Sets the content type.
|
298
|
+
#
|
299
|
+
# ==== Options
|
300
|
+
#
|
301
|
+
# * content_type - the content type
|
302
|
+
#
|
303
|
+
def content_type=(content_type)
|
304
|
+
Cproton.pn_message_set_content_type(@impl, content_type)
|
305
|
+
end
|
306
|
+
|
307
|
+
# Returns the content type
|
308
|
+
#
|
309
|
+
def content_type
|
310
|
+
Cproton.pn_message_get_content_type(@impl)
|
311
|
+
end
|
312
|
+
|
313
|
+
# Sets the message content.
|
314
|
+
#
|
315
|
+
# ==== Options
|
316
|
+
#
|
317
|
+
# * content - the content
|
318
|
+
#
|
319
|
+
def content=(content)
|
320
|
+
Cproton.pn_message_load(@impl, content)
|
321
|
+
end
|
322
|
+
|
323
|
+
# Returns the message content.
|
324
|
+
#
|
325
|
+
def content
|
326
|
+
Cproton.pn_message_save(@impl, 1024)[1]
|
327
|
+
end
|
328
|
+
|
329
|
+
# Sets the content encoding type.
|
330
|
+
#
|
331
|
+
# ==== Options
|
332
|
+
#
|
333
|
+
# * encoding - the content encoding
|
334
|
+
#
|
335
|
+
def content_encoding=(encoding)
|
336
|
+
Cproton.pn_message_set_content_encoding(@impl, encoding)
|
337
|
+
end
|
338
|
+
|
339
|
+
# Returns the content encoding type.
|
340
|
+
#
|
341
|
+
def content_encoding
|
342
|
+
Cproton.pn_message_get_content_encoding(@impl)
|
343
|
+
end
|
344
|
+
|
345
|
+
# Sets the expiration time.
|
346
|
+
#
|
347
|
+
# ==== Options
|
348
|
+
#
|
349
|
+
# * time - the expiry time
|
350
|
+
#
|
351
|
+
def expires=(time)
|
352
|
+
raise TypeError.new("invalid expiry time: #{time}") if time.nil?
|
353
|
+
raise ArgumentError.new("expiry time cannot be negative: #{time}") if time < 0
|
354
|
+
Cproton.pn_message_set_expiry_time(@impl, time)
|
355
|
+
end
|
356
|
+
|
357
|
+
# Returns the expiration time.
|
358
|
+
#
|
359
|
+
def expires
|
360
|
+
Cproton.pn_message_get_expiry_time(@impl)
|
361
|
+
end
|
362
|
+
|
363
|
+
# Sets the creation time.
|
364
|
+
#
|
365
|
+
# ==== Options
|
366
|
+
#
|
367
|
+
# * time - the creation time
|
368
|
+
#
|
369
|
+
def creation_time=(time)
|
370
|
+
raise TypeError.new("invalid time: #{time}") if time.nil?
|
371
|
+
raise ArgumentError.new("time cannot be negative") if time < 0
|
372
|
+
Cproton.pn_message_set_creation_time(@impl, time)
|
373
|
+
end
|
374
|
+
|
375
|
+
# Returns the creation time.
|
376
|
+
#
|
377
|
+
def creation_time
|
378
|
+
Cproton.pn_message_get_creation_time(@impl)
|
379
|
+
end
|
380
|
+
|
381
|
+
# Sets the group id.
|
382
|
+
#
|
383
|
+
# ==== Options
|
384
|
+
#
|
385
|
+
# * id - the group id
|
386
|
+
#
|
387
|
+
def group_id=(id)
|
388
|
+
Cproton.pn_message_set_group_id(@impl, id)
|
389
|
+
end
|
390
|
+
|
391
|
+
# Returns the group id.
|
392
|
+
#
|
393
|
+
def group_id
|
394
|
+
Cproton.pn_message_get_group_id(@impl)
|
395
|
+
end
|
396
|
+
|
397
|
+
# Sets the group sequence number.
|
398
|
+
#
|
399
|
+
# ==== Options
|
400
|
+
#
|
401
|
+
# * seq - the sequence number
|
402
|
+
#
|
403
|
+
def group_sequence=(seq)
|
404
|
+
raise TypeError.new("invalid seq: #{seq}") if seq.nil?
|
405
|
+
Cproton.pn_message_set_group_sequence(@impl, seq)
|
406
|
+
end
|
407
|
+
|
408
|
+
# Returns the group sequence number.
|
409
|
+
#
|
410
|
+
def group_sequence
|
411
|
+
Cproton.pn_message_get_group_sequence(@impl)
|
412
|
+
end
|
413
|
+
|
414
|
+
# Sets the reply-to group id.
|
415
|
+
#
|
416
|
+
# ==== Options
|
417
|
+
#
|
418
|
+
# * id - the id
|
419
|
+
#
|
420
|
+
def reply_to_group_id=(id)
|
421
|
+
Cproton.pn_message_set_reply_to_group_id(@impl, id)
|
422
|
+
end
|
423
|
+
|
424
|
+
# Returns the reply-to group id.
|
425
|
+
#
|
426
|
+
def reply_to_group_id
|
427
|
+
Cproton.pn_message_get_reply_to_group_id(@impl)
|
428
|
+
end
|
429
|
+
|
430
|
+
end
|
431
|
+
|
432
|
+
end
|
433
|
+
|
434
|
+
end
|