agent_orange 0.0.6 → 0.0.7
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/bin/agent_orange_example +3 -0
- data/lib/agent_orange/base.rb +58 -0
- data/lib/agent_orange/browser.rb +33 -41
- data/lib/agent_orange/device.rb +25 -42
- data/lib/agent_orange/engine.rb +8 -47
- data/lib/agent_orange/operating_system.rb +33 -52
- data/lib/agent_orange/platform.rb +34 -6
- data/lib/agent_orange/version.rb +8 -1
- metadata +4 -3
data/bin/agent_orange_example
CHANGED
@@ -0,0 +1,58 @@
|
|
1
|
+
module AgentOrange
|
2
|
+
class Base
|
3
|
+
|
4
|
+
def initialize(user_agent)
|
5
|
+
self.parse(user_agent)
|
6
|
+
end
|
7
|
+
|
8
|
+
def parse_user_agent_string_into_groups(user_agent)
|
9
|
+
results = user_agent.scan(/([^\/[:space:]]*)(\/([^[:space:]]*))?([[:space:]]*\[[a-zA-Z][a-zA-Z]\])?[[:space:]]*(\((([^()]|(\([^()]*\)))*)\))?[[:space:]]*/i)
|
10
|
+
groups = []
|
11
|
+
results.each do |result|
|
12
|
+
if result[0] != "" # Add the group of content if name isn't blank
|
13
|
+
groups << { :name => result[0], :version => result[2], :comment => result[5] }
|
14
|
+
end
|
15
|
+
end
|
16
|
+
groups
|
17
|
+
end
|
18
|
+
|
19
|
+
def parse_comment(comment)
|
20
|
+
groups = []
|
21
|
+
comment.split('; ').each do |piece|
|
22
|
+
content = { :name => nil, :version => nil }
|
23
|
+
|
24
|
+
# Remove 'like Mac OS X' or similar since it distracts from real results
|
25
|
+
piece = piece.scan(/(.+) like .+$/i)[0][0] if piece =~ /(.+) like (.+)$/i
|
26
|
+
|
27
|
+
if piece =~ /(.+)[ \/]([\w.]+)$/i
|
28
|
+
chopped = piece.scan(/(.+)[ \/]([\w.]+)$/i)[0]
|
29
|
+
groups << { :name => chopped[0], :version => chopped[1] }
|
30
|
+
end
|
31
|
+
end
|
32
|
+
groups
|
33
|
+
end
|
34
|
+
|
35
|
+
def determine_type(types={}, content="")
|
36
|
+
# Determine type
|
37
|
+
type = nil
|
38
|
+
types.each do |key, value|
|
39
|
+
type = key if content =~ /(#{value})/i
|
40
|
+
end
|
41
|
+
type = "other" if type.nil?
|
42
|
+
type
|
43
|
+
end
|
44
|
+
|
45
|
+
def debug_raw_content(content)
|
46
|
+
AgentOrange.debug " Raw Name : #{content[:name]}", 2
|
47
|
+
AgentOrange.debug " Raw Version: #{content[:version]}", 2
|
48
|
+
AgentOrange.debug " Raw Comment: #{content[:comment]}", 2
|
49
|
+
end
|
50
|
+
|
51
|
+
def debug_content(content)
|
52
|
+
AgentOrange.debug " Type: #{self.type}", 2
|
53
|
+
AgentOrange.debug " Name: #{self.name}", 2
|
54
|
+
AgentOrange.debug " Version: #{self.version}", 2
|
55
|
+
end
|
56
|
+
|
57
|
+
end
|
58
|
+
end
|
data/lib/agent_orange/browser.rb
CHANGED
@@ -1,7 +1,8 @@
|
|
1
|
+
require 'agent_orange/base'
|
1
2
|
require 'agent_orange/version'
|
2
3
|
|
3
4
|
module AgentOrange
|
4
|
-
class Browser
|
5
|
+
class Browser < Base
|
5
6
|
attr_accessor :type, :name, :version
|
6
7
|
attr_accessor :security
|
7
8
|
|
@@ -12,53 +13,44 @@ module AgentOrange
|
|
12
13
|
:safari => 'Safari'
|
13
14
|
}
|
14
15
|
|
15
|
-
def initialize(user_agent)
|
16
|
-
self.parse(user_agent)
|
17
|
-
end
|
18
|
-
|
19
16
|
def parse(user_agent)
|
20
17
|
AgentOrange.debug "BROWSER PARSING", 2
|
21
|
-
|
22
|
-
groups
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
#
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
# Determine browser type
|
36
|
-
if name =~ /(#{BROWSERS[:ie]})/i
|
37
|
-
self.type = "ie"
|
38
|
-
elsif name =~ /(#{BROWSERS[:firefox]})/i
|
39
|
-
self.type = "firefox"
|
40
|
-
elsif name =~ /(#{BROWSERS[:safari]})/i
|
41
|
-
self.type = "safari"
|
42
|
-
elsif name =~ /(#{BROWSERS[:opera]})/i
|
43
|
-
self.type = "opera"
|
44
|
-
else
|
45
|
-
self.type = "other"
|
18
|
+
|
19
|
+
groups = parse_user_agent_string_into_groups(user_agent)
|
20
|
+
groups.each_with_index do |content,i|
|
21
|
+
if content[:name] =~ /(#{BROWSERS.collect{|cat,regex| regex}.join(')|(')})/i
|
22
|
+
# Matched group against name
|
23
|
+
self.populate(content)
|
24
|
+
elsif content[:comment] =~ /(#{BROWSERS.collect{|cat,regex| regex}.join(')|(')})/i
|
25
|
+
# Matched group against comment
|
26
|
+
chosen_content = { :name => nil, :version => nil }
|
27
|
+
additional_groups = parse_comment(content[:comment])
|
28
|
+
additional_groups.each do |additional_content|
|
29
|
+
if additional_content[:name] =~ /(#{BROWSERS.collect{|cat,regex| regex}.join(')|(')})/i
|
30
|
+
chosen_content = additional_content
|
31
|
+
end
|
46
32
|
end
|
47
|
-
|
48
|
-
|
49
|
-
self.name = name
|
50
|
-
|
51
|
-
# Determine device version
|
52
|
-
self.version = AgentOrange::Version.new(version)
|
53
|
-
|
33
|
+
|
34
|
+
self.populate(chosen_content)
|
54
35
|
end
|
55
|
-
|
56
36
|
end
|
57
37
|
|
38
|
+
self.analysis
|
39
|
+
end
|
40
|
+
|
41
|
+
def populate(content={})
|
42
|
+
self.debug_raw_content(content)
|
43
|
+
AgentOrange.debug "", 2
|
44
|
+
|
45
|
+
self.type = self.determine_type(BROWSERS, content[:name])
|
46
|
+
self.name = content[:name]
|
47
|
+
self.version = AgentOrange::Version.new(content[:version])
|
48
|
+
self
|
49
|
+
end
|
50
|
+
|
51
|
+
def analysis
|
58
52
|
AgentOrange.debug "BROWSER ANALYSIS", 2
|
59
|
-
|
60
|
-
AgentOrange.debug " Name: #{self.name}", 2
|
61
|
-
AgentOrange.debug " Version: #{self.version}", 2
|
53
|
+
self.debug_content(:type => self.type, :name => self.name, :version => self.version)
|
62
54
|
AgentOrange.debug "", 2
|
63
55
|
end
|
64
56
|
|
data/lib/agent_orange/device.rb
CHANGED
@@ -1,10 +1,11 @@
|
|
1
|
+
require 'agent_orange/base'
|
1
2
|
require 'agent_orange/platform'
|
2
3
|
require 'agent_orange/operating_system'
|
3
4
|
require 'agent_orange/engine'
|
4
5
|
require 'agent_orange/version'
|
5
6
|
|
6
7
|
module AgentOrange
|
7
|
-
class Device
|
8
|
+
class Device < Base
|
8
9
|
attr_accessor :type, :name, :version
|
9
10
|
attr_accessor :platform
|
10
11
|
attr_accessor :operating_system
|
@@ -16,58 +17,40 @@ module AgentOrange
|
|
16
17
|
:bot => 'bot'
|
17
18
|
}
|
18
19
|
|
19
|
-
def initialize(user_agent)
|
20
|
-
self.parse(user_agent)
|
21
|
-
end
|
22
|
-
|
23
20
|
def parse(user_agent)
|
24
21
|
AgentOrange.debug "DEVICE PARSING", 2
|
25
|
-
|
26
|
-
groups
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
if comment =~ /(#{DEVICES.collect{|cat,regex| regex}.join(')|(')})/i
|
32
|
-
# Found the device
|
33
|
-
AgentOrange.debug " Got a device in group #{i+1}!", 2
|
34
|
-
AgentOrange.debug " Group Raw Name : #{name}", 2
|
35
|
-
AgentOrange.debug " Group Raw Version: #{version}", 2
|
36
|
-
AgentOrange.debug " Group Raw Comment: #{comment}", 2
|
37
|
-
AgentOrange.debug "", 2
|
38
|
-
|
39
|
-
# Determine device type
|
40
|
-
if comment =~ /(#{DEVICES[:computer]})/i
|
41
|
-
self.type = "computer"
|
42
|
-
end
|
43
|
-
if comment =~ /(#{DEVICES[:mobile]})/i
|
44
|
-
self.type = "mobile"
|
45
|
-
end
|
46
|
-
if comment =~ /(#{DEVICES[:bot]})/i
|
47
|
-
self.type = "bot"
|
48
|
-
end
|
49
|
-
|
50
|
-
# Determine device name
|
51
|
-
self.name = self.type.capitalize
|
52
|
-
|
53
|
-
# Determine device version
|
54
|
-
self.version = nil
|
55
|
-
|
22
|
+
|
23
|
+
groups = parse_user_agent_string_into_groups(user_agent)
|
24
|
+
groups.each_with_index do |content,i|
|
25
|
+
if content[:comment] =~ /(#{DEVICES.collect{|cat,regex| regex}.join(')|(')})/i
|
26
|
+
# Matched group against name
|
27
|
+
self.populate(content)
|
56
28
|
end
|
57
|
-
|
58
29
|
end
|
59
30
|
|
60
|
-
|
61
|
-
AgentOrange.debug " Type: #{self.type}", 2
|
62
|
-
AgentOrange.debug " Name: #{self.name}", 2
|
63
|
-
AgentOrange.debug " Version: #{self.version}", 2
|
64
|
-
AgentOrange.debug "", 2
|
31
|
+
self.analysis
|
65
32
|
|
66
33
|
self.platform = AgentOrange::Platform.new(user_agent)
|
67
34
|
self.operating_system = AgentOrange::OperatingSystem.new(user_agent)
|
68
35
|
self.engine = AgentOrange::Engine.new(user_agent)
|
69
36
|
end
|
70
37
|
|
38
|
+
def populate(content={})
|
39
|
+
self.debug_raw_content(content)
|
40
|
+
AgentOrange.debug "", 2
|
41
|
+
|
42
|
+
self.type = self.determine_type(DEVICES, content[:comment])
|
43
|
+
self.name = self.type.to_s.capitalize
|
44
|
+
self.version = nil
|
45
|
+
self
|
46
|
+
end
|
47
|
+
|
48
|
+
def analysis
|
49
|
+
AgentOrange.debug "DEVICE ANALYSIS", 2
|
50
|
+
self.debug_content(:type => self.type, :name => self.name, :version => self.version)
|
51
|
+
AgentOrange.debug "", 2
|
52
|
+
end
|
53
|
+
|
71
54
|
def is_computer?(name=nil)
|
72
55
|
if name
|
73
56
|
case name
|
data/lib/agent_orange/engine.rb
CHANGED
@@ -1,9 +1,10 @@
|
|
1
|
+
require 'agent_orange/base'
|
1
2
|
require 'agent_orange/browser'
|
2
3
|
require 'agent_orange/version'
|
3
4
|
require 'pp'
|
4
5
|
|
5
6
|
module AgentOrange
|
6
|
-
class Engine
|
7
|
+
class Engine < Base
|
7
8
|
attr_accessor :type, :name, :version
|
8
9
|
attr_accessor :browser
|
9
10
|
|
@@ -15,14 +16,10 @@ module AgentOrange
|
|
15
16
|
:other => 'Other'
|
16
17
|
}
|
17
18
|
|
18
|
-
def initialize(user_agent)
|
19
|
-
self.parse(user_agent)
|
20
|
-
end
|
21
|
-
|
22
19
|
def parse(user_agent)
|
23
20
|
AgentOrange.debug "ENGINE PARSING", 2
|
24
|
-
|
25
|
-
groups =
|
21
|
+
|
22
|
+
groups = parse_user_agent_string_into_groups(user_agent)
|
26
23
|
groups.each_with_index do |content,i|
|
27
24
|
if content[:name] =~ /(#{ENGINES.collect{|cat,regex| regex}.join(')|(')})/i
|
28
25
|
# Matched group against name
|
@@ -45,45 +42,11 @@ module AgentOrange
|
|
45
42
|
self.browser = AgentOrange::Browser.new(user_agent)
|
46
43
|
end
|
47
44
|
|
48
|
-
def scan_results_into_groups(results)
|
49
|
-
groups = []
|
50
|
-
results.each do |result|
|
51
|
-
if result[0] != "" # Add the group of content if name isn't blank
|
52
|
-
groups << { :name => result[0], :version => result[2], :comment => result[5] }
|
53
|
-
end
|
54
|
-
end
|
55
|
-
groups
|
56
|
-
end
|
57
|
-
|
58
|
-
def parse_comment(comment)
|
59
|
-
groups = []
|
60
|
-
comment.split('; ').each do |piece|
|
61
|
-
content = { :name => nil, :version => nil }
|
62
|
-
if piece =~ /(.+)[ \/]([\w.]+)$/i
|
63
|
-
chopped = piece.scan(/(.+)[ \/]([\w.]+)$/i)[0]
|
64
|
-
groups << { :name => chopped[0], :version => chopped[1] }
|
65
|
-
end
|
66
|
-
end
|
67
|
-
groups
|
68
|
-
end
|
69
|
-
|
70
|
-
def determine_type(content="")
|
71
|
-
# Determine type
|
72
|
-
type = nil
|
73
|
-
ENGINES.each do |key, value|
|
74
|
-
type = key if content =~ /(#{value})/i
|
75
|
-
end
|
76
|
-
type = "other" if type.nil?
|
77
|
-
type
|
78
|
-
end
|
79
|
-
|
80
45
|
def populate(content={})
|
81
|
-
|
82
|
-
AgentOrange.debug " Raw Version: #{content[:version]}", 2
|
83
|
-
AgentOrange.debug " Raw Comment: #{content[:comment]}", 2
|
46
|
+
self.debug_raw_content(content)
|
84
47
|
AgentOrange.debug "", 2
|
85
|
-
|
86
|
-
self.type = self.determine_type(content[:name])
|
48
|
+
|
49
|
+
self.type = self.determine_type(ENGINES, content[:name])
|
87
50
|
self.name = ENGINES[self.type.to_sym]
|
88
51
|
self.version = AgentOrange::Version.new(content[:version])
|
89
52
|
self
|
@@ -91,9 +54,7 @@ module AgentOrange
|
|
91
54
|
|
92
55
|
def analysis
|
93
56
|
AgentOrange.debug "ENGINE ANALYSIS", 2
|
94
|
-
|
95
|
-
AgentOrange.debug " Name: #{self.name}", 2
|
96
|
-
AgentOrange.debug " Version: #{self.version}", 2
|
57
|
+
self.debug_content(:type => self.type, :name => self.name, :version => self.version)
|
97
58
|
AgentOrange.debug "", 2
|
98
59
|
end
|
99
60
|
|
@@ -1,5 +1,7 @@
|
|
1
|
+
require 'agent_orange/base'
|
2
|
+
|
1
3
|
module AgentOrange
|
2
|
-
class OperatingSystem
|
4
|
+
class OperatingSystem < Base
|
3
5
|
attr_accessor :type, :name, :version
|
4
6
|
|
5
7
|
OPERATING_SYSTEMS = {
|
@@ -21,66 +23,45 @@ module AgentOrange
|
|
21
23
|
:osx => 'Mac OS X',
|
22
24
|
:windows => 'Windows'
|
23
25
|
}
|
24
|
-
|
25
|
-
def initialize(user_agent)
|
26
|
-
self.parse(user_agent)
|
27
|
-
end
|
28
26
|
|
29
27
|
def parse(user_agent)
|
30
28
|
AgentOrange.debug "OPERATING SYSTEM PARSING", 2
|
31
|
-
|
32
|
-
groups
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
AgentOrange.debug " Raw Comment: #{comment}", 2
|
43
|
-
AgentOrange.debug "", 2
|
44
|
-
|
45
|
-
# Determine operating system type
|
46
|
-
if comment =~ /(#{OPERATING_SYSTEMS[:android]})/i
|
47
|
-
self.type = "android"
|
48
|
-
end
|
49
|
-
if comment =~ /(#{OPERATING_SYSTEMS[:freebsd]})/i
|
50
|
-
self.type = "freebsd"
|
51
|
-
end
|
52
|
-
if comment =~ /(#{OPERATING_SYSTEMS[:ios]})/i
|
53
|
-
self.type = "ios"
|
54
|
-
end
|
55
|
-
if comment =~ /(#{OPERATING_SYSTEMS[:linux]})/i
|
56
|
-
self.type = "linux"
|
57
|
-
end
|
58
|
-
if comment =~ /(#{OPERATING_SYSTEMS[:netbsd]})/i
|
59
|
-
self.type = "netbsd"
|
60
|
-
end
|
61
|
-
if comment =~ /(#{OPERATING_SYSTEMS[:osx]})/i
|
62
|
-
self.type = "osx"
|
63
|
-
end
|
64
|
-
if comment =~ /(#{OPERATING_SYSTEMS[:windows]})/i
|
65
|
-
self.type = "windows"
|
29
|
+
|
30
|
+
groups = parse_user_agent_string_into_groups(user_agent)
|
31
|
+
groups.each_with_index do |content,i|
|
32
|
+
if content[:comment] =~ /(#{OPERATING_SYSTEMS.collect{|cat,regex| regex}.join(')|(')})/i
|
33
|
+
# Matched group against comment
|
34
|
+
chosen_content = { :name => nil, :version => nil }
|
35
|
+
additional_groups = parse_comment(content[:comment])
|
36
|
+
additional_groups.each do |additional_content|
|
37
|
+
if additional_content[:name] =~ /(#{OPERATING_SYSTEMS.collect{|cat,regex| regex}.join(')|(')})/i
|
38
|
+
chosen_content = additional_content
|
39
|
+
end
|
66
40
|
end
|
67
|
-
|
68
|
-
|
69
|
-
self.name = OPERATING_SYSTEM_NAMES[self.type.to_sym]
|
70
|
-
|
71
|
-
# Determine operating system version
|
72
|
-
self.version = nil
|
41
|
+
|
42
|
+
self.populate(chosen_content)
|
73
43
|
end
|
74
|
-
|
75
44
|
end
|
76
|
-
|
45
|
+
|
46
|
+
self.analysis
|
47
|
+
end
|
48
|
+
|
49
|
+
def populate(content={})
|
50
|
+
self.debug_raw_content(content)
|
51
|
+
AgentOrange.debug "", 2
|
52
|
+
|
53
|
+
self.type = self.determine_type(OPERATING_SYSTEMS, content[:name])
|
54
|
+
self.name = OPERATING_SYSTEM_NAMES[self.type.to_sym]
|
55
|
+
self.version = AgentOrange::Version.new(content[:version])
|
56
|
+
self
|
57
|
+
end
|
58
|
+
|
59
|
+
def analysis
|
77
60
|
AgentOrange.debug "OPERATING SYSTEM ANALYSIS", 2
|
78
|
-
|
79
|
-
AgentOrange.debug " Name: #{self.name}", 2
|
80
|
-
AgentOrange.debug " Version: #{self.version}", 2
|
61
|
+
self.debug_content(:type => self.type, :name => self.name, :version => self.version)
|
81
62
|
AgentOrange.debug "", 2
|
82
63
|
end
|
83
|
-
|
64
|
+
|
84
65
|
def to_s
|
85
66
|
[self.name, self.version].compact.join(' ')
|
86
67
|
end
|
@@ -1,5 +1,7 @@
|
|
1
|
+
require 'agent_orange/base'
|
2
|
+
|
1
3
|
module AgentOrange
|
2
|
-
class Platform
|
4
|
+
class Platform < Base
|
3
5
|
attr_accessor :type, :name, :version
|
4
6
|
|
5
7
|
PLATFORMS = {
|
@@ -16,11 +18,7 @@ module AgentOrange
|
|
16
18
|
:pc => 'PC'
|
17
19
|
}
|
18
20
|
|
19
|
-
def
|
20
|
-
self.parse(user_agent)
|
21
|
-
end
|
22
|
-
|
23
|
-
def parse(user_agent)
|
21
|
+
def old_parse(user_agent)
|
24
22
|
AgentOrange.debug "PLATFORM PARSING", 2
|
25
23
|
groups = user_agent.scan(/([^\/[:space:]]*)(\/([^[:space:]]*))?([[:space:]]*\[[a-zA-Z][a-zA-Z]\])?[[:space:]]*(\((([^()]|(\([^()]*\)))*)\))?[[:space:]]*/i)
|
26
24
|
groups.each_with_index do |pieces,i|
|
@@ -66,6 +64,36 @@ module AgentOrange
|
|
66
64
|
AgentOrange.debug "", 2
|
67
65
|
end
|
68
66
|
|
67
|
+
def parse(user_agent)
|
68
|
+
AgentOrange.debug "PLATFORM PARSING", 2
|
69
|
+
|
70
|
+
groups = parse_user_agent_string_into_groups(user_agent)
|
71
|
+
groups.each_with_index do |content,i|
|
72
|
+
if content[:comment] =~ /(#{PLATFORMS.collect{|cat,regex| regex}.join(')|(')})/i
|
73
|
+
# Matched group against name
|
74
|
+
self.populate(content)
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
self.analysis
|
79
|
+
end
|
80
|
+
|
81
|
+
def populate(content={})
|
82
|
+
self.debug_raw_content(content)
|
83
|
+
AgentOrange.debug "", 2
|
84
|
+
|
85
|
+
self.type = self.determine_type(PLATFORMS, content[:comment])
|
86
|
+
self.name = PLATFORM_NAMES[self.type.to_sym]
|
87
|
+
self.version = nil
|
88
|
+
self
|
89
|
+
end
|
90
|
+
|
91
|
+
def analysis
|
92
|
+
AgentOrange.debug "PLATFORM ANALYSIS", 2
|
93
|
+
self.debug_content(:type => self.type, :name => self.name, :version => self.version)
|
94
|
+
AgentOrange.debug "", 2
|
95
|
+
end
|
96
|
+
|
69
97
|
def to_s
|
70
98
|
[self.name, self.version].compact.join(' ')
|
71
99
|
end
|
data/lib/agent_orange/version.rb
CHANGED
@@ -1,10 +1,11 @@
|
|
1
1
|
module AgentOrange
|
2
|
-
VERSION = "0.0.
|
2
|
+
VERSION = "0.0.7" # This is for the gem and does not conflict with the rest of the functionality
|
3
3
|
|
4
4
|
class Version
|
5
5
|
attr_accessor :major, :minor, :patch_level, :build_number
|
6
6
|
|
7
7
|
def initialize(version_string)
|
8
|
+
version_string = sanitize_version_string(version_string)
|
8
9
|
self.major = nil
|
9
10
|
self.minor = nil
|
10
11
|
self.patch_level = nil
|
@@ -22,5 +23,11 @@ module AgentOrange
|
|
22
23
|
def to_s
|
23
24
|
[self.major, self.minor, self.patch_level, self.build_number].compact.join('.')
|
24
25
|
end
|
26
|
+
|
27
|
+
private
|
28
|
+
|
29
|
+
def sanitize_version_string(version_string)
|
30
|
+
version_string.gsub('_','.')
|
31
|
+
end
|
25
32
|
end
|
26
33
|
end
|
metadata
CHANGED
@@ -1,13 +1,13 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: agent_orange
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
hash:
|
4
|
+
hash: 17
|
5
5
|
prerelease:
|
6
6
|
segments:
|
7
7
|
- 0
|
8
8
|
- 0
|
9
|
-
-
|
10
|
-
version: 0.0.
|
9
|
+
- 7
|
10
|
+
version: 0.0.7
|
11
11
|
platform: ruby
|
12
12
|
authors:
|
13
13
|
- Kevin Elliott
|
@@ -35,6 +35,7 @@ files:
|
|
35
35
|
- agent_orange.gemspec
|
36
36
|
- bin/agent_orange_example
|
37
37
|
- lib/agent_orange.rb
|
38
|
+
- lib/agent_orange/base.rb
|
38
39
|
- lib/agent_orange/browser.rb
|
39
40
|
- lib/agent_orange/device.rb
|
40
41
|
- lib/agent_orange/engine.rb
|