golf_switch 1.0.0
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +18 -0
- data/Gemfile +6 -0
- data/LICENSE.txt +22 -0
- data/README.md +127 -0
- data/Rakefile +1 -0
- data/examples/area_test.rb +15 -0
- data/examples/book_golf.rb +74 -0
- data/examples/cancel_booking.rb +78 -0
- data/examples/course_avail.rb +26 -0
- data/examples/course_avail_list.rb +33 -0
- data/examples/course_info.rb +15 -0
- data/examples/course_list.rb +15 -0
- data/examples/course_policy_test.rb +15 -0
- data/golf_switch.gemspec +20 -0
- data/lib/golf_switch.rb +42 -0
- data/lib/golf_switch/alt_rate_type.rb +28 -0
- data/lib/golf_switch/area.rb +52 -0
- data/lib/golf_switch/area_response.rb +27 -0
- data/lib/golf_switch/available_course.rb +53 -0
- data/lib/golf_switch/book_golf.rb +41 -0
- data/lib/golf_switch/book_golf_item.rb +50 -0
- data/lib/golf_switch/cancel_golf.rb +49 -0
- data/lib/golf_switch/cancel_golf_response.rb +16 -0
- data/lib/golf_switch/configuration.rb +28 -0
- data/lib/golf_switch/country.rb +30 -0
- data/lib/golf_switch/country_region.rb +29 -0
- data/lib/golf_switch/course.rb +28 -0
- data/lib/golf_switch/course_avail.rb +73 -0
- data/lib/golf_switch/course_avail_date.rb +25 -0
- data/lib/golf_switch/course_avail_list.rb +85 -0
- data/lib/golf_switch/course_avail_request.rb +56 -0
- data/lib/golf_switch/course_avail_time.rb +31 -0
- data/lib/golf_switch/course_info.rb +38 -0
- data/lib/golf_switch/course_info_course.rb +90 -0
- data/lib/golf_switch/course_list.rb +62 -0
- data/lib/golf_switch/course_list_course.rb +27 -0
- data/lib/golf_switch/course_policy.rb +14 -0
- data/lib/golf_switch/course_policy_response.rb +18 -0
- data/lib/golf_switch/get_alt_rate_type.rb +42 -0
- data/lib/golf_switch/get_course_policy.rb +50 -0
- data/lib/golf_switch/get_golf_booking.rb +49 -0
- data/lib/golf_switch/golf_book.rb +42 -0
- data/lib/golf_switch/golf_book_info.rb +17 -0
- data/lib/golf_switch/payment.rb +39 -0
- data/lib/golf_switch/player.rb +35 -0
- data/lib/golf_switch/region_area.rb +13 -0
- data/lib/golf_switch/request.rb +62 -0
- data/lib/golf_switch/score_card.rb +5 -0
- data/lib/golf_switch/version.rb +3 -0
- metadata +110 -0
@@ -0,0 +1,62 @@
|
|
1
|
+
module GolfSwitch
|
2
|
+
class CourseList < GolfSwitch::Request
|
3
|
+
attr_accessor :country_id,:region_id,:area,:latitude,:longitude,:postal_code
|
4
|
+
attr_accessor :max_distance,:max_distance_type,:show_all_status,:show_dis_connected,:featured_only,:sort
|
5
|
+
attr_accessor :api_response
|
6
|
+
def initialize(attributes = {})
|
7
|
+
attributes.each do |name, value|
|
8
|
+
begin
|
9
|
+
send("#{name}=", value)
|
10
|
+
end
|
11
|
+
end
|
12
|
+
@max_distance_type = "M" unless ["M","K"].include?(@max_distance_type)
|
13
|
+
@country_id ||="USA"
|
14
|
+
end
|
15
|
+
|
16
|
+
def option_attributes
|
17
|
+
options = {}
|
18
|
+
options.merge!("CountryId"=>@country_id) unless @country_id.blank?
|
19
|
+
options.merge!("RegionId"=>@region_id) unless @region_id.blank?
|
20
|
+
options.merge!("Area"=>@area) unless @area.blank?
|
21
|
+
options.merge!("Latitude"=>@latitude) unless @latitude.blank?
|
22
|
+
options.merge!("Longitude"=>@longitude) unless @longitude.blank?
|
23
|
+
options.merge!("PostalCode"=>@postal_code) unless @postal_code.blank?
|
24
|
+
options.merge!("MaxDistance"=>@max_distance) unless @max_distance.blank?
|
25
|
+
options.merge!("MaxDistanceType"=>@max_distance_type) if !@max_distance.blank? && !@max_distance_type.blank?
|
26
|
+
options.merge!("ShowDisConnected"=>@show_dis_connected) unless @show_dis_connected.blank?
|
27
|
+
options.merge!("FeaturedOnly"=>@featured_only) unless @featured_only.blank?
|
28
|
+
options.merge!("Sort"=>@sort) if !@sort.blank? && ["N",""].include?(@sort)
|
29
|
+
options
|
30
|
+
end
|
31
|
+
|
32
|
+
def get_options
|
33
|
+
{
|
34
|
+
"Req"=>
|
35
|
+
option_attributes
|
36
|
+
|
37
|
+
}
|
38
|
+
end
|
39
|
+
|
40
|
+
def commit
|
41
|
+
super("course_list")
|
42
|
+
end
|
43
|
+
|
44
|
+
def parse_error
|
45
|
+
@response[:course_list_response][:course_list_result]
|
46
|
+
end
|
47
|
+
|
48
|
+
def parse_response
|
49
|
+
begin
|
50
|
+
unless error?
|
51
|
+
@api_response = CourseListCourse.parse_courses(@response[:course_list_response][:course_list_result])
|
52
|
+
else
|
53
|
+
puts "Error #{error_message}"
|
54
|
+
end
|
55
|
+
rescue
|
56
|
+
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
end
|
61
|
+
|
62
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
module GolfSwitch
|
2
|
+
class CourseListCourse < GolfSwitch::Course
|
3
|
+
def initialize(attributes={})
|
4
|
+
attributes.each do |name, value|
|
5
|
+
begin
|
6
|
+
send("#{name}=", value)
|
7
|
+
end
|
8
|
+
end
|
9
|
+
end
|
10
|
+
def self.parse_courses(response_hash)
|
11
|
+
courses= []
|
12
|
+
|
13
|
+
if response_hash[:courses] && response_hash[:courses][:cl_course]
|
14
|
+
if response_hash[:courses][:cl_course].is_a?(Array)
|
15
|
+
response_hash[:courses][:cl_course].each do |course|
|
16
|
+
begin
|
17
|
+
courses << CourseListCourse.new(course.merge(:img_base=>response_hash[:img_base]))
|
18
|
+
end
|
19
|
+
end
|
20
|
+
elsif response_hash[:courses][:cl_course].is_a?(Hash)
|
21
|
+
courses << CourseListCourse.new(response_hash[:courses][:cl_course].merge(:img_base=>response_hash[:img_base]))
|
22
|
+
end
|
23
|
+
end
|
24
|
+
courses
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
module GolfSwitch
|
2
|
+
class CoursePolicyResponse
|
3
|
+
attr_accessor :ret_cd,:ret_msg,:note,:cxl_policy,:rate_policy,:misc_policies
|
4
|
+
def initialize(attributes={})
|
5
|
+
attributes.each do |name, value|
|
6
|
+
begin
|
7
|
+
if name.to_s =="cxl_policy"
|
8
|
+
@cxl_policy = GolfSwitch::CoursePolicy.new(value)
|
9
|
+
else
|
10
|
+
send("#{name}=", value)
|
11
|
+
end
|
12
|
+
rescue
|
13
|
+
puts "Add #{name} is accessor in course policy response"
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
@@ -0,0 +1,42 @@
|
|
1
|
+
module GolfSwitch
|
2
|
+
class GetAltRateType < GolfSwitch::Request
|
3
|
+
attr_accessor :alt_rate_type_id
|
4
|
+
|
5
|
+
def initialize(alt_rate_type_id)
|
6
|
+
@alt_rate_type_id = alt_rate_type_id
|
7
|
+
end
|
8
|
+
|
9
|
+
def get_options
|
10
|
+
{
|
11
|
+
"Req"=>option_attributes
|
12
|
+
}
|
13
|
+
end
|
14
|
+
|
15
|
+
def option_attributes
|
16
|
+
{
|
17
|
+
"AltRateTypeId"=>@alt_rate_type_id
|
18
|
+
}
|
19
|
+
end
|
20
|
+
|
21
|
+
def commit
|
22
|
+
super("get_alt_rate_types")
|
23
|
+
end
|
24
|
+
|
25
|
+
def parse_error
|
26
|
+
@response[:GetAltRateTypesResponse][:get_alt_rate_types_result]
|
27
|
+
end
|
28
|
+
|
29
|
+
def parse_response
|
30
|
+
begin
|
31
|
+
unless error?
|
32
|
+
@api_response = GolfSwitch::GolfBook.parse_golf_books(@response[:book_golf_response][:book_golf_result])
|
33
|
+
else
|
34
|
+
puts "Error #{error_message}"
|
35
|
+
end
|
36
|
+
rescue
|
37
|
+
puts "Parse Error On Alt Rare type"
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
end
|
42
|
+
end
|
@@ -0,0 +1,50 @@
|
|
1
|
+
module GolfSwitch
|
2
|
+
class GetCoursePolicy < GolfSwitch::Request
|
3
|
+
attr_accessor :course_id,:play_date,:alt_rate_type,:api_response
|
4
|
+
|
5
|
+
def initialize(attributes={})
|
6
|
+
attributes.each do |name, value|
|
7
|
+
begin
|
8
|
+
send("#{name}=", value)
|
9
|
+
rescue
|
10
|
+
puts "Add #{name} is not valid"
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
14
|
+
def get_options
|
15
|
+
{
|
16
|
+
"Req"=>
|
17
|
+
option_attributes
|
18
|
+
|
19
|
+
}
|
20
|
+
end
|
21
|
+
def option_attributes
|
22
|
+
options = {}
|
23
|
+
options.merge!("CourseId"=>@course_id) unless @course_id.blank?
|
24
|
+
options.merge!("PlayDate"=>DateTime.parse(@play_date).strftime("%Y-%m-%dT00:00:00")) unless @play_date.blank?
|
25
|
+
options.merge!("AltRateType"=>@alt_rate_type) unless @alt_rate_type.blank?
|
26
|
+
options
|
27
|
+
end
|
28
|
+
|
29
|
+
def commit
|
30
|
+
super("get_course_policies")
|
31
|
+
end
|
32
|
+
|
33
|
+
def parse_error
|
34
|
+
@response[:get_course_policies_response][:get_course_policies_result]
|
35
|
+
end
|
36
|
+
|
37
|
+
def parse_response
|
38
|
+
begin
|
39
|
+
unless error?
|
40
|
+
@api_response = GolfSwitch::CoursePolicyResponse.new(@response[:get_course_policies_response][:get_course_policies_result])
|
41
|
+
else
|
42
|
+
puts "Error #{error_message}"
|
43
|
+
end
|
44
|
+
rescue
|
45
|
+
puts "Parse Error On Getting golf info Response"
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
end
|
50
|
+
end
|
@@ -0,0 +1,49 @@
|
|
1
|
+
module GolfSwitch
|
2
|
+
class GetGolfBooking < GolfSwitch::Request
|
3
|
+
attr_accessor :course_id,:tee_date,:confirmation_no,:booking_id,:note
|
4
|
+
|
5
|
+
def initialize(course_id,tee_date,confirmation_no=nil,booking_id=nil)
|
6
|
+
@course_id = course_id
|
7
|
+
@tee_date = tee_date
|
8
|
+
@confirmation_no = confirmation_no
|
9
|
+
@booking_id = booking_id
|
10
|
+
end
|
11
|
+
|
12
|
+
def get_options
|
13
|
+
{
|
14
|
+
"Req"=>
|
15
|
+
option_attributes
|
16
|
+
}
|
17
|
+
end
|
18
|
+
|
19
|
+
def option_attributes
|
20
|
+
options = {}
|
21
|
+
options.merge!("CourseId"=>@course_id)
|
22
|
+
options.merge!("TeeDate"=>DateTime.parse(@tee_date).strftime("%Y-%m-%dT00:00:00"))
|
23
|
+
options.merge!("ConfirmationNo"=>@confirmation_no) unless @confirmation_no.blank?
|
24
|
+
options.merge!("BookingId"=>@booking_id) unless @booking_id.blank?
|
25
|
+
options
|
26
|
+
end
|
27
|
+
|
28
|
+
def commit
|
29
|
+
super("get_golf_booking")
|
30
|
+
end
|
31
|
+
|
32
|
+
def parse_error
|
33
|
+
@response[:get_golf_booking_response][:get_golf_booking_result]
|
34
|
+
end
|
35
|
+
|
36
|
+
def parse_response
|
37
|
+
begin
|
38
|
+
unless error?
|
39
|
+
@api_response = GolfSwitch::GolfBookInfo.new(@response[:get_golf_booking_response][:get_golf_booking_result])
|
40
|
+
else
|
41
|
+
puts "Error #{error_message}"
|
42
|
+
end
|
43
|
+
rescue
|
44
|
+
puts "Parse Error On Getting golf info Response"
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
end
|
49
|
+
end
|
@@ -0,0 +1,42 @@
|
|
1
|
+
module GolfSwitch
|
2
|
+
class GolfBook
|
3
|
+
attr_accessor :rc,:msg,:course_id,:course_xid,:course_name,:course_phone,:course_email
|
4
|
+
attr_accessor :course_note,:on_req,:play_date,:play_time,:num_players,:confirmation_no
|
5
|
+
attr_accessor :booking_id,:tot_greens_fee,:curr_greens_fee,:tot_trans_fee,:tot_cc_charged
|
6
|
+
attr_accessor :curr_charged,:tot_voucher_charged,:tot_non_refundable,:tot_golf_pass_rounds
|
7
|
+
attr_accessor :img,:cxl_policy,:course_x_id,:rate_policy
|
8
|
+
|
9
|
+
def initialize(attributes={})
|
10
|
+
attributes.each do |name, value|
|
11
|
+
begin
|
12
|
+
if name.to_s=="cxl_policy"
|
13
|
+
@cxl_policy = GolfSwitch::CoursePolicy.new(value)
|
14
|
+
else
|
15
|
+
send("#{name}=", value)
|
16
|
+
end
|
17
|
+
rescue
|
18
|
+
puts "Add #{name} as accessor in Golf Book"
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
def self.parse_golf_books(response)
|
24
|
+
golf_books = []
|
25
|
+
if response[:golf_books] && response[:golf_books][:golf_book].is_a?(Array)
|
26
|
+
response[:golf_books][:golf_book].each do |golf_book|
|
27
|
+
golf_books << GolfSwitch::GolfBook.new(response[:golf_books][:golf_book])
|
28
|
+
end
|
29
|
+
elsif response[:golf_books] && response[:golf_books][:golf_book].is_a?(Hash)
|
30
|
+
golf_books << GolfSwitch::GolfBook.new(response[:golf_books][:golf_book])
|
31
|
+
end
|
32
|
+
golf_books
|
33
|
+
end
|
34
|
+
|
35
|
+
def to_hash
|
36
|
+
hash = {}
|
37
|
+
instance_variables.each {|var| hash[var.to_s.delete("@")] = instance_variable_get(var) }
|
38
|
+
hash
|
39
|
+
end
|
40
|
+
|
41
|
+
end
|
42
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
module GolfSwitch
|
2
|
+
class GolfBookInfo
|
3
|
+
attr_accessor :ret_cd,:ret_msg,:res_name,:course_id,:course_xid,:course_name,:tee_date
|
4
|
+
attr_accessor :tee_time,:players,:tot_greens_fee,:greens_fee_curr
|
5
|
+
attr_accessor :tot_trans_fee,:tot_cc_charged,:curr_charged,:charge_curr,:tot_non_refundable
|
6
|
+
attr_accessor :tot_voucher_charged,:tot_cc_credited,:tot_voucher_credited,:cancellation_no
|
7
|
+
def initialize(attributes={})
|
8
|
+
attributes.each do |name, value|
|
9
|
+
begin
|
10
|
+
send("#{name}=", value)
|
11
|
+
rescue
|
12
|
+
puts "Add #{name} as accessor in Golf Book Response"
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,39 @@
|
|
1
|
+
module GolfSwitch
|
2
|
+
|
3
|
+
class Payment
|
4
|
+
# cc_type is VI: Visa,MC: MastercardAX: American Express only
|
5
|
+
attr_accessor :pay_type,:cc_type,:pay_number,:cc_exp_mo,:cc_exp_yr,:cc_cvv
|
6
|
+
attr_accessor :cc_name,:cc_address1,:cc_city,:cc_state,:cc_country,:cc_postal_code,:cc_email
|
7
|
+
attr_accessor :cc_phone,:pay_amount,:pay_curr
|
8
|
+
def initialize(attributes={})
|
9
|
+
attributes.each do |name, value|
|
10
|
+
begin
|
11
|
+
send("#{name}=", value)
|
12
|
+
rescue
|
13
|
+
puts "invalid attribute #{name} in payment"
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
def option_attributes
|
19
|
+
options = {}
|
20
|
+
options.merge!("PayType"=>@pay_type || "CC")
|
21
|
+
options.merge!("CcType"=>@cc_type|| "VI")
|
22
|
+
options.merge!("PayNumber"=>@pay_number)
|
23
|
+
options.merge!("CcExpMo"=>@cc_exp_mo)
|
24
|
+
options.merge!("CcExpYr"=>@cc_exp_yr)
|
25
|
+
options.merge!("CcCVV"=>@cc_cvv) unless @cc_cvv.blank?
|
26
|
+
options.merge!("CcName"=>@cc_name)
|
27
|
+
options.merge!("CcAddress1"=>@cc_address1)
|
28
|
+
options.merge!("CcCity"=>@cc_city)
|
29
|
+
options.merge!("CcState"=>@cc_state)
|
30
|
+
options.merge!("CcCountry"=>@cc_country || "USA")
|
31
|
+
options.merge!("CcPostalCode"=>@cc_postal_code)
|
32
|
+
options.merge!("CcEmail"=>@cc_email) unless @cc_email.blank?
|
33
|
+
options.merge!("CcPhone"=>@cc_phone) unless @cc_phone.blank?
|
34
|
+
options.merge!("PayAmount"=>@pay_amount)
|
35
|
+
options.merge!("PayCurr"=>@pay_curr || "USD")
|
36
|
+
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
module GolfSwitch
|
2
|
+
class Player
|
3
|
+
attr_accessor :profile_id,:first_name,:last_name,:email,:phone,:address1,:city
|
4
|
+
attr_accessor :state,:country,:postal_code,:member_no,:handicap,:rewards_pgm_id,:rewards_id
|
5
|
+
|
6
|
+
def initialize(attributes={})
|
7
|
+
attributes.each do |name, value|
|
8
|
+
begin
|
9
|
+
send("#{name}=", value)
|
10
|
+
rescue
|
11
|
+
puts "invalid attribute #{name} in player"
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
def option_attributes
|
17
|
+
options = {}
|
18
|
+
options.merge!("ProfileId"=>@profile_id) unless @profile_id.blank?
|
19
|
+
options.merge!("FirstName"=>@first_name)
|
20
|
+
options.merge!("LastName"=>@last_name)
|
21
|
+
options.merge!("Email"=>@email)
|
22
|
+
options.merge!("Phone"=>@phone)
|
23
|
+
options.merge!("Address1"=>@address1) unless @address1.blank?
|
24
|
+
options.merge!("City"=>@city)
|
25
|
+
options.merge!("State"=>@state)
|
26
|
+
options.merge!("Country"=>@country || "USA")
|
27
|
+
options.merge!("PostalCode"=>@postal_code)
|
28
|
+
options.merge!("MemberNo"=>@member_no) unless @member_no.blank?
|
29
|
+
options.merge!("Handicap"=>@handicap) unless @handicap.blank? && @handicap!="Handicap"
|
30
|
+
options.merge!("RewardsPgmId"=>@rewards_pgm_id) unless @rewards_pgm_id.blank?
|
31
|
+
options.merge!("RewardsId"=>@rewards_id) unless @rewards_id.blank?
|
32
|
+
options
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
@@ -0,0 +1,13 @@
|
|
1
|
+
module GolfSwitch
|
2
|
+
class RegionArea < AreaResponse
|
3
|
+
def initialize(area_id=nil,name=nil)
|
4
|
+
super(area_id,name)
|
5
|
+
@region_areas = []
|
6
|
+
end
|
7
|
+
|
8
|
+
def self.parse_region_area(area)
|
9
|
+
golfswitch_area = RegionArea.new(area[:id],area[:nm])
|
10
|
+
golfswitch_area
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
@@ -0,0 +1,62 @@
|
|
1
|
+
|
2
|
+
module GolfSwitch
|
3
|
+
class Request
|
4
|
+
attr_accessor :client,:config,:response,:request,:soap_error
|
5
|
+
def commit(method_name)
|
6
|
+
@soap_error = false
|
7
|
+
@config =GolfSwitch.configuration
|
8
|
+
@client = Savon.client({:wsdl=>@config.get_golf_switch_wsdl})
|
9
|
+
# Available Operations
|
10
|
+
# [:areas,:course_list,:course_info,:course_avail_list,:course_avail,:book_golf,
|
11
|
+
# :get_golf_booking,:cancel_golf, :get_alt_rate_types,:get_course_policies]
|
12
|
+
begin
|
13
|
+
@request = @client.call(method_name.to_sym) do
|
14
|
+
message get_authentication_header.merge(get_options)
|
15
|
+
end
|
16
|
+
|
17
|
+
rescue Savon::SOAPFault => error
|
18
|
+
|
19
|
+
@request = error.to_hash
|
20
|
+
@soap_error= true
|
21
|
+
rescue Savon::Error => error
|
22
|
+
@request = error.to_hash
|
23
|
+
@soap_error= true
|
24
|
+
rescue Savon::InvalidResponseError
|
25
|
+
Logger.log "Invalid server response"
|
26
|
+
end
|
27
|
+
@response = @request.body
|
28
|
+
|
29
|
+
end
|
30
|
+
def get_authentication_header
|
31
|
+
|
32
|
+
{
|
33
|
+
"Hdr"=>{
|
34
|
+
"ResellerId"=>@config.reseller_id,
|
35
|
+
"PartnerId"=>@config.partner_id,
|
36
|
+
"SourceCd"=>@config.source_cd || "A",
|
37
|
+
"Lang"=>@config.lang,
|
38
|
+
"UserIp"=>@config.user_ip,
|
39
|
+
"UserSessionId"=>@config.user_session_id,
|
40
|
+
"AccessKey"=>@config.access_key,
|
41
|
+
"Agent"=>@config.agent,
|
42
|
+
"gsSource"=>@config.gs_source,
|
43
|
+
"gsDebug"=>@config.gs_debug || false
|
44
|
+
|
45
|
+
}
|
46
|
+
}
|
47
|
+
end
|
48
|
+
|
49
|
+
def error?
|
50
|
+
parse_error[:ret_cd].to_i != 0 || @soap_error
|
51
|
+
end
|
52
|
+
|
53
|
+
def error_message
|
54
|
+
if @soap_error
|
55
|
+
@request
|
56
|
+
else
|
57
|
+
parse_error[:ret_msg]
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
end
|
62
|
+
end
|