golf_switch 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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
|