blizzard_api 0.2.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.
- checksums.yaml +7 -0
- data/.gitignore +12 -0
- data/.gitlab-ci.yml +28 -0
- data/.rubocop.yml +13 -0
- data/.rubocop_todo.yml +7 -0
- data/.travis.yml +7 -0
- data/CHANGELOG.md +4 -0
- data/Gemfile +8 -0
- data/Gemfile.lock +44 -0
- data/LICENSE.txt +21 -0
- data/README.md +208 -0
- data/Rakefile +12 -0
- data/bin/console +14 -0
- data/bin/setup +8 -0
- data/blizzard_api.gemspec +42 -0
- data/lib/blizzard_api.rb +14 -0
- data/lib/blizzard_api/configuration.rb +82 -0
- data/lib/blizzard_api/diablo.rb +76 -0
- data/lib/blizzard_api/diablo/community/act.rb +35 -0
- data/lib/blizzard_api/diablo/community/artisan.rb +38 -0
- data/lib/blizzard_api/diablo/community/character.rb +38 -0
- data/lib/blizzard_api/diablo/community/follower.rb +25 -0
- data/lib/blizzard_api/diablo/community/item.rb +26 -0
- data/lib/blizzard_api/diablo/community/item_type.rb +35 -0
- data/lib/blizzard_api/diablo/community/profile.rb +77 -0
- data/lib/blizzard_api/diablo/game_data/era.rb +21 -0
- data/lib/blizzard_api/diablo/game_data/generic_data_endpoint.rb +58 -0
- data/lib/blizzard_api/diablo/game_data/season.rb +21 -0
- data/lib/blizzard_api/diablo/request.rb +15 -0
- data/lib/blizzard_api/exception.rb +12 -0
- data/lib/blizzard_api/request.rb +182 -0
- data/lib/blizzard_api/starcraft.rb +40 -0
- data/lib/blizzard_api/starcraft/community/account.rb +23 -0
- data/lib/blizzard_api/starcraft/community/ladder.rb +34 -0
- data/lib/blizzard_api/starcraft/community/profile.rb +76 -0
- data/lib/blizzard_api/starcraft/game_data/league.rb +27 -0
- data/lib/blizzard_api/starcraft/request.rb +36 -0
- data/lib/blizzard_api/version.rb +6 -0
- data/lib/blizzard_api/wow.rb +167 -0
- data/lib/blizzard_api/wow/community/achievements.rb +45 -0
- data/lib/blizzard_api/wow/community/auction.rb +25 -0
- data/lib/blizzard_api/wow/community/boss.rb +35 -0
- data/lib/blizzard_api/wow/community/challenge.rb +35 -0
- data/lib/blizzard_api/wow/community/character.rb +103 -0
- data/lib/blizzard_api/wow/community/guild.rb +67 -0
- data/lib/blizzard_api/wow/community/item.rb +46 -0
- data/lib/blizzard_api/wow/community/mount.rb +24 -0
- data/lib/blizzard_api/wow/community/pets.rb +85 -0
- data/lib/blizzard_api/wow/community/pvp.rb +34 -0
- data/lib/blizzard_api/wow/community/quest.rb +25 -0
- data/lib/blizzard_api/wow/community/recipe.rb +25 -0
- data/lib/blizzard_api/wow/community/spell.rb +25 -0
- data/lib/blizzard_api/wow/community/zone.rb +35 -0
- data/lib/blizzard_api/wow/game_data/connected_realm.rb +37 -0
- data/lib/blizzard_api/wow/game_data/generic_data_endpoint.rb +58 -0
- data/lib/blizzard_api/wow/game_data/mythic_keystone_affix.rb +23 -0
- data/lib/blizzard_api/wow/game_data/playable_class.rb +62 -0
- data/lib/blizzard_api/wow/game_data/playable_specialization.rb +70 -0
- data/lib/blizzard_api/wow/game_data/power_type.rb +23 -0
- data/lib/blizzard_api/wow/game_data/race.rb +51 -0
- data/lib/blizzard_api/wow/game_data/realm.rb +48 -0
- data/lib/blizzard_api/wow/game_data/region.rb +49 -0
- data/lib/blizzard_api/wow/request.rb +16 -0
- metadata +198 -0
@@ -0,0 +1,27 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module BlizzardApi
|
4
|
+
module Starcraft
|
5
|
+
##
|
6
|
+
# This class allows access to Starcraft II league data
|
7
|
+
#
|
8
|
+
# @see https://develop.battle.net/documentation/api-reference/starcraft-2-game-data-api
|
9
|
+
#
|
10
|
+
# You can get an instance of this class using the default region as follows:
|
11
|
+
# api_instance = BlizzardApi::Starcraft.league
|
12
|
+
class League < Starcraft::Request
|
13
|
+
##
|
14
|
+
# Return information about league
|
15
|
+
#
|
16
|
+
# @param [Integer] season_id Season id
|
17
|
+
# @param [Integer] queue_id Queue id
|
18
|
+
# @param [Integer] team_type Team type
|
19
|
+
# @param [Integer] league_id League id
|
20
|
+
# @!macro request_options
|
21
|
+
def get(season_id, queue_id, team_type, league_id, options = {})
|
22
|
+
opts = { ttl: CACHE_DAY }.merge(options)
|
23
|
+
api_request "#{base_url(:game_data)}/league/#{season_id}/#{queue_id}/#{team_type}/#{league_id}", opts
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
@@ -0,0 +1,36 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
##
|
4
|
+
# @!macro [new] sc2_regions
|
5
|
+
# @param {Symbol} region_id One of the valid Starcraft II regions *:US*, *:EU*, *:KO*, and *:TW*
|
6
|
+
# @note This gem do not support nor will support China endpoints
|
7
|
+
|
8
|
+
module BlizzardApi
|
9
|
+
module Starcraft
|
10
|
+
##
|
11
|
+
# Starcraft requests
|
12
|
+
class Request < BlizzardApi::Request
|
13
|
+
# Possible regions for the SC II API (Except China)
|
14
|
+
SC_REGION = { US: 1, EU: 2, KO: 3, TW: 3 }.freeze
|
15
|
+
|
16
|
+
##
|
17
|
+
# @!macro regions
|
18
|
+
def initialize(region = nil)
|
19
|
+
super region
|
20
|
+
@game = 'sc2'
|
21
|
+
end
|
22
|
+
|
23
|
+
private
|
24
|
+
|
25
|
+
##
|
26
|
+
# Helper method to find a region_id by its symbol
|
27
|
+
def resolve_region(region_arg)
|
28
|
+
return region_arg if region_arg.is_a? Integer
|
29
|
+
|
30
|
+
return SC_REGION[region_arg] if region_arg.is_a? Symbol
|
31
|
+
|
32
|
+
raise ArgumentError, 'Invalid region, please read the documentation'
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
@@ -0,0 +1,167 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module BlizzardApi
|
4
|
+
# World of Warcraft related classes
|
5
|
+
module Wow
|
6
|
+
require_relative 'wow/request'
|
7
|
+
require_relative 'wow/game_data/generic_data_endpoint'
|
8
|
+
|
9
|
+
# WoW data api
|
10
|
+
require_relative 'wow/game_data/region'
|
11
|
+
require_relative 'wow/game_data/realm'
|
12
|
+
require_relative 'wow/game_data/connected_realm'
|
13
|
+
require_relative 'wow/game_data/race'
|
14
|
+
require_relative 'wow/game_data/playable_class'
|
15
|
+
require_relative 'wow/game_data/playable_specialization'
|
16
|
+
require_relative 'wow/game_data/power_type'
|
17
|
+
require_relative 'wow/game_data/mythic_keystone_affix'
|
18
|
+
|
19
|
+
##
|
20
|
+
# @return {Region}
|
21
|
+
def self.region
|
22
|
+
BlizzardApi::Wow::Region.new
|
23
|
+
end
|
24
|
+
|
25
|
+
##
|
26
|
+
# @return {Realm}
|
27
|
+
def self.realm
|
28
|
+
BlizzardApi::Wow::Realm.new
|
29
|
+
end
|
30
|
+
|
31
|
+
##
|
32
|
+
# @return {ConnectedRealm}
|
33
|
+
def self.connected_realm
|
34
|
+
BlizzardApi::Wow::ConnectedRealm.new
|
35
|
+
end
|
36
|
+
|
37
|
+
##
|
38
|
+
# @return {Race}
|
39
|
+
def self.race
|
40
|
+
BlizzardApi::Wow::Race.new
|
41
|
+
end
|
42
|
+
|
43
|
+
##
|
44
|
+
# @return {PlayableClass}
|
45
|
+
def self.playable_class
|
46
|
+
BlizzardApi::Wow::PlayableClass.new
|
47
|
+
end
|
48
|
+
|
49
|
+
##
|
50
|
+
# @return {PlayableSpecialization}
|
51
|
+
def self.playable_specialization
|
52
|
+
BlizzardApi::Wow::PlayableSpecialization.new
|
53
|
+
end
|
54
|
+
|
55
|
+
##
|
56
|
+
# @return {PowerType}
|
57
|
+
def self.power_type
|
58
|
+
BlizzardApi::Wow::PowerType.new
|
59
|
+
end
|
60
|
+
|
61
|
+
##
|
62
|
+
# @return {MythicKeystoneAffix}
|
63
|
+
def self.mythic_keystone_affix
|
64
|
+
BlizzardApi::Wow::MythicKeystoneAffix.new
|
65
|
+
end
|
66
|
+
|
67
|
+
# Wow community api
|
68
|
+
require_relative 'wow/community/achievements'
|
69
|
+
require_relative 'wow/community/auction'
|
70
|
+
require_relative 'wow/community/boss'
|
71
|
+
require_relative 'wow/community/challenge'
|
72
|
+
require_relative 'wow/community/character'
|
73
|
+
require_relative 'wow/community/guild'
|
74
|
+
require_relative 'wow/community/item'
|
75
|
+
require_relative 'wow/community/mount'
|
76
|
+
require_relative 'wow/community/pets'
|
77
|
+
require_relative 'wow/community/pvp'
|
78
|
+
require_relative 'wow/community/quest'
|
79
|
+
require_relative 'wow/community/recipe'
|
80
|
+
require_relative 'wow/community/spell'
|
81
|
+
require_relative 'wow/community/zone'
|
82
|
+
|
83
|
+
##
|
84
|
+
# @return {Achievement}
|
85
|
+
def self.achievement
|
86
|
+
BlizzardApi::Wow::Achievement.new
|
87
|
+
end
|
88
|
+
|
89
|
+
##
|
90
|
+
# @return {Auction}
|
91
|
+
def self.auction
|
92
|
+
BlizzardApi::Wow::Auction.new
|
93
|
+
end
|
94
|
+
|
95
|
+
##
|
96
|
+
# @return {Boss}
|
97
|
+
def self.boss
|
98
|
+
BlizzardApi::Wow::Boss.new
|
99
|
+
end
|
100
|
+
|
101
|
+
##
|
102
|
+
# @return {Challenge}
|
103
|
+
def self.challenge
|
104
|
+
BlizzardApi::Wow::Challenge.new
|
105
|
+
end
|
106
|
+
|
107
|
+
##
|
108
|
+
# @return {Character}
|
109
|
+
def self.character
|
110
|
+
BlizzardApi::Wow::Character.new
|
111
|
+
end
|
112
|
+
|
113
|
+
##
|
114
|
+
# @return {Guild}
|
115
|
+
def self.guild
|
116
|
+
BlizzardApi::Wow::Guild.new
|
117
|
+
end
|
118
|
+
|
119
|
+
##
|
120
|
+
# @return {Item}
|
121
|
+
def self.item
|
122
|
+
BlizzardApi::Wow::Item.new
|
123
|
+
end
|
124
|
+
|
125
|
+
##
|
126
|
+
# @return {Mount}
|
127
|
+
def self.mount
|
128
|
+
BlizzardApi::Wow::Mount.new
|
129
|
+
end
|
130
|
+
|
131
|
+
##
|
132
|
+
# @return {Pet}
|
133
|
+
def self.pet
|
134
|
+
BlizzardApi::Wow::Pet.new
|
135
|
+
end
|
136
|
+
|
137
|
+
##
|
138
|
+
# @return {PvP}
|
139
|
+
def self.pvp
|
140
|
+
BlizzardApi::Wow::PvP.new
|
141
|
+
end
|
142
|
+
|
143
|
+
##
|
144
|
+
# @return {Quest}
|
145
|
+
def self.quest
|
146
|
+
BlizzardApi::Wow::Quest.new
|
147
|
+
end
|
148
|
+
|
149
|
+
##
|
150
|
+
# @return {Recipe}
|
151
|
+
def self.recipe
|
152
|
+
BlizzardApi::Wow::Recipe.new
|
153
|
+
end
|
154
|
+
|
155
|
+
##
|
156
|
+
# @return {Spell}
|
157
|
+
def self.spell
|
158
|
+
BlizzardApi::Wow::Spell.new
|
159
|
+
end
|
160
|
+
|
161
|
+
##
|
162
|
+
# @return {Zone}
|
163
|
+
def self.zone
|
164
|
+
BlizzardApi::Wow::Zone.new
|
165
|
+
end
|
166
|
+
end
|
167
|
+
end
|
@@ -0,0 +1,45 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module BlizzardApi
|
4
|
+
module Wow
|
5
|
+
##
|
6
|
+
# This class allows access to World of Warcraft achievements
|
7
|
+
#
|
8
|
+
# @see https://develop.battle.net/documentation/api-reference/world-of-warcraft-community-api
|
9
|
+
#
|
10
|
+
# You can get an instance of this class using the default region as follows:
|
11
|
+
# api_instance = BlizzardApi::Wow.achievements
|
12
|
+
class Achievement < Wow::Request
|
13
|
+
##
|
14
|
+
# Return complete achievement data by achievement id
|
15
|
+
#
|
16
|
+
# @param id [Integer] Achievement id
|
17
|
+
# @!macro request_options
|
18
|
+
#
|
19
|
+
# @!macro response
|
20
|
+
def get(id, options = {})
|
21
|
+
api_request "#{base_url(:community)}/achievement/#{id}", { ttl: CACHE_TRIMESTER }.merge(options)
|
22
|
+
end
|
23
|
+
|
24
|
+
##
|
25
|
+
# Return a list of possible character achievements
|
26
|
+
#
|
27
|
+
# @!macro request_options
|
28
|
+
#
|
29
|
+
# @!macro response
|
30
|
+
def character_achievement_index(options = {})
|
31
|
+
api_request "#{base_url(:community)}/data/character/achievements", { ttl: CACHE_TRIMESTER }.merge(options)
|
32
|
+
end
|
33
|
+
|
34
|
+
##
|
35
|
+
# Return a list of possible guild achievements
|
36
|
+
#
|
37
|
+
# @!macro request_options
|
38
|
+
#
|
39
|
+
# @!macro response
|
40
|
+
def guild_achievement_index(options = {})
|
41
|
+
api_request "#{base_url(:community)}/data/guild/achievements", { ttl: CACHE_TRIMESTER }.merge(options)
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module BlizzardApi
|
4
|
+
module Wow
|
5
|
+
##
|
6
|
+
# This class allows access to World of Warcraft auctions
|
7
|
+
#
|
8
|
+
# @see https://develop.battle.net/documentation/api-reference/world-of-warcraft-community-api
|
9
|
+
#
|
10
|
+
# You can get an instance of this class using the default region as follows:
|
11
|
+
# api_instance = BlizzardApi::Wow.auction
|
12
|
+
class Auction < Wow::Request
|
13
|
+
##
|
14
|
+
# Return a link to the most recent dump of all active auctions for the desired realm
|
15
|
+
#
|
16
|
+
# @param realm [String] Realm's slug
|
17
|
+
# @!macro request_options
|
18
|
+
#
|
19
|
+
# @!macro response
|
20
|
+
def get(realm, options = {})
|
21
|
+
api_request "#{base_url(:community)}/auction/data/#{realm}", { ttl: CACHE_HOUR }.merge(options)
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module BlizzardApi
|
4
|
+
module Wow
|
5
|
+
##
|
6
|
+
# This class allows access to World of Warcraft bosses
|
7
|
+
#
|
8
|
+
# @see https://develop.battle.net/documentation/api-reference/world-of-warcraft-community-api
|
9
|
+
#
|
10
|
+
# You can get an instance of this class using the default region as follows:
|
11
|
+
# api_instance = BlizzardApi::Wow.boss
|
12
|
+
class Boss < Wow::Request
|
13
|
+
##
|
14
|
+
# Return a list of every World of Warcraft boss currently in game
|
15
|
+
#
|
16
|
+
# @!macro request_options
|
17
|
+
#
|
18
|
+
# @!macro response
|
19
|
+
def index(options = {})
|
20
|
+
api_request "#{base_url(:community)}/boss/", { ttl: CACHE_TRIMESTER }.merge(options)
|
21
|
+
end
|
22
|
+
|
23
|
+
##
|
24
|
+
# Return detailed information about a boss by its ID
|
25
|
+
#
|
26
|
+
# @param id [Integer] Boss id
|
27
|
+
# @!macro request_options
|
28
|
+
#
|
29
|
+
# @!macro response
|
30
|
+
def get(id, options = {})
|
31
|
+
api_request "#{base_url(:community)}/boss/#{id}", { ttl: CACHE_TRIMESTER }.merge(options)
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module BlizzardApi
|
4
|
+
module Wow
|
5
|
+
##
|
6
|
+
# This class allows access to World of Warcraft challenges
|
7
|
+
#
|
8
|
+
# @see https://develop.battle.net/documentation/api-reference/world-of-warcraft-community-api
|
9
|
+
#
|
10
|
+
# You can get an instance of this class using the default region as follows:
|
11
|
+
# api_instance = BlizzardApi::Wow.challenge
|
12
|
+
class Challenge < Wow::Request
|
13
|
+
##
|
14
|
+
# Most recent challenge leaderboard for the specified realm
|
15
|
+
#
|
16
|
+
# @param name [String] Realm's slug
|
17
|
+
# @!macro request_options
|
18
|
+
#
|
19
|
+
# @!macro response
|
20
|
+
def realm_index(name, options = {})
|
21
|
+
api_request "#{base_url(:community)}/challenge/#{name}", { ttl: CACHE_HOUR }.merge(options)
|
22
|
+
end
|
23
|
+
|
24
|
+
##
|
25
|
+
# Most recent challenge leaderboard for the entire region
|
26
|
+
#
|
27
|
+
# @!macro request_options
|
28
|
+
#
|
29
|
+
# @!macro response
|
30
|
+
def region_index(options = {})
|
31
|
+
api_request "#{base_url(:community)}/challenge/region", { ttl: CACHE_HOUR }.merge(options)
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
@@ -0,0 +1,103 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module BlizzardApi
|
4
|
+
module Wow
|
5
|
+
##
|
6
|
+
# This class allows access to World of Warcraft character data
|
7
|
+
#
|
8
|
+
# @see https://develop.battle.net/documentation/api-reference/world-of-warcraft-community-api
|
9
|
+
#
|
10
|
+
# You can get an instance of this class using the default region as follows:
|
11
|
+
# api_instance = BlizzardApi::Wow.character
|
12
|
+
class Character < Wow::Request
|
13
|
+
# Valid fields for character profile requests
|
14
|
+
VALID_FIELDS = %w[
|
15
|
+
achievements
|
16
|
+
appearance
|
17
|
+
feed
|
18
|
+
guild
|
19
|
+
hunterPets
|
20
|
+
items
|
21
|
+
mounts
|
22
|
+
pets
|
23
|
+
petSlots
|
24
|
+
professions
|
25
|
+
progression
|
26
|
+
pvp
|
27
|
+
quests
|
28
|
+
reputation
|
29
|
+
statistics
|
30
|
+
stats
|
31
|
+
talents
|
32
|
+
titles
|
33
|
+
audit
|
34
|
+
].freeze
|
35
|
+
|
36
|
+
##
|
37
|
+
# Helper method for checking valid fields. Use this to validate an array of fields if you are not sure about their
|
38
|
+
# names.
|
39
|
+
#
|
40
|
+
# @param fields [Array<String>] Array containing desired fields to include
|
41
|
+
#
|
42
|
+
# @raise ArgumentError
|
43
|
+
def validate_fields(fields)
|
44
|
+
fields.each do |field|
|
45
|
+
raise ArgumentError, "Unrecognized field #{field}" unless VALID_FIELDS.include? field
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
##
|
50
|
+
# Return data about the specified char
|
51
|
+
#
|
52
|
+
# @param realm [String] The character realm's slug
|
53
|
+
# @param character [String] The character name
|
54
|
+
# @param fields [Array<String>] An array containing all the fields you want to be included in the response.
|
55
|
+
# @!macro request_options
|
56
|
+
#
|
57
|
+
# @!macro response
|
58
|
+
def get(realm, character, fields = [], options = {})
|
59
|
+
validate_fields fields if options.include? :validate_fields
|
60
|
+
|
61
|
+
opts = { ttl: CACHE_DAY, fields: fields.join(',') }.merge(options)
|
62
|
+
|
63
|
+
api_request "#{base_url(:community)}/character/#{realm}/#{CGI.escape(character)}", opts
|
64
|
+
end
|
65
|
+
|
66
|
+
##
|
67
|
+
# Return the mythic keystone profile of a character
|
68
|
+
#
|
69
|
+
# @note This endpoint requires a user token obtained through the user authorization flow
|
70
|
+
# @see https://develop.battle.net/documentation/guides/using-oauth/authorization-code-flow
|
71
|
+
#
|
72
|
+
# @param realm [String] The character realm's slug
|
73
|
+
# @param character [String] The character name
|
74
|
+
# @param user_token [String] A token obtained by the authorization flow. See link below.
|
75
|
+
# @param season [Integer] Season ID if you want only a specific season or nil to include all.
|
76
|
+
# @!macro request_options
|
77
|
+
#
|
78
|
+
# @!macro response
|
79
|
+
def get_keystone_profile(realm, character, user_token, season = nil, options = {})
|
80
|
+
opts = { ttl: CACHE_HOUR, namespace: "profile-#{region}" }.merge(options)
|
81
|
+
opts[:access_token] = user_token
|
82
|
+
url = "#{base_url(:profile)}/character/#{realm}/#{CGI.escape(character)}/mythic-keystone-profile"
|
83
|
+
url += "/season/#{season}" unless season.nil?
|
84
|
+
api_request url, opts
|
85
|
+
end
|
86
|
+
|
87
|
+
##
|
88
|
+
# Return a list containing all WoW characters of a BNet account
|
89
|
+
#
|
90
|
+
# @note This endpoint requires a user token obtained through the user authorization flow
|
91
|
+
# @see https://develop.battle.net/documentation/guides/using-oauth/authorization-code-flow
|
92
|
+
#
|
93
|
+
# @param user_token [String] A token obtained by the authorization flow. See link below.
|
94
|
+
# @!macro request_options
|
95
|
+
#
|
96
|
+
# @!macro response
|
97
|
+
def get_user_characters(user_token, options = {})
|
98
|
+
opts = { ttl: CACHE_HOUR, access_token: user_token }.merge(options)
|
99
|
+
api_request "#{base_url(:community)}/user/characters", opts
|
100
|
+
end
|
101
|
+
end
|
102
|
+
end
|
103
|
+
end
|