browser2 1.0.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.
Files changed (65) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +5 -0
  3. data/.hound.yml +90 -0
  4. data/.rubocop.yml +90 -0
  5. data/.travis.yml +14 -0
  6. data/CONTRIBUTING.md +44 -0
  7. data/Gemfile +2 -0
  8. data/LICENSE +20 -0
  9. data/README.md +125 -0
  10. data/Rakefile +33 -0
  11. data/browser2.gemspec +42 -0
  12. data/config.ru +2 -0
  13. data/data/bots.json +176 -0
  14. data/data/languages.json +115 -0
  15. data/gemfiles/rails3.gemfile +4 -0
  16. data/lib/browser/action_controller.rb +20 -0
  17. data/lib/browser/data/bots.rb +5 -0
  18. data/lib/browser/data/languages.rb +5 -0
  19. data/lib/browser/data/search_engines.rb +14 -0
  20. data/lib/browser/meta/base.rb +20 -0
  21. data/lib/browser/meta/generic_browser.rb +15 -0
  22. data/lib/browser/meta/id.rb +9 -0
  23. data/lib/browser/meta/ie.rb +18 -0
  24. data/lib/browser/meta/ios.rb +9 -0
  25. data/lib/browser/meta/mobile.rb +9 -0
  26. data/lib/browser/meta/modern.rb +9 -0
  27. data/lib/browser/meta/platform.rb +9 -0
  28. data/lib/browser/meta/safari.rb +9 -0
  29. data/lib/browser/meta/webkit.rb +9 -0
  30. data/lib/browser/methods/blackberry.rb +51 -0
  31. data/lib/browser/methods/bots.rb +37 -0
  32. data/lib/browser/methods/consoles.rb +43 -0
  33. data/lib/browser/methods/devices.rb +41 -0
  34. data/lib/browser/methods/ie.rb +104 -0
  35. data/lib/browser/methods/language.rb +16 -0
  36. data/lib/browser/methods/mobile.rb +30 -0
  37. data/lib/browser/methods/platform.rb +142 -0
  38. data/lib/browser/methods/tv.rb +8 -0
  39. data/lib/browser/middleware/context/additions.rb +16 -0
  40. data/lib/browser/middleware/context/url_methods.rb +13 -0
  41. data/lib/browser/middleware/context.rb +20 -0
  42. data/lib/browser/middleware.rb +66 -0
  43. data/lib/browser/rails.rb +14 -0
  44. data/lib/browser/version.rb +8 -0
  45. data/lib/browser.rb +255 -0
  46. data/test/benchmark_test.rb +83 -0
  47. data/test/browser_test.rb +248 -0
  48. data/test/middleware_test.rb +50 -0
  49. data/test/sample_app.rb +31 -0
  50. data/test/test_helper.rb +20 -0
  51. data/test/ua.yml +122 -0
  52. data/test/unit/adobe_air_test.rb +13 -0
  53. data/test/unit/android_test.rb +93 -0
  54. data/test/unit/blackberry_test.rb +104 -0
  55. data/test/unit/bots_test.rb +116 -0
  56. data/test/unit/chrome_test.rb +56 -0
  57. data/test/unit/console_test.rb +67 -0
  58. data/test/unit/firefox_test.rb +37 -0
  59. data/test/unit/ie_test.rb +377 -0
  60. data/test/unit/ios_test.rb +139 -0
  61. data/test/unit/kindle_test.rb +37 -0
  62. data/test/unit/opera_test.rb +42 -0
  63. data/test/unit/windows_phone_test.rb +50 -0
  64. data/test/unit/windows_test.rb +60 -0
  65. metadata +240 -0
