trafficlogger 1.0.1 → 1.0.2

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.
@@ -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
+