device_detector 0.7.0 → 0.8.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/Gemfile +4 -0
- data/Rakefile +12 -6
- data/device_detector.gemspec +1 -1
- data/lib/device_detector.rb +65 -4
- data/lib/device_detector/client.rb +6 -6
- data/lib/device_detector/device.rb +62 -31
- data/lib/device_detector/memory_cache.rb +1 -1
- data/lib/device_detector/metadata_extractor.rb +4 -13
- data/lib/device_detector/model_extractor.rb +10 -1
- data/lib/device_detector/name_extractor.rb +1 -1
- data/lib/device_detector/os.rb +141 -5
- data/lib/device_detector/parser.rb +23 -12
- data/lib/device_detector/version.rb +1 -1
- data/lib/device_detector/version_extractor.rb +1 -1
- data/regexes/bots.yml +36 -1
- data/regexes/{browser_engines.yml → client/browser_engine.yml} +4 -1
- data/regexes/{browsers.yml → client/browsers.yml} +31 -27
- data/regexes/{feed_readers.yml → client/feed_readers.yml} +0 -1
- data/regexes/{libraries.yml → client/libraries.yml} +1 -1
- data/regexes/{mediaplayers.yml → client/mediaplayers.yml} +1 -1
- data/regexes/{mobile_apps.yml → client/mobile_apps.yml} +0 -1
- data/regexes/{pim.yml → client/pim.yml} +1 -1
- data/regexes/{devices → device}/cameras.yml +1 -1
- data/regexes/{devices → device}/car_browsers.yml +0 -1
- data/regexes/{devices → device}/consoles.yml +0 -1
- data/regexes/{devices → device}/mobiles.yml +193 -49
- data/regexes/{devices/portable_media_players.yml → device/portable_media_player.yml} +0 -1
- data/regexes/{devices → device}/televisions.yml +0 -3
- data/regexes/oss.yml +105 -102
- data/regexes/vendorfragments.yml +70 -0
- data/spec/device_detector/bot_fixtures_spec.rb +30 -0
- data/spec/device_detector/client_fixtures_spec.rb +31 -0
- data/spec/device_detector/concrete_user_agent_spec.rb +41 -1
- data/spec/device_detector/detector_fixtures_spec.rb +56 -0
- data/spec/device_detector/device_fixtures_spec.rb +36 -0
- data/spec/device_detector/device_spec.rb +3 -3
- data/spec/device_detector/memory_cache_spec.rb +1 -1
- data/spec/device_detector/model_extractor_spec.rb +7 -7
- data/spec/device_detector/os_fixtures_spec.rb +26 -0
- data/spec/device_detector/version_extractor_spec.rb +10 -10
- data/spec/device_detector_spec.rb +1 -1
- data/spec/fixtures/client/browser.yml +986 -0
- data/spec/fixtures/client/feed_reader.yml +180 -0
- data/spec/fixtures/client/library.yml +78 -0
- data/spec/fixtures/client/mediaplayer.yml +144 -0
- data/spec/fixtures/client/mobile_app.yml +24 -0
- data/spec/fixtures/client/pim.yml +90 -0
- data/spec/fixtures/detector/bots.yml +716 -0
- data/spec/fixtures/detector/camera.yml +91 -0
- data/spec/fixtures/detector/car_browser.yml +19 -0
- data/spec/fixtures/detector/console.yml +253 -0
- data/spec/fixtures/detector/desktop.yml +4568 -0
- data/spec/fixtures/detector/feature_phone.yml +719 -0
- data/spec/fixtures/detector/feed_reader.yml +462 -0
- data/spec/fixtures/detector/mediaplayer.yml +141 -0
- data/spec/fixtures/detector/mobile_apps.yml +32 -0
- data/spec/fixtures/detector/phablet.yml +1095 -0
- data/spec/fixtures/detector/portable_media_player.yml +145 -0
- data/spec/fixtures/detector/smart_display.yml +19 -0
- data/spec/fixtures/detector/smartphone.yml +28673 -0
- data/spec/fixtures/detector/tablet.yml +13201 -0
- data/spec/fixtures/detector/tv.yml +1380 -0
- data/spec/fixtures/detector/unknown.yml +3536 -0
- data/spec/fixtures/device/camera.yml +18 -0
- data/spec/fixtures/device/car_browser.yml +6 -0
- data/spec/fixtures/device/console.yml +72 -0
- data/spec/fixtures/parser/bots.yml +2055 -0
- data/spec/fixtures/parser/oss.yml +607 -0
- data/spec/fixtures/parser/vendorfragments.yml +156 -0
- data/spec/spec_helper.rb +6 -2
- metadata +84 -17
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 98cdaab8265efd95799dcb71e4588cef6c300528
|
4
|
+
data.tar.gz: f43a7ef253ca782d672d8856d1b1214c6b300cfb
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 579c755cd334bb9dbb4f23402de2f7982d7b62f1d6a852524834ddc28f09a099e849d8a7c3111e89dfbed39ece1eb2467a07cb333dc8b7f1b458cc209eda1bc1
|
7
|
+
data.tar.gz: 84c58c57130167b1eab5162aaf4aa000e62ec1f38fd3e550f802602f483e85c1a4ff969fe31d7bc30fff2cfc14e3c8243a90dfde32495257cb4bb0070bc509b5
|
data/Gemfile
CHANGED
data/Rakefile
CHANGED
@@ -1,6 +1,9 @@
|
|
1
1
|
require 'rake'
|
2
2
|
require 'rake/testtask'
|
3
3
|
|
4
|
+
$:.unshift 'lib'
|
5
|
+
require 'device_detector'
|
6
|
+
|
4
7
|
Rake::TestTask.new do |t|
|
5
8
|
t.pattern = 'spec/**/*_spec.rb'
|
6
9
|
t.libs.push 'spec'
|
@@ -9,14 +12,12 @@ end
|
|
9
12
|
task default: :test
|
10
13
|
|
11
14
|
task :detectable_names do
|
12
|
-
|
13
|
-
bot_names = DeviceDetector::Bot.new.send(:regexes).map { |r| r['name'] }.uniq
|
15
|
+
bot_names = DeviceDetector::Bot.new.send(:regexes).map { |r| r['name'] }.uniq.sort_by { |n| n.downcase }
|
14
16
|
bot_names.delete('$1')
|
15
|
-
client_names = DeviceDetector::Client.new.send(:regexes).map { |r| r['name'] }.uniq
|
17
|
+
client_names = DeviceDetector::Client.new.send(:regexes).map { |r| r['name'] }.uniq.sort_by { |n| n.downcase }
|
16
18
|
client_names.delete('$1')
|
17
|
-
|
18
|
-
|
19
|
-
device_names = device_regexes.flat_map { |dn| dn.keys }.sort.uniq
|
19
|
+
device_regexes = DeviceDetector::Device.new.send(:load_regexes)
|
20
|
+
device_names = device_regexes.flat_map { |dn| dn.keys }.uniq.sort_by { |n| n.downcase }
|
20
21
|
|
21
22
|
today = Date.today.strftime
|
22
23
|
|
@@ -38,3 +39,8 @@ task :detectable_names do
|
|
38
39
|
puts
|
39
40
|
end
|
40
41
|
|
42
|
+
desc 'update regex database from piwik project'
|
43
|
+
task :update_regexes do
|
44
|
+
top = File.expand_path('..', __FILE__)
|
45
|
+
system "curl -s -L https://api.github.com/repos/piwik/device-detector/tarball/master | tar xzvf - --strip-components 1 --include */regexes/*.yml -C #{top}"
|
46
|
+
end
|
data/device_detector.gemspec
CHANGED
data/lib/device_detector.rb
CHANGED
@@ -1,8 +1,5 @@
|
|
1
1
|
require 'yaml'
|
2
2
|
|
3
|
-
$LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
|
4
|
-
$LOAD_PATH.unshift(File.dirname(__FILE__))
|
5
|
-
|
6
3
|
require 'device_detector/version'
|
7
4
|
require 'device_detector/metadata_extractor'
|
8
5
|
require 'device_detector/version_extractor'
|
@@ -44,7 +41,55 @@ class DeviceDetector
|
|
44
41
|
end
|
45
42
|
|
46
43
|
def device_type
|
47
|
-
device.type
|
44
|
+
t = device.type
|
45
|
+
|
46
|
+
if t.nil? && android_tablet_fragment?
|
47
|
+
t = 'tablet'
|
48
|
+
end
|
49
|
+
|
50
|
+
if t.nil? && android_mobile_fragment?
|
51
|
+
t = 'smartphone'
|
52
|
+
end
|
53
|
+
|
54
|
+
# Android up to 3.0 was designed for smartphones only. But as 3.0,
|
55
|
+
# which was tablet only, was published too late, there were a
|
56
|
+
# bunch of tablets running with 2.x With 4.0 the two trees were
|
57
|
+
# merged and it is for smartphones and tablets
|
58
|
+
#
|
59
|
+
# So were are expecting that all devices running Android < 2 are
|
60
|
+
# smartphones Devices running Android 3.X are tablets. Device type
|
61
|
+
# of Android 2.X and 4.X+ are unknown
|
62
|
+
if t.nil? && os.short_name == 'AND' && os.full_version && !os.full_version.empty?
|
63
|
+
if os.full_version < '2'
|
64
|
+
t = 'smartphone'
|
65
|
+
elsif os.full_version >= '3' && os.full_version < '4'
|
66
|
+
t = 'tablet'
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
# All detected feature phones running android are more likely a smartphone
|
71
|
+
if t == 'feature phone' && os.family == 'Android'
|
72
|
+
t = 'smartphone'
|
73
|
+
end
|
74
|
+
|
75
|
+
# According to http://msdn.microsoft.com/en-us/library/ie/hh920767(v=vs.85).aspx
|
76
|
+
# Internet Explorer 10 introduces the "Touch" UA string token. If this token is present at the end of the
|
77
|
+
# UA string, the computer has touch capability, and is running Windows 8 (or later).
|
78
|
+
# This UA string will be transmitted on a touch-enabled system running Windows 8 (RT)
|
79
|
+
#
|
80
|
+
# As most touch enabled devices are tablets and only a smaller part are desktops/notebooks we assume that
|
81
|
+
# all Windows 8 touch devices are tablets.
|
82
|
+
if t.nil? && touch_enabled? &&
|
83
|
+
(os.short_name == 'WRT' || (os.short_name == 'WIN' && os.full_version && os.full_version >= '8'))
|
84
|
+
t = 'tablet'
|
85
|
+
end
|
86
|
+
|
87
|
+
# set device type to desktop for all devices running a desktop os that were not detected as an other device type
|
88
|
+
if t.nil? && os.desktop?
|
89
|
+
t = 'desktop'
|
90
|
+
end
|
91
|
+
|
92
|
+
t
|
48
93
|
end
|
49
94
|
|
50
95
|
def known?
|
@@ -104,4 +149,20 @@ class DeviceDetector
|
|
104
149
|
@os ||= OS.new(user_agent)
|
105
150
|
end
|
106
151
|
|
152
|
+
def android_tablet_fragment?
|
153
|
+
user_agent =~ build_regex('Android; Tablet;')
|
154
|
+
end
|
155
|
+
|
156
|
+
def android_mobile_fragment?
|
157
|
+
user_agent =~ build_regex('Android; Mobile;')
|
158
|
+
end
|
159
|
+
|
160
|
+
def touch_enabled?
|
161
|
+
user_agent =~ build_regex('Touch')
|
162
|
+
end
|
163
|
+
|
164
|
+
def build_regex(src)
|
165
|
+
Regexp.new('(?:^|[^A-Z0-9\_\-])(?:' + src + ')', Regexp::IGNORECASE)
|
166
|
+
end
|
167
|
+
|
107
168
|
end
|
@@ -9,12 +9,12 @@ class DeviceDetector
|
|
9
9
|
|
10
10
|
def filenames
|
11
11
|
[
|
12
|
-
'
|
13
|
-
'
|
14
|
-
'
|
15
|
-
'
|
16
|
-
'
|
17
|
-
'
|
12
|
+
'client/feed_readers.yml',
|
13
|
+
'client/mobile_apps.yml',
|
14
|
+
'client/mediaplayers.yml',
|
15
|
+
'client/pim.yml',
|
16
|
+
'client/browsers.yml',
|
17
|
+
'client/libraries.yml',
|
18
18
|
]
|
19
19
|
end
|
20
20
|
end
|
@@ -1,6 +1,21 @@
|
|
1
1
|
class DeviceDetector
|
2
2
|
class Device < Parser
|
3
3
|
|
4
|
+
# order is relevant for testing with fixtures
|
5
|
+
DEVICE_NAMES = [
|
6
|
+
'desktop',
|
7
|
+
'smartphone',
|
8
|
+
'tablet',
|
9
|
+
'feature phone',
|
10
|
+
'console',
|
11
|
+
'tv',
|
12
|
+
'car browser',
|
13
|
+
'smart display',
|
14
|
+
'camera',
|
15
|
+
'portable media player',
|
16
|
+
'phablet'
|
17
|
+
]
|
18
|
+
|
4
19
|
def known?
|
5
20
|
regex_meta.any?
|
6
21
|
end
|
@@ -10,50 +25,66 @@ class DeviceDetector
|
|
10
25
|
end
|
11
26
|
|
12
27
|
def type
|
13
|
-
regex_meta[
|
28
|
+
hbbtv? ? 'tv' : regex_meta[:device]
|
14
29
|
end
|
15
30
|
|
16
31
|
private
|
17
32
|
|
18
|
-
# The order of files
|
19
|
-
#
|
20
|
-
# which would otherwise be detected as iPhones
|
21
|
-
# televisions.yml works best at the end
|
33
|
+
# The order of files needs to be the same as the order of device
|
34
|
+
# parser classes used in the piwik project.
|
22
35
|
def filenames
|
23
36
|
[
|
24
|
-
'
|
25
|
-
'
|
26
|
-
'
|
27
|
-
'
|
28
|
-
'
|
29
|
-
'
|
37
|
+
'device/televisions.yml',
|
38
|
+
'device/consoles.yml',
|
39
|
+
'device/car_browsers.yml',
|
40
|
+
'device/cameras.yml',
|
41
|
+
'device/portable_media_player.yml',
|
42
|
+
'device/mobiles.yml',
|
30
43
|
]
|
31
44
|
end
|
32
45
|
|
33
|
-
def
|
34
|
-
|
46
|
+
def matching_regex
|
47
|
+
from_cache([self.class.name, user_agent]) do
|
48
|
+
regex_list = hbbtv? ? regexes_for_hbbtv : regexes_other
|
49
|
+
regex = regex_list.find { |r| user_agent =~ r[:regex] }
|
50
|
+
if regex && regex[:models]
|
51
|
+
model_regex = regex[:models].find { |m| user_agent =~ m[:regex]}
|
52
|
+
if model_regex
|
53
|
+
regex = regex.merge(:regex_model => model_regex[:regex], :model => model_regex[:model])
|
54
|
+
regex[:device] = model_regex[:device] if model_regex.key?(:device)
|
55
|
+
regex.delete(:models)
|
56
|
+
end
|
57
|
+
end
|
58
|
+
regex
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
def hbbtv?
|
63
|
+
@regex_hbbtv ||= build_regex('HbbTV/([1-9]{1}(\.[0-9]{1}){1,2})')
|
64
|
+
user_agent =~ @regex_hbbtv
|
65
|
+
end
|
35
66
|
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
else
|
40
|
-
regex =
|
41
|
-
case base
|
42
|
-
when Hash
|
43
|
-
base
|
44
|
-
when String
|
45
|
-
nest
|
46
|
-
else
|
47
|
-
fail "#{filenames.join(', ')} regexes are either malformed or format has changes."
|
48
|
-
end
|
67
|
+
def regexes_for_hbbtv
|
68
|
+
regexes.select { |r| r[:path] == :'device/televisions.yml' }
|
69
|
+
end
|
49
70
|
|
50
|
-
|
51
|
-
|
71
|
+
def regexes_other
|
72
|
+
regexes.select { |r| r[:path] != :'device/televisions.yml' }
|
73
|
+
end
|
52
74
|
|
53
|
-
|
75
|
+
def parse_regexes(path, raw_regexes)
|
76
|
+
raw_regexes.map do |brand, meta|
|
77
|
+
fail "invalid device spec: #{meta.inspect}" unless meta[:regex].is_a? String
|
78
|
+
meta[:regex] = build_regex(meta[:regex])
|
79
|
+
if meta.key?(:models)
|
80
|
+
meta[:models].each do |model|
|
81
|
+
fail "invalid model spec: #{model.inspect}" unless model[:regex].is_a? String
|
82
|
+
model[:regex] = build_regex(model[:regex])
|
83
|
+
end
|
54
84
|
end
|
55
|
-
|
56
|
-
|
85
|
+
meta[:path] = path
|
86
|
+
meta
|
87
|
+
end
|
57
88
|
end
|
58
89
|
|
59
90
|
end
|
@@ -14,23 +14,14 @@ class DeviceDetector
|
|
14
14
|
|
15
15
|
def extract_metadata
|
16
16
|
user_agent.match(regex) do |match_data|
|
17
|
-
|
17
|
+
metadata_string.gsub(/\$(\d)/) {
|
18
|
+
match_data[$1.to_i].to_s
|
19
|
+
}.strip
|
18
20
|
end
|
19
21
|
end
|
20
22
|
|
21
|
-
def replace_metadata_string_with(match_data)
|
22
|
-
string = metadata_string
|
23
|
-
|
24
|
-
1.upto(9) do |index|
|
25
|
-
matched_data = String(match_data[index])
|
26
|
-
string = string.gsub(/\$#{index}/, matched_data)
|
27
|
-
end
|
28
|
-
|
29
|
-
string.strip
|
30
|
-
end
|
31
|
-
|
32
23
|
def regex
|
33
|
-
@regex ||= regex_meta[
|
24
|
+
@regex ||= regex_meta[:regex]
|
34
25
|
end
|
35
26
|
|
36
27
|
end
|
@@ -1,10 +1,19 @@
|
|
1
1
|
class DeviceDetector
|
2
2
|
class ModelExtractor < MetadataExtractor
|
3
3
|
|
4
|
+
def call
|
5
|
+
s = super.to_s.gsub('_',' ').strip
|
6
|
+
s.empty? ? nil : s
|
7
|
+
end
|
8
|
+
|
4
9
|
private
|
5
10
|
|
6
11
|
def metadata_string
|
7
|
-
String(regex_meta[
|
12
|
+
String(regex_meta[:model])
|
13
|
+
end
|
14
|
+
|
15
|
+
def regex
|
16
|
+
@regex ||= regex_meta[:regex_model] || regex_meta[:regex]
|
8
17
|
end
|
9
18
|
|
10
19
|
end
|
data/lib/device_detector/os.rb
CHANGED
@@ -1,16 +1,152 @@
|
|
1
|
+
require 'set'
|
2
|
+
|
1
3
|
class DeviceDetector
|
2
4
|
class OS < Parser
|
3
5
|
|
6
|
+
def name
|
7
|
+
os_info[:name]
|
8
|
+
end
|
9
|
+
|
10
|
+
def short_name
|
11
|
+
os_info[:short]
|
12
|
+
end
|
13
|
+
|
14
|
+
def family
|
15
|
+
os_info[:family]
|
16
|
+
end
|
17
|
+
|
18
|
+
def desktop?
|
19
|
+
DESKTOP_OSS.include?(family)
|
20
|
+
end
|
21
|
+
|
4
22
|
def full_version
|
5
|
-
raw_version = super
|
23
|
+
raw_version = super.to_s.split('_').join('.')
|
24
|
+
raw_version == '' ? nil : raw_version
|
25
|
+
end
|
26
|
+
|
27
|
+
private
|
6
28
|
|
7
|
-
|
8
|
-
|
9
|
-
|
29
|
+
def os_info
|
30
|
+
from_cache(['os_info', self.class.name, user_agent]) do
|
31
|
+
os_name = NameExtractor.new(user_agent, regex_meta).call
|
32
|
+
if os_name && short = DOWNCASED_OPERATING_SYSTEMS[os_name.downcase]
|
33
|
+
os_name = OPERATING_SYSTEMS[short]
|
34
|
+
else
|
35
|
+
short = 'UNK'
|
36
|
+
end
|
37
|
+
{ name: os_name, short: short, family: FAMILY_TO_OS[short] }
|
10
38
|
end
|
11
39
|
end
|
12
40
|
|
13
|
-
|
41
|
+
DESKTOP_OSS = Set.new(['AmigaOS', 'IBM', 'GNU/Linux', 'Mac', 'Unix', 'Windows', 'BeOS', 'Chrome OS'])
|
42
|
+
|
43
|
+
# OS short codes mapped to long names
|
44
|
+
OPERATING_SYSTEMS = {
|
45
|
+
'AIX' => 'AIX',
|
46
|
+
'AND' => 'Android',
|
47
|
+
'AMG' => 'AmigaOS',
|
48
|
+
'ATV' => 'Apple TV',
|
49
|
+
'ARL' => 'Arch Linux',
|
50
|
+
'BTR' => 'BackTrack',
|
51
|
+
'SBA' => 'Bada',
|
52
|
+
'BEO' => 'BeOS',
|
53
|
+
'BLB' => 'BlackBerry OS',
|
54
|
+
'QNX' => 'BlackBerry Tablet OS',
|
55
|
+
'BMP' => 'Brew',
|
56
|
+
'CES' => 'CentOS',
|
57
|
+
'COS' => 'Chrome OS',
|
58
|
+
'CYN' => 'CyanogenMod',
|
59
|
+
'DEB' => 'Debian',
|
60
|
+
'DFB' => 'DragonFly',
|
61
|
+
'FED' => 'Fedora',
|
62
|
+
'FOS' => 'Firefox OS',
|
63
|
+
'BSD' => 'FreeBSD',
|
64
|
+
'GNT' => 'Gentoo',
|
65
|
+
'GTV' => 'Google TV',
|
66
|
+
'HPX' => 'HP-UX',
|
67
|
+
'HAI' => 'Haiku OS',
|
68
|
+
'IRI' => 'IRIX',
|
69
|
+
'INF' => 'Inferno',
|
70
|
+
'KNO' => 'Knoppix',
|
71
|
+
'KBT' => 'Kubuntu',
|
72
|
+
'LIN' => 'GNU/Linux',
|
73
|
+
'LBT' => 'Lubuntu',
|
74
|
+
'VLN' => 'VectorLinux',
|
75
|
+
'MAC' => 'Mac',
|
76
|
+
'MDR' => 'Mandriva',
|
77
|
+
'SMG' => 'MeeGo',
|
78
|
+
'MCD' => 'MocorDroid',
|
79
|
+
'MIN' => 'Mint',
|
80
|
+
'MLD' => 'MildWild',
|
81
|
+
'MOR' => 'MorphOS',
|
82
|
+
'NBS' => 'NetBSD',
|
83
|
+
'WII' => 'Nintendo',
|
84
|
+
'NDS' => 'Nintendo Mobile',
|
85
|
+
'OS2' => 'OS/2',
|
86
|
+
'T64' => 'OSF1',
|
87
|
+
'OBS' => 'OpenBSD',
|
88
|
+
'PSP' => 'PlayStation Portable',
|
89
|
+
'PS3' => 'PlayStation',
|
90
|
+
'RHT' => 'Red Hat',
|
91
|
+
'ROS' => 'RISC OS',
|
92
|
+
'RZD' => 'RazoDroiD',
|
93
|
+
'SAB' => 'Sabayon',
|
94
|
+
'SSE' => 'SUSE',
|
95
|
+
'SAF' => 'Sailfish OS',
|
96
|
+
'SLW' => 'Slackware',
|
97
|
+
'SOS' => 'Solaris',
|
98
|
+
'SYL' => 'Syllable',
|
99
|
+
'SYM' => 'Symbian',
|
100
|
+
'SYS' => 'Symbian OS',
|
101
|
+
'S40' => 'Symbian OS Series 40',
|
102
|
+
'S60' => 'Symbian OS Series 60',
|
103
|
+
'SY3' => 'Symbian^3',
|
104
|
+
'TIZ' => 'Tizen',
|
105
|
+
'UBT' => 'Ubuntu',
|
106
|
+
'WTV' => 'WebTV',
|
107
|
+
'WIN' => 'Windows',
|
108
|
+
'WCE' => 'Windows CE',
|
109
|
+
'WMO' => 'Windows Mobile',
|
110
|
+
'WPH' => 'Windows Phone',
|
111
|
+
'WRT' => 'Windows RT',
|
112
|
+
'XBX' => 'Xbox',
|
113
|
+
'XBT' => 'Xubuntu',
|
114
|
+
'YNS' => 'YunOs',
|
115
|
+
'IOS' => 'iOS',
|
116
|
+
'POS' => 'palmOS',
|
117
|
+
'WOS' => 'webOS'
|
118
|
+
}
|
119
|
+
|
120
|
+
DOWNCASED_OPERATING_SYSTEMS = OPERATING_SYSTEMS.each_with_object({}){|(short,long),h| h[long.downcase] = short}
|
121
|
+
|
122
|
+
OS_FAMILIES = {
|
123
|
+
'Android' => ['AND', 'CYN', 'RZD', 'MLD', 'MCD'],
|
124
|
+
'AmigaOS' => ['AMG', 'MOR'],
|
125
|
+
'Apple TV' => ['ATV'],
|
126
|
+
'BlackBerry' => ['BLB', 'QNX'],
|
127
|
+
'Brew' => ['BMP'],
|
128
|
+
'BeOS' => ['BEO', 'HAI'],
|
129
|
+
'Chrome OS' => ['COS'],
|
130
|
+
'Firefox OS' => ['FOS'],
|
131
|
+
'Gaming Console' => ['WII', 'PS3'],
|
132
|
+
'Google TV' => ['GTV'],
|
133
|
+
'IBM' => ['OS2'],
|
134
|
+
'iOS' => ['IOS'],
|
135
|
+
'RISC OS' => ['ROS'],
|
136
|
+
'GNU/Linux' => ['LIN', 'ARL', 'DEB', 'KNO', 'MIN', 'UBT', 'KBT', 'XBT', 'LBT', 'FED', 'RHT', 'VLN', 'MDR', 'GNT', 'SAB', 'SLW', 'SSE', 'CES', 'BTR', 'YNS', 'SAF'],
|
137
|
+
'Mac' => ['MAC'],
|
138
|
+
'Mobile Gaming Console' => ['PSP', 'NDS', 'XBX'],
|
139
|
+
'Other Mobile' => ['WOS', 'POS', 'SBA', 'TIZ', 'SMG'],
|
140
|
+
'Symbian' => ['SYM', 'SYS', 'SY3', 'S60', 'S40'],
|
141
|
+
'Unix' => ['SOS', 'AIX', 'HPX', 'BSD', 'NBS', 'OBS', 'DFB', 'SYL', 'IRI', 'T64', 'INF'],
|
142
|
+
'WebTV' => ['WTV'],
|
143
|
+
'Windows' => ['WIN'],
|
144
|
+
'Windows Mobile' => ['WPH', 'WMO', 'WCE', 'WRT']
|
145
|
+
}
|
146
|
+
|
147
|
+
FAMILY_TO_OS = OS_FAMILIES.each_with_object({}) do |(family,oss),h|
|
148
|
+
oss.each{|os| h[os] = family}
|
149
|
+
end
|
14
150
|
|
15
151
|
def filenames
|
16
152
|
['oss.yml']
|