Codebase list ruby-user-agent-parser / 7a312df
New upstream release. Debian Janitor 1 year, 3 months ago
29 changed file(s) with 1299 addition(s) and 5328 deletion(s). Raw diff Collapse all Expand all
0 repository_id: '19e90f01-0da7-45f2-b0a7-afc6ad40e30e'
1 api_key: <%= ENV['CODITSU_API_KEY'] %>
2 api_secret: <%= ENV['CODITSU_API_SECRET'] %>
0 name: ci
1
2 on:
3 push:
4 branches: [main]
5 pull_request:
6 branches: [main]
7
8 jobs:
9 specs:
10 runs-on: ubuntu-latest
11 strategy:
12 fail-fast: false
13 matrix:
14 ruby:
15 - '3.1'
16 - '3.0'
17 - '2.7'
18 - '2.6'
19 - '2.5'
20 - 'jruby'
21 include:
22 - ruby: '3.1'
23 coverage: 'true'
24 steps:
25 - uses: actions/checkout@v2
26 with:
27 submodules: true
28 - name: Setup Ruby
29 uses: ruby/setup-ruby@v1
30 with:
31 ruby-version: ${{ matrix.ruby }}
32 - name: Update rubygems
33 run: |
34 gem update --system
35 - uses: actions/cache@v2
36 with:
37 path: vendor/bundle
38 key: bundle-use-ruby-${{ matrix.ruby }}-${{ hashFiles('**/Gemfile.lock') }}
39 restore-keys: |
40 bundle-use-ruby-${{ matrix.ruby }}-
41 - name: Bundle install
42 run: |
43 bundle config path vendor/bundle
44 bundle install --jobs 4 --retry 3
45 - name: Run specs
46 env:
47 GITHUB_COVERAGE: ${{ matrix.coverage }}
48 run: |
49 bundle exec rake test
50
51 # coditsu:
52 # runs-on: ubuntu-latest
53 # strategy:
54 # fail-fast: false
55 # steps:
56 # - uses: actions/checkout@v2
57 # with:
58 # fetch-depth: 0
59 # - name: Run Coditsu
60 # run: \curl -sSL https://api.coditsu.io/run/ci | bash
0 .bundle
1 coverage
2 vendor/bundle
3 .coditsu/local.yml
4 pkg
0 [submodule "vendor/uap-core"]
1 path = vendor/uap-core
2 url = https://github.com/ua-parser/uap-core.git
0 # master
1
2 # 2.13.0 (2022-10-21)
3 * Support loading multiple database files (via #70) (@misdoro)
4 * Support `patterns_path` argument but deprecate `pattern_path` attribute accessor
5 in `UserAgentParser::Parser`
6 * Add new `patterns_paths` array argument `UserAgentParser::Parser` to enable loading
7 multiple patterns files
8
9 # 2.12.0 (2022-10-20)
10
11 * sync with https://github.com/ua-parser/uap-core/commit/dc85ab2628798538a2874dea4a9563f40a31f55a
12 * Memory optimization (via #104) (@casperisfine)
13
14 # 2.11.0 (2022-04-18)
15 * Make user agent versions comparable (via #68) (@misdoro)
16
17 # 2.10.0 (2022-04-18)
18 * sync with uap-core 09e9ccc
19
20 # 2.9.0 (2022-01-27)
21 * sync with uap-core 0.15.0
22
23 # 2.8.0 (2021-11-02)
24 * sync with uap-core 0.14.0
25 * drop support for ruby 2.4
26
27 # 2.7.0 (2020-05-25)
28 * sync with uap-core 0.10.0
0 # frozen_string_literal: true
1
2 source 'https://rubygems.org/'
3
4 gemspec
5
6 group :development, :test do
7 gem 'coveralls_reborn'
8 gem 'minitest'
9 gem 'rake'
10 end
0 PATH
1 remote: .
2 specs:
3 user_agent_parser (2.13.0)
4
5 GEM
6 remote: https://rubygems.org/
7 specs:
8 coveralls_reborn (0.25.0)
9 simplecov (>= 0.18.1, < 0.22.0)
10 term-ansicolor (~> 1.6)
11 thor (>= 0.20.3, < 2.0)
12 tins (~> 1.16)
13 docile (1.4.0)
14 minitest (5.16.3)
15 rake (13.0.6)
16 simplecov (0.21.2)
17 docile (~> 1.1)
18 simplecov-html (~> 0.11)
19 simplecov_json_formatter (~> 0.1)
20 simplecov-html (0.12.3)
21 simplecov_json_formatter (0.1.4)
22 sync (0.5.0)
23 term-ansicolor (1.7.1)
24 tins (~> 1.0)
25 thor (1.2.1)
26 tins (1.31.1)
27 sync
28
29 PLATFORMS
30 java
31 ruby
32
33 DEPENDENCIES
34 coveralls_reborn
35 minitest
36 rake
37 user_agent_parser!
38
39 BUNDLED WITH
40 2.3.24
1616 NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
1717 LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
1818 OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
19 WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
19 WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
0 # UserAgentParser [![Build Status](https://github.com/ua-parser/uap-ruby/actions/workflows/ci.yml/badge.svg)](https://github.com/ua-parser/uap-ruby/actions/workflows/ci.yml) [![Coverage Status](https://coveralls.io/repos/github/ua-parser/uap-ruby/badge.svg)](https://coveralls.io/github/ua-parser/uap-ruby)
1
2 UserAgentParser is a simple, comprehensive Ruby gem for parsing user agent strings. It uses [BrowserScope](http://www.browserscope.org/)'s [parsing patterns](https://github.com/ua-parser/uap-core).
3
4 ## Supported Rubies
5
6 * Ruby 3.0
7 * Ruby 2.7
8 * Ruby 2.6
9 * Ruby 2.5
10 * JRuby
11
12 ## Installation
13
14 ```bash
15 $ gem install user_agent_parser
16 ```
17
18 ## Example usage
19
20 ```ruby
21 require 'user_agent_parser'
22 => true
23 user_agent = UserAgentParser.parse 'Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.0;)'
24 => #<UserAgentParser::UserAgent IE 9.0 (Windows Vista)>
25 user_agent.to_s
26 => "IE 9.0"
27 user_agent.family
28 => "IE"
29 user_agent.version.to_s
30 => "9.0"
31 user_agent.version.major
32 => "9"
33 user_agent.version.minor
34 => "0"
35 user_agent.family == "IE" && user_agent.version >= "9"
36 => true
37 operating_system = user_agent.os
38 => #<UserAgentParser::OperatingSystem Windows Vista>
39 operating_system.to_s
40 => "Windows Vista"
41
42 # Device information can also be determined from some devices
43 user_agent = UserAgentParser.parse "Mozilla/5.0 (Linux; Android 7.0; SAMSUNG SM-G930T Build/NRD90M) AppleWebKit/537.36 (KHTML, like Gecko) SamsungBrowser/5.0 Chrome/51.0.2704.106 Mobile Safari/537.36"
44 => #<UserAgentParser::UserAgent Samsung Internet 5.0 (Android 7.0) (Samsung SM-G930T)>
45 user_agent.device.family
46 => "Samsung SM-G930T"
47 user_agent.device.brand
48 => "Samsung"
49 user_agent.device.model
50 => "SM-G930T"
51
52 user_agent = UserAgentParser.parse "Mozilla/5.0 (iPad; CPU OS 10_2_1 like Mac OS X) AppleWebKit/600.1.4 (KHTML, like Gecko) GSA/23.1.148956103 Mobile/14D27 Safari/600.1.4"
53 => #<UserAgentParser::UserAgent Mobile Safari 10.2.1 (iOS 10.2.1) (iPad)>
54 irb(main):026:0> user_agent.device.family
55 => "iPad"
56 irb(main):027:0> user_agent.device.brand
57 => "Apple"
58 irb(main):028:0> user_agent.device.model
59 => "iPad"
60
61
62 # The parser database will be loaded and parsed on every call to
63 # UserAgentParser.parse. To avoid this, instantiate your own Parser instance.
64 parser = UserAgentParser::Parser.new
65 parser.parse 'Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.0;)'
66 => #<UserAgentParser::UserAgent IE 9.0 (Windows Vista)>
67 parser.parse 'Opera/9.80 (Windows NT 5.1; U; ru) Presto/2.5.24 Version/10.53'
68 => #<UserAgentParser::UserAgent Opera 10.53 (Windows XP)>
69 ```
70
71 In a larger application, you could store a parser in a global to avoid repeat pattern loading:
72
73 ```ruby
74 module MyApplication
75
76 # Instantiate the parser on load as it's quite expensive
77 USER_AGENT_PARSER = UserAgentParser::Parser.new
78
79 def self.user_agent_parser
80 USER_AGENT_PARSER
81 end
82
83 end
84 ```
85
86 ## The pattern database
87
88 The [ua-parser database](https://github.com/ua-parser/uap-core/blob/master/regexes.yaml) is included via a [git submodule](http://help.github.com/submodules/). To update the database the submodule needs to be updated and the gem re-released (pull requests for this are very welcome!).
89
90 You can also specify the path to your own, updated and/or customised `regexes.yaml` file as a second argument to `UserAgentParser.parse`:
91
92 ```ruby
93 UserAgentParser.parse(ua_string, patterns_path: '/some/path/to/regexes.yaml')
94 ```
95
96 or when instantiating a `UserAgentParser::Parser`:
97
98 ```ruby
99 UserAgentParser::Parser.new(patterns_path: '/some/path/to/regexes.yaml').parse(ua_string)
100 ```
101
102 Extending the standard database is possible by providing multiple files in `patterns_paths` (plural) array argument:
103 ```ruby
104 UserAgentParser::Parser.new(patterns_paths: [UserAgentParser::DefaultPatternsPath, '/some/path/to/regexes.yaml'])
105 ```
106
107 ## Command line tool
108
109 The gem incldes a `user_agent_parser` bin command which will read from
110 standard input, parse each line and print the result, for example:
111
112 ```bash
113 $ cat > SOME-FILE-WITH-USER-AGENTS.txt
114 USER_AGENT_1
115 USER_AGENT_2
116 ...
117 $ cat SOME-FILE-WITH-USER-AGENTS.txt | user_agent_parser --format '%f %M' | distribution
118 ```
119
120 See `user_agent_parser -h` for more information.
121
122 ## Contributing
123
124 1. Fork
125 2. Hack
126 3. `rake test`
127 4. Send a pull request
128
129 All accepted pull requests will earn you commit and release rights.
130
131 ## Releasing a new version
132
133 1. Update the version in `user_agent_parser.gemspec`
134 2. `git commit user_agent_parser.gemspec` with the following message format:
135
136 Version x.x.x
137
138 Changelog:
139 * Some new feature
140 * Some new bug fix
141 3. `rake release`
142 4. Create a [new Github release](https://github.com/ua-parser/uap-ruby/releases/new)
143
144 ## License
145
146 MIT
0 # frozen_string_literal: true
1
2 require 'rake/testtask'
3 require 'bundler'
4
5 task default: :test
6
7 desc 'Run tests'
8 Rake::TestTask.new do |t|
9 t.warning = true
10 t.verbose = true
11 t.pattern = 'spec/*_spec.rb'
12 end
13
14 Bundler::GemHelper.install_tasks
15
16 # Does not actually get all families, as some are only listed in the regexes,
17 # but gives you a pretty good idea of what will be returned.
18 desc 'Lists all unique family names for browsers and operating systems.'
19 task :families do
20 require 'pathname'
21 require 'pp'
22
23 root = Pathname(__FILE__).dirname
24 path = root.join('vendor', 'uap-core')
25
26 browser_families = paths_to_families(
27 [
28 # path.join('tests', 'test_ua.yaml'),
29 path.join('test_resources', 'firefox_user_agent_strings.yaml'),
30 path.join('test_resources', 'pgts_browser_list.yaml')
31 ]
32 )
33
34 os_families = paths_to_families(
35 [
36 # path.join('tests', 'test_os.yaml'),
37 path.join('test_resources', 'additional_os_tests.yaml')
38 ]
39 )
40
41 device_families = paths_to_families(
42 [
43 # path.join('tests', 'test_device.yaml'),
44 ]
45 )
46
47 puts "\n\nBrowser Families"
48 puts browser_families.inspect
49
50 puts "\n\nOS Families"
51 puts os_families.inspect
52
53 puts "\n\nDevice Families"
54 puts device_families.inspect
55
56 puts "\n\n"
57 puts "Browser Family Count: #{browser_families.size}"
58 puts "OS Family Count: #{os_families.size}"
59 puts "Device Family Count: #{device_families.size}"
60 end
61
62 def paths_to_families(paths)
63 require 'yaml'
64
65 families = []
66
67 paths.each do |path|
68 data = YAML.load_file(path)
69 test_cases = data.fetch('test_cases')
70 families.concat test_cases.map { |row| row['family'] }
71 end
72
73 families.compact.uniq.sort
74 end
0 ruby-user-agent-parser (2.5.1-3) UNRELEASED; urgency=low
0 ruby-user-agent-parser (2.13.0-1) UNRELEASED; urgency=low
11
22 * Set field Upstream-Contact in debian/copyright.
33 * Remove obsolete field Contact from debian/upstream/metadata (already present
44 in machine-readable debian/copyright).
55 * Bump debhelper from old 12 to 13.
66 * Update standards version to 4.5.1, no changes needed.
7 * New upstream release.
78
8 -- Debian Janitor <janitor@jelmer.uk> Sat, 25 Jul 2020 15:26:29 -0000
9 -- Debian Janitor <janitor@jelmer.uk> Fri, 20 Jan 2023 06:31:54 -0000
910
1011 ruby-user-agent-parser (2.5.1-2) unstable; urgency=medium
1112
11
22 module UserAgentParser
33 class Device
4 DEFAULT_FAMILY = 'Other'
5
46 attr_reader :family, :model, :brand
57
68 alias name family
79
810 def initialize(family = nil, model = nil, brand = nil)
9 @family = family || 'Other'
11 @family = family || DEFAULT_FAMILY
1012 @model = model || @family
1113 @brand = brand
1214 end
11
22 module UserAgentParser
33 class OperatingSystem
4 DEFAULT_FAMILY = 'Other'
5
46 attr_reader :family, :version
57
68 alias name family
79
8 def initialize(family = 'Other', version = nil)
10 def initialize(family = DEFAULT_FAMILY, version = nil)
911 @family = family
1012 @version = version
1113 end
33
44 module UserAgentParser
55 class Parser
6 extend Gem::Deprecate
7
68 FAMILY_REPLACEMENT_KEYS = %w[
79 family_replacement
810 v1_replacement
2123
2224 private_constant :FAMILY_REPLACEMENT_KEYS, :OS_REPLACEMENT_KEYS
2325
24 attr_reader :patterns_path
26 attr_reader :patterns_paths
2527
26 def initialize(options = {})
27 @patterns_path = options[:patterns_path] || UserAgentParser::DefaultPatternsPath
28 @ua_patterns, @os_patterns, @device_patterns = load_patterns(patterns_path)
28 def initialize(patterns_path: nil, patterns_paths: [])
29 @patterns_paths = [patterns_path, *patterns_paths].compact
30 @patterns_paths = [UserAgentParser::DefaultPatternsPath] if @patterns_paths.empty?
31
32 @ua_patterns, @os_patterns, @device_patterns = load_patterns(@patterns_paths)
2933 end
3034
3135 def parse(user_agent)
3438 parse_ua(user_agent, os, device)
3539 end
3640
41 def patterns_path
42 patterns_paths.first
43 end
44 deprecate :patterns_path, :patterns_paths, 2022, 12
45
3746 private
3847
39 def load_patterns(path)
40 yml = YAML.load_file(path)
48 def load_patterns(patterns_paths)
49 patterns_paths.each_with_object([[], [], []]) do |path, patterns|
50 ua_patterns, os_patterns, device_patterns = load_patterns_file(path)
51 patterns[0] += ua_patterns
52 patterns[1] += os_patterns
53 patterns[2] += device_patterns
54 end
55 end
4156
42 # Parse all the regexs
43 yml.each_pair do |_type, patterns|
44 patterns.each do |pattern|
45 pattern[:regex] = Regexp.new(pattern['regex'], pattern['regex_flag'] == 'i')
46 end
57 def load_patterns_file(path)
58 yml = begin
59 YAML.load_file(path, freeze: true)
60 rescue ArgumentError
61 YAML.load_file(path)
4762 end
63 [
64 parse_pattern(yml['user_agent_parsers']),
65 parse_pattern(yml['os_parsers']),
66 parse_pattern(yml['device_parsers']),
67 ]
68 end
4869
49 [yml['user_agent_parsers'], yml['os_parsers'], yml['device_parsers']]
70 def parse_pattern(patterns)
71 patterns.map do |pattern|
72 pattern = pattern.dup
73 pattern[:regex] = Regexp.new(pattern.delete('regex'), pattern.delete('regex_flag') == 'i')
74 pattern
75 end
5076 end
5177
5278 def parse_ua(user_agent, os = nil, device = nil)
79105 end
80106 end
81107
82 if Gem::Version.new(RUBY_VERSION) >= Gem::Version.new('2.4.0')
83 def first_pattern_match(patterns, value)
84 patterns.each do |pattern|
85 if pattern[:regex].match?(value)
86 return [pattern, pattern[:regex].match(value)]
87 end
88 end
89 nil
108 def first_pattern_match(patterns, value)
109 patterns.each do |pattern|
110 return [pattern, pattern[:regex].match(value)] if pattern[:regex].match?(value)
90111 end
91 else
92 def first_pattern_match(patterns, value)
93 patterns.each do |pattern|
94 if (match = pattern[:regex].match(value))
95 return [pattern, match]
96 end
97 end
98 nil
99 end
112 nil
100113 end
101114
102115 def user_agent_from_pattern_match(pattern, match, os = nil, device = nil)
11
22 module UserAgentParser
33 class UserAgent
4 DEFAULT_FAMILY = 'Other'
5
46 attr_reader :family, :version, :os, :device
57
68 alias name family
79
810 def initialize(family = nil, version = nil, os = nil, device = nil)
9 @family = family || 'Other'
11 @family = family || DEFAULT_FAMILY
1012 @version = version
1113 @os = os
1214 @device = device
00 # frozen_string_literal: true
1
2 require 'rubygems/version'
13
24 module UserAgentParser
35 class Version
6 include Comparable
7
48 # Private: Regex used to split string version string into major, minor,
59 # patch, and patch_minor.
6 SEGMENTS_REGEX = /\d+\-\d+|\d+[a-zA-Z]+$|\d+|[A-Za-z][0-9A-Za-z-]*$/
10 SEGMENTS_REGEX = /\d+\-\d+|\d+[a-zA-Z]+$|\d+|[A-Za-z][0-9A-Za-z-]*$/.freeze
711
812 attr_reader :version
913 alias to_s version
4448 version == other.version
4549 end
4650
47 alias == eql?
51 def <=>(other)
52 Gem::Version.new(version).<=>(Gem::Version.new(other.to_s))
53 end
4854
49 # Private
5055 def segments
5156 @segments ||= version.scan(SEGMENTS_REGEX)
5257 end
99 DefaultPatternsPath = File.join(File.dirname(__FILE__), '../vendor/uap-core/regexes.yaml')
1010
1111 # Parse the given +user_agent_string+, returning a +UserAgent+
12 def self.parse(user_agent_string, options = {})
13 Parser.new(options).parse(user_agent_string)
12 def self.parse(user_agent_string, **args)
13 Parser.new(**args).parse(user_agent_string)
1414 end
1515 end
0 # frozen_string_literal: true
1
2 require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
3 require 'user_agent_parser/cli'
4
5 describe UserAgentParser::Cli do
6 let(:cli) { UserAgentParser::Cli.new(user_agent, options) }
7 let(:options) { {} }
8 let(:parser) { UserAgentParser::Parser.new }
9 let(:user_agent) do
10 parser.parse('Mozilla/5.0 (iPad; CPU OS 6_0_1 like Mac OS X) AppleWebKit/536.26 (KHTML, like Gecko) Version/6.0 Mobile/10A523 Safari/8536.25')
11 end
12
13 it 'prints family and version when no options' do
14 _(cli.run!).must_equal('Mobile Safari 6.0')
15 end
16
17 describe 'invalid version' do
18 let(:user_agent) do
19 parser.parse('Mozilla/5.0 (iPad; CPU OS like Mac OS X) AppleWebKit/536.26 (KHTML, like Gecko) Version/XYZ Mobile/10A523 Safari/8536.25')
20 end
21
22 describe '--version' do
23 let(:options) { { version: true } }
24
25 it 'returns nil' do
26 _(cli.run!).must_be_nil
27 end
28 end
29
30 describe '--major' do
31 let(:options) { { major: true } }
32
33 it 'returns nil' do
34 _(cli.run!).must_be_nil
35 end
36 end
37
38 describe '--minor' do
39 let(:options) { { minor: true } }
40
41 it 'returns nil' do
42 _(cli.run!).must_be_nil
43 end
44 end
45
46 describe '--format' do
47 let(:options) { { format: '%n|%f|%v|%M|%m|%o' } }
48
49 it 'returns string without versions' do
50 _(cli.run!).must_equal('Mobile Safari|Mobile Safari||||iOS')
51 end
52 end
53 end
54
55 describe '--name' do
56 let(:options) { { name: true } }
57
58 it 'returns name only' do
59 _(cli.run!).must_equal('Mobile Safari')
60 end
61 end
62
63 describe '--family' do
64 let(:options) { { family: true } }
65
66 it 'returns family only' do
67 _(cli.run!).must_equal('Mobile Safari')
68 end
69 end
70
71 describe '--version' do
72 let(:options) { { version: true } }
73
74 it 'returns version only' do
75 _(cli.run!).must_equal('6.0')
76 end
77 end
78
79 describe '--major' do
80 let(:options) { { major: true } }
81
82 it 'returns major version only' do
83 _(cli.run!).must_equal('6')
84 end
85 end
86
87 describe '--minor' do
88 let(:options) { { minor: true } }
89
90 it 'returns minor version only' do
91 _(cli.run!).must_equal('0')
92 end
93 end
94
95 describe '--os' do
96 let(:options) { { os: true } }
97
98 it 'returns operating system only' do
99 _(cli.run!).must_equal('iOS 6.0.1')
100 end
101 end
102
103 describe '--format' do
104 let(:options) { { format: '%n|%v|%M|%m|%o' } }
105
106 it 'return string with correct replacements' do
107 _(cli.run!).must_equal('Mobile Safari|6.0|6|0|iOS 6.0.1')
108 end
109 end
110 end
0 user_agent_parsers:
1 - regex: 'Any.*'
2 family_replacement: 'Custom browser'
3 v1_replacement: '1'
4 v2_replacement: '2'
5 v3_replacement: '3'
6 v4_replacement: '4'
7
8 os_parsers:
9 - regex: 'Any.*'
10 os_replacement: 'Custom OS'
11 os_v1_replacement: '1'
12 os_v2_replacement: '2'
13
14 device_parsers:
15 - regex: 'Any.*'
16 device_replacement: 'Custom device'
0 # frozen_string_literal: true
1
2 require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
3
4 describe UserAgentParser::Device do
5 describe '#name' do
6 it 'returns family' do
7 os = UserAgentParser::Device.new('iPod')
8 _(os.name).must_equal os.family
9 end
10 end
11
12 describe '#to_s' do
13 it 'returns a string of just the family' do
14 os = UserAgentParser::Device.new('iPod')
15 _(os.to_s).must_equal 'iPod'
16 end
17 end
18
19 describe '#==' do
20 it 'returns true for same family' do
21 device1 = UserAgentParser::Device.new('iPod')
22 device2 = UserAgentParser::Device.new('iPod')
23 _(device1).must_equal device2
24 end
25
26 it 'returns false different family' do
27 device1 = UserAgentParser::Device.new('iPod')
28 device2 = UserAgentParser::Device.new('iPad')
29 _(device1).wont_equal device2
30 end
31 end
32
33 describe '#eql?' do
34 it 'returns true for same family' do
35 device1 = UserAgentParser::Device.new('iPod')
36 device2 = UserAgentParser::Device.new('iPod')
37 assert_equal true, device1.eql?(device2)
38 end
39
40 it 'returns false different family' do
41 device1 = UserAgentParser::Device.new('iPod')
42 device2 = UserAgentParser::Device.new('iPad')
43 assert_equal false, device1.eql?(device2)
44 end
45 end
46
47 describe '#inspect' do
48 it 'returns class family and instance to_s' do
49 device = UserAgentParser::Device.new('iPod')
50 _(device.inspect.to_s).must_equal '#<UserAgentParser::Device iPod>'
51 end
52 end
53 end
0 # frozen_string_literal: true
1
2 require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
3
4 describe UserAgentParser::OperatingSystem do
5 describe '#name' do
6 it 'returns family' do
7 os = UserAgentParser::OperatingSystem.new('Windows')
8 _(os.name).must_equal os.family
9 end
10 end
11
12 describe '#to_s' do
13 it 'returns a string of just the family' do
14 os = UserAgentParser::OperatingSystem.new('Windows')
15 _(os.to_s).must_equal 'Windows'
16 end
17
18 it 'returns a string of family and version' do
19 version = UserAgentParser::Version.new('7')
20 os = UserAgentParser::OperatingSystem.new('Windows', version)
21 _(os.to_s).must_equal 'Windows 7'
22 end
23 end
24
25 describe '#==' do
26 it "returns true for same user agents across different O/S's" do
27 version = UserAgentParser::Version.new('7')
28 os1 = UserAgentParser::OperatingSystem.new('Windows', version)
29 os2 = UserAgentParser::OperatingSystem.new('Windows', version)
30 _(os1).must_equal os2
31 end
32
33 it 'returns false for same family, different versions' do
34 seven = UserAgentParser::Version.new('7')
35 eight = UserAgentParser::Version.new('8')
36 os1 = UserAgentParser::OperatingSystem.new('Windows', seven)
37 os2 = UserAgentParser::OperatingSystem.new('Windows', eight)
38 _(os1).wont_equal os2
39 end
40
41 it 'returns false for different family, same version' do
42 version = UserAgentParser::Version.new('7')
43 os1 = UserAgentParser::OperatingSystem.new('Windows', version)
44 os2 = UserAgentParser::OperatingSystem.new('Blah', version)
45 _(os1).wont_equal os2
46 end
47 end
48
49 describe '#eql?' do
50 it "returns true for same user agents across different O/S's" do
51 version = UserAgentParser::Version.new('7')
52 os1 = UserAgentParser::OperatingSystem.new('Windows', version)
53 os2 = UserAgentParser::OperatingSystem.new('Windows', version)
54 assert_equal true, os1.eql?(os2)
55 end
56
57 it 'returns false for same family, different versions' do
58 seven = UserAgentParser::Version.new('7')
59 eight = UserAgentParser::Version.new('8')
60 os1 = UserAgentParser::OperatingSystem.new('Windows', seven)
61 os2 = UserAgentParser::OperatingSystem.new('Windows', eight)
62 assert_equal false, os1.eql?(os2)
63 end
64
65 it 'returns false for different family, same version' do
66 version = UserAgentParser::Version.new('7')
67 os1 = UserAgentParser::OperatingSystem.new('Windows', version)
68 os2 = UserAgentParser::OperatingSystem.new('Blah', version)
69 assert_equal false, os1.eql?(os2)
70 end
71 end
72
73 describe '#inspect' do
74 it 'returns class family and instance to_s' do
75 version = UserAgentParser::Version.new('10.7.4')
76 os = UserAgentParser::OperatingSystem.new('OS X', version)
77 _(os.inspect.to_s).must_equal '#<UserAgentParser::OperatingSystem OS X 10.7.4>'
78 end
79 end
80 end
0 user_agent_parsers:
1 - regex: 'Other.*'
2 family_replacement: 'Other browser'
3 v1_replacement: '1'
4 v2_replacement: '2'
5 v3_replacement: '3'
6 v4_replacement: '4'
7
8 os_parsers:
9 - regex: 'Other.*'
10 os_replacement: 'Other OS'
11 os_v1_replacement: '1'
12 os_v2_replacement: '2'
13
14 device_parsers:
15 - regex: 'Other.*'
16 device_replacement: 'Other device'
0 # frozen_string_literal: true
1
2 require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
3 require 'yaml'
4
5 describe UserAgentParser::Parser do
6 PARSER = UserAgentParser::Parser.new
7
8 # Some Ruby versions (JRuby) need sanitised test names, as some chars screw
9 # up the test method definitions
10 def self.test_case_to_test_name(test_case)
11 name = "#{test_case['user_agent_string']}_#{test_case['family']}"
12 name.gsub(/[^a-z0-9_.-]/i, '_').squeeze('_')
13 end
14
15 def self.file_to_test_cases(file)
16 file_to_yaml(file)['test_cases'].map do |test_case|
17 {
18 'user_agent_string' => test_case['user_agent_string'],
19 'family' => test_case['family'],
20 'major' => test_case['major'],
21 'minor' => test_case['minor'],
22 'patch' => test_case['patch'],
23 'patch_minor' => test_case['patch_minor'],
24 'brand' => test_case['brand'],
25 'model' => test_case['model']
26 }
27 end.reject do |test_case|
28 # We don't do the hacky javascript user agent overrides
29 test_case.key?('js_ua') ||
30 test_case['family'] == 'IE Platform Preview' ||
31 test_case['user_agent_string'].include?('chromeframe;')
32 end
33 end
34
35 def self.file_to_yaml(resource)
36 uap_path = File.expand_path('../../vendor/uap-core', __FILE__)
37 resource_path = File.join(uap_path, resource)
38 YAML.load_file(resource_path)
39 end
40
41 def self.user_agent_test_cases
42 file_to_test_cases('test_resources/firefox_user_agent_strings.yaml')
43 file_to_test_cases('tests/test_ua.yaml')
44 end
45
46 def self.operating_system_test_cases
47 file_to_test_cases('tests/test_os.yaml') +
48 file_to_test_cases('test_resources/additional_os_tests.yaml')
49 end
50
51 def self.device_test_cases
52 file_to_test_cases('tests/test_device.yaml')
53 end
54
55 def custom_patterns_path
56 File.join(File.dirname(__FILE__), 'custom_regexes.yaml')
57 end
58
59 def other_patterns_path
60 File.join(File.dirname(__FILE__), 'other_regexes.yaml')
61 end
62
63 describe '::parse' do
64 it 'parses a UA' do
65 ua = UserAgentParser.parse('Mozilla/5.0 (Macintosh; U; PPC Mac OS X; en-us) AppleWebKit/418.8 (KHTML, like Gecko) Safari/419.3')
66 _(ua.family).must_equal('Safari')
67 end
68 it 'accepts a custom patterns path' do
69 ua = UserAgentParser.parse('Any user agent string', patterns_path: custom_patterns_path)
70 _(ua.family).must_equal('Custom browser')
71 end
72 end
73
74 describe '#initialize with a custom patterns path' do
75 it 'accepts a single patterns_path string' do
76 parser = UserAgentParser::Parser.new(patterns_path: custom_patterns_path)
77 ua = parser.parse('Any user agent string')
78
79 _(parser.patterns_paths).must_equal([custom_patterns_path])
80 _(parser.patterns_path).must_equal(custom_patterns_path)
81
82 _(ua.family).must_equal('Custom browser')
83 _(ua.version.major).must_equal('1')
84 _(ua.version.minor).must_equal('2')
85 _(ua.version.patch).must_equal('3')
86 _(ua.version.patch_minor).must_equal('4')
87
88 _(ua.os.family).must_equal('Custom OS')
89 _(ua.os.version.major).must_equal('1')
90 _(ua.os.version.minor).must_equal('2')
91
92 _(ua.device.family).must_equal('Custom device')
93 end
94
95 it 'accepts patterns_paths array' do
96 patterns_paths = [custom_patterns_path, other_patterns_path]
97 parser = UserAgentParser::Parser.new(patterns_paths: patterns_paths)
98
99 _(parser.patterns_paths).must_equal(patterns_paths)
100 _(parser.patterns_path).must_equal(custom_patterns_path)
101
102 ua = parser.parse('Any user agent string')
103 oua = parser.parse('Other user agent string')
104
105 _(ua.family).must_equal('Custom browser')
106 _(oua.family).must_equal('Other browser')
107 end
108 end
109
110 describe '#parse' do
111 user_agent_test_cases.each do |test_case|
112 it "parses UA for #{test_case_to_test_name(test_case)}" do
113 user_agent = PARSER.parse(test_case['user_agent_string'])
114
115 if test_case['family']
116 _(user_agent.family).must_equal_test_case_property(test_case, 'family')
117 end
118
119 if test_case['major']
120 _(user_agent.version.major).must_equal_test_case_property(test_case, 'major')
121 end
122
123 if test_case['minor']
124 _(user_agent.version.minor).must_equal_test_case_property(test_case, 'minor')
125 end
126
127 if test_case['patch']
128 _(user_agent.version.patch).must_equal_test_case_property(test_case, 'patch')
129 end
130 end
131 end
132
133 operating_system_test_cases.each do |test_case|
134 it "parses OS for #{test_case_to_test_name(test_case)}" do
135 user_agent = PARSER.parse(test_case['user_agent_string'])
136 operating_system = user_agent.os
137
138 if test_case['family']
139 _(operating_system.family).must_equal_test_case_property(test_case, 'family')
140 end
141
142 if test_case['major']
143 _(operating_system.version.major).must_equal_test_case_property(test_case, 'major')
144 end
145
146 if test_case['minor']
147 _(operating_system.version.minor).must_equal_test_case_property(test_case, 'minor')
148 end
149
150 if test_case['patch']
151 _(operating_system.version.patch).must_equal_test_case_property(test_case, 'patch')
152 end
153
154 if test_case['patch_minor']
155 _(operating_system.version.patch_minor).must_equal_test_case_property(test_case, 'patch_minor')
156 end
157 end
158 end
159
160 device_test_cases.each do |test_case|
161 it "parses device for #{test_case_to_test_name(test_case)}" do
162 user_agent = PARSER.parse(test_case['user_agent_string'])
163 device = user_agent.device
164
165 if test_case['family']
166 _(device.family).must_equal_test_case_property(test_case, 'family')
167 end
168
169 if test_case['model']
170 _(device.model).must_equal_test_case_property(test_case, 'model')
171 end
172
173 if test_case['brand']
174 _(device.brand).must_equal_test_case_property(test_case, 'brand')
175 end
176 end
177 end
178 end
179 end
0 # frozen_string_literal: true
1
2 require 'coveralls'
3 require 'simplecov'
4
5 SimpleCov.formatter = Coveralls::SimpleCov::Formatter
6 SimpleCov.start do
7 add_filter '/.bundle/'
8 add_filter '/doc/'
9 add_filter '/spec/'
10 add_filter '/config/'
11 merge_timeout 600
12 end
13
14 require 'minitest/autorun'
15
16 $:.unshift File.expand_path('../../lib', __FILE__)
17 require 'user_agent_parser'
18
19 module MiniTest
20 module Assertions
21 # Asserts the test case property is equal to the expected value. On failure
22 # the message includes the property and user_agent_string from the test
23 # case for easier debugging
24 def assert_test_case_property_equal(test_case, actual, test_case_property)
25 assert_equal test_case[test_case_property],
26 actual,
27 "#{test_case_property} failed for user agent: #{test_case['user_agent_string']}"
28 end
29
30 Object.infect_an_assertion :assert_test_case_property_equal, :must_equal_test_case_property
31 end
32 end
0 # frozen_string_literal: true
1
2 require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
3
4 describe UserAgentParser::UserAgent do
5 describe '#to_s' do
6 it 'returns a string of just the family' do
7 _(UserAgentParser::UserAgent.new('Chrome').to_s).must_equal 'Chrome'
8 end
9
10 it 'returns a string of family and version' do
11 version = UserAgentParser::Version.new('1.2.3pre')
12 agent = UserAgentParser::UserAgent.new('Chrome', version)
13 _(agent.to_s).must_equal 'Chrome 1.2.3pre'
14 end
15 end
16
17 describe '#initialize' do
18 describe 'with family' do
19 it 'sets family' do
20 agent = UserAgentParser::UserAgent.new('Chromium')
21 _(agent.family).must_equal 'Chromium'
22 end
23 end
24
25 describe 'with no family' do
26 it 'sets family to Other' do
27 agent = UserAgentParser::UserAgent.new
28 _(agent.family).must_equal 'Other'
29 end
30 end
31
32 describe 'with version' do
33 it 'sets version' do
34 version = UserAgentParser::Version.new('1.2.3')
35 agent = UserAgentParser::UserAgent.new(nil, version)
36 _(agent.version).must_equal version
37 end
38 end
39
40 describe 'with os' do
41 it 'sets os' do
42 os = UserAgentParser::OperatingSystem.new('Windows XP')
43 agent = UserAgentParser::UserAgent.new(nil, nil, os)
44 _(agent.os).must_equal os
45 end
46 end
47
48 describe 'with device' do
49 it 'sets device' do
50 device = UserAgentParser::Device.new('iPhone')
51 agent = UserAgentParser::UserAgent.new(nil, nil, nil, device)
52 _(agent.device).must_equal device
53 end
54 end
55 end
56
57 describe '#name' do
58 it 'returns family' do
59 agent = UserAgentParser::UserAgent.new('Safari')
60 _(agent.name).must_equal agent.family
61 end
62 end
63
64 describe '#==' do
65 it 'returns true for same agents with no OS' do
66 version = UserAgentParser::Version.new('1.0')
67 agent1 = UserAgentParser::UserAgent.new('Chrome', version)
68 agent2 = UserAgentParser::UserAgent.new('Chrome', version)
69 _(agent1).must_equal agent2
70 end
71
72 it 'returns true for same agents on same OS' do
73 version = UserAgentParser::Version.new('1.0')
74 os = UserAgentParser::OperatingSystem.new('Windows')
75 agent1 = UserAgentParser::UserAgent.new('Chrome', version, os)
76 agent2 = UserAgentParser::UserAgent.new('Chrome', version, os)
77 _(agent1).must_equal agent2
78 end
79
80 it 'returns false for same agent on different OS' do
81 version = UserAgentParser::Version.new('1.0')
82 windows = UserAgentParser::OperatingSystem.new('Windows')
83 mac = UserAgentParser::OperatingSystem.new('Mac')
84 agent1 = UserAgentParser::UserAgent.new('Chrome', version, windows)
85 agent2 = UserAgentParser::UserAgent.new('Chrome', version, mac)
86 _(agent1).wont_equal agent2
87 end
88
89 it 'returns false for same os, but different browser version' do
90 browser_version1 = UserAgentParser::Version.new('1.0')
91 browser_version2 = UserAgentParser::Version.new('2.0')
92 os = UserAgentParser::OperatingSystem.new('Windows')
93 agent1 = UserAgentParser::UserAgent.new('Chrome', browser_version1, os)
94 agent2 = UserAgentParser::UserAgent.new('Chrome', browser_version2, os)
95 _(agent1).wont_equal agent2
96 end
97 end
98
99 describe '#eql?' do
100 it 'returns true for same agents with no OS' do
101 version = UserAgentParser::Version.new('1.0')
102 agent1 = UserAgentParser::UserAgent.new('Chrome', version)
103 agent2 = UserAgentParser::UserAgent.new('Chrome', version)
104 assert_equal true, agent1.eql?(agent2)
105 end
106
107 it 'returns true for same agents on same OS' do
108 version = UserAgentParser::Version.new('1.0')
109 os = UserAgentParser::OperatingSystem.new('Windows')
110 agent1 = UserAgentParser::UserAgent.new('Chrome', version, os)
111 agent2 = UserAgentParser::UserAgent.new('Chrome', version, os)
112 assert_equal true, agent1.eql?(agent2)
113 end
114
115 it 'returns false for same agent on different OS' do
116 version = UserAgentParser::Version.new('1.0')
117 windows = UserAgentParser::OperatingSystem.new('Windows')
118 mac = UserAgentParser::OperatingSystem.new('Mac')
119 agent1 = UserAgentParser::UserAgent.new('Chrome', version, windows)
120 agent2 = UserAgentParser::UserAgent.new('Chrome', version, mac)
121 assert_equal false, agent1.eql?(agent2)
122 end
123
124 it 'returns false for same os, but different browser version' do
125 browser_version1 = UserAgentParser::Version.new('1.0')
126 browser_version2 = UserAgentParser::Version.new('2.0')
127 os = UserAgentParser::OperatingSystem.new('Windows')
128 agent1 = UserAgentParser::UserAgent.new('Chrome', browser_version1, os)
129 agent2 = UserAgentParser::UserAgent.new('Chrome', browser_version2, os)
130 assert_equal false, agent1.eql?(agent2)
131 end
132 end
133
134 describe '#inspect' do
135 it 'returns the family and version' do
136 browser_version = UserAgentParser::Version.new('1.0')
137 agent = UserAgentParser::UserAgent.new('Chrome', browser_version)
138 _(agent.inspect.to_s).must_equal '#<UserAgentParser::UserAgent Chrome 1.0>'
139 end
140
141 it 'returns the OS if present' do
142 browser_version = UserAgentParser::Version.new('1.0')
143 os_version = UserAgentParser::Version.new('10.7.4')
144 os = UserAgentParser::OperatingSystem.new('OS X', os_version)
145 agent = UserAgentParser::UserAgent.new('Chrome', browser_version, os)
146 _(agent.inspect).must_equal '#<UserAgentParser::UserAgent Chrome 1.0 (OS X 10.7.4)>'
147 end
148
149 it 'returns device if present' do
150 browser_version = UserAgentParser::Version.new('5.0.2')
151 os_version = UserAgentParser::Version.new('4.2.1')
152 os = UserAgentParser::OperatingSystem.new('iOS', os_version)
153 device = UserAgentParser::Device.new('iPhone')
154 agent = UserAgentParser::UserAgent.new('Mobile Safari', browser_version, os, device)
155 _(agent.inspect).must_equal '#<UserAgentParser::UserAgent Mobile Safari 5.0.2 (iOS 4.2.1) (iPhone)>'
156 end
157 end
158
159 describe '#to_h' do
160 let(:expected) do
161 {
162 device: { family: 'iPhone', model: 'iPhone', brand: nil },
163 family: 'Mobile Safari',
164 os: {
165 version: { version: '4.2.1', major: '4', minor: '2', patch: '1', patch_minor: nil},
166 family: 'iOS'
167 },
168 version: { version: '5.0.2', major: '5', minor: '0', patch: '2', patch_minor: nil }
169 }
170 end
171
172 it 'returns everything' do
173 browser_version = UserAgentParser::Version.new('5.0.2')
174 os_version = UserAgentParser::Version.new('4.2.1')
175 os = UserAgentParser::OperatingSystem.new('iOS', os_version)
176 device = UserAgentParser::Device.new('iPhone')
177 agent = UserAgentParser::UserAgent.new('Mobile Safari', browser_version, os, device)
178 assert_equal(expected, agent.to_h)
179 end
180 end
181 end
0 # frozen_string_literal: true
1
2 require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
3
4 describe UserAgentParser::Version do
5 it "parses '1'" do
6 version = UserAgentParser::Version.new('1')
7 _(version.major).must_equal '1'
8 end
9
10 it "parses '1.2'" do
11 version = UserAgentParser::Version.new('1.2')
12 _(version.major).must_equal '1'
13 _(version.minor).must_equal '2'
14 end
15
16 it "parses '1.2.3'" do
17 version = UserAgentParser::Version.new('1.2.3')
18 _(version.major).must_equal '1'
19 _(version.minor).must_equal '2'
20 _(version.patch).must_equal '3'
21 end
22
23 it "parses '1.2.3b4'" do
24 version = UserAgentParser::Version.new('1.2.3b4')
25 _(version.major).must_equal '1'
26 _(version.minor).must_equal '2'
27 _(version.patch).must_equal '3'
28 _(version.patch_minor).must_equal 'b4'
29 end
30
31 it "parses '1.2.3-b4'" do
32 version = UserAgentParser::Version.new('1.2.3-b4')
33 _(version.major).must_equal '1'
34 _(version.minor).must_equal '2'
35 _(version.patch).must_equal '3'
36 _(version.patch_minor).must_equal 'b4'
37 end
38
39 it "parses '1.2.3pre'" do
40 version = UserAgentParser::Version.new('1.2.3pre')
41 _(version.major).must_equal '1'
42 _(version.minor).must_equal '2'
43 _(version.patch).must_equal '3pre'
44 end
45
46 it "parses '1.2.3-45'" do
47 version = UserAgentParser::Version.new('1.2.3-45')
48 _(version.major).must_equal '1'
49 _(version.minor).must_equal '2'
50 _(version.patch).must_equal '3-45'
51 end
52
53 it 'accepts Fixnum and String arguments' do
54 version = UserAgentParser::Version.new(1, '2a', 3, '4b')
55 _(version.major).must_equal '1'
56 _(version.minor).must_equal '2a'
57 _(version.patch).must_equal '3'
58 _(version.patch_minor).must_equal '4b'
59 end
60
61 describe '#to_s' do
62 it 'returns the same string as initialized with' do
63 version = UserAgentParser::Version.new('1.2.3b4')
64 _(version.to_s).must_equal '1.2.3b4'
65 end
66 end
67
68 describe '#==' do
69 it 'returns true for same versions' do
70 version = UserAgentParser::Version.new('1.2.3')
71 _(version).must_equal UserAgentParser::Version.new('1.2.3')
72 end
73
74 it 'returns false for different versions' do
75 version = UserAgentParser::Version.new('1.2.3')
76 _(version).wont_equal UserAgentParser::Version.new('1.2.2')
77 end
78 end
79
80 describe '#<=>' do
81 it 'accepts string for comparison' do
82 version = UserAgentParser::Version.new('1.2.3')
83
84 assert_operator version, :<, '1.2.4'
85 assert_operator version, :==, '1.2.3'
86 assert_operator version, :>, '1.2.2'
87 end
88
89 it 'accepts another instance of Version for comparison' do
90 version = UserAgentParser::Version.new('1.2.3')
91
92 assert_operator version, :>, UserAgentParser::Version.new('1.2.2')
93 assert_operator version, :==, UserAgentParser::Version.new('1.2.3')
94 assert_operator version, :<, UserAgentParser::Version.new('1.2.4')
95 end
96
97 it 'is comparing major version' do
98 version = UserAgentParser::Version.new('1.2.3')
99
100 assert_operator version, :<, '2'
101 assert_operator version, :>=, '1'
102 assert_operator version, :>, '0'
103 end
104
105 it 'is comparing minor version' do
106 version = UserAgentParser::Version.new('1.2.3')
107
108 assert_operator version, :<, '2.0'
109 assert_operator version, :<, '1.3'
110 assert_operator version, :>=, '1.2'
111 assert_operator version, :>, '1.1'
112 assert_operator version, :>, '0.1'
113 end
114
115 it 'is comparing patch level' do
116 version = UserAgentParser::Version.new('1.2.3')
117
118 assert_operator version, :<, '1.2.4'
119 assert_operator version, :>=, '1.2.3'
120 assert_operator version, :<=, '1.2.3'
121 assert_operator version, :>, '1.2.2'
122 end
123
124 it 'is comparing patch_minor level correctly' do
125 version = UserAgentParser::Version.new('1.2.3.p1')
126
127 assert_operator version, :<, '1.2.4'
128 assert_operator version, :<, '1.2.3.p2'
129 assert_operator version, :>=, '1.2.3.p1'
130 assert_operator version, :<=, '1.2.3.p1'
131 assert_operator version, :>, '1.2.3.p0'
132 assert_operator version, :>, '1.2.2'
133 assert_operator version, :>, '1.1'
134 end
135
136 it 'is correctly comparing versions with different lengths' do
137 version = UserAgentParser::Version.new('1.42.3')
138
139 assert_operator version, :<, '1.142'
140 assert_operator version, :<, '1.42.4'
141 assert_operator version, :>=, '1.42'
142 assert_operator version, :>, '1.14'
143 assert_operator version, :>, '1.7'
144 assert_operator version, :>, '1.3'
145 end
146
147 it 'does its best to compare string versions' do
148 version = UserAgentParser::Version.new('1.2.3.a')
149
150 assert_operator version, :<, '1.2.4'
151 assert_operator version, :<, '1.2.3.b'
152 assert_operator version, :<, '1.2.3.p1'
153 assert_operator version, :<, '1.2.3.p0'
154 assert_operator version, :>, '1.2.2'
155 end
156 end
157
158 describe '#inspect' do
159 it 'returns the class and version' do
160 version = UserAgentParser::Version.new('1.2.3')
161 _(version.inspect).must_equal '#<UserAgentParser::Version 1.2.3>'
162 end
163 end
164 end
0 #########################################################
1 # This file has been automatically generated by gem2tgz #
2 #########################################################
3 # -*- encoding: utf-8 -*-
4 # stub: user_agent_parser 2.5.1 ruby lib
0 # frozen_string_literal: true
51
6 Gem::Specification.new do |s|
7 s.name = "user_agent_parser".freeze
8 s.version = "2.5.1"
2 Gem::Specification.new do |gem|
3 gem.name = 'user_agent_parser'
4 gem.version = '2.13.0'
95
10 s.required_rubygems_version = Gem::Requirement.new(">= 0".freeze) if s.respond_to? :required_rubygems_version=
11 s.require_paths = ["lib".freeze]
12 s.authors = ["Tim Lucas".freeze]
13 s.date = "2019-01-08"
14 s.description = "A simple, comprehensive Ruby gem for parsing user agent strings with the help of BrowserScope's UA database".freeze
15 s.email = "t@toolmantim.com".freeze
16 s.executables = ["user_agent_parser".freeze]
17 s.files = ["MIT-LICENSE".freeze, "bin/user_agent_parser".freeze, "lib/user_agent_parser.rb".freeze, "lib/user_agent_parser/cli.rb".freeze, "lib/user_agent_parser/device.rb".freeze, "lib/user_agent_parser/operating_system.rb".freeze, "lib/user_agent_parser/parser.rb".freeze, "lib/user_agent_parser/user_agent.rb".freeze, "lib/user_agent_parser/version.rb".freeze, "vendor/uap-core/regexes.yaml".freeze]
18 s.homepage = "https://github.com/ua-parser/uap-ruby".freeze
19 s.licenses = ["MIT".freeze]
20 s.required_ruby_version = Gem::Requirement.new(">= 2.3".freeze)
21 s.rubygems_version = "2.7.6.2".freeze
22 s.summary = "A simple, comprehensive Ruby gem for parsing user agent strings with the help of BrowserScope's UA database".freeze
6 gem.authors = 'Tim Lucas'
7 gem.email = 't@toolmantim.com'
8 gem.homepage = 'https://github.com/ua-parser/uap-ruby'
9 gem.summary = "Parsing user agent strings with the help of BrowserScope's UA database"
10 gem.description = <<~DESCRIPTION
11 A simple, comprehensive Ruby gem for parsing user agent strings
12 with the help of BrowserScope's UserAgent database
13 DESCRIPTION
14 gem.license = 'MIT'
15 gem.executables = ['user_agent_parser']
16
17 gem.files = %x{git ls-files}.split("\n").select { |d| d =~ %r{^(MIT-LICENSE|Readme.md|lib|bin/)} } + ['vendor/uap-core/regexes.yaml']
18
19 gem.required_ruby_version = '>= 2.5'
2320 end
+0
-5267
vendor/uap-core/regexes.yaml less more
0 user_agent_parsers:
1 #### SPECIAL CASES TOP ####
2
3 # CFNetwork Podcast catcher Applications
4 - regex: '(ESPN)[%20| ]+Radio/(\d+)\.(\d+)\.(\d+) CFNetwork'
5 - regex: '(Antenna)/(\d+) CFNetwork'
6 family_replacement: 'AntennaPod'
7 - regex: '(TopPodcasts)Pro/(\d+) CFNetwork'
8 - regex: '(MusicDownloader)Lite/(\d+)\.(\d+)\.(\d+) CFNetwork'
9 - regex: '^(.*)-iPad/(\d+)\.?(\d+)?.?(\d+)?.?(\d+)? CFNetwork'
10 - regex: '^(.*)-iPhone/(\d+)\.?(\d+)?.?(\d+)?.?(\d+)? CFNetwork'
11 - regex: '^(.*)/(\d+)\.?(\d+)?.?(\d+)?.?(\d+)? CFNetwork'
12
13 # Podcast catchers
14 - regex: '(espn\.go)'
15 family_replacement: 'ESPN'
16 - regex: '(espnradio\.com)'
17 family_replacement: 'ESPN'
18 - regex: 'ESPN APP$'
19 family_replacement: 'ESPN'
20 - regex: '(audioboom\.com)'
21 family_replacement: 'AudioBoom'
22 - regex: ' (Rivo) RHYTHM'
23
24 # @note: iOS / OSX Applications
25 - regex: '(CFNetwork)(?:/(\d+)\.(\d+)\.?(\d+)?)?'
26 family_replacement: 'CFNetwork'
27
28 # Pingdom
29 - regex: '(Pingdom.com_bot_version_)(\d+)\.(\d+)'
30 family_replacement: 'PingdomBot'
31 # 'Mozilla/5.0 (Unknown; Linux x86_64) AppleWebKit/534.34 (KHTML, like Gecko) PingdomTMS/0.8.5 Safari/534.34'
32 - regex: '(PingdomTMS)/(\d+)\.(\d+)\.(\d+)'
33 family_replacement: 'PingdomBot'
34
35 # New Relic Pinger
36 - regex: '(NewRelicPinger)/(\d+)\.(\d+)'
37 family_replacement: 'NewRelicPingerBot'
38
39 # Tableau
40 - regex: '(Tableau)/(\d+)\.(\d+)'
41 family_replacement: 'Tableau'
42
43 # Salesforce
44 - regex: '(Salesforce)(?:.)\/(\d+)\.(\d?)'
45
46 #StatusCake
47 - regex: '(\(StatusCake\))'
48 family_replacement: 'StatusCakeBot'
49
50 # Facebook
51 - regex: '(facebookexternalhit)/(\d+)\.(\d+)'
52 family_replacement: 'FacebookBot'
53
54 # Google Plus
55 - regex: 'Google.*/\+/web/snippet'
56 family_replacement: 'GooglePlusBot'
57
58 # Gmail
59 - regex: 'via ggpht.com GoogleImageProxy'
60 family_replacement: 'GmailImageProxy'
61
62 # Yahoo
63 - regex: 'YahooMailProxy; https://help.yahoo.com/kb/yahoo-mail-proxy-SLN28749.html'
64 family_replacement: 'YahooMailProxy'
65
66 # Twitter
67 - regex: '(Twitterbot)/(\d+)\.(\d+)'
68 family_replacement: 'TwitterBot'
69
70 # Bots Pattern '/name-0.0'
71 - regex: '/((?:Ant-)?Nutch|[A-z]+[Bb]ot|[A-z]+[Ss]pider|Axtaris|fetchurl|Isara|ShopSalad|Tailsweep)[ \-](\d+)(?:\.(\d+)(?:\.(\d+))?)?'
72 # Bots Pattern 'name/0.0'
73 - regex: '\b(008|Altresium|Argus|BaiduMobaider|BoardReader|DNSGroup|DataparkSearch|EDI|Goodzer|Grub|INGRID|Infohelfer|LinkedInBot|LOOQ|Nutch|PathDefender|Peew|PostPost|Steeler|Twitterbot|VSE|WebCrunch|WebZIP|Y!J-BR[A-Z]|YahooSeeker|envolk|sproose|wminer)/(\d+)(?:\.(\d+)(?:\.(\d+))?)?'
74
75 # MSIECrawler
76 - regex: '(MSIE) (\d+)\.(\d+)([a-z]\d?)?;.* MSIECrawler'
77 family_replacement: 'MSIECrawler'
78
79 # DAVdroid
80 - regex: '(DAVdroid)/(\d+)\.(\d+)(?:\.(\d+))?'
81
82 # Downloader ...
83 - regex: '(Google-HTTP-Java-Client|Apache-HttpClient|Go-http-client|scalaj-http|http%20client|Python-urllib|HttpMonitor|TLSProber|WinHTTP|JNLP|okhttp|aihttp|reqwest)(?:[ /](\d+)(?:\.(\d+)(?:\.(\d+))?)?)?'
84
85 # Pinterestbot
86 - regex: '(Pinterest(?:bot)?)/(\d+)(?:\.(\d+)(?:\.(\d+))?)?[;\s\(]+\+https://www.pinterest.com/bot.html'
87 family_replacement: 'Pinterestbot'
88
89 # Bots
90 - regex: '(1470\.net crawler|50\.nu|8bo Crawler Bot|Aboundex|Accoona-[A-z]+-Agent|AdsBot-Google(?:-[a-z]+)?|altavista|AppEngine-Google|archive.*?\.org_bot|archiver|Ask Jeeves|[Bb]ai[Dd]u[Ss]pider(?:-[A-Za-z]+)*|bingbot|BingPreview|blitzbot|BlogBridge|Bloglovin|BoardReader(?: [A-Za-z]+)*|boitho.com-dc|BotSeer|BUbiNG|\b\w*favicon\w*\b|\bYeti(?:-[a-z]+)?|Catchpoint(?: bot)?|[Cc]harlotte|Checklinks|clumboot|Comodo HTTP\(S\) Crawler|Comodo-Webinspector-Crawler|ConveraCrawler|CRAWL-E|CrawlConvera|Daumoa(?:-feedfetcher)?|Feed Seeker Bot|Feedbin|findlinks|Flamingo_SearchEngine|FollowSite Bot|furlbot|Genieo|gigabot|GomezAgent|gonzo1|(?:[a-zA-Z]+-)?Googlebot(?:-[a-zA-Z]+)?|Google SketchUp|grub-client|gsa-crawler|heritrix|HiddenMarket|holmes|HooWWWer|htdig|ia_archiver|ICC-Crawler|Icarus6j|ichiro(?:/mobile)?|IconSurf|IlTrovatore(?:-Setaccio)?|InfuzApp|Innovazion Crawler|InternetArchive|IP2[a-z]+Bot|jbot\b|KaloogaBot|Kraken|Kurzor|larbin|LEIA|LesnikBot|Linguee Bot|LinkAider|LinkedInBot|Lite Bot|Llaut|lycos|Mail\.RU_Bot|masscan|masidani_bot|Mediapartners-Google|Microsoft .*? Bot|mogimogi|mozDex|MJ12bot|msnbot(?:-media *)?|msrbot|Mtps Feed Aggregation System|netresearch|Netvibes|NewsGator[^/]*|^NING|Nutch[^/]*|Nymesis|ObjectsSearch|Orbiter|OOZBOT|PagePeeker|PagesInventory|PaxleFramework|Peeplo Screenshot Bot|PlantyNet_WebRobot|Pompos|Qwantify|Read%20Later|Reaper|RedCarpet|Retreiver|Riddler|Rival IQ|scooter|Scrapy|Scrubby|searchsight|seekbot|semanticdiscovery|SemrushBot|Simpy|SimplePie|SEOstats|SimpleRSS|SiteCon|Slackbot-LinkExpanding|Slack-ImgProxy|Slurp|snappy|Speedy Spider|Squrl Java|Stringer|TheUsefulbot|ThumbShotsBot|Thumbshots\.ru|Tiny Tiny RSS|TwitterBot|WhatsApp|URL2PNG|Vagabondo|VoilaBot|^vortex|Votay bot|^voyager|WASALive.Bot|Web-sniffer|WebThumb|WeSEE:[A-z]+|WhatWeb|WIRE|WordPress|Wotbox|www\.almaden\.ibm\.com|Xenu(?:.s)? Link Sleuth|Xerka [A-z]+Bot|yacy(?:bot)?|Yahoo[a-z]*Seeker|Yahoo! Slurp|Yandex\w+|YodaoBot(?:-[A-z]+)?|YottaaMonitor|Yowedo|^Zao|^Zao-Crawler|ZeBot_www\.ze\.bz|ZooShot|ZyBorg)(?:[ /]v?(\d+)(?:\.(\d+)(?:\.(\d+))?)?)?'
91
92 # AWS S3 Clients
93 # must come before "Bots General matcher" to catch "boto"/"boto3" before "bot"
94 - regex: '\b(Boto3?|JetS3t|aws-(?:cli|sdk-(?:cpp|go|java|nodejs|ruby2?))|s3fs)/(\d+)\.(\d+)(?:\.(\d+))?'
95
96 # Bots General matcher 'name/0.0'
97 - regex: '(?:\/[A-Za-z0-9\.]+)? *([A-Za-z0-9 \-_\!\[\]:]*(?:[Aa]rchiver|[Ii]ndexer|[Ss]craper|[Bb]ot|[Ss]pider|[Cc]rawl[a-z]*))/(\d+)(?:\.(\d+)(?:\.(\d+))?)?'
98 # Bots General matcher 'name 0.0'
99 - regex: '(?:\/[A-Za-z0-9\.]+)? *([A-Za-z0-9 _\!\[\]:]*(?:[Aa]rchiver|[Ii]ndexer|[Ss]craper|[Bb]ot|[Ss]pider|[Cc]rawl[a-z]*)) (\d+)(?:\.(\d+)(?:\.(\d+))?)?'
100 # Bots containing spider|scrape|bot(but not CUBOT)|Crawl
101 - regex: '((?:[A-z0-9]+|[A-z\-]+ ?)?(?: the )?(?:[Ss][Pp][Ii][Dd][Ee][Rr]|[Ss]crape|[A-Za-z0-9-]*(?:[^C][^Uu])[Bb]ot|[Cc][Rr][Aa][Ww][Ll])[A-z0-9]*)(?:(?:[ /]| v)(\d+)(?:\.(\d+)(?:\.(\d+))?)?)?'
102
103 # HbbTV standard defines what features the browser should understand.
104 # but it's like targeting "HTML5 browsers", effective browser support depends on the model
105 # See os_parsers if you want to target a specific TV
106 - regex: '(HbbTV)/(\d+)\.(\d+)\.(\d+) \('
107
108 # must go before Firefox to catch Chimera/SeaMonkey/Camino/Waterfox
109 - regex: '(Chimera|SeaMonkey|Camino|Waterfox)/(\d+)\.(\d+)\.?([ab]?\d+[a-z]*)?'
110
111 # Social Networks
112 # Facebook
113 - regex: '\[FB.*;(FBAV)/(\d+)(?:\.(\d+)(?:\.(\d+))?)?'
114 family_replacement: 'Facebook'
115 # Pinterest
116 - regex: '\[(Pinterest)/[^\]]+\]'
117 - regex: '(Pinterest)(?: for Android(?: Tablet)?)?/(\d+)(?:\.(\d+)(?:\.(\d+))?)?'
118 # Instagram app
119 - regex: 'Mozilla.*Mobile.*(Instagram).(\d+)\.(\d+)\.(\d+)'
120 # Flipbaord app
121 - regex: 'Mozilla.*Mobile.*(Flipboard).(\d+)\.(\d+)\.(\d+)'
122 # Flipbaord-briefing app
123 - regex: 'Mozilla.*Mobile.*(Flipboard-Briefing).(\d+)\.(\d+)\.(\d+)'
124 # Onefootball app
125 - regex: 'Mozilla.*Mobile.*(Onefootball)\/Android.(\d+)\.(\d+)\.(\d+)'
126
127 # Basilisk
128 - regex: '(Firefox)/(\d+)\.(\d+) Basilisk/(\d+)'
129 family_replacement: 'Basilisk'
130
131 # Pale Moon
132 - regex: '(PaleMoon)/(\d+)\.(\d+)\.?(\d+)?'
133 family_replacement: 'Pale Moon'
134
135 # Firefox
136 - regex: '(Fennec)/(\d+)\.(\d+)\.?([ab]?\d+[a-z]*)'
137 family_replacement: 'Firefox Mobile'
138 - regex: '(Fennec)/(\d+)\.(\d+)(pre)'
139 family_replacement: 'Firefox Mobile'
140 - regex: '(Fennec)/(\d+)\.(\d+)'
141 family_replacement: 'Firefox Mobile'
142 - regex: '(?:Mobile|Tablet);.*(Firefox)/(\d+)\.(\d+)'
143 family_replacement: 'Firefox Mobile'
144 - regex: '(Namoroka|Shiretoko|Minefield)/(\d+)\.(\d+)\.(\d+(?:pre)?)'
145 family_replacement: 'Firefox ($1)'
146 - regex: '(Firefox)/(\d+)\.(\d+)(a\d+[a-z]*)'
147 family_replacement: 'Firefox Alpha'
148 - regex: '(Firefox)/(\d+)\.(\d+)(b\d+[a-z]*)'
149 family_replacement: 'Firefox Beta'
150 - regex: '(Firefox)-(?:\d+\.\d+)?/(\d+)\.(\d+)(a\d+[a-z]*)'
151 family_replacement: 'Firefox Alpha'
152 - regex: '(Firefox)-(?:\d+\.\d+)?/(\d+)\.(\d+)(b\d+[a-z]*)'
153 family_replacement: 'Firefox Beta'
154 - regex: '(Namoroka|Shiretoko|Minefield)/(\d+)\.(\d+)([ab]\d+[a-z]*)?'
155 family_replacement: 'Firefox ($1)'
156 - regex: '(Firefox).*Tablet browser (\d+)\.(\d+)\.(\d+)'
157 family_replacement: 'MicroB'
158 - regex: '(MozillaDeveloperPreview)/(\d+)\.(\d+)([ab]\d+[a-z]*)?'
159 - regex: '(FxiOS)/(\d+)\.(\d+)(\.(\d+))?(\.(\d+))?'
160 family_replacement: 'Firefox iOS'
161
162 # e.g.: Flock/2.0b2
163 - regex: '(Flock)/(\d+)\.(\d+)(b\d+?)'
164
165 # RockMelt
166 - regex: '(RockMelt)/(\d+)\.(\d+)\.(\d+)'
167
168 # e.g.: Fennec/0.9pre
169 - regex: '(Navigator)/(\d+)\.(\d+)\.(\d+)'
170 family_replacement: 'Netscape'
171
172 - regex: '(Navigator)/(\d+)\.(\d+)([ab]\d+)'
173 family_replacement: 'Netscape'
174
175 - regex: '(Netscape6)/(\d+)\.(\d+)\.?([ab]?\d+)?'
176 family_replacement: 'Netscape'
177
178 - regex: '(MyIBrow)/(\d+)\.(\d+)'
179 family_replacement: 'My Internet Browser'
180
181 # UC Browser
182 # we need check it before opera. In other case case UC Browser detected look like Opera Mini
183 - regex: '(UC? ?Browser|UCWEB|U3)[ /]?(\d+)\.(\d+)\.(\d+)'
184 family_replacement: 'UC Browser'
185
186 # Opera will stop at 9.80 and hide the real version in the Version string.
187 # see: http://dev.opera.com/articles/view/opera-ua-string-changes/
188 - regex: '(Opera Tablet).*Version/(\d+)\.(\d+)(?:\.(\d+))?'
189 - regex: '(Opera Mini)(?:/att)?/?(\d+)?(?:\.(\d+))?(?:\.(\d+))?'
190 - regex: '(Opera)/.+Opera Mobi.+Version/(\d+)\.(\d+)'
191 family_replacement: 'Opera Mobile'
192 - regex: '(Opera)/(\d+)\.(\d+).+Opera Mobi'
193 family_replacement: 'Opera Mobile'
194 - regex: 'Opera Mobi.+(Opera)(?:/|\s+)(\d+)\.(\d+)'
195 family_replacement: 'Opera Mobile'
196 - regex: 'Opera Mobi'
197 family_replacement: 'Opera Mobile'
198 - regex: '(Opera)/9.80.*Version/(\d+)\.(\d+)(?:\.(\d+))?'
199
200 # Opera 14 for Android uses a WebKit render engine.
201 - regex: '(?:Mobile Safari).*(OPR)/(\d+)\.(\d+)\.(\d+)'
202 family_replacement: 'Opera Mobile'
203
204 # Opera >=15 for Desktop is similar to Chrome but includes an "OPR" Version string.
205 - regex: '(?:Chrome).*(OPR)/(\d+)\.(\d+)\.(\d+)'
206 family_replacement: 'Opera'
207
208 # Opera Coast
209 - regex: '(Coast)/(\d+).(\d+).(\d+)'
210 family_replacement: 'Opera Coast'
211
212 # Opera Mini for iOS (from version 8.0.0)
213 - regex: '(OPiOS)/(\d+).(\d+).(\d+)'
214 family_replacement: 'Opera Mini'
215
216 # Opera Neon
217 - regex: 'Chrome/.+( MMS)/(\d+).(\d+).(\d+)'
218 family_replacement: 'Opera Neon'
219
220 # Palm WebOS looks a lot like Safari.
221 - regex: '(hpw|web)OS/(\d+)\.(\d+)(?:\.(\d+))?'
222 family_replacement: 'webOS Browser'
223
224 # LuaKit has no version info.
225 # http://luakit.org/projects/luakit/
226 - regex: '(luakit)'
227 family_replacement: 'LuaKit'
228
229 # Snowshoe
230 - regex: '(Snowshoe)/(\d+)\.(\d+).(\d+)'
231
232 # Lightning (for Thunderbird)
233 # http://www.mozilla.org/projects/calendar/lightning/
234 - regex: 'Gecko/\d+ (Lightning)/(\d+)\.(\d+)\.?((?:[ab]?\d+[a-z]*)|(?:\d*))'
235
236 # Swiftfox
237 - regex: '(Firefox)/(\d+)\.(\d+)\.(\d+(?:pre)?) \(Swiftfox\)'
238 family_replacement: 'Swiftfox'
239 - regex: '(Firefox)/(\d+)\.(\d+)([ab]\d+[a-z]*)? \(Swiftfox\)'
240 family_replacement: 'Swiftfox'
241
242 # Rekonq
243 - regex: '(rekonq)/(\d+)\.(\d+)\.?(\d+)? Safari'
244 family_replacement: 'Rekonq'
245 - regex: 'rekonq'
246 family_replacement: 'Rekonq'
247
248 # Conkeror lowercase/uppercase
249 # http://conkeror.org/
250 - regex: '(conkeror|Conkeror)/(\d+)\.(\d+)\.?(\d+)?'
251 family_replacement: 'Conkeror'
252
253 # catches lower case konqueror
254 - regex: '(konqueror)/(\d+)\.(\d+)\.(\d+)'
255 family_replacement: 'Konqueror'
256
257 - regex: '(WeTab)-Browser'
258
259 - regex: '(Comodo_Dragon)/(\d+)\.(\d+)\.(\d+)'
260 family_replacement: 'Comodo Dragon'
261
262 - regex: '(Symphony) (\d+).(\d+)'
263
264 - regex: 'PLAYSTATION 3.+WebKit'
265 family_replacement: 'NetFront NX'
266 - regex: 'PLAYSTATION 3'
267 family_replacement: 'NetFront'
268 - regex: '(PlayStation Portable)'
269 family_replacement: 'NetFront'
270 - regex: '(PlayStation Vita)'
271 family_replacement: 'NetFront NX'
272
273 - regex: 'AppleWebKit.+ (NX)/(\d+)\.(\d+)\.(\d+)'
274 family_replacement: 'NetFront NX'
275 - regex: '(Nintendo 3DS)'
276 family_replacement: 'NetFront NX'
277
278 # Amazon Silk, should go before Safari and Chrome Mobile
279 - regex: '(Silk)/(\d+)\.(\d+)(?:\.([0-9\-]+))?'
280 family_replacement: 'Amazon Silk'
281
282 # @ref: http://www.puffinbrowser.com
283 - regex: '(Puffin)/(\d+)\.(\d+)(?:\.(\d+))?'
284
285 # Edge Mobile
286 - regex: 'Windows Phone .*(Edge)/(\d+)\.(\d+)'
287 family_replacement: 'Edge Mobile'
288
289 # Samsung Internet (based on Chrome, but lacking some features)
290 - regex: '(SamsungBrowser)/(\d+)\.(\d+)'
291 family_replacement: 'Samsung Internet'
292
293 # Seznam.cz browser (based on WebKit)
294 - regex: '(SznProhlizec)/(\d+)\.(\d+)(?:\.(\d+))?'
295 family_replacement: 'Seznam prohlížeč'
296
297 # Coc Coc browser, based on Chrome (used in Vietnam)
298 - regex: '(coc_coc_browser)/(\d+)\.(\d+)(?:\.(\d+))?'
299 family_replacement: 'Coc Coc'
300
301 # Baidu Browsers (desktop spoofs chrome & IE, explorer is mobile)
302 - regex: '(baidubrowser)[/\s](\d+)(?:\.(\d+)(?:\.(\d+))?)?'
303 family_replacement: 'Baidu Browser'
304 - regex: '(FlyFlow)/(\d+)\.(\d+)'
305 family_replacement: 'Baidu Explorer'
306
307 # MxBrowser is Maxthon. Must go before Mobile Chrome for Android
308 - regex: '(MxBrowser)/(\d+)\.(\d+)(?:\.(\d+))?'
309 family_replacement: 'Maxthon'
310
311 # Crosswalk must go before Mobile Chrome for Android
312 - regex: '(Crosswalk)/(\d+)\.(\d+)\.(\d+)\.(\d+)'
313
314 # Chrome Mobile
315 - regex: 'Version/.+(Chrome)/(\d+)\.(\d+)\.(\d+)\.(\d+)'
316 family_replacement: 'Chrome Mobile WebView'
317 - regex: '; wv\).+(Chrome)/(\d+)\.(\d+)\.(\d+)\.(\d+)'
318 family_replacement: 'Chrome Mobile WebView'
319 - regex: '(CrMo)/(\d+)\.(\d+)\.(\d+)\.(\d+)'
320 family_replacement: 'Chrome Mobile'
321 - regex: '(CriOS)/(\d+)\.(\d+)\.(\d+)\.(\d+)'
322 family_replacement: 'Chrome Mobile iOS'
323 - regex: '(Chrome)/(\d+)\.(\d+)\.(\d+)\.(\d+) Mobile(?:[ /]|$)'
324 family_replacement: 'Chrome Mobile'
325 - regex: ' Mobile .*(Chrome)/(\d+)\.(\d+)\.(\d+)\.(\d+)'
326 family_replacement: 'Chrome Mobile'
327
328 # Chrome Frame must come before MSIE.
329 - regex: '(chromeframe)/(\d+)\.(\d+)\.(\d+)'
330 family_replacement: 'Chrome Frame'
331
332 # Tizen Browser (second case included in browser/major.minor regex)
333 - regex: '(SLP Browser)/(\d+)\.(\d+)'
334 family_replacement: 'Tizen Browser'
335
336 # Sogou Explorer 2.X
337 - regex: '(SE 2\.X) MetaSr (\d+)\.(\d+)'
338 family_replacement: 'Sogou Explorer'
339
340 # QQ Browsers
341 - regex: '(MQQBrowser/Mini)(?:(\d+)(?:\.(\d+)(?:\.(\d+))?)?)?'
342 family_replacement: 'QQ Browser Mini'
343 - regex: '(MQQBrowser)(?:/(\d+)(?:\.(\d+)(?:\.(\d+))?)?)?'
344 family_replacement: 'QQ Browser Mobile'
345 - regex: '(QQBrowser)(?:/(\d+)(?:\.(\d+)\.(\d+)(?:\.(\d+))?)?)?'
346 family_replacement: 'QQ Browser'
347
348 # Rackspace Monitoring
349 - regex: '(Rackspace Monitoring)/(\d+)\.(\d+)'
350 family_replacement: 'RackspaceBot'
351
352 # PyAMF
353 - regex: '(PyAMF)/(\d+)\.(\d+)\.(\d+)'
354
355 # Yandex Browser
356 - regex: '(YaBrowser)/(\d+)\.(\d+)\.(\d+)'
357 family_replacement: 'Yandex Browser'
358
359 # Mail.ru Amigo/Internet Browser (Chromium-based)
360 - regex: '(Chrome)/(\d+)\.(\d+)\.(\d+).* MRCHROME'
361 family_replacement: 'Mail.ru Chromium Browser'
362
363 # AOL Browser (IE-based)
364 - regex: '(AOL) (\d+)\.(\d+); AOLBuild (\d+)'
365
366 # Podcast catcher Applications using iTunes
367 - regex: '(PodCruncher|Downcast)[ /]?(\d+)\.?(\d+)?\.?(\d+)?\.?(\d+)?'
368
369 # Box Notes https://www.box.com/resources/downloads
370 # Must be before Electron
371 - regex: ' (BoxNotes)/(\d+)\.(\d+)\.(\d+)'
372
373 # Whale
374 - regex: '(Whale)/(\d+)\.(\d+)\.(\d+)\.(\d+) Mobile(?:[ /]|$)'
375 family_replacement: 'Whale'
376
377 - regex: '(Whale)/(\d+)\.(\d+)\.(\d+)'
378 family_replacement: 'Whale'
379
380 #### END SPECIAL CASES TOP ####
381
382 #### MAIN CASES - this catches > 50% of all browsers ####
383
384
385 # Slack desktop client (needs to be before Apple Mail, Electron, and Chrome as it gets wrongly detected on Mac OS otherwise)
386 - regex: '(Slack_SSB)/(\d+)\.(\d+)\.(\d+)'
387 family_replacement: 'Slack Desktop Client'
388
389 # HipChat provides a version on Mac, but not on Windows.
390 # Needs to be before Chrome on Windows, and AppleMail on Mac.
391 - regex: '(HipChat)/?(\d+)?'
392 family_replacement: 'HipChat Desktop Client'
393
394 # Browser/major_version.minor_version.beta_version
395 - regex: '\b(MobileIron|FireWeb|Jasmine|ANTGalio|Midori|Fresco|Lobo|PaleMoon|Maxthon|Lynx|OmniWeb|Dillo|Camino|Demeter|Fluid|Fennec|Epiphany|Shiira|Sunrise|Spotify|Flock|Netscape|Lunascape|WebPilot|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|MacOutlook|Electron|OktaMobile)/(\d+)\.(\d+)\.(\d+)'
396
397 # Outlook 2007
398 - regex: 'Microsoft Office Outlook 12\.\d+\.\d+|MSOffice 12'
399 family_replacement: 'Outlook'
400 v1_replacement: '2007'
401
402 # Outlook 2010
403 - regex: 'Microsoft Outlook 14\.\d+\.\d+|MSOffice 14'
404 family_replacement: 'Outlook'
405 v1_replacement: '2010'
406
407 # Outlook 2013
408 - regex: 'Microsoft Outlook 15\.\d+\.\d+'
409 family_replacement: 'Outlook'
410 v1_replacement: '2013'
411
412 # Outlook 2016
413 - regex: 'Microsoft Outlook (?:Mail )?16\.\d+\.\d+'
414 family_replacement: 'Outlook'
415 v1_replacement: '2016'
416
417 # Windows Live Mail
418 - regex: 'Outlook-Express\/7\.0.*'
419 family_replacement: 'Windows Live Mail'
420
421 # Apple Air Mail
422 - regex: '(Airmail) (\d+)\.(\d+)(?:\.(\d+))?'
423
424 # Thunderbird
425 - regex: '(Thunderbird)/(\d+)\.(\d+)(?:\.(\d+(?:pre)?))?'
426 family_replacement: 'Thunderbird'
427
428 # Postbox
429 - regex: '(Postbox)/(\d+)\.(\d+)\.(\d+)'
430 family_replacement: 'Postbox'
431
432 # Barca
433 - regex: '(Barca(?:Pro)?)/(\d+)\.(\d+)(?:\.(\d+))?'
434 family_replacement: 'Barca'
435
436 # Lotus Notes
437 - regex: '(Lotus-Notes)/(\d+)\.(\d+)(?:\.(\d+))?'
438 family_replacement: 'Lotus Notes'
439
440 # Vivaldi uses "Vivaldi"
441 - regex: '(Vivaldi)/(\d+)\.(\d+)\.(\d+)'
442
443 # Edge/major_version.minor_version
444 - regex: '(Edge)/(\d+)(?:\.(\d+))?'
445
446 # Brave Browser https://brave.com/
447 - regex: '(brave)/(\d+)\.(\d+)\.(\d+) Chrome'
448 family_replacement: 'Brave'
449
450 # Iron Browser ~since version 50
451 - regex: '(Chrome)/(\d+)\.(\d+)\.(\d+)[\d.]* Iron[^/]'
452 family_replacement: 'Iron'
453
454 # Dolphin Browser
455 # @ref: http://www.dolphin.com
456 - regex: '\b(Dolphin)(?: |HDCN/|/INT\-)(\d+)\.(\d+)\.?(\d+)?'
457
458 # Headless Chrome
459 # https://chromium.googlesource.com/chromium/src/+/lkgr/headless/README.md
460 - regex: '(HeadlessChrome)(?:/(\d+)\.(\d+)\.(\d+))?'
461
462 # Evolution Mail CardDav/CalDav integration
463 - regex: '(Evolution)/(\d+)\.(\d+)\.(\d+\.\d+)'
464
465 # Roundcube Mail CardDav plugin
466 - regex: '(RCM CardDAV plugin)/(\d+)\.(\d+)\.(\d+(?:-dev)?)'
467
468 # Browser/major_version.minor_version
469 - regex: '(bingbot|Bolt|AdobeAIR|Jasmine|IceCat|Skyfire|Midori|Maxthon|Lynx|Arora|IBrowse|Dillo|Camino|Shiira|Fennec|Phoenix|Flock|Netscape|Lunascape|Epiphany|WebPilot|Opera Mini|Opera|NetFront|Netfront|Konqueror|Googlebot|SeaMonkey|Kazehakase|Vienna|Iceape|Iceweasel|IceWeasel|Iron|K-Meleon|Sleipnir|Galeon|GranParadiso|iCab|iTunes|MacAppStore|NetNewsWire|Space Bison|Stainless|Orca|Dolfin|BOLT|Minimo|Tizen Browser|Polaris|Abrowser|Planetweb|ICE Browser|mDolphin|qutebrowser|Otter|QupZilla|MailBar|kmail2|YahooMobileMail|ExchangeWebServices|ExchangeServicesClient|Dragon|Outlook-iOS-Android)/(\d+)\.(\d+)(?:\.(\d+))?'
470
471 # Chrome/Chromium/major_version.minor_version
472 - regex: '(Chromium|Chrome)/(\d+)\.(\d+)(?:\.(\d+))?(?:\.(\d+))?'
473
474 ##########
475 # IE Mobile needs to happen before Android to catch cases such as:
476 # Mozilla/5.0 (Mobile; Windows Phone 8.1; Android 4.0; ARM; Trident/7.0; Touch; rv:11.0; IEMobile/11.0; NOKIA; Lumia 920)...
477 # Mozilla/5.0 (Mobile; Windows Phone 8.1; Android 4.0; ARM; Trident/7.0; Touch; rv:11.0; IEMobile/11.0; NOKIA; Lumia 920; ANZ821)...
478 # Mozilla/5.0 (Mobile; Windows Phone 8.1; Android 4.0; ARM; Trident/7.0; Touch; rv:11.0; IEMobile/11.0; NOKIA; Lumia 920; Orange)...
479 # Mozilla/5.0 (Mobile; Windows Phone 8.1; Android 4.0; ARM; Trident/7.0; Touch; rv:11.0; IEMobile/11.0; NOKIA; Lumia 920; Vodafone)...
480 ##########
481
482 # IE Mobile
483 - regex: '(IEMobile)[ /](\d+)\.(\d+)'
484 family_replacement: 'IE Mobile'
485
486 # Baca Berita App News Reader
487 - regex: '(BacaBerita App)\/(\d+)\.(\d+)\.(\d+)'
488
489 # Podcast catchers
490 - regex: '^(bPod|Pocket Casts|Player FM)$'
491 - regex: '^(AlexaMediaPlayer|VLC)/(\d+)\.(\d+)\.([^.\s]+)'
492 - regex: '^(AntennaPod|WMPlayer|Zune|Podkicker|Radio|ExoPlayerDemo|Overcast|PocketTunes|NSPlayer|okhttp|DoggCatcher|QuickNews|QuickTime|Peapod|Podcasts|GoldenPod|VLC|Spotify|Miro|MediaGo|Juice|iPodder|gPodder|Banshee)/(\d+)\.(\d+)\.?(\d+)?\.?(\d+)?'
493 - regex: '^(Peapod|Liferea)/([^.\s]+)\.([^.\s]+)?\.?([^.\s]+)?'
494 - regex: '^(bPod|Player FM) BMID/(\S+)'
495 - regex: '^(Podcast ?Addict)/v(\d+) '
496 - regex: '^(Podcast ?Addict) '
497 family_replacement: 'PodcastAddict'
498 - regex: '(Replay) AV'
499 - regex: '(VOX) Music Player'
500 - regex: '(CITA) RSS Aggregator/(\d+)\.(\d+)'
501 - regex: '(Pocket Casts)$'
502 - regex: '(Player FM)$'
503 - regex: '(LG Player|Doppler|FancyMusic|MediaMonkey|Clementine) (\d+)\.(\d+)\.?([^.\s]+)?\.?([^.\s]+)?'
504 - regex: '(philpodder)/(\d+)\.(\d+)\.?([^.\s]+)?\.?([^.\s]+)?'
505 - regex: '(Player FM|Pocket Casts|DoggCatcher|Spotify|MediaMonkey|MediaGo|BashPodder)'
506 - regex: '(QuickTime)\.(\d+)\.(\d+)\.(\d+)'
507 - regex: '(Kinoma)(\d+)'
508 - regex: '(Fancy) Cloud Music (\d+)\.(\d+)'
509 family_replacement: 'FancyMusic'
510 - regex: 'EspnDownloadManager'
511 family_replacement: 'ESPN'
512 - regex: '(ESPN) Radio (\d+)\.(\d+)\.?(\d+)? ?(?:rv:(\d+))? '
513 - regex: '(podracer|jPodder) v ?(\d+)\.(\d+)\.?(\d+)?'
514 - regex: '(ZDM)/(\d+)\.(\d+)[; ]?'
515 - regex: '(Zune|BeyondPod) (\d+)\.?(\d+)?[\);]'
516 - regex: '(WMPlayer)/(\d+)\.(\d+)\.(\d+)\.(\d+)'
517 - regex: '^(Lavf)'
518 family_replacement: 'WMPlayer'
519 - regex: '^(RSSRadio)[ /]?(\d+)?'
520 - regex: '(RSS_Radio) (\d+)\.(\d+)'
521 family_replacement: 'RSSRadio'
522 - regex: '(Podkicker) \S+/(\d+)\.(\d+)\.(\d+)'
523 family_replacement: 'Podkicker'
524 - regex: '^(HTC) Streaming Player \S+ / \S+ / \S+ / (\d+)\.(\d+)\.?(\d+)?'
525 - regex: '^(Stitcher)/iOS'
526 - regex: '^(Stitcher)/Android'
527 - regex: '^(VLC) .*version (\d+)\.(\d+)\.(\d+)'
528 - regex: ' (VLC) for'
529 - regex: '(vlc)/(\d+)\.(\d+)\.(\d+)'
530 family_replacement: 'VLC'
531 - regex: '^(foobar)\S+/([^.\s]+)\.([^.\s]+)?\.?([^.\s]+)?'
532 - regex: '^(Clementine)\S+ ([^.\s]+)\.([^.\s]+)?\.?([^.\s]+)?'
533 - regex: '(amarok)/([^.\s]+)\.([^.\s]+)?\.?([^.\s]+)?'
534 family_replacement: 'Amarok'
535 - regex: '(Custom)-Feed Reader'
536
537 # Browser major_version.minor_version.beta_version (space instead of slash)
538 - regex: '(iRider|Crazy Browser|SkipStone|iCab|Lunascape|Sleipnir|Maemo Browser) (\d+)\.(\d+)\.(\d+)'
539 # Browser major_version.minor_version (space instead of slash)
540 - regex: '(iCab|Lunascape|Opera|Android|Jasmine|Polaris|Microsoft SkyDriveSync|The Bat!) (\d+)\.(\d+)\.?(\d+)?'
541
542 # Kindle WebKit
543 - regex: '(Kindle)/(\d+)\.(\d+)'
544
545 # weird android UAs
546 - regex: '(Android) Donut'
547 v1_replacement: '1'
548 v2_replacement: '2'
549
550 - regex: '(Android) Eclair'
551 v1_replacement: '2'
552 v2_replacement: '1'
553
554 - regex: '(Android) Froyo'
555 v1_replacement: '2'
556 v2_replacement: '2'
557
558 - regex: '(Android) Gingerbread'
559 v1_replacement: '2'
560 v2_replacement: '3'
561
562 - regex: '(Android) Honeycomb'
563 v1_replacement: '3'
564
565 # desktop mode
566 # http://www.anandtech.com/show/3982/windows-phone-7-review
567 - regex: '(MSIE) (\d+)\.(\d+).*XBLWP7'
568 family_replacement: 'IE Large Screen'
569
570 # Nextcloud desktop sync client
571 - regex: '(Nextcloud)'
572
573 # Generic mirall client
574 - regex: '(mirall)/(\d+)\.(\d+)\.(\d+)'
575
576 # Nextcloud/Owncloud android client
577 - regex: '(ownCloud-android)/(\d+)\.(\d+)\.(\d+)'
578 family_replacement: 'Owncloud'
579
580 #### END MAIN CASES ####
581
582 #### SPECIAL CASES ####
583 - regex: '(Obigo)InternetBrowser'
584 - regex: '(Obigo)\-Browser'
585 - regex: '(Obigo|OBIGO)[^\d]*(\d+)(?:.(\d+))?'
586 family_replacement: 'Obigo'
587
588 - regex: '(MAXTHON|Maxthon) (\d+)\.(\d+)'
589 family_replacement: 'Maxthon'
590 - regex: '(Maxthon|MyIE2|Uzbl|Shiira)'
591 v1_replacement: '0'
592
593 - regex: '(BrowseX) \((\d+)\.(\d+)\.(\d+)'
594
595 - regex: '(NCSA_Mosaic)/(\d+)\.(\d+)'
596 family_replacement: 'NCSA Mosaic'
597
598 # Polaris/d.d is above
599 - regex: '(POLARIS)/(\d+)\.(\d+)'
600 family_replacement: 'Polaris'
601 - regex: '(Embider)/(\d+)\.(\d+)'
602 family_replacement: 'Polaris'
603
604 - regex: '(BonEcho)/(\d+)\.(\d+)\.?([ab]?\d+)?'
605 family_replacement: 'Bon Echo'
606
607 # @note: iOS / OSX Applications
608 - regex: '(iPod|iPhone|iPad).+Version/(\d+)\.(\d+)(?:\.(\d+))?.*[ +]Safari'
609 family_replacement: 'Mobile Safari'
610 - regex: '(iPod|iPod touch|iPhone|iPad);.*CPU.*OS[ +](\d+)_(\d+)(?:_(\d+))?.* AppleNews\/\d+\.\d+\.\d+?'
611 family_replacement: 'Mobile Safari UI/WKWebView'
612 - regex: '(iPod|iPhone|iPad).+Version/(\d+)\.(\d+)(?:\.(\d+))?'
613 family_replacement: 'Mobile Safari UI/WKWebView'
614 - regex: '(iPod|iPod touch|iPhone|iPad);.*CPU.*OS[ +](\d+)_(\d+)(?:_(\d+))?.*Mobile.*[ +]Safari'
615 family_replacement: 'Mobile Safari'
616 - regex: '(iPod|iPod touch|iPhone|iPad);.*CPU.*OS[ +](\d+)_(\d+)(?:_(\d+))?.*Mobile'
617 family_replacement: 'Mobile Safari UI/WKWebView'
618 - regex: '(iPod|iPhone|iPad).* Safari'
619 family_replacement: 'Mobile Safari'
620 - regex: '(iPod|iPhone|iPad)'
621 family_replacement: 'Mobile Safari UI/WKWebView'
622
623 ##########################
624 # Outlook on iOS >= 2.62.0
625 ##########################
626 - regex: '(Outlook-iOS)/\d+\.\d+\.prod\.iphone \((\d+)\.(\d+)\.(\d+)\)'
627
628 - regex: '(AvantGo) (\d+).(\d+)'
629
630 - regex: '(OneBrowser)/(\d+).(\d+)'
631 family_replacement: 'ONE Browser'
632
633 - regex: '(Avant)'
634 v1_replacement: '1'
635
636 # This is the Tesla Model S (see similar entry in device parsers)
637 - regex: '(QtCarBrowser)'
638 v1_replacement: '1'
639
640 - regex: '^(iBrowser/Mini)(\d+).(\d+)'
641 family_replacement: 'iBrowser Mini'
642 - regex: '^(iBrowser|iRAPP)/(\d+).(\d+)'
643
644 # nokia browsers
645 # based on: http://www.developer.nokia.com/Community/Wiki/User-Agent_headers_for_Nokia_devices
646 - regex: '^(Nokia)'
647 family_replacement: 'Nokia Services (WAP) Browser'
648 - regex: '(NokiaBrowser)/(\d+)\.(\d+).(\d+)\.(\d+)'
649 family_replacement: 'Nokia Browser'
650 - regex: '(NokiaBrowser)/(\d+)\.(\d+).(\d+)'
651 family_replacement: 'Nokia Browser'
652 - regex: '(NokiaBrowser)/(\d+)\.(\d+)'
653 family_replacement: 'Nokia Browser'
654 - regex: '(BrowserNG)/(\d+)\.(\d+).(\d+)'
655 family_replacement: 'Nokia Browser'
656 - regex: '(Series60)/5\.0'
657 family_replacement: 'Nokia Browser'
658 v1_replacement: '7'
659 v2_replacement: '0'
660 - regex: '(Series60)/(\d+)\.(\d+)'
661 family_replacement: 'Nokia OSS Browser'
662 - regex: '(S40OviBrowser)/(\d+)\.(\d+)\.(\d+)\.(\d+)'
663 family_replacement: 'Ovi Browser'
664 - regex: '(Nokia)[EN]?(\d+)'
665
666 # BlackBerry devices
667 - regex: '(PlayBook).+RIM Tablet OS (\d+)\.(\d+)\.(\d+)'
668 family_replacement: 'BlackBerry WebKit'
669 - regex: '(Black[bB]erry|BB10).+Version/(\d+)\.(\d+)\.(\d+)'
670 family_replacement: 'BlackBerry WebKit'
671 - regex: '(Black[bB]erry)\s?(\d+)'
672 family_replacement: 'BlackBerry'
673
674 - regex: '(OmniWeb)/v(\d+)\.(\d+)'
675
676 - regex: '(Blazer)/(\d+)\.(\d+)'
677 family_replacement: 'Palm Blazer'
678
679 - regex: '(Pre)/(\d+)\.(\d+)'
680 family_replacement: 'Palm Pre'
681
682 # fork of Links
683 - regex: '(ELinks)/(\d+)\.(\d+)'
684 - regex: '(ELinks) \((\d+)\.(\d+)'
685 - regex: '(Links) \((\d+)\.(\d+)'
686
687 - regex: '(QtWeb) Internet Browser/(\d+)\.(\d+)'
688
689 #- regex: '\(iPad;.+(Version)/(\d+)\.(\d+)(?:\.(\d+))?.*Safari/'
690 # family_replacement: 'iPad'
691
692 # Phantomjs, should go before Safari
693 - regex: '(PhantomJS)/(\d+)\.(\d+)\.(\d+)'
694
695 # WebKit Nightly
696 - regex: '(AppleWebKit)/(\d+)\.?(\d+)?\+ .* Safari'
697 family_replacement: 'WebKit Nightly'
698
699 # Safari
700 - regex: '(Version)/(\d+)\.(\d+)(?:\.(\d+))?.*Safari/'
701 family_replacement: 'Safari'
702 # Safari didn't provide "Version/d.d.d" prior to 3.0
703 - regex: '(Safari)/\d+'
704
705 - regex: '(OLPC)/Update(\d+)\.(\d+)'
706
707 - regex: '(OLPC)/Update()\.(\d+)'
708 v1_replacement: '0'
709
710 - regex: '(SEMC\-Browser)/(\d+)\.(\d+)'
711
712 - regex: '(Teleca)'
713 family_replacement: 'Teleca Browser'
714
715 - regex: '(Phantom)/V(\d+)\.(\d+)'
716 family_replacement: 'Phantom Browser'
717
718 - regex: '(Trident)/(7|8)\.(0)'
719 family_replacement: 'IE'
720 v1_replacement: '11'
721
722 - regex: '(Trident)/(6)\.(0)'
723 family_replacement: 'IE'
724 v1_replacement: '10'
725
726 - regex: '(Trident)/(5)\.(0)'
727 family_replacement: 'IE'
728 v1_replacement: '9'
729
730 - regex: '(Trident)/(4)\.(0)'
731 family_replacement: 'IE'
732 v1_replacement: '8'
733
734 # Espial
735 - regex: '(Espial)/(\d+)(?:\.(\d+))?(?:\.(\d+))?'
736
737 # Apple Mail
738
739 # apple mail - not directly detectable, have it after Safari stuff
740 - regex: '(AppleWebKit)/(\d+)\.(\d+)\.(\d+)'
741 family_replacement: 'Apple Mail'
742
743 # AFTER THE EDGE CASES ABOVE!
744 # AFTER IE11
745 # BEFORE all other IE
746 - regex: '(Firefox)/(\d+)\.(\d+)\.(\d+)'
747 - regex: '(Firefox)/(\d+)\.(\d+)(pre|[ab]\d+[a-z]*)?'
748
749 - regex: '([MS]?IE) (\d+)\.(\d+)'
750 family_replacement: 'IE'
751
752 - regex: '(python-requests)/(\d+)\.(\d+)'
753 family_replacement: 'Python Requests'
754
755 # headless user-agents
756 - regex: '\b(Windows-Update-Agent|Microsoft-CryptoAPI|SophosUpdateManager|SophosAgent|Debian APT-HTTP|Ubuntu APT-HTTP|libcurl-agent|libwww-perl|urlgrabber|curl|PycURL|Wget|aria2|Axel|OpenBSD ftp|lftp|jupdate|insomnia)(?:[ /](\d+)(?:\.(\d+)(?:\.(\d+))?)?)?'
757
758 - regex: '(Java)[/ ]{0,1}\d+\.(\d+)\.(\d+)[_-]*([a-zA-Z0-9]+)*'
759
760 # Cloud Storage Clients
761 - regex: '^(Cyberduck)/(\d+)\.(\d+)\.(\d+)(?:\.\d+)?'
762 - regex: '^(S3 Browser) (\d+)-(\d+)-(\d+)(?:\s*http://s3browser\.com)?'
763 # rclone - rsync for cloud storage - https://rclone.org/
764 - regex: '^(rclone)/v(\d+)\.(\d+)'
765
766 # Roku Digital-Video-Players https://www.roku.com/
767 - regex: '^(Roku)/DVP-(\d+)\.(\d+)'
768
769 # Kurio App News Reader https://kurio.co.id/
770 - regex: '(Kurio)\/(\d+)\.(\d+)\.(\d+)'
771 family_replacement: 'Kurio App'
772
773 # Box Drive and Box Sync https://www.box.com/resources/downloads
774 - regex: '^(Box(?: Sync)?)/(\d+)\.(\d+)\.(\d+)'
775
776 os_parsers:
777 ##########
778 # HbbTV vendors
779 ##########
780
781 # starts with the easy one : Panasonic seems consistent across years, hope it will continue
782 #HbbTV/1.1.1 (;Panasonic;VIERA 2011;f.532;0071-0802 2000-0000;)
783 #HbbTV/1.1.1 (;Panasonic;VIERA 2012;1.261;0071-3103 2000-0000;)
784 #HbbTV/1.2.1 (;Panasonic;VIERA 2013;3.672;4101-0003 0002-0000;)
785 #- regex: 'HbbTV/\d+\.\d+\.\d+ \(;(Panasonic);VIERA ([0-9]{4});'
786
787 # Sony is consistent too but do not place year like the other
788 # Opera/9.80 (Linux armv7l; HbbTV/1.1.1 (; Sony; KDL32W650A; PKG3.211EUA; 2013;); ) Presto/2.12.362 Version/12.11
789 # Opera/9.80 (Linux mips; U; HbbTV/1.1.1 (; Sony; KDL40HX751; PKG1.902EUA; 2012;);; en) Presto/2.10.250 Version/11.60
790 # Opera/9.80 (Linux mips; U; HbbTV/1.1.1 (; Sony; KDL22EX320; PKG4.017EUA; 2011;);; en) Presto/2.7.61 Version/11.00
791 #- regex: 'HbbTV/\d+\.\d+\.\d+ \(; (Sony);.*;.*; ([0-9]{4});\)'
792
793
794 # LG is consistent too, but we need to add manually the year model
795 #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 ;)
796 #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 ;)
797 - regex: 'HbbTV/\d+\.\d+\.\d+ \( ;(LG)E ;NetCast 4.0'
798 os_v1_replacement: '2013'
799 - regex: 'HbbTV/\d+\.\d+\.\d+ \( ;(LG)E ;NetCast 3.0'
800 os_v1_replacement: '2012'
801
802 # Samsung is on its way of normalizing their user-agent
803 # HbbTV/1.1.1 (;Samsung;SmartTV2013;T-FXPDEUC-1102.2;;) WebKit
804 # HbbTV/1.1.1 (;Samsung;SmartTV2013;T-MST12DEUC-1102.1;;) WebKit
805 # HbbTV/1.1.1 (;Samsung;SmartTV2012;;;) WebKit
806 # HbbTV/1.1.1 (;;;;;) Maple_2011
807 - regex: 'HbbTV/1.1.1 \(;;;;;\) Maple_2011'
808 os_replacement: 'Samsung'
809 os_v1_replacement: '2011'
810 # manage the two models of 2013
811 - regex: 'HbbTV/\d+\.\d+\.\d+ \(;(Samsung);SmartTV([0-9]{4});.*FXPDEUC'
812 os_v2_replacement: 'UE40F7000'
813 - regex: 'HbbTV/\d+\.\d+\.\d+ \(;(Samsung);SmartTV([0-9]{4});.*MST12DEUC'
814 os_v2_replacement: 'UE32F4500'
815 # generic Samsung (works starting in 2012)
816 #- regex: 'HbbTV/\d+\.\d+\.\d+ \(;(Samsung);SmartTV([0-9]{4});'
817
818 # Philips : not found any other way than a manual mapping
819 # 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
820 # 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
821 - regex: 'HbbTV/1.1.1 \(; (Philips);.*NETTV/4'
822 os_v1_replacement: '2013'
823 - regex: 'HbbTV/1.1.1 \(; (Philips);.*NETTV/3'
824 os_v1_replacement: '2012'
825 - regex: 'HbbTV/1.1.1 \(; (Philips);.*NETTV/2'
826 os_v1_replacement: '2011'
827
828 # the HbbTV emulator developers use HbbTV/1.1.1 (;;;;;) firetv-firefox-plugin 1.1.20
829 - regex: 'HbbTV/\d+\.\d+\.\d+.*(firetv)-firefox-plugin (\d+).(\d+).(\d+)'
830 os_replacement: 'FireHbbTV'
831
832 # generic HbbTV, hoping to catch manufacturer name (always after 2nd comma) and the first string that looks like a 2011-2019 year
833 - regex: 'HbbTV/\d+\.\d+\.\d+ \(.*; ?([a-zA-Z]+) ?;.*(201[1-9]).*\)'
834
835 ##########
836 # @note: Windows Phone needs to come before Windows NT 6.1 *and* before Android to catch cases such as:
837 # Mozilla/5.0 (Mobile; Windows Phone 8.1; Android 4.0; ARM; Trident/7.0; Touch; rv:11.0; IEMobile/11.0; NOKIA; Lumia 920)...
838 # Mozilla/5.0 (Mobile; Windows Phone 8.1; Android 4.0; ARM; Trident/7.0; Touch; rv:11.0; IEMobile/11.0; NOKIA; Lumia 920; ANZ821)...
839 # Mozilla/5.0 (Mobile; Windows Phone 8.1; Android 4.0; ARM; Trident/7.0; Touch; rv:11.0; IEMobile/11.0; NOKIA; Lumia 920; Orange)...
840 # Mozilla/5.0 (Mobile; Windows Phone 8.1; Android 4.0; ARM; Trident/7.0; Touch; rv:11.0; IEMobile/11.0; NOKIA; Lumia 920; Vodafone)...
841 ##########
842
843 - regex: '(Windows Phone) (?:OS[ /])?(\d+)\.(\d+)'
844
845 # Again a MS-special one: iPhone.*Outlook-iOS-Android/x.x is erroneously detected as Android
846 - regex: '(CPU[ +]OS|iPhone[ +]OS|CPU[ +]iPhone)[ +]+(\d+)[_\.](\d+)(?:[_\.](\d+))?.*Outlook-iOS-Android'
847 os_replacement: 'iOS'
848
849 ##########
850 # Android
851 # can actually detect rooted android os. do we care?
852 ##########
853 - regex: '(Android)[ \-/](\d+)\.?(\d+)?(?:[.\-]([a-z0-9]+))?'
854
855 - regex: '(Android) Donut'
856 os_v1_replacement: '1'
857 os_v2_replacement: '2'
858
859 - regex: '(Android) Eclair'
860 os_v1_replacement: '2'
861 os_v2_replacement: '1'
862
863 - regex: '(Android) Froyo'
864 os_v1_replacement: '2'
865 os_v2_replacement: '2'
866
867 - regex: '(Android) Gingerbread'
868 os_v1_replacement: '2'
869 os_v2_replacement: '3'
870
871 - regex: '(Android) Honeycomb'
872 os_v1_replacement: '3'
873
874 # UCWEB
875 - regex: '^UCWEB.*; (Adr) (\d+)\.(\d+)(?:[.\-]([a-z0-9]+))?;'
876 os_replacement: 'Android'
877 - regex: '^UCWEB.*; (iPad|iPh|iPd) OS (\d+)_(\d+)(?:_(\d+))?;'
878 os_replacement: 'iOS'
879 - regex: '^UCWEB.*; (wds) (\d+)\.(\d+)(?:\.(\d+))?;'
880 os_replacement: 'Windows Phone'
881 # JUC
882 - regex: '^(JUC).*; ?U; ?(?:Android)?(\d+)\.(\d+)(?:[\.\-]([a-z0-9]+))?'
883 os_replacement: 'Android'
884
885 # Salesforce
886 - regex: '(android)\s(?:mobile\/)(\d+)\.(\d+)\.?(\d+)?'
887 os_replacement: 'Android'
888
889 ##########
890 # Kindle Android
891 ##########
892 - regex: '(Silk-Accelerated=[a-z]{4,5})'
893 os_replacement: 'Android'
894
895 ##########
896 # Windows
897 # http://en.wikipedia.org/wiki/Windows_NT#Releases
898 # possibility of false positive when different marketing names share same NT kernel
899 # e.g. windows server 2003 and windows xp
900 # lots of ua strings have Windows NT 4.1 !?!?!?!? !?!? !? !????!?! !!! ??? !?!?! ?
901 # (very) roughly ordered in terms of frequency of occurence of regex (win xp currently most frequent, etc)
902 ##########
903
904 # ie mobile desktop mode
905 # spoofs nt 6.1. must come before windows 7
906 - regex: '(XBLWP7)'
907 os_replacement: 'Windows Phone'
908
909 # @note: This needs to come before Windows NT 6.1
910 - regex: '(Windows ?Mobile)'
911 os_replacement: 'Windows Mobile'
912
913 - regex: '(Windows (?:NT 5\.2|NT 5\.1))'
914 os_replacement: 'Windows'
915 os_v1_replacement: 'XP'
916
917 - regex: '(Windows NT 6\.1)'
918 os_replacement: 'Windows'
919 os_v1_replacement: '7'
920
921 - regex: '(Windows NT 6\.0)'
922 os_replacement: 'Windows'
923 os_v1_replacement: 'Vista'
924
925 - regex: '(Win 9x 4\.90)'
926 os_replacement: 'Windows'
927 os_v1_replacement: 'ME'
928
929 - regex: '(Windows 98|Windows XP|Windows ME|Windows 95|Windows CE|Windows 7|Windows NT 4\.0|Windows Vista|Windows 2000|Windows 3.1)'
930
931 - regex: '(Windows NT 6\.2; ARM;)'
932 os_replacement: 'Windows'
933 os_v1_replacement: 'RT'
934
935 - regex: '(Windows NT 6\.2)'
936 os_replacement: 'Windows'
937 os_v1_replacement: '8'
938
939 - regex: '(Windows NT 6\.3; ARM;)'
940 os_replacement: 'Windows'
941 os_v1_replacement: 'RT 8.1'
942
943 - regex: '(Windows NT 6\.3)'
944 os_replacement: 'Windows'
945 os_v1_replacement: '8.1'
946
947 - regex: '(Windows NT 6\.4)'
948 os_replacement: 'Windows'
949 os_v1_replacement: '10'
950
951 - regex: '(Windows NT 10\.0)'
952 os_replacement: 'Windows'
953 os_v1_replacement: '10'
954
955 - regex: '(Windows NT 5\.0)'
956 os_replacement: 'Windows'
957 os_v1_replacement: '2000'
958
959 - regex: '(WinNT4.0)'
960 os_replacement: 'Windows'
961 os_v1_replacement: 'NT 4.0'
962
963 - regex: '(Windows ?CE)'
964 os_replacement: 'Windows'
965 os_v1_replacement: 'CE'
966
967 - regex: 'Win ?(95|98|3.1|NT|ME|2000)'
968 os_replacement: 'Windows'
969 os_v1_replacement: '$1'
970
971 - regex: 'Win16'
972 os_replacement: 'Windows'
973 os_v1_replacement: '3.1'
974
975 - regex: 'Win32'
976 os_replacement: 'Windows'
977 os_v1_replacement: '95'
978
979 # Box apps (Drive, Sync, Notes) on Windows https://www.box.com/resources/downloads
980 - regex: '^Box.*Windows/([\d.]+);'
981 os_replacement: 'Windows'
982 os_v1_replacement: '$1'
983
984 ##########
985 # Tizen OS from Samsung
986 # spoofs Android so pushing it above
987 ##########
988 - regex: '(Tizen)[/ ](\d+)\.(\d+)'
989
990 ##########
991 # Mac OS
992 # @ref: http://en.wikipedia.org/wiki/Mac_OS_X#Versions
993 # @ref: http://www.puredarwin.org/curious/versions
994 ##########
995 - regex: '((?:Mac[ +]?|; )OS[ +]X)[\s+/](?:(\d+)[_.](\d+)(?:[_.](\d+))?|Mach-O)'
996 os_replacement: 'Mac OS X'
997 - regex: '(\w+\s+Mac OS X\s+\w+\s+(\d+).(\d+).(\d+).*)'
998 os_replacement: 'Mac OS X'
999 os_v1_replacement: '$2'
1000 os_v2_replacement: '$3'
1001 os_v3_replacement: '$4'
1002 # Leopard
1003 - regex: ' (Dar)(win)/(9).(\d+).*\((?:i386|x86_64|Power Macintosh)\)'
1004 os_replacement: 'Mac OS X'
1005 os_v1_replacement: '10'
1006 os_v2_replacement: '5'
1007 # Snow Leopard
1008 - regex: ' (Dar)(win)/(10).(\d+).*\((?:i386|x86_64)\)'
1009 os_replacement: 'Mac OS X'
1010 os_v1_replacement: '10'
1011 os_v2_replacement: '6'
1012 # Lion
1013 - regex: ' (Dar)(win)/(11).(\d+).*\((?:i386|x86_64)\)'
1014 os_replacement: 'Mac OS X'
1015 os_v1_replacement: '10'
1016 os_v2_replacement: '7'
1017 # Mountain Lion
1018 - regex: ' (Dar)(win)/(12).(\d+).*\((?:i386|x86_64)\)'
1019 os_replacement: 'Mac OS X'
1020 os_v1_replacement: '10'
1021 os_v2_replacement: '8'
1022 # Mavericks
1023 - regex: ' (Dar)(win)/(13).(\d+).*\((?:i386|x86_64)\)'
1024 os_replacement: 'Mac OS X'
1025 os_v1_replacement: '10'
1026 os_v2_replacement: '9'
1027 # Yosemite is Darwin/14.x but patch versions are inconsistent in the Darwin string;
1028 # more accurately covered by CFNetwork regexes downstream
1029
1030 # IE on Mac doesn't specify version number
1031 - regex: 'Mac_PowerPC'
1032 os_replacement: 'Mac OS'
1033
1034 # builds before tiger don't seem to specify version?
1035
1036 # ios devices spoof (mac os x), so including intel/ppc prefixes
1037 - regex: '(?:PPC|Intel) (Mac OS X)'
1038
1039 # Box Drive and Box Sync on Mac OS X use OSX version numbers, not Darwin
1040 - regex: '^Box.*;(Darwin)/(10)\.(1\d)(?:\.(\d+))?'
1041 os_replacement: 'Mac OS X'
1042
1043 ##########
1044 # iOS
1045 # http://en.wikipedia.org/wiki/IOS_version_history
1046 ##########
1047 # keep this above generic iOS, since AppleTV UAs contain 'CPU OS'
1048 - regex: '(Apple\s?TV)(?:/(\d+)\.(\d+))?'
1049 os_replacement: 'ATV OS X'
1050
1051 - regex: '(CPU[ +]OS|iPhone[ +]OS|CPU[ +]iPhone|CPU IPhone OS)[ +]+(\d+)[_\.](\d+)(?:[_\.](\d+))?'
1052 os_replacement: 'iOS'
1053
1054 # remaining cases are mostly only opera uas, so catch opera as to not catch iphone spoofs
1055 - regex: '(iPhone|iPad|iPod); Opera'
1056 os_replacement: 'iOS'
1057
1058 # few more stragglers
1059 - regex: '(iPhone|iPad|iPod).*Mac OS X.*Version/(\d+)\.(\d+)'
1060 os_replacement: 'iOS'
1061
1062 # CFNetwork/Darwin - The specific CFNetwork or Darwin version determines
1063 # whether the os maps to Mac OS, or iOS, or just Darwin.
1064 # See: http://user-agents.me/cfnetwork-version-list
1065 - regex: '(CFNetwork)/(5)48\.0\.3.* Darwin/11\.0\.0'
1066 os_replacement: 'iOS'
1067 - regex: '(CFNetwork)/(5)48\.(0)\.4.* Darwin/(1)1\.0\.0'
1068 os_replacement: 'iOS'
1069 - regex: '(CFNetwork)/(5)48\.(1)\.4'
1070 os_replacement: 'iOS'
1071 - regex: '(CFNetwork)/(4)85\.1(3)\.9'
1072 os_replacement: 'iOS'
1073 - regex: '(CFNetwork)/(6)09\.(1)\.4'
1074 os_replacement: 'iOS'
1075 - regex: '(CFNetwork)/(6)(0)9'
1076 os_replacement: 'iOS'
1077 - regex: '(CFNetwork)/6(7)2\.(1)\.13'
1078 os_replacement: 'iOS'
1079 - regex: '(CFNetwork)/6(7)2\.(1)\.(1)4'
1080 os_replacement: 'iOS'
1081 - regex: '(CF)(Network)/6(7)(2)\.1\.15'
1082 os_replacement: 'iOS'
1083 os_v1_replacement: '7'
1084 os_v2_replacement: '1'
1085 - regex: '(CFNetwork)/6(7)2\.(0)\.(?:2|8)'
1086 os_replacement: 'iOS'
1087 - regex: '(CFNetwork)/709\.1'
1088 os_replacement: 'iOS'
1089 os_v1_replacement: '8'
1090 os_v2_replacement: '0.b5'
1091 - regex: '(CF)(Network)/711\.(\d)'
1092 os_replacement: 'iOS'
1093 os_v1_replacement: '8'
1094 - regex: '(CF)(Network)/(720)\.(\d)'
1095 os_replacement: 'Mac OS X'
1096 os_v1_replacement: '10'
1097 os_v2_replacement: '10'
1098 - regex: '(CF)(Network)/(760)\.(\d)'
1099 os_replacement: 'Mac OS X'
1100 os_v1_replacement: '10'
1101 os_v2_replacement: '11'
1102 - regex: 'CFNetwork/7.* Darwin/15\.4\.\d+'
1103 os_replacement: 'iOS'
1104 os_v1_replacement: '9'
1105 os_v2_replacement: '3'
1106 os_v3_replacement: '1'
1107 - regex: 'CFNetwork/7.* Darwin/15\.5\.\d+'
1108 os_replacement: 'iOS'
1109 os_v1_replacement: '9'
1110 os_v2_replacement: '3'
1111 os_v3_replacement: '2'
1112 - regex: 'CFNetwork/7.* Darwin/15\.6\.\d+'
1113 os_replacement: 'iOS'
1114 os_v1_replacement: '9'
1115 os_v2_replacement: '3'
1116 os_v3_replacement: '5'
1117 - regex: '(CF)(Network)/758\.(\d)'
1118 os_replacement: 'iOS'
1119 os_v1_replacement: '9'
1120 - regex: 'CFNetwork/808\.3 Darwin/16\.3\.\d+'
1121 os_replacement: 'iOS'
1122 os_v1_replacement: '10'
1123 os_v2_replacement: '2'
1124 os_v3_replacement: '1'
1125 - regex: '(CF)(Network)/808\.(\d)'
1126 os_replacement: 'iOS'
1127 os_v1_replacement: '10'
1128
1129 ##########
1130 # CFNetwork macOS Apps (must be before CFNetwork iOS Apps
1131 # @ref: https://en.wikipedia.org/wiki/Darwin_(operating_system)#Release_history
1132 ##########
1133 - regex: 'CFNetwork/.* Darwin/17\.\d+.*\(x86_64\)'
1134 os_replacement: 'Mac OS X'
1135 os_v1_replacement: '10'
1136 os_v2_replacement: '13'
1137 - regex: 'CFNetwork/.* Darwin/16\.\d+.*\(x86_64\)'
1138 os_replacement: 'Mac OS X'
1139 os_v1_replacement: '10'
1140 os_v2_replacement: '12'
1141 - regex: 'CFNetwork/8.* Darwin/15\.\d+.*\(x86_64\)'
1142 os_replacement: 'Mac OS X'
1143 os_v1_replacement: '10'
1144 os_v2_replacement: '11'
1145 ##########
1146 # CFNetwork iOS Apps
1147 # @ref: https://en.wikipedia.org/wiki/Darwin_(operating_system)#Release_history
1148 ##########
1149 - regex: 'CFNetwork/.* Darwin/(9)\.\d+'
1150 os_replacement: 'iOS'
1151 os_v1_replacement: '1'
1152 - regex: 'CFNetwork/.* Darwin/(10)\.\d+'
1153 os_replacement: 'iOS'
1154 os_v1_replacement: '4'
1155 - regex: 'CFNetwork/.* Darwin/(11)\.\d+'
1156 os_replacement: 'iOS'
1157 os_v1_replacement: '5'
1158 - regex: 'CFNetwork/.* Darwin/(13)\.\d+'
1159 os_replacement: 'iOS'
1160 os_v1_replacement: '6'
1161 - regex: 'CFNetwork/6.* Darwin/(14)\.\d+'
1162 os_replacement: 'iOS'
1163 os_v1_replacement: '7'
1164 - regex: 'CFNetwork/7.* Darwin/(14)\.\d+'
1165 os_replacement: 'iOS'
1166 os_v1_replacement: '8'
1167 os_v2_replacement: '0'
1168 - regex: 'CFNetwork/7.* Darwin/(15)\.\d+'
1169 os_replacement: 'iOS'
1170 os_v1_replacement: '9'
1171 os_v2_replacement: '0'
1172 - regex: 'CFNetwork/8.* Darwin/16\.5\.\d+'
1173 os_replacement: 'iOS'
1174 os_v1_replacement: '10'
1175 os_v2_replacement: '3'
1176 - regex: 'CFNetwork/8.* Darwin/16\.6\.\d+'
1177 os_replacement: 'iOS'
1178 os_v1_replacement: '10'
1179 os_v2_replacement: '3'
1180 os_v3_replacement: '2'
1181 - regex: 'CFNetwork/8.* Darwin/16\.7\.\d+'
1182 os_replacement: 'iOS'
1183 os_v1_replacement: '10'
1184 os_v2_replacement: '3'
1185 os_v3_replacement: '3'
1186 - regex: 'CFNetwork/8.* Darwin/(16)\.\d+'
1187 os_replacement: 'iOS'
1188 os_v1_replacement: '10'
1189 - regex: 'CFNetwork/8.* Darwin/17\.0\.\d+'
1190 os_replacement: 'iOS'
1191 os_v1_replacement: '11'
1192 os_v2_replacement: '0'
1193 - regex: 'CFNetwork/8.* Darwin/17\.2\.\d+'
1194 os_replacement: 'iOS'
1195 os_v1_replacement: '11'
1196 os_v2_replacement: '1'
1197 - regex: 'CFNetwork/8.* Darwin/17\.3\.\d+'
1198 os_replacement: 'iOS'
1199 os_v1_replacement: '11'
1200 os_v2_replacement: '2'
1201 - regex: 'CFNetwork/8.* Darwin/17\.4\.\d+'
1202 os_replacement: 'iOS'
1203 os_v1_replacement: '11'
1204 os_v2_replacement: '2'
1205 os_v3_replacement: '6'
1206 - regex: 'CFNetwork/8.* Darwin/17\.5\.\d+'
1207 os_replacement: 'iOS'
1208 os_v1_replacement: '11'
1209 os_v2_replacement: '3'
1210 - regex: 'CFNetwork/9.* Darwin/17\.6\.\d+'
1211 os_replacement: 'iOS'
1212 os_v1_replacement: '11'
1213 os_v2_replacement: '4'
1214 - regex: 'CFNetwork/9.* Darwin/17\.7\.\d+'
1215 os_replacement: 'iOS'
1216 os_v1_replacement: '11'
1217 os_v2_replacement: '4'
1218 os_v3_replacement: '1'
1219 - regex: 'CFNetwork/8.* Darwin/(17)\.\d+'
1220 os_replacement: 'iOS'
1221 os_v1_replacement: '11'
1222 - regex: 'CFNetwork/9.* Darwin/18\.0\.\d+'
1223 os_replacement: 'iOS'
1224 os_v1_replacement: '12'
1225 os_v2_replacement: '0'
1226 - regex: 'CFNetwork/9.* Darwin/(18)\.\d+'
1227 os_replacement: 'iOS'
1228 os_v1_replacement: '12'
1229 - regex: 'CFNetwork/.* Darwin/'
1230 os_replacement: 'iOS'
1231
1232 # iOS Apps
1233 - regex: '\b(iOS[ /]|iOS; |iPhone(?:/| v|[ _]OS[/,]|; | OS : |\d,\d/|\d,\d; )|iPad/)(\d{1,2})[_\.](\d{1,2})(?:[_\.](\d+))?'
1234 os_replacement: 'iOS'
1235 - regex: '\((iOS);'
1236
1237 ##########################
1238 # Outlook on iOS >= 2.62.0
1239 ##########################
1240 - regex: 'Outlook-(iOS)/\d+\.\d+\.prod\.iphone'
1241
1242 ##########
1243 # Apple TV
1244 ##########
1245 - regex: '(tvOS)/(\d+).(\d+)'
1246 os_replacement: 'tvOS'
1247
1248 ##########
1249 # Chrome OS
1250 # if version 0.0.0, probably this stuff:
1251 # http://code.google.com/p/chromium-os/issues/detail?id=11573
1252 # http://code.google.com/p/chromium-os/issues/detail?id=13790
1253 ##########
1254 - regex: '(CrOS) [a-z0-9_]+ (\d+)\.(\d+)(?:\.(\d+))?'
1255 os_replacement: 'Chrome OS'
1256
1257 ##########
1258 # Linux distros
1259 ##########
1260 - regex: '([Dd]ebian)'
1261 os_replacement: 'Debian'
1262 - regex: '(Linux Mint)(?:/(\d+))?'
1263 - regex: '(Mandriva)(?: Linux)?/(?:[\d.-]+m[a-z]{2}(\d+).(\d))?'
1264
1265 ##########
1266 # Symbian + Symbian OS
1267 # http://en.wikipedia.org/wiki/History_of_Symbian
1268 ##########
1269 - regex: '(Symbian[Oo][Ss])[/ ](\d+)\.(\d+)'
1270 os_replacement: 'Symbian OS'
1271 - regex: '(Symbian/3).+NokiaBrowser/7\.3'
1272 os_replacement: 'Symbian^3 Anna'
1273 - regex: '(Symbian/3).+NokiaBrowser/7\.4'
1274 os_replacement: 'Symbian^3 Belle'
1275 - regex: '(Symbian/3)'
1276 os_replacement: 'Symbian^3'
1277 - regex: '\b(Series 60|SymbOS|S60Version|S60V\d|S60\b)'
1278 os_replacement: 'Symbian OS'
1279 - regex: '(MeeGo)'
1280 - regex: 'Symbian [Oo][Ss]'
1281 os_replacement: 'Symbian OS'
1282 - regex: 'Series40;'
1283 os_replacement: 'Nokia Series 40'
1284 - regex: 'Series30Plus;'
1285 os_replacement: 'Nokia Series 30 Plus'
1286
1287 ##########
1288 # BlackBerry devices
1289 ##########
1290 - regex: '(BB10);.+Version/(\d+)\.(\d+)\.(\d+)'
1291 os_replacement: 'BlackBerry OS'
1292 - regex: '(Black[Bb]erry)[0-9a-z]+/(\d+)\.(\d+)\.(\d+)(?:\.(\d+))?'
1293 os_replacement: 'BlackBerry OS'
1294 - regex: '(Black[Bb]erry).+Version/(\d+)\.(\d+)\.(\d+)(?:\.(\d+))?'
1295 os_replacement: 'BlackBerry OS'
1296 - regex: '(RIM Tablet OS) (\d+)\.(\d+)\.(\d+)'
1297 os_replacement: 'BlackBerry Tablet OS'
1298 - regex: '(Play[Bb]ook)'
1299 os_replacement: 'BlackBerry Tablet OS'
1300 - regex: '(Black[Bb]erry)'
1301 os_replacement: 'BlackBerry OS'
1302
1303 ##########
1304 # Firefox OS
1305 ##########
1306 - regex: '\((?:Mobile|Tablet);.+Gecko/18.0 Firefox/\d+\.\d+'
1307 os_replacement: 'Firefox OS'
1308 os_v1_replacement: '1'
1309 os_v2_replacement: '0'
1310 os_v3_replacement: '1'
1311
1312 - regex: '\((?:Mobile|Tablet);.+Gecko/18.1 Firefox/\d+\.\d+'
1313 os_replacement: 'Firefox OS'
1314 os_v1_replacement: '1'
1315 os_v2_replacement: '1'
1316
1317 - regex: '\((?:Mobile|Tablet);.+Gecko/26.0 Firefox/\d+\.\d+'
1318 os_replacement: 'Firefox OS'
1319 os_v1_replacement: '1'
1320 os_v2_replacement: '2'
1321
1322 - regex: '\((?:Mobile|Tablet);.+Gecko/28.0 Firefox/\d+\.\d+'
1323 os_replacement: 'Firefox OS'
1324 os_v1_replacement: '1'
1325 os_v2_replacement: '3'
1326
1327 - regex: '\((?:Mobile|Tablet);.+Gecko/30.0 Firefox/\d+\.\d+'
1328 os_replacement: 'Firefox OS'
1329 os_v1_replacement: '1'
1330 os_v2_replacement: '4'
1331
1332 - regex: '\((?:Mobile|Tablet);.+Gecko/32.0 Firefox/\d+\.\d+'
1333 os_replacement: 'Firefox OS'
1334 os_v1_replacement: '2'
1335 os_v2_replacement: '0'
1336
1337 - regex: '\((?:Mobile|Tablet);.+Gecko/34.0 Firefox/\d+\.\d+'
1338 os_replacement: 'Firefox OS'
1339 os_v1_replacement: '2'
1340 os_v2_replacement: '1'
1341
1342 # Firefox OS Generic
1343 - regex: '\((?:Mobile|Tablet);.+Firefox/\d+\.\d+'
1344 os_replacement: 'Firefox OS'
1345
1346
1347 ##########
1348 # BREW
1349 # yes, Brew is lower-cased for Brew MP
1350 ##########
1351 - regex: '(BREW)[ /](\d+)\.(\d+)\.(\d+)'
1352 - regex: '(BREW);'
1353 - regex: '(Brew MP|BMP)[ /](\d+)\.(\d+)\.(\d+)'
1354 os_replacement: 'Brew MP'
1355 - regex: 'BMP;'
1356 os_replacement: 'Brew MP'
1357
1358 ##########
1359 # Google TV
1360 ##########
1361 - regex: '(GoogleTV)(?: (\d+)\.(\d+)(?:\.(\d+))?|/[\da-z]+)'
1362
1363 - regex: '(WebTV)/(\d+).(\d+)'
1364
1365 ##########
1366 # Chromecast
1367 ##########
1368 - regex: '(CrKey)(?:[/](\d+)\.(\d+)(?:\.(\d+))?)?'
1369 os_replacement: 'Chromecast'
1370
1371 ##########
1372 # Misc mobile
1373 ##########
1374 - regex: '(hpw|web)OS/(\d+)\.(\d+)(?:\.(\d+))?'
1375 os_replacement: 'webOS'
1376 - regex: '(VRE);'
1377
1378 ##########
1379 # Generic patterns
1380 # since the majority of os cases are very specific, these go last
1381 ##########
1382 - regex: '(Fedora|Red Hat|PCLinuxOS|Puppy|Ubuntu|Kindle|Bada|Lubuntu|BackTrack|Slackware|(?:Free|Open|Net|\b)BSD)[/ ](\d+)\.(\d+)(?:\.(\d+)(?:\.(\d+))?)?'
1383
1384 # Gentoo Linux + Kernel Version
1385 - regex: '(Linux)[ /](\d+)\.(\d+)(?:\.(\d+))?.*gentoo'
1386 os_replacement: 'Gentoo'
1387
1388 # Opera Mini Bada
1389 - regex: '\((Bada);'
1390
1391 # just os
1392 - regex: '(Windows|Android|WeTab|Maemo|Web0S)'
1393 - regex: '(Ubuntu|Kubuntu|Arch Linux|CentOS|Slackware|Gentoo|openSUSE|SUSE|Red Hat|Fedora|PCLinuxOS|Mageia|(?:Free|Open|Net|\b)BSD)'
1394 # Linux + Kernel Version
1395 - regex: '(Linux)(?:[ /](\d+)\.(\d+)(?:\.(\d+))?)?'
1396 - regex: 'SunOS'
1397 os_replacement: 'Solaris'
1398 # Wget/x.x.x (linux-gnu)
1399 - regex: '\(linux-gnu\)'
1400 os_replacement: 'Linux'
1401 - regex: '\(x86_64-redhat-linux-gnu\)'
1402 os_replacement: 'Red Hat'
1403 - regex: '\((freebsd)(\d+)\.(\d+)\)'
1404 os_replacement: 'FreeBSD'
1405
1406 # Roku Digital-Video-Players https://www.roku.com/
1407 - regex: '^(Roku)/DVP-(\d+)\.(\d+)'
1408
1409 device_parsers:
1410
1411 #########
1412 # Mobile Spiders
1413 # Catch the mobile crawler before checking for iPhones / Androids.
1414 #########
1415 - regex: '(?:(?:iPhone|Windows CE|Windows Phone|Android).*(?:(?:Bot|Yeti)-Mobile|YRSpider|BingPreview|bots?/\d|(?:bot|spider)\.html)|AdsBot-Google-Mobile.*iPhone)'
1416 regex_flag: 'i'
1417 device_replacement: 'Spider'
1418 brand_replacement: 'Spider'
1419 model_replacement: 'Smartphone'
1420 - regex: '(?:DoCoMo|\bMOT\b|\bLG\b|Nokia|Samsung|SonyEricsson).*(?:(?:Bot|Yeti)-Mobile|bots?/\d|(?:bot|crawler)\.html|(?:jump|google|Wukong)bot|ichiro/mobile|/spider|YahooSeeker)'
1421 regex_flag: 'i'
1422 device_replacement: 'Spider'
1423 brand_replacement: 'Spider'
1424 model_replacement: 'Feature Phone'
1425
1426 #########
1427 # WebBrowser for SmartWatch
1428 # @ref: https://play.google.com/store/apps/details?id=se.vaggan.webbrowser&hl=en
1429 #########
1430 - regex: '\bSmartWatch *\( *([^;]+) *; *([^;]+) *;'
1431 device_replacement: '$1 $2'
1432 brand_replacement: '$1'
1433 model_replacement: '$2'
1434
1435 ######################################################################
1436 # Android parsers
1437 #
1438 # @ref: https://support.google.com/googleplay/answer/1727131?hl=en
1439 ######################################################################
1440
1441 # Android Application
1442 - regex: 'Android Application[^\-]+ - (Sony) ?(Ericsson)? (.+) \w+ - '
1443 device_replacement: '$1 $2'
1444 brand_replacement: '$1$2'
1445 model_replacement: '$3'
1446 - regex: 'Android Application[^\-]+ - (?:HTC|HUAWEI|LGE|LENOVO|MEDION|TCT) (HTC|HUAWEI|LG|LENOVO|MEDION|ALCATEL)[ _\-](.+) \w+ - '
1447 regex_flag: 'i'
1448 device_replacement: '$1 $2'
1449 brand_replacement: '$1'
1450 model_replacement: '$2'
1451 - regex: 'Android Application[^\-]+ - ([^ ]+) (.+) \w+ - '
1452 device_replacement: '$1 $2'
1453 brand_replacement: '$1'
1454 model_replacement: '$2'
1455
1456 #########
1457 # 3Q
1458 # @ref: http://www.3q-int.com/
1459 #########
1460 - regex: '; *([BLRQ]C\d{4}[A-Z]+) +Build/'
1461 device_replacement: '3Q $1'
1462 brand_replacement: '3Q'
1463 model_replacement: '$1'
1464 - regex: '; *(?:3Q_)([^;/]+) +Build'
1465 device_replacement: '3Q $1'
1466 brand_replacement: '3Q'
1467 model_replacement: '$1'
1468
1469 #########
1470 # Acer
1471 # @ref: http://us.acer.com/ac/en/US/content/group/tablets
1472 #########
1473 - regex: 'Android [34].*; *(A100|A101|A110|A200|A210|A211|A500|A501|A510|A511|A700(?: Lite| 3G)?|A701|B1-A71|A1-\d{3}|B1-\d{3}|V360|V370|W500|W500P|W501|W501P|W510|W511|W700|Slider SL101|DA22[^;/]+) Build'
1474 device_replacement: '$1'
1475 brand_replacement: 'Acer'
1476 model_replacement: '$1'
1477 - regex: '; *Acer Iconia Tab ([^;/]+) Build'
1478 device_replacement: '$1'
1479 brand_replacement: 'Acer'
1480 model_replacement: '$1'
1481 - regex: '; *(Z1[1235]0|E320[^/]*|S500|S510|Liquid[^;/]*|Iconia A\d+) Build'
1482 device_replacement: '$1'
1483 brand_replacement: 'Acer'
1484 model_replacement: '$1'
1485 - regex: '; *(Acer |ACER )([^;/]+) Build'
1486 device_replacement: '$1$2'
1487 brand_replacement: 'Acer'
1488 model_replacement: '$2'
1489
1490 #########
1491 # Advent
1492 # @ref: https://en.wikipedia.org/wiki/Advent_Vega
1493 # @note: VegaBean and VegaComb (names derived from jellybean, honeycomb) are
1494 # custom ROM builds for Vega
1495 #########
1496 - regex: '; *(Advent )?(Vega(?:Bean|Comb)?).* Build'
1497 device_replacement: '$1$2'
1498 brand_replacement: 'Advent'
1499 model_replacement: '$2'
1500
1501 #########
1502 # Ainol
1503 # @ref: http://www.ainol.com/plugin.php?identifier=ainol&module=product
1504 #########
1505 - regex: '; *(Ainol )?((?:NOVO|[Nn]ovo)[^;/]+) Build'
1506 device_replacement: '$1$2'
1507 brand_replacement: 'Ainol'
1508 model_replacement: '$2'
1509
1510 #########
1511 # Airis
1512 # @ref: http://airis.es/Tienda/Default.aspx?idG=001
1513 #########
1514 - regex: '; *AIRIS[ _\-]?([^/;\)]+) *(?:;|\)|Build)'
1515 regex_flag: 'i'
1516 device_replacement: '$1'
1517 brand_replacement: 'Airis'
1518 model_replacement: '$1'
1519 - regex: '; *(OnePAD[^;/]+) Build'
1520 regex_flag: 'i'
1521 device_replacement: '$1'
1522 brand_replacement: 'Airis'
1523 model_replacement: '$1'
1524
1525 #########
1526 # Airpad
1527 # @ref: ??
1528 #########
1529 - regex: '; *Airpad[ \-]([^;/]+) Build'
1530 device_replacement: 'Airpad $1'
1531 brand_replacement: 'Airpad'
1532 model_replacement: '$1'
1533
1534 #########
1535 # Alcatel - TCT
1536 # @ref: http://www.alcatelonetouch.com/global-en/products/smartphones.html
1537 #########
1538 - regex: '; *(one ?touch) (EVO7|T10|T20) Build'
1539 device_replacement: 'Alcatel One Touch $2'
1540 brand_replacement: 'Alcatel'
1541 model_replacement: 'One Touch $2'
1542 - regex: '; *(?:alcatel[ _])?(?:(?:one[ _]?touch[ _])|ot[ \-])([^;/]+);? Build'
1543 regex_flag: 'i'
1544 device_replacement: 'Alcatel One Touch $1'
1545 brand_replacement: 'Alcatel'
1546 model_replacement: 'One Touch $1'
1547 - regex: '; *(TCL)[ _]([^;/]+) Build'
1548 device_replacement: '$1 $2'
1549 brand_replacement: '$1'
1550 model_replacement: '$2'
1551 # operator specific models
1552 - regex: '; *(Vodafone Smart II|Optimus_Madrid) Build'
1553 device_replacement: 'Alcatel $1'
1554 brand_replacement: 'Alcatel'
1555 model_replacement: '$1'
1556 - regex: '; *BASE_Lutea_3 Build'
1557 device_replacement: 'Alcatel One Touch 998'
1558 brand_replacement: 'Alcatel'
1559 model_replacement: 'One Touch 998'
1560 - regex: '; *BASE_Varia Build'
1561 device_replacement: 'Alcatel One Touch 918D'
1562 brand_replacement: 'Alcatel'
1563 model_replacement: 'One Touch 918D'
1564
1565 #########
1566 # Allfine
1567 # @ref: http://www.myallfine.com/Products.asp
1568 #########
1569 - regex: '; *((?:FINE|Fine)\d[^;/]+) Build'
1570 device_replacement: '$1'
1571 brand_replacement: 'Allfine'
1572 model_replacement: '$1'
1573
1574 #########
1575 # Allview
1576 # @ref: http://www.allview.ro/produse/droseries/lista-tablete-pc/
1577 #########
1578 - regex: '; *(ALLVIEW[ _]?|Allview[ _]?)((?:Speed|SPEED).*) Build/'
1579 device_replacement: '$1$2'
1580 brand_replacement: 'Allview'
1581 model_replacement: '$2'
1582 - regex: '; *(ALLVIEW[ _]?|Allview[ _]?)?(AX1_Shine|AX2_Frenzy) Build'
1583 device_replacement: '$1$2'
1584 brand_replacement: 'Allview'
1585 model_replacement: '$2'
1586 - regex: '; *(ALLVIEW[ _]?|Allview[ _]?)([^;/]*) Build'
1587 device_replacement: '$1$2'
1588 brand_replacement: 'Allview'
1589 model_replacement: '$2'
1590
1591 #########
1592 # Allwinner
1593 # @ref: http://www.allwinner.com/
1594 # @models: A31 (13.3"),A20,A10,
1595 #########
1596 - regex: '; *(A13-MID) Build'
1597 device_replacement: '$1'
1598 brand_replacement: 'Allwinner'
1599 model_replacement: '$1'
1600 - regex: '; *(Allwinner)[ _\-]?([^;/]+) Build'
1601 device_replacement: '$1 $2'
1602 brand_replacement: 'Allwinner'
1603 model_replacement: '$1'
1604
1605 #########
1606 # Amaway
1607 # @ref: http://www.amaway.cn/
1608 #########
1609 - regex: '; *(A651|A701B?|A702|A703|A705|A706|A707|A711|A712|A713|A717|A722|A785|A801|A802|A803|A901|A902|A1002|A1003|A1006|A1007|A9701|A9703|Q710|Q80) Build'
1610 device_replacement: '$1'
1611 brand_replacement: 'Amaway'
1612 model_replacement: '$1'
1613
1614 #########
1615 # Amoi
1616 # @ref: http://www.amoi.com/en/prd/prd_index.jspx
1617 #########
1618 - regex: '; *(?:AMOI|Amoi)[ _]([^;/]+) Build'
1619 device_replacement: 'Amoi $1'
1620 brand_replacement: 'Amoi'
1621 model_replacement: '$1'
1622 - regex: '^(?:AMOI|Amoi)[ _]([^;/]+) Linux'
1623 device_replacement: 'Amoi $1'
1624 brand_replacement: 'Amoi'
1625 model_replacement: '$1'
1626
1627 #########
1628 # Aoc
1629 # @ref: http://latin.aoc.com/media_tablet
1630 #########
1631 - regex: '; *(MW(?:0[789]|10)[^;/]+) Build'
1632 device_replacement: '$1'
1633 brand_replacement: 'Aoc'
1634 model_replacement: '$1'
1635
1636 #########
1637 # Aoson
1638 # @ref: http://www.luckystar.com.cn/en/mid.aspx?page=1
1639 # @ref: http://www.luckystar.com.cn/en/mobiletel.aspx?page=1
1640 # @note: brand owned by luckystar
1641 #########
1642 - regex: '; *(G7|M1013|M1015G|M11[CG]?|M-?12[B]?|M15|M19[G]?|M30[ACQ]?|M31[GQ]|M32|M33[GQ]|M36|M37|M38|M701T|M710|M712B|M713|M715G|M716G|M71(?:G|GS|T)?|M72[T]?|M73[T]?|M75[GT]?|M77G|M79T|M7L|M7LN|M81|M810|M81T|M82|M92|M92KS|M92S|M717G|M721|M722G|M723|M725G|M739|M785|M791|M92SK|M93D) Build'
1643 device_replacement: 'Aoson $1'
1644 brand_replacement: 'Aoson'
1645 model_replacement: '$1'
1646 - regex: '; *Aoson ([^;/]+) Build'
1647 regex_flag: 'i'
1648 device_replacement: 'Aoson $1'
1649 brand_replacement: 'Aoson'
1650 model_replacement: '$1'
1651
1652 #########
1653 # Apanda
1654 # @ref: http://www.apanda.com.cn/
1655 #########
1656 - regex: '; *[Aa]panda[ _\-]([^;/]+) Build'
1657 device_replacement: 'Apanda $1'
1658 brand_replacement: 'Apanda'
1659 model_replacement: '$1'
1660
1661 #########
1662 # Archos
1663 # @ref: http://www.archos.com/de/products/tablets.html
1664 # @ref: http://www.archos.com/de/products/smartphones/index.html
1665 #########
1666 - regex: '; *(?:ARCHOS|Archos) ?(GAMEPAD.*?)(?: Build|[;/\(\)\-])'
1667 device_replacement: 'Archos $1'
1668 brand_replacement: 'Archos'
1669 model_replacement: '$1'
1670 - regex: 'ARCHOS; GOGI; ([^;]+);'
1671 device_replacement: 'Archos $1'
1672 brand_replacement: 'Archos'
1673 model_replacement: '$1'
1674 - regex: '(?:ARCHOS|Archos)[ _]?(.*?)(?: Build|[;/\(\)\-]|$)'
1675 device_replacement: 'Archos $1'
1676 brand_replacement: 'Archos'
1677 model_replacement: '$1'
1678 - regex: '; *(AN(?:7|8|9|10|13)[A-Z0-9]{1,4}) Build'
1679 device_replacement: 'Archos $1'
1680 brand_replacement: 'Archos'
1681 model_replacement: '$1'
1682 - regex: '; *(A28|A32|A43|A70(?:BHT|CHT|HB|S|X)|A101(?:B|C|IT)|A7EB|A7EB-WK|101G9|80G9) Build'
1683 device_replacement: 'Archos $1'
1684 brand_replacement: 'Archos'
1685 model_replacement: '$1'
1686
1687 #########
1688 # A-rival
1689 # @ref: http://www.a-rival.de/de/
1690 #########
1691 - regex: '; *(PAD-FMD[^;/]+) Build'
1692 device_replacement: '$1'
1693 brand_replacement: 'Arival'
1694 model_replacement: '$1'
1695 - regex: '; *(BioniQ) ?([^;/]+) Build'
1696 device_replacement: '$1 $2'
1697 brand_replacement: 'Arival'
1698 model_replacement: '$1 $2'
1699
1700 #########
1701 # Arnova
1702 # @ref: http://arnovatech.com/
1703 #########
1704 - regex: '; *(AN\d[^;/]+|ARCHM\d+) Build'
1705 device_replacement: 'Arnova $1'
1706 brand_replacement: 'Arnova'
1707 model_replacement: '$1'
1708 - regex: '; *(?:ARNOVA|Arnova) ?([^;/]+) Build'
1709 device_replacement: 'Arnova $1'
1710 brand_replacement: 'Arnova'
1711 model_replacement: '$1'
1712
1713 #########
1714 # Assistant
1715 # @ref: http://www.assistant.ua
1716 #########
1717 - regex: '; *(?:ASSISTANT )?(AP)-?([1789]\d{2}[A-Z]{0,2}|80104) Build'
1718 device_replacement: 'Assistant $1-$2'
1719 brand_replacement: 'Assistant'
1720 model_replacement: '$1-$2'
1721
1722 #########
1723 # Asus
1724 # @ref: http://www.asus.com/uk/Tablets_Mobile/
1725 #########
1726 - regex: '; *(ME17\d[^;/]*|ME3\d{2}[^;/]+|K00[A-Z]|Nexus 10|Nexus 7(?: 2013)?|PadFone[^;/]*|Transformer[^;/]*|TF\d{3}[^;/]*|eeepc) Build'
1727 device_replacement: 'Asus $1'
1728 brand_replacement: 'Asus'
1729 model_replacement: '$1'
1730 - regex: '; *ASUS[ _]*([^;/]+) Build'
1731 device_replacement: 'Asus $1'
1732 brand_replacement: 'Asus'
1733 model_replacement: '$1'
1734
1735 #########
1736 # Garmin-Asus
1737 #########
1738 - regex: '; *Garmin-Asus ([^;/]+) Build'
1739 device_replacement: 'Garmin-Asus $1'
1740 brand_replacement: 'Garmin-Asus'
1741 model_replacement: '$1'
1742 - regex: '; *(Garminfone) Build'
1743 device_replacement: 'Garmin $1'
1744 brand_replacement: 'Garmin-Asus'
1745 model_replacement: '$1'
1746
1747 #########
1748 # Attab
1749 # @ref: http://www.theattab.com/
1750 #########
1751 - regex: '; (@TAB-[^;/]+) Build'
1752 device_replacement: '$1'
1753 brand_replacement: 'Attab'
1754 model_replacement: '$1'
1755
1756 #########
1757 # Audiosonic
1758 # @ref: ??
1759 # @note: Take care with Docomo T-01 Toshiba
1760 #########
1761 - regex: '; *(T-(?:07|[^0]\d)[^;/]+) Build'
1762 device_replacement: '$1'
1763 brand_replacement: 'Audiosonic'
1764 model_replacement: '$1'
1765
1766 #########
1767 # Axioo
1768 # @ref: http://www.axiooworld.com/ww/index.php
1769 #########
1770 - regex: '; *(?:Axioo[ _\-]([^;/]+)|(picopad)[ _\-]([^;/]+)) Build'
1771 regex_flag: 'i'
1772 device_replacement: 'Axioo $1$2 $3'
1773 brand_replacement: 'Axioo'
1774 model_replacement: '$1$2 $3'
1775
1776 #########
1777 # Azend
1778 # @ref: http://azendcorp.com/index.php/products/portable-electronics
1779 #########
1780 - regex: '; *(V(?:100|700|800)[^;/]*) Build'
1781 device_replacement: '$1'
1782 brand_replacement: 'Azend'
1783 model_replacement: '$1'
1784
1785 #########
1786 # Bak
1787 # @ref: http://www.bakinternational.com/produtos.php?cat=80
1788 #########
1789 - regex: '; *(IBAK\-[^;/]*) Build'
1790 regex_flag: 'i'
1791 device_replacement: '$1'
1792 brand_replacement: 'Bak'
1793 model_replacement: '$1'
1794
1795 #########
1796 # Bedove
1797 # @ref: http://www.bedove.com/product.html
1798 # @models: HY6501|HY5001|X12|X21|I5
1799 #########
1800 - regex: '; *(HY5001|HY6501|X12|X21|I5) Build'
1801 device_replacement: 'Bedove $1'
1802 brand_replacement: 'Bedove'
1803 model_replacement: '$1'
1804
1805 #########
1806 # Benss
1807 # @ref: http://www.benss.net/
1808 #########
1809 - regex: '; *(JC-[^;/]*) Build'
1810 device_replacement: 'Benss $1'
1811 brand_replacement: 'Benss'
1812 model_replacement: '$1'
1813
1814 #########
1815 # Blackberry
1816 # @ref: http://uk.blackberry.com/
1817 # @note: Android Apps seams to be used here
1818 #########
1819 - regex: '; *(BB) ([^;/]+) Build'
1820 device_replacement: '$1 $2'
1821 brand_replacement: 'Blackberry'
1822 model_replacement: '$2'
1823
1824 #########
1825 # Blackbird
1826 # @ref: http://iblackbird.co.kr
1827 #########
1828 - regex: '; *(BlackBird)[ _](I8.*) Build'
1829 device_replacement: '$1 $2'
1830 brand_replacement: '$1'
1831 model_replacement: '$2'
1832 - regex: '; *(BlackBird)[ _](.*) Build'
1833 device_replacement: '$1 $2'
1834 brand_replacement: '$1'
1835 model_replacement: '$2'
1836
1837 #########
1838 # Blaupunkt
1839 # @ref: http://www.blaupunkt.com
1840 #########
1841 # Endeavour
1842 - regex: '; *([0-9]+BP[EM][^;/]*|Endeavour[^;/]+) Build'
1843 device_replacement: 'Blaupunkt $1'
1844 brand_replacement: 'Blaupunkt'
1845 model_replacement: '$1'
1846
1847 #########
1848 # Blu
1849 # @ref: http://bluproducts.com
1850 #########
1851 - regex: '; *((?:BLU|Blu)[ _\-])([^;/]+) Build'
1852 device_replacement: '$1$2'
1853 brand_replacement: 'Blu'
1854 model_replacement: '$2'
1855 # BMOBILE = operator branded device
1856 - regex: '; *(?:BMOBILE )?(Blu|BLU|DASH [^;/]+|VIVO 4\.3|TANK 4\.5) Build'
1857 device_replacement: '$1'
1858 brand_replacement: 'Blu'
1859 model_replacement: '$1'
1860
1861 #########
1862 # Blusens
1863 # @ref: http://www.blusens.com/es/?sg=1&sv=al&roc=1
1864 #########
1865 # tablet
1866 - regex: '; *(TOUCH\d[^;/]+) Build'
1867 device_replacement: '$1'
1868 brand_replacement: 'Blusens'
1869 model_replacement: '$1'
1870
1871 #########
1872 # Bmobile
1873 # @ref: http://bmobile.eu.com/?categoria=smartphones-2
1874 # @note: Might collide with Maxx as AX is used also there.
1875 #########
1876 # smartphone
1877 - regex: '; *(AX5\d+) Build'
1878 device_replacement: '$1'
1879 brand_replacement: 'Bmobile'
1880 model_replacement: '$1'
1881
1882 #########
1883 # bq
1884 # @ref: http://bqreaders.com
1885 #########
1886 - regex: '; *([Bb]q) ([^;/]+);? Build'
1887 device_replacement: '$1 $2'
1888 brand_replacement: 'bq'
1889 model_replacement: '$2'
1890 - regex: '; *(Maxwell [^;/]+) Build'
1891 device_replacement: '$1'
1892 brand_replacement: 'bq'
1893 model_replacement: '$1'
1894
1895 #########
1896 # Braun Phototechnik
1897 # @ref: http://www.braun-phototechnik.de/en/products/list/~pcat.250/Tablet-PC.html
1898 #########
1899 - regex: '; *((?:B-Tab|B-TAB) ?\d[^;/]+) Build'
1900 device_replacement: '$1'
1901 brand_replacement: 'Braun'
1902 model_replacement: '$1'
1903
1904 #########
1905 # Broncho
1906 # @ref: http://www.broncho.cn/
1907 #########
1908 - regex: '; *(Broncho) ([^;/]+) Build'
1909 device_replacement: '$1 $2'
1910 brand_replacement: '$1'
1911 model_replacement: '$2'
1912
1913 #########
1914 # Captiva
1915 # @ref: http://www.captiva-power.de
1916 #########
1917 - regex: '; *CAPTIVA ([^;/]+) Build'
1918 device_replacement: 'Captiva $1'
1919 brand_replacement: 'Captiva'
1920 model_replacement: '$1'
1921
1922 #########
1923 # Casio
1924 # @ref: http://www.casiogzone.com/
1925 #########
1926 - regex: '; *(C771|CAL21|IS11CA) Build'
1927 device_replacement: '$1'
1928 brand_replacement: 'Casio'
1929 model_replacement: '$1'
1930
1931 #########
1932 # Cat
1933 # @ref: http://www.cat-sound.com
1934 #########
1935 - regex: '; *(?:Cat|CAT) ([^;/]+) Build'
1936 device_replacement: 'Cat $1'
1937 brand_replacement: 'Cat'
1938 model_replacement: '$1'
1939 - regex: '; *(?:Cat)(Nova.*) Build'
1940 device_replacement: 'Cat $1'
1941 brand_replacement: 'Cat'
1942 model_replacement: '$1'
1943 - regex: '; *(INM8002KP|ADM8000KP_[AB]) Build'
1944 device_replacement: '$1'
1945 brand_replacement: 'Cat'
1946 model_replacement: 'Tablet PHOENIX 8.1J0'
1947
1948 #########
1949 # Celkon
1950 # @ref: http://www.celkonmobiles.com/?_a=products
1951 # @models: A10, A19Q, A101, A105, A107, A107\+, A112, A118, A119, A119Q, A15, A19, A20, A200, A220, A225, A22 Race, A27, A58, A59, A60, A62, A63, A64, A66, A67, A69, A75, A77, A79, A8\+, A83, A85, A86, A87, A89 Ultima, A9\+, A90, A900, A95, A97i, A98, AR 40, AR 45, AR 50, ML5
1952 #########
1953 - regex: '; *(?:[Cc]elkon[ _\*]|CELKON[ _\*])([^;/\)]+) ?(?:Build|;|\))'
1954 device_replacement: '$1'
1955 brand_replacement: 'Celkon'
1956 model_replacement: '$1'
1957 - regex: 'Build/(?:[Cc]elkon)+_?([^;/_\)]+)'
1958 device_replacement: '$1'
1959 brand_replacement: 'Celkon'
1960 model_replacement: '$1'
1961 - regex: '; *(CT)-?(\d+) Build'
1962 device_replacement: '$1$2'
1963 brand_replacement: 'Celkon'
1964 model_replacement: '$1$2'
1965 # smartphones
1966 - regex: '; *(A19|A19Q|A105|A107[^;/\)]*) ?(?:Build|;|\))'
1967 device_replacement: '$1'
1968 brand_replacement: 'Celkon'
1969 model_replacement: '$1'
1970
1971 #########
1972 # ChangJia
1973 # @ref: http://www.cjshowroom.com/eproducts.aspx?classcode=004001001
1974 # @brief: China manufacturer makes tablets for different small brands
1975 # (eg. http://www.zeepad.net/index.html)
1976 #########
1977 - regex: '; *(TPC[0-9]{4,5}) Build'
1978 device_replacement: '$1'
1979 brand_replacement: 'ChangJia'
1980 model_replacement: '$1'
1981
1982 #########
1983 # Cloudfone
1984 # @ref: http://www.cloudfonemobile.com/
1985 #########
1986 - regex: '; *(Cloudfone)[ _](Excite)([^ ][^;/]+) Build'
1987 device_replacement: '$1 $2 $3'
1988 brand_replacement: 'Cloudfone'
1989 model_replacement: '$1 $2 $3'
1990 - regex: '; *(Excite|ICE)[ _](\d+[^;/]+) Build'
1991 device_replacement: 'Cloudfone $1 $2'
1992 brand_replacement: 'Cloudfone'
1993 model_replacement: 'Cloudfone $1 $2'
1994 - regex: '; *(Cloudfone|CloudPad)[ _]([^;/]+) Build'
1995 device_replacement: '$1 $2'
1996 brand_replacement: 'Cloudfone'
1997 model_replacement: '$1 $2'
1998
1999 #########
2000 # Cmx
2001 # @ref: http://cmx.at/de/
2002 #########
2003 - regex: '; *((?:Aquila|Clanga|Rapax)[^;/]+) Build'
2004 regex_flag: 'i'
2005 device_replacement: '$1'
2006 brand_replacement: 'Cmx'
2007 model_replacement: '$1'
2008
2009 #########
2010 # CobyKyros
2011 # @ref: http://cobykyros.com
2012 # @note: Be careful with MID\d{3} from MpMan or Manta
2013 #########
2014 - regex: '; *(?:CFW-|Kyros )?(MID[0-9]{4}(?:[ABC]|SR|TV)?)(\(3G\)-4G| GB 8K| 3G| 8K| GB)? *(?:Build|[;\)])'
2015 device_replacement: 'CobyKyros $1$2'
2016 brand_replacement: 'CobyKyros'
2017 model_replacement: '$1$2'
2018
2019 #########
2020 # Coolpad
2021 # @ref: ??
2022 #########
2023 - regex: '; *([^;/]*)Coolpad[ _]([^;/]+) Build'
2024 device_replacement: '$1$2'
2025 brand_replacement: 'Coolpad'
2026 model_replacement: '$1$2'
2027
2028 #########
2029 # Cube
2030 # @ref: http://www.cube-tablet.com/buy-products.html
2031 #########
2032 - regex: '; *(CUBE[ _])?([KU][0-9]+ ?GT.*|A5300) Build'
2033 regex_flag: 'i'
2034 device_replacement: '$1$2'
2035 brand_replacement: 'Cube'
2036 model_replacement: '$2'
2037
2038 #########
2039 # Cubot
2040 # @ref: http://www.cubotmall.com/
2041 #########
2042 - regex: '; *CUBOT ([^;/]+) Build'
2043 regex_flag: 'i'
2044 device_replacement: '$1'
2045 brand_replacement: 'Cubot'
2046 model_replacement: '$1'
2047 - regex: '; *(BOBBY) Build'
2048 regex_flag: 'i'
2049 device_replacement: '$1'
2050 brand_replacement: 'Cubot'
2051 model_replacement: '$1'
2052
2053 #########
2054 # Danew
2055 # @ref: http://www.danew.com/produits-tablette.php
2056 #########
2057 - regex: '; *(Dslide [^;/]+) Build'
2058 device_replacement: '$1'
2059 brand_replacement: 'Danew'
2060 model_replacement: '$1'
2061
2062 #########
2063 # Dell
2064 # @ref: http://www.dell.com
2065 # @ref: http://www.softbank.jp/mobile/support/product/101dl/
2066 # @ref: http://www.softbank.jp/mobile/support/product/001dl/
2067 # @ref: http://developer.emnet.ne.jp/android.html
2068 # @ref: http://www.dell.com/in/p/mobile-xcd28/pd
2069 # @ref: http://www.dell.com/in/p/mobile-xcd35/pd
2070 #########
2071 - regex: '; *(XCD)[ _]?(28|35) Build'
2072 device_replacement: 'Dell $1$2'
2073 brand_replacement: 'Dell'
2074 model_replacement: '$1$2'
2075 - regex: '; *(001DL) Build'
2076 device_replacement: 'Dell $1'
2077 brand_replacement: 'Dell'
2078 model_replacement: 'Streak'
2079 - regex: '; *(?:Dell|DELL) (Streak) Build'
2080 device_replacement: 'Dell $1'
2081 brand_replacement: 'Dell'
2082 model_replacement: 'Streak'
2083 - regex: '; *(101DL|GS01|Streak Pro[^;/]*) Build'
2084 device_replacement: 'Dell $1'
2085 brand_replacement: 'Dell'
2086 model_replacement: 'Streak Pro'
2087 - regex: '; *([Ss]treak ?7) Build'
2088 device_replacement: 'Dell $1'
2089 brand_replacement: 'Dell'
2090 model_replacement: 'Streak 7'
2091 - regex: '; *(Mini-3iX) Build'
2092 device_replacement: 'Dell $1'
2093 brand_replacement: 'Dell'
2094 model_replacement: '$1'
2095 - regex: '; *(?:Dell|DELL)[ _](Aero|Venue|Thunder|Mini.*|Streak[ _]Pro) Build'
2096 device_replacement: 'Dell $1'
2097 brand_replacement: 'Dell'
2098 model_replacement: '$1'
2099 - regex: '; *Dell[ _]([^;/]+) Build'
2100 device_replacement: 'Dell $1'
2101 brand_replacement: 'Dell'
2102 model_replacement: '$1'
2103 - regex: '; *Dell ([^;/]+) Build'
2104 device_replacement: 'Dell $1'
2105 brand_replacement: 'Dell'
2106 model_replacement: '$1'
2107
2108 #########
2109 # Denver
2110 # @ref: http://www.denver-electronics.com/tablets1/
2111 #########
2112 - regex: '; *(TA[CD]-\d+[^;/]*) Build'
2113 device_replacement: '$1'
2114 brand_replacement: 'Denver'
2115 model_replacement: '$1'
2116
2117 #########
2118 # Dex
2119 # @ref: http://dex.ua/
2120 #########
2121 - regex: '; *(iP[789]\d{2}(?:-3G)?|IP10\d{2}(?:-8GB)?) Build'
2122 device_replacement: '$1'
2123 brand_replacement: 'Dex'
2124 model_replacement: '$1'
2125
2126 #########
2127 # DNS AirTab
2128 # @ref: http://www.dns-shop.ru/
2129 #########
2130 - regex: '; *(AirTab)[ _\-]([^;/]+) Build'
2131 device_replacement: '$1 $2'
2132 brand_replacement: 'DNS'
2133 model_replacement: '$1 $2'
2134
2135 #########
2136 # Docomo (Operator Branded Device)
2137 # @ref: http://www.ipentec.com/document/document.aspx?page=android-useragent
2138 #########
2139 - regex: '; *(F\-\d[^;/]+) Build'
2140 device_replacement: '$1'
2141 brand_replacement: 'Fujitsu'
2142 model_replacement: '$1'
2143 - regex: '; *(HT-03A) Build'
2144 device_replacement: '$1'
2145 brand_replacement: 'HTC'
2146 model_replacement: 'Magic'
2147 - regex: '; *(HT\-\d[^;/]+) Build'
2148 device_replacement: '$1'
2149 brand_replacement: 'HTC'
2150 model_replacement: '$1'
2151 - regex: '; *(L\-\d[^;/]+) Build'
2152 device_replacement: '$1'
2153 brand_replacement: 'LG'
2154 model_replacement: '$1'
2155 - regex: '; *(N\-\d[^;/]+) Build'
2156 device_replacement: '$1'
2157 brand_replacement: 'Nec'
2158 model_replacement: '$1'
2159 - regex: '; *(P\-\d[^;/]+) Build'
2160 device_replacement: '$1'
2161 brand_replacement: 'Panasonic'
2162 model_replacement: '$1'
2163 - regex: '; *(SC\-\d[^;/]+) Build'
2164 device_replacement: '$1'
2165 brand_replacement: 'Samsung'
2166 model_replacement: '$1'
2167 - regex: '; *(SH\-\d[^;/]+) Build'
2168 device_replacement: '$1'
2169 brand_replacement: 'Sharp'
2170 model_replacement: '$1'
2171 - regex: '; *(SO\-\d[^;/]+) Build'
2172 device_replacement: '$1'
2173 brand_replacement: 'SonyEricsson'
2174 model_replacement: '$1'
2175 - regex: '; *(T\-0[12][^;/]+) Build'
2176 device_replacement: '$1'
2177 brand_replacement: 'Toshiba'
2178 model_replacement: '$1'
2179
2180 #########
2181 # DOOV
2182 # @ref: http://www.doov.com.cn/
2183 #########
2184 - regex: '; *(DOOV)[ _]([^;/]+) Build'
2185 device_replacement: '$1 $2'
2186 brand_replacement: 'DOOV'
2187 model_replacement: '$2'
2188
2189 #########
2190 # Enot
2191 # @ref: http://www.enot.ua/
2192 #########
2193 - regex: '; *(Enot|ENOT)[ -]?([^;/]+) Build'
2194 device_replacement: '$1 $2'
2195 brand_replacement: 'Enot'
2196 model_replacement: '$2'
2197
2198 #########
2199 # Evercoss
2200 # @ref: http://evercoss.com/android/
2201 #########
2202 - regex: '; *[^;/]+ Build/(?:CROSS|Cross)+[ _\-]([^\)]+)'
2203 device_replacement: 'CROSS $1'
2204 brand_replacement: 'Evercoss'
2205 model_replacement: 'Cross $1'
2206 - regex: '; *(CROSS|Cross)[ _\-]([^;/]+) Build'
2207 device_replacement: '$1 $2'
2208 brand_replacement: 'Evercoss'
2209 model_replacement: 'Cross $2'
2210
2211 #########
2212 # Explay
2213 # @ref: http://explay.ru/
2214 #########
2215 - regex: '; *Explay[_ ](.+?)(?:[\)]| Build)'
2216 device_replacement: '$1'
2217 brand_replacement: 'Explay'
2218 model_replacement: '$1'
2219
2220 #########
2221 # Fly
2222 # @ref: http://www.fly-phone.com/
2223 #########
2224 - regex: '; *(IQ.*) Build'
2225 device_replacement: '$1'
2226 brand_replacement: 'Fly'
2227 model_replacement: '$1'
2228 - regex: '; *(Fly|FLY)[ _](IQ[^;]+|F[34]\d+[^;]*);? Build'
2229 device_replacement: '$1 $2'
2230 brand_replacement: 'Fly'
2231 model_replacement: '$2'
2232
2233 #########
2234 # Fujitsu
2235 # @ref: http://www.fujitsu.com/global/
2236 #########
2237 - regex: '; *(M532|Q572|FJL21) Build/'
2238 device_replacement: '$1'
2239 brand_replacement: 'Fujitsu'
2240 model_replacement: '$1'
2241
2242 #########
2243 # Galapad
2244 # @ref: http://www.galapad.net/product.html
2245 #########
2246 - regex: '; *(G1) Build'
2247 device_replacement: '$1'
2248 brand_replacement: 'Galapad'
2249 model_replacement: '$1'
2250
2251 #########
2252 # Geeksphone
2253 # @ref: http://www.geeksphone.com/
2254 #########
2255 - regex: '; *(Geeksphone) ([^;/]+) Build'
2256 device_replacement: '$1 $2'
2257 brand_replacement: '$1'
2258 model_replacement: '$2'
2259
2260 #########
2261 # Gfive
2262 # @ref: http://www.gfivemobile.com/en
2263 #########
2264 #- regex: '; *(G\'?FIVE) ([^;/]+) Build' # there is a problem with python yaml parser here
2265 - regex: '; *(G[^F]?FIVE) ([^;/]+) Build'
2266 device_replacement: '$1 $2'
2267 brand_replacement: 'Gfive'
2268 model_replacement: '$2'
2269
2270 #########
2271 # Gionee
2272 # @ref: http://www.gionee.com/
2273 #########
2274 - regex: '; *(Gionee)[ _\-]([^;/]+)(?:/[^;/]+)? Build'
2275 regex_flag: 'i'
2276 device_replacement: '$1 $2'
2277 brand_replacement: 'Gionee'
2278 model_replacement: '$2'
2279 - regex: '; *(GN\d+[A-Z]?|INFINITY_PASSION|Ctrl_V1) Build'
2280 device_replacement: 'Gionee $1'
2281 brand_replacement: 'Gionee'
2282 model_replacement: '$1'
2283 - regex: '; *(E3) Build/JOP40D'
2284 device_replacement: 'Gionee $1'
2285 brand_replacement: 'Gionee'
2286 model_replacement: '$1'
2287 - regex: '\sGIONEE[-\s_](\w*)'
2288 regex_flag: 'i'
2289 device_replacement: 'Gionee $1'
2290 brand_replacement: 'Gionee'
2291 model_replacement: '$1'
2292
2293 #########
2294 # GoClever
2295 # @ref: http://www.goclever.com
2296 #########
2297 - regex: '; *((?:FONE|QUANTUM|INSIGNIA) \d+[^;/]*|PLAYTAB) Build'
2298 device_replacement: 'GoClever $1'
2299 brand_replacement: 'GoClever'
2300 model_replacement: '$1'
2301 - regex: '; *GOCLEVER ([^;/]+) Build'
2302 device_replacement: 'GoClever $1'
2303 brand_replacement: 'GoClever'
2304 model_replacement: '$1'
2305
2306 #########
2307 # Google
2308 # @ref: http://www.google.de/glass/start/
2309 #########
2310 - regex: '; *(Glass \d+) Build'
2311 device_replacement: '$1'
2312 brand_replacement: 'Google'
2313 model_replacement: '$1'
2314 - regex: '; *(Pixel.*) Build'
2315 device_replacement: '$1'
2316 brand_replacement: 'Google'
2317 model_replacement: '$1'
2318
2319 #########
2320 # Gigabyte
2321 # @ref: http://gsmart.gigabytecm.com/en/
2322 #########
2323 - regex: '; *(GSmart)[ -]([^/]+) Build'
2324 device_replacement: '$1 $2'
2325 brand_replacement: 'Gigabyte'
2326 model_replacement: '$1 $2'
2327
2328 #########
2329 # Freescale development boards
2330 # @ref: http://www.freescale.com/webapp/sps/site/prod_summary.jsp?code=IMX53QSB
2331 #########
2332 - regex: '; *(imx5[13]_[^/]+) Build'
2333 device_replacement: 'Freescale $1'
2334 brand_replacement: 'Freescale'
2335 model_replacement: '$1'
2336
2337 #########
2338 # Haier
2339 # @ref: http://www.haier.com/
2340 # @ref: http://www.haier.com/de/produkte/tablet/
2341 #########
2342 - regex: '; *Haier[ _\-]([^/]+) Build'
2343 device_replacement: 'Haier $1'
2344 brand_replacement: 'Haier'
2345 model_replacement: '$1'
2346 - regex: '; *(PAD1016) Build'
2347 device_replacement: 'Haipad $1'
2348 brand_replacement: 'Haipad'
2349 model_replacement: '$1'
2350
2351 #########
2352 # Haipad
2353 # @ref: http://www.haipad.net/
2354 # @models: V7P|M7SM7S|M9XM9X|M7XM7X|M9|M8|M7-M|M1002|M7|M701
2355 #########
2356 - regex: '; *(M701|M7|M8|M9) Build'
2357 device_replacement: 'Haipad $1'
2358 brand_replacement: 'Haipad'
2359 model_replacement: '$1'
2360
2361 #########
2362 # Hannspree
2363 # @ref: http://www.hannspree.eu/
2364 # @models: SN10T1|SN10T2|SN70T31B|SN70T32W
2365 #########
2366 - regex: '; *(SN\d+T[^;\)/]*)(?: Build|[;\)])'
2367 device_replacement: 'Hannspree $1'
2368 brand_replacement: 'Hannspree'
2369 model_replacement: '$1'
2370
2371 #########
2372 # HCLme
2373 # @ref: http://www.hclmetablet.com/india/
2374 #########
2375 - regex: 'Build/HCL ME Tablet ([^;\)]+)[\);]'
2376 device_replacement: 'HCLme $1'
2377 brand_replacement: 'HCLme'
2378 model_replacement: '$1'
2379 - regex: '; *([^;\/]+) Build/HCL'
2380 device_replacement: 'HCLme $1'
2381 brand_replacement: 'HCLme'
2382 model_replacement: '$1'
2383
2384 #########
2385 # Hena
2386 # @ref: http://www.henadigital.com/en/product/index.asp?id=6
2387 #########
2388 - regex: '; *(MID-?\d{4}C[EM]) Build'
2389 device_replacement: 'Hena $1'
2390 brand_replacement: 'Hena'
2391 model_replacement: '$1'
2392
2393 #########
2394 # Hisense
2395 # @ref: http://www.hisense.com/
2396 #########
2397 - regex: '; *(EG\d{2,}|HS-[^;/]+|MIRA[^;/]+) Build'
2398 device_replacement: 'Hisense $1'
2399 brand_replacement: 'Hisense'
2400 model_replacement: '$1'
2401 - regex: '; *(andromax[^;/]+) Build'
2402 regex_flag: 'i'
2403 device_replacement: 'Hisense $1'
2404 brand_replacement: 'Hisense'
2405 model_replacement: '$1'
2406
2407 #########
2408 # hitech
2409 # @ref: http://www.hitech-mobiles.com/
2410 #########
2411 - regex: '; *(?:AMAZE[ _](S\d+)|(S\d+)[ _]AMAZE) Build'
2412 device_replacement: 'AMAZE $1$2'
2413 brand_replacement: 'hitech'
2414 model_replacement: 'AMAZE $1$2'
2415
2416 #########
2417 # HP
2418 # @ref: http://www.hp.com/
2419 #########
2420 - regex: '; *(PlayBook) Build'
2421 device_replacement: 'HP $1'
2422 brand_replacement: 'HP'
2423 model_replacement: '$1'
2424 - regex: '; *HP ([^/]+) Build'
2425 device_replacement: 'HP $1'
2426 brand_replacement: 'HP'
2427 model_replacement: '$1'
2428 - regex: '; *([^/]+_tenderloin) Build'
2429 device_replacement: 'HP TouchPad'
2430 brand_replacement: 'HP'
2431 model_replacement: 'TouchPad'
2432
2433 #########
2434 # Huawei
2435 # @ref: http://www.huaweidevice.com
2436 # @note: Needs to be before HTC due to Desire HD Build on U8815
2437 #########
2438 - regex: '; *(HUAWEI |Huawei-)?([UY][^;/]+) Build/(?:Huawei|HUAWEI)([UY][^\);]+)\)'
2439 device_replacement: '$1$2'
2440 brand_replacement: 'Huawei'
2441 model_replacement: '$2'
2442 - regex: '; *([^;/]+) Build[/ ]Huawei(MT1-U06|[A-Z]+\d+[^\);]+)[^\);]*\)'
2443 device_replacement: '$1'
2444 brand_replacement: 'Huawei'
2445 model_replacement: '$2'
2446 - regex: '; *(S7|M860) Build'
2447 device_replacement: '$1'
2448 brand_replacement: 'Huawei'
2449 model_replacement: '$1'
2450 - regex: '; *((?:HUAWEI|Huawei)[ \-]?)(MediaPad) Build'
2451 device_replacement: '$1$2'
2452 brand_replacement: 'Huawei'
2453 model_replacement: '$2'
2454 - regex: '; *((?:HUAWEI[ _]?|Huawei[ _])?Ascend[ _])([^;/]+) Build'
2455 device_replacement: '$1$2'
2456 brand_replacement: 'Huawei'
2457 model_replacement: '$2'
2458 - regex: '; *((?:HUAWEI|Huawei)[ _\-]?)((?:G700-|MT-)[^;/]+) Build'
2459 device_replacement: '$1$2'
2460 brand_replacement: 'Huawei'
2461 model_replacement: '$2'
2462 - regex: '; *((?:HUAWEI|Huawei)[ _\-]?)([^;/]+) Build'
2463 device_replacement: '$1$2'
2464 brand_replacement: 'Huawei'
2465 model_replacement: '$2'
2466 - regex: '; *(MediaPad[^;]+|SpringBoard) Build/Huawei'
2467 device_replacement: '$1'
2468 brand_replacement: 'Huawei'
2469 model_replacement: '$1'
2470 - regex: '; *([^;]+) Build/(?:Huawei|HUAWEI)'
2471 device_replacement: '$1'
2472 brand_replacement: 'Huawei'
2473 model_replacement: '$1'
2474 - regex: '; *([Uu])([89]\d{3}) Build'
2475 device_replacement: '$1$2'
2476 brand_replacement: 'Huawei'
2477 model_replacement: 'U$2'
2478 - regex: '; *(?:Ideos |IDEOS )(S7) Build'
2479 device_replacement: 'Huawei Ideos$1'
2480 brand_replacement: 'Huawei'
2481 model_replacement: 'Ideos$1'
2482 - regex: '; *(?:Ideos |IDEOS )([^;/]+\s*|\s*)Build'
2483 device_replacement: 'Huawei Ideos$1'
2484 brand_replacement: 'Huawei'
2485 model_replacement: 'Ideos$1'
2486 - regex: '; *(Orange Daytona|Pulse|Pulse Mini|Vodafone 858|C8500|C8600|C8650|C8660|Nexus 6P|ATH-.+?) Build[/ ]'
2487 device_replacement: 'Huawei $1'
2488 brand_replacement: 'Huawei'
2489 model_replacement: '$1'
2490
2491 #########
2492 # HTC
2493 # @ref: http://www.htc.com/www/products/
2494 # @ref: http://en.wikipedia.org/wiki/List_of_HTC_phones
2495 #########
2496
2497 - regex: '; *HTC[ _]([^;]+); Windows Phone'
2498 device_replacement: 'HTC $1'
2499 brand_replacement: 'HTC'
2500 model_replacement: '$1'
2501
2502 # Android HTC with Version Number matcher
2503 # ; HTC_0P3Z11/1.12.161.3 Build
2504 # ;HTC_A3335 V2.38.841.1 Build
2505 - regex: '; *(?:HTC[ _/])+([^ _/]+)(?:[/\\]1\.0 | V|/| +)\d+\.\d[\d\.]*(?: *Build|\))'
2506 device_replacement: 'HTC $1'
2507 brand_replacement: 'HTC'
2508 model_replacement: '$1'
2509 - regex: '; *(?:HTC[ _/])+([^ _/]+)(?:[ _/]([^ _/]+))?(?:[/\\]1\.0 | V|/| +)\d+\.\d[\d\.]*(?: *Build|\))'
2510 device_replacement: 'HTC $1 $2'
2511 brand_replacement: 'HTC'
2512 model_replacement: '$1 $2'
2513 - regex: '; *(?:HTC[ _/])+([^ _/]+)(?:[ _/]([^ _/]+)(?:[ _/]([^ _/]+))?)?(?:[/\\]1\.0 | V|/| +)\d+\.\d[\d\.]*(?: *Build|\))'
2514 device_replacement: 'HTC $1 $2 $3'
2515 brand_replacement: 'HTC'
2516 model_replacement: '$1 $2 $3'
2517 - regex: '; *(?:HTC[ _/])+([^ _/]+)(?:[ _/]([^ _/]+)(?:[ _/]([^ _/]+)(?:[ _/]([^ _/]+))?)?)?(?:[/\\]1\.0 | V|/| +)\d+\.\d[\d\.]*(?: *Build|\))'
2518 device_replacement: 'HTC $1 $2 $3 $4'
2519 brand_replacement: 'HTC'
2520 model_replacement: '$1 $2 $3 $4'
2521
2522 # Android HTC without Version Number matcher
2523 - regex: '; *(?:(?:HTC|htc)(?:_blocked)*[ _/])+([^ _/;]+)(?: *Build|[;\)]| - )'
2524 device_replacement: 'HTC $1'
2525 brand_replacement: 'HTC'
2526 model_replacement: '$1'
2527 - regex: '; *(?:(?:HTC|htc)(?:_blocked)*[ _/])+([^ _/]+)(?:[ _/]([^ _/;\)]+))?(?: *Build|[;\)]| - )'
2528 device_replacement: 'HTC $1 $2'
2529 brand_replacement: 'HTC'
2530 model_replacement: '$1 $2'
2531 - regex: '; *(?:(?:HTC|htc)(?:_blocked)*[ _/])+([^ _/]+)(?:[ _/]([^ _/]+)(?:[ _/]([^ _/;\)]+))?)?(?: *Build|[;\)]| - )'
2532 device_replacement: 'HTC $1 $2 $3'
2533 brand_replacement: 'HTC'
2534 model_replacement: '$1 $2 $3'
2535 - regex: '; *(?:(?:HTC|htc)(?:_blocked)*[ _/])+([^ _/]+)(?:[ _/]([^ _/]+)(?:[ _/]([^ _/]+)(?:[ _/]([^ /;]+))?)?)?(?: *Build|[;\)]| - )'
2536 device_replacement: 'HTC $1 $2 $3 $4'
2537 brand_replacement: 'HTC'
2538 model_replacement: '$1 $2 $3 $4'
2539
2540 # HTC Streaming Player
2541 - regex: 'HTC Streaming Player [^\/]*/[^\/]*/ htc_([^/]+) /'
2542 device_replacement: 'HTC $1'
2543 brand_replacement: 'HTC'
2544 model_replacement: '$1'
2545 # general matcher for anything else
2546 - regex: '(?:[;,] *|^)(?:htccn_chs-)?HTC[ _-]?([^;]+?)(?: *Build|clay|Android|-?Mozilla| Opera| Profile| UNTRUSTED|[;/\(\)]|$)'
2547 regex_flag: 'i'
2548 device_replacement: 'HTC $1'
2549 brand_replacement: 'HTC'
2550 model_replacement: '$1'
2551 # Android matchers without HTC
2552 - regex: '; *(A6277|ADR6200|ADR6300|ADR6350|ADR6400[A-Z]*|ADR6425[A-Z]*|APX515CKT|ARIA|Desire[^_ ]*|Dream|EndeavorU|Eris|Evo|Flyer|HD2|Hero|HERO200|Hero CDMA|HTL21|Incredible|Inspire[A-Z0-9]*|Legend|Liberty|Nexus ?(?:One|HD2)|One|One S C2|One[ _]?(?:S|V|X\+?)\w*|PC36100|PG06100|PG86100|S31HT|Sensation|Wildfire)(?: Build|[/;\(\)])'
2553 regex_flag: 'i'
2554 device_replacement: 'HTC $1'
2555 brand_replacement: 'HTC'
2556 model_replacement: '$1'
2557 - regex: '; *(ADR6200|ADR6400L|ADR6425LVW|Amaze|DesireS?|EndeavorU|Eris|EVO|Evo\d[A-Z]+|HD2|IncredibleS?|Inspire[A-Z0-9]*|Inspire[A-Z0-9]*|Sensation[A-Z0-9]*|Wildfire)[ _-](.+?)(?:[/;\)]|Build|MIUI|1\.0)'
2558 regex_flag: 'i'
2559 device_replacement: 'HTC $1 $2'
2560 brand_replacement: 'HTC'
2561 model_replacement: '$1 $2'
2562
2563 #########
2564 # Hyundai
2565 # @ref: http://www.hyundaitechnologies.com
2566 #########
2567 - regex: '; *HYUNDAI (T\d[^/]*) Build'
2568 device_replacement: 'Hyundai $1'
2569 brand_replacement: 'Hyundai'
2570 model_replacement: '$1'
2571 - regex: '; *HYUNDAI ([^;/]+) Build'
2572 device_replacement: 'Hyundai $1'
2573 brand_replacement: 'Hyundai'
2574 model_replacement: '$1'
2575 # X900? http://www.amazon.com/Hyundai-X900-Retina-Android-Bluetooth/dp/B00AO07H3O
2576 - regex: '; *(X700|Hold X|MB-6900) Build'
2577 device_replacement: 'Hyundai $1'
2578 brand_replacement: 'Hyundai'
2579 model_replacement: '$1'
2580
2581 #########
2582 # iBall
2583 # @ref: http://www.iball.co.in/Category/Mobiles/22
2584 #########
2585 - regex: '; *(?:iBall[ _\-])?(Andi)[ _]?(\d[^;/]*) Build'
2586 regex_flag: 'i'
2587 device_replacement: '$1 $2'
2588 brand_replacement: 'iBall'
2589 model_replacement: '$1 $2'
2590 - regex: '; *(IBall)(?:[ _]([^;/]+))? Build'
2591 regex_flag: 'i'
2592 device_replacement: '$1 $2'
2593 brand_replacement: 'iBall'
2594 model_replacement: '$2'
2595
2596 #########
2597 # IconBIT
2598 # @ref: http://www.iconbit.com/catalog/tablets/
2599 #########
2600 - regex: '; *(NT-\d+[^ ;/]*|Net[Tt]AB [^;/]+|Mercury [A-Z]+|iconBIT)(?: S/N:[^;/]+)? Build'
2601 device_replacement: '$1'
2602 brand_replacement: 'IconBIT'
2603 model_replacement: '$1'
2604
2605 #########
2606 # IMO
2607 # @ref: http://www.ponselimo.com/
2608 #########
2609 - regex: '; *(IMO)[ _]([^;/]+) Build'
2610 regex_flag: 'i'
2611 device_replacement: '$1 $2'
2612 brand_replacement: 'IMO'
2613 model_replacement: '$2'
2614
2615 #########
2616 # i-mobile
2617 # @ref: http://www.i-mobilephone.com/
2618 #########
2619 - regex: '; *i-?mobile[ _]([^/]+) Build/'
2620 regex_flag: 'i'
2621 device_replacement: 'i-mobile $1'
2622 brand_replacement: 'imobile'
2623 model_replacement: '$1'
2624 - regex: '; *(i-(?:style|note)[^/]*) Build/'
2625 regex_flag: 'i'
2626 device_replacement: 'i-mobile $1'
2627 brand_replacement: 'imobile'
2628 model_replacement: '$1'
2629
2630 #########
2631 # Impression
2632 # @ref: http://impression.ua/planshetnye-kompyutery
2633 #########
2634 - regex: '; *(ImPAD) ?(\d+(?:.)*) Build'
2635 device_replacement: '$1 $2'
2636 brand_replacement: 'Impression'
2637 model_replacement: '$1 $2'
2638
2639 #########
2640 # Infinix
2641 # @ref: http://www.infinixmobility.com/index.html
2642 #########
2643 - regex: '; *(Infinix)[ _]([^;/]+) Build'
2644 device_replacement: '$1 $2'
2645 brand_replacement: 'Infinix'
2646 model_replacement: '$2'
2647
2648 #########
2649 # Informer
2650 # @ref: ??
2651 #########
2652 - regex: '; *(Informer)[ \-]([^;/]+) Build'
2653 device_replacement: '$1 $2'
2654 brand_replacement: 'Informer'
2655 model_replacement: '$2'
2656
2657 #########
2658 # Intenso
2659 # @ref: http://www.intenso.de
2660 # @models: 7":TAB 714,TAB 724;8":TAB 814,TAB 824;10":TAB 1004
2661 #########
2662 - regex: '; *(TAB) ?([78][12]4) Build'
2663 device_replacement: 'Intenso $1'
2664 brand_replacement: 'Intenso'
2665 model_replacement: '$1 $2'
2666
2667 #########
2668 # Intex
2669 # @ref: http://intexmobile.in/index.aspx
2670 # @note: Zync also offers a "Cloud Z5" device
2671 #########
2672 # smartphones
2673 - regex: '; *(?:Intex[ _])?(AQUA|Aqua)([ _\.\-])([^;/]+) *(?:Build|;)'
2674 device_replacement: '$1$2$3'
2675 brand_replacement: 'Intex'
2676 model_replacement: '$1 $3'
2677 # matches "INTEX CLOUD X1"
2678 - regex: '; *(?:INTEX|Intex)(?:[_ ]([^\ _;/]+))(?:[_ ]([^\ _;/]+))? *(?:Build|;)'
2679 device_replacement: '$1 $2'
2680 brand_replacement: 'Intex'
2681 model_replacement: '$1 $2'
2682 # tablets
2683 - regex: '; *([iI]Buddy)[ _]?(Connect)(?:_|\?_| )?([^;/]*) *(?:Build|;)'
2684 device_replacement: '$1 $2 $3'
2685 brand_replacement: 'Intex'
2686 model_replacement: 'iBuddy $2 $3'
2687 - regex: '; *(I-Buddy)[ _]([^;/]+) *(?:Build|;)'
2688 device_replacement: '$1 $2'
2689 brand_replacement: 'Intex'
2690 model_replacement: 'iBuddy $2'
2691
2692 #########
2693 # iOCEAN
2694 # @ref: http://www.iocean.cc/
2695 #########
2696 - regex: '; *(iOCEAN) ([^/]+) Build'
2697 regex_flag: 'i'
2698 device_replacement: '$1 $2'
2699 brand_replacement: 'iOCEAN'
2700 model_replacement: '$2'
2701
2702 #########
2703 # i.onik
2704 # @ref: http://www.i-onik.de/
2705 #########
2706 - regex: '; *(TP\d+(?:\.\d+)?\-\d[^;/]+) Build'
2707 device_replacement: 'ionik $1'
2708 brand_replacement: 'ionik'
2709 model_replacement: '$1'
2710
2711 #########
2712 # IRU.ru
2713 # @ref: http://www.iru.ru/catalog/soho/planetable/
2714 #########
2715 - regex: '; *(M702pro) Build'
2716 device_replacement: '$1'
2717 brand_replacement: 'Iru'
2718 model_replacement: '$1'
2719
2720 #########
2721 # Ivio
2722 # @ref: http://www.ivio.com/mobile.php
2723 # @models: DG80,DG20,DE38,DE88,MD70
2724 #########
2725 - regex: '; *(DE88Plus|MD70) Build'
2726 device_replacement: '$1'
2727 brand_replacement: 'Ivio'
2728 model_replacement: '$1'
2729 - regex: '; *IVIO[_\-]([^;/]+) Build'
2730 device_replacement: '$1'
2731 brand_replacement: 'Ivio'
2732 model_replacement: '$1'
2733
2734 #########
2735 # Jaytech
2736 # @ref: http://www.jay-tech.de/jaytech/servlet/frontend/
2737 #########
2738 - regex: '; *(TPC-\d+|JAY-TECH) Build'
2739 device_replacement: '$1'
2740 brand_replacement: 'Jaytech'
2741 model_replacement: '$1'
2742
2743 #########
2744 # Jiayu
2745 # @ref: http://www.ejiayu.com/en/Product.html
2746 #########
2747 - regex: '; *(JY-[^;/]+|G[234]S?) Build'
2748 device_replacement: '$1'
2749 brand_replacement: 'Jiayu'
2750 model_replacement: '$1'
2751
2752 #########
2753 # JXD
2754 # @ref: http://www.jxd.hk/
2755 #########
2756 - regex: '; *(JXD)[ _\-]([^;/]+) Build'
2757 device_replacement: '$1 $2'
2758 brand_replacement: 'JXD'
2759 model_replacement: '$2'
2760
2761 #########
2762 # Karbonn
2763 # @ref: http://www.karbonnmobiles.com/products_tablet.php
2764 #########
2765 - regex: '; *Karbonn[ _]?([^;/]+) *(?:Build|;)'
2766 regex_flag: 'i'
2767 device_replacement: '$1'
2768 brand_replacement: 'Karbonn'
2769 model_replacement: '$1'
2770 - regex: '; *([^;]+) Build/Karbonn'
2771 device_replacement: '$1'
2772 brand_replacement: 'Karbonn'
2773 model_replacement: '$1'
2774 - regex: '; *(A11|A39|A37|A34|ST8|ST10|ST7|Smart Tab3|Smart Tab2|Titanium S\d) +Build'
2775 device_replacement: '$1'
2776 brand_replacement: 'Karbonn'
2777 model_replacement: '$1'
2778
2779 #########
2780 # KDDI (Operator Branded Device)
2781 # @ref: http://www.ipentec.com/document/document.aspx?page=android-useragent
2782 #########
2783 - regex: '; *(IS01|IS03|IS05|IS\d{2}SH) Build'
2784 device_replacement: '$1'
2785 brand_replacement: 'Sharp'
2786 model_replacement: '$1'
2787 - regex: '; *(IS04) Build'
2788 device_replacement: '$1'
2789 brand_replacement: 'Regza'
2790 model_replacement: '$1'
2791 - regex: '; *(IS06|IS\d{2}PT) Build'
2792 device_replacement: '$1'
2793 brand_replacement: 'Pantech'
2794 model_replacement: '$1'
2795 - regex: '; *(IS11S) Build'
2796 device_replacement: '$1'
2797 brand_replacement: 'SonyEricsson'
2798 model_replacement: 'Xperia Acro'
2799 - regex: '; *(IS11CA) Build'
2800 device_replacement: '$1'
2801 brand_replacement: 'Casio'
2802 model_replacement: 'GzOne $1'
2803 - regex: '; *(IS11LG) Build'
2804 device_replacement: '$1'
2805 brand_replacement: 'LG'
2806 model_replacement: 'Optimus X'
2807 - regex: '; *(IS11N) Build'
2808 device_replacement: '$1'
2809 brand_replacement: 'Medias'
2810 model_replacement: '$1'
2811 - regex: '; *(IS11PT) Build'
2812 device_replacement: '$1'
2813 brand_replacement: 'Pantech'
2814 model_replacement: 'MIRACH'
2815 - regex: '; *(IS12F) Build'
2816 device_replacement: '$1'
2817 brand_replacement: 'Fujitsu'
2818 model_replacement: 'Arrows ES'
2819 # @ref: https://ja.wikipedia.org/wiki/IS12M
2820 - regex: '; *(IS12M) Build'
2821 device_replacement: '$1'
2822 brand_replacement: 'Motorola'
2823 model_replacement: 'XT909'
2824 - regex: '; *(IS12S) Build'
2825 device_replacement: '$1'
2826 brand_replacement: 'SonyEricsson'
2827 model_replacement: 'Xperia Acro HD'
2828 - regex: '; *(ISW11F) Build'
2829 device_replacement: '$1'
2830 brand_replacement: 'Fujitsu'
2831 model_replacement: 'Arrowz Z'
2832 - regex: '; *(ISW11HT) Build'
2833 device_replacement: '$1'
2834 brand_replacement: 'HTC'
2835 model_replacement: 'EVO'
2836 - regex: '; *(ISW11K) Build'
2837 device_replacement: '$1'
2838 brand_replacement: 'Kyocera'
2839 model_replacement: 'DIGNO'
2840 - regex: '; *(ISW11M) Build'
2841 device_replacement: '$1'
2842 brand_replacement: 'Motorola'
2843 model_replacement: 'Photon'
2844 - regex: '; *(ISW11SC) Build'
2845 device_replacement: '$1'
2846 brand_replacement: 'Samsung'
2847 model_replacement: 'GALAXY S II WiMAX'
2848 - regex: '; *(ISW12HT) Build'
2849 device_replacement: '$1'
2850 brand_replacement: 'HTC'
2851 model_replacement: 'EVO 3D'
2852 - regex: '; *(ISW13HT) Build'
2853 device_replacement: '$1'
2854 brand_replacement: 'HTC'
2855 model_replacement: 'J'
2856 - regex: '; *(ISW?[0-9]{2}[A-Z]{0,2}) Build'
2857 device_replacement: '$1'
2858 brand_replacement: 'KDDI'
2859 model_replacement: '$1'
2860 - regex: '; *(INFOBAR [^;/]+) Build'
2861 device_replacement: '$1'
2862 brand_replacement: 'KDDI'
2863 model_replacement: '$1'
2864
2865 #########
2866 # Kingcom
2867 # @ref: http://www.e-kingcom.com
2868 #########
2869 - regex: '; *(JOYPAD|Joypad)[ _]([^;/]+) Build/'
2870 device_replacement: '$1 $2'
2871 brand_replacement: 'Kingcom'
2872 model_replacement: '$1 $2'
2873
2874 #########
2875 # Kobo
2876 # @ref: https://en.wikipedia.org/wiki/Kobo_Inc.
2877 # @ref: http://www.kobo.com/devices#tablets
2878 #########
2879 - regex: '; *(Vox|VOX|Arc|K080) Build/'
2880 regex_flag: 'i'
2881 device_replacement: '$1'
2882 brand_replacement: 'Kobo'
2883 model_replacement: '$1'
2884 - regex: '\b(Kobo Touch)\b'
2885 device_replacement: '$1'
2886 brand_replacement: 'Kobo'
2887 model_replacement: '$1'
2888
2889 #########
2890 # K-Touch
2891 # @ref: ??
2892 #########
2893 - regex: '; *(K-Touch)[ _]([^;/]+) Build'
2894 regex_flag: 'i'
2895 device_replacement: '$1 $2'
2896 brand_replacement: 'Ktouch'
2897 model_replacement: '$2'
2898
2899 #########
2900 # KT Tech
2901 # @ref: http://www.kttech.co.kr
2902 #########
2903 - regex: '; *((?:EV|KM)-S\d+[A-Z]?) Build'
2904 regex_flag: 'i'
2905 device_replacement: '$1'
2906 brand_replacement: 'KTtech'
2907 model_replacement: '$1'
2908
2909 #########
2910 # Kyocera
2911 # @ref: http://www.android.com/devices/?country=all&m=kyocera
2912 #########
2913 - regex: '; *(Zio|Hydro|Torque|Event|EVENT|Echo|Milano|Rise|URBANO PROGRESSO|WX04K|WX06K|WX10K|KYL21|101K|C5[12]\d{2}) Build/'
2914 device_replacement: '$1'
2915 brand_replacement: 'Kyocera'
2916 model_replacement: '$1'
2917
2918 #########
2919 # Lava
2920 # @ref: http://www.lavamobiles.com/
2921 #########
2922 - regex: '; *(?:LAVA[ _])?IRIS[ _\-]?([^/;\)]+) *(?:;|\)|Build)'
2923 regex_flag: 'i'
2924 device_replacement: 'Iris $1'
2925 brand_replacement: 'Lava'
2926 model_replacement: 'Iris $1'
2927 - regex: '; *LAVA[ _]([^;/]+) Build'
2928 device_replacement: '$1'
2929 brand_replacement: 'Lava'
2930 model_replacement: '$1'
2931
2932 #########
2933 # Lemon
2934 # @ref: http://www.lemonmobiles.com/products.php?type=1
2935 #########
2936 - regex: '; *(?:(Aspire A1)|(?:LEMON|Lemon)[ _]([^;/]+))_? Build'
2937 device_replacement: 'Lemon $1$2'
2938 brand_replacement: 'Lemon'
2939 model_replacement: '$1$2'
2940
2941 #########
2942 # Lenco
2943 # @ref: http://www.lenco.com/c/tablets/
2944 #########
2945 - regex: '; *(TAB-1012) Build/'
2946 device_replacement: 'Lenco $1'
2947 brand_replacement: 'Lenco'
2948 model_replacement: '$1'
2949 - regex: '; Lenco ([^;/]+) Build/'
2950 device_replacement: 'Lenco $1'
2951 brand_replacement: 'Lenco'
2952 model_replacement: '$1'
2953
2954 #########
2955 # Lenovo
2956 # @ref: http://support.lenovo.com/en_GB/downloads/default.page?#
2957 #########
2958 - regex: '; *(A1_07|A2107A-H|S2005A-H|S1-37AH0) Build'
2959 device_replacement: '$1'
2960 brand_replacement: 'Lenovo'
2961 model_replacement: '$1'
2962 - regex: '; *(Idea[Tp]ab)[ _]([^;/]+);? Build'
2963 device_replacement: 'Lenovo $1 $2'
2964 brand_replacement: 'Lenovo'
2965 model_replacement: '$1 $2'
2966 - regex: '; *(Idea(?:Tab|pad)) ?([^;/]+) Build'
2967 device_replacement: 'Lenovo $1 $2'
2968 brand_replacement: 'Lenovo'
2969 model_replacement: '$1 $2'
2970 - regex: '; *(ThinkPad) ?(Tablet) Build/'
2971 device_replacement: 'Lenovo $1 $2'
2972 brand_replacement: 'Lenovo'
2973 model_replacement: '$1 $2'
2974 - regex: '; *(?:LNV-)?(?:=?[Ll]enovo[ _\-]?|LENOVO[ _])+(.+?)(?:Build|[;/\)])'
2975 device_replacement: 'Lenovo $1'
2976 brand_replacement: 'Lenovo'
2977 model_replacement: '$1'
2978 - regex: '[;,] (?:Vodafone )?(SmartTab) ?(II) ?(\d+) Build/'
2979 device_replacement: 'Lenovo $1 $2 $3'
2980 brand_replacement: 'Lenovo'
2981 model_replacement: '$1 $2 $3'
2982 - regex: '; *(?:Ideapad )?K1 Build/'
2983 device_replacement: 'Lenovo Ideapad K1'
2984 brand_replacement: 'Lenovo'
2985 model_replacement: 'Ideapad K1'
2986 - regex: '; *(3GC101|3GW10[01]|A390) Build/'
2987 device_replacement: '$1'
2988 brand_replacement: 'Lenovo'
2989 model_replacement: '$1'
2990 - regex: '\b(?:Lenovo|LENOVO)+[ _\-]?([^,;:/ ]+)'
2991 device_replacement: 'Lenovo $1'
2992 brand_replacement: 'Lenovo'
2993 model_replacement: '$1'
2994
2995 #########
2996 # Lexibook
2997 # @ref: http://www.lexibook.com/fr
2998 #########
2999 - regex: '; *(MFC\d+)[A-Z]{2}([^;,/]*),? Build'
3000 device_replacement: '$1$2'
3001 brand_replacement: 'Lexibook'
3002 model_replacement: '$1$2'
3003
3004 #########
3005 # LG
3006 # @ref: http://www.lg.com/uk/mobile
3007 #########
3008 - regex: '; *(E[34][0-9]{2}|LS[6-8][0-9]{2}|VS[6-9][0-9]+[^;/]+|Nexus 4|Nexus 5X?|GT540f?|Optimus (?:2X|G|4X HD)|OptimusX4HD) *(?:Build|;)'
3009 device_replacement: '$1'
3010 brand_replacement: 'LG'
3011 model_replacement: '$1'
3012 - regex: '[;:] *(L-\d+[A-Z]|LGL\d+[A-Z]?)(?:/V\d+)? *(?:Build|[;\)])'
3013 device_replacement: '$1'
3014 brand_replacement: 'LG'
3015 model_replacement: '$1'
3016 - regex: '; *(LG-)([A-Z]{1,2}\d{2,}[^,;/\)\(]*?)(?:Build| V\d+|[,;/\)\(]|$)'
3017 device_replacement: '$1$2'
3018 brand_replacement: 'LG'
3019 model_replacement: '$2'
3020 - regex: '; *(LG[ \-]|LG)([^;/]+)[;/]? Build'
3021 device_replacement: '$1$2'
3022 brand_replacement: 'LG'
3023 model_replacement: '$2'
3024 - regex: '^(LG)-([^;/]+)/ Mozilla/.*; Android'
3025 device_replacement: '$1 $2'
3026 brand_replacement: 'LG'
3027 model_replacement: '$2'
3028 - regex: '(Web0S); Linux/(SmartTV)'
3029 device_replacement: 'LG $1 $2'
3030 brand_replacement: 'LG'
3031 model_replacement: '$1 $2'
3032
3033 #########
3034 # Malata
3035 # @ref: http://www.malata.com/en/products.aspx?classid=680
3036 #########
3037 - regex: '; *((?:SMB|smb)[^;/]+) Build/'
3038 device_replacement: '$1'
3039 brand_replacement: 'Malata'
3040 model_replacement: '$1'
3041 - regex: '; *(?:Malata|MALATA) ([^;/]+) Build/'
3042 device_replacement: '$1'
3043 brand_replacement: 'Malata'
3044 model_replacement: '$1'
3045
3046 #########
3047 # Manta
3048 # @ref: http://www.manta.com.pl/en
3049 #########
3050 - regex: '; *(MS[45][0-9]{3}|MID0[568][NS]?|MID[1-9]|MID[78]0[1-9]|MID970[1-9]|MID100[1-9]) Build/'
3051 device_replacement: '$1'
3052 brand_replacement: 'Manta'
3053 model_replacement: '$1'
3054
3055 #########
3056 # Match
3057 # @ref: http://www.match.net.cn/products.asp
3058 #########
3059 - regex: '; *(M1052|M806|M9000|M9100|M9701|MID100|MID120|MID125|MID130|MID135|MID140|MID701|MID710|MID713|MID727|MID728|MID731|MID732|MID733|MID735|MID736|MID737|MID760|MID800|MID810|MID820|MID830|MID833|MID835|MID860|MID900|MID930|MID933|MID960|MID980) Build/'
3060 device_replacement: '$1'
3061 brand_replacement: 'Match'
3062 model_replacement: '$1'
3063
3064 #########
3065 # Maxx
3066 # @ref: http://www.maxxmobile.in/
3067 # @models: Maxx MSD7-Play, Maxx MX245+ Trance, Maxx AX8 Race, Maxx MSD7 3G- AX50, Maxx Genx Droid 7 - AX40, Maxx AX5 Duo,
3068 # Maxx AX3 Duo, Maxx AX3, Maxx AX8 Note II (Note 2), Maxx AX8 Note I, Maxx AX8, Maxx AX5 Plus, Maxx MSD7 Smarty,
3069 # Maxx AX9Z Race,
3070 # Maxx MT150, Maxx MQ601, Maxx M2020, Maxx Sleek MX463neo, Maxx MX525, Maxx MX192-Tune, Maxx Genx Droid 7 AX353,
3071 # @note: Need more User-Agents!!!
3072 #########
3073 - regex: '; *(GenxDroid7|MSD7.*|AX\d.*|Tab 701|Tab 722) Build/'
3074 device_replacement: 'Maxx $1'
3075 brand_replacement: 'Maxx'
3076 model_replacement: '$1'
3077
3078 #########
3079 # Mediacom
3080 # @ref: http://www.mediacomeurope.it/
3081 #########
3082 - regex: '; *(M-PP[^;/]+|PhonePad ?\d{2,}[^;/]+) Build'
3083 device_replacement: 'Mediacom $1'
3084 brand_replacement: 'Mediacom'
3085 model_replacement: '$1'
3086 - regex: '; *(M-MP[^;/]+|SmartPad ?\d{2,}[^;/]+) Build'
3087 device_replacement: 'Mediacom $1'
3088 brand_replacement: 'Mediacom'
3089 model_replacement: '$1'
3090
3091 #########
3092 # Medion
3093 # @ref: http://www.medion.com/en/
3094 #########
3095 - regex: '; *(?:MD_)?LIFETAB[ _]([^;/]+) Build'
3096 regex_flag: 'i'
3097 device_replacement: 'Medion Lifetab $1'
3098 brand_replacement: 'Medion'
3099 model_replacement: 'Lifetab $1'
3100 - regex: '; *MEDION ([^;/]+) Build'
3101 device_replacement: 'Medion $1'
3102 brand_replacement: 'Medion'
3103 model_replacement: '$1'
3104
3105 #########
3106 # Meizu
3107 # @ref: http://www.meizu.com
3108 #########
3109 - regex: '; *(M030|M031|M035|M040|M065|m9) Build'
3110 device_replacement: 'Meizu $1'
3111 brand_replacement: 'Meizu'
3112 model_replacement: '$1'
3113 - regex: '; *(?:meizu_|MEIZU )(.+?) *(?:Build|[;\)])'
3114 device_replacement: 'Meizu $1'
3115 brand_replacement: 'Meizu'
3116 model_replacement: '$1'
3117
3118 #########
3119 # Micromax
3120 # @ref: http://www.micromaxinfo.com
3121 #########
3122 - regex: '; *(?:Micromax[ _](A111|A240)|(A111|A240)) Build'
3123 regex_flag: 'i'
3124 device_replacement: 'Micromax $1$2'
3125 brand_replacement: 'Micromax'
3126 model_replacement: '$1$2'
3127 - regex: '; *Micromax[ _](A\d{2,3}[^;/]*) Build'
3128 regex_flag: 'i'
3129 device_replacement: 'Micromax $1'
3130 brand_replacement: 'Micromax'
3131 model_replacement: '$1'
3132 # be carefull here with Acer e.g. A500
3133 - regex: '; *(A\d{2}|A[12]\d{2}|A90S|A110Q) Build'
3134 regex_flag: 'i'
3135 device_replacement: 'Micromax $1'
3136 brand_replacement: 'Micromax'
3137 model_replacement: '$1'
3138 - regex: '; *Micromax[ _](P\d{3}[^;/]*) Build'
3139 regex_flag: 'i'
3140 device_replacement: 'Micromax $1'
3141 brand_replacement: 'Micromax'
3142 model_replacement: '$1'
3143 - regex: '; *(P\d{3}|P\d{3}\(Funbook\)) Build'
3144 regex_flag: 'i'
3145 device_replacement: 'Micromax $1'
3146 brand_replacement: 'Micromax'
3147 model_replacement: '$1'
3148
3149 #########
3150 # Mito
3151 # @ref: http://new.mitomobile.com/
3152 #########
3153 - regex: '; *(MITO)[ _\-]?([^;/]+) Build'
3154 regex_flag: 'i'
3155 device_replacement: '$1 $2'
3156 brand_replacement: 'Mito'
3157 model_replacement: '$2'
3158
3159 #########
3160 # Mobistel
3161 # @ref: http://www.mobistel.com/
3162 #########
3163 - regex: '; *(Cynus)[ _](F5|T\d|.+?) *(?:Build|[;/\)])'
3164 regex_flag: 'i'
3165 device_replacement: '$1 $2'
3166 brand_replacement: 'Mobistel'
3167 model_replacement: '$1 $2'
3168
3169 #########
3170 # Modecom
3171 # @ref: http://www.modecom.eu/tablets/portal/
3172 #########
3173 - regex: '; *(MODECOM )?(FreeTab) ?([^;/]+) Build'
3174 regex_flag: 'i'
3175 device_replacement: '$1$2 $3'
3176 brand_replacement: 'Modecom'
3177 model_replacement: '$2 $3'
3178 - regex: '; *(MODECOM )([^;/]+) Build'
3179 regex_flag: 'i'
3180 device_replacement: '$1 $2'
3181 brand_replacement: 'Modecom'
3182 model_replacement: '$2'
3183
3184 #########
3185 # Motorola
3186 # @ref: http://www.motorola.com/us/shop-all-mobile-phones/
3187 #########
3188 - regex: '; *(MZ\d{3}\+?|MZ\d{3} 4G|Xoom|XOOM[^;/]*) Build'
3189 device_replacement: 'Motorola $1'
3190 brand_replacement: 'Motorola'
3191 model_replacement: '$1'
3192 - regex: '; *(Milestone )(XT[^;/]*) Build'
3193 device_replacement: 'Motorola $1$2'
3194 brand_replacement: 'Motorola'
3195 model_replacement: '$2'
3196 - regex: '; *(Motoroi ?x|Droid X|DROIDX) Build'
3197 regex_flag: 'i'
3198 device_replacement: 'Motorola $1'
3199 brand_replacement: 'Motorola'
3200 model_replacement: 'DROID X'
3201 - regex: '; *(Droid[^;/]*|DROID[^;/]*|Milestone[^;/]*|Photon|Triumph|Devour|Titanium) Build'
3202 device_replacement: 'Motorola $1'
3203 brand_replacement: 'Motorola'
3204 model_replacement: '$1'
3205 - regex: '; *(A555|A85[34][^;/]*|A95[356]|ME[58]\d{2}\+?|ME600|ME632|ME722|MB\d{3}\+?|MT680|MT710|MT870|MT887|MT917|WX435|WX453|WX44[25]|XT\d{3,4}[A-Z\+]*|CL[iI]Q|CL[iI]Q XT) Build'
3206 device_replacement: '$1'
3207 brand_replacement: 'Motorola'
3208 model_replacement: '$1'
3209 - regex: '; *(Motorola MOT-|Motorola[ _\-]|MOT\-?)([^;/]+) Build'
3210 device_replacement: '$1$2'
3211 brand_replacement: 'Motorola'
3212 model_replacement: '$2'
3213 - regex: '; *(Moto[_ ]?|MOT\-)([^;/]+) Build'
3214 device_replacement: '$1$2'
3215 brand_replacement: 'Motorola'
3216 model_replacement: '$2'
3217
3218 #########
3219 # MpMan
3220 # @ref: http://www.mpmaneurope.com
3221 #########
3222 - regex: '; *((?:MP[DQ]C|MPG\d{1,4}|MP\d{3,4}|MID(?:(?:10[234]|114|43|7[247]|8[24]|7)C|8[01]1))[^;/]*) Build'
3223 device_replacement: '$1'
3224 brand_replacement: 'Mpman'
3225 model_replacement: '$1'
3226
3227 #########
3228 # MSI
3229 # @ref: http://www.msi.com/product/windpad/
3230 #########
3231 - regex: '; *(?:MSI[ _])?(Primo\d+|Enjoy[ _\-][^;/]+) Build'
3232 regex_flag: 'i'
3233 device_replacement: '$1'
3234 brand_replacement: 'Msi'
3235 model_replacement: '$1'
3236
3237 #########
3238 # Multilaser
3239 # http://www.multilaser.com.br/listagem_produtos.php?cat=5
3240 #########
3241 - regex: '; *Multilaser[ _]([^;/]+) Build'
3242 device_replacement: '$1'
3243 brand_replacement: 'Multilaser'
3244 model_replacement: '$1'
3245
3246 #########
3247 # MyPhone
3248 # @ref: http://myphone.com.ph/
3249 #########
3250 - regex: '; *(My)[_]?(Pad)[ _]([^;/]+) Build'
3251 device_replacement: '$1$2 $3'
3252 brand_replacement: 'MyPhone'
3253 model_replacement: '$1$2 $3'
3254 - regex: '; *(My)\|?(Phone)[ _]([^;/]+) Build'
3255 device_replacement: '$1$2 $3'
3256 brand_replacement: 'MyPhone'
3257 model_replacement: '$3'
3258 - regex: '; *(A\d+)[ _](Duo)? Build'
3259 regex_flag: 'i'
3260 device_replacement: '$1 $2'
3261 brand_replacement: 'MyPhone'
3262 model_replacement: '$1 $2'
3263
3264 #########
3265 # Mytab
3266 # @ref: http://www.mytab.eu/en/category/mytab-products/
3267 #########
3268 - regex: '; *(myTab[^;/]*) Build'
3269 device_replacement: '$1'
3270 brand_replacement: 'Mytab'
3271 model_replacement: '$1'
3272
3273 #########
3274 # Nabi
3275 # @ref: https://www.nabitablet.com
3276 #########
3277 - regex: '; *(NABI2?-)([^;/]+) Build/'
3278 device_replacement: '$1$2'
3279 brand_replacement: 'Nabi'
3280 model_replacement: '$2'
3281
3282 #########
3283 # Nec Medias
3284 # @ref: http://www.n-keitai.com/
3285 #########
3286 - regex: '; *(N-\d+[CDE]) Build/'
3287 device_replacement: '$1'
3288 brand_replacement: 'Nec'
3289 model_replacement: '$1'
3290 - regex: '; ?(NEC-)(.*) Build/'
3291 device_replacement: '$1$2'
3292 brand_replacement: 'Nec'
3293 model_replacement: '$2'
3294 - regex: '; *(LT-NA7) Build/'
3295 device_replacement: '$1'
3296 brand_replacement: 'Nec'
3297 model_replacement: 'Lifetouch Note'
3298
3299 #########
3300 # Nextbook
3301 # @ref: http://nextbookusa.com
3302 #########
3303 - regex: '; *(NXM\d+[A-z0-9_]*|Next\d[A-z0-9_ \-]*|NEXT\d[A-z0-9_ \-]*|Nextbook [A-z0-9_ ]*|DATAM803HC|M805)(?: Build|[\);])'
3304 device_replacement: '$1'
3305 brand_replacement: 'Nextbook'
3306 model_replacement: '$1'
3307
3308 #########
3309 # Nokia
3310 # @ref: http://www.nokia.com
3311 #########
3312 - regex: '; *(Nokia)([ _\-]*)([^;/]*) Build'
3313 regex_flag: 'i'
3314 device_replacement: '$1$2$3'
3315 brand_replacement: 'Nokia'
3316 model_replacement: '$3'
3317
3318 #########
3319 # Nook
3320 # @ref:
3321 # TODO nook browser/1.0
3322 #########
3323 - regex: '; *(Nook ?|Barnes & Noble Nook |BN )([^;/]+) Build'
3324 device_replacement: '$1$2'
3325 brand_replacement: 'Nook'
3326 model_replacement: '$2'
3327 - regex: '; *(NOOK )?(BNRV200|BNRV200A|BNTV250|BNTV250A|BNTV400|BNTV600|LogicPD Zoom2) Build'
3328 device_replacement: '$1$2'
3329 brand_replacement: 'Nook'
3330 model_replacement: '$2'
3331 - regex: '; Build/(Nook)'
3332 device_replacement: '$1'
3333 brand_replacement: 'Nook'
3334 model_replacement: 'Tablet'
3335
3336 #########
3337 # Olivetti
3338 # @ref: http://www.olivetti.de/EN/Page/t02/view_html?idp=348
3339 #########
3340 - regex: '; *(OP110|OliPad[^;/]+) Build'
3341 device_replacement: 'Olivetti $1'
3342 brand_replacement: 'Olivetti'
3343 model_replacement: '$1'
3344
3345 #########
3346 # Omega
3347 # @ref: http://omega-technology.eu/en/produkty/346/tablets
3348 # @note: MID tablets might get matched by CobyKyros first
3349 # @models: (T107|MID(?:700[2-5]|7031|7108|7132|750[02]|8001|8500|9001|971[12])
3350 #########
3351 - regex: '; *OMEGA[ _\-](MID[^;/]+) Build'
3352 device_replacement: 'Omega $1'
3353 brand_replacement: 'Omega'
3354 model_replacement: '$1'
3355 - regex: '^(MID7500|MID\d+) Mozilla/5\.0 \(iPad;'
3356 device_replacement: 'Omega $1'
3357 brand_replacement: 'Omega'
3358 model_replacement: '$1'
3359
3360 #########
3361 # OpenPeak
3362 # @ref: https://support.google.com/googleplay/answer/1727131?hl=en
3363 #########
3364 - regex: '; *((?:CIUS|cius)[^;/]*) Build'
3365 device_replacement: 'Openpeak $1'
3366 brand_replacement: 'Openpeak'
3367 model_replacement: '$1'
3368
3369 #########
3370 # Oppo
3371 # @ref: http://en.oppo.com/products/
3372 #########
3373 - regex: '; *(Find ?(?:5|7a)|R8[012]\d{1,2}|T703\d{0,1}|U70\d{1,2}T?|X90\d{1,2}) Build'
3374 device_replacement: 'Oppo $1'
3375 brand_replacement: 'Oppo'
3376 model_replacement: '$1'
3377 - regex: '; *OPPO ?([^;/]+) Build/'
3378 device_replacement: 'Oppo $1'
3379 brand_replacement: 'Oppo'
3380 model_replacement: '$1'
3381
3382 #########
3383 # Odys
3384 # @ref: http://odys.de
3385 #########
3386 - regex: '; *(?:Odys\-|ODYS\-|ODYS )([^;/]+) Build'
3387 device_replacement: 'Odys $1'
3388 brand_replacement: 'Odys'
3389 model_replacement: '$1'
3390 - regex: '; *(SELECT) ?(7) Build'
3391 device_replacement: 'Odys $1 $2'
3392 brand_replacement: 'Odys'
3393 model_replacement: '$1 $2'
3394 - regex: '; *(PEDI)_(PLUS)_(W) Build'
3395 device_replacement: 'Odys $1 $2 $3'
3396 brand_replacement: 'Odys'
3397 model_replacement: '$1 $2 $3'
3398 # Weltbild - Tablet PC 4 = Cat Phoenix = Odys Tablet PC 4?
3399 - regex: '; *(AEON|BRAVIO|FUSION|FUSION2IN1|Genio|EOS10|IEOS[^;/]*|IRON|Loox|LOOX|LOOX Plus|Motion|NOON|NOON_PRO|NEXT|OPOS|PEDI[^;/]*|PRIME[^;/]*|STUDYTAB|TABLO|Tablet-PC-4|UNO_X8|XELIO[^;/]*|Xelio ?\d+ ?[Pp]ro|XENO10|XPRESS PRO) Build'
3400 device_replacement: 'Odys $1'
3401 brand_replacement: 'Odys'
3402 model_replacement: '$1'
3403
3404 #########
3405 # OnePlus
3406 # @ref https://oneplus.net/
3407 #########
3408 - regex: '; (ONE [a-zA-Z]\d+) Build/'
3409 device_replacement: 'OnePlus $1'
3410 brand_replacement: 'OnePlus'
3411 model_replacement: '$1'
3412 - regex: '; (ONEPLUS [a-zA-Z]\d+) Build/'
3413 device_replacement: 'OnePlus $1'
3414 brand_replacement: 'OnePlus'
3415 model_replacement: '$1'
3416
3417 #########
3418 # Orion
3419 # @ref: http://www.orion.ua/en/products/computer-products/tablet-pcs.html
3420 #########
3421 - regex: '; *(TP-\d+) Build/'
3422 device_replacement: 'Orion $1'
3423 brand_replacement: 'Orion'
3424 model_replacement: '$1'
3425
3426 #########
3427 # PackardBell
3428 # @ref: http://www.packardbell.com/pb/en/AE/content/productgroup/tablets
3429 #########
3430 - regex: '; *(G100W?) Build/'
3431 device_replacement: 'PackardBell $1'
3432 brand_replacement: 'PackardBell'
3433 model_replacement: '$1'
3434
3435 #########
3436 # Panasonic
3437 # @ref: http://panasonic.jp/mobile/
3438 # @models: T11, T21, T31, P11, P51, Eluga Power, Eluga DL1
3439 # @models: (tab) Toughpad FZ-A1, Toughpad JT-B1
3440 #########
3441 - regex: '; *(Panasonic)[_ ]([^;/]+) Build'
3442 device_replacement: '$1 $2'
3443 brand_replacement: '$1'
3444 model_replacement: '$2'
3445 # Toughpad
3446 - regex: '; *(FZ-A1B|JT-B1) Build'
3447 device_replacement: 'Panasonic $1'
3448 brand_replacement: 'Panasonic'
3449 model_replacement: '$1'
3450 # Eluga Power
3451 - regex: '; *(dL1|DL1) Build'
3452 device_replacement: 'Panasonic $1'
3453 brand_replacement: 'Panasonic'
3454 model_replacement: '$1'
3455
3456 #########
3457 # Pantech
3458 # @href: http://www.pantech.co.kr/en/prod/prodList.do?gbrand=PANTECH
3459 # @href: http://www.pantech.co.kr/en/prod/prodList.do?gbrand=VEGA
3460 # @models: ADR8995, ADR910L, ADR930VW, C790, CDM8992, CDM8999, IS06, IS11PT, P2000, P2020, P2030, P4100, P5000, P6010, P6020, P6030, P7000, P7040, P8000, P8010, P9020, P9050, P9060, P9070, P9090, PT001, PT002, PT003, TXT8040, TXT8045, VEGA PTL21
3461 #########
3462 - regex: '; *(SKY[ _])?(IM\-[AT]\d{3}[^;/]+).* Build/'
3463 device_replacement: 'Pantech $1$2'
3464 brand_replacement: 'Pantech'
3465 model_replacement: '$1$2'
3466 - regex: '; *((?:ADR8995|ADR910L|ADR930L|ADR930VW|PTL21|P8000)(?: 4G)?) Build/'
3467 device_replacement: '$1'
3468 brand_replacement: 'Pantech'
3469 model_replacement: '$1'
3470 - regex: '; *Pantech([^;/]+).* Build/'
3471 device_replacement: 'Pantech $1'
3472 brand_replacement: 'Pantech'
3473 model_replacement: '$1'
3474
3475 #########
3476 # Papayre
3477 # @ref: http://grammata.es/
3478 #########
3479 - regex: '; *(papyre)[ _\-]([^;/]+) Build/'
3480 regex_flag: 'i'
3481 device_replacement: '$1 $2'
3482 brand_replacement: 'Papyre'
3483 model_replacement: '$2'
3484
3485 #########
3486 # Pearl
3487 # @ref: http://www.pearl.de/c-1540.shtml
3488 #########
3489 - regex: '; *(?:Touchlet )?(X10\.[^;/]+) Build/'
3490 device_replacement: 'Pearl $1'
3491 brand_replacement: 'Pearl'
3492 model_replacement: '$1'
3493
3494 #########
3495 # Phicomm
3496 # @ref: http://www.phicomm.com.cn/
3497 #########
3498 - regex: '; PHICOMM (i800) Build/'
3499 device_replacement: 'Phicomm $1'
3500 brand_replacement: 'Phicomm'
3501 model_replacement: '$1'
3502 - regex: '; PHICOMM ([^;/]+) Build/'
3503 device_replacement: 'Phicomm $1'
3504 brand_replacement: 'Phicomm'
3505 model_replacement: '$1'
3506 - regex: '; *(FWS\d{3}[^;/]+) Build/'
3507 device_replacement: 'Phicomm $1'
3508 brand_replacement: 'Phicomm'
3509 model_replacement: '$1'
3510
3511 #########
3512 # Philips
3513 # @ref: http://www.support.philips.com/support/catalog/products.jsp?_dyncharset=UTF-8&country=&categoryid=MOBILE_PHONES_SMART_SU_CN_CARE&userLanguage=en&navCount=2&groupId=PC_PRODUCTS_AND_PHONES_GR_CN_CARE&catalogType=&navAction=push&userCountry=cn&title=Smartphones&cateId=MOBILE_PHONES_CA_CN_CARE
3514 # @TODO: Philips Tablets User-Agents missing!
3515 # @ref: http://www.support.philips.com/support/catalog/products.jsp?_dyncharset=UTF-8&country=&categoryid=ENTERTAINMENT_TABLETS_SU_CN_CARE&userLanguage=en&navCount=0&groupId=&catalogType=&navAction=push&userCountry=cn&title=Entertainment+Tablets&cateId=TABLETS_CA_CN_CARE
3516 #########
3517 # @note: this a best guess according to available philips models. Need more User-Agents
3518 - regex: '; *(D633|D822|D833|T539|T939|V726|W335|W336|W337|W3568|W536|W5510|W626|W632|W6350|W6360|W6500|W732|W736|W737|W7376|W820|W832|W8355|W8500|W8510|W930) Build'
3519 device_replacement: '$1'
3520 brand_replacement: 'Philips'
3521 model_replacement: '$1'
3522 - regex: '; *(?:Philips|PHILIPS)[ _]([^;/]+) Build'
3523 device_replacement: 'Philips $1'
3524 brand_replacement: 'Philips'
3525 model_replacement: '$1'
3526
3527 #########
3528 # Pipo
3529 # @ref: http://www.pipo.cn/En/
3530 #########
3531 - regex: 'Android 4\..*; *(M[12356789]|U[12368]|S[123])\ ?(pro)? Build'
3532 device_replacement: 'Pipo $1$2'
3533 brand_replacement: 'Pipo'
3534 model_replacement: '$1$2'
3535
3536 #########
3537 # Ployer
3538 # @ref: http://en.ployer.cn/
3539 #########
3540 - regex: '; *(MOMO[^;/]+) Build'
3541 device_replacement: '$1'
3542 brand_replacement: 'Ployer'
3543 model_replacement: '$1'
3544
3545 #########
3546 # Polaroid/ Acho
3547 # @ref: http://polaroidstore.com/store/start.asp?category_id=382&category_id2=0&order=title&filter1=&filter2=&filter3=&view=all
3548 #########
3549 - regex: '; *(?:Polaroid[ _])?((?:MIDC\d{3,}|PMID\d{2,}|PTAB\d{3,})[^;/]*)(\/[^;/]*)? Build/'
3550 device_replacement: '$1'
3551 brand_replacement: 'Polaroid'
3552 model_replacement: '$1'
3553 - regex: '; *(?:Polaroid )(Tablet) Build/'
3554 device_replacement: '$1'
3555 brand_replacement: 'Polaroid'
3556 model_replacement: '$1'
3557
3558 #########
3559 # Pomp
3560 # @ref: http://pompmobileshop.com/
3561 #########
3562 #~ TODO
3563 - regex: '; *(POMP)[ _\-](.+?) *(?:Build|[;/\)])'
3564 device_replacement: '$1 $2'
3565 brand_replacement: 'Pomp'
3566 model_replacement: '$2'
3567
3568 #########
3569 # Positivo
3570 # @ref: http://www.positivoinformatica.com.br/www/pessoal/tablet-ypy/
3571 #########
3572 - regex: '; *(TB07STA|TB10STA|TB07FTA|TB10FTA) Build/'
3573 device_replacement: '$1'
3574 brand_replacement: 'Positivo'
3575 model_replacement: '$1'
3576 - regex: '; *(?:Positivo )?((?:YPY|Ypy)[^;/]+) Build/'
3577 device_replacement: '$1'
3578 brand_replacement: 'Positivo'
3579 model_replacement: '$1'
3580
3581 #########
3582 # POV
3583 # @ref: http://www.pointofview-online.com/default2.php
3584 # @TODO: Smartphone Models MOB-3515, MOB-5045-B missing
3585 #########
3586 - regex: '; *(MOB-[^;/]+) Build/'
3587 device_replacement: '$1'
3588 brand_replacement: 'POV'
3589 model_replacement: '$1'
3590 - regex: '; *POV[ _\-]([^;/]+) Build/'
3591 device_replacement: 'POV $1'
3592 brand_replacement: 'POV'
3593 model_replacement: '$1'
3594 - regex: '; *((?:TAB-PLAYTAB|TAB-PROTAB|PROTAB|PlayTabPro|Mobii[ _\-]|TAB-P)[^;/]*) Build/'
3595 device_replacement: 'POV $1'
3596 brand_replacement: 'POV'
3597 model_replacement: '$1'
3598
3599 #########
3600 # Prestigio
3601 # @ref: http://www.prestigio.com/catalogue/MultiPhones
3602 # @ref: http://www.prestigio.com/catalogue/MultiPads
3603 #########
3604 - regex: '; *(?:Prestigio )?((?:PAP|PMP)\d[^;/]+) Build/'
3605 device_replacement: 'Prestigio $1'
3606 brand_replacement: 'Prestigio'
3607 model_replacement: '$1'
3608
3609 #########
3610 # Proscan
3611 # @ref: http://www.proscanvideo.com/products-search.asp?itemClass=TABLET&itemnmbr=
3612 #########
3613 - regex: '; *(PLT[0-9]{4}.*) Build/'
3614 device_replacement: '$1'
3615 brand_replacement: 'Proscan'
3616 model_replacement: '$1'
3617
3618 #########
3619 # QMobile
3620 # @ref: http://www.qmobile.com.pk/
3621 #########
3622 - regex: '; *(A2|A5|A8|A900)_?(Classic)? Build'
3623 device_replacement: '$1 $2'
3624 brand_replacement: 'Qmobile'
3625 model_replacement: '$1 $2'
3626 - regex: '; *(Q[Mm]obile)_([^_]+)_([^_]+) Build'
3627 device_replacement: 'Qmobile $2 $3'
3628 brand_replacement: 'Qmobile'
3629 model_replacement: '$2 $3'
3630 - regex: '; *(Q\-?[Mm]obile)[_ ](A[^;/]+) Build'
3631 device_replacement: 'Qmobile $2'
3632 brand_replacement: 'Qmobile'
3633 model_replacement: '$2'
3634
3635 #########
3636 # Qmobilevn
3637 # @ref: http://qmobile.vn/san-pham.html
3638 #########
3639 - regex: '; *(Q\-Smart)[ _]([^;/]+) Build/'
3640 device_replacement: '$1 $2'
3641 brand_replacement: 'Qmobilevn'
3642 model_replacement: '$2'
3643 - regex: '; *(Q\-?[Mm]obile)[ _\-](S[^;/]+) Build/'
3644 device_replacement: '$1 $2'
3645 brand_replacement: 'Qmobilevn'
3646 model_replacement: '$2'
3647
3648 #########
3649 # Quanta
3650 # @ref: ?
3651 #########
3652 - regex: '; *(TA1013) Build'
3653 device_replacement: '$1'
3654 brand_replacement: 'Quanta'
3655 model_replacement: '$1'
3656
3657 #########
3658 # RCA
3659 # @ref: http://rcamobilephone.com/
3660 #########
3661 - regex: '; (RCT\w+) Build/'
3662 device_replacement: '$1'
3663 brand_replacement: 'RCA'
3664 model_replacement: '$1'
3665 - regex: '; RCA (\w+) Build/'
3666 device_replacement: 'RCA $1'
3667 brand_replacement: 'RCA'
3668 model_replacement: '$1'
3669
3670 #########
3671 # Rockchip
3672 # @ref: http://www.rock-chips.com/a/cn/product/index.html
3673 # @note: manufacturer sells chipsets - I assume that these UAs are dev-boards
3674 #########
3675 - regex: '; *(RK\d+),? Build/'
3676 device_replacement: '$1'
3677 brand_replacement: 'Rockchip'
3678 model_replacement: '$1'
3679 - regex: ' Build/(RK\d+)'
3680 device_replacement: '$1'
3681 brand_replacement: 'Rockchip'
3682 model_replacement: '$1'
3683
3684 #########
3685 # Samsung Android Devices
3686 # @ref: http://www.samsung.com/us/mobile/cell-phones/all-products
3687 #########
3688 - regex: '; *(SAMSUNG |Samsung )?((?:Galaxy (?:Note II|S\d)|GT-I9082|GT-I9205|GT-N7\d{3}|SM-N9005)[^;/]*)\/?[^;/]* Build/'
3689 device_replacement: 'Samsung $1$2'
3690 brand_replacement: 'Samsung'
3691 model_replacement: '$2'
3692 - regex: '; *(Google )?(Nexus [Ss](?: 4G)?) Build/'
3693 device_replacement: 'Samsung $1$2'
3694 brand_replacement: 'Samsung'
3695 model_replacement: '$2'
3696 - regex: '; *(SAMSUNG |Samsung )([^\/]*)\/[^ ]* Build/'
3697 device_replacement: 'Samsung $2'
3698 brand_replacement: 'Samsung'
3699 model_replacement: '$2'
3700 - regex: '; *(Galaxy(?: Ace| Nexus| S ?II+|Nexus S| with MCR 1.2| Mini Plus 4G)?) Build/'
3701 device_replacement: 'Samsung $1'
3702 brand_replacement: 'Samsung'
3703 model_replacement: '$1'
3704 - regex: '; *(SAMSUNG[ _\-] *)+([^;/]+) Build'
3705 device_replacement: 'Samsung $2'
3706 brand_replacement: 'Samsung'
3707 model_replacement: '$2'
3708 - regex: '; *(SAMSUNG-)?(GT\-[BINPS]\d{4}[^\/]*)(\/[^ ]*) Build'
3709 device_replacement: 'Samsung $1$2$3'
3710 brand_replacement: 'Samsung'
3711 model_replacement: '$2'
3712 - regex: '(?:; *|^)((?:GT\-[BIiNPS]\d{4}|I9\d{2}0[A-Za-z\+]?\b)[^;/\)]*?)(?:Build|Linux|MIUI|[;/\)])'
3713 device_replacement: 'Samsung $1'
3714 brand_replacement: 'Samsung'
3715 model_replacement: '$1'
3716 - regex: '; (SAMSUNG-)([A-Za-z0-9\-]+).* Build/'
3717 device_replacement: 'Samsung $1$2'
3718 brand_replacement: 'Samsung'
3719 model_replacement: '$2'
3720 - regex: '; *((?:SCH|SGH|SHV|SHW|SPH|SC|SM)\-[A-Za-z0-9 ]+)(/?[^ ]*)? Build'
3721 device_replacement: 'Samsung $1'
3722 brand_replacement: 'Samsung'
3723 model_replacement: '$1'
3724 - regex: ' ((?:SCH)\-[A-Za-z0-9 ]+)(/?[^ ]*)? Build'
3725 device_replacement: 'Samsung $1'
3726 brand_replacement: 'Samsung'
3727 model_replacement: '$1'
3728 - regex: '; *(Behold ?(?:2|II)|YP\-G[^;/]+|EK-GC100|SCL21|I9300) Build'
3729 device_replacement: 'Samsung $1'
3730 brand_replacement: 'Samsung'
3731 model_replacement: '$1'
3732
3733 #########
3734 # Sharp
3735 # @ref: http://www.sharp-phone.com/en/index.html
3736 # @ref: http://www.android.com/devices/?country=all&m=sharp
3737 #########
3738 - regex: '; *(SH\-?\d\d[^;/]+|SBM\d[^;/]+) Build'
3739 device_replacement: '$1'
3740 brand_replacement: 'Sharp'
3741 model_replacement: '$1'
3742 - regex: '; *(SHARP[ -])([^;/]+) Build'
3743 device_replacement: '$1$2'
3744 brand_replacement: 'Sharp'
3745 model_replacement: '$2'
3746
3747 #########
3748 # Simvalley
3749 # @ref: http://www.simvalley-mobile.de/
3750 #########
3751 - regex: '; *(SPX[_\-]\d[^;/]*) Build/'
3752 device_replacement: '$1'
3753 brand_replacement: 'Simvalley'
3754 model_replacement: '$1'
3755 - regex: '; *(SX7\-PEARL\.GmbH) Build/'
3756 device_replacement: '$1'
3757 brand_replacement: 'Simvalley'
3758 model_replacement: '$1'
3759 - regex: '; *(SP[T]?\-\d{2}[^;/]*) Build/'
3760 device_replacement: '$1'
3761 brand_replacement: 'Simvalley'
3762 model_replacement: '$1'
3763
3764 #########
3765 # SK Telesys
3766 # @ref: http://www.sk-w.com/phone/phone_list.jsp
3767 # @ref: http://www.android.com/devices/?country=all&m=sk-telesys
3768 #########
3769 - regex: '; *(SK\-.*) Build/'
3770 device_replacement: '$1'
3771 brand_replacement: 'SKtelesys'
3772 model_replacement: '$1'
3773
3774 #########
3775 # Skytex
3776 # @ref: http://skytex.com/android
3777 #########
3778 - regex: '; *(?:SKYTEX|SX)-([^;/]+) Build'
3779 device_replacement: '$1'
3780 brand_replacement: 'Skytex'
3781 model_replacement: '$1'
3782 - regex: '; *(IMAGINE [^;/]+) Build'
3783 device_replacement: '$1'
3784 brand_replacement: 'Skytex'
3785 model_replacement: '$1'
3786
3787 #########
3788 # SmartQ
3789 # @ref: http://en.smartdevices.com.cn/Products/
3790 # @models: Z8, X7, U7H, U7, T30, T20, Ten3, V5-II, T7-3G, SmartQ5, K7, S7, Q8, T19, Ten2, Ten, R10, T7, R7, V5, V7, SmartQ7
3791 #########
3792 - regex: '; *(SmartQ) ?([^;/]+) Build/'
3793 device_replacement: '$1 $2'
3794 brand_replacement: '$1'
3795 model_replacement: '$2'
3796
3797 #########
3798 # Smartbitt
3799 # @ref: http://www.smartbitt.com/
3800 # @missing: SBT Useragents
3801 #########
3802 - regex: '; *(WF7C|WF10C|SBT[^;/]+) Build'
3803 device_replacement: '$1'
3804 brand_replacement: 'Smartbitt'
3805 model_replacement: '$1'
3806
3807 #########
3808 # Softbank (Operator Branded Devices)
3809 # @ref: http://www.ipentec.com/document/document.aspx?page=android-useragent
3810 #########
3811 - regex: '; *(SBM(?:003SH|005SH|006SH|007SH|102SH)) Build'
3812 device_replacement: '$1'
3813 brand_replacement: 'Sharp'
3814 model_replacement: '$1'
3815 - regex: '; *(003P|101P|101P11C|102P) Build'
3816 device_replacement: '$1'
3817 brand_replacement: 'Panasonic'
3818 model_replacement: '$1'
3819 - regex: '; *(00\dZ) Build/'
3820 device_replacement: '$1'
3821 brand_replacement: 'ZTE'
3822 model_replacement: '$1'
3823 - regex: '; HTC(X06HT) Build'
3824 device_replacement: '$1'
3825 brand_replacement: 'HTC'
3826 model_replacement: '$1'
3827 - regex: '; *(001HT|X06HT) Build'
3828 device_replacement: '$1'
3829 brand_replacement: 'HTC'
3830 model_replacement: '$1'
3831 - regex: '; *(201M) Build'
3832 device_replacement: '$1'
3833 brand_replacement: 'Motorola'
3834 model_replacement: 'XT902'
3835
3836 #########
3837 # Trekstor
3838 # @ref: http://www.trekstor.co.uk/surftabs-en.html
3839 # @note: Must come before SonyEricsson
3840 #########
3841 - regex: '; *(ST\d{4}.*)Build/ST'
3842 device_replacement: 'Trekstor $1'
3843 brand_replacement: 'Trekstor'
3844 model_replacement: '$1'
3845 - regex: '; *(ST\d{4}.*) Build/'
3846 device_replacement: 'Trekstor $1'
3847 brand_replacement: 'Trekstor'
3848 model_replacement: '$1'
3849
3850 #########
3851 # SonyEricsson
3852 # @note: Must come before nokia since they also use symbian
3853 # @ref: http://www.android.com/devices/?country=all&m=sony-ericssons
3854 # @TODO: type!
3855 #########
3856 # android matchers
3857 - regex: '; *(Sony ?Ericsson ?)([^;/]+) Build'
3858 device_replacement: '$1$2'
3859 brand_replacement: 'SonyEricsson'
3860 model_replacement: '$2'
3861 - regex: '; *((?:SK|ST|E|X|LT|MK|MT|WT)\d{2}[a-z0-9]*(?:-o)?|R800i|U20i) Build'
3862 device_replacement: '$1'
3863 brand_replacement: 'SonyEricsson'
3864 model_replacement: '$1'
3865 # TODO X\d+ is wrong
3866 - regex: '; *(Xperia (?:A8|Arc|Acro|Active|Live with Walkman|Mini|Neo|Play|Pro|Ray|X\d+)[^;/]*) Build'
3867 regex_flag: 'i'
3868 device_replacement: '$1'
3869 brand_replacement: 'SonyEricsson'
3870 model_replacement: '$1'
3871
3872 #########
3873 # Sony
3874 # @ref: http://www.sonymobile.co.jp/index.html
3875 # @ref: http://www.sonymobile.com/global-en/products/phones/
3876 # @ref: http://www.sony.jp/tablet/
3877 #########
3878 - regex: '; Sony (Tablet[^;/]+) Build'
3879 device_replacement: 'Sony $1'
3880 brand_replacement: 'Sony'
3881 model_replacement: '$1'
3882 - regex: '; Sony ([^;/]+) Build'
3883 device_replacement: 'Sony $1'
3884 brand_replacement: 'Sony'
3885 model_replacement: '$1'
3886 - regex: '; *(Sony)([A-Za-z0-9\-]+) Build'
3887 device_replacement: '$1 $2'
3888 brand_replacement: '$1'
3889 model_replacement: '$2'
3890 - regex: '; *(Xperia [^;/]+) Build'
3891 device_replacement: '$1'
3892 brand_replacement: 'Sony'
3893 model_replacement: '$1'
3894 - regex: '; *(C(?:1[0-9]|2[0-9]|53|55|6[0-9])[0-9]{2}|D[25]\d{3}|D6[56]\d{2}) Build'
3895 device_replacement: '$1'
3896 brand_replacement: 'Sony'
3897 model_replacement: '$1'
3898 - regex: '; *(SGP\d{3}|SGPT\d{2}) Build'
3899 device_replacement: '$1'
3900 brand_replacement: 'Sony'
3901 model_replacement: '$1'
3902 - regex: '; *(NW-Z1000Series) Build'
3903 device_replacement: '$1'
3904 brand_replacement: 'Sony'
3905 model_replacement: '$1'
3906
3907 ##########
3908 # Sony PlayStation
3909 # @ref: http://playstation.com
3910 # The Vita spoofs the Kindle
3911 ##########
3912 - regex: 'PLAYSTATION 3'
3913 device_replacement: 'PlayStation 3'
3914 brand_replacement: 'Sony'
3915 model_replacement: 'PlayStation 3'
3916 - regex: '(PlayStation (?:Portable|Vita|\d+))'
3917 device_replacement: '$1'
3918 brand_replacement: 'Sony'
3919 model_replacement: '$1'
3920
3921 #########
3922 # Spice
3923 # @ref: http://www.spicemobilephones.co.in/
3924 #########
3925 - regex: '; *((?:CSL_Spice|Spice|SPICE|CSL)[ _\-]?)?([Mm][Ii])([ _\-])?(\d{3}[^;/]*) Build/'
3926 device_replacement: '$1$2$3$4'
3927 brand_replacement: 'Spice'
3928 model_replacement: 'Mi$4'
3929
3930 #########
3931 # Sprint (Operator Branded Devices)
3932 # @ref:
3933 #########
3934 - regex: '; *(Sprint )(.+?) *(?:Build|[;/])'
3935 device_replacement: '$1$2'
3936 brand_replacement: 'Sprint'
3937 model_replacement: '$2'
3938 - regex: '\b(Sprint)[: ]([^;,/ ]+)'
3939 device_replacement: '$1$2'
3940 brand_replacement: 'Sprint'
3941 model_replacement: '$2'
3942
3943 #########
3944 # Tagi
3945 # @ref: ??
3946 #########
3947 - regex: '; *(TAGI[ ]?)(MID) ?([^;/]+) Build/'
3948 device_replacement: '$1$2$3'
3949 brand_replacement: 'Tagi'
3950 model_replacement: '$2$3'
3951
3952 #########
3953 # Tecmobile
3954 # @ref: http://www.tecmobile.com/
3955 #########
3956 - regex: '; *(Oyster500|Opal 800) Build'
3957 device_replacement: 'Tecmobile $1'
3958 brand_replacement: 'Tecmobile'
3959 model_replacement: '$1'
3960
3961 #########
3962 # Tecno
3963 # @ref: www.tecno-mobile.com/‎
3964 #########
3965 - regex: '; *(TECNO[ _])([^;/]+) Build/'
3966 device_replacement: '$1$2'
3967 brand_replacement: 'Tecno'
3968 model_replacement: '$2'
3969
3970 #########
3971 # Telechips, Techvision evaluation boards
3972 # @ref:
3973 #########
3974 - regex: '; *Android for (Telechips|Techvision) ([^ ]+) '
3975 regex_flag: 'i'
3976 device_replacement: '$1 $2'
3977 brand_replacement: '$1'
3978 model_replacement: '$2'
3979
3980 #########
3981 # Telstra
3982 # @ref: http://www.telstra.com.au/home-phone/thub-2/
3983 # @ref: https://support.google.com/googleplay/answer/1727131?hl=en
3984 #########
3985 - regex: '; *(T-Hub2) Build/'
3986 device_replacement: '$1'
3987 brand_replacement: 'Telstra'
3988 model_replacement: '$1'
3989
3990 #########
3991 # Terra
3992 # @ref: http://www.wortmann.de/
3993 #########
3994 - regex: '; *(PAD) ?(100[12]) Build/'
3995 device_replacement: 'Terra $1$2'
3996 brand_replacement: 'Terra'
3997 model_replacement: '$1$2'
3998
3999 #########
4000 # Texet
4001 # @ref: http://www.texet.ru/tablet/
4002 #########
4003 - regex: '; *(T[BM]-\d{3}[^;/]+) Build/'
4004 device_replacement: '$1'
4005 brand_replacement: 'Texet'
4006 model_replacement: '$1'
4007
4008 #########
4009 # Thalia
4010 # @ref: http://www.thalia.de/shop/tolino-shine-ereader/show/
4011 #########
4012 - regex: '; *(tolino [^;/]+) Build'
4013 device_replacement: '$1'
4014 brand_replacement: 'Thalia'
4015 model_replacement: '$1'
4016 - regex: '; *Build/.* (TOLINO_BROWSER)'
4017 device_replacement: '$1'
4018 brand_replacement: 'Thalia'
4019 model_replacement: 'Tolino Shine'
4020
4021 #########
4022 # Thl
4023 # @ref: http://en.thl.com.cn/Mobile
4024 # @ref: http://thlmobilestore.com
4025 #########
4026 - regex: '; *(?:CJ[ -])?(ThL|THL)[ -]([^;/]+) Build/'
4027 device_replacement: '$1 $2'
4028 brand_replacement: 'Thl'
4029 model_replacement: '$2'
4030 - regex: '; *(T100|T200|T5|W100|W200|W8s) Build/'
4031 device_replacement: '$1'
4032 brand_replacement: 'Thl'
4033 model_replacement: '$1'
4034
4035 #########
4036 # T-Mobile (Operator Branded Devices)
4037 #########
4038 # @ref: https://en.wikipedia.org/wiki/HTC_Hero
4039 - regex: '; *(T-Mobile[ _]G2[ _]Touch) Build'
4040 device_replacement: '$1'
4041 brand_replacement: 'HTC'
4042 model_replacement: 'Hero'
4043 # @ref: https://en.wikipedia.org/wiki/HTC_Desire_Z
4044 - regex: '; *(T-Mobile[ _]G2) Build'
4045 device_replacement: '$1'
4046 brand_replacement: 'HTC'
4047 model_replacement: 'Desire Z'
4048 - regex: '; *(T-Mobile myTouch Q) Build'
4049 device_replacement: '$1'
4050 brand_replacement: 'Huawei'
4051 model_replacement: 'U8730'
4052 - regex: '; *(T-Mobile myTouch) Build'
4053 device_replacement: '$1'
4054 brand_replacement: 'Huawei'
4055 model_replacement: 'U8680'
4056 - regex: '; *(T-Mobile_Espresso) Build'
4057 device_replacement: '$1'
4058 brand_replacement: 'HTC'
4059 model_replacement: 'Espresso'
4060 - regex: '; *(T-Mobile G1) Build'
4061 device_replacement: '$1'
4062 brand_replacement: 'HTC'
4063 model_replacement: 'Dream'
4064 - regex: '\b(T-Mobile ?)?(myTouch)[ _]?([34]G)[ _]?([^\/]*) (?:Mozilla|Build)'
4065 device_replacement: '$1$2 $3 $4'
4066 brand_replacement: 'HTC'
4067 model_replacement: '$2 $3 $4'
4068 - regex: '\b(T-Mobile)_([^_]+)_(.*) Build'
4069 device_replacement: '$1 $2 $3'
4070 brand_replacement: 'Tmobile'
4071 model_replacement: '$2 $3'
4072 - regex: '\b(T-Mobile)[_ ]?(.*?)Build'
4073 device_replacement: '$1 $2'
4074 brand_replacement: 'Tmobile'
4075 model_replacement: '$2'
4076
4077 #########
4078 # Tomtec
4079 # @ref: http://www.tom-tec.eu/pages/tablets.php
4080 #########
4081 - regex: ' (ATP[0-9]{4}) Build'
4082 device_replacement: '$1'
4083 brand_replacement: 'Tomtec'
4084 model_replacement: '$1'
4085
4086 #########
4087 # Tooky
4088 # @ref: http://www.tookymobile.com/
4089 #########
4090 - regex: ' *(TOOKY)[ _\-]([^;/]+) ?(?:Build|;)'
4091 regex_flag: 'i'
4092 device_replacement: '$1 $2'
4093 brand_replacement: 'Tooky'
4094 model_replacement: '$2'
4095
4096 #########
4097 # Toshiba
4098 # @ref: http://www.toshiba.co.jp/
4099 # @missing: LT170, Thrive 7, TOSHIBA STB10
4100 #########
4101 - regex: '\b(TOSHIBA_AC_AND_AZ|TOSHIBA_FOLIO_AND_A|FOLIO_AND_A)'
4102 device_replacement: '$1'
4103 brand_replacement: 'Toshiba'
4104 model_replacement: 'Folio 100'
4105 - regex: '; *([Ff]olio ?100) Build/'
4106 device_replacement: '$1'
4107 brand_replacement: 'Toshiba'
4108 model_replacement: 'Folio 100'
4109 - regex: '; *(AT[0-9]{2,3}(?:\-A|LE\-A|PE\-A|SE|a)?|AT7-A|AT1S0|Hikari-iFrame/WDPF-[^;/]+|THRiVE|Thrive) Build/'
4110 device_replacement: 'Toshiba $1'
4111 brand_replacement: 'Toshiba'
4112 model_replacement: '$1'
4113
4114 #########
4115 # Touchmate
4116 # @ref: http://touchmatepc.com/new/
4117 #########
4118 - regex: '; *(TM-MID\d+[^;/]+|TOUCHMATE|MID-750) Build'
4119 device_replacement: '$1'
4120 brand_replacement: 'Touchmate'
4121 model_replacement: '$1'
4122 # @todo: needs verification user-agents missing
4123 - regex: '; *(TM-SM\d+[^;/]+) Build'
4124 device_replacement: '$1'
4125 brand_replacement: 'Touchmate'
4126 model_replacement: '$1'
4127
4128 #########
4129 # Treq
4130 # @ref: http://www.treq.co.id/product
4131 #########
4132 - regex: '; *(A10 [Bb]asic2?) Build/'
4133 device_replacement: '$1'
4134 brand_replacement: 'Treq'
4135 model_replacement: '$1'
4136 - regex: '; *(TREQ[ _\-])([^;/]+) Build'
4137 regex_flag: 'i'
4138 device_replacement: '$1$2'
4139 brand_replacement: 'Treq'
4140 model_replacement: '$2'
4141
4142 #########
4143 # Umeox
4144 # @ref: http://umeox.com/
4145 # @models: A936|A603|X-5|X-3
4146 #########
4147 # @todo: guessed markers
4148 - regex: '; *(X-?5|X-?3) Build/'
4149 device_replacement: '$1'
4150 brand_replacement: 'Umeox'
4151 model_replacement: '$1'
4152 # @todo: guessed markers
4153 - regex: '; *(A502\+?|A936|A603|X1|X2) Build/'
4154 device_replacement: '$1'
4155 brand_replacement: 'Umeox'
4156 model_replacement: '$1'
4157
4158 #########
4159 # Versus
4160 # @ref: http://versusuk.com/support.html
4161 #########
4162 - regex: '(TOUCH(?:TAB|PAD).+?) Build/'
4163 regex_flag: 'i'
4164 device_replacement: 'Versus $1'
4165 brand_replacement: 'Versus'
4166 model_replacement: '$1'
4167
4168 #########
4169 # Vertu
4170 # @ref: http://www.vertu.com/
4171 #########
4172 - regex: '(VERTU) ([^;/]+) Build/'
4173 device_replacement: '$1 $2'
4174 brand_replacement: 'Vertu'
4175 model_replacement: '$2'
4176
4177 #########
4178 # Videocon
4179 # @ref: http://www.videoconmobiles.com
4180 #########
4181 - regex: '; *(Videocon)[ _\-]([^;/]+) *(?:Build|;)'
4182 device_replacement: '$1 $2'
4183 brand_replacement: 'Videocon'
4184 model_replacement: '$2'
4185 - regex: ' (VT\d{2}[A-Za-z]*) Build'
4186 device_replacement: '$1'
4187 brand_replacement: 'Videocon'
4188 model_replacement: '$1'
4189
4190 #########
4191 # Viewsonic
4192 # @ref: http://viewsonic.com
4193 #########
4194 - regex: '; *((?:ViewPad|ViewPhone|VSD)[^;/]+) Build/'
4195 device_replacement: '$1'
4196 brand_replacement: 'Viewsonic'
4197 model_replacement: '$1'
4198 - regex: '; *(ViewSonic-)([^;/]+) Build/'
4199 device_replacement: '$1$2'
4200 brand_replacement: 'Viewsonic'
4201 model_replacement: '$2'
4202 - regex: '; *(GTablet.*) Build/'
4203 device_replacement: '$1'
4204 brand_replacement: 'Viewsonic'
4205 model_replacement: '$1'
4206
4207 #########
4208 # vivo
4209 # @ref: http://vivo.cn/
4210 #########
4211 - regex: '; *([Vv]ivo)[ _]([^;/]+) Build'
4212 device_replacement: '$1 $2'
4213 brand_replacement: 'vivo'
4214 model_replacement: '$2'
4215
4216 #########
4217 # Vodafone (Operator Branded Devices)
4218 # @ref: ??
4219 #########
4220 - regex: '(Vodafone) (.*) Build/'
4221 device_replacement: '$1 $2'
4222 brand_replacement: '$1'
4223 model_replacement: '$2'
4224
4225 #########
4226 # Walton
4227 # @ref: http://www.waltonbd.com/
4228 #########
4229 - regex: '; *(?:Walton[ _\-])?(Primo[ _\-][^;/]+) Build'
4230 regex_flag: 'i'
4231 device_replacement: 'Walton $1'
4232 brand_replacement: 'Walton'
4233 model_replacement: '$1'
4234
4235 #########
4236 # Wiko
4237 # @ref: http://fr.wikomobile.com/collection.php?s=Smartphones
4238 #########
4239 - regex: '; *(?:WIKO[ \-])?(CINK\+?|BARRY|BLOOM|DARKFULL|DARKMOON|DARKNIGHT|DARKSIDE|FIZZ|HIGHWAY|IGGY|OZZY|RAINBOW|STAIRWAY|SUBLIM|WAX|CINK [^;/]+) Build/'
4240 regex_flag: 'i'
4241 device_replacement: 'Wiko $1'
4242 brand_replacement: 'Wiko'
4243 model_replacement: '$1'
4244
4245 #########
4246 # WellcoM
4247 # @ref: ??
4248 #########
4249 - regex: '; *WellcoM-([^;/]+) Build'
4250 device_replacement: 'Wellcom $1'
4251 brand_replacement: 'Wellcom'
4252 model_replacement: '$1'
4253
4254 ##########
4255 # WeTab
4256 # @ref: http://wetab.mobi/
4257 ##########
4258 - regex: '(?:(WeTab)-Browser|; (wetab) Build)'
4259 device_replacement: '$1'
4260 brand_replacement: 'WeTab'
4261 model_replacement: 'WeTab'
4262
4263 #########
4264 # Wolfgang
4265 # @ref: http://wolfgangmobile.com/
4266 #########
4267 - regex: '; *(AT-AS[^;/]+) Build'
4268 device_replacement: 'Wolfgang $1'
4269 brand_replacement: 'Wolfgang'
4270 model_replacement: '$1'
4271
4272 #########
4273 # Woxter
4274 # @ref: http://www.woxter.es/es-es/categories/index
4275 #########
4276 - regex: '; *(?:Woxter|Wxt) ([^;/]+) Build'
4277 device_replacement: 'Woxter $1'
4278 brand_replacement: 'Woxter'
4279 model_replacement: '$1'
4280
4281 #########
4282 # Yarvik Zania
4283 # @ref: http://yarvik.com
4284 #########
4285 - regex: '; *(?:Xenta |Luna )?(TAB[234][0-9]{2}|TAB0[78]-\d{3}|TAB0?9-\d{3}|TAB1[03]-\d{3}|SMP\d{2}-\d{3}) Build/'
4286 device_replacement: 'Yarvik $1'
4287 brand_replacement: 'Yarvik'
4288 model_replacement: '$1'
4289
4290 #########
4291 # Yifang
4292 # @note: Needs to be at the very last as manufacturer builds for other brands.
4293 # @ref: http://www.yifangdigital.com/
4294 # @models: M1010, M1011, M1007, M1008, M1005, M899, M899LP, M909, M8000,
4295 # M8001, M8002, M8003, M849, M815, M816, M819, M805, M878, M780LPW,
4296 # M778, M7000, M7000AD, M7000NBD, M7001, M7002, M7002KBD, M777, M767,
4297 # M789, M799, M769, M757, M755, M753, M752, M739, M729, M723, M712, M727
4298 #########
4299 - regex: '; *([A-Z]{2,4})(M\d{3,}[A-Z]{2})([^;\)\/]*)(?: Build|[;\)])'
4300 device_replacement: 'Yifang $1$2$3'
4301 brand_replacement: 'Yifang'
4302 model_replacement: '$2'
4303
4304 #########
4305 # XiaoMi
4306 # @ref: http://www.xiaomi.com/event/buyphone
4307 #########
4308 - regex: '; *((Mi|MI|HM|MI-ONE|Redmi)[ -](NOTE |Note )?[^;/]*) (Build|MIUI)/'
4309 device_replacement: 'XiaoMi $1'
4310 brand_replacement: 'XiaoMi'
4311 model_replacement: '$1'
4312
4313 #########
4314 # Xolo
4315 # @ref: http://www.xolo.in/
4316 #########
4317 - regex: '; *XOLO[ _]([^;/]*tab.*) Build'
4318 regex_flag: 'i'
4319 device_replacement: 'Xolo $1'
4320 brand_replacement: 'Xolo'
4321 model_replacement: '$1'
4322 - regex: '; *XOLO[ _]([^;/]+) Build'
4323 regex_flag: 'i'
4324 device_replacement: 'Xolo $1'
4325 brand_replacement: 'Xolo'
4326 model_replacement: '$1'
4327 - regex: '; *(q\d0{2,3}[a-z]?) Build'
4328 regex_flag: 'i'
4329 device_replacement: 'Xolo $1'
4330 brand_replacement: 'Xolo'
4331 model_replacement: '$1'
4332
4333 #########
4334 # Xoro
4335 # @ref: http://www.xoro.de/produkte/
4336 #########
4337 - regex: '; *(PAD ?[79]\d+[^;/]*|TelePAD\d+[^;/]) Build'
4338 device_replacement: 'Xoro $1'
4339 brand_replacement: 'Xoro'
4340 model_replacement: '$1'
4341
4342 #########
4343 # Zopo
4344 # @ref: http://www.zopomobiles.com/products.html
4345 #########
4346 - regex: '; *(?:(?:ZOPO|Zopo)[ _]([^;/]+)|(ZP ?(?:\d{2}[^;/]+|C2))|(C[2379])) Build'
4347 device_replacement: '$1$2$3'
4348 brand_replacement: 'Zopo'
4349 model_replacement: '$1$2$3'
4350
4351 #########
4352 # ZiiLabs
4353 # @ref: http://www.ziilabs.com/products/platforms/androidreferencetablets.php
4354 #########
4355 - regex: '; *(ZiiLABS) (Zii[^;/]*) Build'
4356 device_replacement: '$1 $2'
4357 brand_replacement: 'ZiiLabs'
4358 model_replacement: '$2'
4359 - regex: '; *(Zii)_([^;/]*) Build'
4360 device_replacement: '$1 $2'
4361 brand_replacement: 'ZiiLabs'
4362 model_replacement: '$2'
4363
4364 #########
4365 # ZTE
4366 # @ref: http://www.ztedevices.com/
4367 #########
4368 - regex: '; *(ARIZONA|(?:ATLAS|Atlas) W|D930|Grand (?:[SX][^;]*|Era|Memo[^;]*)|JOE|(?:Kis|KIS)\b[^;]*|Libra|Light [^;]*|N8[056][01]|N850L|N8000|N9[15]\d{2}|N9810|NX501|Optik|(?:Vip )Racer[^;]*|RacerII|RACERII|San Francisco[^;]*|V9[AC]|V55|V881|Z[679][0-9]{2}[A-z]?) Build'
4369 device_replacement: '$1'
4370 brand_replacement: 'ZTE'
4371 model_replacement: '$1'
4372 - regex: '; *([A-Z]\d+)_USA_[^;]* Build'
4373 device_replacement: '$1'
4374 brand_replacement: 'ZTE'
4375 model_replacement: '$1'
4376 - regex: '; *(SmartTab\d+)[^;]* Build'
4377 device_replacement: '$1'
4378 brand_replacement: 'ZTE'
4379 model_replacement: '$1'
4380 - regex: '; *(?:Blade|BLADE|ZTE-BLADE)([^;/]*) Build'
4381 device_replacement: 'ZTE Blade$1'
4382 brand_replacement: 'ZTE'
4383 model_replacement: 'Blade$1'
4384 - regex: '; *(?:Skate|SKATE|ZTE-SKATE)([^;/]*) Build'
4385 device_replacement: 'ZTE Skate$1'
4386 brand_replacement: 'ZTE'
4387 model_replacement: 'Skate$1'
4388 - regex: '; *(Orange |Optimus )(Monte Carlo|San Francisco) Build'
4389 device_replacement: '$1$2'
4390 brand_replacement: 'ZTE'
4391 model_replacement: '$1$2'
4392 - regex: '; *(?:ZXY-ZTE_|ZTE\-U |ZTE[\- _]|ZTE-C[_ ])([^;/]+) Build'
4393 device_replacement: 'ZTE $1'
4394 brand_replacement: 'ZTE'
4395 model_replacement: '$1'
4396 # operator specific
4397 - regex: '; (BASE) (lutea|Lutea 2|Tab[^;]*) Build'
4398 device_replacement: '$1 $2'
4399 brand_replacement: 'ZTE'
4400 model_replacement: '$1 $2'
4401 - regex: '; (Avea inTouch 2|soft stone|tmn smart a7|Movistar[ _]Link) Build'
4402 regex_flag: 'i'
4403 device_replacement: '$1'
4404 brand_replacement: 'ZTE'
4405 model_replacement: '$1'
4406 - regex: '; *(vp9plus)\)'
4407 device_replacement: '$1'
4408 brand_replacement: 'ZTE'
4409 model_replacement: '$1'
4410
4411 ##########
4412 # Zync
4413 # @ref: http://www.zync.in/index.php/our-products/tablet-phablets
4414 ##########
4415 - regex: '; ?(Cloud[ _]Z5|z1000|Z99 2G|z99|z930|z999|z990|z909|Z919|z900) Build/'
4416 device_replacement: '$1'
4417 brand_replacement: 'Zync'
4418 model_replacement: '$1'
4419
4420 ##########
4421 # Kindle
4422 # @note: Needs to be after Sony Playstation Vita as this UA contains Silk/3.2
4423 # @ref: https://developer.amazon.com/sdk/fire/specifications.html
4424 # @ref: http://amazonsilk.wordpress.com/useful-bits/silk-user-agent/
4425 ##########
4426 - regex: '; ?(KFOT|Kindle Fire) Build\b'
4427 device_replacement: 'Kindle Fire'
4428 brand_replacement: 'Amazon'
4429 model_replacement: 'Kindle Fire'
4430 - regex: '; ?(KFOTE|Amazon Kindle Fire2) Build\b'
4431 device_replacement: 'Kindle Fire 2'
4432 brand_replacement: 'Amazon'
4433 model_replacement: 'Kindle Fire 2'
4434 - regex: '; ?(KFTT) Build\b'
4435 device_replacement: 'Kindle Fire HD'
4436 brand_replacement: 'Amazon'
4437 model_replacement: 'Kindle Fire HD 7"'
4438 - regex: '; ?(KFJWI) Build\b'
4439 device_replacement: 'Kindle Fire HD 8.9" WiFi'
4440 brand_replacement: 'Amazon'
4441 model_replacement: 'Kindle Fire HD 8.9" WiFi'
4442 - regex: '; ?(KFJWA) Build\b'
4443 device_replacement: 'Kindle Fire HD 8.9" 4G'
4444 brand_replacement: 'Amazon'
4445 model_replacement: 'Kindle Fire HD 8.9" 4G'
4446 - regex: '; ?(KFSOWI) Build\b'
4447 device_replacement: 'Kindle Fire HD 7" WiFi'
4448 brand_replacement: 'Amazon'
4449 model_replacement: 'Kindle Fire HD 7" WiFi'
4450 - regex: '; ?(KFTHWI) Build\b'
4451 device_replacement: 'Kindle Fire HDX 7" WiFi'
4452 brand_replacement: 'Amazon'
4453 model_replacement: 'Kindle Fire HDX 7" WiFi'
4454 - regex: '; ?(KFTHWA) Build\b'
4455 device_replacement: 'Kindle Fire HDX 7" 4G'
4456 brand_replacement: 'Amazon'
4457 model_replacement: 'Kindle Fire HDX 7" 4G'
4458 - regex: '; ?(KFAPWI) Build\b'
4459 device_replacement: 'Kindle Fire HDX 8.9" WiFi'
4460 brand_replacement: 'Amazon'
4461 model_replacement: 'Kindle Fire HDX 8.9" WiFi'
4462 - regex: '; ?(KFAPWA) Build\b'
4463 device_replacement: 'Kindle Fire HDX 8.9" 4G'
4464 brand_replacement: 'Amazon'
4465 model_replacement: 'Kindle Fire HDX 8.9" 4G'
4466 - regex: '; ?Amazon ([^;/]+) Build\b'
4467 device_replacement: '$1'
4468 brand_replacement: 'Amazon'
4469 model_replacement: '$1'
4470 - regex: '; ?(Kindle) Build\b'
4471 device_replacement: 'Kindle'
4472 brand_replacement: 'Amazon'
4473 model_replacement: 'Kindle'
4474 - regex: '; ?(Silk)/(\d+)\.(\d+)(?:\.([0-9\-]+))? Build\b'
4475 device_replacement: 'Kindle Fire'
4476 brand_replacement: 'Amazon'
4477 model_replacement: 'Kindle Fire$2'
4478 - regex: ' (Kindle)/(\d+\.\d+)'
4479 device_replacement: 'Kindle'
4480 brand_replacement: 'Amazon'
4481 model_replacement: '$1 $2'
4482 - regex: ' (Silk|Kindle)/(\d+)\.'
4483 device_replacement: 'Kindle'
4484 brand_replacement: 'Amazon'
4485 model_replacement: 'Kindle'
4486
4487 #########
4488 # Devices from chinese manufacturer(s)
4489 # @note: identified by x-wap-profile http://218.249.47.94/Xianghe/.*
4490 #########
4491 - regex: '(sprd)\-([^/]+)/'
4492 device_replacement: '$1 $2'
4493 brand_replacement: '$1'
4494 model_replacement: '$2'
4495 # @ref: http://eshinechina.en.alibaba.com/
4496 - regex: '; *(H\d{2}00\+?) Build'
4497 device_replacement: '$1'
4498 brand_replacement: 'Hero'
4499 model_replacement: '$1'
4500 - regex: '; *(iphone|iPhone5) Build/'
4501 device_replacement: 'Xianghe $1'
4502 brand_replacement: 'Xianghe'
4503 model_replacement: '$1'
4504 - regex: '; *(e\d{4}[a-z]?_?v\d+|v89_[^;/]+)[^;/]+ Build/'
4505 device_replacement: 'Xianghe $1'
4506 brand_replacement: 'Xianghe'
4507 model_replacement: '$1'
4508
4509 #########
4510 # Cellular
4511 # @ref:
4512 # @note: Operator branded devices
4513 #########
4514 - regex: '\bUSCC[_\-]?([^ ;/\)]+)'
4515 device_replacement: '$1'
4516 brand_replacement: 'Cellular'
4517 model_replacement: '$1'
4518
4519 ######################################################################
4520 # Windows Phone Parsers
4521 ######################################################################
4522
4523 #########
4524 # Alcatel Windows Phones
4525 #########
4526 - regex: 'Windows Phone [^;]+; .*?IEMobile/[^;\)]+[;\)] ?(?:ARM; ?Touch; ?|Touch; ?)?(?:ALCATEL)[^;]*; *([^;,\)]+)'
4527 device_replacement: 'Alcatel $1'
4528 brand_replacement: 'Alcatel'
4529 model_replacement: '$1'
4530
4531 #########
4532 # Asus Windows Phones
4533 #########
4534 #~ - regex: 'Windows Phone [^;]+; .*?IEMobile/[^;\)]+[;\)] ?(?:ARM; ?Touch; ?|Touch; ?|WpsLondonTest; ?)?(?:ASUS|Asus)[^;]*; *([^;,\)]+)'
4535 - regex: 'Windows Phone [^;]+; .*?IEMobile/[^;\)]+[;\)] ?(?:ARM; ?Touch; ?|Touch; ?|WpsLondonTest; ?)?(?:ASUS|Asus)[^;]*; *([^;,\)]+)'
4536 device_replacement: 'Asus $1'
4537 brand_replacement: 'Asus'
4538 model_replacement: '$1'
4539
4540 #########
4541 # Dell Windows Phones
4542 #########
4543 - regex: 'Windows Phone [^;]+; .*?IEMobile/[^;\)]+[;\)] ?(?:ARM; ?Touch; ?|Touch; ?)?(?:DELL|Dell)[^;]*; *([^;,\)]+)'
4544 device_replacement: 'Dell $1'
4545 brand_replacement: 'Dell'
4546 model_replacement: '$1'
4547
4548 #########
4549 # HTC Windows Phones
4550 #########
4551 - regex: 'Windows Phone [^;]+; .*?IEMobile/[^;\)]+[;\)] ?(?:ARM; ?Touch; ?|Touch; ?|WpsLondonTest; ?)?(?:HTC|Htc|HTC_blocked[^;]*)[^;]*; *(?:HTC)?([^;,\)]+)'
4552 device_replacement: 'HTC $1'
4553 brand_replacement: 'HTC'
4554 model_replacement: '$1'
4555
4556 #########
4557 # Huawei Windows Phones
4558 #########
4559 - regex: 'Windows Phone [^;]+; .*?IEMobile/[^;\)]+[;\)] ?(?:ARM; ?Touch; ?|Touch; ?)?(?:HUAWEI)[^;]*; *(?:HUAWEI )?([^;,\)]+)'
4560 device_replacement: 'Huawei $1'
4561 brand_replacement: 'Huawei'
4562 model_replacement: '$1'
4563
4564 #########
4565 # LG Windows Phones
4566 #########
4567 - regex: 'Windows Phone [^;]+; .*?IEMobile/[^;\)]+[;\)] ?(?:ARM; ?Touch; ?|Touch; ?)?(?:LG|Lg)[^;]*; *(?:LG[ \-])?([^;,\)]+)'
4568 device_replacement: 'LG $1'
4569 brand_replacement: 'LG'
4570 model_replacement: '$1'
4571
4572 #########
4573 # Noka Windows Phones
4574 #########
4575 - regex: 'Windows Phone [^;]+; .*?IEMobile/[^;\)]+[;\)] ?(?:ARM; ?Touch; ?|Touch; ?)?(?:rv:11; )?(?:NOKIA|Nokia)[^;]*; *(?:NOKIA ?|Nokia ?|LUMIA ?|[Ll]umia ?)*(\d{3,}[^;\)]*)'
4576 device_replacement: 'Lumia $1'
4577 brand_replacement: 'Nokia'
4578 model_replacement: 'Lumia $1'
4579 - regex: 'Windows Phone [^;]+; .*?IEMobile/[^;\)]+[;\)] ?(?:ARM; ?Touch; ?|Touch; ?)?(?:NOKIA|Nokia)[^;]*; *(RM-\d{3,})'
4580 device_replacement: 'Nokia $1'
4581 brand_replacement: 'Nokia'
4582 model_replacement: '$1'
4583 - regex: '(?:Windows Phone [^;]+; .*?IEMobile/[^;\)]+[;\)]|WPDesktop;) ?(?:ARM; ?Touch; ?|Touch; ?)?(?:NOKIA|Nokia)[^;]*; *(?:NOKIA ?|Nokia ?|LUMIA ?|[Ll]umia ?)*([^;\)]+)'
4584 device_replacement: 'Nokia $1'
4585 brand_replacement: 'Nokia'
4586 model_replacement: '$1'
4587
4588 #########
4589 # Microsoft Windows Phones
4590 #########
4591 - regex: 'Windows Phone [^;]+; .*?IEMobile/[^;\)]+[;\)] ?(?:ARM; ?Touch; ?|Touch; ?)?(?:Microsoft(?: Corporation)?)[^;]*; *([^;,\)]+)'
4592 device_replacement: 'Microsoft $1'
4593 brand_replacement: 'Microsoft'
4594 model_replacement: '$1'
4595
4596 #########
4597 # Samsung Windows Phones
4598 #########
4599 - regex: 'Windows Phone [^;]+; .*?IEMobile/[^;\)]+[;\)] ?(?:ARM; ?Touch; ?|Touch; ?|WpsLondonTest; ?)?(?:SAMSUNG)[^;]*; *(?:SAMSUNG )?([^;,\.\)]+)'
4600 device_replacement: 'Samsung $1'
4601 brand_replacement: 'Samsung'
4602 model_replacement: '$1'
4603
4604 #########
4605 # Toshiba Windows Phones
4606 #########
4607 - regex: 'Windows Phone [^;]+; .*?IEMobile/[^;\)]+[;\)] ?(?:ARM; ?Touch; ?|Touch; ?|WpsLondonTest; ?)?(?:TOSHIBA|FujitsuToshibaMobileCommun)[^;]*; *([^;,\)]+)'
4608 device_replacement: 'Toshiba $1'
4609 brand_replacement: 'Toshiba'
4610 model_replacement: '$1'
4611
4612 #########
4613 # Generic Windows Phones
4614 #########
4615 - regex: 'Windows Phone [^;]+; .*?IEMobile/[^;\)]+[;\)] ?(?:ARM; ?Touch; ?|Touch; ?|WpsLondonTest; ?)?([^;]+); *([^;,\)]+)'
4616 device_replacement: '$1 $2'
4617 brand_replacement: '$1'
4618 model_replacement: '$2'
4619
4620 ######################################################################
4621 # Other Devices Parser
4622 ######################################################################
4623
4624 #########
4625 # Samsung Bada Phones
4626 #########
4627 - regex: '(?:^|; )SAMSUNG\-([A-Za-z0-9\-]+).* Bada/'
4628 device_replacement: 'Samsung $1'
4629 brand_replacement: 'Samsung'
4630 model_replacement: '$1'
4631
4632 #########
4633 # Firefox OS
4634 #########
4635 - regex: '\(Mobile; ALCATEL ?(One|ONE) ?(Touch|TOUCH) ?([^;/]+)(?:/[^;]+)?; rv:[^\)]+\) Gecko/[^\/]+ Firefox/'
4636 device_replacement: 'Alcatel $1 $2 $3'
4637 brand_replacement: 'Alcatel'
4638 model_replacement: 'One Touch $3'
4639 - regex: '\(Mobile; (?:ZTE([^;]+)|(OpenC)); rv:[^\)]+\) Gecko/[^\/]+ Firefox/'
4640 device_replacement: 'ZTE $1$2'
4641 brand_replacement: 'ZTE'
4642 model_replacement: '$1$2'
4643
4644 ##########
4645 # NOKIA
4646 # @note: NokiaN8-00 comes before iphone. Sometimes spoofs iphone
4647 ##########
4648 - regex: 'Nokia(N[0-9]+)([A-z_\-][A-z0-9_\-]*)'
4649 device_replacement: 'Nokia $1'
4650 brand_replacement: 'Nokia'
4651 model_replacement: '$1$2'
4652 - regex: '(?:NOKIA|Nokia)(?:\-| *)(?:([A-Za-z0-9]+)\-[0-9a-f]{32}|([A-Za-z0-9\-]+)(?:UCBrowser)|([A-Za-z0-9\-]+))'
4653 device_replacement: 'Nokia $1$2$3'
4654 brand_replacement: 'Nokia'
4655 model_replacement: '$1$2$3'
4656 - regex: 'Lumia ([A-Za-z0-9\-]+)'
4657 device_replacement: 'Lumia $1'
4658 brand_replacement: 'Nokia'
4659 model_replacement: 'Lumia $1'
4660 # UCWEB Browser on Symbian
4661 - regex: '\(Symbian; U; S60 V5; [A-z]{2}\-[A-z]{2}; (SonyEricsson|Samsung|Nokia|LG)([^;/]+)\)'
4662 device_replacement: '$1 $2'
4663 brand_replacement: '$1'
4664 model_replacement: '$2'
4665 # Nokia Symbian
4666 - regex: '\(Symbian(?:/3)?; U; ([^;]+);'
4667 device_replacement: 'Nokia $1'
4668 brand_replacement: 'Nokia'
4669 model_replacement: '$1'
4670
4671 ##########
4672 # BlackBerry
4673 # @ref: http://www.useragentstring.com/pages/BlackBerry/
4674 ##########
4675 - regex: 'BB10; ([A-Za-z0-9\- ]+)\)'
4676 device_replacement: 'BlackBerry $1'
4677 brand_replacement: 'BlackBerry'
4678 model_replacement: '$1'
4679 - regex: 'Play[Bb]ook.+RIM Tablet OS'
4680 device_replacement: 'BlackBerry Playbook'
4681 brand_replacement: 'BlackBerry'
4682 model_replacement: 'Playbook'
4683 - regex: 'Black[Bb]erry ([0-9]+);'
4684 device_replacement: 'BlackBerry $1'
4685 brand_replacement: 'BlackBerry'
4686 model_replacement: '$1'
4687 - regex: 'Black[Bb]erry([0-9]+)'
4688 device_replacement: 'BlackBerry $1'
4689 brand_replacement: 'BlackBerry'
4690 model_replacement: '$1'
4691 - regex: 'Black[Bb]erry;'
4692 device_replacement: 'BlackBerry'
4693 brand_replacement: 'BlackBerry'
4694
4695 ##########
4696 # PALM / HP
4697 # @note: some palm devices must come before iphone. sometimes spoofs iphone in ua
4698 ##########
4699 - regex: '(Pre|Pixi)/\d+\.\d+'
4700 device_replacement: 'Palm $1'
4701 brand_replacement: 'Palm'
4702 model_replacement: '$1'
4703 - regex: 'Palm([0-9]+)'
4704 device_replacement: 'Palm $1'
4705 brand_replacement: 'Palm'
4706 model_replacement: '$1'
4707 - regex: 'Treo([A-Za-z0-9]+)'
4708 device_replacement: 'Palm Treo $1'
4709 brand_replacement: 'Palm'
4710 model_replacement: 'Treo $1'
4711 - regex: 'webOS.*(P160U(?:NA)?)/(\d+).(\d+)'
4712 device_replacement: 'HP Veer'
4713 brand_replacement: 'HP'
4714 model_replacement: 'Veer'
4715 - regex: '(Touch[Pp]ad)/\d+\.\d+'
4716 device_replacement: 'HP TouchPad'
4717 brand_replacement: 'HP'
4718 model_replacement: 'TouchPad'
4719 - regex: 'HPiPAQ([A-Za-z0-9]+)/\d+.\d+'
4720 device_replacement: 'HP iPAQ $1'
4721 brand_replacement: 'HP'
4722 model_replacement: 'iPAQ $1'
4723 - regex: 'PDA; (PalmOS)/sony/model ([a-z]+)/Revision'
4724 device_replacement: '$1'
4725 brand_replacement: 'Sony'
4726 model_replacement: '$1 $2'
4727
4728 ##########
4729 # AppleTV
4730 # No built in browser that I can tell
4731 # Stack Overflow indicated iTunes-AppleTV/4.1 as a known UA for app available and I'm seeing it in live traffic
4732 ##########
4733 - regex: '(Apple\s?TV)'
4734 device_replacement: 'AppleTV'
4735 brand_replacement: 'Apple'
4736 model_replacement: 'AppleTV'
4737
4738 #########
4739 # Tesla Model S
4740 #########
4741 - regex: '(QtCarBrowser)'
4742 device_replacement: 'Tesla Model S'
4743 brand_replacement: 'Tesla'
4744 model_replacement: 'Model S'
4745
4746 ##########
4747 # iSTUFF
4748 # @note: complete but probably catches spoofs
4749 # ipad and ipod must be parsed before iphone
4750 # cannot determine specific device type from ua string. (3g, 3gs, 4, etc)
4751 ##########
4752 # @note: on some ua the device can be identified e.g. iPhone5,1
4753 - regex: '(iPhone|iPad|iPod)(\d+,\d+)'
4754 device_replacement: '$1'
4755 brand_replacement: 'Apple'
4756 model_replacement: '$1$2'
4757 # @note: iPad needs to be before iPhone
4758 - regex: '(iPad)(?:;| Simulator;)'
4759 device_replacement: '$1'
4760 brand_replacement: 'Apple'
4761 model_replacement: '$1'
4762 - regex: '(iPod)(?:;| touch;| Simulator;)'
4763 device_replacement: '$1'
4764 brand_replacement: 'Apple'
4765 model_replacement: '$1'
4766 - regex: '(iPhone)(?:;| Simulator;)'
4767 device_replacement: '$1'
4768 brand_replacement: 'Apple'
4769 model_replacement: '$1'
4770 - regex: '(Apple Watch)(?:;| Simulator;)'
4771 device_replacement: '$1'
4772 brand_replacement: 'Apple'
4773 model_replacement: '$1'
4774 - regex: '(HomePod)(?:;| Simulator;)'
4775 device_replacement: '$1'
4776 brand_replacement: 'Apple'
4777 model_replacement: '$1'
4778 - regex: 'iPhone'
4779 device_replacement: 'iPhone'
4780 brand_replacement: 'Apple'
4781 model_replacement: 'iPhone'
4782 # @note: desktop applications show device info
4783 - regex: 'CFNetwork/.* Darwin/\d.*\(((?:Mac|iMac|PowerMac|PowerBook)[^\d]*)(\d+)(?:,|%2C)(\d+)'
4784 device_replacement: '$1$2,$3'
4785 brand_replacement: 'Apple'
4786 model_replacement: '$1$2,$3'
4787 # @note: newer desktop applications don't show device info
4788 # This is here so as to not have them recorded as iOS-Device
4789 - regex: 'CFNetwork/.* Darwin/\d+\.\d+\.\d+ \(x86_64\)'
4790 device_replacement: 'Mac'
4791 brand_replacement: 'Apple'
4792 model_replacement: 'Mac'
4793 # @note: iOS applications do not show device info
4794 - regex: 'CFNetwork/.* Darwin/\d'
4795 device_replacement: 'iOS-Device'
4796 brand_replacement: 'Apple'
4797 model_replacement: 'iOS-Device'
4798
4799 ##########################
4800 # Outlook on iOS >= 2.62.0
4801 ##########################
4802 - regex: 'Outlook-(iOS)/\d+\.\d+\.prod\.iphone'
4803 brand_replacement: 'Apple'
4804 device_replacement: 'iPhone'
4805 model_replacement: 'iPhone'
4806
4807 ##########
4808 # Acer
4809 ##########
4810 - regex: 'acer_([A-Za-z0-9]+)_'
4811 device_replacement: 'Acer $1'
4812 brand_replacement: 'Acer'
4813 model_replacement: '$1'
4814
4815 ##########
4816 # Alcatel
4817 ##########
4818 - regex: '(?:ALCATEL|Alcatel)-([A-Za-z0-9\-]+)'
4819 device_replacement: 'Alcatel $1'
4820 brand_replacement: 'Alcatel'
4821 model_replacement: '$1'
4822
4823 ##########
4824 # Amoi
4825 ##########
4826 - regex: '(?:Amoi|AMOI)\-([A-Za-z0-9]+)'
4827 device_replacement: 'Amoi $1'
4828 brand_replacement: 'Amoi'
4829 model_replacement: '$1'
4830
4831 ##########
4832 # Asus
4833 ##########
4834 - regex: '(?:; |\/|^)((?:Transformer (?:Pad|Prime) |Transformer |PadFone[ _]?)[A-Za-z0-9]*)'
4835 device_replacement: 'Asus $1'
4836 brand_replacement: 'Asus'
4837 model_replacement: '$1'
4838 - regex: '(?:asus.*?ASUS|Asus|ASUS|asus)[\- ;]*((?:Transformer (?:Pad|Prime) |Transformer |Padfone |Nexus[ _])?[A-Za-z0-9]+)'
4839 device_replacement: 'Asus $1'
4840 brand_replacement: 'Asus'
4841 model_replacement: '$1'
4842
4843
4844 ##########
4845 # Bird
4846 ##########
4847 - regex: '\bBIRD[ \-\.]([A-Za-z0-9]+)'
4848 device_replacement: 'Bird $1'
4849 brand_replacement: 'Bird'
4850 model_replacement: '$1'
4851
4852 ##########
4853 # Dell
4854 ##########
4855 - regex: '\bDell ([A-Za-z0-9]+)'
4856 device_replacement: 'Dell $1'
4857 brand_replacement: 'Dell'
4858 model_replacement: '$1'
4859
4860 ##########
4861 # DoCoMo
4862 ##########
4863 - regex: 'DoCoMo/2\.0 ([A-Za-z0-9]+)'
4864 device_replacement: 'DoCoMo $1'
4865 brand_replacement: 'DoCoMo'
4866 model_replacement: '$1'
4867 - regex: '([A-Za-z0-9]+)_W;FOMA'
4868 device_replacement: 'DoCoMo $1'
4869 brand_replacement: 'DoCoMo'
4870 model_replacement: '$1'
4871 - regex: '([A-Za-z0-9]+);FOMA'
4872 device_replacement: 'DoCoMo $1'
4873 brand_replacement: 'DoCoMo'
4874 model_replacement: '$1'
4875
4876 ##########
4877 # htc
4878 ##########
4879 - regex: '\b(?:HTC/|HTC/[a-z0-9]+/)?HTC[ _\-;]? *(.*?)(?:-?Mozilla|fingerPrint|[;/\(\)]|$)'
4880 device_replacement: 'HTC $1'
4881 brand_replacement: 'HTC'
4882 model_replacement: '$1'
4883
4884 ##########
4885 # Huawei
4886 ##########
4887 - regex: 'Huawei([A-Za-z0-9]+)'
4888 device_replacement: 'Huawei $1'
4889 brand_replacement: 'Huawei'
4890 model_replacement: '$1'
4891 - regex: 'HUAWEI-([A-Za-z0-9]+)'
4892 device_replacement: 'Huawei $1'
4893 brand_replacement: 'Huawei'
4894 model_replacement: '$1'
4895 - regex: 'vodafone([A-Za-z0-9]+)'
4896 device_replacement: 'Huawei Vodafone $1'
4897 brand_replacement: 'Huawei'
4898 model_replacement: 'Vodafone $1'
4899
4900 ##########
4901 # i-mate
4902 ##########
4903 - regex: 'i\-mate ([A-Za-z0-9]+)'
4904 device_replacement: 'i-mate $1'
4905 brand_replacement: 'i-mate'
4906 model_replacement: '$1'
4907
4908 ##########
4909 # kyocera
4910 ##########
4911 - regex: 'Kyocera\-([A-Za-z0-9]+)'
4912 device_replacement: 'Kyocera $1'
4913 brand_replacement: 'Kyocera'
4914 model_replacement: '$1'
4915 - regex: 'KWC\-([A-Za-z0-9]+)'
4916 device_replacement: 'Kyocera $1'
4917 brand_replacement: 'Kyocera'
4918 model_replacement: '$1'
4919
4920 ##########
4921 # lenovo
4922 ##########
4923 - regex: 'Lenovo[_\-]([A-Za-z0-9]+)'
4924 device_replacement: 'Lenovo $1'
4925 brand_replacement: 'Lenovo'
4926 model_replacement: '$1'
4927
4928 ##########
4929 # HbbTV (European and Australian standard)
4930 # written before the LG regexes, as LG is making HbbTV too
4931 ##########
4932 - regex: '(HbbTV)/[0-9]+\.[0-9]+\.[0-9]+ \([^;]*; *(LG)E *; *([^;]*) *;[^;]*;[^;]*;\)'
4933 device_replacement: '$1'
4934 brand_replacement: '$2'
4935 model_replacement: '$3'
4936 - regex: '(HbbTV)/1\.1\.1.*CE-HTML/1\.\d;(Vendor/)*(THOM[^;]*?)[;\s](?:.*SW-Version/.*)*(LF[^;]+);?'
4937 device_replacement: '$1'
4938 brand_replacement: 'Thomson'
4939 model_replacement: '$4'
4940 - regex: '(HbbTV)(?:/1\.1\.1)?(?: ?\(;;;;;\))?; *CE-HTML(?:/1\.\d)?; *([^ ]+) ([^;]+);'
4941 device_replacement: '$1'
4942 brand_replacement: '$2'
4943 model_replacement: '$3'
4944 - regex: '(HbbTV)/1\.1\.1 \(;;;;;\) Maple_2011'
4945 device_replacement: '$1'
4946 brand_replacement: 'Samsung'
4947 - regex: '(HbbTV)/[0-9]+\.[0-9]+\.[0-9]+ \([^;]*; *(?:CUS:([^;]*)|([^;]+)) *; *([^;]*) *;.*;'
4948 device_replacement: '$1'
4949 brand_replacement: '$2$3'
4950 model_replacement: '$4'
4951 - regex: '(HbbTV)/[0-9]+\.[0-9]+\.[0-9]+'
4952 device_replacement: '$1'
4953
4954 ##########
4955 # LGE NetCast TV
4956 ##########
4957 - regex: 'LGE; (?:Media\/)?([^;]*);[^;]*;[^;]*;?\); "?LG NetCast(\.TV|\.Media)?-\d+'
4958 device_replacement: 'NetCast$2'
4959 brand_replacement: 'LG'
4960 model_replacement: '$1'
4961
4962 ##########
4963 # InettvBrowser
4964 ##########
4965 - regex: 'InettvBrowser/[0-9]+\.[0-9A-Z]+ \([^;]*;(Sony)([^;]*);[^;]*;[^\)]*\)'
4966 device_replacement: 'Inettv'
4967 brand_replacement: '$1'
4968 model_replacement: '$2'
4969 - regex: 'InettvBrowser/[0-9]+\.[0-9A-Z]+ \([^;]*;([^;]*);[^;]*;[^\)]*\)'
4970 device_replacement: 'Inettv'
4971 brand_replacement: 'Generic_Inettv'
4972 model_replacement: '$1'
4973 - regex: '(?:InettvBrowser|TSBNetTV|NETTV|HBBTV)'
4974 device_replacement: 'Inettv'
4975 brand_replacement: 'Generic_Inettv'
4976
4977 ##########
4978 # lg
4979 ##########
4980 # LG Symbian Phones
4981 - regex: 'Series60/\d\.\d (LG)[\-]?([A-Za-z0-9 \-]+)'
4982 device_replacement: '$1 $2'
4983 brand_replacement: '$1'
4984 model_replacement: '$2'
4985 # other LG phones
4986 - regex: '\b(?:LGE[ \-]LG\-(?:AX)?|LGE |LGE?-LG|LGE?[ \-]|LG[ /\-]|lg[\-])([A-Za-z0-9]+)\b'
4987 device_replacement: 'LG $1'
4988 brand_replacement: 'LG'
4989 model_replacement: '$1'
4990 - regex: '(?:^LG[\-]?|^LGE[\-/]?)([A-Za-z]+[0-9]+[A-Za-z]*)'
4991 device_replacement: 'LG $1'
4992 brand_replacement: 'LG'
4993 model_replacement: '$1'
4994 - regex: '^LG([0-9]+[A-Za-z]*)'
4995 device_replacement: 'LG $1'
4996 brand_replacement: 'LG'
4997 model_replacement: '$1'
4998
4999 ##########
5000 # microsoft
5001 ##########
5002 - regex: '(KIN\.[^ ]+) (\d+)\.(\d+)'
5003 device_replacement: 'Microsoft $1'
5004 brand_replacement: 'Microsoft'
5005 model_replacement: '$1'
5006 - regex: '(?:MSIE|XBMC).*\b(Xbox)\b'
5007 device_replacement: '$1'
5008 brand_replacement: 'Microsoft'
5009 model_replacement: '$1'
5010 - regex: '; ARM; Trident/6\.0; Touch[\);]'
5011 device_replacement: 'Microsoft Surface RT'
5012 brand_replacement: 'Microsoft'
5013 model_replacement: 'Surface RT'
5014
5015 ##########
5016 # motorola
5017 ##########
5018 - regex: 'Motorola\-([A-Za-z0-9]+)'
5019 device_replacement: 'Motorola $1'
5020 brand_replacement: 'Motorola'
5021 model_replacement: '$1'
5022 - regex: 'MOTO\-([A-Za-z0-9]+)'
5023 device_replacement: 'Motorola $1'
5024 brand_replacement: 'Motorola'
5025 model_replacement: '$1'
5026 - regex: 'MOT\-([A-z0-9][A-z0-9\-]*)'
5027 device_replacement: 'Motorola $1'
5028 brand_replacement: 'Motorola'
5029 model_replacement: '$1'
5030
5031 ##########
5032 # nintendo
5033 ##########
5034 - regex: 'Nintendo WiiU'
5035 device_replacement: 'Nintendo Wii U'
5036 brand_replacement: 'Nintendo'
5037 model_replacement: 'Wii U'
5038 - regex: 'Nintendo (DS|3DS|DSi|Wii);'
5039 device_replacement: 'Nintendo $1'
5040 brand_replacement: 'Nintendo'
5041 model_replacement: '$1'
5042
5043 ##########
5044 # pantech
5045 ##########
5046 - regex: '(?:Pantech|PANTECH)[ _-]?([A-Za-z0-9\-]+)'
5047 device_replacement: 'Pantech $1'
5048 brand_replacement: 'Pantech'
5049 model_replacement: '$1'
5050
5051 ##########
5052 # philips
5053 ##########
5054 - regex: 'Philips([A-Za-z0-9]+)'
5055 device_replacement: 'Philips $1'
5056 brand_replacement: 'Philips'
5057 model_replacement: '$1'
5058 - regex: 'Philips ([A-Za-z0-9]+)'
5059 device_replacement: 'Philips $1'
5060 brand_replacement: 'Philips'
5061 model_replacement: '$1'
5062
5063 ##########
5064 # Samsung
5065 ##########
5066 # Samsung Smart-TV
5067 - regex: '(SMART-TV); .* Tizen '
5068 device_replacement: 'Samsung $1'
5069 brand_replacement: 'Samsung'
5070 model_replacement: '$1'
5071 # Samsung Symbian Devices
5072 - regex: 'SymbianOS/9\.\d.* Samsung[/\-]([A-Za-z0-9 \-]+)'
5073 device_replacement: 'Samsung $1'
5074 brand_replacement: 'Samsung'
5075 model_replacement: '$1'
5076 - regex: '(Samsung)(SGH)(i[0-9]+)'
5077 device_replacement: '$1 $2$3'
5078 brand_replacement: '$1'
5079 model_replacement: '$2-$3'
5080 - regex: 'SAMSUNG-ANDROID-MMS/([^;/]+)'
5081 device_replacement: '$1'
5082 brand_replacement: 'Samsung'
5083 model_replacement: '$1'
5084 # Other Samsung
5085 #- regex: 'SAMSUNG(?:; |-)([A-Za-z0-9\-]+)'
5086 - regex: 'SAMSUNG(?:; |[ -/])([A-Za-z0-9\-]+)'
5087 regex_flag: 'i'
5088 device_replacement: 'Samsung $1'
5089 brand_replacement: 'Samsung'
5090 model_replacement: '$1'
5091
5092 ##########
5093 # Sega
5094 ##########
5095 - regex: '(Dreamcast)'
5096 device_replacement: 'Sega $1'
5097 brand_replacement: 'Sega'
5098 model_replacement: '$1'
5099
5100 ##########
5101 # Siemens mobile
5102 ##########
5103 - regex: '^SIE-([A-Za-z0-9]+)'
5104 device_replacement: 'Siemens $1'
5105 brand_replacement: 'Siemens'
5106 model_replacement: '$1'
5107
5108 ##########
5109 # Softbank
5110 ##########
5111 - regex: 'Softbank/[12]\.0/([A-Za-z0-9]+)'
5112 device_replacement: 'Softbank $1'
5113 brand_replacement: 'Softbank'
5114 model_replacement: '$1'
5115
5116 ##########
5117 # SonyEricsson
5118 ##########
5119 - regex: 'SonyEricsson ?([A-Za-z0-9\-]+)'
5120 device_replacement: 'Ericsson $1'
5121 brand_replacement: 'SonyEricsson'
5122 model_replacement: '$1'
5123
5124 ##########
5125 # Sony
5126 ##########
5127 - regex: 'Android [^;]+; ([^ ]+) (Sony)/'
5128 device_replacement: '$2 $1'
5129 brand_replacement: '$2'
5130 model_replacement: '$1'
5131 - regex: '(Sony)(?:BDP\/|\/)?([^ /;\)]+)[ /;\)]'
5132 device_replacement: '$1 $2'
5133 brand_replacement: '$1'
5134 model_replacement: '$2'
5135
5136 #########
5137 # Puffin Browser Device detect
5138 # A=Android, I=iOS, P=Phone, T=Tablet
5139 # AT=Android+Tablet
5140 #########
5141 - regex: 'Puffin/[\d\.]+IT'
5142 device_replacement: 'iPad'
5143 brand_replacement: 'Apple'
5144 model_replacement: 'iPad'
5145 - regex: 'Puffin/[\d\.]+IP'
5146 device_replacement: 'iPhone'
5147 brand_replacement: 'Apple'
5148 model_replacement: 'iPhone'
5149 - regex: 'Puffin/[\d\.]+AT'
5150 device_replacement: 'Generic Tablet'
5151 brand_replacement: 'Generic'
5152 model_replacement: 'Tablet'
5153 - regex: 'Puffin/[\d\.]+AP'
5154 device_replacement: 'Generic Smartphone'
5155 brand_replacement: 'Generic'
5156 model_replacement: 'Smartphone'
5157
5158 #########
5159 # Android General Device Matching (far from perfect)
5160 #########
5161 - regex: 'Android[\- ][\d]+\.[\d]+; [A-Za-z]{2}\-[A-Za-z]{0,2}; WOWMobile (.+) Build[/ ]'
5162 brand_replacement: 'Generic_Android'
5163 model_replacement: '$1'
5164 - regex: 'Android[\- ][\d]+\.[\d]+\-update1; [A-Za-z]{2}\-[A-Za-z]{0,2} *; *(.+?) Build[/ ]'
5165 brand_replacement: 'Generic_Android'
5166 model_replacement: '$1'
5167 - regex: 'Android[\- ][\d]+(?:\.[\d]+){1,2}; *[A-Za-z]{2}[_\-][A-Za-z]{0,2}\-? *; *(.+?) Build[/ ]'
5168 brand_replacement: 'Generic_Android'
5169 model_replacement: '$1'
5170 - regex: 'Android[\- ][\d]+(?:\.[\d]+){1,2}; *[A-Za-z]{0,2}\- *; *(.+?) Build[/ ]'
5171 brand_replacement: 'Generic_Android'
5172 model_replacement: '$1'
5173 # No build info at all - "Build" follows locale immediately
5174 - regex: 'Android[\- ][\d]+(?:\.[\d]+){1,2}; *[a-z]{0,2}[_\-]?[A-Za-z]{0,2};? Build[/ ]'
5175 device_replacement: 'Generic Smartphone'
5176 brand_replacement: 'Generic'
5177 model_replacement: 'Smartphone'
5178 - regex: 'Android[\- ][\d]+(?:\.[\d]+){1,2}; *\-?[A-Za-z]{2}; *(.+?) Build[/ ]'
5179 brand_replacement: 'Generic_Android'
5180 model_replacement: '$1'
5181 - regex: 'Android[\- ][\d]+(?:\.[\d]+){1,2}(?:;.*)?; *(.+?) Build[/ ]'
5182 brand_replacement: 'Generic_Android'
5183 model_replacement: '$1'
5184
5185 ##########
5186 # Google TV
5187 ##########
5188 - regex: '(GoogleTV)'
5189 brand_replacement: 'Generic_Inettv'
5190 model_replacement: '$1'
5191
5192 ##########
5193 # WebTV
5194 ##########
5195 - regex: '(WebTV)/\d+.\d+'
5196 brand_replacement: 'Generic_Inettv'
5197 model_replacement: '$1'
5198 # Roku Digital-Video-Players https://www.roku.com/
5199 - regex: '^(Roku)/DVP-\d+\.\d+'
5200 brand_replacement: 'Generic_Inettv'
5201 model_replacement: '$1'
5202
5203 ##########
5204 # Generic Tablet
5205 ##########
5206 - regex: '(Android 3\.\d|Opera Tablet|Tablet; .+Firefox/|Android.*(?:Tab|Pad))'
5207 regex_flag: 'i'
5208 device_replacement: 'Generic Tablet'
5209 brand_replacement: 'Generic'
5210 model_replacement: 'Tablet'
5211
5212 ##########
5213 # Generic Smart Phone
5214 ##########
5215 - regex: '(Symbian|\bS60(Version|V\d)|\bS60\b|\((Series 60|Windows Mobile|Palm OS|Bada); Opera Mini|Windows CE|Opera Mobi|BREW|Brew|Mobile; .+Firefox/|iPhone OS|Android|MobileSafari|Windows *Phone|\(webOS/|PalmOS)'
5216 device_replacement: 'Generic Smartphone'
5217 brand_replacement: 'Generic'
5218 model_replacement: 'Smartphone'
5219 - regex: '(hiptop|avantgo|plucker|xiino|blazer|elaine)'
5220 regex_flag: 'i'
5221 device_replacement: 'Generic Smartphone'
5222 brand_replacement: 'Generic'
5223 model_replacement: 'Smartphone'
5224
5225 ##########
5226 # Spiders (this is hack...)
5227 ##########
5228 - regex: '(bot|BUbiNG|zao|borg|DBot|oegp|silk|Xenu|zeal|^NING|CCBot|crawl|htdig|lycos|slurp|teoma|voila|yahoo|Sogou|CiBra|Nutch|^Java/|^JNLP/|Daumoa|Daum|Genieo|ichiro|larbin|pompos|Scrapy|snappy|speedy|spider|msnbot|msrbot|vortex|^vortex|crawler|favicon|indexer|Riddler|scooter|scraper|scrubby|WhatWeb|WinHTTP|bingbot|BingPreview|openbot|gigabot|furlbot|polybot|seekbot|^voyager|archiver|Icarus6j|mogimogi|Netvibes|blitzbot|altavista|charlotte|findlinks|Retreiver|TLSProber|WordPress|SeznamBot|ProoXiBot|wsr\-agent|Squrl Java|EtaoSpider|PaperLiBot|SputnikBot|A6\-Indexer|netresearch|searchsight|baiduspider|YisouSpider|ICC\-Crawler|http%20client|Python-urllib|dataparksearch|converacrawler|Screaming Frog|AppEngine-Google|YahooCacheSystem|fast\-webcrawler|Sogou Pic Spider|semanticdiscovery|Innovazion Crawler|facebookexternalhit|Google.*/\+/web/snippet|Google-HTTP-Java-Client|BlogBridge|IlTrovatore-Setaccio|InternetArchive|GomezAgent|WebThumbnail|heritrix|NewsGator|PagePeeker|Reaper|ZooShot|holmes|NL-Crawler|Pingdom|StatusCake|WhatsApp|masscan|Google Web Preview|Qwantify|Yeti)'
5229 regex_flag: 'i'
5230 device_replacement: 'Spider'
5231 brand_replacement: 'Spider'
5232 model_replacement: 'Desktop'
5233
5234 ##########
5235 # Generic Feature Phone
5236 # take care to do case insensitive matching
5237 ##########
5238 - 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|bmobile|bell|bird|bw\-n|bw\-u|beck|benq|bilb|blac|c55/|cdm\-|chtm|capi|comp|cond|dall|dbte|dc\-s|dica|ds\-d|ds12|dait|devi|dmob|doco|dopo|dorado|el(?:38|39|48|49|50|55|58|68)|el[3456]\d{2}dual|erk0|esl8|ex300|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)'
5239 regex_flag: 'i'
5240 device_replacement: 'Generic Feature Phone'
5241 brand_replacement: 'Generic'
5242 model_replacement: 'Feature Phone'
5243 - regex: '^(htcp|htcs|htct|htc_|haie|hita|huaw|hutc|i\-20|i\-go|i\-ma|i\-mobile|i230|iac|iac\-|iac/|ig01|im1k|inno|iris|jata|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/|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)'
5244 regex_flag: 'i'
5245 device_replacement: 'Generic Feature Phone'
5246 brand_replacement: 'Generic'
5247 model_replacement: 'Feature Phone'
5248 - 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)'
5249 regex_flag: 'i'
5250 device_replacement: 'Generic Feature Phone'
5251 brand_replacement: 'Generic'
5252 model_replacement: 'Feature Phone'
5253 - regex: '^(talk|teli|topl|tosh|up.b|upg1|utst|v400|v750|veri|vk\-v|vk40|vk50|vk52|vk53|vm40|vx98|virg|vertu|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_)'
5254 regex_flag: 'i'
5255 device_replacement: 'Generic Feature Phone'
5256 brand_replacement: 'Generic'
5257 model_replacement: 'Feature Phone'
5258 - regex: '^(Ice)$'
5259 device_replacement: 'Generic Feature Phone'
5260 brand_replacement: 'Generic'
5261 model_replacement: 'Feature Phone'
5262 - regex: '(wap[\-\ ]browser|maui|netfront|obigo|teleca|up\.browser|midp|Opera Mini)'
5263 regex_flag: 'i'
5264 device_replacement: 'Generic Feature Phone'
5265 brand_replacement: 'Generic'
5266 model_replacement: 'Feature Phone'