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,15 @@
|
|
1
|
+
require_relative "./../lib/golf_switch"
|
2
|
+
GolfSwitch.configure do |config|
|
3
|
+
config.reseller_id="GHE"
|
4
|
+
config.partner_id=""
|
5
|
+
config.source_cd="A"
|
6
|
+
config.lang=""
|
7
|
+
config.user_ip="120.62.161.103"
|
8
|
+
config.user_session_id="some_session"
|
9
|
+
config.access_key="some_access_key"
|
10
|
+
config.gs_source=""
|
11
|
+
end
|
12
|
+
course_policy = GolfSwitch::GetCoursePolicy.new({:course_id=>14002,:play_date=>Date.today.strftime("%Y-%m-%d")})
|
13
|
+
course_policy.commit
|
14
|
+
course_policy.parse_response
|
15
|
+
course_policy.api_response
|
data/golf_switch.gemspec
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require 'golf_switch/version'
|
5
|
+
|
6
|
+
Gem::Specification.new do |gem|
|
7
|
+
gem.name = "golf_switch"
|
8
|
+
gem.version = GolfSwitch::VERSION
|
9
|
+
gem.authors = ["amardaxini"]
|
10
|
+
gem.email = ["amardaxini@gmail.com"]
|
11
|
+
gem.description = %q{Ruby Wrapper of golf switch API}
|
12
|
+
gem.summary = %q{Ruby Wrapper of golf switch API more info devxml.golfswitch.com/examples/definitions.htm,https://devxml.golfswitch.com/golfservice.asmx}
|
13
|
+
gem.homepage = ""
|
14
|
+
|
15
|
+
gem.files = `git ls-files`.split($/)
|
16
|
+
gem.executables = gem.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
|
17
|
+
gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
|
18
|
+
gem.require_paths = ["lib"]
|
19
|
+
gem.add_dependency('savon', '~> 2.1.0')
|
20
|
+
end
|
data/lib/golf_switch.rb
ADDED
@@ -0,0 +1,42 @@
|
|
1
|
+
require 'savon'
|
2
|
+
require 'ostruct'
|
3
|
+
|
4
|
+
require "golf_switch/version"
|
5
|
+
require "golf_switch/configuration"
|
6
|
+
require "golf_switch/request"
|
7
|
+
require "golf_switch/area"
|
8
|
+
require "golf_switch/area_response"
|
9
|
+
require "golf_switch/country"
|
10
|
+
require "golf_switch/country_region"
|
11
|
+
require "golf_switch/region_area"
|
12
|
+
require "golf_switch/course"
|
13
|
+
require "golf_switch/course_list_course"
|
14
|
+
require "golf_switch/course_list"
|
15
|
+
require "golf_switch/course_avail_list"
|
16
|
+
require "golf_switch/course_avail_date"
|
17
|
+
require "golf_switch/course_avail_time"
|
18
|
+
require "golf_switch/available_course"
|
19
|
+
require "golf_switch/course_info"
|
20
|
+
require "golf_switch/course_info_course"
|
21
|
+
require "golf_switch/course_policy"
|
22
|
+
require "golf_switch/score_card"
|
23
|
+
require "golf_switch/course_avail"
|
24
|
+
require "golf_switch/course_avail_request"
|
25
|
+
require "golf_switch/book_golf"
|
26
|
+
require "golf_switch/book_golf_item"
|
27
|
+
require "golf_switch/payment"
|
28
|
+
require "golf_switch/player"
|
29
|
+
require "golf_switch/golf_book"
|
30
|
+
require "golf_switch/get_course_policy"
|
31
|
+
require "golf_switch/course_policy_response"
|
32
|
+
require "golf_switch/course_policy"
|
33
|
+
require "golf_switch/get_alt_rate_type"
|
34
|
+
require "golf_switch/golf_book_info"
|
35
|
+
require "golf_switch/cancel_golf"
|
36
|
+
require "golf_switch/cancel_golf_response"
|
37
|
+
|
38
|
+
|
39
|
+
|
40
|
+
module GolfSwitch
|
41
|
+
# Your code goes here...
|
42
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
module GolfSwitch
|
2
|
+
class AltRateType
|
3
|
+
attr_accessor :id,:nm,:desc
|
4
|
+
|
5
|
+
def initialize(attributes={})
|
6
|
+
attributes.each do |name, value|
|
7
|
+
begin
|
8
|
+
send("#{name}=", value)
|
9
|
+
rescue
|
10
|
+
puts "Add #{name} to accessor in alt rate type"
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
def self.patse_alt_rate_types(response)
|
16
|
+
alt_rate_types = []
|
17
|
+
if response[:alt_rate_types].is_a?(Array)
|
18
|
+
response[:alt_rate_types].each do |alt_rate_type|
|
19
|
+
alt_rate_types << GolfSwitch::AltRateType.new(alt_rate_types)
|
20
|
+
end
|
21
|
+
elsif response[:alt_rate_types].is_a?(Hash)
|
22
|
+
alt_rate_types << GolfSwitch::AltRateType.new(response[:alt_rate_types])
|
23
|
+
end
|
24
|
+
alt_rate_types
|
25
|
+
end
|
26
|
+
|
27
|
+
end
|
28
|
+
end
|
@@ -0,0 +1,52 @@
|
|
1
|
+
module GolfSwitch
|
2
|
+
class Area < GolfSwitch::Request
|
3
|
+
attr_accessor :country_id,:region_id,:api_response
|
4
|
+
def initialize(attributes = {})
|
5
|
+
attributes.each do |name, value|
|
6
|
+
begin
|
7
|
+
send("#{name}=", value)
|
8
|
+
rescue
|
9
|
+
puts "invalid attribute #{name} in area"
|
10
|
+
end
|
11
|
+
|
12
|
+
end
|
13
|
+
@area_response = []
|
14
|
+
end
|
15
|
+
|
16
|
+
def get_options
|
17
|
+
{
|
18
|
+
"Req"=>
|
19
|
+
option_attributes
|
20
|
+
|
21
|
+
}
|
22
|
+
end
|
23
|
+
|
24
|
+
def option_attributes
|
25
|
+
options = {}
|
26
|
+
options.merge!("CountryId"=>@country_id) unless @country_id.blank?
|
27
|
+
options.merge!("RegionId"=>@region_id) unless @region_id.blank?
|
28
|
+
options
|
29
|
+
end
|
30
|
+
|
31
|
+
def commit
|
32
|
+
super("areas")
|
33
|
+
end
|
34
|
+
|
35
|
+
def parse_error
|
36
|
+
@response[:areas_response][:areas_result]
|
37
|
+
end
|
38
|
+
|
39
|
+
def parse_response
|
40
|
+
begin
|
41
|
+
unless error?
|
42
|
+
@api_response = AreaResponse.parse_areas(@response[:areas_response][:areas_result])
|
43
|
+
else
|
44
|
+
puts "Error #{error_message}"
|
45
|
+
end
|
46
|
+
rescue
|
47
|
+
puts "Parse Error On Area"
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
end
|
52
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
module GolfSwitch
|
2
|
+
class AreaResponse
|
3
|
+
attr_accessor :area_id,:name,:countries
|
4
|
+
def initialize(area_id=nil,name=nil)
|
5
|
+
@area_id = area_id
|
6
|
+
@name = name
|
7
|
+
@countries= []
|
8
|
+
end
|
9
|
+
|
10
|
+
def self.parse_areas(response_hash)
|
11
|
+
areas = AreaResponse.new
|
12
|
+
|
13
|
+
unless response_hash[:countries] && response_hash[:countries].blank?
|
14
|
+
# Searching for single country
|
15
|
+
if response_hash[:countries][:country] && response_hash[:countries][:country].is_a?(Hash)
|
16
|
+
areas.countries << Country.parse_country(response_hash[:countries][:country])
|
17
|
+
elsif response_hash[:countries][:country] && response_hash[:countries][:country].is_a?(Array)
|
18
|
+
response_hash[:countries][:country].each do |country|
|
19
|
+
areas.countries << Country.parse_country(country)
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
areas
|
24
|
+
end
|
25
|
+
|
26
|
+
end
|
27
|
+
end
|
@@ -0,0 +1,53 @@
|
|
1
|
+
module GolfSwitch
|
2
|
+
class AvailableCourse < GolfSwitch::Course
|
3
|
+
attr_accessor :rt_type,:f_prc,:t_prc,:curr,:rating_cnt,:max_rew_pts,:cc_allow,:note,:dates,:is_gsw,:rc,:msg,:addr1,:zip
|
4
|
+
# ccAllow Comma separated list of allowed credit card types.VI: Visa,MC: Mastercard,AX: American Express,DS: Discover
|
5
|
+
def initialize(attributes={})
|
6
|
+
@dates = []
|
7
|
+
|
8
|
+
attributes.each do |name, value|
|
9
|
+
if name.to_s=="dates"
|
10
|
+
|
11
|
+
parse_date_info(value)
|
12
|
+
else
|
13
|
+
begin
|
14
|
+
send("#{name}=", value)
|
15
|
+
rescue
|
16
|
+
puts "#{name} attribute is not present"
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
def self.parse_courses(response_hash)
|
22
|
+
courses= []
|
23
|
+
|
24
|
+
if response_hash[:courses]
|
25
|
+
avail_courses= response_hash[:courses][:al_course] || response_hash[:courses][:ca_course]
|
26
|
+
if avail_courses.is_a?(Array)
|
27
|
+
avail_courses.each do |course|
|
28
|
+
begin
|
29
|
+
courses << AvailableCourse.new(course.merge(:img_base=>response_hash[:img_base]))
|
30
|
+
end
|
31
|
+
end
|
32
|
+
elsif avail_courses.is_a?(Hash)
|
33
|
+
courses << AvailableCourse.new(avail_courses.merge(:img_base=>response_hash[:img_base]))
|
34
|
+
end
|
35
|
+
end
|
36
|
+
courses
|
37
|
+
end
|
38
|
+
|
39
|
+
def parse_date_info(value)
|
40
|
+
|
41
|
+
if value[:al_date].is_a?(Array)
|
42
|
+
value[:al_date].each do |al_date|
|
43
|
+
@dates << CourseAvailDate.parse_date_info(al_date)
|
44
|
+
end
|
45
|
+
elsif value[:al_date].is_a?(Hash)
|
46
|
+
@dates << CourseAvailDate.parse_date_info(value[:al_date])
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
|
51
|
+
end
|
52
|
+
|
53
|
+
end
|
@@ -0,0 +1,41 @@
|
|
1
|
+
module GolfSwitch
|
2
|
+
class BookGolf < GolfSwitch::Request
|
3
|
+
attr_accessor :book_golf_items,:api_response
|
4
|
+
def initialize(attributes={})
|
5
|
+
@book_golf_items = []
|
6
|
+
end
|
7
|
+
|
8
|
+
def get_options
|
9
|
+
{
|
10
|
+
"Req"=>option_attributes
|
11
|
+
|
12
|
+
}
|
13
|
+
end
|
14
|
+
def option_attributes
|
15
|
+
{
|
16
|
+
"BookGolfItems"=>{"BookGolfItem"=>Array(@book_golf_items).collect{|bgi| bgi.option_attributes}}
|
17
|
+
}
|
18
|
+
end
|
19
|
+
|
20
|
+
def commit
|
21
|
+
super("book_golf")
|
22
|
+
end
|
23
|
+
|
24
|
+
def parse_error
|
25
|
+
@response[:book_golf_response][:book_golf_result]
|
26
|
+
end
|
27
|
+
|
28
|
+
def parse_response
|
29
|
+
begin
|
30
|
+
unless error?
|
31
|
+
@api_response = GolfSwitch::GolfBook.parse_golf_books(@response[:book_golf_response][:book_golf_result])
|
32
|
+
else
|
33
|
+
puts "Error #{error_message}"
|
34
|
+
end
|
35
|
+
rescue
|
36
|
+
puts "Parse Error On Book Golf"
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
end
|
41
|
+
end
|
@@ -0,0 +1,50 @@
|
|
1
|
+
module GolfSwitch
|
2
|
+
class BookGolfItem
|
3
|
+
attr_accessor :course_id,:play_date,:play_time,:num_players,:alt_rate_type,:promo_code
|
4
|
+
attr_accessor :pp_price,:curr,:pp_txn_fee,:pp_charge,:chrg_curr,:pp_non_ref,:pp_net_rt
|
5
|
+
attr_accessor :tot_price,:tot_txn_fee,:tot_charge,:tot_non_ref,:tot_net_rt,:flags
|
6
|
+
attr_accessor :package_id,:book_notes,:ignore_pricing,:players,:payment
|
7
|
+
def initialize(attributes={})
|
8
|
+
attributes.each do |name, value|
|
9
|
+
begin
|
10
|
+
send("#{name}=", value)
|
11
|
+
rescue
|
12
|
+
puts "invalid attribute #{name} in player"
|
13
|
+
end
|
14
|
+
end
|
15
|
+
@players ||=[]
|
16
|
+
end
|
17
|
+
|
18
|
+
def option_attributes
|
19
|
+
@ignore_pricing =false if @ignore_pricing.blank?
|
20
|
+
options = {}
|
21
|
+
options.merge!("CourseId"=>@course_id) unless @course_id.blank?
|
22
|
+
options.merge!("PlayDate"=>(DateTime.parse(@play_date).strftime("%Y-%m-%dT00:00:00")))
|
23
|
+
options.merge!("PlayTime"=>@play_time)
|
24
|
+
options.merge!("NumPlayers"=>@num_players)
|
25
|
+
options.merge!("AltRateType"=>@alt_rate_type) unless @alt_rate_type.blank?
|
26
|
+
options.merge!("PromoCode"=>@promo_code) unless @promo_code.blank?
|
27
|
+
options.merge!("PpPrice"=>@pp_price)
|
28
|
+
options.merge!("Curr"=>@curr||"USD")
|
29
|
+
options.merge!("PpTxnFee"=>@pp_txn_fee)
|
30
|
+
options.merge!("PpCharge"=>@pp_charge)
|
31
|
+
options.merge!("ChrgCurr"=>@chrg_curr || "USD")
|
32
|
+
options.merge!("PpNonRef"=>@pp_non_ref)
|
33
|
+
options.merge!("PpNetRt"=>@pp_net_rt)
|
34
|
+
options.merge!("TotPrice"=>@tot_price)
|
35
|
+
options.merge!("TotTxnFee"=>@tot_txn_fee)
|
36
|
+
options.merge!("TotCharge"=>@tot_charge)
|
37
|
+
options.merge!("TotNonRef"=>@tot_non_ref)
|
38
|
+
options.merge!("TotNetRt"=>@tot_net_rt)
|
39
|
+
options.merge!("Flags"=>@flags) unless @flags.blank?
|
40
|
+
options.merge!("PackageId"=>@package_id) unless @package_id.blank?
|
41
|
+
options.merge!("BookNotes"=>@book_notes) unless @book_notes.blank?
|
42
|
+
options.merge!("IgnorePricing"=>@ignore_pricing)
|
43
|
+
options["Players"]={"Player"=>Array(@players).collect{|x| x.option_attributes}}
|
44
|
+
options["Payments"]={"Payment"=>@payment.option_attributes}
|
45
|
+
|
46
|
+
options
|
47
|
+
end
|
48
|
+
|
49
|
+
end
|
50
|
+
end
|
@@ -0,0 +1,49 @@
|
|
1
|
+
module GolfSwitch
|
2
|
+
class CancelGolf < GolfSwitch::Request
|
3
|
+
attr_accessor :course_id,:tee_date,:confirmation_no,:booking_id
|
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("cancel_golf")
|
30
|
+
end
|
31
|
+
|
32
|
+
def parse_error
|
33
|
+
@response[:cancel_golf_response][:cancel_golf_result]
|
34
|
+
end
|
35
|
+
|
36
|
+
def parse_response
|
37
|
+
begin
|
38
|
+
unless error?
|
39
|
+
@api_response = GolfSwitch::CancelGolfResponse.new(@response[:cancel_golf_response][:cancel_golf_result])
|
40
|
+
else
|
41
|
+
puts "Error #{error_message}"
|
42
|
+
end
|
43
|
+
rescue
|
44
|
+
puts "Parse Error On Cancel Golf Response"
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
end
|
49
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
module GolfSwitch
|
2
|
+
class CancelGolfResponse < GolfSwitch::GolfBookInfo
|
3
|
+
attr_accessor :confirmation_no,:tot_voucher_charged,:tot_cc_credited,:tot_voucher_credited,:cancellation_no
|
4
|
+
|
5
|
+
|
6
|
+
def initialize(attributes={})
|
7
|
+
attributes.each do |name, value|
|
8
|
+
begin
|
9
|
+
send("#{name}=", value)
|
10
|
+
rescue
|
11
|
+
puts "Add #{name} as accessor in Cancel Golf Response"
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
module GolfSwitch
|
2
|
+
class Configuration
|
3
|
+
attr_accessor :reseller_id,:partner_id,:source_cd,:lang,:user_ip,:user_session_id,:access_key,:gs_source,:gs_debug,:golf_switch_wsdl,:agent,:mode
|
4
|
+
def initialize(mode="development")
|
5
|
+
@reseller_id,@partner_id,@source_cd,@lang,@user_ip,@user_session_id,@access_key,@gs_source,@agent=nil
|
6
|
+
@gs_debug= true
|
7
|
+
@mode = mode
|
8
|
+
get_golf_switch_wsdl
|
9
|
+
end
|
10
|
+
|
11
|
+
def get_golf_switch_wsdl
|
12
|
+
if @mode=="development"
|
13
|
+
@golf_switch_wsdl = "https://devxml.golfswitch.com/golfservice.asmx?WSDL"
|
14
|
+
elsif @mode=="production"
|
15
|
+
@golf_switch_wsdl="https://xml.golfswitch.com/golfService.asmx?WSDL"
|
16
|
+
end
|
17
|
+
|
18
|
+
end
|
19
|
+
end
|
20
|
+
class << self
|
21
|
+
attr_accessor :configuration
|
22
|
+
end
|
23
|
+
def self.configure
|
24
|
+
|
25
|
+
self.configuration = Configuration.new
|
26
|
+
yield(configuration) if block_given?
|
27
|
+
end
|
28
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
module GolfSwitch
|
2
|
+
class Country < AreaResponse
|
3
|
+
attr_accessor :country_regions
|
4
|
+
def initialize(area_id=nil,name=nil)
|
5
|
+
super(area_id,name)
|
6
|
+
@country_regions = []
|
7
|
+
end
|
8
|
+
|
9
|
+
def self.parse_country(country)
|
10
|
+
golfswitch_country = Country.new(country[:id],country[:nm])
|
11
|
+
golfswitch_country.parse_regions(country[:regions])
|
12
|
+
golfswitch_country
|
13
|
+
end
|
14
|
+
|
15
|
+
def regions
|
16
|
+
@country_regions
|
17
|
+
end
|
18
|
+
|
19
|
+
def parse_regions(regions)
|
20
|
+
|
21
|
+
if regions[:region] && regions[:region].is_a?(Array)
|
22
|
+
regions[:region].each do |region|
|
23
|
+
@country_regions << CountryRegion.parse_region(region)
|
24
|
+
end
|
25
|
+
elsif regions[:region] && regions.is_a?(Hash)
|
26
|
+
@country_regions << CountryRegion.parse_region(regions[:region])
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|