adam 1.0.2

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,8 @@
1
+ module Adam
2
+ VERSION = '1.0.2'
3
+
4
+ autoload :Killmail, 'adam/killmail'
5
+ autoload :KillLog, 'adam/kill_log'
6
+ autoload :Kill, 'adam/kill'
7
+ autoload :Killboard, 'adam/killboard'
8
+ end
@@ -0,0 +1,137 @@
1
+ require 'digest'
2
+
3
+ module Adam
4
+
5
+ class Kill
6
+ attr_accessor :eve_id, :time, :solar_system, :victim, :involved_parties, :loot
7
+
8
+ def initialize
9
+ yield self if block_given?
10
+ end
11
+
12
+ def to_killmail
13
+
14
+ killmail = ""
15
+ killmail << time.strftime("%Y.%m.%d %H:%M")
16
+ killmail << "\n"
17
+ killmail << "Victim: #{victim.pilot}\n"
18
+ killmail << "Corp: #{victim.corporation}\n"
19
+ killmail << "Alliance: #{victim.alliance}\n" if victim.alliance
20
+ killmail << "Alliance: Unknown\n" unless victim.alliance
21
+ killmail << "Faction: #{victim.faction}\n" if victim.faction
22
+ killmail << "Faction: NONE\n" unless victim.faction
23
+ killmail << "Destroyed: #{victim.ship}\n"
24
+ killmail << "System: #{solar_system.name}\n"
25
+ killmail << "Security: #{solar_system.security_status.round(2)}\n"
26
+ killmail << "Damage Taken: #{victim.damage_taken}\n"
27
+ killmail << "\n"
28
+ killmail << "Involved parties:\n"
29
+ killmail << "\n"
30
+
31
+ involved_parties.each do |involved_party|
32
+
33
+ case involved_party.type
34
+
35
+ when "PC"
36
+ killmail << "Name: #{involved_party.pilot} (laid the final blow)\n" if involved_party.final_blow
37
+ killmail << "Name: #{involved_party.pilot}\n" unless involved_party.final_blow
38
+ killmail << "Security: #{involved_party.security_status.round(2)}\n"
39
+ killmail << "Corp: #{involved_party.corporation}\n"
40
+ killmail << "Alliance: #{involved_party.alliance}\n" if involved_party.alliance
41
+ killmail << "Alliance: NONE\n" unless involved_party.alliance
42
+ killmail << "Faction: #{involved_party.faction}\n" if involved_party.faction
43
+ killmail << "Faction: NONE\n" unless involved_party.faction
44
+ killmail << "Ship: #{involved_party.ship}\n"
45
+ killmail << "Weapon: #{involved_party.weapon}\n"
46
+ killmail << "Damage Done: #{involved_party.damage_done}\n"
47
+ killmail << "\n"
48
+
49
+ when "NPC"
50
+ killmail << "Name: #{involved_party.ship} / #{involved_party.corporation or involved_party.faction} (laid the final blow)\n" if involved_party.final_blow
51
+ killmail << "Name: #{involved_party.ship} / #{involved_party.corporation or involved_party.faction}\n" unless involved_party.final_blow
52
+ killmail << "Damage Done: #{involved_party.damage_done}\n"
53
+ killmail << "\n"
54
+
55
+ end
56
+
57
+ end
58
+
59
+ killmail << "\n"
60
+ killmail << "\n"
61
+
62
+ destroyed_items = loot.select { |l| l.dropped == false }
63
+ unless destroyed_items.empty?
64
+ killmail << "Destroyed items:\n"
65
+ killmail << "\n"
66
+ destroyed_items.each do |loot|
67
+ killmail << "#{loot.name}"
68
+ killmail << ", Qty: #{loot.quantity}" if loot.quantity > 1
69
+ killmail << " (Cargo)" if loot.cargo
70
+ killmail << " (Drone Bay)" if loot.drone_bay
71
+ killmail << "\n"
72
+ end
73
+ end
74
+
75
+ dropped_items = loot.select { |l| l.dropped == true }
76
+ unless dropped_items.empty?
77
+ killmail << "Dropped items:\n"
78
+ killmail << "\n"
79
+ dropped_items.each do |loot|
80
+ killmail << "#{loot.name}"
81
+ killmail << ", Qty: #{loot.quantity}" if loot.quantity > 1
82
+ killmail << " (Cargo)" if loot.cargo
83
+ killmail << " (Drone Bay)" if loot.drone_bay
84
+ killmail << "\n"
85
+ end
86
+ end
87
+
88
+ killmail
89
+ end
90
+
91
+ alias_method :to_s, :to_killmail
92
+
93
+ def digest
94
+ string = time.to_s + victim.pilot.to_s + victim.ship.to_s + solar_system.to_s + victim.damage_taken.to_s
95
+ involved_parties.sort! { |x, y| x.damage_done <=> y.damage_done }
96
+ involved_parties.each { |p| string += p.pilot.to_s + p.damage_done.to_s }
97
+ Digest::MD5.hexdigest(string)
98
+ end
99
+
100
+ end
101
+
102
+ class Kill::SolarSystem
103
+ attr_accessor :name, :security_status
104
+
105
+ def initialize
106
+ yield self if block_given?
107
+ end
108
+
109
+ end
110
+
111
+ class Kill::Victim
112
+ attr_accessor :pilot, :corporation, :alliance, :faction, :ship, :damage_taken
113
+
114
+ def initialize
115
+ yield self if block_given?
116
+ end
117
+
118
+ end
119
+
120
+ class Kill::InvolvedParty
121
+ attr_accessor :type, :pilot, :security_status, :corporation, :alliance, :faction, :ship, :weapon, :damage_done, :final_blow
122
+
123
+ def initialize
124
+ yield self if block_given?
125
+ end
126
+
127
+ end
128
+
129
+ class Kill::Loot
130
+ attr_accessor :name, :quantity, :cargo, :drone_bay, :dropped
131
+
132
+ def initialize
133
+ yield self if block_given?
134
+ end
135
+ end
136
+
137
+ end
@@ -0,0 +1,109 @@
1
+ require 'adam/kill_log/validation_error'
2
+ require 'models' unless defined?(SolarSystem) and defined?(Item)
3
+
4
+ require 'hpricot'
5
+ require 'time'
6
+
7
+ module Adam
8
+
9
+ module KillLog
10
+
11
+ extend self
12
+
13
+ def parse(source)
14
+ document = Hpricot(source)
15
+
16
+ kill_logs = []
17
+ document.search("//rowset[@name=kills]/row").each do |kill_log|
18
+ begin
19
+ kill_logs << parse_single(kill_log)
20
+ rescue ValidationError
21
+ next
22
+ end
23
+ end
24
+
25
+ kill_logs
26
+ end
27
+
28
+ private
29
+
30
+ def parse_single(kill_element)
31
+
32
+ kill = Adam::Kill.new do |kill|
33
+
34
+ kill.eve_id = kill_element['killid'].to_i
35
+ kill.time = Time.parse(kill_element['killtime']).utc
36
+
37
+ kill.solar_system = Adam::Kill::SolarSystem.new do |ss|
38
+ ss.name = SolarSystem.find(kill_element['solarsystemid']).name
39
+ ss.security_status = SolarSystem.find(kill_element['solarsystemid']).security_status
40
+ end
41
+
42
+ kill.victim = Adam::Kill::Victim.new do |v|
43
+ victim_element = kill_element.at('/victim')
44
+
45
+ raise ValidationError, "Victim pilot no longer exists" if victim_element['characterid'] != '0' and victim_element['charactername'].empty?
46
+ raise ValidationError, "Victim corporation no longer exists" if victim_element['corporationid'] != '0' and victim_element['corporationname'].empty?
47
+ raise ValidationError, "Victim alliance no longer exists" if victim_element['allianceid'] != '0' and victim_element['alliancename'].empty?
48
+
49
+ v.pilot = victim_element['charactername']
50
+ v.corporation = victim_element['corporationname']
51
+ v.alliance = victim_element['alliancename'] == '' ? false : victim_element['alliancename']
52
+ v.faction = victim_element['factionname'] == '' ? false: victim_element['factionname']
53
+ v.ship = Item.find(victim_element['shiptypeid']).name
54
+ v.damage_taken = victim_element['damagetaken'].to_i
55
+ end
56
+
57
+ kill.involved_parties = []
58
+ kill_element.search('/rowset[@name=attackers]/row').each do |involved_party_element|
59
+
60
+ kill.involved_parties << Adam::Kill::InvolvedParty.new do |ip|
61
+ raise ValidationError, "Involved party pilot no longer exists" if involved_party_element['characterid'] != '0' and involved_party_element['charactername'].empty?
62
+ raise ValidationError, "Involved party corporation no longer exists" if involved_party_element['corporationid'] != '0' and involved_party_element['corporationname'].empty?
63
+ raise ValidationError, "Involved party alliance no longer exists" if involved_party_element['allianceid'] != '0' and involved_party_element['alliancename'].empty?
64
+
65
+ ip.type = involved_party_element['charactername'].empty? ? 'NPC' : 'PC'
66
+ ip.pilot = involved_party_element['charactername'] unless involved_party_element['charactername'].empty?
67
+ ip.corporation = involved_party_element['corporationname']
68
+ ip.alliance = involved_party_element['alliancename'] == '' ? false : involved_party_element['alliancename']
69
+ ip.faction = involved_party_element['factionname'] == '' ? false : involved_party_element['factionname']
70
+ ip.security_status = involved_party_element['securitystatus'].to_f
71
+ ip.ship = Item.find(involved_party_element['shiptypeid']).name
72
+ ip.weapon = Item.find(involved_party_element['weapontypeid']).name
73
+ ip.damage_done = involved_party_element['damagedone'].to_i
74
+ ip.final_blow = involved_party_element['finalblow'] == '1' ? true : false
75
+ end
76
+
77
+ end
78
+
79
+ kill.loot = []
80
+ kill_element.search('/rowset[@name=items]/row').each do |loot_element|
81
+ if loot_element['qtydropped'].to_i > 0
82
+ kill.loot << Adam::Kill::Loot.new do |l|
83
+ l.name = Item.find(loot_element['typeid']).name
84
+ l.quantity = loot_element['qtydropped'].to_i
85
+ l.cargo = loot_element['flag'] == '5' ? true : false
86
+ l.drone_bay = loot_element['flag'] == '87' ? true : false
87
+ l.dropped = true
88
+ end
89
+ end
90
+
91
+ if loot_element['qtydestroyed'].to_i > 0
92
+ kill.loot << Adam::Kill::Loot.new do |l|
93
+ l.name = Item.find(loot_element['typeid']).name
94
+ l.quantity = loot_element['qtydropped'].to_i
95
+ l.cargo = loot_element['flag'] == '5' ? true : false
96
+ l.drone_bay = loot_element['flag'] == '87' ? true : false
97
+ l.dropped = false
98
+ end
99
+ end
100
+ end
101
+
102
+ end
103
+
104
+ return kill
105
+ end
106
+
107
+ end
108
+
109
+ end
@@ -0,0 +1,5 @@
1
+ module Adam
2
+ module KillLog
3
+ class ValidationError < RuntimeError; end
4
+ end
5
+ end
@@ -0,0 +1,52 @@
1
+ require 'adam/killboard/feed_error'
2
+
3
+ require 'date'
4
+ require 'net/http'
5
+ require 'uri'
6
+ require 'cgi'
7
+ require 'hpricot'
8
+
9
+ module Adam
10
+
11
+ class Killboard
12
+ attr_reader :uri, :feed_uri
13
+
14
+ def initialize(options = {})
15
+ @uri, @feed_uri = options[:uri], options[:feed_uri]
16
+ end
17
+
18
+ # Loads an array of killmails from an EDK-compatible feed.
19
+ #
20
+ # +options+ is a hash with these keys:
21
+ # * +week+ - An integer determining which week to import. Defaults to current week.
22
+ # * +year+ - An integer determining which year to import the week from. Defaults to current year.
23
+ def killmails(options = {})
24
+ options = { :week => Date.today.cweek, :year => Date.today.year }.merge!(options)
25
+
26
+ uri = URI.parse(@feed_uri)
27
+
28
+ query_string = { 'week' => options[:week], 'year' => options[:year], 'nocache' => Time.now.to_i }.map{ |k, v| "#{CGI.escape(k.to_s)}=#{CGI.escape(v.to_s)}" }.join("&")
29
+
30
+ response = nil
31
+ connection = Net::HTTP.new(uri.host, uri.port)
32
+ connection.start do |http|
33
+ tries = 0
34
+ begin
35
+ response = http.get(uri.path + '?' + uri.query + '&' + query_string)
36
+ rescue Timeout::Error
37
+ tries += 1
38
+ sleep 10
39
+ retry if tries < 3
40
+ end
41
+ end
42
+
43
+ xml = Hpricot.XML(response.body)
44
+
45
+ raise FeedError.new(response.body), "Feed malformed" unless xml.at('/rss')
46
+
47
+ killmails = xml.search("//item/description").collect { |element| element.inner_text }
48
+ end
49
+
50
+ end
51
+
52
+ end
@@ -0,0 +1,15 @@
1
+ module Adam
2
+
3
+ class Killboard
4
+
5
+ class FeedError < RuntimeError
6
+ attr_reader :source
7
+
8
+ def initialize(source)
9
+ @source = source
10
+ end
11
+ end
12
+
13
+ end
14
+
15
+ end
@@ -0,0 +1,130 @@
1
+ require "adam/killmail/validation_error"
2
+
3
+ require "time"
4
+
5
+ module Adam
6
+
7
+ module Killmail
8
+
9
+ extend self
10
+
11
+ def parse(source)
12
+
13
+ # Normalize line endings
14
+ source.encode! :universal_newline => true
15
+
16
+ kill = Adam::Kill.new do |kill|
17
+
18
+ time = source[/([0-9]{4}\.[0-9]{2}\.[0-9]{2} [0-9]{2}:[0-9]{2})/, 1] or raise ValidationError.new(source), "Time malformed"
19
+ time = Time.parse(time + " UTC")
20
+
21
+ kill.time = time
22
+
23
+ kill.solar_system = Adam::Kill::SolarSystem.new do |ss|
24
+ ss.name = source[/System: (.+)/, 1] or raise ValidationError.new(source), "Solar system malformed"
25
+ ss.security_status = source[/Security: ([\.0-9]+)/, 1].to_f or raise ValidationError.new(source), "Solar system security malformed"
26
+ end
27
+
28
+ kill.victim = Adam::Kill::Victim.new do |v|
29
+ v.pilot = source[/Victim: ([a-zA-Z0-9]{1}[a-zA-Z0-9'. -]{1,48}[a-zA-Z0-9.]{1})/, 1] or raise ValidationError.new(source), "Victim pilot malformed"
30
+ v.corporation = source[/Corp: ([a-zA-Z0-9]{1}[a-zA-Z0-9'. -]{1,48}[a-zA-Z0-9.]{1})/, 1] or raise ValidationError.new(source), "Victim corporation malformed"
31
+ v.alliance = source[/Alliance: ([a-zA-Z0-9]{1}[a-zA-Z0-9'. -]{1,48}[a-zA-Z0-9.]{1})/, 1] or raise ValidationError.new(source), "Victim alliance malformed"
32
+ v.faction = source[/Faction: ([a-zA-Z0-9]{1}[a-zA-Z0-9'. -]{1,48}[a-zA-Z0-9.]{1})/, 1] or raise ValidationError.new(source), "Victim faction malformed"
33
+ v.ship = source[/Destroyed: (.+)/, 1] or raise ValidationError.new(source), "Victim ship malformed"
34
+ v.damage_taken = source[/Damage Taken: ([0-9]+)/, 1].to_i or raise ValidationError.new(source), "Victim damage taken malformed"
35
+
36
+ # Set pilot to nil if it's a moon
37
+ v.pilot = nil if v.pilot =~ /[a-zA-Z0-9\- ]+ - Moon [0-9]+/
38
+
39
+ # Convert alliance/faction from "unknown" or "none" to false
40
+ v.alliance = false if v.alliance =~ /unknown|none/i
41
+ v.faction = false if v.faction =~ /unknown|none/i
42
+ end
43
+
44
+ kill.involved_parties = []
45
+
46
+ involved_parties = source[/Involved parties:\n\n(((.+\n){8}\n|(.+\n){2}\n)*)/, 1] or raise ValidationError.new(source), "Involved parties malformed"
47
+ involved_parties.split("\n\n").each_with_index do |snippet, i|
48
+
49
+ lines = 0 and snippet.each_line { |line| lines += 1 }
50
+
51
+ case lines
52
+
53
+ when 8
54
+ kill.involved_parties << Adam::Kill::InvolvedParty.new do |ip|
55
+ ip.type = "PC"
56
+ ip.pilot = snippet[/Name: ([a-zA-Z0-9]{1}[a-zA-Z0-9'. -]{1,48}[a-zA-Z0-9.]{1})/, 1] or raise ValidationError.new(source), "Involved party #{i+1} pilot malformed"
57
+ ip.security_status = snippet[/Security: ([\-\.0-9]+)/, 1].to_f or raise ValidationError.new(source), "Involved party #{i+1} security malformed"
58
+ ip.corporation = snippet[/Corp: ([a-zA-Z0-9]{1}[a-zA-Z0-9'. -]{1,48}[a-zA-Z0-9.]{1})/, 1] or raise ValidationError.new(source), "Involved party #{i+1} corporation malformed"
59
+ ip.alliance = snippet[/Alliance: ([a-zA-Z0-9]{1}[a-zA-Z0-9'. -]{1,48}[a-zA-Z0-9.]{1})/, 1] or raise ValidationError.new(source), "Involved party #{i+1} alliance malformed"
60
+ ip.faction = snippet[/Faction: ([a-zA-Z0-9]{1}[a-zA-Z0-9'. -]{1,48}[a-zA-Z0-9.]{1})/, 1] or raise ValidationError.new(source), "Involved party #{i+1} faction malformed"
61
+ ip.ship = snippet[/Ship: (.+)/, 1] or raise ValidationError.new(source), "Involved party #{i+1} ship malformed"
62
+ ip.weapon = snippet[/Weapon: (.+)/, 1] or raise ValidationError.new(source), "Involved party #{i+1} weapon malformed"
63
+ ip.damage_done = (snippet[/Damage Done: ([0-9]+)/, 1] or raise ValidationError.new(source), "Involved party #{i+1} damage malformed").to_i
64
+ ip.final_blow = snippet =~ /\(laid the final blow\)/ ? true : false
65
+
66
+ # Convert alliance/faction from "unknown" or "none" to false
67
+ ip.alliance = false if ip.alliance =~ /unknown|none/i
68
+ ip.faction = false if ip.faction =~ /unknown|none/i
69
+ end
70
+
71
+ when 2
72
+ kill.involved_parties << Adam::Kill::InvolvedParty.new do |ip|
73
+ ip.type = "NPC"
74
+ ip.ship = snippet[/Name: ([^\/]+)/, 1] or raise ValidationError.new(source), "Involved party #{i+1} ship malformed"
75
+ ip.damage_done = (snippet[/Damage Done: ([0-9]+)/, 1] or raise ValidationError.new(source), "Involved party #{i+1} damage malformed").to_i
76
+ ip.final_blow = snippet =~ /\(laid the final blow\)/ ? true : false
77
+
78
+ # Determine whether allegiance is a faction or a corporation
79
+ allegiance = snippet[/Name: [^\/]+ \/ ([a-zA-Z0-9]{1}[a-zA-Z0-9'. -]{1,48}[a-zA-Z0-9.]{1})/, 1] or raise ValidationError.new(source), "Involved party #{i+1} allegiance malformed"
80
+ if allegiance =~ /^(Caldari State|Minmatar Republic|Amarr Empire|Gallente Federation|Jove Empire|CONCORD Assembly|Ammatar Mandate|Khanid Kingdom|The Syndicate|Guristas Pirates|Angel Cartel|The Blood Raider Covenant|The InterBus|ORE|Thukker Tribe|The Servant Sisters of EVE|The Society|Mordu's Legion Command|Sansha's Nation|Serpentis)$/
81
+ ip.faction = allegiance
82
+ elsif allegiance == 'Unknown'
83
+ ip.corporation = false
84
+ else
85
+ ip.corporation = allegiance
86
+ end
87
+ end
88
+
89
+ end
90
+
91
+ end
92
+
93
+ kill.loot = []
94
+
95
+ if source =~ /Destroyed items:/
96
+ source[/Destroyed items:\n\n(((.+)\n)*)/, 1].split("\n").each_with_index do |snippet, i|
97
+ loot = Adam::Kill::Loot.new do |l|
98
+ l.name = snippet[/([^,\(\)]+)/, 1] or raise ValidationError.new(source), "Destroyed item #{i+1} name malformed"
99
+ l.quantity = snippet =~ /Qty: ([0-9]+)/ ? snippet[/Qty: ([0-9]+)/, 1].to_i : 1
100
+ l.cargo = snippet[/(Cargo)/] ? true : false
101
+ l.drone_bay = snippet[/(Drone Bay)/] ? true : false
102
+ l.dropped = false
103
+ end
104
+ existing_loot = kill.loot.select { |el| el.name.eql?(loot.name) and el.cargo.eql?(loot.cargo) and el.drone_bay.eql?(loot.drone_bay) and el.dropped.eql?(loot.dropped) }[0]
105
+ existing_loot ? existing_loot.quantity += loot.quantity : kill.loot << loot
106
+ end
107
+ end
108
+
109
+ if source =~ /Dropped items:/
110
+ source[/Dropped items:\n\n(((.+)\n)*)/, 1].split("\n").each_with_index do |snippet, i|
111
+ loot = Adam::Kill::Loot.new do |l|
112
+ l.name = snippet[/([^,\(\)]+)/, 1] or raise ValidationError.new(source), "Dropped item #{i+1} name malformed"
113
+ l.quantity = snippet =~ /Qty: ([0-9]+)/ ? snippet[/Qty: ([0-9]+)/, 1].to_i : 1
114
+ l.cargo = snippet[/(Cargo)/] ? true : false
115
+ l.drone_bay = snippet[/(Drone Bay)/] ? true : false
116
+ l.dropped = true
117
+ end
118
+ existing_loot = kill.loot.select { |el| el.name.eql?(loot.name) and el.cargo.eql?(loot.cargo) and el.drone_bay.eql?(loot.drone_bay) and el.dropped.eql?(loot.dropped) }[0]
119
+ existing_loot ? existing_loot.quantity += loot.quantity : kill.loot << loot
120
+ end
121
+ end
122
+
123
+ end
124
+
125
+ return kill
126
+ end
127
+
128
+ end
129
+
130
+ end