figo 1.2.5 → 1.3.3
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/Gemfile +1 -0
- data/config.yml +4 -0
- data/console_demo.rb +1 -1
- data/figo.gemspec +3 -3
- data/lib/account/api_call.rb +55 -0
- data/lib/account/model.rb +122 -0
- data/lib/account_balance/api_call.rb +18 -0
- data/lib/account_balance/model.rb +31 -0
- data/lib/authentification/api_call.rb +88 -0
- data/lib/bank/api_call.rb +49 -0
- data/lib/bank/model.rb +23 -0
- data/lib/base.rb +56 -0
- data/lib/cacert.pem +0 -0
- data/lib/figo.rb +54 -380
- data/lib/helpers/error.rb +20 -0
- data/lib/helpers/https.rb +52 -0
- data/lib/notification/api_call.rb +40 -0
- data/lib/notification/model.rb +27 -0
- data/lib/payment/api_call.rb +71 -0
- data/lib/payment/model.rb +75 -0
- data/lib/process/api_call.rb +17 -0
- data/lib/process/model.rb +34 -0
- data/lib/security/api_call.rb +59 -0
- data/lib/security/model.rb +83 -0
- data/lib/standing_order/api_call.rb +24 -0
- data/lib/standing_order/model.rb +75 -0
- data/lib/synchronization_status/api_call.rb +27 -0
- data/lib/synchronization_status/model.rb +23 -0
- data/lib/task/api_call.rb +37 -0
- data/lib/task/model.rb +43 -0
- data/lib/transaction/api_call.rb +57 -0
- data/lib/transaction/model.rb +75 -0
- data/lib/user/api_call.rb +46 -0
- data/lib/user/model.rb +55 -0
- data/test/config.yml +7 -0
- data/test/test_account_sync_and_setup.rb +67 -0
- data/test/test_accounts.rb +106 -0
- data/test/test_authentififcation.rb +68 -0
- data/test/test_business_processes.rb +43 -0
- data/test/test_figo.rb +5 -86
- data/test/test_notifications.rb +83 -0
- data/test/test_payments.rb +106 -0
- data/test/test_securities.rb +70 -0
- data/test/test_standing_orders.rb +49 -0
- data/test/test_transactions.rb +87 -0
- data/test/test_user_management.rb +91 -0
- metadata +64 -14
- data/lib/models.rb +0 -466
@@ -0,0 +1,24 @@
|
|
1
|
+
require_relative "model.rb"
|
2
|
+
module Figo
|
3
|
+
# Retreive a specific standing order.
|
4
|
+
# @param standing_order_id [String] - ID of standing order to retreive
|
5
|
+
# @param cents [Boolean] - whether to show the balance in cents (optional)
|
6
|
+
# @return [StandingOrder] - a single `standing_order` hash.
|
7
|
+
def get_standing_order(standing_order_id)
|
8
|
+
query_api_object StandingOrder, "/rest/standing_orders/" + standing_order_id, nil, "GET", nil
|
9
|
+
end
|
10
|
+
|
11
|
+
# Get all standing orders.
|
12
|
+
# @param cents [Boolean] - whether to show the balance in cents (optional)
|
13
|
+
# @return [StandingOrder] a list of `standing_order` objects.
|
14
|
+
def get_standing_orders()
|
15
|
+
query_api_object StandingOrder, "/rest/standing_orders", nil, "GET", "standing_orders"
|
16
|
+
end
|
17
|
+
|
18
|
+
# Get all standing orders.
|
19
|
+
# @param account_id [Boolean] - ID of account to standing order
|
20
|
+
# @return [StandingOrder] a list of `standing_order` objects.
|
21
|
+
def get_account_standing_orders(account_id)
|
22
|
+
query_api_object StandingOrder, "/rest/accounts/#{account_id}/standing_orders", nil, "GET", "standing_orders"
|
23
|
+
end
|
24
|
+
end
|
@@ -0,0 +1,75 @@
|
|
1
|
+
require_relative "../base.rb"
|
2
|
+
module Figo
|
3
|
+
# Object representing a Payment
|
4
|
+
class StandingOrder < Base
|
5
|
+
@dump_attributes = []
|
6
|
+
|
7
|
+
def initialize(session, json)
|
8
|
+
super(session, json)
|
9
|
+
end
|
10
|
+
|
11
|
+
# Name of creditor or debtor
|
12
|
+
# @return [String]
|
13
|
+
attr_accessor :name
|
14
|
+
|
15
|
+
# Internal figo Connect standing order ID
|
16
|
+
# @return [String]
|
17
|
+
attr_accessor :standing_order_id
|
18
|
+
|
19
|
+
# Internal figo Connect account ID
|
20
|
+
# @return [String]
|
21
|
+
attr_accessor :account_id
|
22
|
+
|
23
|
+
# First execution date of the standing order
|
24
|
+
# @return [Date]
|
25
|
+
attr_accessor :first_execution_date
|
26
|
+
|
27
|
+
# Last execution date of the standing order (this field might be emtpy, if no last execution date is set)
|
28
|
+
# @return [Date]
|
29
|
+
attr_accessor :last_execution_date
|
30
|
+
|
31
|
+
# The day the standing order gets executed
|
32
|
+
# @return [Number]
|
33
|
+
attr_accessor :execution_day
|
34
|
+
|
35
|
+
# The interval the standing order gets executed (possible values are weekly, monthly, two monthly, quarterly, half yearly and yearly)
|
36
|
+
# @return [String]
|
37
|
+
attr_accessor :interval
|
38
|
+
|
39
|
+
# Name of recipient
|
40
|
+
# @return [String]
|
41
|
+
attr_accessor :name
|
42
|
+
|
43
|
+
# Account number recipient
|
44
|
+
# @return [String]
|
45
|
+
attr_accessor :account_number
|
46
|
+
|
47
|
+
# Bank code of recipient
|
48
|
+
# @return [String]
|
49
|
+
attr_accessor :bank_code
|
50
|
+
|
51
|
+
# Bank name of recipient
|
52
|
+
# @return [String]
|
53
|
+
attr_accessor :bank_name
|
54
|
+
|
55
|
+
# Standing order amount
|
56
|
+
# @return [Number]
|
57
|
+
attr_accessor :amount
|
58
|
+
|
59
|
+
# Three-character currency code
|
60
|
+
# @return [String]
|
61
|
+
attr_accessor :currency
|
62
|
+
|
63
|
+
# Purpose text (this field might be empty if the standing order has no purpose)
|
64
|
+
# @return [String]
|
65
|
+
attr_accessor :purpose
|
66
|
+
|
67
|
+
# Internal creation timestamp on the figo Connect server
|
68
|
+
# @return [Date]
|
69
|
+
attr_accessor :creation_timestamp
|
70
|
+
|
71
|
+
# Internal modification timestamp on the figo
|
72
|
+
# @return [Date]
|
73
|
+
attr_accessor :modification_timestamp
|
74
|
+
end
|
75
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
require_relative "model.rb"
|
2
|
+
module Figo
|
3
|
+
# Retrieve the URL a user should open in the web browser to start the synchronization process.
|
4
|
+
#
|
5
|
+
# @param redirect_uri [String] The user will be redirected to this URL after the sync process completes.
|
6
|
+
# @param state [String] This string will be passed on through the complete synchronization process
|
7
|
+
# @return [String] The result parameter is the URL to be opened by the user.
|
8
|
+
def get_sync_url(redirect_uri, state)
|
9
|
+
res = query_api "/rest/sync", {redirect_uri: redirect_uri, state: state}.to_query, "POST"
|
10
|
+
|
11
|
+
"https://" + Config.api_endpoint + "/task/start?id=" + res["task_token"]
|
12
|
+
end
|
13
|
+
|
14
|
+
# Retrieve the URL a user should open in the web browser to start the synchronization process.
|
15
|
+
#
|
16
|
+
# @param redirect_uri [String] the user will be redirected to this URL after the process completes
|
17
|
+
# @param state [String] this string will be passed on through the complete synchronization process
|
18
|
+
# and to the redirect target at the end. It should be used to validated the authenticity of
|
19
|
+
# the call to the redirect URL
|
20
|
+
# @param if_not_synced_since [Integer] if this parameter is set, only those accounts will be
|
21
|
+
# synchronized, which have not been synchronized within the specified number of minutes.
|
22
|
+
# @return [String] the URL to be opened by the user.
|
23
|
+
def sync_url(redirect_uri, state, if_not_synced_since = 0)
|
24
|
+
response = query_api "/rest/sync", {"redirect_uri" => redirect_uri, "state" => state, "if_not_synced_since" => if_not_synced_since}, "POST"
|
25
|
+
return "https://#{$api_endpoint}/task/start?id=#{response["task_token"]}"
|
26
|
+
end
|
27
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
require_relative "../base.rb"
|
2
|
+
module Figo
|
3
|
+
# Object representing the bank server synchronization status
|
4
|
+
class SynchronizationStatus < Base
|
5
|
+
@dump_attributes = []
|
6
|
+
|
7
|
+
# Internal figo Connect status code
|
8
|
+
# @return [Integer]
|
9
|
+
attr_accessor :code
|
10
|
+
|
11
|
+
# Human-readable error message
|
12
|
+
# @return [String]
|
13
|
+
attr_accessor :message
|
14
|
+
|
15
|
+
# Timestamp of last synchronization
|
16
|
+
# @return [DateTime]
|
17
|
+
attr_accessor :sync_timestamp
|
18
|
+
|
19
|
+
# Timestamp of last successful synchronization
|
20
|
+
# @return [DateTime]
|
21
|
+
attr_accessor :success_timestamp
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,37 @@
|
|
1
|
+
require_relative "model.rb"
|
2
|
+
module Figo
|
3
|
+
# Start communication with bank server.
|
4
|
+
#
|
5
|
+
# @param task_token [Object] Task token object from the initial request
|
6
|
+
def start_task(task_token)
|
7
|
+
query_api("/task/start?id=" + task_token.task_token, nil, "GET");
|
8
|
+
end
|
9
|
+
|
10
|
+
# Poll the task progress.
|
11
|
+
#
|
12
|
+
# @param task [Object] - Task object
|
13
|
+
# @param options [Object] - further options (optional)
|
14
|
+
# @param options.pin [Boolean] - submit PIN
|
15
|
+
# @param options.continue [Boolean] - this flag signals to continue after an error condition or to skip a PIN or challenge-response entry
|
16
|
+
# @param options.save_pin [Boolean] - this flag indicates whether the user has chosen to save the PIN on the figo Connect server
|
17
|
+
# @param options.response [Boolean] - submit response to challenge
|
18
|
+
# @return [TaskState] The result parameter is a TaskState object which represents the current status of the task.
|
19
|
+
def get_task_state(task, options)
|
20
|
+
options ||= {}
|
21
|
+
options["id"] = task["task_token"]
|
22
|
+
if (options.pin)
|
23
|
+
options.save_pin ||= 0
|
24
|
+
end
|
25
|
+
options.continue ||= 0
|
26
|
+
|
27
|
+
query_api_object TaskState, "/task/progress?id=" + task.task_token, options.to_query, "POST", nil
|
28
|
+
end
|
29
|
+
|
30
|
+
# Cancel a task.
|
31
|
+
#
|
32
|
+
# @param task_token [Object] Task token object
|
33
|
+
def cancel_task(task_token)
|
34
|
+
options["id"] = task_token["task_token"]
|
35
|
+
query_api_object TaskToken, "/task/cancel?id=" + task_token["task_token"], options.to_query, "POST", nil
|
36
|
+
end
|
37
|
+
end
|
data/lib/task/model.rb
ADDED
@@ -0,0 +1,43 @@
|
|
1
|
+
require_relative "../base.rb"
|
2
|
+
module Figo
|
3
|
+
|
4
|
+
class TaskToken < Base
|
5
|
+
@dump_attributes = [:task_token]
|
6
|
+
|
7
|
+
def initialize(session, json)
|
8
|
+
super(session, json)
|
9
|
+
end
|
10
|
+
# Name of creditor or debtor
|
11
|
+
# @param task_token [Hash] - Task ID
|
12
|
+
attr_accessor :task_token
|
13
|
+
end
|
14
|
+
|
15
|
+
class TaskState < Base
|
16
|
+
@dump_attributes = [:account_id, :message, :is_waiting_for_pin, :is_waiting_for_response, :is_erroneous, :is_ended, :challenge]
|
17
|
+
|
18
|
+
def initialize(session, json)
|
19
|
+
super(session, json)
|
20
|
+
end
|
21
|
+
|
22
|
+
# @param account_id [String] - Account ID of currently processed accoount
|
23
|
+
attr_accessor :account_id
|
24
|
+
|
25
|
+
# @param message [String] - Status message or error message for currently processed amount
|
26
|
+
attr_accessor :message
|
27
|
+
|
28
|
+
# @param is_waiting_for_pin [Boolean] - The figo Connect server is waiting for PIN
|
29
|
+
attr_accessor :is_waiting_for_pin
|
30
|
+
|
31
|
+
# @param is_waiting_for_response [Boolean] - The figo Connect server is waiting for a response to the parameter challenge
|
32
|
+
attr_accessor :is_waiting_for_response
|
33
|
+
|
34
|
+
# @param is_erroneous [Boolean] - An error occured and the figo Connect server is waiting for continuation
|
35
|
+
attr_accessor :is_erroneous
|
36
|
+
|
37
|
+
# @param is_ended [Boolean] - The communication with a bank server has been completed
|
38
|
+
attr_accessor :is_ended
|
39
|
+
|
40
|
+
# @param challenge [Object] - A challenge object
|
41
|
+
attr_accessor :challenge
|
42
|
+
end
|
43
|
+
end
|
@@ -0,0 +1,57 @@
|
|
1
|
+
require_relative "model.rb"
|
2
|
+
module Figo
|
3
|
+
# Retrieve list of transactions (on all or a specific account)
|
4
|
+
#
|
5
|
+
# @param account_id [String] ID of the account for which to list the transactions
|
6
|
+
# @param since [String, Date] this parameter can either be a transaction ID or a date
|
7
|
+
# @param count [Integer] limit the number of returned transactions
|
8
|
+
# @param offset [Integer] which offset into the result set should be used to determin the first transaction to return (useful in combination with count)
|
9
|
+
# @param include_pending [Boolean] this flag indicates whether pending transactions should be included
|
10
|
+
# in the response; pending transactions are always included as a complete set, regardless of
|
11
|
+
# the `since` parameter
|
12
|
+
# @return [Array] an array of `Transaction` objects, one for each transaction of the user
|
13
|
+
def transactions(account_id = nil, since = nil, count = 1000, offset = 0, include_pending = false)
|
14
|
+
data = {"count" => count.to_s, "offset" => offset.to_s, "include_pending" => include_pending ? "1" : "0"}
|
15
|
+
data["since"] = ((since.is_a?(Date) ? since.to_s : since) unless since.nil?)
|
16
|
+
|
17
|
+
query_api_object Transaction, (account_id.nil? ? "/rest/transactions?" : "/rest/accounts/#{account_id}/transactions?") + URI.encode_www_form(data), nil, "GET", "transactions"
|
18
|
+
end
|
19
|
+
|
20
|
+
# Retrieve a specific transaction
|
21
|
+
#
|
22
|
+
# @param account_id [String] ID of the account on which the transaction occured
|
23
|
+
# @param transaction_id [String] ID of the transaction to be retrieved
|
24
|
+
# @return [Transaction] transaction object
|
25
|
+
def get_transaction(account_id, transaction_id)
|
26
|
+
query_api_object Transaction, "/rest/accounts/#{account_id}/transactions/#{transaction_id}"
|
27
|
+
end
|
28
|
+
|
29
|
+
# Modify trasnaction
|
30
|
+
#
|
31
|
+
# @param account_id [String] ID of an account the transaction belongs to
|
32
|
+
# @param transaction_id [String] ID of the transaction
|
33
|
+
# @param visited [Boolean] a bit showing whether the user has already seen this transaction or not
|
34
|
+
def modify_transaction(account_id, transaction_id, visited)
|
35
|
+
query_api_object Transaction, "/rest/accounts/" + account_id + "/transactions/" + transaction_id, {"visited" => visited}, "PUT"
|
36
|
+
end
|
37
|
+
|
38
|
+
# Modify transactions
|
39
|
+
#
|
40
|
+
# @param visited [Boolean] a bit showing whether the user has already seen this transaction or not
|
41
|
+
# @param account_id [String] ID of the account transactions belongs to (optional)
|
42
|
+
def modify_transactions(visited, account_id = nil)
|
43
|
+
if account_id
|
44
|
+
query_api "/rest/accounts/" + account_id + "/transactions", {"visited" => visited}, "PUT"
|
45
|
+
else
|
46
|
+
query_api "/rest/transactions", {"visited" => visited}, "PUT"
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
# Delete transaction
|
51
|
+
#
|
52
|
+
# @param account_id [String] ID of an account the transaction belongs to
|
53
|
+
# @param transaction_id [String] ID of transaction to be deleted
|
54
|
+
def delete_transaction(account_id, transaction_id)
|
55
|
+
query_api "/rest/accounts/" + account_id + "/transactions/" + transaction_id, nil, "DELETE"
|
56
|
+
end
|
57
|
+
end
|
@@ -0,0 +1,75 @@
|
|
1
|
+
require_relative "../base.rb"
|
2
|
+
module Figo
|
3
|
+
# Object representing one bank transaction on a certain bank account of the User
|
4
|
+
class Transaction < Base
|
5
|
+
@dump_attributes = []
|
6
|
+
|
7
|
+
def initialize(session, json)
|
8
|
+
super(session, json)
|
9
|
+
end
|
10
|
+
|
11
|
+
# Internal figo Connect transaction ID
|
12
|
+
# @return [String]
|
13
|
+
attr_accessor :transaction_id
|
14
|
+
|
15
|
+
# Internal figo Connect account ID
|
16
|
+
# @return [String]
|
17
|
+
attr_accessor :account_id
|
18
|
+
|
19
|
+
# Name of originator or recipient
|
20
|
+
# @return [String]
|
21
|
+
attr_accessor :name
|
22
|
+
|
23
|
+
# Account number of originator or recipient
|
24
|
+
# @return [String]
|
25
|
+
attr_accessor :account_number
|
26
|
+
|
27
|
+
# Bank code of originator or recipient
|
28
|
+
# @return [String]
|
29
|
+
attr_accessor :bank_code
|
30
|
+
|
31
|
+
# Bank name of originator or recipient
|
32
|
+
# @return [String]
|
33
|
+
attr_accessor :bank_name
|
34
|
+
|
35
|
+
# Transaction amount
|
36
|
+
# @return [DecNum]
|
37
|
+
attr_accessor :amount
|
38
|
+
|
39
|
+
# Three-character currency code
|
40
|
+
# @return [String]
|
41
|
+
attr_accessor :currency
|
42
|
+
|
43
|
+
# Booking date
|
44
|
+
# @return [Date]
|
45
|
+
attr_accessor :booking_date
|
46
|
+
|
47
|
+
# Value date
|
48
|
+
# @return [Date]
|
49
|
+
attr_accessor :value_date
|
50
|
+
|
51
|
+
# Purpose text
|
52
|
+
# @return [String]
|
53
|
+
attr_accessor :purpose
|
54
|
+
|
55
|
+
# Transaction type
|
56
|
+
# @return [String]
|
57
|
+
attr_accessor :type
|
58
|
+
|
59
|
+
# Booking text
|
60
|
+
# @return [String]
|
61
|
+
attr_accessor :booking_text
|
62
|
+
|
63
|
+
# This flag indicates whether the transaction is booked or pending
|
64
|
+
# @return [Boolean]
|
65
|
+
attr_accessor :booked
|
66
|
+
|
67
|
+
# Internal creation timestamp on the figo Connect server
|
68
|
+
# @return [DateTime]
|
69
|
+
attr_accessor :creation_timestamp
|
70
|
+
|
71
|
+
# Internal modification timestamp on the figo Connect server
|
72
|
+
# @return [DateTime]
|
73
|
+
attr_accessor :modification_timestamp
|
74
|
+
end
|
75
|
+
end
|
@@ -0,0 +1,46 @@
|
|
1
|
+
require_relative "model.rb"
|
2
|
+
module Figo
|
3
|
+
# Retrieve current User
|
4
|
+
#
|
5
|
+
# @return [User] the current user
|
6
|
+
def user
|
7
|
+
query_api_object User, "/rest/user"
|
8
|
+
end
|
9
|
+
|
10
|
+
# Modify the current user
|
11
|
+
#
|
12
|
+
# @param user [User] the modified user object to be saved
|
13
|
+
# @return [User] the modified user returned
|
14
|
+
def modify_user(user)
|
15
|
+
query_api_object User, "/rest/user", user.dump(), "PUT"
|
16
|
+
end
|
17
|
+
|
18
|
+
# Remove the current user
|
19
|
+
# Note: this has immidiate effect and you wont be able to interact with the user after this call
|
20
|
+
#
|
21
|
+
def remove_user
|
22
|
+
query_api "/rest/user", nil, "DELETE"
|
23
|
+
end
|
24
|
+
|
25
|
+
# Re-send verification email
|
26
|
+
#
|
27
|
+
def resend_verification
|
28
|
+
query_api "/rest/user/resend_verification", nil, "POST"
|
29
|
+
end
|
30
|
+
|
31
|
+
# Create a new figo Account
|
32
|
+
# @param name [String] First and last name
|
33
|
+
# @param email [String] Email address; It must obey the figo username & password policy
|
34
|
+
# @param password [String] New figo Account password; It must obey the figo username & password policy
|
35
|
+
# @param language [String] Two-letter code of preferred language
|
36
|
+
# @param send_newsletter [Boolean] This flag indicates whether the user has agreed to be contacted by email
|
37
|
+
# @return [Hash] an object with the key `recovery_password` as documented in the figo Connect API specification.
|
38
|
+
def create_user(name, email, password, language, send_newsletter=nil)
|
39
|
+
options = { name: name, email: email, password: password, send_newsletter: send_newsletter }
|
40
|
+
options["language"] = language if (language)
|
41
|
+
options["send_newsletter"] = !!send_newsletter == send_newsletter ? send_newsletter : nil
|
42
|
+
|
43
|
+
query_api "/auth/user", options
|
44
|
+
end
|
45
|
+
|
46
|
+
end
|
data/lib/user/model.rb
ADDED
@@ -0,0 +1,55 @@
|
|
1
|
+
require_relative "../base.rb"
|
2
|
+
module Figo
|
3
|
+
# Object representing an User
|
4
|
+
class User < Base
|
5
|
+
@dump_attributes = [:name, :address, :send_newsletter, :language]
|
6
|
+
|
7
|
+
def initialize(session, json)
|
8
|
+
super(session, json)
|
9
|
+
end
|
10
|
+
|
11
|
+
# Internal figo Connect User ID
|
12
|
+
# @return [String]
|
13
|
+
attr_accessor :User_id
|
14
|
+
|
15
|
+
# First and last name
|
16
|
+
# @return [String]
|
17
|
+
attr_accessor :name
|
18
|
+
|
19
|
+
# Email address
|
20
|
+
# @return [String]
|
21
|
+
attr_accessor :email
|
22
|
+
|
23
|
+
#Postal address for bills, etc.
|
24
|
+
# @return [Dict]
|
25
|
+
attr_accessor :address
|
26
|
+
|
27
|
+
# This flag indicates whether the email address has been verified
|
28
|
+
# @return [Boolean]
|
29
|
+
attr_accessor :verified_email
|
30
|
+
|
31
|
+
# This flag indicates whether the User has agreed to be contacted by email
|
32
|
+
# @return [Boolean]
|
33
|
+
attr_accessor :send_newsletter
|
34
|
+
|
35
|
+
# Two-letter code of preferred language
|
36
|
+
# @return [String]
|
37
|
+
attr_accessor :language
|
38
|
+
|
39
|
+
# This flag indicates whether the figo Account plan is free or premium
|
40
|
+
# @return [Boolean]
|
41
|
+
attr_accessor :premium
|
42
|
+
|
43
|
+
# Timestamp of premium figo Account expiry
|
44
|
+
# @return [DateTime]
|
45
|
+
attr_accessor :premium_expires_on
|
46
|
+
|
47
|
+
# Provider for premium subscription or nil of no subscription is active
|
48
|
+
# @return [String]
|
49
|
+
attr_accessor :premium_subscription
|
50
|
+
|
51
|
+
# Timestamp of figo Account registration
|
52
|
+
# @return [DateTime]
|
53
|
+
attr_accessor :join_date
|
54
|
+
end
|
55
|
+
end
|