eway_rapid 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (76) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +25 -0
  3. data/.travis.yml +11 -0
  4. data/CHANGELOG.md +7 -0
  5. data/Gemfile +2 -0
  6. data/LICENSE.md +21 -0
  7. data/README.md +96 -0
  8. data/Rakefile +14 -0
  9. data/eway_rapid.gemspec +26 -0
  10. data/lib/eway_rapid.rb +78 -0
  11. data/lib/eway_rapid/constants.rb +126 -0
  12. data/lib/eway_rapid/entities/cancel_authorisation_request.rb +9 -0
  13. data/lib/eway_rapid/entities/cancel_authorisation_response.rb +34 -0
  14. data/lib/eway_rapid/entities/capture_payment_request.rb +11 -0
  15. data/lib/eway_rapid/entities/capture_payment_response.rb +34 -0
  16. data/lib/eway_rapid/entities/create_access_code_request.rb +35 -0
  17. data/lib/eway_rapid/entities/create_access_code_response.rb +128 -0
  18. data/lib/eway_rapid/entities/create_access_code_shared_request.rb +53 -0
  19. data/lib/eway_rapid/entities/create_access_code_shared_response.rb +40 -0
  20. data/lib/eway_rapid/entities/create_customer_response.rb +8 -0
  21. data/lib/eway_rapid/entities/direct_customer_search_request.rb +9 -0
  22. data/lib/eway_rapid/entities/direct_customer_search_response.rb +23 -0
  23. data/lib/eway_rapid/entities/direct_payment_request.rb +29 -0
  24. data/lib/eway_rapid/entities/direct_payment_response.rb +58 -0
  25. data/lib/eway_rapid/entities/direct_refund_request.rb +26 -0
  26. data/lib/eway_rapid/entities/direct_refund_response.rb +44 -0
  27. data/lib/eway_rapid/entities/transaction_search_response.rb +23 -0
  28. data/lib/eway_rapid/exceptions.rb +51 -0
  29. data/lib/eway_rapid/message/convert/customer_to_internal_customer.rb +70 -0
  30. data/lib/eway_rapid/message/convert/direct_payment_to_trans_status.rb +47 -0
  31. data/lib/eway_rapid/message/convert/direct_refund_to_trans_status.rb +33 -0
  32. data/lib/eway_rapid/message/convert/internal_customer_to_customer.rb +41 -0
  33. data/lib/eway_rapid/message/convert/internal_trans_to_trans.rb +62 -0
  34. data/lib/eway_rapid/message/convert/internal_transaction_to_address.rb +27 -0
  35. data/lib/eway_rapid/message/convert/internal_transaction_to_status.rb +55 -0
  36. data/lib/eway_rapid/message/convert/payment_to_payment_details.rb +25 -0
  37. data/lib/eway_rapid/message/convert/request/refund_to_direct_refund_req.rb +41 -0
  38. data/lib/eway_rapid/message/convert/request/transaction_to_capture_payment.rb +28 -0
  39. data/lib/eway_rapid/message/convert/request/transaction_to_create_access_code_request.rb +58 -0
  40. data/lib/eway_rapid/message/convert/request/transaction_to_create_access_code_shared_request.rb +54 -0
  41. data/lib/eway_rapid/message/convert/request/transaction_to_direct_payment.rb +45 -0
  42. data/lib/eway_rapid/message/convert/response/access_code_shared_to_create_cust.rb +23 -0
  43. data/lib/eway_rapid/message/convert/response/access_code_shared_to_create_trans.rb +28 -0
  44. data/lib/eway_rapid/message/convert/response/access_code_to_create_cust.rb +24 -0
  45. data/lib/eway_rapid/message/convert/response/access_code_to_create_trans.rb +27 -0
  46. data/lib/eway_rapid/message/convert/response/cancel_authorisation_to_refund.rb +37 -0
  47. data/lib/eway_rapid/message/convert/response/capture_payment_to_create_transaction.rb +43 -0
  48. data/lib/eway_rapid/message/convert/response/direct_customer_to_query_customer.rb +55 -0
  49. data/lib/eway_rapid/message/convert/response/direct_payment_to_create_cust.rb +23 -0
  50. data/lib/eway_rapid/message/convert/response/direct_payment_to_create_trans.rb +32 -0
  51. data/lib/eway_rapid/message/convert/response/direct_refund_to_refund_response.rb +28 -0
  52. data/lib/eway_rapid/message/convert/response/search_to_query_trans.rb +30 -0
  53. data/lib/eway_rapid/message/convert/shipping_details_to_address.rb +35 -0
  54. data/lib/eway_rapid/message/convert/transaction_shipping_address.rb +37 -0
  55. data/lib/eway_rapid/message/convert/transaction_to_arr_line_item.rb +14 -0
  56. data/lib/eway_rapid/message/convert/transaction_to_arr_option.rb +25 -0
  57. data/lib/eway_rapid/message/convert/transaction_to_payment.rb +29 -0
  58. data/lib/eway_rapid/message/convert/verification_to_verification_result.rb +33 -0
  59. data/lib/eway_rapid/message/process/customer_process.rb +255 -0
  60. data/lib/eway_rapid/message/process/refund_process.rb +76 -0
  61. data/lib/eway_rapid/message/process/rest_process.rb +87 -0
  62. data/lib/eway_rapid/message/process/transaction_process.rb +139 -0
  63. data/lib/eway_rapid/models/enums.rb +126 -0
  64. data/lib/eway_rapid/models/internal_models.rb +431 -0
  65. data/lib/eway_rapid/models/models.rb +334 -0
  66. data/lib/eway_rapid/output/create_transaction_response.rb +24 -0
  67. data/lib/eway_rapid/output/query_customer_response.rb +25 -0
  68. data/lib/eway_rapid/output/query_transaction_response.rb +16 -0
  69. data/lib/eway_rapid/output/refund_response.rb +9 -0
  70. data/lib/eway_rapid/output/response_output.rb +14 -0
  71. data/lib/eway_rapid/rapid_client.rb +444 -0
  72. data/lib/eway_rapid/rapid_logger.rb +40 -0
  73. data/lib/eway_rapid/resources/err_code_resource_en.yml +237 -0
  74. data/lib/eway_rapid/resources/rapid-api.yml +4 -0
  75. data/lib/eway_rapid/version.rb +3 -0
  76. metadata +201 -0
