steam-condenser 1.3.2 → 1.3.3
Sign up to get free protection for your applications and to get access to all the features.
- data/Gemfile.lock +3 -3
- data/lib/errors/packet_format_error.rb +0 -8
- data/lib/errors/steam_condenser_error.rb +16 -1
- data/lib/steam-condenser/version.rb +1 -1
- data/lib/steam/community/alien_swarm/alien_swarm_stats.rb +67 -61
- data/lib/steam/community/css/css_stats.rb +45 -40
- data/lib/steam/community/game_leaderboard.rb +19 -15
- data/lib/steam/community/game_stats.rb +1 -1
- data/lib/steam/community/l4d/abstract_l4d_stats.rb +62 -50
- data/lib/steam/community/l4d/l4d2_stats.rb +36 -29
- data/lib/steam/community/steam_group.rb +8 -10
- data/lib/steam/community/steam_id.rb +53 -61
- data/lib/steam/community/xml_data.rb +3 -0
- data/lib/steam/packets/s2a_info2_packet.rb +36 -24
- data/lib/steam/packets/s2a_info_base_packet.rb +3 -13
- data/lib/steam/packets/s2a_info_detailed_packet.rb +26 -28
- data/lib/steam/servers/game_server.rb +2 -2
- data/steam-condenser.gemspec +1 -1
- data/test/core_ext/test_stringio.rb +1 -1
- data/test/steam/servers/test_game_server.rb +2 -2
- metadata +118 -101
@@ -1,7 +1,7 @@
|
|
1
1
|
# This code is free software; you can redistribute it and/or modify it under
|
2
2
|
# the terms of the new BSD License.
|
3
3
|
#
|
4
|
-
# Copyright (c) 2009-
|
4
|
+
# Copyright (c) 2009-2013, Sebastian Staudt
|
5
5
|
|
6
6
|
require 'steam/community/l4d/abstract_l4d_stats'
|
7
7
|
require 'steam/community/l4d/l4d2_map'
|
@@ -34,11 +34,13 @@ class L4D2Stats < GameStats
|
|
34
34
|
def initialize(steam_id)
|
35
35
|
super steam_id, 'l4d2'
|
36
36
|
|
37
|
+
weapons_data = @xml_data['stats']['weapons']
|
38
|
+
|
37
39
|
@damage_percentages = {
|
38
|
-
:melee =>
|
39
|
-
:pistols =>
|
40
|
-
:rifles =>
|
41
|
-
:shotguns =>
|
40
|
+
:melee => weapons_data['meleepctdmg'].to_f,
|
41
|
+
:pistols => weapons_data['pistolspctdmg'].to_f,
|
42
|
+
:rifles => weapons_data['bulletspctdmg'].to_f,
|
43
|
+
:shotguns => weapons_data['shellspctdmg'].to_f
|
42
44
|
}
|
43
45
|
end
|
44
46
|
|
@@ -58,9 +60,11 @@ class L4D2Stats < GameStats
|
|
58
60
|
|
59
61
|
if @lifetime_stats.nil?
|
60
62
|
super
|
61
|
-
|
62
|
-
|
63
|
-
@lifetime_stats[:
|
63
|
+
|
64
|
+
lifetime_data = @xml_data['stats']['lifetime']
|
65
|
+
@lifetime_stats[:avg_adrenaline_shared] = lifetime_data['adrenalineshared'].to_f
|
66
|
+
@lifetime_stats[:avg_adrenaline_used] = lifetime_data['adrenalineused'].to_f
|
67
|
+
@lifetime_stats[:avg_defibrillators_used] = lifetime_data['defibrillatorsused'].to_f
|
64
68
|
end
|
65
69
|
|
66
70
|
@lifetime_stats
|
@@ -77,33 +81,36 @@ class L4D2Stats < GameStats
|
|
77
81
|
return unless public?
|
78
82
|
|
79
83
|
if @scavenge_stats.nil?
|
84
|
+
scavange_data = @xml_data['stats']['scavenge']
|
85
|
+
|
80
86
|
@scavenge_stats = {}
|
81
|
-
@scavenge_stats[:avg_cans_per_round] =
|
82
|
-
@scavenge_stats[:perfect_rounds] =
|
83
|
-
@scavenge_stats[:rounds_lost] =
|
84
|
-
@scavenge_stats[:rounds_played] =
|
85
|
-
@scavenge_stats[:rounds_won] =
|
86
|
-
@scavenge_stats[:total_cans] =
|
87
|
+
@scavenge_stats[:avg_cans_per_round] = scavange_data['avgcansperround'].to_f
|
88
|
+
@scavenge_stats[:perfect_rounds] = scavange_data['perfect16canrounds'].to_i
|
89
|
+
@scavenge_stats[:rounds_lost] = scavange_data['roundslost'].to_i
|
90
|
+
@scavenge_stats[:rounds_played] = scavange_data['roundsplayed'].to_i
|
91
|
+
@scavenge_stats[:rounds_won] = scavange_data['roundswon'].to_i
|
92
|
+
@scavenge_stats[:total_cans] = scavange_data['totalcans'].to_i
|
87
93
|
|
88
94
|
@scavenge_stats[:maps] = {}
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
@scavenge_stats[:maps][
|
95
|
+
scavange_data['mapstats']['map'].each do |map_data|
|
96
|
+
map_stats = {}
|
97
|
+
map_stats['avg_round_score'] = map_data['avgscoreperround'].to_i
|
98
|
+
map_stats['highest_game_score'] = map_data['highgamescore'].to_i
|
99
|
+
map_stats['highest_round_score'] = map_data['highroundscore'].to_i
|
100
|
+
map_stats['name'] = map_data['fullname']
|
101
|
+
map_stats['rounds_played'] = map_data['roundsplayed'].to_i
|
102
|
+
map_stats['rounds_won'] = map_data['roundswon'].to_i
|
103
|
+
@scavenge_stats[:maps][map_data['name']] = map_stats
|
104
|
+
|
98
105
|
end
|
99
106
|
|
100
107
|
@scavenge_stats[:infected] = {}
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
@scavenge_stats[:infected][
|
108
|
+
scavange_data['infectedstats']['special'].each do |infected_data|
|
109
|
+
infected_stats = {}
|
110
|
+
infected_stats['max_damage_per_life'] = infected_data['maxdmg1life'].to_i
|
111
|
+
infected_stats['max_pours_interrupted'] = infected_data['maxpoursinterrupted'].to_i
|
112
|
+
infected_stats['special_attacks'] = infected_data['specialattacks'].to_i
|
113
|
+
@scavenge_stats[:infected][infected_data['name']] = infected_stats
|
107
114
|
end
|
108
115
|
end
|
109
116
|
|
@@ -112,19 +112,17 @@ class SteamGroup
|
|
112
112
|
def fetch_page(page)
|
113
113
|
member_data = parse "#{base_url}/memberslistxml?p=#{page}"
|
114
114
|
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
@members << SteamId.new(member.to_i, false)
|
122
|
-
end
|
123
|
-
rescue
|
124
|
-
raise SteamCondenserError, 'XML data could not be parsed.', $!.backtrace
|
115
|
+
@group_id64 = member_data['groupID64'].to_i if page == 1
|
116
|
+
@member_count = member_data['memberCount'].to_i
|
117
|
+
total_pages = member_data['totalPages'].to_i
|
118
|
+
|
119
|
+
member_data['members']['steamID64'].each do |member|
|
120
|
+
@members << SteamId.new(member.to_i, false)
|
125
121
|
end
|
126
122
|
|
127
123
|
total_pages
|
124
|
+
rescue
|
125
|
+
raise SteamCondenserError, 'XML data could not be parsed.'
|
128
126
|
end
|
129
127
|
|
130
128
|
end
|
@@ -1,7 +1,7 @@
|
|
1
1
|
# This code is free software; you can redistribute it and/or modify it under
|
2
2
|
# the terms of the new BSD License.
|
3
3
|
#
|
4
|
-
# Copyright (c) 2008-
|
4
|
+
# Copyright (c) 2008-2013, Sebastian Staudt
|
5
5
|
|
6
6
|
require 'cgi'
|
7
7
|
|
@@ -244,64 +244,55 @@ class SteamId
|
|
244
244
|
# when it is private
|
245
245
|
# @see Cacheable#fetch
|
246
246
|
def fetch
|
247
|
-
|
248
|
-
profile = parse "#{base_url}?xml=1"
|
247
|
+
profile = parse "#{base_url}?xml=1"
|
249
248
|
|
250
|
-
|
249
|
+
raise SteamCondenserError, profile['error'] unless profile['error'].nil?
|
251
250
|
|
252
|
-
|
253
|
-
|
251
|
+
unless profile['privacyMessage'].nil?
|
252
|
+
raise SteamCondenserError, profile['privacyMessage']
|
253
|
+
end
|
254
|
+
|
255
|
+
@nickname = CGI.unescapeHTML profile['steamID']
|
256
|
+
@steam_id64 = profile['steamID64'].to_i
|
257
|
+
@limited = (profile['isLimitedAccount'].to_i == 1)
|
258
|
+
@trade_ban_state = profile['tradeBanState']
|
259
|
+
@vac_banned = (profile['vacBanned'].to_i == 1)
|
260
|
+
|
261
|
+
@image_url = profile['avatarIcon'][0..-5]
|
262
|
+
@online_state = profile['onlineState']
|
263
|
+
@privacy_state = profile['privacyState']
|
264
|
+
@state_message = profile['stateMessage']
|
265
|
+
@visibility_state = profile['visibilityState'].to_i
|
266
|
+
|
267
|
+
if public?
|
268
|
+
@custom_url = (profile['customURL'] || '').downcase
|
269
|
+
@custom_url = nil if @custom_url.empty?
|
270
|
+
|
271
|
+
@head_line = CGI.unescapeHTML profile['headline'] || ''
|
272
|
+
@hours_played = profile['hoursPlayed2Wk'].to_f
|
273
|
+
@location = profile['location']
|
274
|
+
@member_since = Time.parse profile['memberSince']
|
275
|
+
@real_name = CGI.unescapeHTML profile['realname'] || ''
|
276
|
+
@steam_rating = profile['steamRating'].to_f
|
277
|
+
@summary = CGI.unescapeHTML profile['summary'] || ''
|
278
|
+
|
279
|
+
@most_played_games = {}
|
280
|
+
[(profile['mostPlayedGames'] || {})['mostPlayedGame']].compact.flatten.each do |most_played_game|
|
281
|
+
@most_played_games[most_played_game['gameName']] = most_played_game['hoursPlayed'].to_f
|
282
|
+
end
|
283
|
+
|
284
|
+
@groups = []
|
285
|
+
[(profile['groups'] || {})['group']].compact.flatten.each do |group|
|
286
|
+
@groups << SteamGroup.new(group['groupID64'].to_i, false)
|
254
287
|
end
|
255
288
|
|
256
|
-
@
|
257
|
-
|
258
|
-
|
259
|
-
@trade_ban_state = profile['tradeBanState']
|
260
|
-
@vac_banned = (profile['vacBanned'].to_i == 1)
|
261
|
-
|
262
|
-
@image_url = profile['avatarIcon'][0..-5]
|
263
|
-
@online_state = profile['onlineState']
|
264
|
-
@privacy_state = profile['privacyState']
|
265
|
-
@state_message = profile['stateMessage']
|
266
|
-
@visibility_state = profile['visibilityState'].to_i
|
267
|
-
|
268
|
-
if public?
|
269
|
-
@custom_url = profile['customURL'].downcase rescue ''
|
270
|
-
@custom_url = nil if @custom_url.empty?
|
271
|
-
|
272
|
-
@head_line = CGI.unescapeHTML profile['headline'] || ''
|
273
|
-
@hours_played = profile['hoursPlayed2Wk'].to_f
|
274
|
-
@location = profile['location']
|
275
|
-
@member_since = Time.parse profile['memberSince']
|
276
|
-
@real_name = CGI.unescapeHTML profile['realname'] || ''
|
277
|
-
@steam_rating = profile['steamRating'].to_f
|
278
|
-
@summary = CGI.unescapeHTML profile['summary'] || ''
|
279
|
-
|
280
|
-
@most_played_games = {}
|
281
|
-
unless profile['mostPlayedGames'].to_s.strip.empty?
|
282
|
-
[profile['mostPlayedGames']['mostPlayedGame']].flatten.each do |most_played_game|
|
283
|
-
@most_played_games[most_played_game['gameName']] = most_played_game['hoursPlayed'].to_f
|
284
|
-
end
|
285
|
-
end
|
286
|
-
|
287
|
-
@groups = []
|
288
|
-
unless profile['groups'].to_s.strip.empty?
|
289
|
-
[profile['groups']['group']].flatten.each do |group|
|
290
|
-
@groups << SteamGroup.new(group['groupID64'].to_i, false)
|
291
|
-
end
|
292
|
-
end
|
293
|
-
|
294
|
-
@links = {}
|
295
|
-
unless profile['weblinks'].to_s.strip.empty?
|
296
|
-
[profile['weblinks']['weblink']].flatten.each do |link|
|
297
|
-
@links[CGI.unescapeHTML link['title']] = link['link']
|
298
|
-
end
|
299
|
-
end
|
289
|
+
@links = {}
|
290
|
+
[(profile['weblinks'] || {})['weblink']].compact.flatten.each do |link|
|
291
|
+
@links[CGI.unescapeHTML link['title']] = link['link']
|
300
292
|
end
|
301
|
-
rescue
|
302
|
-
raise $! if $!.is_a? SteamCondenserError
|
303
|
-
raise SteamCondenserError, 'XML data could not be parsed.', $!.backtrace
|
304
293
|
end
|
294
|
+
rescue
|
295
|
+
raise SteamCondenserError, 'XML data could not be parsed.'
|
305
296
|
end
|
306
297
|
|
307
298
|
# Fetches the friends of this user
|
@@ -328,17 +319,18 @@ class SteamId
|
|
328
319
|
# @see #games
|
329
320
|
def fetch_games
|
330
321
|
games_data = parse "#{base_url}/games?xml=1"
|
331
|
-
@games
|
332
|
-
@
|
322
|
+
@games = {}
|
323
|
+
@recent_playtimes = {}
|
324
|
+
@total_playtimes = {}
|
333
325
|
games_data['games']['game'].each do |game_data|
|
334
326
|
app_id = game_data['appID'].to_i
|
335
|
-
|
336
|
-
@games[app_id] = game
|
327
|
+
@games[app_id] = SteamGame.new app_id, game_data
|
337
328
|
|
338
329
|
recent = game_data['hoursLast2Weeks'].to_f
|
339
330
|
total = (game_data['hoursOnRecord'] || '').delete(',').to_f
|
340
331
|
|
341
|
-
@
|
332
|
+
@recent_playtimes[app_id] = (recent * 60).to_i
|
333
|
+
@total_playtimes[app_id] = (total * 60).to_i
|
342
334
|
end
|
343
335
|
|
344
336
|
true
|
@@ -408,7 +400,7 @@ class SteamId
|
|
408
400
|
#
|
409
401
|
# @return [Fixnum, String] The 64bit numeric SteamID or the custom URL
|
410
402
|
def id
|
411
|
-
@custom_url
|
403
|
+
@custom_url || @steam_id64
|
412
404
|
end
|
413
405
|
|
414
406
|
# Returns whether the owner of this SteamId is playing a game
|
@@ -457,7 +449,7 @@ class SteamId
|
|
457
449
|
# the last two weeks
|
458
450
|
def recent_playtime(id)
|
459
451
|
game = find_game id
|
460
|
-
@
|
452
|
+
@recent_playtimes[game.app_id]
|
461
453
|
end
|
462
454
|
|
463
455
|
# Returns the total time in minutes this user has played this game
|
@@ -468,7 +460,7 @@ class SteamId
|
|
468
460
|
# game
|
469
461
|
def total_playtime(id)
|
470
462
|
game = find_game id
|
471
|
-
@
|
463
|
+
@total_playtimes[game.app_id]
|
472
464
|
end
|
473
465
|
|
474
466
|
private
|
@@ -16,9 +16,12 @@ module XMLData
|
|
16
16
|
#
|
17
17
|
# @param [String] url The URL to parse
|
18
18
|
# @return [Hash<String, Object>] The data parsed from the XML document
|
19
|
+
# @raise [SteamCondenserError] if an error occurs while parsing the XML data
|
19
20
|
def parse(url)
|
20
21
|
data = open(url, { :proxy => true })
|
21
22
|
@xml_data = MultiXml.parse(data).values.first
|
23
|
+
rescue
|
24
|
+
raise SteamCondenserError.new "XML data could not be parsed: #{$!.message}", $!
|
22
25
|
end
|
23
26
|
|
24
27
|
end
|
@@ -1,7 +1,7 @@
|
|
1
1
|
# This code is free software; you can redistribute it and/or modify it under
|
2
2
|
# the terms of the new BSD License.
|
3
3
|
#
|
4
|
-
# Copyright (c) 2008-
|
4
|
+
# Copyright (c) 2008-2013, Sebastian Staudt
|
5
5
|
|
6
6
|
require 'steam/packets/s2a_info_base_packet'
|
7
7
|
|
@@ -17,6 +17,12 @@ class S2A_INFO2_Packet
|
|
17
17
|
|
18
18
|
include S2A_INFO_BasePacket
|
19
19
|
|
20
|
+
EDF_GAME_ID = 0x01
|
21
|
+
EDF_GAME_PORT = 0x80
|
22
|
+
EDF_SERVER_ID = 0x10
|
23
|
+
EDF_SERVER_TAGS = 0x20
|
24
|
+
EDF_SOURCE_TV = 0x40
|
25
|
+
|
20
26
|
# Creates a new S2A_INFO2 response object based on the given data
|
21
27
|
#
|
22
28
|
# @param [String] data The raw packet data replied from the server
|
@@ -24,39 +30,45 @@ class S2A_INFO2_Packet
|
|
24
30
|
def initialize(data)
|
25
31
|
super S2A_INFO2_HEADER, data
|
26
32
|
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
33
|
+
info[:protocol_version] = @content_data.byte
|
34
|
+
info[:server_name] = @content_data.cstring
|
35
|
+
info[:map_name] = @content_data.cstring
|
36
|
+
info[:game_directory] = @content_data.cstring
|
37
|
+
info[:game_description] = @content_data.cstring
|
38
|
+
info[:app_id] = @content_data.short
|
39
|
+
info[:number_of_players] = @content_data.byte
|
40
|
+
info[:max_players] = @content_data.byte
|
41
|
+
info[:number_of_bots] = @content_data.byte
|
42
|
+
info[:dedicated] = @content_data.byte.chr
|
43
|
+
info[:operating_system] = @content_data.byte.chr
|
44
|
+
info[:password_needed] = @content_data.byte == 1
|
45
|
+
info[:secure] = @content_data.byte == 1
|
46
|
+
info[:game_version] = @content_data.cstring
|
41
47
|
|
42
48
|
if @content_data.remaining > 0
|
43
49
|
extra_data_flag = @content_data.byte
|
44
50
|
|
45
|
-
|
51
|
+
if extra_data_flag & EDF_GAME_PORT != 0
|
52
|
+
info[:server_port] = @content_data.short
|
53
|
+
end
|
46
54
|
|
47
|
-
|
48
|
-
|
55
|
+
if extra_data_flag & EDF_SERVER_ID != 0
|
56
|
+
info[:server_id] = @content_data.long | (@content_data.long << 32)
|
49
57
|
end
|
50
58
|
|
51
|
-
|
52
|
-
|
53
|
-
|
59
|
+
if extra_data_flag & EDF_SOURCE_TV != 0
|
60
|
+
info[:tv_port] = @content_data.short
|
61
|
+
info[:tv_name] = @content_data.cstring
|
54
62
|
end
|
55
63
|
|
56
|
-
|
57
|
-
|
64
|
+
if extra_data_flag & EDF_SERVER_TAGS != 0
|
65
|
+
info[:server_tags] = @content_data.cstring
|
66
|
+
end
|
58
67
|
|
59
|
-
|
68
|
+
if extra_data_flag & EDF_GAME_ID != 0
|
69
|
+
info[:game_id] = @content_data.long | (@content_data.long << 32)
|
70
|
+
end
|
71
|
+
end
|
60
72
|
end
|
61
73
|
|
62
74
|
end
|
@@ -1,7 +1,7 @@
|
|
1
1
|
# This code is free software; you can redistribute it and/or modify it under
|
2
2
|
# the terms of the new BSD License.
|
3
3
|
#
|
4
|
-
# Copyright (c) 2008-
|
4
|
+
# Copyright (c) 2008-2013, Sebastian Staudt
|
5
5
|
|
6
6
|
require 'steam/packets/steam_packet'
|
7
7
|
|
@@ -18,18 +18,8 @@ module S2A_INFO_BasePacket
|
|
18
18
|
# Returns the information provided by the server
|
19
19
|
#
|
20
20
|
# @return [Hash<String, Object>] The information provided by the server
|
21
|
-
|
22
|
-
|
23
|
-
protected
|
24
|
-
|
25
|
-
# Generates a hash of server properties from the instance variables of the
|
26
|
-
# including packet object
|
27
|
-
def generate_info_hash
|
28
|
-
@info_hash = Hash[
|
29
|
-
*instance_variables.map { |var|
|
30
|
-
[var[1..-1].to_sym, instance_variable_get(var)] if var != '@content_data' && var != '@header_data'
|
31
|
-
}.compact.flatten
|
32
|
-
]
|
21
|
+
def info
|
22
|
+
@info ||= {}
|
33
23
|
end
|
34
24
|
|
35
25
|
end
|
@@ -1,7 +1,7 @@
|
|
1
1
|
# This code is free software; you can redistribute it and/or modify it under
|
2
2
|
# the terms of the new BSD License.
|
3
3
|
#
|
4
|
-
# Copyright (c) 2008-
|
4
|
+
# Copyright (c) 2008-2013, Sebastian Staudt
|
5
5
|
|
6
6
|
require 'steam/packets/s2a_info_base_packet'
|
7
7
|
|
@@ -24,38 +24,36 @@ class S2A_INFO_DETAILED_Packet
|
|
24
24
|
def initialize(data)
|
25
25
|
super S2A_INFO_DETAILED_HEADER, data
|
26
26
|
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
if
|
41
|
-
|
42
|
-
|
43
|
-
|
27
|
+
info[:game_ip] = @content_data.cstring
|
28
|
+
info[:server_name] = @content_data.cstring
|
29
|
+
info[:map_name] = @content_data.cstring
|
30
|
+
info[:game_directory] = @content_data.cstring
|
31
|
+
info[:game_description] = @content_data.cstring
|
32
|
+
info[:number_of_players] = @content_data.byte
|
33
|
+
info[:max_players] = @content_data.byte
|
34
|
+
info[:network_version] = @content_data.byte
|
35
|
+
info[:dedicated] = @content_data.byte.chr
|
36
|
+
info[:operating_system] = @content_data.byte.chr
|
37
|
+
info[:password_needed] = @content_data.byte == 1
|
38
|
+
info[:is_mod] = @content_data.byte == 1
|
39
|
+
|
40
|
+
if info[:is_mod]
|
41
|
+
info[:mod_info] = {}
|
42
|
+
info[:mod_info][:url_info] = @content_data.cstring
|
43
|
+
info[:mod_info][:url_dl] = @content_data.cstring
|
44
44
|
@content_data.byte
|
45
45
|
if @content_data.remaining == 12
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
46
|
+
info[:mod_info][:mod_version] = @content_data.long
|
47
|
+
info[:mod_info][:mod_size] = @content_data.long
|
48
|
+
info[:mod_info][:sv_only] = @content_data.byte == 1
|
49
|
+
info[:mod_info][:cl_dll] = @content_data.byte == 1
|
50
|
+
info[:secure] = @content_data.byte == 1
|
51
|
+
info[:number_of_bots] = @content_data.byte
|
52
52
|
end
|
53
53
|
else
|
54
|
-
|
55
|
-
|
54
|
+
info[:secure] = @content_data.byte == 1
|
55
|
+
info[:number_of_bots] = @content_data.byte
|
56
56
|
end
|
57
|
-
|
58
|
-
generate_info_hash
|
59
57
|
end
|
60
58
|
|
61
59
|
end
|