agent_orange 0.1.3 → 0.1.4
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/Gemfile +1 -0
- data/README.rdoc +3 -1
- data/Rakefile +1 -1
- data/lib/agent_orange/browser.rb +9 -0
- data/lib/agent_orange/device.rb +13 -5
- data/lib/agent_orange/version.rb +1 -1
- data/spec/long_user_agent_spec.rb +58 -0
- data/spec/spec_helper.rb +2 -11
- data/spec/user_agent_spec.rb +56 -66
- metadata +32 -9
data/Gemfile
CHANGED
data/README.rdoc
CHANGED
@@ -78,7 +78,7 @@ If you're going to use it with Rails then add the gem to your Gemfile.
|
|
78
78
|
|
79
79
|
=== Looking at the operating system
|
80
80
|
|
81
|
-
>> os = ua.device.
|
81
|
+
>> os = ua.device.operating_system
|
82
82
|
=> "iPhone OS 4.3"
|
83
83
|
>> os.type
|
84
84
|
=> "iphone_os"
|
@@ -163,6 +163,8 @@ A warm thank you to all contributors to the project, who have put effort and tim
|
|
163
163
|
* David Rice (@davidjrice) - RSpec tests and bug fixes.
|
164
164
|
* Joshua Siler (@eatenbyagrue) - Bot detection, initial test, and bug fixes.
|
165
165
|
* Alexander Rozumiy (@brain-geek) - Rspec testing for 1.9, updated travis-ci config, updated useragents to test against.
|
166
|
+
* Joe Lencioni (@lencioni) - Improved bot detection.
|
167
|
+
* Todd Huss (@thuss) of Two Bit Labs (@twobitlabs) - Google Mobile crawler detection as mobile and bot.
|
166
168
|
|
167
169
|
== License
|
168
170
|
|
data/Rakefile
CHANGED
@@ -1,4 +1,5 @@
|
|
1
1
|
require 'bundler/gem_tasks'
|
2
|
+
require 'rake/dsl_definition'
|
2
3
|
Dir.glob('./lib/tasks/*.rake').each { |r| import r }
|
3
4
|
|
4
5
|
begin
|
@@ -9,6 +10,5 @@ begin
|
|
9
10
|
# t.pattern = "./spec/**/*_spec.rb" # don't need this, it's default.
|
10
11
|
# Put spec opts in a file named .rspec in root
|
11
12
|
end
|
12
|
-
|
13
13
|
task :default => :spec
|
14
14
|
end
|
data/lib/agent_orange/browser.rb
CHANGED
@@ -10,9 +10,12 @@ module AgentOrange
|
|
10
10
|
:ie => 'MSIE|Internet Explorer|IE',
|
11
11
|
:firefox => 'Firefox',
|
12
12
|
:opera => 'Opera',
|
13
|
+
:chrome => 'Chrome',
|
13
14
|
:safari => 'Safari'
|
14
15
|
}
|
15
16
|
|
17
|
+
BROWSER_TITLES = BROWSERS.merge :ie => 'MSIE'
|
18
|
+
|
16
19
|
def parse(user_agent)
|
17
20
|
AgentOrange.debug "BROWSER PARSING", 2
|
18
21
|
|
@@ -21,6 +24,7 @@ module AgentOrange
|
|
21
24
|
if content[:name] =~ /(#{BROWSERS.collect{|cat,regex| regex}.join(')|(')})/i
|
22
25
|
# Matched group against name
|
23
26
|
self.populate(content)
|
27
|
+
break
|
24
28
|
elsif content[:comment] =~ /(#{BROWSERS.collect{|cat,regex| regex}.join(')|(')})/i
|
25
29
|
# Matched group against comment
|
26
30
|
chosen_content = { :name => nil, :version => nil }
|
@@ -28,6 +32,11 @@ module AgentOrange
|
|
28
32
|
additional_groups.each do |additional_content|
|
29
33
|
if additional_content[:name] =~ /(#{BROWSERS.collect{|cat,regex| regex}.join(')|(')})/i
|
30
34
|
chosen_content = additional_content
|
35
|
+
|
36
|
+
#Additional checking for chromeframe, iemobile, etc.
|
37
|
+
BROWSERS.each do |cat, regex|
|
38
|
+
chosen_content[:name] = BROWSER_TITLES[cat] if additional_content[:name] =~ /(#{regex})/i
|
39
|
+
end
|
31
40
|
end
|
32
41
|
end
|
33
42
|
|
data/lib/agent_orange/device.rb
CHANGED
@@ -6,15 +6,18 @@ require 'agent_orange/version'
|
|
6
6
|
|
7
7
|
module AgentOrange
|
8
8
|
class Device < Base
|
9
|
-
attr_accessor :type, :name, :version
|
9
|
+
attr_accessor :type, :name, :version, :bot
|
10
10
|
attr_accessor :platform
|
11
11
|
attr_accessor :operating_system
|
12
12
|
attr_accessor :engine
|
13
13
|
|
14
14
|
DEVICES = {
|
15
15
|
:computer => 'windows|macintosh|x11|linux',
|
16
|
-
:mobile => 'ipod|ipad|iphone|palm|android|opera mini|hiptop|windows ce|smartphone|mobile|treo|psp'
|
17
|
-
|
16
|
+
:mobile => 'ipod|ipad|iphone|palm|android|opera mini|hiptop|windows ce|smartphone|mobile|treo|psp'
|
17
|
+
}
|
18
|
+
|
19
|
+
BOTS = {
|
20
|
+
:bot => 'alexa|bot|crawl(er|ing)|facebookexternalhit|feedburner|google web preview|nagios|postrank|pingdom|slurp|spider|yahoo!|yandex'
|
18
21
|
}
|
19
22
|
|
20
23
|
def parse(user_agent)
|
@@ -22,7 +25,8 @@ module AgentOrange
|
|
22
25
|
|
23
26
|
groups = parse_user_agent_string_into_groups(user_agent)
|
24
27
|
groups.each_with_index do |content,i|
|
25
|
-
|
28
|
+
devices_and_bots = DEVICES.merge(BOTS)
|
29
|
+
if content[:comment] =~ /(#{devices_and_bots.collect{|cat,regex| regex}.join(')|(')})/i
|
26
30
|
# Matched group against name
|
27
31
|
self.populate(content)
|
28
32
|
end
|
@@ -40,6 +44,10 @@ module AgentOrange
|
|
40
44
|
AgentOrange.debug "", 2
|
41
45
|
|
42
46
|
self.type = self.determine_type(DEVICES, content[:comment])
|
47
|
+
self.bot = self.determine_type(BOTS, content[:comment]) == :bot
|
48
|
+
if (self.bot && self.type == "other")
|
49
|
+
self.type = :bot # backwards compatability
|
50
|
+
end
|
43
51
|
self.name = self.type.to_s.capitalize
|
44
52
|
self.version = nil
|
45
53
|
self
|
@@ -86,7 +94,7 @@ module AgentOrange
|
|
86
94
|
return self.name.downcase.include?(name.to_s.downcase)
|
87
95
|
end
|
88
96
|
else
|
89
|
-
|
97
|
+
self.bot
|
90
98
|
end
|
91
99
|
end
|
92
100
|
|
data/lib/agent_orange/version.rb
CHANGED
@@ -1,5 +1,5 @@
|
|
1
1
|
module AgentOrange
|
2
|
-
VERSION = "0.1.
|
2
|
+
VERSION = "0.1.4" # 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
|
@@ -0,0 +1,58 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/spec_helper'
|
2
|
+
require 'net/http'
|
3
|
+
require 'iconv'
|
4
|
+
|
5
|
+
describe AgentOrange::UserAgent do
|
6
|
+
describe 'checking with real browsers list' do
|
7
|
+
before do
|
8
|
+
@lists = [Iconv.new('UTF-8//IGNORE', 'UTF-8').iconv( File.open("spec/fixtures/browser_ids.htm").read)]
|
9
|
+
|
10
|
+
begin
|
11
|
+
@lists.push Net::HTTP.get('www.zytrax.com', '/tech/web/browser_ids.htm')
|
12
|
+
rescue
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
it "should parse browsers from list" do
|
17
|
+
[
|
18
|
+
{
|
19
|
+
:a_name => 'chrome',
|
20
|
+
:browser_names => ['Chrome', 'Safari']
|
21
|
+
},
|
22
|
+
{
|
23
|
+
:a_name => 'safari',
|
24
|
+
:browser_names => ['Safari']
|
25
|
+
},
|
26
|
+
{
|
27
|
+
:a_name => 'firefox',
|
28
|
+
:browser_names => ['Firefox']
|
29
|
+
},
|
30
|
+
{
|
31
|
+
:a_name => 'msie',
|
32
|
+
#chromeframe!
|
33
|
+
:browser_names => ['MSIE', 'Chrome']
|
34
|
+
},
|
35
|
+
{
|
36
|
+
:a_name => 'opera',
|
37
|
+
:browser_names => ['Opera']
|
38
|
+
}
|
39
|
+
].each do |params|
|
40
|
+
part = ''
|
41
|
+
|
42
|
+
@lists.each do |list|
|
43
|
+
part += list.scan(/<a name="#{params[:a_name]}">.+?<a name="/m).first.to_s
|
44
|
+
end
|
45
|
+
|
46
|
+
part.scan(/<p class="g-c-s">([^<]+)<\/p>/).each do |q|
|
47
|
+
unless params[:browser_names]== ['Opera'] && q.first == 'Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1)'
|
48
|
+
ua = AgentOrange::UserAgent.new(q.first)
|
49
|
+
br_name = ua.device.engine.browser.name
|
50
|
+
|
51
|
+
puts "Test failing at user id: '#{q}'" unless params[:browser_names].include?(br_name)
|
52
|
+
params[:browser_names].should include(br_name)
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
data/spec/spec_helper.rb
CHANGED
@@ -1,15 +1,6 @@
|
|
1
1
|
require 'rubygems'
|
2
|
-
require 'bundler'
|
3
|
-
|
4
|
-
Bundler.setup(:default, :development)
|
5
|
-
rescue Bundler::BundlerError => e
|
6
|
-
$stderr.puts e.message
|
7
|
-
$stderr.puts "Run `bundle install` to install missing gems"
|
8
|
-
exit e.status_code
|
9
|
-
end
|
10
|
-
|
11
|
-
require File.join(File.dirname(__FILE__), "user_agent_matcher")
|
12
|
-
|
2
|
+
require 'bundler/setup'
|
3
|
+
require File.join(File.dirname(__FILE__), 'user_agent_matcher')
|
13
4
|
|
14
5
|
$LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
|
15
6
|
$LOAD_PATH.unshift(File.dirname(__FILE__))
|
data/spec/user_agent_spec.rb
CHANGED
@@ -9,6 +9,7 @@ describe AgentOrange::UserAgent do
|
|
9
9
|
ua.device.type.should == :computer
|
10
10
|
ua.device.name.should == "Computer"
|
11
11
|
ua.device.version.should == nil
|
12
|
+
ua.device.bot.should == false
|
12
13
|
|
13
14
|
ua.device.operating_system.name.should == "Mac OS X"
|
14
15
|
ua.device.operating_system.version.to_s.should == "10.6.8"
|
@@ -22,24 +23,6 @@ describe AgentOrange::UserAgent do
|
|
22
23
|
ua.device.engine.browser.name.should == "Safari"
|
23
24
|
ua.device.engine.browser.version.to_s.should == "533.21.1"
|
24
25
|
end
|
25
|
-
|
26
|
-
detect "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_7_1) AppleWebKit/535.5 (KHTML, like Gecko) Chrome/16.0.891.1 Safari/535.5" do |ua|
|
27
|
-
ua.device.type.should == :computer
|
28
|
-
ua.device.name.should == "Computer"
|
29
|
-
ua.device.version.should == nil
|
30
|
-
|
31
|
-
ua.device.operating_system.name.should == "Mac OS X"
|
32
|
-
ua.device.operating_system.version.to_s.should == "10.7.1"
|
33
|
-
|
34
|
-
ua.device.platform.name.should == "Macintosh"
|
35
|
-
ua.device.platform.version.should == nil
|
36
|
-
|
37
|
-
ua.device.engine.name.should == "AppleWebKit"
|
38
|
-
ua.device.engine.version.to_s.should == "535.5"
|
39
|
-
|
40
|
-
ua.device.engine.browser.name.should == "Safari"
|
41
|
-
ua.device.engine.browser.version.to_s.should == "535.5"
|
42
|
-
end
|
43
26
|
end
|
44
27
|
|
45
28
|
describe "Firefox" do
|
@@ -47,6 +30,7 @@ describe AgentOrange::UserAgent do
|
|
47
30
|
ua.device.type.should == :computer
|
48
31
|
ua.device.name.should == "Computer"
|
49
32
|
ua.device.version.should == nil
|
33
|
+
ua.device.bot.should == false
|
50
34
|
|
51
35
|
ua.device.operating_system.name.should == "Linux"
|
52
36
|
ua.device.operating_system.version.to_s.should == "i686"
|
@@ -68,6 +52,7 @@ describe AgentOrange::UserAgent do
|
|
68
52
|
ua.device.type.should == :computer
|
69
53
|
ua.device.name.should == "Computer"
|
70
54
|
ua.device.version.should == nil
|
55
|
+
ua.device.bot.should == false
|
71
56
|
|
72
57
|
ua.device.operating_system.name.should == "Windows"
|
73
58
|
ua.device.operating_system.version.to_s.should == "5.1"
|
@@ -78,61 +63,66 @@ describe AgentOrange::UserAgent do
|
|
78
63
|
ua.device.engine.name.should == "AppleWebKit"
|
79
64
|
ua.device.engine.version.to_s.should == "535.2"
|
80
65
|
|
81
|
-
|
82
|
-
ua.device.engine.browser.
|
83
|
-
ua.device.engine.browser.version.to_s.should == "535.2"
|
66
|
+
ua.device.engine.browser.name.should == "Chrome"
|
67
|
+
ua.device.engine.browser.version.to_s.should == "15.0.872.0"
|
84
68
|
end
|
85
|
-
end
|
86
69
|
|
87
|
-
|
88
|
-
|
89
|
-
|
70
|
+
detect "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_7_1) AppleWebKit/535.5 (KHTML, like Gecko) Chrome/16.0.891.1 Safari/535.5" do |ua|
|
71
|
+
ua.device.type.should == :computer
|
72
|
+
ua.device.name.should == "Computer"
|
73
|
+
ua.device.version.should == nil
|
74
|
+
ua.device.bot.should == false
|
75
|
+
|
76
|
+
ua.device.operating_system.name.should == "Mac OS X"
|
77
|
+
ua.device.operating_system.version.to_s.should == "10.7.1"
|
90
78
|
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
79
|
+
ua.device.platform.name.should == "Macintosh"
|
80
|
+
ua.device.platform.version.should == nil
|
81
|
+
|
82
|
+
ua.device.engine.name.should == "AppleWebKit"
|
83
|
+
ua.device.engine.version.to_s.should == "535.5"
|
96
84
|
|
97
|
-
|
98
|
-
|
99
|
-
{
|
100
|
-
:a_name => 'chrome',
|
101
|
-
:browser_names => ['Safari']
|
102
|
-
},
|
103
|
-
{
|
104
|
-
:a_name => 'safari',
|
105
|
-
:browser_names => ['Safari']
|
106
|
-
},
|
107
|
-
{
|
108
|
-
:a_name => 'firefox',
|
109
|
-
:browser_names => ['Firefox']
|
110
|
-
},
|
111
|
-
{
|
112
|
-
:a_name => 'msie',
|
113
|
-
:browser_names => ['MSIE','IEMobile']
|
114
|
-
},
|
115
|
-
{
|
116
|
-
:a_name => 'opera',
|
117
|
-
:browser_names => ['Opera']
|
118
|
-
}
|
119
|
-
].each do |params|
|
120
|
-
part = ''
|
121
|
-
|
122
|
-
@lists.each do |list|
|
123
|
-
part += list.scan(/<a name="#{params[:a_name]}">.+?<a name="/m).first.to_s
|
124
|
-
end
|
125
|
-
|
126
|
-
part.scan(/<p class="g-c-s">([^<]+)<\/p>/).each do |q|
|
127
|
-
ua = AgentOrange::UserAgent.new(q.first)
|
128
|
-
br_name = ua.device.engine.browser.name
|
129
|
-
|
130
|
-
params[:browser_names].should include(br_name)
|
131
|
-
end
|
132
|
-
end
|
85
|
+
ua.device.engine.browser.name.should == "Chrome"
|
86
|
+
ua.device.engine.browser.version.to_s.should == "16.0.891.1"
|
133
87
|
end
|
134
88
|
|
89
|
+
detect "Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 5.1; Trident/4.0; chromeframe/13.0.782.218; chromeframe; .NET CLR 1.1.4322; .NET CLR 2.0.50727; .NET CLR 3.0.04506.30; .NET CLR 3.0.04506.648; .NET CLR 3.5.21022; .NET CLR 3.0.4506.2152; .NET CLR 3.5.30729)" do |ua|
|
90
|
+
ua.device.type.should == :computer
|
91
|
+
ua.device.name.should == "Computer"
|
92
|
+
ua.device.version.should == nil
|
93
|
+
ua.device.bot.should == false
|
94
|
+
|
95
|
+
ua.device.engine.browser.name.should == "Chrome"
|
96
|
+
ua.device.engine.browser.version.to_s.should == "13.0.782.218"
|
97
|
+
end
|
135
98
|
end
|
99
|
+
|
100
|
+
describe "Google User Agents" do
|
101
|
+
detect "Mozilla/5.0 (iPhone; U; CPU iPhone OS 4_1 like Mac OS X; en-us) AppleWebKit/532.9 (KHTML, like Gecko) Version/4.0.5 Mobile/8B117 Safari/6531.22.7 (compatible; Googlebot-Mobile/2.1; +http://www.google.com/bot.html)" do |ua|
|
102
|
+
ua.device.type.should == :mobile
|
103
|
+
ua.device.name.should == "Mobile"
|
104
|
+
ua.device.version.should == nil
|
105
|
+
ua.device.bot.should == true
|
106
|
+
ua.is_mobile?.should == true
|
107
|
+
ua.is_computer?.should == false
|
108
|
+
ua.is_bot?.should == true
|
136
109
|
|
110
|
+
ua.device.engine.browser.name.should == "Safari"
|
111
|
+
ua.device.engine.browser.version.to_s.should == "6531.22.7"
|
112
|
+
end
|
113
|
+
|
114
|
+
detect "Mozilla/5.0 (compatible; Googlebot/2.1; +http://www.google.com/bot.html)" do |ua|
|
115
|
+
ua.device.type.should == :bot
|
116
|
+
ua.device.name.should == "Bot"
|
117
|
+
ua.device.version.should == nil
|
118
|
+
ua.device.bot.should == true
|
119
|
+
ua.is_mobile?.should == false
|
120
|
+
ua.is_computer?.should == false
|
121
|
+
ua.is_bot?.should == true
|
137
122
|
|
123
|
+
ua.device.engine.browser.name.should == nil
|
124
|
+
ua.device.engine.browser.version.to_s.should == ""
|
125
|
+
end
|
126
|
+
|
127
|
+
end
|
138
128
|
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: agent_orange
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.1.
|
4
|
+
version: 0.1.4
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,11 +9,11 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date:
|
12
|
+
date: 2012-10-02 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: rake
|
16
|
-
requirement:
|
16
|
+
requirement: !ruby/object:Gem::Requirement
|
17
17
|
none: false
|
18
18
|
requirements:
|
19
19
|
- - ! '>='
|
@@ -21,10 +21,15 @@ dependencies:
|
|
21
21
|
version: '0'
|
22
22
|
type: :development
|
23
23
|
prerelease: false
|
24
|
-
version_requirements:
|
24
|
+
version_requirements: !ruby/object:Gem::Requirement
|
25
|
+
none: false
|
26
|
+
requirements:
|
27
|
+
- - ! '>='
|
28
|
+
- !ruby/object:Gem::Version
|
29
|
+
version: '0'
|
25
30
|
- !ruby/object:Gem::Dependency
|
26
31
|
name: rspec
|
27
|
-
requirement:
|
32
|
+
requirement: !ruby/object:Gem::Requirement
|
28
33
|
none: false
|
29
34
|
requirements:
|
30
35
|
- - ! '>='
|
@@ -32,10 +37,15 @@ dependencies:
|
|
32
37
|
version: '0'
|
33
38
|
type: :development
|
34
39
|
prerelease: false
|
35
|
-
version_requirements:
|
40
|
+
version_requirements: !ruby/object:Gem::Requirement
|
41
|
+
none: false
|
42
|
+
requirements:
|
43
|
+
- - ! '>='
|
44
|
+
- !ruby/object:Gem::Version
|
45
|
+
version: '0'
|
36
46
|
- !ruby/object:Gem::Dependency
|
37
47
|
name: bundler
|
38
|
-
requirement:
|
48
|
+
requirement: !ruby/object:Gem::Requirement
|
39
49
|
none: false
|
40
50
|
requirements:
|
41
51
|
- - ! '>='
|
@@ -43,7 +53,12 @@ dependencies:
|
|
43
53
|
version: '0'
|
44
54
|
type: :development
|
45
55
|
prerelease: false
|
46
|
-
version_requirements:
|
56
|
+
version_requirements: !ruby/object:Gem::Requirement
|
57
|
+
none: false
|
58
|
+
requirements:
|
59
|
+
- - ! '>='
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '0'
|
47
62
|
description: Parse and process User Agents like a secret one
|
48
63
|
email:
|
49
64
|
- kevin@welikeinc.com
|
@@ -71,6 +86,7 @@ files:
|
|
71
86
|
- lib/tasks/allagents.xml
|
72
87
|
- lib/tasks/bot_agent_test.rake
|
73
88
|
- spec/fixtures/browser_ids.htm
|
89
|
+
- spec/long_user_agent_spec.rb
|
74
90
|
- spec/spec_helper.rb
|
75
91
|
- spec/user_agent_matcher.rb
|
76
92
|
- spec/user_agent_spec.rb
|
@@ -86,20 +102,27 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
86
102
|
- - ! '>='
|
87
103
|
- !ruby/object:Gem::Version
|
88
104
|
version: '0'
|
105
|
+
segments:
|
106
|
+
- 0
|
107
|
+
hash: 3447996973066074909
|
89
108
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
90
109
|
none: false
|
91
110
|
requirements:
|
92
111
|
- - ! '>='
|
93
112
|
- !ruby/object:Gem::Version
|
94
113
|
version: '0'
|
114
|
+
segments:
|
115
|
+
- 0
|
116
|
+
hash: 3447996973066074909
|
95
117
|
requirements: []
|
96
118
|
rubyforge_project: agent_orange
|
97
|
-
rubygems_version: 1.8.
|
119
|
+
rubygems_version: 1.8.24
|
98
120
|
signing_key:
|
99
121
|
specification_version: 3
|
100
122
|
summary: Parse and process User Agents like a secret one
|
101
123
|
test_files:
|
102
124
|
- spec/fixtures/browser_ids.htm
|
125
|
+
- spec/long_user_agent_spec.rb
|
103
126
|
- spec/spec_helper.rb
|
104
127
|
- spec/user_agent_matcher.rb
|
105
128
|
- spec/user_agent_spec.rb
|