trafficlogger 1.0.1 → 1.0.2

Sign up to get free protection for your applications and to get access to all the features.
@@ -4,7 +4,8 @@ module Trafficlogger
4
4
  :request_uri,:query_string,:remote_host,:http_accept_encoding,
5
5
  :http_user_agent,:server_protocol,:http_accept_language,:http_host,
6
6
  :remote_addr,:http_referer,:http_cookie,:http_accept,
7
- :request_method,:http_connection,:http_version,:original_full_path
7
+ :request_method,:http_connection,:http_version,:original_full_path,
8
+ :platform,:device,:operating_system
8
9
 
9
10
  class << self
10
11
  def logger(req=nil)
@@ -32,6 +33,12 @@ module Trafficlogger
32
33
  log_data["http_connection"] = data["HTTP_CONNECTION"]
33
34
  log_data["http_version"] = data["HTTP_VERSION"]
34
35
  log_data["original_full_path"] = data["ORIGINAL_FULLPATH"]
36
+ # Extract Relevant Information from User Agent
37
+ operating_system,device,platform = ::Trafficlogger::UAParse.extract data["HTTP_USER_AGENT"].to_s
38
+ log_data["operating_system"] = operating_system
39
+ log_data["device"] = device
40
+ log_data["platform"] = platform
41
+
35
42
  Analytic.create(log_data)
36
43
  end
37
44
 
@@ -40,14 +47,16 @@ module Trafficlogger
40
47
  case searchtype
41
48
  when "path_info"
42
49
  where("path_info = ?",searchterm).order("created_at desc")
43
- when "original_full_path"
44
- where("original_full_path = ?",searchterm).order("created_at desc")
45
50
  when "request_uri"
46
51
  where("request_uri = ?",searchterm).order("created_at desc")
47
- when "http_user_agent"
48
- where("http_user_agent LIKE ?","%#{searchterm}%").order("created_at desc")
49
52
  when "request_method"
50
53
  where("request_method = ?",searchterm).order("created_at desc")
54
+ when "operating_system"
55
+ where("operating_system = ?",searchterm).order("created_at desc")
56
+ when "device"
57
+ where("device = ?",searchterm).order("created_at desc")
58
+ when "platform"
59
+ where("platform = ?",searchterm).order("created_at desc")
51
60
  else
52
61
  order("created_at desc").scoped
53
62
  end
@@ -1,21 +1,25 @@
1
1
  <% if @records.blank? %>
2
2
  <div>
3
3
  <% if params[:searchterm] and params[:searchtype] %>
4
- <h4>There are no records in this Queue for search term <font color='green'><%= params[:searchterm] %></font> and search type <font color='green'><%= params[:searchtype]%></font></h4>
4
+ <h4><font color='red'>No records found...</font></h4>
5
5
  <% end %>
6
6
  </div>
7
7
  <% end %>
8
- <%= will_paginate @records %>
8
+ <div class="r_pagination">
9
+ <%= will_paginate @records %>
10
+ </div>
9
11
  <table class="resultlist" cellspacing='0'>
10
12
  <thead>
11
13
  <tr>
12
14
  <th>ID</th>
13
- <th>Requested URI</th>
14
- <th>Original Requested URI</th>
15
- <th>Original Requested URI(with Host)</th>
16
- <th>Server Name</th>
17
- <th>Request Type</th>
18
- <th>Referer URI</th>
15
+ <th>Request URI</th>
16
+ <th>Full URI</th>
17
+ <th>Server</th>
18
+ <th>Method</th>
19
+ <th>Referer</th>
20
+ <th>User Platform</th>
21
+ <th>User OS</th>
22
+ <th>User Device</th>
19
23
  <th></th>
20
24
  </tr>
21
25
  </thead>
@@ -25,13 +29,15 @@
25
29
  <tr class="<%= klass %>">
26
30
  <td><%= rec.id %></td>
27
31
  <td><%= rec.path_info %></td>
28
- <td><%= rec.original_full_path %></td>
29
32
  <td><%= rec.request_uri %></td>
30
33
  <td><%= rec.server_name %></td>
31
34
  <td><%= rec.request_method %></td>
32
35
  <td><%= rec.http_referer %></td>
36
+ <td><%= rec.operating_system %></td>
37
+ <td><%= rec.device %></td>
38
+ <td><%= rec.platform %></td>
33
39
  <td>
34
- <button class="show_more_button complete_record_details" data="<%= rec.id %>">More</button>
40
+ <button class="r_button complete_record_details" data="<%= rec.id %>">More</button>
35
41
  </td>
36
42
  </tr>
37
43
  <tr>
@@ -39,7 +45,11 @@
39
45
  <table class="resultlist" cellspacing='0'>
40
46
  <tbody>
41
47
  <tr>
42
- <td>User Agent</td>
48
+ <td>URI Path</td>
49
+ <td><%= rec.original_full_path %></td>
50
+ </tr>
51
+ <tr>
52
+ <td>User Agent Data</td>
43
53
  <td><%= rec.http_user_agent %></td>
44
54
  </tr>
45
55
  <tr>
@@ -70,6 +80,10 @@
70
80
  <td>Server Port</td>
71
81
  <td><%= rec.server_port %></td>
72
82
  </tr>
83
+ <tr>
84
+ <td>Created At</td>
85
+ <td><%= rec.created_at %></td>
86
+ </tr>
73
87
  </tbody>
74
88
  </table>
75
89
  </td>
@@ -78,7 +92,9 @@
78
92
  </tobdy>
79
93
  </table>
80
94
  <% if !@records.blank? %>
81
- <%= will_paginate @records %>
95
+ <div class="r_pagination">
96
+ <%= will_paginate @records %>
97
+ </div>
82
98
  <% end %>
83
99
  <script>