@@ -0,0 +1,26 @@
1
+ module EwayRapid
2
+ class DirectRefundRequest
3
+ attr_accessor :customer
4
+ attr_accessor :shipping_address
5
+ attr_accessor :refund
6
+ attr_accessor :line_items
7
+ attr_accessor :options
8
+ attr_accessor :device_id
9
+ attr_accessor :customer_ip
10
+ attr_accessor :partner_id
11
+
12
+ def to_json(opts={})
13
+ {
14
+ Constants::CUSTOMER => InternalModels::Customer.to_hash(customer),
15
+ Constants::SHIPPING_ADDRESS => InternalModels::ShippingAddress.to_hash(shipping_address),
16
+ Constants::REFUND => InternalModels::RefundDetails.to_hash(refund),
17
+ Constants::LINE_ITEMS => Models::LineItem.to_array(line_items),
18
+ Constants::OPTIONS => InternalModels::Option.to_array(options),
19
+ Constants::DEVICE_ID => device_id,
20
+ Constants::CUSTOMER_DEVICE_IP => customer_ip,
21
+ Constants::PARTNER_ID => partner_id
22
+ }.to_json
23
+ end
24
+
25
+ end
26
+ end
@@ -0,0 +1,44 @@
1
+ module EwayRapid
2
+ class DirectRefundResponse
3
+ attr_accessor :authorisation_code
4
+ attr_accessor :response_code
5
+ attr_accessor :response_message
6
+ attr_accessor :transaction_id
7
+ attr_accessor :transaction_status
8
+ attr_accessor :verification
9
+ attr_accessor :customer
10
+ attr_accessor :refund
11
+ attr_accessor :errors
12
+
13
+ alias_method :transaction_status?, :transaction_status
14
+
15
+ def to_json(options={})
16
+ {Constants::AUTHORISATION_CODE => authorisation_code,
17
+ Constants::RESPONSE_CODE => response_code,
18
+ Constants::TRANSACTION_ID => transaction_id,
19
+ Constants::TRANSACTION_STATUS => transaction_status,
20
+ Constants::VERIFICATION => verification,
21
+ Constants::CUSTOMER => customer,
22
+ Constants::REFUND => refund,
23
+ Constants::ERRORS_CAPITALIZED => errors}.to_json
24
+ end
25
+
26
+ def self.from_json(json)
27
+ hash = JSON.parse(json)
28
+ from_hash(hash)
29
+ end
30
+
31
+ def self.from_hash(hash)
32
+ direct_refund_response = DirectRefundResponse.new
33
+ direct_refund_response.authorisation_code = hash[Constants::AUTHORISATION_CODE]
34
+ direct_refund_response.response_code = hash[Constants::RESPONSE_CODE]
35
+ direct_refund_response.transaction_id = hash[Constants::TRANSACTION_ID]
36
+ direct_refund_response.transaction_status = hash[Constants::TRANSACTION_STATUS]
37
+ direct_refund_response.verification = hash[Constants::VERIFICATION]
38
+ direct_refund_response.customer = InternalModels::Customer.from_hash(hash[Constants::CUSTOMER])
39
+ direct_refund_response.refund = InternalModels::RefundDetails.from_hash(hash[Constants::REFUND])
40
+ direct_refund_response.errors = hash[Constants::ERRORS_CAPITALIZED]
41
+ direct_refund_response
42
+ end
43
+ end
44
+ end
@@ -0,0 +1,23 @@
1
+ module EwayRapid
2
+ class TransactionSearchResponse
3
+ attr_accessor :transactions
4
+ attr_accessor :error
5
+
6
+ def to_json(options={})
7
+ {Constants::TRANSACTIONS => transactions,
8
+ Constants::ERRORS_CAPITALIZED => error}.to_json
9
+ end
10
+
11
+ def self.from_json(json)
12
+ hash = JSON.parse(json)
13
+ from_hash(hash)
14
+ end
15
+
16
+ def self.from_hash(hash)
17
+ transaction_search_response = TransactionSearchResponse.new
18
+ transaction_search_response.transactions = InternalModels::Transaction.from_array(hash[Constants::TRANSACTIONS])
19
+ transaction_search_response.error = hash[Constants::ERRORS_CAPITALIZED]
20
+ transaction_search_response
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,51 @@
1
+ module EwayRapid
2
+ module Exceptions
3
+
4
+ # The root exception class for all of business Rapid API exceptions
5
+ # Optional parameters :
6
+ # * :error_code the business error code
7
+ class RapidSdkException < StandardError
8
+ attr_accessor :error_code
9
+
10
+ def initialize(error_code, message)
11
+ super(message)
12
+ @error_code = error_code
13
+ end
14
+ end
15
+
16
+ # Rapid API key, password or endpoint invalid exception
17
+ class APIKeyInvalidException < RapidSdkException
18
+ def initialize(message)
19
+ super(Constants::API_KEY_INVALID_ERROR_CODE, message)
20
+ end
21
+ end
22
+
23
+ # Authentication to Rapid API failed (server returned HTTP 40*)
24
+ class AuthenticationFailureException < RapidSdkException
25
+ def initialize(message)
26
+ super(Constants::AUTHENTICATION_FAILURE_ERROR_CODE, message)
27
+ end
28
+ end
29
+
30
+ # Error connecting to Rapid API
31
+ class CommunicationFailureException < RapidSdkException
32
+ def initialize(message)
33
+ super(Constants::COMMUNICATION_FAILURE_ERROR_CODE, message)
34
+ end
35
+ end
36
+
37
+ # Invalid parameter exception
38
+ class ParameterInvalidException < RapidSdkException
39
+ def initialize(message)
40
+ super(Constants::INTERNAL_RAPID_API_ERROR_CODE, message)
41
+ end
42
+ end
43
+
44
+ # Invalid response from Rapid API
45
+ class SystemErrorException <RapidSdkException
46
+ def initialize(message)
47
+ super(Constants::INTERNAL_RAPID_SERVER_ERROR_CODE, message)
48
+ end
49
+ end
50
+ end
51
+ end
@@ -0,0 +1,70 @@
1
+ module EwayRapid
2
+ module Message
3
+ module Convert
4
+ class CustomerToInternalCustomer
5
+ @merge_card_detail_to_this = true
6
+
7
+ def initialize(is_merge_card_info = nil)
8
+ @merge_card_detail_to_this = is_merge_card_info unless is_merge_card_info.nil?
9
+ end
10
+
11
+ # @param [Models::Customer] customer
12
+ # @return [InternalModels::Customer]
13
+ def do_convert(customer)
14
+ i_customer = InternalModels::Customer.new
15
+ if customer
16
+ i_customer.phone = customer.phone
17
+ i_customer.reference = customer.reference
18
+ i_customer.token_customer_id = customer.token_customer_id
19
+ i_customer.comments = customer.comments
20
+ i_customer.mobile = customer.mobile
21
+ i_customer.title = customer.title
22
+ i_customer.fax = customer.fax
23
+ i_customer.customer_device_ip = customer.customer_device_ip
24
+ i_customer.email = customer.email
25
+
26
+ # @type [Models::CardDetails]
27
+ card_details = customer.card_details
28
+ i_customer.card_details = card_details
29
+
30
+ if card_details && @merge_card_detail_to_this
31
+ i_customer.card_start_month = card_details.start_month
32
+ i_customer.card_start_year = card_details.start_year
33
+ i_customer.card_issue_number = card_details.issue_number
34
+ i_customer.card_name = card_details.name
35
+ i_customer.card_number = card_details.number
36
+ begin
37
+ i_customer.card_expiry_year = Integer(card_details.expiry_year)
38
+ rescue
39
+ raise ArgumentError.new 'Invalid expiry year in card details'
40
+ end
41
+ begin
42
+ i_customer.card_expiry_month = Integer(card_details.expiry_month)
43
+ rescue
44
+ raise ArgumentError.new 'Invalid expiry month param in card details'
45
+ end
46
+ end
47
+
48
+ i_customer.company_name = customer.company_name
49
+ i_customer.url = customer.url
50
+ i_customer.first_name = customer.first_name
51
+ i_customer.last_name = customer.last_name
52
+
53
+ # @type [Models::Address]
54
+ cus_address = customer.address
55
+ if cus_address
56
+ i_customer.state = cus_address.state
57
+ i_customer.postal_code = cus_address.postal_code
58
+ i_customer.country = cus_address.country
59
+ i_customer.city = cus_address.city
60
+ i_customer.street1 = cus_address.street1
61
+ i_customer.street2 = cus_address.street2
62
+ end
63
+ i_customer.job_description = customer.job_description
64
+ end
65
+ i_customer
66
+ end
67
+ end
68
+ end
69
+ end
70
+ end
@@ -0,0 +1,47 @@
1
+ module EwayRapid
2
+ module Message
3
+ module Convert
4
+ class DirectPaymentToTransStatus
5
+
6
+ # @param [DirectPaymentResponse] response
7
+ # @return [Models::TransactionStatus]
8
+ def do_convert(response)
9
+ status = Models::TransactionStatus.new
10
+ status.beagle_score = !response.beagle_score.nil? ? response.beagle_score : 0.0
11
+ status.captured = to_boolean(response.transaction_captured)
12
+ status.fraud_action = response.fraud_action if response.fraud_action
13
+ status.processing_details = get_processing_details(response)
14
+ status.status = response.transaction_status if response.transaction_status
15
+ status.total = response.payment.total_amount if response.payment
16
+ status.transaction_id = if response.transaction_id
17
+ begin
18
+ Integer(response.transaction_id)
19
+ rescue
20
+ raise ArgumentError.new 'Invalid transaction id when converting direct payment to transaction status'
21
+ end
22
+ else
23
+ 0
24
+ end
25
+
26
+ verification_convert = VerificationToVerificationResult.new
27
+ status.verification_result = verification_convert.do_convert(response.verification)
28
+ status
29
+ end
30
+
31
+ def to_boolean(string)
32
+ string == 'true'
33
+ end
34
+
35
+ # @param [DirectPaymentResponse] response
36
+ # @return [Models::ProcessingDetails]
37
+ def get_processing_details(response)
38
+ processing_details = Models::ProcessingDetails.new
39
+ processing_details.authorisation_code = response.authorisation_code
40
+ processing_details.response_code = response.response_code
41
+ processing_details.response_message = response.response_message
42
+ processing_details
43
+ end
44
+ end
45
+ end
46
+ end
47
+ end
@@ -0,0 +1,33 @@
1
+ module EwayRapid
2
+ module Message
3
+ module Convert
4
+ class DirectRefundToTransStatus
5
+
6
+ # @param [DirectRefundResponse] response
7
+ # @return [Models::TransactionStatus]
8
+ def do_convert(response)
9
+ status = Models::TransactionStatus.new
10
+ status.processing_details = get_processing_details(response)
11
+ status.status = response.transaction_status if response.transaction_status
12
+ begin
13
+ status.transaction_id = Integer(response.transaction_id) if response.transaction_id
14
+ rescue
15
+ raise ArgumentError.new 'Invalid transaction id when converting direct refund to transaction status'
16
+ end
17
+
18
+ status
19
+ end
20
+
21
+ # @param [DirectRefundResponse] response
22
+ # @return [Models::ProcessingDetails]
23
+ def get_processing_details(response)
24
+ processing_details = Models::ProcessingDetails.new
25
+ processing_details.authorisation_code = response.authorisation_code
26
+ processing_details.response_code = response.response_code
27
+ processing_details.response_message = response.response_message
28
+ processing_details
29
+ end
30
+ end
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,41 @@
1
+ module EwayRapid
2
+ module Message
3
+ module Convert
4
+ class InternalCustomerToCustomer
5
+
6
+ # @param [InternalModels::Customer] i_customer
7
+ # @return [Models::Customer]
8
+ def do_convert(i_customer)
9
+ customer = Models::Customer.new
10
+ if i_customer
11
+ customer.comments = i_customer.comments
12
+ customer.token_customer_id = i_customer.token_customer_id
13
+ customer.mobile = i_customer.mobile
14
+ customer.phone = i_customer.phone
15
+ customer.title = i_customer.title
16
+ customer.company_name = i_customer.company_name
17
+ customer.fax = i_customer.fax
18
+ customer.first_name = i_customer.first_name
19
+ customer.last_name = i_customer.last_name
20
+ customer.job_description = i_customer.job_description
21
+ customer.reference = i_customer.reference
22
+ customer.url = i_customer.url
23
+ customer.customer_device_ip = i_customer.customer_device_ip
24
+ customer.email = i_customer.email
25
+
26
+ address = Models::Address.new
27
+ address.city = i_customer.city
28
+ address.street1 = i_customer.street1
29
+ address.street2 = i_customer.street2
30
+ address.postal_code = i_customer.postal_code
31
+ address.country = i_customer.country
32
+ address.state = i_customer.state
33
+ customer.address = address
34
+ customer.card_details = i_customer.card_details
35
+ end
36
+ customer
37
+ end
38
+ end
39
+ end
40
+ end
41
+ end
@@ -0,0 +1,62 @@
1
+ module EwayRapid
2
+ module Message
3
+ module Convert
4
+ class InternalTransToTrans
5
+
6
+ # @param [InternalModels::Transaction] i_transaction
7
+ # @return [Models::Transaction]
8
+ def do_convert(i_transaction)
9
+ transaction = Models::Transaction.new
10
+ transaction.customer = get_eway_customer(i_transaction)
11
+ transaction.payment_details = get_payment_details(i_transaction)
12
+ transaction.shipping_details = get_shipping_details(i_transaction)
13
+ transaction.options = i_transaction.options
14
+ transaction
15
+ end
16
+
17
+ # @param [InternalModels::Transaction] i_transaction
18
+ # @return [Models::Customer]
19
+ def get_eway_customer(i_transaction)
20
+ # @type [InternalModels::Customer]
21
+ i_customer = i_transaction.customer
22
+ customer_convert = InternalCustomerToCustomer.new
23
+
24
+ # @type [Models::Customer]
25
+ customer = customer_convert.do_convert(i_customer)
26
+ address_convert = InternalTransactionToAddress.new
27
+ customer.address = address_convert.do_convert(i_transaction)
28
+ customer
29
+ end
30
+
31
+ # @param [InternalModels::Transaction] i_transaction
32
+ # @return [Models::PaymentDetails]
33
+ def get_payment_details(i_transaction)
34
+ payment_details = Models::PaymentDetails.new
35
+ payment_details.total_amount = i_transaction.total_amount
36
+ payment_details.invoice_reference = i_transaction.invoice_reference
37
+ payment_details.invoice_number = i_transaction.invoice_number
38
+ payment_details
39
+ end
40
+
41
+ # @param [InternalModels::Transaction] i_transaction
42
+ # @return [Models::ShippingDetails]
43
+ def get_shipping_details(i_transaction)
44
+ shipping_details = Models::ShippingDetails.new
45
+
46
+ if i_transaction.shipping_address
47
+ address_convert = InternalTransactionToAddress.new
48
+ shipping_details.shipping_address = address_convert.do_convert(i_transaction)
49
+ shipping_details.shipping_method = i_transaction.shipping_address.shipping_method || ''
50
+ shipping_details.first_name = i_transaction.shipping_address.first_name
51
+ shipping_details.last_name = i_transaction.shipping_address.last_name
52
+ shipping_details.email = i_transaction.shipping_address.email
53
+ shipping_details.fax = i_transaction.shipping_address.fax
54
+ shipping_details.phone = i_transaction.shipping_address.phone
55
+ end
56
+
57
+ shipping_details
58
+ end
59
+ end
60
+ end
61
+ end
62
+ end
@@ -0,0 +1,27 @@
1
+ module EwayRapid
2
+ module Message
3
+ module Convert
4
+ class InternalTransactionToAddress
5
+
6
+ # @param [InternalModels::Transaction] i_transaction
7
+ # @return [Models::Address]
8
+ def do_convert(i_transaction)
9
+ address = Models::Address.new
10
+
11
+ # @type [InternalModels::ShippingAddress]
12
+ shipping_address = i_transaction.shipping_address
13
+
14
+ if shipping_address
15
+ address.state = shipping_address.state
16
+ address.street1 = shipping_address.street1
17
+ address.postal_code = shipping_address.postal_code
18
+ address.city = shipping_address.city
19
+ address.country = shipping_address.country
20
+ address.street2 = shipping_address.street2
21
+ end
22
+ address
23
+ end
24
+ end
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,55 @@
1
+ module EwayRapid
2
+ module Message
3
+ module Convert
4
+ class InternalTransactionToStatus
5
+
6
+ # @param [InternalModels::Transaction] transaction
7
+ # @return [Models::TransactionStatus]
8
+ def do_convert(transaction)
9
+ transaction_status = Models::TransactionStatus.new
10
+ transaction_status.beagle_score = transaction.beagle_score if transaction.beagle_score
11
+ transaction_status.status = transaction.transaction_status
12
+ transaction_status.total = transaction.total_amount
13
+ transaction_status.processing_details = get_processing_details(transaction)
14
+ transaction_status.verification_result = get_verification_result(transaction)
15
+ begin
16
+ transaction_status.transaction_id = Integer(transaction.transaction_id) if transaction.transaction_id
17
+ rescue
18
+ raise ArgumentError.new 'Invalid transaction id when converting transaction to internal transaction status'
19
+ end
20
+ transaction_status
21
+ end
22
+
23
+ # @param [InternalModels::Transaction] transaction
24
+ # @return [Models::ProcessingDetails]
25
+ def get_processing_details(transaction)
26
+ processing_details = Models::ProcessingDetails.new
27
+ processing_details.authorisation_code = transaction.authorisation_code
28
+ processing_details.response_code = transaction.response_code
29
+ processing_details.response_message = transaction.response_message
30
+ processing_details
31
+ end
32
+
33
+ # @param [InternalModels::Transaction] transaction
34
+ def get_verification_result(transaction)
35
+ converter = VerificationToVerificationResult.new
36
+ verification_result = converter.do_convert(transaction.verification)
37
+ if transaction.beagle_verification
38
+ verification_result.beagle_email = get_beagle_status(transaction.beagle_verification.phone)
39
+ verification_result.beagle_phone = get_beagle_status(transaction.beagle_verification.email)
40
+ end
41
+ verification_result
42
+ end
43
+
44
+ def get_beagle_status(status)
45
+ begin
46
+ index = Integer(status)
47
+ Enums::BeagleVerifyStatus.calculate_beagle_status(index)
48
+ rescue StandardError
49
+ return nil
50
+ end
51
+ end
52
+ end
53
+ end
54
+ end
55
+ end