@@ -0,0 +1,115 @@
1
+ {
2
+ "af": "Afrikaans",
3
+ "sq": "Albanian",
4
+ "eu": "Basque",
5
+ "bg": "Bulgarian",
6
+ "be": "Byelorussian",
7
+ "ca": "Catalan",
8
+ "zh": "Chinese",
9
+ "zh-cn": "Chinese/China",
10
+ "zh-tw": "Chinese/Taiwan",
11
+ "zh-hk": "Chinese/Hong Kong",
12
+ "zh-sg": "Chinese/singapore",
13
+ "hr": "Croatian",
14
+ "cs": "Czech",
15
+ "da": "Danish",
16
+ "nl": "Dutch",
17
+ "nl-nl": "Dutch/Netherlands",
18
+ "nl-be": "Dutch/Belgium",
19
+ "en": "English",
20
+ "en-gb": "English/United Kingdom",
21
+ "en-us": "English/United States",
22
+ "en-au": "English/Australian",
23
+ "en-ca": "English/Canada",
24
+ "en-nz": "English/New Zealand",
25
+ "en-ie": "English/Ireland",
26
+ "en-za": "English/South Africa",
27
+ "en-jm": "English/Jamaica",
28
+ "en-bz": "English/Belize",
29
+ "en-tt": "English/Trinidad",
30
+ "et": "Estonian",
31
+ "fo": "Faeroese",
32
+ "fa": "Farsi",
33
+ "fi": "Finnish",
34
+ "fr": "French",
35
+ "fr-be": "French/Belgium",
36
+ "fr-fr": "French/France",
37
+ "fr-ch": "French/Switzerland",
38
+ "fr-ca": "French/Canada",
39
+ "fr-lu": "French/Luxembourg",
40
+ "gl": "Galician",
41
+ "de": "German",
42
+ "de-at": "German/Austria",
43
+ "de-de": "German/Germany",
44
+ "de-ch": "German/Switzerland",
45
+ "de-lu": "German/Luxembourg",
46
+ "de-li": "German/Liechtenstein",
47
+ "el": "Greek",
48
+ "he": "Hebrew",
49
+ "he-il": "Hebrew/Israel",
50
+ "hi": "Hindi",
51
+ "hu": "Hungarian",
52
+ "ie-ee": "Internet Explorer/Easter Egg",
53
+ "is": "Icelandic",
54
+ "id": "Indonesian",
55
+ "in": "Indonesian",
56
+ "ga": "Irish",
57
+ "it": "Italian",
58
+ "it-ch": "Italian/ Switzerland",
59
+ "ja": "Japanese",
60
+ "km": "Khmer",
61
+ "km-kh": "Khmer/Cambodia",
62
+ "ko": "Korean",
63
+ "lv": "Latvian",
64
+ "lt": "Lithuanian",
65
+ "mk": "Macedonian",
66
+ "ms": "Malaysian",
67
+ "mt": "Maltese",
68
+ "no": "Norwegian",
69
+ "pl": "Polish",
70
+ "pt": "Portuguese",
71
+ "pt-br": "Portuguese/Brazil",
72
+ "rm": "Rhaeto-Romanic",
73
+ "ro": "Romanian",
74
+ "ro-mo": "Romanian/Moldavia",
75
+ "ru": "Russian",
76
+ "ru-mo": "Russian /Moldavia",
77
+ "gd": "Scots Gaelic",
78
+ "sr": "Serbian",
79
+ "sk": "Slovack",
80
+ "sl": "Slovenian",
81
+ "sb": "Sorbian",
82
+ "es": "Spanish",
83
+ "es-do": "Spanish",
84
+ "es-ar": "Spanish/Argentina",
85
+ "es-co": "Spanish/Colombia",
86
+ "es-mx": "Spanish/Mexico",
87
+ "es-es": "Spanish/Spain",
88
+ "es-gt": "Spanish/Guatemala",
89
+ "es-cr": "Spanish/Costa Rica",
90
+ "es-pa": "Spanish/Panama",
91
+ "es-ve": "Spanish/Venezuela",
92
+ "es-pe": "Spanish/Peru",
93
+ "es-ec": "Spanish/Ecuador",
94
+ "es-cl": "Spanish/Chile",
95
+ "es-uy": "Spanish/Uruguay",
96
+ "es-py": "Spanish/Paraguay",
97
+ "es-bo": "Spanish/Bolivia",
98
+ "es-sv": "Spanish/El salvador",
99
+ "es-hn": "Spanish/Honduras",
100
+ "es-ni": "Spanish/Nicaragua",
101
+ "es-pr": "Spanish/Puerto Rico",
102
+ "sx": "Sutu",
103
+ "sv": "Swedish",
104
+ "sv-se": "Swedish/Sweden",
105
+ "sv-fi": "Swedish/Finland",
106
+ "ts": "Thai",
107
+ "tn": "Tswana",
108
+ "tr": "Turkish",
109
+ "uk": "Ukrainian",
110
+ "ur": "Urdu",
111
+ "vi": "Vietnamese",
112
+ "xh": "Xshosa",
113
+ "ji": "Yiddish",
114
+ "zu": "Zulu"
115
+ }
@@ -0,0 +1,4 @@
1
+ source "https://rubygems.org"
2
+ gemspec path: ".."
3
+
4
+ gem "rails", "~> 3.2.13"
@@ -0,0 +1,20 @@
1
+ require "action_controller/railtie"
2
+
3
+ class Browser
4
+ module ActionController
5
+ extend ActiveSupport::Concern
6
+
7
+ included do
8
+ helper_method :browser
9
+ end
10
+
11
+ private
12
+
13
+ def browser
14
+ @browser ||= Browser.new(
15
+ accept_language: request.headers["Accept-Language"],
16
+ ua: request.headers["User-Agent"]
17
+ )
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,5 @@
1
+ class Browser
2
+ module Data
3
+ BOTS = MultiJson.load File.read(File.expand_path('../../../../data/bots.json', __FILE__))
4
+ end
5
+ end
@@ -0,0 +1,5 @@
1
+ class Browser
2
+ module Data
3
+ LANGUAGES = MultiJson.load File.read(File.expand_path('../../../../data/languages.json', __FILE__))
4
+ end
5
+ end
@@ -0,0 +1,14 @@
1
+ # frozen_string_literal: true
2
+
3
+ class Browser
4
+ module Data
5
+ SEARCH_ENGINES = {
6
+ 'Baidu' => 'Chinese search engine',
7
+ 'bingbot' => 'Microsoft bing bot',
8
+ 'Googlebot' => 'Google spider',
9
+ 'Slurp' => 'Yahoo spider',
10
+ 'DuckDuckBot' => 'Duck Duck Go',
11
+ 'Ask Jeeves' => 'Ask Jeeves'
12
+ }.freeze
13
+ end
14
+ end
@@ -0,0 +1,20 @@
1
+ class Browser
2
+ module Meta
3
+ class Base
4
+ # Set the browser instance.
5
+ attr_reader :browser
6
+
7
+ def initialize(browser)
8
+ @browser = browser
9
+ end
10
+
11
+ def meta
12
+ nil
13
+ end
14
+
15
+ def to_a
16
+ meta.to_s.squeeze(" ").split(" ")
17
+ end
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,15 @@
1
+ class Browser
2
+ module Meta
3
+ class GenericBrowser < Base
4
+ def meta
5
+ "#{browser.id} #{browser.id}#{browser.version}" if generic?
6
+ end
7
+
8
+ private
9
+
10
+ def generic?
11
+ !browser.safari? && !browser.chrome?
12
+ end
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,9 @@
1
+ class Browser
2
+ module Meta
3
+ class Id < Base
4
+ def meta
5
+ browser.id
6
+ end
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,18 @@
1
+ class Browser
2
+ module Meta
3
+ class IE < Base
4
+ def version
5
+ @version ||= browser.version.to_i
6
+ end
7
+
8
+ def meta
9
+ return unless browser.ie?
10
+
11
+ meta = ""
12
+ meta << "oldie lt-ie8 lt-ie9" if version < 8
13
+ meta << "lt-ie9" if version == 8
14
+ meta
15
+ end
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,9 @@
1
+ class Browser
2
+ module Meta
3
+ class IOS < Base
4
+ def meta
5
+ "ios" if browser.ios?
6
+ end
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,9 @@
1
+ class Browser
2
+ module Meta
3
+ class Mobile < Base
4
+ def meta
5
+ "mobile" if browser.mobile?
6
+ end
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,9 @@
1
+ class Browser
2
+ module Meta
3
+ class Modern < Base
4
+ def meta
5
+ "modern" if browser.modern?
6
+ end
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,9 @@
1
+ class Browser
2
+ module Meta
3
+ class Platform < Base
4
+ def meta
5
+ browser.platform
6
+ end
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,9 @@
1
+ class Browser
2
+ module Meta
3
+ class Safari < Base
4
+ def meta
5
+ "safari safari#{browser.version}" if browser.safari?
6
+ end
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,9 @@
1
+ class Browser
2
+ module Meta
3
+ class Webkit < Base
4
+ def meta
5
+ "webkit" if browser.webkit?
6
+ end
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,51 @@
1
+ class Browser
2
+ module BlackBerry
3
+ # Return BlackBerry version.
4
+ def blackberry_version
5
+ ua[/BB(10)/, 1] ||
6
+ ua[/BlackBerry\d+\/(\d+)/, 1] ||
7
+ ua[/BlackBerry.*?Version\/(\d+)/, 1]
8
+ end
9
+
10
+ # Detect if browser is BlackBerry
11
+ def blackberry?(version = nil)
12
+ !!(ua =~ /(BlackBerry|BB10)/) && detect_version?(blackberry_version, version)
13
+ end
14
+
15
+ # Detect if is BlackBerry 4.
16
+ def blackberry4?
17
+ deprecate "Browser##{__method__} is deprecated; use Browser#ie?(version) instead"
18
+ blackberry?(4)
19
+ end
20
+
21
+ # Detect if is BlackBerry 5.
22
+ def blackberry5?
23
+ deprecate "Browser##{__method__} is deprecated; use Browser#ie?(version) instead"
24
+ blackberry?(5)
25
+ end
26
+
27
+ # Detect if is BlackBerry 6.
28
+ def blackberry6?
29
+ deprecate "Browser##{__method__} is deprecated; use Browser#ie?(version) instead"
30
+ blackberry?(6)
31
+ end
32
+
33
+ # Detect if is BlackBerry 7.
34
+ def blackberry7?
35
+ deprecate "Browser##{__method__} is deprecated; use Browser#ie?(version) instead"
36
+ blackberry?(7)
37
+ end
38
+
39
+ # Detect if is BlackBerry 10.
40
+ def blackberry10?
41
+ deprecate "Browser##{__method__} is deprecated; use Browser#blackberry?(version) instead"
42
+ blackberry?(10)
43
+ end
44
+
45
+ private
46
+
47
+ def blackberry_running_safari?
48
+ blackberry? && safari?
49
+ end
50
+ end
51
+ end
@@ -0,0 +1,37 @@
1
+ # frozen_string_literal: true
2
+
3
+ class Browser
4
+ module Bots
5
+ BOTS = Browser::Data::BOTS
6
+ SEARCH_ENGINES = Browser::Data::SEARCH_ENGINES
7
+
8
+ def self.detect_empty_ua!
9
+ @detect_empty_ua = true
10
+ end
11
+
12
+ def self.detect_empty_ua?
13
+ !!@detect_empty_ua
14
+ end
15
+
16
+ def bot?
17
+ bot_with_empty_ua? || BOTS.any? {|key, _| ua.include?(key) }
18
+ end
19
+
20
+ def bot_name
21
+ return 'Generic Bot' if bot_with_empty_ua?
22
+
23
+ pair = BOTS.find {|key, _| ua.include?(key) }
24
+ return pair ? pair.first : nil
25
+ end
26
+
27
+ def search_engine?
28
+ SEARCH_ENGINES.any? {|key, _| ua.include?(key) }
29
+ end
30
+
31
+ private
32
+
33
+ def bot_with_empty_ua?
34
+ Browser::Bots.detect_empty_ua? && ua.strip == ''
35
+ end
36
+ end
37
+ end
@@ -0,0 +1,43 @@
1
+ class Browser
2
+ module Consoles
3
+ # Detect if browser is running under Xbox.
4
+ def xbox?
5
+ !!(ua =~ /xbox/i)
6
+ end
7
+
8
+ # Detect if browser is running under Xbox One.
9
+ def xbox_one?
10
+ !!(ua =~ /xbox one/i)
11
+ end
12
+
13
+ # Detect if browser is running under PlayStation.
14
+ def playstation?
15
+ !!(ua =~ /playstation/i)
16
+ end
17
+
18
+ # Detect if browser is running under PlayStation 4.
19
+ def playstation4?
20
+ !!(ua =~ /playstation 4/i)
21
+ end
22
+
23
+ # Detect if browser is Nintendo.
24
+ def nintendo?
25
+ !!(ua =~ /nintendo/i)
26
+ end
27
+
28
+ # Detect if browser is console (currently Xbox, PlayStation, or Nintendo).
29
+ def console?
30
+ xbox? || playstation? || nintendo?
31
+ end
32
+
33
+ # Detect if browser is running from PSP.
34
+ def psp?
35
+ !!(ua =~ /(PSP)/ || psp_vita?)
36
+ end
37
+
38
+ # Detect if browser is running from PSP Vita.
39
+ def psp_vita?
40
+ !!(ua =~ /Playstation Vita/)
41
+ end
42
+ end
43
+ end
@@ -0,0 +1,41 @@
1
+ class Browser
2
+ module Devices
3
+ # Detect if browser is iPhone.
4
+ def iphone?
5
+ in_ua? 'iPhone'
6
+ end
7
+
8
+ # Detect if browser is iPad.
9
+ def ipad?
10
+ in_ua? 'iPad'
11
+ end
12
+
13
+ # Detect if browser is iPod.
14
+ def ipod?
15
+ in_ua? 'Pod'
16
+ end
17
+
18
+ def surface?
19
+ windows_rt? && in_ua?('Touch')
20
+ end
21
+
22
+ # Detect if browser is tablet (currently iPad, Android, Surface or Playbook).
23
+ def tablet?
24
+ !!(ipad? || (android? && !detect_mobile?) || surface? || playbook?)
25
+ end
26
+
27
+ # Detect if browser is Kindle.
28
+ def kindle?
29
+ in_ua?('Kindle') || silk?
30
+ end
31
+
32
+ # Detect if browser if a Blackberry Playbook tablet
33
+ def playbook?
34
+ !!(ua =~ /PlayBook/ && ua =~ /RIM Tablet/)
35
+ end
36
+
37
+ def windows_touchscreen_desktop?
38
+ windows? && !!(ua =~ /Touch/)
39
+ end
40
+ end
41
+ end
@@ -0,0 +1,104 @@
1
+ # frozen_string_literal: true
2
+
3
+ class Browser
4
+ module IE
5
+ TRIDENT_VERSION_REGEX = %r[Trident/([0-9.]+)]
6
+ MODERN_IE = %r[Trident/.*?; rv:(.*?)]
7
+ MSIE = %r{MSIE ([\d.]+)|Trident/.*?; rv:([\d.]+)}
8
+ EDGE = %r{(Edge/[\d.]+|Trident/8)}
9
+
10
+ # https://msdn.microsoft.com/en-us/library/ms537503(v=vs.85).aspx#TriToken
11
+ TRIDENT_MAPPING = {
12
+ "4.0" => "8",
13
+ "5.0" => "9",
14
+ "6.0" => "10",
15
+ "7.0" => "11",
16
+ "8.0" => "12"
17
+ }
18
+
19
+ def ie_version
20
+ TRIDENT_MAPPING[trident_version] || msie_version
21
+ end
22
+
23
+ def ie_full_version
24
+ "#{ie_version}.0"
25
+ end
26
+
27
+ def msie_full_version
28
+ (ua.match(MSIE) && ($1 || $2)) || "0.0"
29
+ end
30
+
31
+ def msie_version
32
+ msie_full_version.to_s.split(".").first || "0"
33
+ end
34
+
35
+ # Return the trident version.
36
+ def trident_version
37
+ ua.match(TRIDENT_VERSION_REGEX) && $1
38
+ end
39
+
40
+ # Detect if browser is Internet Explorer.
41
+ def ie?(version = nil)
42
+ (msie? || modern_ie?) && detect_version?(ie_version, version)
43
+ end
44
+
45
+ # Detect if browser is Internet Explorer 6.
46
+ def ie6?
47
+ deprecate "Browser##{__method__} is deprecated; use Browser#ie?(version) instead"
48
+ ie?(6)
49
+ end
50
+
51
+ # Detect if browser is Internet Explorer 7.
52
+ def ie7?
53
+ deprecate "Browser##{__method__} is deprecated; use Browser#ie?(version) instead"
54
+ ie?(7)
55
+ end
56
+
57
+ # Detect if browser is Internet Explorer 8.
58
+ def ie8?
59
+ deprecate "Browser##{__method__} is deprecated; use Browser#ie?(version) instead"
60
+ ie?(8)
61
+ end
62
+
63
+ # Detect if browser is Internet Explorer 9.
64
+ def ie9?
65
+ deprecate "Browser##{__method__} is deprecated; use Browser#ie?(version) instead"
66
+ ie?(9)
67
+ end
68
+
69
+ # Detect if browser is Internet Explorer 10.
70
+ def ie10?
71
+ deprecate "Browser##{__method__} is deprecated; use Browser#ie?(version) instead"
72
+ ie?(10)
73
+ end
74
+
75
+ # Detect if browser is Internet Explorer 11.
76
+ def ie11?
77
+ deprecate "Browser##{__method__} is deprecated; use Browser#ie?(version) instead"
78
+ ie?(11)
79
+ end
80
+
81
+ # Detect if browser is Microsoft Edge.
82
+ def edge?
83
+ in_ua?('Edge/') || in_ua?('Trident/8')
84
+
85
+ # Old regex approach:
86
+ # !!(ua =~ EDGE)
87
+ end
88
+
89
+ # Detect if IE is running in compatibility mode.
90
+ def compatibility_view?
91
+ ie? && trident_version && msie_version.to_i < (trident_version.to_i + 4)
92
+ end
93
+
94
+ private
95
+
96
+ def msie?
97
+ !!(ua =~ /MSIE/ && ua !~ /Opera/)
98
+ end
99
+
100
+ def modern_ie?
101
+ !!(ua =~ MODERN_IE)
102
+ end
103
+ end
104
+ end
@@ -0,0 +1,16 @@
1
+ class Browser
2
+ module Language
3
+ LANGUAGES = Browser::Data::LANGUAGES
4
+
5
+ # Set browser's preferred language
6
+ attr_writer :accept_language
7
+
8
+ # Return an array with all preferred languages that this browser accepts.
9
+ def accept_language
10
+ @accept_language
11
+ .gsub(/;q=[\d.]+/, "")
12
+ .split(",")
13
+ .map {|l| l.downcase.gsub(/\s/m, "") }
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,30 @@
1
+ class Browser
2
+ module Mobile
3
+ # Detect if browser is mobile.
4
+ def mobile?
5
+ detect_mobile? && !tablet?
6
+ end
7
+
8
+ # Detect if browser is Opera Mini.
9
+ def opera_mini?
10
+ !!(ua =~ /Opera Mini/)
11
+ end
12
+
13
+ # Detect if browser is Adobe AIR.
14
+ def adobe_air?
15
+ !!(ua =~ /adobeair/i)
16
+ end
17
+
18
+ private
19
+
20
+ # Regex taken from http://detectmobilebrowsers.com
21
+ def detect_mobile?
22
+ !!(
23
+ psp? ||
24
+ /zunewp7/i.match(ua) ||
25
+ /(android|bb\d+|meego).+mobile|avantgo|bada\/|blackberry|blazer|compal|elaine|fennec|hiptop|iemobile|ip(hone|od)|iris|kindle|lge |maemo|midp|mmp|mobile.+firefox|netfront|opera m(ob|in)i|palm( os)?|phone|p(ixi|re)\/|plucker|pocket|psp|series(4|6)0|symbian|treo|up\.(browser|link)|vodafone|wap|windows ce|xda|xiino/i.match(ua) ||
26
+ /1207|6310|6590|3gso|4thp|50[1-6]i|770s|802s|a wa|abac|ac(er|oo|s\-)|ai(ko|rn)|al(av|ca|co)|amoi|an(ex|ny|yw)|aptu|ar(ch|go)|as(te|us)|attw|au(di|\-m|r |s )|avan|be(ck|ll|nq)|bi(lb|rd)|bl(ac|az)|br(e|v)w|bumb|bw\-(n|u)|c55\/|capi|ccwa|cdm\-|cell|chtm|cldc|cmd\-|co(mp|nd)|craw|da(it|ll|ng)|dbte|dc\-s|devi|dica|dmob|do(c|p)o|ds(12|\-d)|el(49|ai)|em(l2|ul)|er(ic|k0)|esl8|ez([4-7]0|os|wa|ze)|fetc|fly(\-|_)|g1 u|g560|gene|gf\-5|g\-mo|go(\.w|od)|gr(ad|un)|haie|hcit|hd\-(m|p|t)|hei\-|hi(pt|ta)|hp( i|ip)|hs\-c|ht(c(\-| |_|a|g|p|s|t)|tp)|hu(aw|tc)|i\-(20|go|ma)|i230|iac( |\-|\/)|ibro|idea|ig01|ikom|im1k|inno|ipaq|iris|ja(t|v)a|jbro|jemu|jigs|kddi|keji|kgt( |\/)|klon|kpt |kwc\-|kyo(c|k)|le(no|xi)|lg( g|\/(k|l|u)|50|54|\-[a-w])|libw|lynx|m1\-w|m3ga|m50\/|ma(te|ui|xo)|mc(01|21|ca)|m\-cr|me(rc|ri)|mi(o8|oa|ts)|mmef|mo(01|02|bi|de|do|t(\-| |o|v)|zz)|mt(50|p1|v )|mwbp|mywa|n10[0-2]|n20[2-3]|n30(0|2)|n50(0|2|5)|n7(0(0|1)|10)|ne((c|m)\-|on|tf|wf|wg|wt)|nok(6|i)|nzph|o2im|op(ti|wv)|oran|owg1|p800|pan(a|d|t)|pdxg|pg(13|\-([1-8]|c))|phil|pire|pl(ay|uc)|pn\-2|po(ck|rt|se)|prox|psio|pt\-g|qa\-a|qc(07|12|21|32|60|\-[2-7]|i\-)|qtek|r380|r600|raks|rim9|ro(ve|zo)|s55\/|sa(ge|ma|mm|ms|ny|va)|sc(01|h\-|oo|p\-)|sdk\/|se(c(\-|0|1)|47|mc|nd|ri)|sgh\-|shar|sie(\-|m)|sk\-0|sl(45|id)|sm(al|ar|b3|it|t5)|so(ft|ny)|sp(01|h\-|v\-|v )|sy(01|mb)|t2(18|50)|t6(00|10|18)|ta(gt|lk)|tcl\-|tdg\-|tel(i|m)|tim\-|t\-mo|to(pl|sh)|ts(70|m\-|m3|m5)|tx\-9|up(\.b|g1|si)|utst|v400|v750|veri|vi(rg|te)|vk(40|5[0-3]|\-v)|vm40|voda|vulc|vx(52|53|60|61|70|80|81|83|85|98)|w3c(\-| )|webc|whit|wi(g |nc|nw)|wmlb|wonu|x700|yas\-|your|zeto|zte\-/i.match(ua[0..3])
27
+ )
28
+ end
29
+ end
30
+ end