84
100
  $(document).ready(function(){
@@ -197,7 +213,7 @@ $(document).ready(function(){
197
213
  background: -moz-linear-gradient(top, #f2f2f2, #f0f0f0);
198
214
  }
199
215
 
200
- .show_more_button {
216
+ .r_button {
201
217
  -moz-box-shadow:inset 0px 1px 0px 0px #bbdaf7;
202
218
  -webkit-box-shadow:inset 0px 1px 0px 0px #bbdaf7;
203
219
  box-shadow:inset 0px 1px 0px 0px #bbdaf7;
@@ -232,12 +248,12 @@ $(document).ready(function(){
232
248
  text-align:center;
233
249
  text-shadow:1px 1px 0px #528ecc;
234
250
  }
235
- .show_more_button:hover {
251
+ .r_button:hover {
236
252
  background:-webkit-gradient( linear, left top, left bottom, color-stop(0.05, #378de5), color-stop(1, #79bbff) );
237
253
  background:-moz-linear-gradient( center top, #378de5 5%, #79bbff 100% );
238
254
  filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#378de5', endColorstr='#79bbff');
239
255
  background-color:#378de5;
240
- }.show_more_button:active {
256
+ }.r_button:active {
241
257
  position:relative;
242
258
  top:1px;
243
259
  }
@@ -5,9 +5,10 @@
5
5
  <%= submit_tag "Search", :name => nil, :id=>"search_results" %>
6
6
  <%= text_field_tag :searchterm, params[:searchterm] %>
7
7
  <%= radio_button_tag 'searchtype', "path_info", true, :class => "searchtype" %> Req URI
8
- <%= radio_button_tag 'searchtype', "original_full_path", false, :class => "searchtype" %> Original Req URI
9
- <%= radio_button_tag 'searchtype', "request_uri", false, :class => "searchtype" %> Original Req URI(with Hostname)
10
- <%= radio_button_tag 'searchtype', "http_user_agent", false, :class => "searchtype" %> User Agent
8
+ <%= radio_button_tag 'searchtype', "request_uri", false, :class => "searchtype" %> Full URI
9
+ <%= radio_button_tag 'searchtype', "operating_system", false, :class => "searchtype" %> User OS
10
+ <%= radio_button_tag 'searchtype', "device", false, :class => "searchtype" %> User Device
11
+ <%= radio_button_tag 'searchtype', "platform", false, :class => "searchtype" %> User Platform
11
12
  <%= radio_button_tag 'searchtype', "request_method", false, :class => "searchtype" %> Request Type
12
13
  </p>
13
14
  <% end %>
@@ -18,8 +19,10 @@
18
19
  </div>
19
20
  </div>
20
21
  <script>
21
- $("#search_results").click(function() {
22
- $.get($("#records_search").attr("action"), $("#records_search").serialize(), null, "script");
23
- return false;
22
+ $(document).ready(function(){
23
+ $("#search_results").click(function() {
24
+ $.get($("#records_search").attr("action"), $("#records_search").serialize(), null, "script");
25
+ return false;
26
+ });
24
27
  });
25
28
  </script>
@@ -11,7 +11,6 @@ class CreateTrafficloggerAnalytics < ActiveRecord::Migration
11
11
  t.string :query_string
12
12
  t.string :remote_host
13
13
  t.text :http_accept_encoding
14
- t.text :http_user_agent
15
14
  t.string :server_protocol
16
15
  t.string :http_accept_language
17
16
  t.string :http_host
@@ -22,6 +21,10 @@ class CreateTrafficloggerAnalytics < ActiveRecord::Migration
22
21
  t.string :request_method
23
22
  t.string :http_connection
24
23
  t.string :http_version
24
+ t.text :http_user_agent
25
+ t.string :platform
26
+ t.string :device
27
+ t.string :operating_system
25
28
  t.timestamps
26
29
  end
27
30
  add_index :trafficlogger_analytics, :server_name
@@ -29,5 +32,8 @@ class CreateTrafficloggerAnalytics < ActiveRecord::Migration
29
32
  add_index :trafficlogger_analytics, :request_uri
30
33
  add_index :trafficlogger_analytics, :path_info
31
34
  add_index :trafficlogger_analytics, :original_full_path
35
+ add_index :trafficlogger_analytics, :platform
36
+ add_index :trafficlogger_analytics, :device
37
+ add_index :trafficlogger_analytics, :operating_system
32
38
  end
33
39
  end
data/lib/trafficlogger.rb CHANGED
@@ -1,4 +1,66 @@
1
1
  require "trafficlogger/engine"
2
-
2
+ require 'yaml'
3
3
  module Trafficlogger
4
+ class UAParse
5
+ class << self
6
+ def extract(ua_string)
7
+ regexes_file = File.join(Trafficlogger::Engine.root,"lib/trafficlogger/regexes.yaml")
8
+ ua_info = YAML.load_file(regexes_file)
9
+ data = process ua_info
10
+ os = extract_operating_system(data[1],ua_string)
11
+ device = extract_device(data[2],ua_string)
12
+ user_agent = extract_user_agent(data[0],ua_string)
13
+ [os,device,user_agent]
14
+ end
15
+
16
+ def process(ua_info)
17
+ ua_info.each_pair do |type, patterns|
18
+ patterns.each do |pattern|
19
+ pattern["regex"] = Regexp.new(pattern["regex"])
20
+ end
21
+ end
22
+ [ua_info["user_agent_parsers"],ua_info["os_parsers"],ua_info["device_parsers"]]
23
+ end
24
+
25
+ def extract_operating_system(os_parsers,str)
26
+ pattern, match = match_first(os_parsers,str)
27
+ if !match.nil?
28
+ match.captures.first.present? ? match.captures.first : 'unidentifed'
29
+ else
30
+ 'unidentifed'
31
+ end
32
+ end
33
+
34
+ def extract_device(platform_parsers,str)
35
+ pattern, match = match_first(platform_parsers,str)
36
+ if !match.nil?
37
+ match.captures.first.present? ? match.captures.first : 'unidentifed'
38
+ else
39
+ 'unidentifed'
40
+ end
41
+ end
42
+
43
+ def extract_user_agent(user_agent_parsers,str)
44
+ pattern, match = match_first(user_agent_parsers,str)
45
+ if !match.nil?
46
+ name = match.captures.first
47
+ if pattern["family_replacement"]
48
+ name = pattern["family_replacement"].sub('$1', name || '')
49
+ end
50
+ name.present? ? name : 'unidentifed'
51
+ else
52
+ 'unidentifed'
53
+ end
54
+ end
55
+
56
+ def match_first(patterns,str)
57
+ patterns.each do |p|
58
+ if m = p["regex"].match(str)
59
+ return [p,m]
60
+ end
61
+ end
62
+ nil
63
+ end
64
+ end
65
+ end
4
66
  end
@@ -0,0 +1,1125 @@
1
+ user_agent_parsers:
2
+ #### The data contained in this file is Copyright 2009 Google Inc. ####
3
+ #### SPECIAL CASES TOP ####
4
+
5
+ # HbbTV standard defines what features the browser should understand.
6
+ # but it's like targeting "HTML5 browsers", effective browser support depends on the model
7
+ # See os_parsers if you want to target a specific TV
8
+ - regex: '(HbbTV)/(\d+)\.(\d+)\.(\d+) \('
9
+
10
+ # must go before Firefox to catch SeaMonkey/Camino
11
+ - regex: '(SeaMonkey|Camino)/(\d+)\.(\d+)\.?([ab]?\d+[a-z]*)'
12
+
13
+ # Firefox
14
+ - regex: '(Pale[Mm]oon)/(\d+)\.(\d+)\.?(\d+)?'
15
+ family_replacement: 'Pale Moon (Firefox Variant)'
16
+ - regex: '(Fennec)/(\d+)\.(\d+)\.?([ab]?\d+[a-z]*)'
17
+ family_replacement: 'Firefox Mobile'
18
+ - regex: '(Fennec)/(\d+)\.(\d+)(pre)'
19
+ family_replacement: 'Firefox Mobile'
20
+ - regex: '(Fennec)/(\d+)\.(\d+)'
21
+ family_replacement: 'Firefox Mobile'
22
+ - regex: 'Mobile.*(Firefox)/(\d+)\.(\d+)'
23
+ family_replacement: 'Firefox Mobile'
24
+ - regex: '(Namoroka|Shiretoko|Minefield)/(\d+)\.(\d+)\.(\d+(?:pre)?)'
25
+ family_replacement: 'Firefox ($1)'
26
+ - regex: '(Firefox)/(\d+)\.(\d+)(a\d+[a-z]*)'
27
+ family_replacement: 'Firefox Alpha'
28
+ - regex: '(Firefox)/(\d+)\.(\d+)(b\d+[a-z]*)'
29
+ family_replacement: 'Firefox Beta'
30
+ - regex: '(Firefox)-(?:\d+\.\d+)?/(\d+)\.(\d+)(a\d+[a-z]*)'
31
+ family_replacement: 'Firefox Alpha'
32
+ - regex: '(Firefox)-(?:\d+\.\d+)?/(\d+)\.(\d+)(b\d+[a-z]*)'
33
+ family_replacement: 'Firefox Beta'
34
+ - regex: '(Namoroka|Shiretoko|Minefield)/(\d+)\.(\d+)([ab]\d+[a-z]*)?'
35
+ family_replacement: 'Firefox ($1)'
36
+ - regex: '(Firefox).*Tablet browser (\d+)\.(\d+)\.(\d+)'
37
+ family_replacement: 'MicroB'
38
+ - regex: '(MozillaDeveloperPreview)/(\d+)\.(\d+)([ab]\d+[a-z]*)?'
39
+
40
+ # e.g.: Flock/2.0b2
41
+ - regex: '(Flock)/(\d+)\.(\d+)(b\d+?)'
42
+
43
+ # RockMelt
44
+ - regex: '(RockMelt)/(\d+)\.(\d+)\.(\d+)'
45
+
46
+ # e.g.: Fennec/0.9pre
47
+ - regex: '(Navigator)/(\d+)\.(\d+)\.(\d+)'
48
+ family_replacement: 'Netscape'
49
+
50
+ - regex: '(Navigator)/(\d+)\.(\d+)([ab]\d+)'
51
+ family_replacement: 'Netscape'
52
+
53
+ - regex: '(Netscape6)/(\d+)\.(\d+)\.(\d+)'
54
+ family_replacement: 'Netscape'
55
+
56
+ - regex: '(MyIBrow)/(\d+)\.(\d+)'
57
+ family_replacement: 'My Internet Browser'
58
+
59
+ # Opera will stop at 9.80 and hide the real version in the Version string.
60
+ # see: http://dev.opera.com/articles/view/opera-ua-string-changes/
61
+ - regex: '(Opera Tablet).*Version/(\d+)\.(\d+)(?:\.(\d+))?'
62
+ - regex: '(Opera)/.+Opera Mobi.+Version/(\d+)\.(\d+)'
63
+ family_replacement: 'Opera Mobile'
64
+ - regex: 'Opera Mobi'
65
+ family_replacement: 'Opera Mobile'
66
+ - regex: '(Opera Mini)/(\d+)\.(\d+)'
67
+ - regex: '(Opera Mini)/att/(\d+)\.(\d+)'
68
+ - regex: '(Opera)/9.80.*Version/(\d+)\.(\d+)(?:\.(\d+))?'
69
+
70
+ # Opera 14 for Android uses a WebKit render engine.
71
+ - regex: '(?:Mobile Safari).*(OPR)/(\d+)\.(\d+)\.(\d+)'
72
+ family_replacement: 'Opera Mobile'
73
+
74
+ # Opera 15 for Desktop is similar to Chrome but includes an "OPR" Version string.
75
+ - regex: '(?:Chrome).*(OPR)/(\d+)\.(\d+)\.(\d+)'
76
+ family_replacement: 'Opera'
77
+
78
+ # Palm WebOS looks a lot like Safari.
79
+ - regex: '(hpw|web)OS/(\d+)\.(\d+)(?:\.(\d+))?'
80
+ family_replacement: 'webOS Browser'
81
+
82
+ # LuaKit has no version info.
83
+ # http://luakit.org/projects/luakit/
84
+ - regex: '(luakit)'
85
+ family_replacement: 'LuaKit'
86
+
87
+ # Snowshoe
88
+ - regex: '(Snowshoe)/(\d+)\.(\d+).(\d+)'
89
+
90
+ # Lightning (for Thunderbird)
91
+ # http://www.mozilla.org/projects/calendar/lightning/
92
+ - regex: '(Lightning)/(\d+)\.(\d+)\.?((?:[ab]?\d+[a-z]*)|(?:\d*))'
93
+
94
+ # Swiftfox
95
+ - regex: '(Firefox)/(\d+)\.(\d+)\.(\d+(?:pre)?) \(Swiftfox\)'
96
+ family_replacement: 'Swiftfox'
97
+ - regex: '(Firefox)/(\d+)\.(\d+)([ab]\d+[a-z]*)? \(Swiftfox\)'
98
+ family_replacement: 'Swiftfox'
99
+
100
+ # Rekonq
101
+ - regex: '(rekonq)/(\d+)\.(\d+)\.?(\d+)? Safari'
102
+ family_replacement: 'Rekonq'
103
+ - regex: 'rekonq'
104
+ family_replacement: 'Rekonq'
105
+
106
+ # Conkeror lowercase/uppercase
107
+ # http://conkeror.org/
108
+ - regex: '(conkeror|Conkeror)/(\d+)\.(\d+)\.?(\d+)?'
109
+ family_replacement: 'Conkeror'
110
+
111
+ # catches lower case konqueror
112
+ - regex: '(konqueror)/(\d+)\.(\d+)\.(\d+)'
113
+ family_replacement: 'Konqueror'
114
+
115
+ - regex: '(WeTab)-Browser'
116
+
117
+ - regex: '(Comodo_Dragon)/(\d+)\.(\d+)\.(\d+)'
118
+ family_replacement: 'Comodo Dragon'
119
+
120
+ # Bots
121
+ - regex: '(YottaaMonitor|BrowserMob|HttpMonitor|YandexBot|Slurp|BingPreview|PagePeeker|ThumbShotsBot|WebThumb|URL2PNG|ZooShot|GomezA|Catchpoint bot|Willow Internet Crawler|Google SketchUp|Read%20Later)'
122
+
123
+ - regex: '(Symphony) (\d+).(\d+)'
124
+
125
+ - regex: '(Minimo)'
126
+
127
+ # Chrome Mobile
128
+ - regex: '(CrMo)/(\d+)\.(\d+)\.(\d+)\.(\d+)'
129
+ family_replacement: 'Chrome Mobile'
130
+ - regex: '(CriOS)/(\d+)\.(\d+)\.(\d+)\.(\d+)'
131
+ family_replacement: 'Chrome Mobile iOS'
132
+ - regex: '(Chrome)/(\d+)\.(\d+)\.(\d+)\.(\d+) Mobile'
133
+ family_replacement: 'Chrome Mobile'
134
+
135
+ # Chrome Frame must come before MSIE.
136
+ - regex: '(chromeframe)/(\d+)\.(\d+)\.(\d+)'
137
+ family_replacement: 'Chrome Frame'
138
+
139
+ # UC Browser
140
+ - regex: '(UCBrowser)[ /](\d+)\.(\d+)\.(\d+)'
141
+ family_replacement: 'UC Browser'
142
+ - regex: '(UC Browser)[ /](\d+)\.(\d+)\.(\d+)'
143
+ - regex: '(UC Browser|UCBrowser|UCWEB)(\d+)\.(\d+)\.(\d+)'
144
+ family_replacement: 'UC Browser'
145
+
146
+ # Tizen Browser (second case included in browser/major.minor regex)
147
+ - regex: '(SLP Browser)/(\d+)\.(\d+)'
148
+ family_replacement: 'Tizen Browser'
149
+
150
+ # Sogou Explorer 2.X
151
+ - regex: '(SE 2\.X) MetaSr (\d+)\.(\d+)'
152
+ family_replacement: 'Sogou Explorer'
153
+
154
+ # Baidu Browsers (desktop spoofs chrome & IE, explorer is mobile)
155
+ - regex: '(baidubrowser)[/\s](\d+)'
156
+ family_replacement: 'Baidu Browser'
157
+ - regex: '(FlyFlow)/(\d+)\.(\d+)'
158
+ family_replacement: 'Baidu Explorer'
159
+
160
+ # Pingdom
161
+ - regex: '(Pingdom.com_bot_version_)(\d+)\.(\d+)'
162
+ family_replacement: 'PingdomBot'
163
+
164
+ # Facebook
165
+ - regex: '(facebookexternalhit)/(\d+)\.(\d+)'
166
+ family_replacement: 'FacebookBot'
167
+
168
+ # LinkedIn
169
+ - regex: '(LinkedInBot)/(\d+)\.(\d+)'
170
+ family_replacement: 'LinkedInBot'
171
+
172
+ # Twitterbot
173
+ - regex: '(Twitterbot)/(\d+)\.(\d+)'
174
+ family_replacement: 'TwitterBot'
175
+
176
+ # Google Plus
177
+ - regex: 'Google.*/\+/web/snippet'
178
+ family_replacement: 'GooglePlusBot'
179
+
180
+ # Rackspace Monitoring
181
+ - regex: '(Rackspace Monitoring)/(\d+)\.(\d+)'
182
+ family_replacement: 'RackspaceBot'
183
+
184
+ # PyAMF
185
+ - regex: '(PyAMF)/(\d+)\.(\d+)\.(\d+)'
186
+
187
+ # Yandex Browser
188
+ - regex: '(YaBrowser)/(\d+)\.(\d+)\.(\d+)'
189
+ family_replacement: 'Yandex Browser'
190
+
191
+ # Mail.ru Amigo/Internet Browser (Chromium-based)
192
+ - regex: '(Chrome)/(\d+)\.(\d+)\.(\d+).* MRCHROME'
193
+ family_replacement: 'Mail.ru Chromium Browser'
194
+
195
+ # AOL Browser (IE-based)
196
+ - regex: '(AOL) (\d+)\.(\d+); AOLBuild (\d+)'
197
+
198
+
199
+
200
+
201
+ #### END SPECIAL CASES TOP ####
202
+
203
+ #### MAIN CASES - this catches > 50% of all browsers ####
204
+
205
+ # Browser/major_version.minor_version.beta_version
206
+ - regex: '(AdobeAIR|FireWeb|Jasmine|ANTGalio|Midori|Fresco|Lobo|PaleMoon|Maxthon|Lynx|OmniWeb|Dillo|Camino|Demeter|Fluid|Fennec|Epiphany|Shiira|Sunrise|Flock|Netscape|Lunascape|WebPilot|Vodafone|NetFront|Netfront|Konqueror|SeaMonkey|Kazehakase|Vienna|Iceape|Iceweasel|IceWeasel|Iron|K-Meleon|Sleipnir|Galeon|GranParadiso|Opera Mini|iCab|NetNewsWire|ThunderBrowse|Iris|UP\.Browser|Bunjalloo|Google Earth|Raven for Mac|Openwave)/(\d+)\.(\d+)\.(\d+)'
207
+
208
+ # Outlook 2007
209
+ - regex: 'MSOffice 12'
210
+ family_replacement: 'Outlook'
211
+ v1_replacement: '2007'
212
+
213
+ # Outlook 2010
214
+ - regex: 'MSOffice 14'
215
+ family_replacement: 'Outlook'
216
+ v1_replacement: '2010'
217
+
218
+ # Outlook 2013
219
+ - regex: 'Microsoft Outlook 15\.\d+\.\d+'
220
+ family_replacement: 'Outlook'
221
+ v1_replacement: '2013'
222
+
223
+ # Apple Air Mail
224
+ - regex: '(Airmail) (\d+)\.(\d+)(?:\.(\d+))?'
225
+
226
+ # Thunderbird
227
+ - regex: '(Thunderbird)/(\d+)\.(\d+)\.(\d+(?:pre)?)'
228
+ family_replacement: 'Thunderbird'
229
+
230
+ # Chrome/Chromium/major_version.minor_version.beta_version
231
+ - regex: '(Chromium|Chrome)/(\d+)\.(\d+)\.(\d+)'
232
+
233
+ # Browser/major_version.minor_version
234
+ - regex: '(bingbot|Bolt|Jasmine|IceCat|Skyfire|Midori|Maxthon|Lynx|Arora|IBrowse|Dillo|Camino|Shiira|Fennec|Phoenix|Chrome|Flock|Netscape|Lunascape|Epiphany|WebPilot|Opera Mini|Opera|Vodafone|NetFront|Netfront|Konqueror|Googlebot|SeaMonkey|Kazehakase|Vienna|Iceape|Iceweasel|IceWeasel|Iron|K-Meleon|Sleipnir|Galeon|GranParadiso|iCab|NetNewsWire|Space Bison|Stainless|Orca|Dolfin|BOLT|Minimo|Tizen Browser|Polaris|Abrowser|Planetweb|ICE Browser)/(\d+)\.(\d+)'
235
+
236
+ # Chrome/Chromium/major_version.minor_version
237
+ - regex: '(Chromium|Chrome)/(\d+)\.(\d+)'
238
+
239
+ # Browser major_version.minor_version.beta_version (space instead of slash)
240
+ - regex: '(iRider|Crazy Browser|SkipStone|iCab|Lunascape|Sleipnir|Maemo Browser) (\d+)\.(\d+)\.(\d+)'
241
+ # Browser major_version.minor_version (space instead of slash)
242
+ - regex: '(iCab|Lunascape|Opera|Android|Jasmine|Polaris) (\d+)\.(\d+)\.?(\d+)?'
243
+
244
+ # Kindle WebKit
245
+ - regex: '(Kindle)/(\d+)\.(\d+)'
246
+
247
+ # weird android UAs
248
+ - regex: '(Android) Donut'
249
+ v1_replacement: '1'
250
+ v2_replacement: '2'
251
+
252
+ - regex: '(Android) Eclair'
253
+ v1_replacement: '2'
254
+ v2_replacement: '1'
255
+
256
+ - regex: '(Android) Froyo'
257
+ v1_replacement: '2'
258
+ v2_replacement: '2'
259
+
260
+ - regex: '(Android) Gingerbread'
261
+ v1_replacement: '2'
262
+ v2_replacement: '3'
263
+
264
+ - regex: '(Android) Honeycomb'
265
+ v1_replacement: '3'
266
+
267
+ # IE Mobile
268
+ - regex: '(IEMobile)[ /](\d+)\.(\d+)'
269
+ family_replacement: 'IE Mobile'
270
+ # desktop mode
271
+ # http://www.anandtech.com/show/3982/windows-phone-7-review
272
+ - regex: '(MSIE) (\d+)\.(\d+).*XBLWP7'
273
+ family_replacement: 'IE Large Screen'
274
+
275
+ #### END MAIN CASES ####
276
+
277
+ #### SPECIAL CASES ####
278
+ - regex: '(Obigo)InternetBrowser'
279
+ - regex: '(Obigo)\-Browser'
280
+ - regex: '(Obigo|OBIGO)[^\d]*(\d+)(?:.(\d+))?'
281
+ family_replacement: 'Obigo'
282
+
283
+ - regex: '(MAXTHON|Maxthon) (\d+)\.(\d+)'
284
+ family_replacement: 'Maxthon'
285
+ - regex: '(Maxthon|MyIE2|Uzbl|Shiira)'
286
+ v1_replacement: '0'
287
+
288
+ - regex: 'PLAYSTATION 3.+WebKit'
289
+ family_replacement: 'NetFront NX'
290
+ - regex: 'PLAYSTATION 3'
291
+ family_replacement: 'NetFront'
292
+ - regex: '(PlayStation Portable)'
293
+ family_replacement: 'NetFront'
294
+ - regex: '(PlayStation Vita)'
295
+ family_replacement: 'NetFront NX'
296
+
297
+ - regex: 'AppleWebKit.+ (NX)/(\d+)\.(\d+)\.(\d+)'
298
+ family_replacement: 'NetFront NX'
299
+ - regex: '(Nintendo 3DS)'
300
+ family_replacement: 'NetFront NX'
301
+
302
+ - regex: '(BrowseX) \((\d+)\.(\d+)\.(\d+)'
303
+
304
+ - regex: '(NCSA_Mosaic)/(\d+)\.(\d+)'
305
+ family_replacement: 'NCSA Mosaic'
306
+
307
+ # Polaris/d.d is above
308
+ - regex: '(POLARIS)/(\d+)\.(\d+)'
309
+ family_replacement: 'Polaris'
310
+ - regex: '(Embider)/(\d+)\.(\d+)'
311
+ family_replacement: 'Polaris'
312
+
313
+ - regex: '(BonEcho)/(\d+)\.(\d+)\.(\d+)'
314
+ family_replacement: 'Bon Echo'
315
+
316
+ - regex: 'M?QQBrowser'
317
+ family_replacement: 'QQ Browser'
318
+
319
+ - regex: '(iPod).+Version/(\d+)\.(\d+)\.(\d+)'
320
+ family_replacement: 'Mobile Safari'
321
+ - regex: '(iPod).*Version/(\d+)\.(\d+)'
322
+ family_replacement: 'Mobile Safari'
323
+ - regex: '(iPhone).*Version/(\d+)\.(\d+)\.(\d+)'
324
+ family_replacement: 'Mobile Safari'
325
+ - regex: '(iPhone).*Version/(\d+)\.(\d+)'
326
+ family_replacement: 'Mobile Safari'
327
+ - regex: '(iPad).*Version/(\d+)\.(\d+)\.(\d+)'
328
+ family_replacement: 'Mobile Safari'
329
+ - regex: '(iPad).*Version/(\d+)\.(\d+)'
330
+ family_replacement: 'Mobile Safari'
331
+ - regex: '(iPod|iPhone|iPad);.*CPU.*OS (\d+)(?:_\d+)?_(\d+).*Mobile'
332
+ family_replacement: 'Mobile Safari'
333
+ - regex: '(iPod|iPhone|iPad)'
334
+ family_replacement: 'Mobile Safari'
335
+
336
+ - regex: '(AvantGo) (\d+).(\d+)'
337
+
338
+ - regex: '(OneBrowser)/(\d+).(\d+)'
339
+ family_replacement: 'ONE Browser'
340
+
341
+ - regex: '(Avant)'
342
+ v1_replacement: '1'
343
+
344
+ # This is the Tesla Model S (see similar entry in device parsers)
345
+ - regex: '(QtCarBrowser)'
346
+ v1_replacement: '1'
347
+
348
+ - regex: '(iBrowser/Mini)(\d+).(\d+)'
349
+ family_replacement: 'iBrowser Mini'
350
+ # nokia browsers
351
+ # based on: http://www.developer.nokia.com/Community/Wiki/User-Agent_headers_for_Nokia_devices
352
+ - regex: '^(Nokia)'
353
+ family_replacement: 'Nokia Services (WAP) Browser'
354
+ - regex: '(NokiaBrowser)/(\d+)\.(\d+).(\d+)\.(\d+)'
355
+ family_replacement: 'Nokia Browser'
356
+ - regex: '(NokiaBrowser)/(\d+)\.(\d+).(\d+)'
357
+ family_replacement: 'Nokia Browser'
358
+ - regex: '(NokiaBrowser)/(\d+)\.(\d+)'
359
+ family_replacement: 'Nokia Browser'
360
+ - regex: '(BrowserNG)/(\d+)\.(\d+).(\d+)'
361
+ family_replacement: 'Nokia Browser'
362
+ - regex: '(Series60)/5\.0'
363
+ family_replacement: 'Nokia Browser'
364
+ v1_replacement: '7'
365
+ v2_replacement: '0'
366
+ - regex: '(Series60)/(\d+)\.(\d+)'
367
+ family_replacement: 'Nokia OSS Browser'
368
+ - regex: '(S40OviBrowser)/(\d+)\.(\d+)\.(\d+)\.(\d+)'
369
+ family_replacement: 'Ovi Browser'
370
+ - regex: '(Nokia)[EN]?(\d+)'
371
+
372
+ # BlackBerry devices
373
+ - regex: '(BB10);'
374
+ family_replacement: 'BlackBerry WebKit'
375
+ - regex: '(PlayBook).+RIM Tablet OS (\d+)\.(\d+)\.(\d+)'
376
+ family_replacement: 'BlackBerry WebKit'
377
+ - regex: '(Black[bB]erry).+Version/(\d+)\.(\d+)\.(\d+)'
378
+ family_replacement: 'BlackBerry WebKit'
379
+ - regex: '(Black[bB]erry)\s?(\d+)'
380
+ family_replacement: 'BlackBerry'
381
+
382
+ - regex: '(OmniWeb)/v(\d+)\.(\d+)'
383
+
384
+ - regex: '(Blazer)/(\d+)\.(\d+)'
385
+ family_replacement: 'Palm Blazer'
386
+
387
+ - regex: '(Pre)/(\d+)\.(\d+)'
388
+ family_replacement: 'Palm Pre'
389
+
390
+ # fork of Links
391
+ - regex: '(ELinks)/(\d+)\.(\d+)'
392
+ - regex: '(ELinks) \((\d+)\.(\d+)'
393
+ - regex: '(Links) \((\d+)\.(\d+)'
394
+
395
+ - regex: '(QtWeb) Internet Browser/(\d+)\.(\d+)'
396
+
397
+ #- regex: '\(iPad;.+(Version)/(\d+)\.(\d+)(?:\.(\d+))?.*Safari/'
398
+ # family_replacement: 'iPad'
399
+
400
+ # Amazon Silk, should go before Safari
401
+ - regex: '(Silk)/(\d+)\.(\d+)(?:\.([0-9\-]+))?'
402
+ family_replacement: 'Amazon Silk'
403
+
404
+ # Phantomjs, should go before Safari
405
+ - regex: '(PhantomJS)/(\d+)\.(\d+)\.(\d+)'
406
+
407
+ # WebKit Nightly
408
+ - regex: '(AppleWebKit)/(\d+)\.?(\d+)?\+ .* Safari'
409
+ family_replacement: 'WebKit Nightly'
410
+
411
+ # Safari
412
+ - regex: '(Version)/(\d+)\.(\d+)(?:\.(\d+))?.*Safari/'
413
+ family_replacement: 'Safari'
414
+ # Safari didn't provide "Version/d.d.d" prior to 3.0
415
+ - regex: '(Safari)/\d+'
416
+
417
+ - regex: '(OLPC)/Update(\d+)\.(\d+)'
418
+
419
+ - regex: '(OLPC)/Update()\.(\d+)'
420
+ v1_replacement: '0'
421
+
422
+ - regex: '(SEMC\-Browser)/(\d+)\.(\d+)'
423
+
424
+ - regex: '(Teleca)'
425
+ family_replacement: 'Teleca Browser'
426
+
427
+ - regex: '(Phantom)/V(\d+)\.(\d+)'
428
+ family_replacement: 'Phantom Browser'
429
+
430
+ - regex: 'Trident(.*)rv.(\d+)\.(\d+)'
431
+ family_replacement: 'IE'
432
+
433
+ # Apple Mail
434
+
435
+ # apple mail - not directly detectable, have it after Safari stuff
436
+ - regex: '(AppleWebKit)/(\d+)\.(\d+)\.(\d+)'
437
+ family_replacement: 'AppleMail'
438
+
439
+ # AFTER THE EDGE CASES ABOVE!
440
+ # AFTER IE11
441
+ # BEFORE all other IE
442
+ - regex: '(Firefox)/(\d+)\.(\d+)\.(\d+)'
443
+ - regex: '(Firefox)/(\d+)\.(\d+)(pre|[ab]\d+[a-z]*)?'
444
+
445
+ - regex: '([MS]?IE) (\d+)\.(\d+)'
446
+ family_replacement: 'IE'
447
+
448
+ - regex: '(python-requests)/(\d+)\.(\d+)'
449
+ family_replacement: 'Python Requests'
450
+
451
+ os_parsers:
452
+ ##########
453
+ # HbbTV vendors
454
+ ##########
455
+
456
+ # starts with the easy one : Panasonic seems consistent across years, hope it will continue
457
+ #HbbTV/1.1.1 (;Panasonic;VIERA 2011;f.532;0071-0802 2000-0000;)
458
+ #HbbTV/1.1.1 (;Panasonic;VIERA 2012;1.261;0071-3103 2000-0000;)
459
+ #HbbTV/1.2.1 (;Panasonic;VIERA 2013;3.672;4101-0003 0002-0000;)
460
+ #- regex: 'HbbTV/\d+\.\d+\.\d+ \(;(Panasonic);VIERA ([0-9]{4});'
461
+
462
+ # Sony is consistent too but do not place year like the other
463
+ # Opera/9.80 (Linux armv7l; HbbTV/1.1.1 (; Sony; KDL32W650A; PKG3.211EUA; 2013;); ) Presto/2.12.362 Version/12.11
464
+ # Opera/9.80 (Linux mips; U; HbbTV/1.1.1 (; Sony; KDL40HX751; PKG1.902EUA; 2012;);; en) Presto/2.10.250 Version/11.60
465
+ # Opera/9.80 (Linux mips; U; HbbTV/1.1.1 (; Sony; KDL22EX320; PKG4.017EUA; 2011;);; en) Presto/2.7.61 Version/11.00
466
+ #- regex: 'HbbTV/\d+\.\d+\.\d+ \(; (Sony);.*;.*; ([0-9]{4});\)'
467
+
468
+
469
+ # LG is consistent too, but we need to add manually the year model
470
+ #Mozilla/5.0 (Unknown; Linux armv7l) AppleWebKit/537.1+ (KHTML, like Gecko) Safari/537.1+ HbbTV/1.1.1 ( ;LGE ;NetCast 4.0 ;03.20.30 ;1.0M ;)
471
+ #Mozilla/5.0 (DirectFB; Linux armv7l) AppleWebKit/534.26+ (KHTML, like Gecko) Version/5.0 Safari/534.26+ HbbTV/1.1.1 ( ;LGE ;NetCast 3.0 ;1.0 ;1.0M ;)
472
+ - regex: 'HbbTV/\d+\.\d+\.\d+ \( ;(LG)E ;NetCast 4.0'
473
+ os_v1_replacement: '2013'
474
+ - regex: 'HbbTV/\d+\.\d+\.\d+ \( ;(LG)E ;NetCast 3.0'
475
+ os_v1_replacement: '2012'
476
+
477
+ # Samsung is on its way of normalizing their user-agent
478
+ # HbbTV/1.1.1 (;Samsung;SmartTV2013;T-FXPDEUC-1102.2;;) WebKit
479
+ # HbbTV/1.1.1 (;Samsung;SmartTV2013;T-MST12DEUC-1102.1;;) WebKit
480
+ # HbbTV/1.1.1 (;Samsung;SmartTV2012;;;) WebKit
481
+ # HbbTV/1.1.1 (;;;;;) Maple_2011
482
+ - regex: 'HbbTV/1.1.1 \(;;;;;\) Maple_2011'
483
+ os_replacement: 'Samsung'
484
+ os_v1_replacement: '2011'
485
+ # manage the two models of 2013
486
+ - regex: 'HbbTV/\d+\.\d+\.\d+ \(;(Samsung);SmartTV([0-9]{4});.*FXPDEUC'
487
+ os_v2_replacement: 'UE40F7000'
488
+ - regex: 'HbbTV/\d+\.\d+\.\d+ \(;(Samsung);SmartTV([0-9]{4});.*MST12DEUC'
489
+ os_v2_replacement: 'UE32F4500'
490
+ # generic Samsung (works starting in 2012)
491
+ #- regex: 'HbbTV/\d+\.\d+\.\d+ \(;(Samsung);SmartTV([0-9]{4});'
492
+
493
+ # Philips : not found any other way than a manual mapping
494
+ # Opera/9.80 (Linux mips; U; HbbTV/1.1.1 (; Philips; ; ; ; ) CE-HTML/1.0 NETTV/4.1.3 PHILIPSTV/1.1.1; en) Presto/2.10.250 Version/11.60
495
+ # Opera/9.80 (Linux mips ; U; HbbTV/1.1.1 (; Philips; ; ; ; ) CE-HTML/1.0 NETTV/3.2.1; en) Presto/2.6.33 Version/10.70
496
+ - regex: 'HbbTV/1.1.1 \(; (Philips);.*NETTV/4'
497
+ os_v1_replacement: '2013'
498
+ - regex: 'HbbTV/1.1.1 \(; (Philips);.*NETTV/3'
499
+ os_v1_replacement: '2012'
500
+ - regex: 'HbbTV/1.1.1 \(; (Philips);.*NETTV/2'
501
+ os_v1_replacement: '2011'
502
+
503
+ # the HbbTV emulator developers use HbbTV/1.1.1 (;;;;;) firetv-firefox-plugin 1.1.20
504
+ - regex: 'HbbTV/\d+\.\d+\.\d+.*(firetv)-firefox-plugin (\d+).(\d+).(\d+)'
505
+ os_replacement: 'FireHbbTV'
506
+
507
+ # generic HbbTV, hoping to catch manufacturer name (always after 2nd comma) and the first string that looks like a 2011-2019 year
508
+ - regex: 'HbbTV/\d+\.\d+\.\d+ \(.*; ?([a-zA-Z]+) ?;.*(201[1-9]).*\)'
509
+
510
+ ##########
511
+ # Android
512
+ # can actually detect rooted android os. do we care?
513
+ ##########
514
+ - regex: '(Android) (\d+)\.(\d+)(?:[.\-]([a-z0-9]+))?'
515
+ - regex: '(Android)\-(\d+)\.(\d+)(?:[.\-]([a-z0-9]+))?'
516
+
517
+ - regex: '(Android) Donut'
518
+ os_v1_replacement: '1'
519
+ os_v2_replacement: '2'
520
+
521
+ - regex: '(Android) Eclair'
522
+ os_v1_replacement: '2'
523
+ os_v2_replacement: '1'
524
+
525
+ - regex: '(Android) Froyo'
526
+ os_v1_replacement: '2'
527
+ os_v2_replacement: '2'
528
+
529
+ - regex: '(Android) Gingerbread'
530
+ os_v1_replacement: '2'
531
+ os_v2_replacement: '3'
532
+
533
+ - regex: '(Android) Honeycomb'
534
+ os_v1_replacement: '3'
535
+
536
+ ##########
537
+ # Kindle Android
538
+ ##########
539
+ - regex: '(Silk-Accelerated=[a-z]{4,5})'
540
+ os_replacement: 'Android'
541
+
542
+ ##########
543
+ # Windows
544
+ # http://en.wikipedia.org/wiki/Windows_NT#Releases
545
+ # possibility of false positive when different marketing names share same NT kernel
546
+ # e.g. windows server 2003 and windows xp
547
+ # lots of ua strings have Windows NT 4.1 !?!?!?!? !?!? !? !????!?! !!! ??? !?!?! ?
548
+ # (very) roughly ordered in terms of frequency of occurence of regex (win xp currently most frequent, etc)
549
+ ##########
550
+
551
+ - regex: '(Windows (?:NT 5\.2|NT 5\.1))'
552
+ os_replacement: 'Windows XP'
553
+
554
+ # ie mobile des ktop mode
555
+ # spoofs nt 6.1. must come before windows 7
556
+ - regex: '(XBLWP7)'
557
+ os_replacement: 'Windows Phone'
558
+
559
+ - regex: '(Windows NT 6\.1)'
560
+ os_replacement: 'Windows 7'
561
+
562
+ - regex: '(Windows NT 6\.0)'
563
+ os_replacement: 'Windows Vista'
564
+
565
+ - regex: '(Win 9x 4\.90)'
566
+ os_replacement: 'Windows Me'
567
+
568
+ - regex: '(Windows 98|Windows XP|Windows ME|Windows 95|Windows CE|Windows 7|Windows NT 4\.0|Windows Vista|Windows 2000|Windows 3.1)'
569
+
570
+ - regex: '(Windows NT 6\.2; ARM;)'
571
+ os_replacement: 'Windows RT'
572
+
573
+ # is this a spoof or is nt 6.2 out and about in some capacity?
574
+ - regex: '(Windows NT 6\.2)'
575
+ os_replacement: 'Windows 8'
576
+
577
+ - regex: '(Windows NT 5\.0)'
578
+ os_replacement: 'Windows 2000'
579
+
580
+ - regex: '(Windows Phone) (\d+)\.(\d+)'
581
+ - regex: '(Windows Phone) OS (\d+)\.(\d+)'
582
+ - regex: '(Windows ?Mobile)'
583
+ os_replacement: 'Windows Mobile'
584
+
585
+ - regex: '(WinNT4.0)'
586
+ os_replacement: 'Windows NT 4.0'
587
+
588
+ - regex: '(Win98)'
589
+ os_replacement: 'Windows 98'
590
+
591
+ ##########
592
+ # Tizen OS from Samsung
593
+ # spoofs Android so pushing it above
594
+ ##########
595
+ - regex: '(Tizen)/(\d+)\.(\d+)'
596
+
597
+ ##########
598
+ # Mac OS
599
+ # http://en.wikipedia.org/wiki/Mac_OS_X#Versions
600
+ ##########
601
+ - regex: '(Mac OS X) (\d+)[_.](\d+)(?:[_.](\d+))?'
602
+
603
+ # IE on Mac doesn't specify version number
604
+ - regex: 'Mac_PowerPC'
605
+ os_replacement: 'Mac OS'
606
+
607
+ # builds before tiger don't seem to specify version?
608
+
609
+ # ios devices spoof (mac os x), so including intel/ppc prefixes
610
+ - regex: '(?:PPC|Intel) (Mac OS X)'
611
+
612
+ ##########
613
+ # iOS
614
+ # http://en.wikipedia.org/wiki/IOS_version_history
615
+ ##########
616
+ - regex: '(CPU OS|iPhone OS) (\d+)_(\d+)(?:_(\d+))?'
617
+ os_replacement: 'iOS'
618
+
619
+ # remaining cases are mostly only opera uas, so catch opera as to not catch iphone spoofs
620
+ - regex: '(iPhone|iPad|iPod); Opera'
621
+ os_replacement: 'iOS'
622
+
623
+ # few more stragglers
624
+ - regex: '(iPhone|iPad|iPod).*Mac OS X.*Version/(\d+)\.(\d+)'
625
+ os_replacement: 'iOS'
626
+
627
+ - regex: '(AppleTV)/(\d+)\.(\d+)'
628
+ os_replacement: 'ATV OS X'
629
+
630
+ ##########
631
+ # Chrome OS
632
+ # if version 0.0.0, probably this stuff:
633
+ # http://code.google.com/p/chromium-os/issues/detail?id=11573
634
+ # http://code.google.com/p/chromium-os/issues/detail?id=13790
635
+ ##########
636
+ - regex: '(CrOS) [a-z0-9_]+ (\d+)\.(\d+)(?:\.(\d+))?'
637
+ os_replacement: 'Chrome OS'
638
+
639
+ ##########
640
+ # Linux distros
641
+ ##########
642
+ - regex: '([Dd]ebian)'
643
+ os_replacement: 'Debian'
644
+ - regex: '(Linux Mint)(?:/(\d+))?'
645
+ - regex: '(Mandriva)(?: Linux)?/(?:[\d.-]+m[a-z]{2}(\d+).(\d))?'
646
+
647
+ ##########
648
+ # Symbian + Symbian OS
649
+ # http://en.wikipedia.org/wiki/History_of_Symbian
650
+ ##########
651
+ - regex: '(Symbian[Oo][Ss])/(\d+)\.(\d+)'
652
+ os_replacement: 'Symbian OS'
653
+ - regex: '(Symbian/3).+NokiaBrowser/7\.3'
654
+ os_replacement: 'Symbian^3 Anna'
655
+ - regex: '(Symbian/3).+NokiaBrowser/7\.4'
656
+ os_replacement: 'Symbian^3 Belle'
657
+ - regex: '(Symbian/3)'
658
+ os_replacement: 'Symbian^3'
659
+ - regex: '(Series 60|SymbOS|S60)'
660
+ os_replacement: 'Symbian OS'
661
+ - regex: '(MeeGo)'
662
+ - regex: 'Symbian [Oo][Ss]'
663
+ os_replacement: 'Symbian OS'
664
+ - regex: 'Series40;'
665
+ os_replacement: 'Nokia Series 40'
666
+
667
+ ##########
668
+ # BlackBerry devices
669
+ ##########
670
+ - regex: '(BB10);.+Version/(\d+)\.(\d+)\.(\d+)'
671
+ os_replacement: 'BlackBerry OS'
672
+ - regex: '(Black[Bb]erry)[0-9a-z]+/(\d+)\.(\d+)\.(\d+)(?:\.(\d+))?'
673
+ os_replacement: 'BlackBerry OS'
674
+ - regex: '(Black[Bb]erry).+Version/(\d+)\.(\d+)\.(\d+)(?:\.(\d+))?'
675
+ os_replacement: 'BlackBerry OS'
676
+ - regex: '(RIM Tablet OS) (\d+)\.(\d+)\.(\d+)'
677
+ os_replacement: 'BlackBerry Tablet OS'
678
+ - regex: '(Play[Bb]ook)'
679
+ os_replacement: 'BlackBerry Tablet OS'
680
+ - regex: '(Black[Bb]erry)'
681
+ os_replacement: 'BlackBerry OS'
682
+
683
+ ##########
684
+ # Firefox OS
685
+ ##########
686
+ - regex: '\((?:Mobile|Tablet);.+Firefox/\d+\.\d+'
687
+ os_replacement: 'Firefox OS'
688
+
689
+ ##########
690
+ # BREW
691
+ # yes, Brew is lower-cased for Brew MP
692
+ ##########
693
+ - regex: '(BREW)[ /](\d+)\.(\d+)\.(\d+)'
694
+ - regex: '(BREW);'
695
+ - regex: '(Brew MP|BMP)[ /](\d+)\.(\d+)\.(\d+)'
696
+ os_replacement: 'Brew MP'
697
+ - regex: 'BMP;'
698
+ os_replacement: 'Brew MP'
699
+
700
+ ##########
701
+ # Google TV
702
+ ##########
703
+ - regex: '(GoogleTV) (\d+)\.(\d+)\.(\d+)'
704
+ # Old style
705
+ - regex: '(GoogleTV)/[\da-z]+'
706
+
707
+ - regex: '(WebTV)/(\d+).(\d+)'
708
+
709
+ ##########
710
+ # Misc mobile
711
+ ##########
712
+ - regex: '(hpw|web)OS/(\d+)\.(\d+)(?:\.(\d+))?'
713
+ os_replacement: 'webOS'
714
+ - regex: '(VRE);'
715
+
716
+ ##########
717
+ # Generic patterns
718
+ # since the majority of os cases are very specific, these go last
719
+ ##########
720
+ # first.second.third.fourth bits
721
+ - regex: '(Fedora|Red Hat|PCLinuxOS)/(\d+)\.(\d+)\.(\d+)\.(\d+)'
722
+
723
+ # first.second.third bits
724
+ - regex: '(Red Hat|Puppy|PCLinuxOS)/(\d+)\.(\d+)\.(\d+)'
725
+
726
+ # first.second bits
727
+ - regex: '(Ubuntu|Kindle|Bada|Lubuntu|BackTrack|Red Hat|Slackware)/(\d+)\.(\d+)'
728
+
729
+ # just os
730
+ - regex: '(Windows|OpenBSD|FreeBSD|NetBSD|Android|WeTab)'
731
+ - regex: '(Ubuntu|Kubuntu|Arch Linux|CentOS|Slackware|Gentoo|openSUSE|SUSE|Red Hat|Fedora|PCLinuxOS|Gentoo|Mageia)'
732
+ - regex: '(Linux)/(\d+)\.(\d+)'
733
+ - regex: '(Linux|BSD)'
734
+ - regex: 'SunOS'
735
+ os_replacement: 'Solaris'
736
+
737
+ device_parsers:
738
+ ##########
739
+ # incomplete!
740
+ # multiple replacement placeholds i.e. ($1) ($2) help solve problem of single device with multiple representations in ua
741
+ # e.g. HTC Dream S should parse to the same device as HTC_DreamS
742
+ ##########
743
+
744
+ ##########
745
+ # incomplete!
746
+ # HTC
747
+ # http://en.wikipedia.org/wiki/List_of_HTC_phones
748
+ # this is quickly getting unwieldy
749
+ ##########
750
+ # example: Mozilla/5.0 (Linux; U; Android 2.3.2; fr-fr; HTC HD2 Build/FRF91) AppleWebKit/533.1 (KHTML, like Gecko) Version/4.0 Mobile Safari/533.1
751
+ - regex: 'HTC ([A-Z][a-z0-9]+) Build'
752
+ device_replacement: 'HTC $1'
753
+ # example: Mozilla/5.0 (Linux; U; Android 2.1; es-es; HTC Legend 1.23.161.1 Build/ERD79) AppleWebKit/530.17 (KHTML, like Gecko) Version/4.0 Mobile Safari/530.17,gzip
754
+ - regex: 'HTC ([A-Z][a-z0-9 ]+) \d+\.\d+\.\d+\.\d+'
755
+ device_replacement: 'HTC $1'
756
+ # example: Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; HTC_Touch_Diamond2_T5353; Windows Phone 6.5.3.5)
757
+ - regex: 'HTC_Touch_([A-Za-z0-9]+)'
758
+ device_replacement: 'HTC Touch ($1)'
759
+ # should come after HTC_Touch
760
+ - regex: 'USCCHTC(\d+)'
761
+ device_replacement: 'HTC $1 (US Cellular)'
762
+ - regex: 'Sprint APA(9292)'
763
+ device_replacement: 'HTC $1 (Sprint)'
764
+ - regex: 'HTC ([A-Za-z0-9]+ [A-Z])'
765
+ device_replacement: 'HTC $1'
766
+ - regex: 'HTC[-_/\s]([A-Za-z0-9]+)'
767
+ device_replacement: 'HTC $1'
768
+ - regex: '(ADR[A-Za-z0-9]+)'
769
+ device_replacement: 'HTC $1'
770
+ - regex: '(HTC)'
771
+
772
+ # Tesla Model S
773
+ - regex: '(QtCarBrowser)'
774
+ device_replacement: 'Tesla Model S'
775
+
776
+ # Samsung
777
+ - regex: '(SamsungSGHi560)'
778
+ device_replacement: 'Samsung SGHi560'
779
+
780
+ #########
781
+ # Ericsson - must come before nokia since they also use symbian
782
+ #########
783
+ - regex: 'SonyEricsson([A-Za-z0-9]+)/'
784
+ device_replacement: 'Ericsson $1'
785
+
786
+ ##########
787
+ # PlayStation
788
+ # The Vita spoofs the Kindle
789
+ ##########
790
+ - regex: 'PLAYSTATION 3'
791
+ device_replacement: 'PlayStation 3'
792
+ - regex: '(PlayStation Portable)'
793
+ - regex: '(PlayStation Vita)'
794
+
795
+ ##########
796
+ # incomplete!
797
+ # Kindle
798
+ # http://amazonsilk.wordpress.com/useful-bits/silk-user-agent/
799
+ ##########
800
+ - regex: '(KFOT Build)'
801
+ device_replacement: 'Kindle Fire'
802
+ - regex: '(KFTT Build)'
803
+ device_replacement: 'Kindle Fire HD'
804
+ - regex: '(KFJWI Build)'
805
+ device_replacement: 'Kindle Fire HD 8.9" WiFi'
806
+ - regex: '(KFJWA Build)'
807
+ device_replacement: 'Kindle Fire HD 8.9" 4G'
808
+ - regex: '(KFSOWI Build)'
809
+ device_replacement: 'Kindle Fire HD 7" WiFi'
810
+ - regex: '(KFTHWI Build)'
811
+ device_replacement: 'Kindle Fire HDX 7" WiFi'
812
+ - regex: '(KFTHWA Build)'
813
+ device_replacement: 'Kindle Fire HDX 7" 4G'
814
+ - regex: '(KFAPWI Build)'
815
+ device_replacement: 'Kindle Fire HDX 8.9" WiFi'
816
+ - regex: '(KFAPWA Build)'
817
+ device_replacement: 'Kindle Fire HDX 8.9" 4G'
818
+ - regex: '(Kindle Fire)'
819
+ - regex: '(Kindle)'
820
+ - regex: '(Silk)/(\d+)\.(\d+)(?:\.([0-9\-]+))?'
821
+ device_replacement: 'Kindle Fire'
822
+
823
+ #########
824
+ # Android General Device Matching (far from perfect)
825
+ #########
826
+ - regex: 'Android[\- ][\d]+\.[\d]+; [A-Za-z]{2}\-[A-Za-z]{0,2}; WOWMobile (.+) Build'
827
+ - regex: 'Android[\- ][\d]+\.[\d]+\-update1; [A-Za-z]{2}\-[A-Za-z]{0,2}; (.+) Build'
828
+ - regex: 'Android[\- ][\d]+\.[\d]+\.[\d]+; [A-Za-z]{2}\-[A-Za-z]{0,2}; (.+) Build'
829
+ - regex: 'Android[\- ][\d]+\.[\d]+\.[\d]+;[A-Za-z]{2}\-[A-Za-z]{0,2};(.+) Build'
830
+ - regex: 'Android[\- ][\d]+\.[\d]+; [A-Za-z]{2}\-[A-Za-z]{0,2}; (.+) Build'
831
+ - regex: 'Android[\- ][\d]+\.[\d]+\.[\d]+; (.+) Build'
832
+ - regex: 'Android[\- ][\d]+\.[\d]+; (.+) Build'
833
+
834
+ ##########
835
+ # NOKIA
836
+ # nokia NokiaN8-00 comes before iphone. sometimes spoofs iphone
837
+ ##########
838
+ - regex: 'NokiaN([0-9]+)'
839
+ device_replacement: 'Nokia N$1'
840
+ - regex: 'NOKIA([A-Za-z0-9\v-]+)'
841
+ device_replacement: 'Nokia $1'
842
+ - regex: 'Nokia([A-Za-z0-9\v-]+)'
843
+ device_replacement: 'Nokia $1'
844
+ - regex: 'NOKIA ([A-Za-z0-9\-]+)'
845
+ device_replacement: 'Nokia $1'
846
+ - regex: 'Nokia ([A-Za-z0-9\-]+)'
847
+ device_replacement: 'Nokia $1'
848
+ - regex: 'Lumia ([A-Za-z0-9\-]+)'
849
+ device_replacement: 'Lumia $1'
850
+ - regex: 'Symbian'
851
+ device_replacement: 'Nokia'
852
+
853
+ ##########
854
+ # BlackBerry
855
+ # http://www.useragentstring.com/pages/BlackBerry/
856
+ ##########
857
+ - regex: 'BB10; ([A-Za-z0-9\- ]+)\)'
858
+ device_replacement: 'BlackBerry $1'
859
+ - regex: '(PlayBook).+RIM Tablet OS'
860
+ device_replacement: 'BlackBerry Playbook'
861
+ - regex: 'Black[Bb]erry ([0-9]+);'
862
+ device_replacement: 'BlackBerry $1'
863
+ - regex: 'Black[Bb]erry([0-9]+)'
864
+ device_replacement: 'BlackBerry $1'
865
+ - regex: 'Black[Bb]erry;'
866
+ device_replacement: 'BlackBerry'
867
+
868
+ ##########
869
+ # PALM / HP
870
+ ##########
871
+ # some palm devices must come before iphone. sometimes spoofs iphone in ua
872
+ - regex: '(Pre)/(\d+)\.(\d+)'
873
+ device_replacement: 'Palm Pre'
874
+ - regex: '(Pixi)/(\d+)\.(\d+)'
875
+ device_replacement: 'Palm Pixi'
876
+ - regex: '(Touch[Pp]ad)/(\d+)\.(\d+)'
877
+ device_replacement: 'HP TouchPad'
878
+ - regex: 'HPiPAQ([A-Za-z0-9]+)/(\d+).(\d+)'
879
+ device_replacement: 'HP iPAQ $1'
880
+ - regex: 'Palm([A-Za-z0-9]+)'
881
+ device_replacement: 'Palm $1'
882
+ - regex: 'Treo([A-Za-z0-9]+)'
883
+ device_replacement: 'Palm Treo $1'
884
+ - regex: 'webOS.*(P160UNA)/(\d+).(\d+)'
885
+ device_replacement: 'HP Veer'
886
+
887
+ ##########
888
+ # AppleTV
889
+ # No built in browser that I can tell
890
+ # Stack Overflow indicated iTunes-AppleTV/4.1 as a known UA for app available and I'm seeing it in live traffic
891
+ ##########
892
+ - regex: '(AppleTV)'
893
+ device_replacement: 'AppleTV'
894
+
895
+ ##########
896
+ # Catch the google mobile crawler before checking for iPhones.
897
+ ##########
898
+
899
+ - regex: 'AdsBot-Google-Mobile'
900
+ device_replacement: 'Spider'
901
+
902
+ - regex: 'Googlebot-Mobile/(\d+).(\d+)'
903
+ device_replacement: 'Spider'
904
+
905
+ ##########
906
+ # complete but probably catches spoofs
907
+ # iSTUFF
908
+ ##########
909
+ # ipad and ipod must be parsed before iphone
910
+ # cannot determine specific device type from ua string. (3g, 3gs, 4, etc)
911
+ - regex: '(iPad) Simulator;'
912
+ - regex: '(iPad);'
913
+ - regex: '(iPod) touch;'
914
+ - regex: '(iPod);'
915
+ - regex: '(iPhone) Simulator;'
916
+ - regex: '(iPhone);'
917
+
918
+ ##########
919
+ # Acer
920
+ ##########
921
+ - regex: 'acer_([A-Za-z0-9]+)_'
922
+ device_replacement: 'Acer $1'
923
+ - regex: 'acer_([A-Za-z0-9]+)_'
924
+ device_replacement: 'Acer $1'
925
+
926
+ ##########
927
+ # Alcatel
928
+ ##########
929
+ - regex: 'ALCATEL-([A-Za-z0-9]+)'
930
+ device_replacement: 'Alcatel $1'
931
+ - regex: 'Alcatel-([A-Za-z0-9]+)'
932
+ device_replacement: 'Alcatel $1'
933
+
934
+ ##########
935
+ # Amoi
936
+ ##########
937
+ - regex: 'Amoi\-([A-Za-z0-9]+)'
938
+ device_replacement: 'Amoi $1'
939
+ - regex: 'AMOI\-([A-Za-z0-9]+)'
940
+ device_replacement: 'Amoi $1'
941
+
942
+ ##########
943
+ # Amoi
944
+ ##########
945
+ - regex: 'Asus\-([A-Za-z0-9]+)'
946
+ device_replacement: 'Asus $1'
947
+ - regex: 'ASUS\-([A-Za-z0-9]+)'
948
+ device_replacement: 'Asus $1'
949
+
950
+ ##########
951
+ # Bird
952
+ ##########
953
+ - regex: 'BIRD\-([A-Za-z0-9]+)'
954
+ device_replacement: 'Bird $1'
955
+ - regex: 'BIRD\.([A-Za-z0-9]+)'
956
+ device_replacement: 'Bird $1'
957
+ - regex: 'BIRD ([A-Za-z0-9]+)'
958
+ device_replacement: 'Bird $1'
959
+
960
+ ##########
961
+ # Dell
962
+ ##########
963
+ - regex: 'Dell ([A-Za-z0-9]+)'
964
+ device_replacement: 'Dell $1'
965
+
966
+ ##########
967
+ # DoCoMo
968
+ ##########
969
+ - regex: 'DoCoMo/2\.0 ([A-Za-z0-9]+)'
970
+ device_replacement: 'DoCoMo $1'
971
+ - regex: '([A-Za-z0-9]+)_W\;FOMA'
972
+ device_replacement: 'DoCoMo $1'
973
+ - regex: '([A-Za-z0-9]+)\;FOMA'
974
+ device_replacement: 'DoCoMo $1'
975
+
976
+ ##########
977
+ # Huawei
978
+ ##########
979
+ - regex: 'Huawei([A-Za-z0-9]+)'
980
+ device_replacement: 'Huawei $1'
981
+ - regex: 'HUAWEI-([A-Za-z0-9]+)'
982
+ device_replacement: 'Huawei $1'
983
+ - regex: 'vodafone([A-Za-z0-9]+)'
984
+ device_replacement: 'Huawei Vodafone $1'
985
+
986
+ ##########
987
+ # i-mate
988
+ ##########
989
+ - regex: 'i\-mate ([A-Za-z0-9]+)'
990
+ device_replacement: 'i-mate $1'
991
+
992
+ ##########
993
+ # kyocera
994
+ ##########
995
+ - regex: 'Kyocera\-([A-Za-z0-9]+)'
996
+ device_replacement: 'Kyocera $1'
997
+ - regex: 'KWC\-([A-Za-z0-9]+)'
998
+ device_replacement: 'Kyocera $1'
999
+
1000
+ ##########
1001
+ # lenovo
1002
+ ##########
1003
+ - regex: 'Lenovo\-([A-Za-z0-9]+)'
1004
+ device_replacement: 'Lenovo $1'
1005
+ - regex: 'Lenovo_([A-Za-z0-9]+)'
1006
+ device_replacement: 'Lenovo $1'
1007
+
1008
+ ##########
1009
+ # HbbTV (European and Australian standard)
1010
+ # written before the LG regexes, as LG is making HbbTV too
1011
+ ##########
1012
+ - regex: '(HbbTV)/[0-9]+\.[0-9]+\.[0-9]+'
1013
+
1014
+ ##########
1015
+ # lg
1016
+ ##########
1017
+ - regex: 'LG/([A-Za-z0-9]+)'
1018
+ device_replacement: 'LG $1'
1019
+ - regex: 'LG-LG([A-Za-z0-9]+)'
1020
+ device_replacement: 'LG $1'
1021
+ - regex: 'LGE-LG([A-Za-z0-9]+)'
1022
+ device_replacement: 'LG $1'
1023
+ - regex: 'LGE VX([A-Za-z0-9]+)'
1024
+ device_replacement: 'LG $1'
1025
+ - regex: 'LG ([A-Za-z0-9]+)'
1026
+ device_replacement: 'LG $1'
1027
+ - regex: 'LGE LG\-AX([A-Za-z0-9]+)'
1028
+ device_replacement: 'LG $1'
1029
+ - regex: 'LG\-([A-Za-z0-9]+)'
1030
+ device_replacement: 'LG $1'
1031
+ - regex: 'LGE\-([A-Za-z0-9]+)'
1032
+ device_replacement: 'LG $1'
1033
+ - regex: 'LG([A-Za-z0-9]+)'
1034
+ device_replacement: 'LG $1'
1035
+
1036
+ ##########
1037
+ # kin
1038
+ ##########
1039
+ - regex: '(KIN)\.One (\d+)\.(\d+)'
1040
+ device_replacement: 'Microsoft $1'
1041
+ - regex: '(KIN)\.Two (\d+)\.(\d+)'
1042
+ device_replacement: 'Microsoft $1'
1043
+
1044
+ ##########
1045
+ # motorola
1046
+ ##########
1047
+ - regex: '(Motorola)\-([A-Za-z0-9]+)'
1048
+ - regex: 'MOTO\-([A-Za-z0-9]+)'
1049
+ device_replacement: 'Motorola $1'
1050
+ - regex: 'MOT\-([A-Za-z0-9]+)'
1051
+ device_replacement: 'Motorola $1'
1052
+
1053
+ ##########
1054
+ # nintendo
1055
+ ##########
1056
+ - regex: '(Nintendo WiiU)'
1057
+ device_replacement: 'Nintendo Wii U'
1058
+ - regex: 'Nintendo (DS|3DS|DSi|Wii);'
1059
+ device_replacement: 'Nintendo $1'
1060
+
1061
+ ##########
1062
+ # pantech
1063
+ ##########
1064
+ - regex: 'Pantech([A-Za-z0-9]+)'
1065
+ device_replacement: 'Pantech $1'
1066
+
1067
+ ##########
1068
+ # philips
1069
+ ##########
1070
+ - regex: 'Philips([A-Za-z0-9]+)'
1071
+ device_replacement: 'Philips $1'
1072
+ - regex: 'Philips ([A-Za-z0-9]+)'
1073
+ device_replacement: 'Philips $1'
1074
+
1075
+ ##########
1076
+ # Samsung
1077
+ ##########
1078
+ - regex: 'SAMSUNG-([A-Za-z0-9\-]+)'
1079
+ device_replacement: 'Samsung $1'
1080
+ - regex: 'SAMSUNG\; ([A-Za-z0-9\-]+)'
1081
+ device_replacement: 'Samsung $1'
1082
+
1083
+ ##########
1084
+ # Sega
1085
+ ##########
1086
+ - regex: 'Dreamcast'
1087
+ device_replacement: 'Sega Dreamcast'
1088
+
1089
+ ##########
1090
+ # Softbank
1091
+ ##########
1092
+ - regex: 'Softbank/1\.0/([A-Za-z0-9]+)'
1093
+ device_replacement: 'Softbank $1'
1094
+ - regex: 'Softbank/2\.0/([A-Za-z0-9]+)'
1095
+ device_replacement: 'Softbank $1'
1096
+
1097
+ ##########
1098
+ # WebTV
1099
+ ##########
1100
+ - regex: '(WebTV)/(\d+).(\d+)'
1101
+
1102
+ ##########
1103
+ # Generic Smart Phone
1104
+ ##########
1105
+ - regex: '(hiptop|avantgo|plucker|xiino|blazer|elaine|up.browser|up.link|mmp|smartphone|midp|wap|vodafone|o2|pocket|mobile|pda)'
1106
+ device_replacement: "Generic Smartphone"
1107
+
1108
+ ##########
1109
+ # Generic Feature Phone
1110
+ ##########
1111
+ - regex: '^(1207|3gso|4thp|501i|502i|503i|504i|505i|506i|6310|6590|770s|802s|a wa|acer|acs\-|airn|alav|asus|attw|au\-m|aur |aus |abac|acoo|aiko|alco|alca|amoi|anex|anny|anyw|aptu|arch|argo|bell|bird|bw\-n|bw\-u|beck|benq|bilb|blac|c55/|cdm\-|chtm|capi|comp|cond|craw|dall|dbte|dc\-s|dica|ds\-d|ds12|dait|devi|dmob|doco|dopo|el49|erk0|esl8|ez40|ez60|ez70|ezos|ezze|elai|emul|eric|ezwa|fake|fly\-|fly_|g\-mo|g1 u|g560|gf\-5|grun|gene|go.w|good|grad|hcit|hd\-m|hd\-p|hd\-t|hei\-|hp i|hpip|hs\-c|htc |htc\-|htca|htcg)'
1112
+ device_replacement: 'Generic Feature Phone'
1113
+ - regex: '^(htcp|htcs|htct|htc_|haie|hita|huaw|hutc|i\-20|i\-go|i\-ma|i230|iac|iac\-|iac/|ig01|im1k|inno|iris|jata|java|kddi|kgt|kgt/|kpt |kwc\-|klon|lexi|lg g|lg\-a|lg\-b|lg\-c|lg\-d|lg\-f|lg\-g|lg\-k|lg\-l|lg\-m|lg\-o|lg\-p|lg\-s|lg\-t|lg\-u|lg\-w|lg/k|lg/l|lg/u|lg50|lg54|lge\-|lge/|lynx|leno|m1\-w|m3ga|m50/|maui|mc01|mc21|mcca|medi|meri|mio8|mioa|mo01|mo02|mode|modo|mot |mot\-|mt50|mtp1|mtv |mate|maxo|merc|mits|mobi|motv|mozz|n100|n101|n102|n202|n203|n300|n302|n500|n502|n505|n700|n701|n710|nec\-|nem\-|newg|neon)'
1114
+ device_replacement: 'Generic Feature Phone'
1115
+ - regex: '^(netf|noki|nzph|o2 x|o2\-x|opwv|owg1|opti|oran|ot\-s|p800|pand|pg\-1|pg\-2|pg\-3|pg\-6|pg\-8|pg\-c|pg13|phil|pn\-2|pt\-g|palm|pana|pire|pock|pose|psio|qa\-a|qc\-2|qc\-3|qc\-5|qc\-7|qc07|qc12|qc21|qc32|qc60|qci\-|qwap|qtek|r380|r600|raks|rim9|rove|s55/|sage|sams|sc01|sch\-|scp\-|sdk/|se47|sec\-|sec0|sec1|semc|sgh\-|shar|sie\-|sk\-0|sl45|slid|smb3|smt5|sp01|sph\-|spv |spv\-|sy01|samm|sany|sava|scoo|send|siem|smar|smit|soft|sony|t\-mo|t218|t250|t600|t610|t618|tcl\-|tdg\-|telm|tim\-|ts70|tsm\-|tsm3|tsm5|tx\-9|tagt)'
1116
+ device_replacement: 'Generic Feature Phone'
1117
+ - regex: '^(talk|teli|topl|tosh|up.b|upg1|utst|v400|v750|veri|vk\-v|vk40|vk50|vk52|vk53|vm40|vx98|virg|vite|voda|vulc|w3c |w3c\-|wapj|wapp|wapu|wapm|wig |wapi|wapr|wapv|wapy|wapa|waps|wapt|winc|winw|wonu|x700|xda2|xdag|yas\-|your|zte\-|zeto|aste|audi|avan|blaz|brew|brvw|bumb|ccwa|cell|cldc|cmd\-|dang|eml2|fetc|hipt|http|ibro|idea|ikom|ipaq|jbro|jemu|jigs|keji|kyoc|kyok|libw|m\-cr|midp|mmef|moto|mwbp|mywa|newt|nok6|o2im|pant|pdxg|play|pluc|port|prox|rozo|sama|seri|smal|symb|treo|upsi|vx52|vx53|vx60|vx61|vx70|vx80|vx81|vx83|vx85|wap\-|webc|whit|wmlb|xda\-|xda_)'
1118
+ device_replacement: 'Generic Feature Phone'
1119
+
1120
+ ##########
1121
+ # Spiders (this is hack...)
1122
+ ##########
1123
+ - regex: '(bingbot|bot|borg|google(^tv)|yahoo|slurp|msnbot|msrbot|openbot|archiver|netresearch|lycos|scooter|altavista|teoma|gigabot|baiduspider|blitzbot|oegp|charlotte|furlbot|http%20client|polybot|htdig|ichiro|mogimogi|larbin|pompos|scrubby|searchsight|seekbot|semanticdiscovery|silk|snappy|speedy|spider|voila|vortex|voyager|zao|zeal|fast\-webcrawler|converacrawler|dataparksearch|findlinks|crawler)'
1124
+ device_replacement: 'Spider'
1125
+