ruby-aaws 0.4.1
Sign up to get free protection for your applications and to get access to all the features.
- data/COPYING +340 -0
- data/NEWS +304 -0
- data/README +558 -0
- data/README.rdoc +136 -0
- data/example/browse_node_lookup1 +46 -0
- data/example/customer_content_lookup1 +27 -0
- data/example/customer_content_search1 +21 -0
- data/example/example1 +87 -0
- data/example/help1 +25 -0
- data/example/item_lookup1 +55 -0
- data/example/item_lookup2 +55 -0
- data/example/item_search1 +30 -0
- data/example/item_search2 +37 -0
- data/example/item_search3 +23 -0
- data/example/list_lookup1 +29 -0
- data/example/list_search1 +30 -0
- data/example/multiple_operation1 +67 -0
- data/example/seller_listing_lookup1 +30 -0
- data/example/seller_listing_search1 +28 -0
- data/example/seller_lookup1 +45 -0
- data/example/shopping_cart1 +42 -0
- data/example/similarity_lookup1 +48 -0
- data/example/tag_lookup1 +34 -0
- data/example/transaction_lookup1 +26 -0
- data/lib/amazon/aws/cache.rb +141 -0
- data/lib/amazon/aws/search.rb +317 -0
- data/lib/amazon/aws/shoppingcart.rb +504 -0
- data/lib/amazon/aws.rb +1156 -0
- data/lib/amazon/locale.rb +102 -0
- data/lib/amazon.rb +99 -0
- data/test/setup.rb +31 -0
- data/test/tc_amazon.rb +20 -0
- data/test/tc_aws.rb +118 -0
- data/test/tc_item_search.rb +21 -0
- data/test/tc_multiple_operation.rb +58 -0
- data/test/tc_operation_request.rb +58 -0
- data/test/tc_serialisation.rb +103 -0
- data/test/tc_shopping_cart.rb +214 -0
- data/test/ts_aws.rb +12 -0
- metadata +95 -0
@@ -0,0 +1,504 @@
|
|
1
|
+
# $Id: shoppingcart.rb,v 1.17 2008/07/13 01:56:43 ianmacd Exp $
|
2
|
+
#
|
3
|
+
|
4
|
+
require 'amazon/aws/search'
|
5
|
+
|
6
|
+
module Amazon
|
7
|
+
|
8
|
+
module AWS
|
9
|
+
|
10
|
+
# Load this library with:
|
11
|
+
#
|
12
|
+
# require 'amazon/aws/shoppingcart'
|
13
|
+
#
|
14
|
+
module ShoppingCart
|
15
|
+
|
16
|
+
# Attempts to remove non-existent items from a shopping-cart will raise
|
17
|
+
# this exception.
|
18
|
+
#
|
19
|
+
class CartError < StandardError; end
|
20
|
+
|
21
|
+
class Cart < Amazon::AWS::Search::Request
|
22
|
+
|
23
|
+
# _cart_id_ is an alphanumeric token that uniquely identifies a
|
24
|
+
# remote shopping-cart. _hmac_ is a <b>H</b>ash <b>M</b>essage
|
25
|
+
# <b>A</b>uthentication <b>C</b>ode. This is an encrypted alphanumeric
|
26
|
+
# token used to authenticate requests. _purchase_url_ is the URL to
|
27
|
+
# follow in order to complete the purchase of the items in the
|
28
|
+
# shopping-cart. _cart_items_ is an Array of items in the active area
|
29
|
+
# of the cart and _saved_for_later_items_ is an Array of items in the
|
30
|
+
# <i>Save For Later</i> area of the cart.
|
31
|
+
#
|
32
|
+
attr_reader :cart_id, :hmac, :purchase_url, :cart_items,
|
33
|
+
:saved_for_later_items
|
34
|
+
alias :items :cart_items
|
35
|
+
alias :saved_items :saved_for_later_items
|
36
|
+
alias :saved :saved_for_later_items
|
37
|
+
|
38
|
+
|
39
|
+
# Create a new instance of a remote shopping-cart. See
|
40
|
+
# Amazon::AWS::Search::Request.new for details of the parameters.
|
41
|
+
#
|
42
|
+
# Example:
|
43
|
+
#
|
44
|
+
# cart = Cart.new
|
45
|
+
#
|
46
|
+
def initialize(key_id=nil, associate=nil, locale=nil,
|
47
|
+
user_agent=USER_AGENT)
|
48
|
+
|
49
|
+
@cart_items = []
|
50
|
+
@saved_for_later_items = []
|
51
|
+
|
52
|
+
# Note the *false* as the fourth parameter to _super_, because we
|
53
|
+
# never want to cache shopping-cart transactions.
|
54
|
+
#
|
55
|
+
super( key_id, associate, locale, false, user_agent )
|
56
|
+
end
|
57
|
+
|
58
|
+
|
59
|
+
# Prepare the remote shopping-cart for use and place one or more items
|
60
|
+
# in it.
|
61
|
+
#
|
62
|
+
# _id_type_ is a String, either *ASIN* or *OfferListingId*. _item_id_
|
63
|
+
# is the actual ASIN or offer listing ID in question, _quantity_ is
|
64
|
+
# the quantity of the item to add to the cart, and _merge_cart_ is
|
65
|
+
# whether or not the remote shopping-cart should be merged with the
|
66
|
+
# local cart on the Amazon retail site upon check-out.
|
67
|
+
#
|
68
|
+
# _more_items_ is an optional list of Hash objects describing
|
69
|
+
# additional items to place in the cart.
|
70
|
+
#
|
71
|
+
# Example:
|
72
|
+
#
|
73
|
+
# cart.cart_create( :ASIN, 'B00151HZA6', 1,
|
74
|
+
# { 'B000WC4AH0' => 2 },
|
75
|
+
# { 'B000PY32OM' => 3 } )
|
76
|
+
#
|
77
|
+
# or:
|
78
|
+
#
|
79
|
+
# cart.cart_create( :ASIN, 'B00151HZA6', 1,
|
80
|
+
# { 'B000WC4AH0' => 2,
|
81
|
+
# 'B000PY32OM' => 3 } )
|
82
|
+
#
|
83
|
+
# Please note that it's not yet possible to update a wishlist at
|
84
|
+
# purchase time by referring to the item's *ListItemId* when adding
|
85
|
+
# that item to the cart.
|
86
|
+
#
|
87
|
+
def cart_create(id_type, item_id, quantity=1, merge_cart=false,
|
88
|
+
*more_items)
|
89
|
+
cc = CartCreate.new( id_type, item_id, quantity, merge_cart, nil,
|
90
|
+
*more_items )
|
91
|
+
|
92
|
+
@rg = ResponseGroup.new( 'Cart' )
|
93
|
+
cart = search( cc, @rg ).cart_create_response.cart
|
94
|
+
|
95
|
+
@cart_id = cart.cart_id
|
96
|
+
@hmac = cart.hmac
|
97
|
+
@purchase_url = cart.purchase_url
|
98
|
+
@cart_items = cart.cart_items.cart_item
|
99
|
+
end
|
100
|
+
|
101
|
+
alias :create :cart_create
|
102
|
+
|
103
|
+
|
104
|
+
# Add one or more new items to the remote shopping-cart. This can not
|
105
|
+
# be used to update quantities of items *already* in the cart. For
|
106
|
+
# that, you must use Cart#cart_modify instead.
|
107
|
+
#
|
108
|
+
# _id_type_ is a String, either *ASIN* or *OfferListingId*. _item_id_
|
109
|
+
# is the actual ASIN or offer listing ID in question, and _quantity_
|
110
|
+
# is the quantity of the item to add to the cart.
|
111
|
+
#
|
112
|
+
# _more_items_ is an optional list of Hash objects describing
|
113
|
+
# additional items to add to the cart.
|
114
|
+
#
|
115
|
+
# Example:
|
116
|
+
#
|
117
|
+
# cart.cart_add( :ASIN, 'B0014C2BL4', 3,
|
118
|
+
# { 'B00006BCKL' => 2 },
|
119
|
+
# { 'B000VVE2UW' => 1 } )
|
120
|
+
#
|
121
|
+
# or:
|
122
|
+
#
|
123
|
+
# cart.cart_add( :ASIN, 'B0014C2BL4', 3,
|
124
|
+
# { 'B00006BCKL' => 2,
|
125
|
+
# 'B000VVE2UW' => 1 } )
|
126
|
+
#
|
127
|
+
def cart_add(id_type, item_id, quantity=1, *more_items)
|
128
|
+
ca = CartAdd.new( id_type, item_id, quantity, *more_items )
|
129
|
+
ca.params.merge!( { 'CartId' => @cart_id, 'HMAC' => @hmac } )
|
130
|
+
cart = search( ca, @rg ).cart_add_response.cart
|
131
|
+
@cart_items = cart.cart_items.cart_item
|
132
|
+
end
|
133
|
+
|
134
|
+
alias :add :cart_add
|
135
|
+
|
136
|
+
|
137
|
+
# Returns whether or not an item is present in the cart, be it in the
|
138
|
+
# active or <i>Save For Later</i> area.
|
139
|
+
#
|
140
|
+
# _item_id_type_ is the name of the attribute that uniquely identifies
|
141
|
+
# an item, such as *ASIN* or *CartItemId*. _item_id_ is the value of
|
142
|
+
# the _item_id_type_ for the item whose presence in the cart is being
|
143
|
+
# determined.
|
144
|
+
#
|
145
|
+
# If the item is present in the cart, its _CartItemId_ is returned as a
|
146
|
+
# String. Otherwise, *false* is returned.
|
147
|
+
#
|
148
|
+
# Example:
|
149
|
+
#
|
150
|
+
# cart.include?( :ASIN, 'B00151HZA6' )
|
151
|
+
#
|
152
|
+
def include?(item_id_type, item_id)
|
153
|
+
active?( item_id_type, item_id ) ||
|
154
|
+
saved_for_later?( item_id_type, item_id )
|
155
|
+
end
|
156
|
+
|
157
|
+
alias :contain? :include?
|
158
|
+
|
159
|
+
|
160
|
+
# Returns whether or not an item is present in an area of the cart.
|
161
|
+
#
|
162
|
+
# _area_ is an array of cart items, _item_id_type_ is the name of the
|
163
|
+
# attribute that uniquely identifies an item, such as *ASIN* or
|
164
|
+
# *CartItemId* and _item_id_ is the value of the _item_id_type_ for
|
165
|
+
# the item whose presence in the cart is being determined.
|
166
|
+
#
|
167
|
+
# If the item is present in the cart, its _CartItemId_ is returned as a
|
168
|
+
# String. Otherwise, *false* is returned.
|
169
|
+
#
|
170
|
+
# Example:
|
171
|
+
#
|
172
|
+
# cart.in_area?( @cart_items, :ASIN, 'B00151HZA6' )
|
173
|
+
#
|
174
|
+
# or:
|
175
|
+
#
|
176
|
+
# cart.in_area?( @saved_for_later_items, :ASIN, 'B00151HZA6' )
|
177
|
+
#
|
178
|
+
def in_area?(area, item_id_type, item_id)
|
179
|
+
found = area.find do |item|
|
180
|
+
item.send( Amazon.uncamelise( item_id_type.to_s ) ).to_s == item_id
|
181
|
+
end
|
182
|
+
|
183
|
+
found ? found.cart_item_id.to_s : false
|
184
|
+
end
|
185
|
+
private :in_area?
|
186
|
+
|
187
|
+
|
188
|
+
# Returns whether or not an item is present in the active area of the
|
189
|
+
# cart.
|
190
|
+
#
|
191
|
+
# _item_id_type_ is the name of the attribute that uniquely identifies
|
192
|
+
# an item, such as *ASIN* or *CartItemId*. _item_id_ is the value of
|
193
|
+
# the _item_id_type_ for the item whose presence in the cart is being
|
194
|
+
# determined.
|
195
|
+
#
|
196
|
+
# If the item is present in the cart, its _CartItemId_ is returned as a
|
197
|
+
# String. Otherwise, *false* is returned.
|
198
|
+
#
|
199
|
+
# Example:
|
200
|
+
#
|
201
|
+
# cart.active?( :ASIN, 'B00151HZA6' )
|
202
|
+
#
|
203
|
+
def active?(item_id_type, item_id)
|
204
|
+
in_area?( @cart_items, item_id_type, item_id )
|
205
|
+
end
|
206
|
+
|
207
|
+
|
208
|
+
# Returns whether or not an item is present in the <i>Save For
|
209
|
+
# Later</i> area of the cart.
|
210
|
+
#
|
211
|
+
# _item_id_type_ is the name of the attribute that uniquely identifies
|
212
|
+
# an item, such as *ASIN* or *CartItemId*. _item_id_ is the value of
|
213
|
+
# the _item_id_type_ for the item whose presence in the cart is being
|
214
|
+
# determined.
|
215
|
+
#
|
216
|
+
# If the item is present in the cart, its _CartItemId_ is returned as a
|
217
|
+
# String. Otherwise, *false* is returned.
|
218
|
+
#
|
219
|
+
# Example:
|
220
|
+
#
|
221
|
+
# cart.saved_for_later?( :ASIN, 'B00151HZA6' )
|
222
|
+
#
|
223
|
+
def saved_for_later?(item_id_type, item_id)
|
224
|
+
in_area?( @saved_for_later_items, item_id_type, item_id )
|
225
|
+
end
|
226
|
+
|
227
|
+
alias :saved? :saved_for_later?
|
228
|
+
|
229
|
+
|
230
|
+
# Modify the quantities of one or more products already in the cart.
|
231
|
+
# Changing the quantity of an item to <b>0</b> effectively removes it
|
232
|
+
# from the cart.
|
233
|
+
#
|
234
|
+
# _item_id_type_ is the name of the attribute that uniquely identifies
|
235
|
+
# an item in the cart, such as *ASIN* or *CartItemId*. _item_id_ is
|
236
|
+
# the value of the _item_id_type_ of the item to be modified, and
|
237
|
+
# _quantity_ is its new quantity.
|
238
|
+
#
|
239
|
+
# _save_for_later_ should be set to *true* if the items in question
|
240
|
+
# should be moved to the <i>Save For Later</i> area of the
|
241
|
+
# shopping-cart, or *false* if they should be moved to the active
|
242
|
+
# area. _save_for_later_ therefore applies to every item specified by
|
243
|
+
# _item_id_ and _more_items_. Use *nil* when the location of the items
|
244
|
+
# should not be changed.
|
245
|
+
#
|
246
|
+
# Current Amazon AWS documentation claims that specifying partial
|
247
|
+
# quantities can be used to move some copies of an item from one area
|
248
|
+
# of the cart to another, whilst leaving the rest in place. In
|
249
|
+
# practice, however, this causes an AWS error that explains that a
|
250
|
+
# quantity may not be specified in combination with an instruction to
|
251
|
+
# move copies from one area of the cart to another. For this reason,
|
252
|
+
# when _save_for_later_ is not *nil*, item quantities are currently
|
253
|
+
# ignored.
|
254
|
+
#
|
255
|
+
# _more_items_ is an optional list of Hash objects describing
|
256
|
+
# additional items whose quantity should be modified.
|
257
|
+
#
|
258
|
+
# Example:
|
259
|
+
#
|
260
|
+
# cart.cart_modify( :ASIN, 'B00151HZA6', 2, false,
|
261
|
+
# { 'B0013F2M52' => 1 },
|
262
|
+
# { 'B000HCPSR6' => 3 } )
|
263
|
+
#
|
264
|
+
# or:
|
265
|
+
#
|
266
|
+
# cart.cart_modify( :ASIN, 'B00151HZA6', 2, true,
|
267
|
+
# { 'B0013F2M52' => 1,
|
268
|
+
# 'B000HCPSR6' => 3 } )
|
269
|
+
#
|
270
|
+
def cart_modify(item_id_type, item_id, quantity, save_for_later=nil,
|
271
|
+
*more_items)
|
272
|
+
item_quantity1 = quantity
|
273
|
+
|
274
|
+
unless cart_item_id1 = self.include?( item_id_type, item_id )
|
275
|
+
raise CartError,
|
276
|
+
"Can't find item with '#{item_id_type}' of '#{item_id}' in cart."
|
277
|
+
end
|
278
|
+
|
279
|
+
more_items.collect! do |extra_item|
|
280
|
+
items = []
|
281
|
+
|
282
|
+
extra_item.each do |item|
|
283
|
+
item_id, quantity = item
|
284
|
+
unless cart_item_id = self.include?( item_id_type, item_id )
|
285
|
+
raise CartError,
|
286
|
+
"Can't find item with '#{item_id_type}' of '#{item_id}' in cart."
|
287
|
+
end
|
288
|
+
|
289
|
+
items << { cart_item_id => quantity }
|
290
|
+
end
|
291
|
+
|
292
|
+
items
|
293
|
+
end
|
294
|
+
|
295
|
+
more_items.flatten!
|
296
|
+
|
297
|
+
cm = CartModify.new( cart_item_id1, item_quantity1, save_for_later,
|
298
|
+
*more_items )
|
299
|
+
cm.params.merge!( { 'CartId' => @cart_id, 'HMAC' => @hmac } )
|
300
|
+
cart = search( cm, @rg ).cart_modify_response.cart
|
301
|
+
|
302
|
+
if ci = cart.cart_items
|
303
|
+
@cart_items = ci.cart_item
|
304
|
+
else
|
305
|
+
@cart_items = []
|
306
|
+
end
|
307
|
+
|
308
|
+
if sfl = cart.saved_for_later_items
|
309
|
+
@saved_for_later_items = sfl.saved_for_later_item
|
310
|
+
else
|
311
|
+
@saved_for_later_items = []
|
312
|
+
end
|
313
|
+
end
|
314
|
+
|
315
|
+
alias :modify :cart_modify
|
316
|
+
|
317
|
+
|
318
|
+
# Retrieve a remote shopping-cart. This is especially useful when
|
319
|
+
# needing to resurrect a cart at a later time, when the Cart object
|
320
|
+
# containing the original data no longer exists.
|
321
|
+
#
|
322
|
+
# _cart_id_ is the unique ID of the cart to be retrieved and _hmac_ is
|
323
|
+
# the cart's hash message authentication code. These details can
|
324
|
+
# be obtained from an existing cart using the <i>@cart_id</i> and
|
325
|
+
# <i>@hmac</i> instance variables.
|
326
|
+
#
|
327
|
+
# Example:
|
328
|
+
#
|
329
|
+
# old_cart = Cart.new
|
330
|
+
# old_cart.get_cart( '203-4219703-7532717',
|
331
|
+
# 'o98sn9Z16JOEF/9eo6OcD8zOZA4=' )
|
332
|
+
#
|
333
|
+
def cart_get(cart_id, hmac)
|
334
|
+
cg = CartGet.new
|
335
|
+
cg.params.merge!( { 'CartId' => cart_id, 'HMAC' => hmac } )
|
336
|
+
|
337
|
+
@rg = ResponseGroup.new( 'Cart' )
|
338
|
+
cart = search( cg, @rg ).cart_get_response.cart
|
339
|
+
|
340
|
+
@cart_id = cart.cart_id
|
341
|
+
@hmac = cart.hmac
|
342
|
+
@purchase_url = cart.purchase_url
|
343
|
+
|
344
|
+
if ci = cart.cart_items
|
345
|
+
@cart_items = ci.cart_item
|
346
|
+
else
|
347
|
+
@cart_items = []
|
348
|
+
end
|
349
|
+
|
350
|
+
if sfl = cart.saved_for_later_items
|
351
|
+
@saved_for_later_items = sfl.saved_for_later_item
|
352
|
+
else
|
353
|
+
@saved_for_later_items = []
|
354
|
+
end
|
355
|
+
|
356
|
+
self
|
357
|
+
end
|
358
|
+
|
359
|
+
alias :get :cart_get
|
360
|
+
|
361
|
+
|
362
|
+
# Remove all items from the shopping-cart.
|
363
|
+
#
|
364
|
+
# Example:
|
365
|
+
#
|
366
|
+
# cart.cart_clear
|
367
|
+
#
|
368
|
+
def cart_clear
|
369
|
+
cc = CartClear.new
|
370
|
+
cc.params.merge!( { 'CartId' => @cart_id, 'HMAC' => @hmac } )
|
371
|
+
cart = search( cc, @rg ).cart_clear_response.cart
|
372
|
+
@cart_items = []
|
373
|
+
@saved_for_later_items = []
|
374
|
+
end
|
375
|
+
|
376
|
+
alias :clear :cart_clear
|
377
|
+
|
378
|
+
|
379
|
+
include Enumerable
|
380
|
+
|
381
|
+
# Iterator for each item in the cart.
|
382
|
+
#
|
383
|
+
def each
|
384
|
+
@cart_items.each { |item| yield item }
|
385
|
+
end
|
386
|
+
|
387
|
+
alias :each_item :each
|
388
|
+
|
389
|
+
end
|
390
|
+
|
391
|
+
|
392
|
+
# Worker class used by Cart#cart_create.
|
393
|
+
#
|
394
|
+
class CartCreate < Operation # :nodoc:
|
395
|
+
|
396
|
+
# Create a shopping-cart and add item(s) to it.
|
397
|
+
#
|
398
|
+
def initialize(id_type, item_id, quantity, merge_cart=false,
|
399
|
+
save_for_later=nil, *more_items)
|
400
|
+
|
401
|
+
# FIXME: Need to deal with ListItemId, too.
|
402
|
+
|
403
|
+
# Prepend first item to more_items array (which may be empty).
|
404
|
+
#
|
405
|
+
more_items.unshift( { item_id => quantity } )
|
406
|
+
|
407
|
+
mc = merge_cart ? 'True' : 'False'
|
408
|
+
|
409
|
+
more_items.collect! do |extra_item|
|
410
|
+
items = []
|
411
|
+
|
412
|
+
extra_item.each do |item|
|
413
|
+
item_id, quantity = item
|
414
|
+
case save_for_later
|
415
|
+
when true
|
416
|
+
items << { id_type => item_id,
|
417
|
+
'Action' => 'SaveForLater' }
|
418
|
+
when false
|
419
|
+
items << { id_type => item_id,
|
420
|
+
'Action' => 'MoveToCart' }
|
421
|
+
when nil
|
422
|
+
items << { id_type => item_id,
|
423
|
+
'Quantity' => quantity }
|
424
|
+
else
|
425
|
+
raise CartError,
|
426
|
+
"save_for_later must be true, false or nil, but was #{save_for_later}"
|
427
|
+
end
|
428
|
+
end
|
429
|
+
|
430
|
+
items
|
431
|
+
end
|
432
|
+
|
433
|
+
more_items.flatten!
|
434
|
+
|
435
|
+
# Force batch syntax if only a single item is being put in cart.
|
436
|
+
#
|
437
|
+
params = batch_parameters( {}, *more_items )
|
438
|
+
params.merge!( { 'MergeCart' => mc } ) if merge_cart
|
439
|
+
|
440
|
+
super( params )
|
441
|
+
end
|
442
|
+
|
443
|
+
end
|
444
|
+
|
445
|
+
|
446
|
+
# Worker class used by Cart#cart_add.
|
447
|
+
#
|
448
|
+
class CartAdd < CartCreate # :nodoc:
|
449
|
+
|
450
|
+
# Add new item(s) to a cart.
|
451
|
+
#
|
452
|
+
def initialize(id_type, item_id, quantity, *more_items)
|
453
|
+
super( id_type, item_id, quantity, false, nil, *more_items )
|
454
|
+
end
|
455
|
+
|
456
|
+
end
|
457
|
+
|
458
|
+
|
459
|
+
# Worker class used by Cart#cart_modify.
|
460
|
+
#
|
461
|
+
class CartModify < CartCreate # :nodoc:
|
462
|
+
|
463
|
+
# Modify the quantity of item(s) in a cart.
|
464
|
+
#
|
465
|
+
def initialize(cart_item_id, quantity, save_for_later=false,
|
466
|
+
*more_items)
|
467
|
+
|
468
|
+
super( 'CartItemId', cart_item_id, quantity, false, save_for_later,
|
469
|
+
*more_items )
|
470
|
+
end
|
471
|
+
|
472
|
+
end
|
473
|
+
|
474
|
+
|
475
|
+
# Worker class used by Cart#cart_clear.
|
476
|
+
#
|
477
|
+
class CartClear < Operation # :nodoc:
|
478
|
+
|
479
|
+
# Remove all items from a cart.
|
480
|
+
#
|
481
|
+
def initialize
|
482
|
+
super( {} )
|
483
|
+
end
|
484
|
+
|
485
|
+
end
|
486
|
+
|
487
|
+
|
488
|
+
# Worker class used by Cart#cart_get.
|
489
|
+
#
|
490
|
+
class CartGet < Operation # :nodoc:
|
491
|
+
|
492
|
+
# Fetch a cart.
|
493
|
+
#
|
494
|
+
def initialize
|
495
|
+
super( {} )
|
496
|
+
end
|
497
|
+
|
498
|
+
end
|
499
|
+
|
500
|
+
end
|
501
|
+
|
502
|
+
end
|
503
|
+
|
504
|
+
end
|