user_agent_parser 2.5.1 → 2.5.2

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of user_agent_parser might be problematic. Click here for more details.

Files changed (4) hide show
  1. checksums.yaml +4 -4
  2. data/MIT-LICENSE +1 -1
  3. data/vendor/uap-core/regexes.yaml +352 -222
  4. metadata +4 -5
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 7ee9e1b84dccf145ec3f76636257333928009fff83df571dd5d82ab77c987433
4
- data.tar.gz: 0a917cba251dcfc53e91974a6fe32a459be401fb4a8e2f0c89fb2af889959442
3
+ metadata.gz: 2108d04c3b134892dfe8b64a8d922b43cefce3234b97883229c2f94987231fe9
4
+ data.tar.gz: 21ae5ddc52e16c080c20dd7c573f0a0daa46602cdb36ad963f7c408a3122c46d
5
5
  SHA512:
6
- metadata.gz: 43ff78e71fa46cfc3ec4f87d3e0cefcb0f69b91cdd8559e71d1c1a8aa0967149d36d97738f4bb44c5b7c70f3860dbef47be8dce9e4b1f9a3e61ee09976840f53
7
- data.tar.gz: c9ab81808b83142e260b556a0f769567e9991d15d5564edadf5ece00cf2b6b7583056a3e9b3a17b0dafd79c25dfbb64fb6fdb632581719097b1430cb3f63e937
6
+ metadata.gz: fa1854eb92882b92b497775861a4c0063ad644d09f6294e0c629f88eb2bd8dd6e1442140076ed787b7d35f46f7f1c0f13a61df178a6db902b75a5184899166f0
7
+ data.tar.gz: 58235ccba086edc533135b48e49c8b9750c0582b94a87570c4b02878e0fddad9ae69e79218faa2df43aa78c06b66fec10eeb55e958f276bb09416b70b29b4243
@@ -17,4 +17,4 @@ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
17
  NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
18
  LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
19
  OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
- WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -7,9 +7,9 @@ user_agent_parsers:
7
7
  family_replacement: 'AntennaPod'
8
8
  - regex: '(TopPodcasts)Pro/(\d+) CFNetwork'
9
9
  - regex: '(MusicDownloader)Lite/(\d+)\.(\d+)\.(\d+) CFNetwork'
10
- - regex: '^(.*)-iPad/(\d+)\.?(\d+)?.?(\d+)?.?(\d+)? CFNetwork'
11
- - regex: '^(.*)-iPhone/(\d+)\.?(\d+)?.?(\d+)?.?(\d+)? CFNetwork'
12
- - regex: '^(.*)/(\d+)\.?(\d+)?.?(\d+)?.?(\d+)? CFNetwork'
10
+ - regex: '^(.*)-iPad\/(\d+)(?:\.(\d+)|)(?:\.(\d+)|)(?:\.(\d+)|) CFNetwork'
11
+ - regex: '^(.*)-iPhone/(\d+)(?:\.(\d+)|)(?:\.(\d+)|)(?:\.(\d+)|) CFNetwork'
12
+ - regex: '^(.*)/(\d+)(?:\.(\d+)|)(?:\.(\d+)|)(?:\.(\d+)|) CFNetwork'
13
13
 
14
14
  # Podcast catchers
15
15
  - regex: '(espn\.go)'
@@ -23,16 +23,23 @@ user_agent_parsers:
23
23
  - regex: ' (Rivo) RHYTHM'
24
24
 
25
25
  # @note: iOS / OSX Applications
26
- - regex: '(CFNetwork)(?:/(\d+)\.(\d+)\.?(\d+)?)?'
26
+ - regex: '(CFNetwork)(?:/(\d+)\.(\d+)(?:\.(\d+)|)|)'
27
27
  family_replacement: 'CFNetwork'
28
28
 
29
29
  # Pingdom
30
- - regex: '(Pingdom.com_bot_version_)(\d+)\.(\d+)'
30
+ - regex: '(Pingdom\.com_bot_version_)(\d+)\.(\d+)'
31
31
  family_replacement: 'PingdomBot'
32
32
  # 'Mozilla/5.0 (Unknown; Linux x86_64) AppleWebKit/534.34 (KHTML, like Gecko) PingdomTMS/0.8.5 Safari/534.34'
33
33
  - regex: '(PingdomTMS)/(\d+)\.(\d+)\.(\d+)'
34
34
  family_replacement: 'PingdomBot'
35
35
 
36
+ # PTST / WebPageTest.org crawlers
37
+ - regex: ' (PTST)/(\d+)(?:\.(\d+)|)$'
38
+ family_replacement: 'WebPageTest.org bot'
39
+
40
+ # Datanyze.com spider
41
+ - regex: 'X11; (Datanyze); Linux'
42
+
36
43
  # New Relic Pinger
37
44
  - regex: '(NewRelicPinger)/(\d+)\.(\d+)'
38
45
  family_replacement: 'NewRelicPingerBot'
@@ -57,11 +64,11 @@ user_agent_parsers:
57
64
  family_replacement: 'GooglePlusBot'
58
65
 
59
66
  # Gmail
60
- - regex: 'via ggpht.com GoogleImageProxy'
67
+ - regex: 'via ggpht\.com GoogleImageProxy'
61
68
  family_replacement: 'GmailImageProxy'
62
69
 
63
70
  # Yahoo
64
- - regex: 'YahooMailProxy; https://help.yahoo.com/kb/yahoo-mail-proxy-SLN28749.html'
71
+ - regex: 'YahooMailProxy; https://help\.yahoo\.com/kb/yahoo-mail-proxy-SLN28749\.html'
65
72
  family_replacement: 'YahooMailProxy'
66
73
 
67
74
  # Twitter
@@ -69,37 +76,49 @@ user_agent_parsers:
69
76
  family_replacement: 'TwitterBot'
70
77
 
71
78
  # Bots Pattern '/name-0.0'
72
- - regex: '/((?:Ant-)?Nutch|[A-z]+[Bb]ot|[A-z]+[Ss]pider|Axtaris|fetchurl|Isara|ShopSalad|Tailsweep)[ \-](\d+)(?:\.(\d+)(?:\.(\d+))?)?'
79
+ - regex: '/((?:Ant-|)Nutch|[A-z]+[Bb]ot|[A-z]+[Ss]pider|Axtaris|fetchurl|Isara|ShopSalad|Tailsweep)[ \-](\d+)(?:\.(\d+)|)(?:\.(\d+)|)'
73
80
  # Bots Pattern 'name/0.0'
74
- - 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+))?)?'
81
+ - 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+)|)'
75
82
 
76
83
  # MSIECrawler
77
- - regex: '(MSIE) (\d+)\.(\d+)([a-z]\d?)?;.* MSIECrawler'
84
+ - regex: '(MSIE) (\d+)\.(\d+)([a-z]\d|[a-z]|);.* MSIECrawler'
78
85
  family_replacement: 'MSIECrawler'
79
86
 
80
87
  # DAVdroid
81
- - regex: '(DAVdroid)/(\d+)\.(\d+)(?:\.(\d+))?'
88
+ - regex: '(DAVdroid)/(\d+)\.(\d+)(?:\.(\d+)|)'
82
89
 
83
90
  # Downloader ...
84
- - 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+))?)?)?'
91
+ - 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+)|)|)'
85
92
 
86
93
  # Pinterestbot
87
- - regex: '(Pinterest(?:bot)?)/(\d+)(?:\.(\d+)(?:\.(\d+))?)?[;\s\(]+\+https://www.pinterest.com/bot.html'
94
+ - regex: '(Pinterest(?:bot|))/(\d+)(?:\.(\d+)|)(?:\.(\d+)|)[;\s(]+\+https://www.pinterest.com/bot.html'
88
95
  family_replacement: 'Pinterestbot'
89
96
 
90
97
  # Bots
91
- - 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+))?)?)?'
98
+ - regex: '(CSimpleSpider|Cityreview Robot|CrawlDaddy|CrawlFire|Finderbots|Index crawler|Job Roboter|KiwiStatus Spider|Lijit Crawler|QuerySeekerSpider|ScollSpider|Trends Crawler|USyd-NLP-Spider|SiteCat Webbot|BotName\/\$BotVersion|123metaspider-Bot|1470\.net crawler|50\.nu|8bo Crawler Bot|Aboundex|Accoona-[A-z]{1,30}-Agent|AdsBot-Google(?:-[a-z]{1,30}|)|altavista|AppEngine-Google|archive.{0,30}\.org_bot|archiver|Ask Jeeves|[Bb]ai[Dd]u[Ss]pider(?:-[A-Za-z]{1,30})(?:-[A-Za-z]{1,30}|)|bingbot|BingPreview|blitzbot|BlogBridge|Bloglovin|BoardReader Blog Indexer|BoardReader Favicon Fetcher|boitho.com-dc|BotSeer|BUbiNG|\b\w{0,30}favicon\w{0,30}\b|\bYeti(?:-[a-z]{1,30}|)|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]{1,30}-|)Googlebot(?:-[a-zA-Z]{1,30}|)|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]{1,30}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 .{0,30} Bot|mogimogi|mozDex|MJ12bot|msnbot(?:-media {0,2}|)|msrbot|Mtps Feed Aggregation System|netresearch|Netvibes|NewsGator[^/]{0,30}|^NING|Nutch[^/]{0,30}|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]{1,30}|WhatWeb|WIRE|WordPress|Wotbox|www\.almaden\.ibm\.com|Xenu(?:.s|) Link Sleuth|Xerka [A-z]{1,30}Bot|yacy(?:bot|)|YahooSeeker|Yahoo! Slurp|Yandex\w{1,30}|YodaoBot(?:-[A-z]{1,30}|)|YottaaMonitor|Yowedo|^Zao|^Zao-Crawler|ZeBot_www\.ze\.bz|ZooShot|ZyBorg)(?:[ /]v?(\d+)(?:\.(\d+)(?:\.(\d+)|)|)|)'
92
99
 
93
100
  # AWS S3 Clients
94
101
  # must come before "Bots General matcher" to catch "boto"/"boto3" before "bot"
95
- - regex: '\b(Boto3?|JetS3t|aws-(?:cli|sdk-(?:cpp|go|java|nodejs|ruby2?))|s3fs)/(\d+)\.(\d+)(?:\.(\d+))?'
102
+ - regex: '\b(Boto3?|JetS3t|aws-(?:cli|sdk-(?:cpp|go|java|nodejs|ruby2?))|s3fs)/(\d+)\.(\d+)(?:\.(\d+)|)'
103
+
104
+ # Facebook
105
+ # Must come before "Bots General matcher" to catch OrangeBotswana
106
+ # Facebook Messenger must go before Facebook
107
+ - regex: '\[(FBAN/MessengerForiOS|FB_IAB/MESSENGER);FBAV/(\d+)(?:\.(\d+)(?:\.(\d+)|)|)'
108
+ family_replacement: 'Facebook Messenger'
109
+ # Facebook
110
+ - regex: '\[FB.*;(FBAV)/(\d+)(?:\.(\d+)|)(?:\.(\d+)|)'
111
+ family_replacement: 'Facebook'
112
+ # Sometimes Facebook does not specify a version (FBAV)
113
+ - regex: '\[FB.*;'
114
+ family_replacement: 'Facebook'
96
115
 
97
116
  # Bots General matcher 'name/0.0'
98
- - 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+))?)?'
99
- # Bots General matcher 'name 0.0'
100
- - 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+))?)?'
101
- # Bots containing spider|scrape|bot(but not CUBOT)|Crawl
102
- - 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+))?)?)?'
117
+ - regex: '(?:\/[A-Za-z0-9\.]+|) {0,5}([A-Za-z0-9 \-_\!\[\]:]{0,50}(?:[Aa]rchiver|[Ii]ndexer|[Ss]craper|[Bb]ot|[Ss]pider|[Cc]rawl[a-z]{0,50}))[/ ](\d+)(?:\.(\d+)(?:\.(\d+)|)|)'
118
+ # Bots containing bot(but not CUBOT)
119
+ - regex: '((?:[A-Za-z][A-Za-z0-9 -]{0,50}|)[^C][^Uu][Bb]ot)\b(?:(?:[ /]| v)(\d+)(?:\.(\d+)|)(?:\.(\d+)|)|)'
120
+ # Bots containing spider|scrape|Crawl
121
+ - regex: '((?:[A-z0-9]{1,50}|[A-z\-]{1,50} ?|)(?: the |)(?:[Ss][Pp][Ii][Dd][Ee][Rr]|[Ss]crape|[Cc][Rr][Aa][Ww][Ll])[A-z0-9]{0,50})(?:(?:[ /]| v)(\d+)(?:\.(\d+)|)(?:\.(\d+)|)|)'
103
122
 
104
123
  # HbbTV standard defines what features the browser should understand.
105
124
  # but it's like targeting "HTML5 browsers", effective browser support depends on the model
@@ -107,30 +126,33 @@ user_agent_parsers:
107
126
  - regex: '(HbbTV)/(\d+)\.(\d+)\.(\d+) \('
108
127
 
109
128
  # must go before Firefox to catch Chimera/SeaMonkey/Camino/Waterfox
110
- - regex: '(Chimera|SeaMonkey|Camino|Waterfox)/(\d+)\.(\d+)\.?([ab]?\d+[a-z]*)?'
129
+ - regex: '(Chimera|SeaMonkey|Camino|Waterfox)/(\d+)\.(\d+)\.?([ab]?\d+[a-z]*|)'
111
130
 
112
- # Social Networks
113
- # Facebook
114
- - regex: '\[FB.*;(FBAV)/(\d+)(?:\.(\d+)(?:\.(\d+))?)?'
115
- family_replacement: 'Facebook'
131
+ # must be before Firefox / Gecko to catch SailfishBrowser properly
132
+ - regex: '(SailfishBrowser)/(\d+)\.(\d+)(?:\.(\d+)|)'
133
+ family_replacement: 'Sailfish Browser'
134
+
135
+ # Social Networks (non-Facebook)
116
136
  # Pinterest
117
137
  - regex: '\[(Pinterest)/[^\]]+\]'
118
- - regex: '(Pinterest)(?: for Android(?: Tablet)?)?/(\d+)(?:\.(\d+)(?:\.(\d+))?)?'
138
+ - regex: '(Pinterest)(?: for Android(?: Tablet|)|)/(\d+)(?:\.(\d+)|)(?:\.(\d+)|)'
119
139
  # Instagram app
120
140
  - regex: 'Mozilla.*Mobile.*(Instagram).(\d+)\.(\d+)\.(\d+)'
121
- # Flipbaord app
141
+ # Flipboard app
122
142
  - regex: 'Mozilla.*Mobile.*(Flipboard).(\d+)\.(\d+)\.(\d+)'
123
- # Flipbaord-briefing app
143
+ # Flipboard-briefing app
124
144
  - regex: 'Mozilla.*Mobile.*(Flipboard-Briefing).(\d+)\.(\d+)\.(\d+)'
125
145
  # Onefootball app
126
146
  - regex: 'Mozilla.*Mobile.*(Onefootball)\/Android.(\d+)\.(\d+)\.(\d+)'
147
+ # Snapchat
148
+ - regex: '(Snapchat)\/(\d+)\.(\d+)\.(\d+)\.(\d+)'
127
149
 
128
150
  # Basilisk
129
151
  - regex: '(Firefox)/(\d+)\.(\d+) Basilisk/(\d+)'
130
152
  family_replacement: 'Basilisk'
131
153
 
132
154
  # Pale Moon
133
- - regex: '(PaleMoon)/(\d+)\.(\d+)\.?(\d+)?'
155
+ - regex: '(PaleMoon)/(\d+)\.(\d+)(?:\.(\d+)|)'
134
156
  family_replacement: 'Pale Moon'
135
157
 
136
158
  # Firefox
@@ -142,22 +164,22 @@ user_agent_parsers:
142
164
  family_replacement: 'Firefox Mobile'
143
165
  - regex: '(?:Mobile|Tablet);.*(Firefox)/(\d+)\.(\d+)'
144
166
  family_replacement: 'Firefox Mobile'
145
- - regex: '(Namoroka|Shiretoko|Minefield)/(\d+)\.(\d+)\.(\d+(?:pre)?)'
167
+ - regex: '(Namoroka|Shiretoko|Minefield)/(\d+)\.(\d+)\.(\d+(?:pre|))'
146
168
  family_replacement: 'Firefox ($1)'
147
169
  - regex: '(Firefox)/(\d+)\.(\d+)(a\d+[a-z]*)'
148
170
  family_replacement: 'Firefox Alpha'
149
171
  - regex: '(Firefox)/(\d+)\.(\d+)(b\d+[a-z]*)'
150
172
  family_replacement: 'Firefox Beta'
151
- - regex: '(Firefox)-(?:\d+\.\d+)?/(\d+)\.(\d+)(a\d+[a-z]*)'
173
+ - regex: '(Firefox)-(?:\d+\.\d+|)/(\d+)\.(\d+)(a\d+[a-z]*)'
152
174
  family_replacement: 'Firefox Alpha'
153
- - regex: '(Firefox)-(?:\d+\.\d+)?/(\d+)\.(\d+)(b\d+[a-z]*)'
175
+ - regex: '(Firefox)-(?:\d+\.\d+|)/(\d+)\.(\d+)(b\d+[a-z]*)'
154
176
  family_replacement: 'Firefox Beta'
155
- - regex: '(Namoroka|Shiretoko|Minefield)/(\d+)\.(\d+)([ab]\d+[a-z]*)?'
177
+ - regex: '(Namoroka|Shiretoko|Minefield)/(\d+)\.(\d+)([ab]\d+[a-z]*|)'
156
178
  family_replacement: 'Firefox ($1)'
157
179
  - regex: '(Firefox).*Tablet browser (\d+)\.(\d+)\.(\d+)'
158
180
  family_replacement: 'MicroB'
159
- - regex: '(MozillaDeveloperPreview)/(\d+)\.(\d+)([ab]\d+[a-z]*)?'
160
- - regex: '(FxiOS)/(\d+)\.(\d+)(\.(\d+))?(\.(\d+))?'
181
+ - regex: '(MozillaDeveloperPreview)/(\d+)\.(\d+)([ab]\d+[a-z]*|)'
182
+ - regex: '(FxiOS)/(\d+)\.(\d+)(\.(\d+)|)(\.(\d+)|)'
161
183
  family_replacement: 'Firefox iOS'
162
184
 
163
185
  # e.g.: Flock/2.0b2
@@ -173,7 +195,7 @@ user_agent_parsers:
173
195
  - regex: '(Navigator)/(\d+)\.(\d+)([ab]\d+)'
174
196
  family_replacement: 'Netscape'
175
197
 
176
- - regex: '(Netscape6)/(\d+)\.(\d+)\.?([ab]?\d+)?'
198
+ - regex: '(Netscape6)/(\d+)\.(\d+)\.?([ab]?\d+|)'
177
199
  family_replacement: 'Netscape'
178
200
 
179
201
  - regex: '(MyIBrow)/(\d+)\.(\d+)'
@@ -186,8 +208,8 @@ user_agent_parsers:
186
208
 
187
209
  # Opera will stop at 9.80 and hide the real version in the Version string.
188
210
  # see: http://dev.opera.com/articles/view/opera-ua-string-changes/
189
- - regex: '(Opera Tablet).*Version/(\d+)\.(\d+)(?:\.(\d+))?'
190
- - regex: '(Opera Mini)(?:/att)?/?(\d+)?(?:\.(\d+))?(?:\.(\d+))?'
211
+ - regex: '(Opera Tablet).*Version/(\d+)\.(\d+)(?:\.(\d+)|)'
212
+ - regex: '(Opera Mini)(?:/att|)/?(\d+|)(?:\.(\d+)|)(?:\.(\d+)|)'
191
213
  - regex: '(Opera)/.+Opera Mobi.+Version/(\d+)\.(\d+)'
192
214
  family_replacement: 'Opera Mobile'
193
215
  - regex: '(Opera)/(\d+)\.(\d+).+Opera Mobi'
@@ -196,7 +218,7 @@ user_agent_parsers:
196
218
  family_replacement: 'Opera Mobile'
197
219
  - regex: 'Opera Mobi'
198
220
  family_replacement: 'Opera Mobile'
199
- - regex: '(Opera)/9.80.*Version/(\d+)\.(\d+)(?:\.(\d+))?'
221
+ - regex: '(Opera)/9.80.*Version/(\d+)\.(\d+)(?:\.(\d+)|)'
200
222
 
201
223
  # Opera 14 for Android uses a WebKit render engine.
202
224
  - regex: '(?:Mobile Safari).*(OPR)/(\d+)\.(\d+)\.(\d+)'
@@ -219,7 +241,7 @@ user_agent_parsers:
219
241
  family_replacement: 'Opera Neon'
220
242
 
221
243
  # Palm WebOS looks a lot like Safari.
222
- - regex: '(hpw|web)OS/(\d+)\.(\d+)(?:\.(\d+))?'
244
+ - regex: '(hpw|web)OS/(\d+)\.(\d+)(?:\.(\d+)|)'
223
245
  family_replacement: 'webOS Browser'
224
246
 
225
247
  # LuaKit has no version info.
@@ -235,20 +257,20 @@ user_agent_parsers:
235
257
  - regex: 'Gecko/\d+ (Lightning)/(\d+)\.(\d+)\.?((?:[ab]?\d+[a-z]*)|(?:\d*))'
236
258
 
237
259
  # Swiftfox
238
- - regex: '(Firefox)/(\d+)\.(\d+)\.(\d+(?:pre)?) \(Swiftfox\)'
260
+ - regex: '(Firefox)/(\d+)\.(\d+)\.(\d+(?:pre|)) \(Swiftfox\)'
239
261
  family_replacement: 'Swiftfox'
240
- - regex: '(Firefox)/(\d+)\.(\d+)([ab]\d+[a-z]*)? \(Swiftfox\)'
262
+ - regex: '(Firefox)/(\d+)\.(\d+)([ab]\d+[a-z]*|) \(Swiftfox\)'
241
263
  family_replacement: 'Swiftfox'
242
264
 
243
265
  # Rekonq
244
- - regex: '(rekonq)/(\d+)\.(\d+)\.?(\d+)? Safari'
266
+ - regex: '(rekonq)/(\d+)\.(\d+)(?:\.(\d+)|) Safari'
245
267
  family_replacement: 'Rekonq'
246
268
  - regex: 'rekonq'
247
269
  family_replacement: 'Rekonq'
248
270
 
249
271
  # Conkeror lowercase/uppercase
250
272
  # http://conkeror.org/
251
- - regex: '(conkeror|Conkeror)/(\d+)\.(\d+)\.?(\d+)?'
273
+ - regex: '(conkeror|Conkeror)/(\d+)\.(\d+)(?:\.(\d+)|)'
252
274
  family_replacement: 'Conkeror'
253
275
 
254
276
  # catches lower case konqueror
@@ -277,11 +299,11 @@ user_agent_parsers:
277
299
  family_replacement: 'NetFront NX'
278
300
 
279
301
  # Amazon Silk, should go before Safari and Chrome Mobile
280
- - regex: '(Silk)/(\d+)\.(\d+)(?:\.([0-9\-]+))?'
302
+ - regex: '(Silk)/(\d+)\.(\d+)(?:\.([0-9\-]+)|)'
281
303
  family_replacement: 'Amazon Silk'
282
304
 
283
305
  # @ref: http://www.puffinbrowser.com
284
- - regex: '(Puffin)/(\d+)\.(\d+)(?:\.(\d+))?'
306
+ - regex: '(Puffin)/(\d+)\.(\d+)(?:\.(\d+)|)'
285
307
 
286
308
  # Edge Mobile
287
309
  - regex: 'Windows Phone .*(Edge)/(\d+)\.(\d+)'
@@ -292,26 +314,43 @@ user_agent_parsers:
292
314
  family_replacement: 'Samsung Internet'
293
315
 
294
316
  # Seznam.cz browser (based on WebKit)
295
- - regex: '(SznProhlizec)/(\d+)\.(\d+)(?:\.(\d+))?'
317
+ - regex: '(SznProhlizec)/(\d+)\.(\d+)(?:\.(\d+)|)'
296
318
  family_replacement: 'Seznam prohlížeč'
297
319
 
298
320
  # Coc Coc browser, based on Chrome (used in Vietnam)
299
- - regex: '(coc_coc_browser)/(\d+)\.(\d+)(?:\.(\d+))?'
321
+ - regex: '(coc_coc_browser)/(\d+)\.(\d+)(?:\.(\d+)|)'
300
322
  family_replacement: 'Coc Coc'
301
323
 
302
324
  # Baidu Browsers (desktop spoofs chrome & IE, explorer is mobile)
303
- - regex: '(baidubrowser)[/\s](\d+)(?:\.(\d+)(?:\.(\d+))?)?'
325
+ - regex: '(baidubrowser)[/\s](\d+)(?:\.(\d+)|)(?:\.(\d+)|)'
304
326
  family_replacement: 'Baidu Browser'
305
327
  - regex: '(FlyFlow)/(\d+)\.(\d+)'
306
328
  family_replacement: 'Baidu Explorer'
307
329
 
308
330
  # MxBrowser is Maxthon. Must go before Mobile Chrome for Android
309
- - regex: '(MxBrowser)/(\d+)\.(\d+)(?:\.(\d+))?'
331
+ - regex: '(MxBrowser)/(\d+)\.(\d+)(?:\.(\d+)|)'
310
332
  family_replacement: 'Maxthon'
311
333
 
312
334
  # Crosswalk must go before Mobile Chrome for Android
313
335
  - regex: '(Crosswalk)/(\d+)\.(\d+)\.(\d+)\.(\d+)'
314
336
 
337
+ # LINE https://line.me/en/
338
+ # Must go before Mobile Chrome for Android
339
+ - regex: '(Line)/(\d+)\.(\d+)\.(\d+)'
340
+ family_replacement: 'LINE'
341
+
342
+ # MiuiBrowser should got before Mobile Chrome for Android
343
+ - regex: '(MiuiBrowser)/(\d+)\.(\d+)\.(\d+)'
344
+ family_replacement: 'MiuiBrowser'
345
+
346
+ # Mint Browser should got before Mobile Chrome for Android
347
+ - regex: '(Mint Browser)/(\d+)\.(\d+)\.(\d+)'
348
+ family_replacement: 'Mint Browser'
349
+
350
+ # Google Search App on Android, eg:
351
+ - regex: 'Mozilla.+Android.+(GSA)/(\d+)\.(\d+)\.(\d+)'
352
+ family_replacement: 'Google'
353
+
315
354
  # Chrome Mobile
316
355
  - regex: 'Version/.+(Chrome)/(\d+)\.(\d+)\.(\d+)\.(\d+)'
317
356
  family_replacement: 'Chrome Mobile WebView'
@@ -339,11 +378,11 @@ user_agent_parsers:
339
378
  family_replacement: 'Sogou Explorer'
340
379
 
341
380
  # QQ Browsers
342
- - regex: '(MQQBrowser/Mini)(?:(\d+)(?:\.(\d+)(?:\.(\d+))?)?)?'
381
+ - regex: '(MQQBrowser/Mini)(?:(\d+)(?:\.(\d+)|)(?:\.(\d+)|)|)'
343
382
  family_replacement: 'QQ Browser Mini'
344
- - regex: '(MQQBrowser)(?:/(\d+)(?:\.(\d+)(?:\.(\d+))?)?)?'
383
+ - regex: '(MQQBrowser)(?:/(\d+)(?:\.(\d+)|)(?:\.(\d+)|)|)'
345
384
  family_replacement: 'QQ Browser Mobile'
346
- - regex: '(QQBrowser)(?:/(\d+)(?:\.(\d+)\.(\d+)(?:\.(\d+))?)?)?'
385
+ - regex: '(QQBrowser)(?:/(\d+)(?:\.(\d+)\.(\d+)(?:\.(\d+)|)|)|)'
347
386
  family_replacement: 'QQ Browser'
348
387
 
349
388
  # Rackspace Monitoring
@@ -365,7 +404,7 @@ user_agent_parsers:
365
404
  - regex: '(AOL) (\d+)\.(\d+); AOLBuild (\d+)'
366
405
 
367
406
  # Podcast catcher Applications using iTunes
368
- - regex: '(PodCruncher|Downcast)[ /]?(\d+)\.?(\d+)?\.?(\d+)?\.?(\d+)?'
407
+ - regex: '(PodCruncher|Downcast)[ /]?(\d+)(?:\.(\d+)|)(?:\.(\d+)|)(?:\.(\d+)|)'
369
408
 
370
409
  # Box Notes https://www.box.com/resources/downloads
371
410
  # Must be before Electron
@@ -378,6 +417,10 @@ user_agent_parsers:
378
417
  - regex: '(Whale)/(\d+)\.(\d+)\.(\d+)'
379
418
  family_replacement: 'Whale'
380
419
 
420
+ # Ghost
421
+ # @ref: http://www.ghost.org
422
+ - regex: '(Ghost)/(\d+)\.(\d+)\.(\d+)'
423
+
381
424
  #### END SPECIAL CASES TOP ####
382
425
 
383
426
  #### MAIN CASES - this catches > 50% of all browsers ####
@@ -389,7 +432,7 @@ user_agent_parsers:
389
432
 
390
433
  # HipChat provides a version on Mac, but not on Windows.
391
434
  # Needs to be before Chrome on Windows, and AppleMail on Mac.
392
- - regex: '(HipChat)/?(\d+)?'
435
+ - regex: '(HipChat)/?(\d+|)'
393
436
  family_replacement: 'HipChat Desktop Client'
394
437
 
395
438
  # Browser/major_version.minor_version.beta_version
@@ -415,15 +458,18 @@ user_agent_parsers:
415
458
  family_replacement: 'Outlook'
416
459
  v1_replacement: '2016'
417
460
 
461
+ # Word 2014
462
+ - regex: 'Microsoft Office (Word) 2014'
463
+
418
464
  # Windows Live Mail
419
465
  - regex: 'Outlook-Express\/7\.0.*'
420
466
  family_replacement: 'Windows Live Mail'
421
467
 
422
468
  # Apple Air Mail
423
- - regex: '(Airmail) (\d+)\.(\d+)(?:\.(\d+))?'
469
+ - regex: '(Airmail) (\d+)\.(\d+)(?:\.(\d+)|)'
424
470
 
425
471
  # Thunderbird
426
- - regex: '(Thunderbird)/(\d+)\.(\d+)(?:\.(\d+(?:pre)?))?'
472
+ - regex: '(Thunderbird)/(\d+)\.(\d+)(?:\.(\d+(?:pre|))|)'
427
473
  family_replacement: 'Thunderbird'
428
474
 
429
475
  # Postbox
@@ -431,18 +477,20 @@ user_agent_parsers:
431
477
  family_replacement: 'Postbox'
432
478
 
433
479
  # Barca
434
- - regex: '(Barca(?:Pro)?)/(\d+)\.(\d+)(?:\.(\d+))?'
480
+ - regex: '(Barca(?:Pro)?)/(\d+)\.(\d+)(?:\.(\d+)|)'
435
481
  family_replacement: 'Barca'
436
482
 
437
483
  # Lotus Notes
438
- - regex: '(Lotus-Notes)/(\d+)\.(\d+)(?:\.(\d+))?'
484
+ - regex: '(Lotus-Notes)/(\d+)\.(\d+)(?:\.(\d+)|)'
439
485
  family_replacement: 'Lotus Notes'
440
486
 
441
487
  # Vivaldi uses "Vivaldi"
442
488
  - regex: '(Vivaldi)/(\d+)\.(\d+)\.(\d+)'
443
489
 
444
490
  # Edge/major_version.minor_version
445
- - regex: '(Edge)/(\d+)(?:\.(\d+))?'
491
+ # Edge with chromium Edg/major_version.minor_version.patch.minor_patch
492
+ - regex: '(Edge?)/(\d+)(?:\.(\d+)|)(?:\.(\d+)|)(?:\.(\d+)|)'
493
+ family_replacement: 'Edge'
446
494
 
447
495
  # Brave Browser https://brave.com/
448
496
  - regex: '(brave)/(\d+)\.(\d+)\.(\d+) Chrome'
@@ -454,23 +502,23 @@ user_agent_parsers:
454
502
 
455
503
  # Dolphin Browser
456
504
  # @ref: http://www.dolphin.com
457
- - regex: '\b(Dolphin)(?: |HDCN/|/INT\-)(\d+)\.(\d+)\.?(\d+)?'
505
+ - regex: '\b(Dolphin)(?: |HDCN/|/INT\-)(\d+)\.(\d+)(?:\.(\d+)|)'
458
506
 
459
507
  # Headless Chrome
460
508
  # https://chromium.googlesource.com/chromium/src/+/lkgr/headless/README.md
461
- - regex: '(HeadlessChrome)(?:/(\d+)\.(\d+)\.(\d+))?'
509
+ - regex: '(HeadlessChrome)(?:/(\d+)\.(\d+)\.(\d+)|)'
462
510
 
463
511
  # Evolution Mail CardDav/CalDav integration
464
512
  - regex: '(Evolution)/(\d+)\.(\d+)\.(\d+\.\d+)'
465
513
 
466
514
  # Roundcube Mail CardDav plugin
467
- - regex: '(RCM CardDAV plugin)/(\d+)\.(\d+)\.(\d+(?:-dev)?)'
515
+ - regex: '(RCM CardDAV plugin)/(\d+)\.(\d+)\.(\d+(?:-dev|))'
468
516
 
469
517
  # Browser/major_version.minor_version
470
- - 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+))?'
518
+ - 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+)|)'
471
519
 
472
520
  # Chrome/Chromium/major_version.minor_version
473
- - regex: '(Chromium|Chrome)/(\d+)\.(\d+)(?:\.(\d+))?(?:\.(\d+))?'
521
+ - regex: '(Chromium|Chrome)/(\d+)\.(\d+)(?:\.(\d+)|)(?:\.(\d+)|)'
474
522
 
475
523
  ##########
476
524
  # IE Mobile needs to happen before Android to catch cases such as:
@@ -490,8 +538,8 @@ user_agent_parsers:
490
538
  # Podcast catchers
491
539
  - regex: '^(bPod|Pocket Casts|Player FM)$'
492
540
  - regex: '^(AlexaMediaPlayer|VLC)/(\d+)\.(\d+)\.([^.\s]+)'
493
- - 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+)?'
494
- - regex: '^(Peapod|Liferea)/([^.\s]+)\.([^.\s]+)?\.?([^.\s]+)?'
541
+ - 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+)|)'
542
+ - regex: '^(Peapod|Liferea)/([^.\s]+)\.([^.\s]+|)\.?([^.\s]+|)'
495
543
  - regex: '^(bPod|Player FM) BMID/(\S+)'
496
544
  - regex: '^(Podcast ?Addict)/v(\d+) '
497
545
  - regex: '^(Podcast ?Addict) '
@@ -501,8 +549,8 @@ user_agent_parsers:
501
549
  - regex: '(CITA) RSS Aggregator/(\d+)\.(\d+)'
502
550
  - regex: '(Pocket Casts)$'
503
551
  - regex: '(Player FM)$'
504
- - regex: '(LG Player|Doppler|FancyMusic|MediaMonkey|Clementine) (\d+)\.(\d+)\.?([^.\s]+)?\.?([^.\s]+)?'
505
- - regex: '(philpodder)/(\d+)\.(\d+)\.?([^.\s]+)?\.?([^.\s]+)?'
552
+ - regex: '(LG Player|Doppler|FancyMusic|MediaMonkey|Clementine) (\d+)\.(\d+)\.?([^.\s]+|)\.?([^.\s]+|)'
553
+ - regex: '(philpodder)/(\d+)\.(\d+)\.?([^.\s]+|)\.?([^.\s]+|)'
506
554
  - regex: '(Player FM|Pocket Casts|DoggCatcher|Spotify|MediaMonkey|MediaGo|BashPodder)'
507
555
  - regex: '(QuickTime)\.(\d+)\.(\d+)\.(\d+)'
508
556
  - regex: '(Kinoma)(\d+)'
@@ -510,35 +558,35 @@ user_agent_parsers:
510
558
  family_replacement: 'FancyMusic'
511
559
  - regex: 'EspnDownloadManager'
512
560
  family_replacement: 'ESPN'
513
- - regex: '(ESPN) Radio (\d+)\.(\d+)\.?(\d+)? ?(?:rv:(\d+))? '
514
- - regex: '(podracer|jPodder) v ?(\d+)\.(\d+)\.?(\d+)?'
561
+ - regex: '(ESPN) Radio (\d+)\.(\d+)(?:\.(\d+)|) ?(?:rv:(\d+)|) '
562
+ - regex: '(podracer|jPodder) v ?(\d+)\.(\d+)(?:\.(\d+)|)'
515
563
  - regex: '(ZDM)/(\d+)\.(\d+)[; ]?'
516
- - regex: '(Zune|BeyondPod) (\d+)\.?(\d+)?[\);]'
564
+ - regex: '(Zune|BeyondPod) (\d+)(?:\.(\d+)|)[\);]'
517
565
  - regex: '(WMPlayer)/(\d+)\.(\d+)\.(\d+)\.(\d+)'
518
566
  - regex: '^(Lavf)'
519
567
  family_replacement: 'WMPlayer'
520
- - regex: '^(RSSRadio)[ /]?(\d+)?'
568
+ - regex: '^(RSSRadio)[ /]?(\d+|)'
521
569
  - regex: '(RSS_Radio) (\d+)\.(\d+)'
522
570
  family_replacement: 'RSSRadio'
523
571
  - regex: '(Podkicker) \S+/(\d+)\.(\d+)\.(\d+)'
524
572
  family_replacement: 'Podkicker'
525
- - regex: '^(HTC) Streaming Player \S+ / \S+ / \S+ / (\d+)\.(\d+)\.?(\d+)?'
573
+ - regex: '^(HTC) Streaming Player \S+ / \S+ / \S+ / (\d+)\.(\d+)(?:\.(\d+)|)'
526
574
  - regex: '^(Stitcher)/iOS'
527
575
  - regex: '^(Stitcher)/Android'
528
576
  - regex: '^(VLC) .*version (\d+)\.(\d+)\.(\d+)'
529
577
  - regex: ' (VLC) for'
530
578
  - regex: '(vlc)/(\d+)\.(\d+)\.(\d+)'
531
579
  family_replacement: 'VLC'
532
- - regex: '^(foobar)\S+/([^.\s]+)\.([^.\s]+)?\.?([^.\s]+)?'
533
- - regex: '^(Clementine)\S+ ([^.\s]+)\.([^.\s]+)?\.?([^.\s]+)?'
534
- - regex: '(amarok)/([^.\s]+)\.([^.\s]+)?\.?([^.\s]+)?'
580
+ - regex: '^(foobar)\S+/([^.\s]+)\.([^.\s]+|)\.?([^.\s]+|)'
581
+ - regex: '^(Clementine)\S+ ([^.\s]+)\.([^.\s]+|)\.?([^.\s]+|)'
582
+ - regex: '(amarok)/([^.\s]+)\.([^.\s]+|)\.?([^.\s]+|)'
535
583
  family_replacement: 'Amarok'
536
584
  - regex: '(Custom)-Feed Reader'
537
585
 
538
586
  # Browser major_version.minor_version.beta_version (space instead of slash)
539
587
  - regex: '(iRider|Crazy Browser|SkipStone|iCab|Lunascape|Sleipnir|Maemo Browser) (\d+)\.(\d+)\.(\d+)'
540
588
  # Browser major_version.minor_version (space instead of slash)
541
- - regex: '(iCab|Lunascape|Opera|Android|Jasmine|Polaris|Microsoft SkyDriveSync|The Bat!) (\d+)\.(\d+)\.?(\d+)?'
589
+ - regex: '(iCab|Lunascape|Opera|Android|Jasmine|Polaris|Microsoft SkyDriveSync|The Bat!) (\d+)\.(\d+)(?:\.(\d+)|)'
542
590
 
543
591
  # Kindle WebKit
544
592
  - regex: '(Kindle)/(\d+)\.(\d+)'
@@ -578,12 +626,16 @@ user_agent_parsers:
578
626
  - regex: '(ownCloud-android)/(\d+)\.(\d+)\.(\d+)'
579
627
  family_replacement: 'Owncloud'
580
628
 
629
+ # Skype for Business
630
+ - regex: '(OC)/(\d+)\.(\d+)\.(\d+)\.(\d+) \(Skype for Business\)'
631
+ family_replacement: 'Skype'
632
+
581
633
  #### END MAIN CASES ####
582
634
 
583
635
  #### SPECIAL CASES ####
584
636
  - regex: '(Obigo)InternetBrowser'
585
637
  - regex: '(Obigo)\-Browser'
586
- - regex: '(Obigo|OBIGO)[^\d]*(\d+)(?:.(\d+))?'
638
+ - regex: '(Obigo|OBIGO)[^\d]*(\d+)(?:.(\d+)|)'
587
639
  family_replacement: 'Obigo'
588
640
 
589
641
  - regex: '(MAXTHON|Maxthon) (\d+)\.(\d+)'
@@ -602,24 +654,28 @@ user_agent_parsers:
602
654
  - regex: '(Embider)/(\d+)\.(\d+)'
603
655
  family_replacement: 'Polaris'
604
656
 
605
- - regex: '(BonEcho)/(\d+)\.(\d+)\.?([ab]?\d+)?'
657
+ - regex: '(BonEcho)/(\d+)\.(\d+)\.?([ab]?\d+|)'
606
658
  family_replacement: 'Bon Echo'
607
659
 
608
660
  # @note: iOS / OSX Applications
609
- - regex: '(iPod|iPhone|iPad).+Version/(\d+)\.(\d+)(?:\.(\d+))?.*[ +]Safari'
661
+ - regex: '(iPod|iPhone|iPad).+GSA/(\d+)\.(\d+)\.(\d+) Mobile'
662
+ family_replacement: 'Google'
663
+ - regex: '(iPod|iPhone|iPad).+Version/(\d+)\.(\d+)(?:\.(\d+)|).*[ +]Safari'
610
664
  family_replacement: 'Mobile Safari'
611
- - regex: '(iPod|iPod touch|iPhone|iPad);.*CPU.*OS[ +](\d+)_(\d+)(?:_(\d+))?.* AppleNews\/\d+\.\d+\.\d+?'
665
+ - regex: '(iPod|iPod touch|iPhone|iPad);.*CPU.*OS[ +](\d+)_(\d+)(?:_(\d+)|).* AppleNews\/\d+\.\d+\.\d+?'
612
666
  family_replacement: 'Mobile Safari UI/WKWebView'
613
- - regex: '(iPod|iPhone|iPad).+Version/(\d+)\.(\d+)(?:\.(\d+))?'
667
+ - regex: '(iPod|iPhone|iPad).+Version/(\d+)\.(\d+)(?:\.(\d+)|)'
614
668
  family_replacement: 'Mobile Safari UI/WKWebView'
615
- - regex: '(iPod|iPod touch|iPhone|iPad);.*CPU.*OS[ +](\d+)_(\d+)(?:_(\d+))?.*Mobile.*[ +]Safari'
669
+ - regex: '(iPod|iPod touch|iPhone|iPad);.*CPU.*OS[ +](\d+)_(\d+)(?:_(\d+)|).*Mobile.*[ +]Safari'
616
670
  family_replacement: 'Mobile Safari'
617
- - regex: '(iPod|iPod touch|iPhone|iPad);.*CPU.*OS[ +](\d+)_(\d+)(?:_(\d+))?.*Mobile'
671
+ - regex: '(iPod|iPod touch|iPhone|iPad);.*CPU.*OS[ +](\d+)_(\d+)(?:_(\d+)|).*Mobile'
618
672
  family_replacement: 'Mobile Safari UI/WKWebView'
619
673
  - regex: '(iPod|iPhone|iPad).* Safari'
620
674
  family_replacement: 'Mobile Safari'
621
675
  - regex: '(iPod|iPhone|iPad)'
622
676
  family_replacement: 'Mobile Safari UI/WKWebView'
677
+ - regex: '(Watch)(\d+),(\d+)'
678
+ family_replacement: 'Apple $1 App'
623
679
 
624
680
  ##########################
625
681
  # Outlook on iOS >= 2.62.0
@@ -687,18 +743,18 @@ user_agent_parsers:
687
743
 
688
744
  - regex: '(QtWeb) Internet Browser/(\d+)\.(\d+)'
689
745
 
690
- #- regex: '\(iPad;.+(Version)/(\d+)\.(\d+)(?:\.(\d+))?.*Safari/'
746
+ #- regex: '\(iPad;.+(Version)/(\d+)\.(\d+)(?:\.(\d+)|).*Safari/'
691
747
  # family_replacement: 'iPad'
692
748
 
693
749
  # Phantomjs, should go before Safari
694
750
  - regex: '(PhantomJS)/(\d+)\.(\d+)\.(\d+)'
695
751
 
696
752
  # WebKit Nightly
697
- - regex: '(AppleWebKit)/(\d+)\.?(\d+)?\+ .* Safari'
753
+ - regex: '(AppleWebKit)/(\d+)(?:\.(\d+)|)\+ .* Safari'
698
754
  family_replacement: 'WebKit Nightly'
699
755
 
700
756
  # Safari
701
- - regex: '(Version)/(\d+)\.(\d+)(?:\.(\d+))?.*Safari/'
757
+ - regex: '(Version)/(\d+)\.(\d+)(?:\.(\d+)|).*Safari/'
702
758
  family_replacement: 'Safari'
703
759
  # Safari didn't provide "Version/d.d.d" prior to 3.0
704
760
  - regex: '(Safari)/\d+'
@@ -733,9 +789,9 @@ user_agent_parsers:
733
789
  v1_replacement: '8'
734
790
 
735
791
  # Espial
736
- - regex: '(Espial)/(\d+)(?:\.(\d+))?(?:\.(\d+))?'
792
+ - regex: '(Espial)/(\d+)(?:\.(\d+)|)(?:\.(\d+)|)'
737
793
 
738
- # Apple Mail
794
+ # Apple Mail
739
795
 
740
796
  # apple mail - not directly detectable, have it after Safari stuff
741
797
  - regex: '(AppleWebKit)/(\d+)\.(\d+)\.(\d+)'
@@ -745,7 +801,7 @@ user_agent_parsers:
745
801
  # AFTER IE11
746
802
  # BEFORE all other IE
747
803
  - regex: '(Firefox)/(\d+)\.(\d+)\.(\d+)'
748
- - regex: '(Firefox)/(\d+)\.(\d+)(pre|[ab]\d+[a-z]*)?'
804
+ - regex: '(Firefox)/(\d+)\.(\d+)(pre|[ab]\d+[a-z]*|)'
749
805
 
750
806
  - regex: '([MS]?IE) (\d+)\.(\d+)'
751
807
  family_replacement: 'IE'
@@ -754,13 +810,13 @@ user_agent_parsers:
754
810
  family_replacement: 'Python Requests'
755
811
 
756
812
  # headless user-agents
757
- - 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+))?)?)?'
813
+ - 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+)|)|)'
758
814
 
759
- - regex: '(Java)[/ ]{0,1}\d+\.(\d+)\.(\d+)[_-]*([a-zA-Z0-9]+)*'
815
+ - regex: '(Java)[/ ]{0,1}\d+\.(\d+)\.(\d+)[_-]*([a-zA-Z0-9]+|)'
760
816
 
761
817
  # Cloud Storage Clients
762
- - regex: '^(Cyberduck)/(\d+)\.(\d+)\.(\d+)(?:\.\d+)?'
763
- - regex: '^(S3 Browser) (\d+)-(\d+)-(\d+)(?:\s*http://s3browser\.com)?'
818
+ - regex: '^(Cyberduck)/(\d+)\.(\d+)\.(\d+)(?:\.\d+|)'
819
+ - regex: '^(S3 Browser) (\d+)-(\d+)-(\d+)(?:\s*http://s3browser\.com|)'
764
820
  # rclone - rsync for cloud storage - https://rclone.org/
765
821
  - regex: '^(rclone)/v(\d+)\.(\d+)'
766
822
 
@@ -774,6 +830,10 @@ user_agent_parsers:
774
830
  # Box Drive and Box Sync https://www.box.com/resources/downloads
775
831
  - regex: '^(Box(?: Sync)?)/(\d+)\.(\d+)\.(\d+)'
776
832
 
833
+ # ViaFree streaming app https://www.viafree.{dk|se|no}
834
+ - regex: '^(ViaFree|Viafree)-(?:tvOS-)?[A-Z]{2}/(\d+)\.(\d+)\.(\d+)'
835
+ family_replacement: 'ViaFree'
836
+
777
837
  os_parsers:
778
838
  ##########
779
839
  # HbbTV vendors
@@ -819,11 +879,11 @@ os_parsers:
819
879
  # Philips : not found any other way than a manual mapping
820
880
  # 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
821
881
  # 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
822
- - regex: 'HbbTV/1.1.1 \(; (Philips);.*NETTV/4'
882
+ - regex: 'HbbTV/1\.1\.1 \(; (Philips);.*NETTV/4'
823
883
  os_v1_replacement: '2013'
824
- - regex: 'HbbTV/1.1.1 \(; (Philips);.*NETTV/3'
884
+ - regex: 'HbbTV/1\.1\.1 \(; (Philips);.*NETTV/3'
825
885
  os_v1_replacement: '2012'
826
- - regex: 'HbbTV/1.1.1 \(; (Philips);.*NETTV/2'
886
+ - regex: 'HbbTV/1\.1\.1 \(; (Philips);.*NETTV/2'
827
887
  os_v1_replacement: '2011'
828
888
 
829
889
  # the HbbTV emulator developers use HbbTV/1.1.1 (;;;;;) firetv-firefox-plugin 1.1.20
@@ -844,14 +904,14 @@ os_parsers:
844
904
  - regex: '(Windows Phone) (?:OS[ /])?(\d+)\.(\d+)'
845
905
 
846
906
  # Again a MS-special one: iPhone.*Outlook-iOS-Android/x.x is erroneously detected as Android
847
- - regex: '(CPU[ +]OS|iPhone[ +]OS|CPU[ +]iPhone)[ +]+(\d+)[_\.](\d+)(?:[_\.](\d+))?.*Outlook-iOS-Android'
907
+ - regex: '(CPU[ +]OS|iPhone[ +]OS|CPU[ +]iPhone)[ +]+(\d+)[_\.](\d+)(?:[_\.](\d+)|).*Outlook-iOS-Android'
848
908
  os_replacement: 'iOS'
849
909
 
850
910
  ##########
851
911
  # Android
852
912
  # can actually detect rooted android os. do we care?
853
913
  ##########
854
- - regex: '(Android)[ \-/](\d+)\.?(\d+)?(?:[.\-]([a-z0-9]+))?'
914
+ - regex: '(Android)[ \-/](\d+)(?:\.(\d+)|)(?:[.\-]([a-z0-9]+)|)'
855
915
 
856
916
  - regex: '(Android) Donut'
857
917
  os_v1_replacement: '1'
@@ -873,18 +933,18 @@ os_parsers:
873
933
  os_v1_replacement: '3'
874
934
 
875
935
  # UCWEB
876
- - regex: '^UCWEB.*; (Adr) (\d+)\.(\d+)(?:[.\-]([a-z0-9]+))?;'
936
+ - regex: '^UCWEB.*; (Adr) (\d+)\.(\d+)(?:[.\-]([a-z0-9]+)|);'
877
937
  os_replacement: 'Android'
878
- - regex: '^UCWEB.*; (iPad|iPh|iPd) OS (\d+)_(\d+)(?:_(\d+))?;'
938
+ - regex: '^UCWEB.*; (iPad|iPh|iPd) OS (\d+)_(\d+)(?:_(\d+)|);'
879
939
  os_replacement: 'iOS'
880
- - regex: '^UCWEB.*; (wds) (\d+)\.(\d+)(?:\.(\d+))?;'
940
+ - regex: '^UCWEB.*; (wds) (\d+)\.(\d+)(?:\.(\d+)|);'
881
941
  os_replacement: 'Windows Phone'
882
942
  # JUC
883
- - regex: '^(JUC).*; ?U; ?(?:Android)?(\d+)\.(\d+)(?:[\.\-]([a-z0-9]+))?'
943
+ - regex: '^(JUC).*; ?U; ?(?:Android|)(\d+)\.(\d+)(?:[\.\-]([a-z0-9]+)|)'
884
944
  os_replacement: 'Android'
885
945
 
886
946
  # Salesforce
887
- - regex: '(android)\s(?:mobile\/)(\d+)\.(\d+)\.?(\d+)?'
947
+ - regex: '(android)\s(?:mobile\/)(\d+)(?:\.(\d+)(?:\.(\d+)|)|)'
888
948
  os_replacement: 'Android'
889
949
 
890
950
  ##########
@@ -893,6 +953,14 @@ os_parsers:
893
953
  - regex: '(Silk-Accelerated=[a-z]{4,5})'
894
954
  os_replacement: 'Android'
895
955
 
956
+ # Citrix Chrome App on Chrome OS
957
+ # Note, this needs to come before the windows parsers as the app doesn't
958
+ # properly identify as Chrome OS
959
+ #
960
+ # ex: Mozilla/5.0 (X11; Windows aarch64 10718.88.2) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3440.118 Safari/537.36 CitrixChromeApp
961
+ - regex: '(x86_64|aarch64)\ (\d+)\.(\d+)\.(\d+).*Chrome.*(?:CitrixChromeApp)$'
962
+ os_replacement: 'Chrome OS'
963
+
896
964
  ##########
897
965
  # Windows
898
966
  # http://en.wikipedia.org/wiki/Windows_NT#Releases
@@ -911,6 +979,10 @@ os_parsers:
911
979
  - regex: '(Windows ?Mobile)'
912
980
  os_replacement: 'Windows Mobile'
913
981
 
982
+ - regex: '(Windows 10)'
983
+ os_replacement: 'Windows'
984
+ os_v1_replacement: '10'
985
+
914
986
  - regex: '(Windows (?:NT 5\.2|NT 5\.1))'
915
987
  os_replacement: 'Windows'
916
988
  os_v1_replacement: 'XP'
@@ -927,8 +999,6 @@ os_parsers:
927
999
  os_replacement: 'Windows'
928
1000
  os_v1_replacement: 'ME'
929
1001
 
930
- - regex: '(Windows 98|Windows XP|Windows ME|Windows 95|Windows CE|Windows 7|Windows NT 4\.0|Windows Vista|Windows 2000|Windows 3.1)'
931
-
932
1002
  - regex: '(Windows NT 6\.2; ARM;)'
933
1003
  os_replacement: 'Windows'
934
1004
  os_v1_replacement: 'RT'
@@ -939,11 +1009,13 @@ os_parsers:
939
1009
 
940
1010
  - regex: '(Windows NT 6\.3; ARM;)'
941
1011
  os_replacement: 'Windows'
942
- os_v1_replacement: 'RT 8.1'
1012
+ os_v1_replacement: 'RT 8'
1013
+ os_v2_replacement: '1'
943
1014
 
944
1015
  - regex: '(Windows NT 6\.3)'
945
1016
  os_replacement: 'Windows'
946
- os_v1_replacement: '8.1'
1017
+ os_v1_replacement: '8'
1018
+ os_v2_replacement: '1'
947
1019
 
948
1020
  - regex: '(Windows NT 6\.4)'
949
1021
  os_replacement: 'Windows'
@@ -965,7 +1037,7 @@ os_parsers:
965
1037
  os_replacement: 'Windows'
966
1038
  os_v1_replacement: 'CE'
967
1039
 
968
- - regex: 'Win ?(95|98|3.1|NT|ME|2000)'
1040
+ - regex: 'Win(?:dows)? ?(95|98|3.1|NT|ME|2000|XP|Vista|7|CE)'
969
1041
  os_replacement: 'Windows'
970
1042
  os_v1_replacement: '$1'
971
1043
 
@@ -993,13 +1065,13 @@ os_parsers:
993
1065
  # @ref: http://en.wikipedia.org/wiki/Mac_OS_X#Versions
994
1066
  # @ref: http://www.puredarwin.org/curious/versions
995
1067
  ##########
996
- - regex: '((?:Mac[ +]?|; )OS[ +]X)[\s+/](?:(\d+)[_.](\d+)(?:[_.](\d+))?|Mach-O)'
1068
+ - regex: '((?:Mac[ +]?|; )OS[ +]X)[\s+/](?:(\d+)[_.](\d+)(?:[_.](\d+)|)|Mach-O)'
997
1069
  os_replacement: 'Mac OS X'
998
- - regex: '(\w+\s+Mac OS X\s+\w+\s+(\d+).(\d+).(\d+).*)'
1070
+ - regex: '\w+\s+Mac OS X\s+\w+\s+(\d+).(\d+).(\d+).*'
999
1071
  os_replacement: 'Mac OS X'
1000
- os_v1_replacement: '$2'
1001
- os_v2_replacement: '$3'
1002
- os_v3_replacement: '$4'
1072
+ os_v1_replacement: '$1'
1073
+ os_v2_replacement: '$2'
1074
+ os_v3_replacement: '$3'
1003
1075
  # Leopard
1004
1076
  - regex: ' (Dar)(win)/(9).(\d+).*\((?:i386|x86_64|Power Macintosh)\)'
1005
1077
  os_replacement: 'Mac OS X'
@@ -1038,7 +1110,7 @@ os_parsers:
1038
1110
  - regex: '(?:PPC|Intel) (Mac OS X)'
1039
1111
 
1040
1112
  # Box Drive and Box Sync on Mac OS X use OSX version numbers, not Darwin
1041
- - regex: '^Box.*;(Darwin)/(10)\.(1\d)(?:\.(\d+))?'
1113
+ - regex: '^Box.*;(Darwin)/(10)\.(1\d)(?:\.(\d+)|)'
1042
1114
  os_replacement: 'Mac OS X'
1043
1115
 
1044
1116
  ##########
@@ -1046,10 +1118,10 @@ os_parsers:
1046
1118
  # http://en.wikipedia.org/wiki/IOS_version_history
1047
1119
  ##########
1048
1120
  # keep this above generic iOS, since AppleTV UAs contain 'CPU OS'
1049
- - regex: '(Apple\s?TV)(?:/(\d+)\.(\d+))?'
1121
+ - regex: '(Apple\s?TV)(?:/(\d+)\.(\d+)|)'
1050
1122
  os_replacement: 'ATV OS X'
1051
1123
 
1052
- - regex: '(CPU[ +]OS|iPhone[ +]OS|CPU[ +]iPhone|CPU IPhone OS)[ +]+(\d+)[_\.](\d+)(?:[_\.](\d+))?'
1124
+ - regex: '(CPU[ +]OS|iPhone[ +]OS|CPU[ +]iPhone|CPU IPhone OS)[ +]+(\d+)[_\.](\d+)(?:[_\.](\d+)|)'
1053
1125
  os_replacement: 'iOS'
1054
1126
 
1055
1127
  # remaining cases are mostly only opera uas, so catch opera as to not catch iphone spoofs
@@ -1231,19 +1303,31 @@ os_parsers:
1231
1303
  os_replacement: 'iOS'
1232
1304
 
1233
1305
  # iOS Apps
1234
- - regex: '\b(iOS[ /]|iOS; |iPhone(?:/| v|[ _]OS[/,]|; | OS : |\d,\d/|\d,\d; )|iPad/)(\d{1,2})[_\.](\d{1,2})(?:[_\.](\d+))?'
1306
+ - regex: '\b(iOS[ /]|iOS; |iPhone(?:/| v|[ _]OS[/,]|; | OS : |\d,\d/|\d,\d; )|iPad/)(\d{1,2})[_\.](\d{1,2})(?:[_\.](\d+)|)'
1235
1307
  os_replacement: 'iOS'
1236
1308
  - regex: '\((iOS);'
1237
1309
 
1310
+ ##########
1311
+ # Apple Watch
1312
+ ##########
1313
+ - regex: '(watchOS)/(\d+)\.(\d+)(?:\.(\d+)|)'
1314
+ os_replacement: 'WatchOS'
1315
+
1238
1316
  ##########################
1239
1317
  # Outlook on iOS >= 2.62.0
1240
1318
  ##########################
1241
1319
  - regex: 'Outlook-(iOS)/\d+\.\d+\.prod\.iphone'
1242
1320
 
1321
+ ##########################
1322
+ # iOS devices, the same regex matches mobile safari webviews
1323
+ ##########################
1324
+ - regex: '(iPod|iPhone|iPad)'
1325
+ os_replacement: 'iOS'
1326
+
1243
1327
  ##########
1244
1328
  # Apple TV
1245
1329
  ##########
1246
- - regex: '(tvOS)/(\d+).(\d+)'
1330
+ - regex: '(tvOS)[/ ](\d+)\.(\d+)(?:\.(\d+)|)'
1247
1331
  os_replacement: 'tvOS'
1248
1332
 
1249
1333
  ##########
@@ -1252,7 +1336,7 @@ os_parsers:
1252
1336
  # http://code.google.com/p/chromium-os/issues/detail?id=11573
1253
1337
  # http://code.google.com/p/chromium-os/issues/detail?id=13790
1254
1338
  ##########
1255
- - regex: '(CrOS) [a-z0-9_]+ (\d+)\.(\d+)(?:\.(\d+))?'
1339
+ - regex: '(CrOS) [a-z0-9_]+ (\d+)\.(\d+)(?:\.(\d+)|)'
1256
1340
  os_replacement: 'Chrome OS'
1257
1341
 
1258
1342
  ##########
@@ -1260,8 +1344,8 @@ os_parsers:
1260
1344
  ##########
1261
1345
  - regex: '([Dd]ebian)'
1262
1346
  os_replacement: 'Debian'
1263
- - regex: '(Linux Mint)(?:/(\d+))?'
1264
- - regex: '(Mandriva)(?: Linux)?/(?:[\d.-]+m[a-z]{2}(\d+).(\d))?'
1347
+ - regex: '(Linux Mint)(?:/(\d+)|)'
1348
+ - regex: '(Mandriva)(?: Linux|)/(?:[\d.-]+m[a-z]{2}(\d+).(\d)|)'
1265
1349
 
1266
1350
  ##########
1267
1351
  # Symbian + Symbian OS
@@ -1290,9 +1374,9 @@ os_parsers:
1290
1374
  ##########
1291
1375
  - regex: '(BB10);.+Version/(\d+)\.(\d+)\.(\d+)'
1292
1376
  os_replacement: 'BlackBerry OS'
1293
- - regex: '(Black[Bb]erry)[0-9a-z]+/(\d+)\.(\d+)\.(\d+)(?:\.(\d+))?'
1377
+ - regex: '(Black[Bb]erry)[0-9a-z]+/(\d+)\.(\d+)\.(\d+)(?:\.(\d+)|)'
1294
1378
  os_replacement: 'BlackBerry OS'
1295
- - regex: '(Black[Bb]erry).+Version/(\d+)\.(\d+)\.(\d+)(?:\.(\d+))?'
1379
+ - regex: '(Black[Bb]erry).+Version/(\d+)\.(\d+)\.(\d+)(?:\.(\d+)|)'
1296
1380
  os_replacement: 'BlackBerry OS'
1297
1381
  - regex: '(RIM Tablet OS) (\d+)\.(\d+)\.(\d+)'
1298
1382
  os_replacement: 'BlackBerry Tablet OS'
@@ -1359,20 +1443,20 @@ os_parsers:
1359
1443
  ##########
1360
1444
  # Google TV
1361
1445
  ##########
1362
- - regex: '(GoogleTV)(?: (\d+)\.(\d+)(?:\.(\d+))?|/[\da-z]+)'
1446
+ - regex: '(GoogleTV)(?: (\d+)\.(\d+)(?:\.(\d+)|)|/[\da-z]+)'
1363
1447
 
1364
1448
  - regex: '(WebTV)/(\d+).(\d+)'
1365
1449
 
1366
1450
  ##########
1367
1451
  # Chromecast
1368
1452
  ##########
1369
- - regex: '(CrKey)(?:[/](\d+)\.(\d+)(?:\.(\d+))?)?'
1453
+ - regex: '(CrKey)(?:[/](\d+)\.(\d+)(?:\.(\d+)|)|)'
1370
1454
  os_replacement: 'Chromecast'
1371
1455
 
1372
1456
  ##########
1373
1457
  # Misc mobile
1374
1458
  ##########
1375
- - regex: '(hpw|web)OS/(\d+)\.(\d+)(?:\.(\d+))?'
1459
+ - regex: '(hpw|web)OS/(\d+)\.(\d+)(?:\.(\d+)|)'
1376
1460
  os_replacement: 'webOS'
1377
1461
  - regex: '(VRE);'
1378
1462
 
@@ -1380,10 +1464,10 @@ os_parsers:
1380
1464
  # Generic patterns
1381
1465
  # since the majority of os cases are very specific, these go last
1382
1466
  ##########
1383
- - regex: '(Fedora|Red Hat|PCLinuxOS|Puppy|Ubuntu|Kindle|Bada|Lubuntu|BackTrack|Slackware|(?:Free|Open|Net|\b)BSD)[/ ](\d+)\.(\d+)(?:\.(\d+)(?:\.(\d+))?)?'
1467
+ - regex: '(Fedora|Red Hat|PCLinuxOS|Puppy|Ubuntu|Kindle|Bada|Sailfish|Lubuntu|BackTrack|Slackware|(?:Free|Open|Net|\b)BSD)[/ ](\d+)\.(\d+)(?:\.(\d+)|)(?:\.(\d+)|)'
1384
1468
 
1385
1469
  # Gentoo Linux + Kernel Version
1386
- - regex: '(Linux)[ /](\d+)\.(\d+)(?:\.(\d+))?.*gentoo'
1470
+ - regex: '(Linux)[ /](\d+)\.(\d+)(?:\.(\d+)|).*gentoo'
1387
1471
  os_replacement: 'Gentoo'
1388
1472
 
1389
1473
  # Opera Mini Bada
@@ -1393,7 +1477,7 @@ os_parsers:
1393
1477
  - regex: '(Windows|Android|WeTab|Maemo|Web0S)'
1394
1478
  - regex: '(Ubuntu|Kubuntu|Arch Linux|CentOS|Slackware|Gentoo|openSUSE|SUSE|Red Hat|Fedora|PCLinuxOS|Mageia|(?:Free|Open|Net|\b)BSD)'
1395
1479
  # Linux + Kernel Version
1396
- - regex: '(Linux)(?:[ /](\d+)\.(\d+)(?:\.(\d+))?)?'
1480
+ - regex: '(Linux)(?:[ /](\d+)\.(\d+)(?:\.(\d+)|)|)'
1397
1481
  - regex: 'SunOS'
1398
1482
  os_replacement: 'Solaris'
1399
1483
  # Wget/x.x.x (linux-gnu)
@@ -1424,6 +1508,16 @@ device_parsers:
1424
1508
  brand_replacement: 'Spider'
1425
1509
  model_replacement: 'Feature Phone'
1426
1510
 
1511
+ # PTST / WebPageTest.org crawlers
1512
+ - regex: ' PTST/\d+(?:\.)?\d+$'
1513
+ device_replacement: 'Spider'
1514
+ brand_replacement: 'Spider'
1515
+
1516
+ # Datanyze.com spider
1517
+ - regex: 'X11; Datanyze; Linux'
1518
+ device_replacement: 'Spider'
1519
+ brand_replacement: 'Spider'
1520
+
1427
1521
  #########
1428
1522
  # WebBrowser for SmartWatch
1429
1523
  # @ref: https://play.google.com/store/apps/details?id=se.vaggan.webbrowser&hl=en
@@ -1440,7 +1534,7 @@ device_parsers:
1440
1534
  ######################################################################
1441
1535
 
1442
1536
  # Android Application
1443
- - regex: 'Android Application[^\-]+ - (Sony) ?(Ericsson)? (.+) \w+ - '
1537
+ - regex: 'Android Application[^\-]+ - (Sony) ?(Ericsson|) (.+) \w+ - '
1444
1538
  device_replacement: '$1 $2'
1445
1539
  brand_replacement: '$1$2'
1446
1540
  model_replacement: '$3'
@@ -1471,7 +1565,7 @@ device_parsers:
1471
1565
  # Acer
1472
1566
  # @ref: http://us.acer.com/ac/en/US/content/group/tablets
1473
1567
  #########
1474
- - 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'
1568
+ - 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'
1475
1569
  device_replacement: '$1'
1476
1570
  brand_replacement: 'Acer'
1477
1571
  model_replacement: '$1'
@@ -1494,7 +1588,7 @@ device_parsers:
1494
1588
  # @note: VegaBean and VegaComb (names derived from jellybean, honeycomb) are
1495
1589
  # custom ROM builds for Vega
1496
1590
  #########
1497
- - regex: '; *(Advent )?(Vega(?:Bean|Comb)?).* Build'
1591
+ - regex: '; *(Advent |)(Vega(?:Bean|Comb|)).* Build'
1498
1592
  device_replacement: '$1$2'
1499
1593
  brand_replacement: 'Advent'
1500
1594
  model_replacement: '$2'
@@ -1503,7 +1597,7 @@ device_parsers:
1503
1597
  # Ainol
1504
1598
  # @ref: http://www.ainol.com/plugin.php?identifier=ainol&module=product
1505
1599
  #########
1506
- - regex: '; *(Ainol )?((?:NOVO|[Nn]ovo)[^;/]+) Build'
1600
+ - regex: '; *(Ainol |)((?:NOVO|[Nn]ovo)[^;/]+) Build'
1507
1601
  device_replacement: '$1$2'
1508
1602
  brand_replacement: 'Ainol'
1509
1603
  model_replacement: '$2'
@@ -1540,7 +1634,7 @@ device_parsers:
1540
1634
  device_replacement: 'Alcatel One Touch $2'
1541
1635
  brand_replacement: 'Alcatel'
1542
1636
  model_replacement: 'One Touch $2'
1543
- - regex: '; *(?:alcatel[ _])?(?:(?:one[ _]?touch[ _])|ot[ \-])([^;/]+);? Build'
1637
+ - regex: '; *(?:alcatel[ _]|)(?:(?:one[ _]?touch[ _])|ot[ \-])([^;/]+);? Build'
1544
1638
  regex_flag: 'i'
1545
1639
  device_replacement: 'Alcatel One Touch $1'
1546
1640
  brand_replacement: 'Alcatel'
@@ -1580,7 +1674,7 @@ device_parsers:
1580
1674
  device_replacement: '$1$2'
1581
1675
  brand_replacement: 'Allview'
1582
1676
  model_replacement: '$2'
1583
- - regex: '; *(ALLVIEW[ _]?|Allview[ _]?)?(AX1_Shine|AX2_Frenzy) Build'
1677
+ - regex: '; *(ALLVIEW[ _]?|Allview[ _]?|)(AX1_Shine|AX2_Frenzy) Build'
1584
1678
  device_replacement: '$1$2'
1585
1679
  brand_replacement: 'Allview'
1586
1680
  model_replacement: '$2'
@@ -1640,7 +1734,7 @@ device_parsers:
1640
1734
  # @ref: http://www.luckystar.com.cn/en/mobiletel.aspx?page=1
1641
1735
  # @note: brand owned by luckystar
1642
1736
  #########
1643
- - 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'
1737
+ - 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'
1644
1738
  device_replacement: 'Aoson $1'
1645
1739
  brand_replacement: 'Aoson'
1646
1740
  model_replacement: '$1'
@@ -1715,7 +1809,7 @@ device_parsers:
1715
1809
  # Assistant
1716
1810
  # @ref: http://www.assistant.ua
1717
1811
  #########
1718
- - regex: '; *(?:ASSISTANT )?(AP)-?([1789]\d{2}[A-Z]{0,2}|80104) Build'
1812
+ - regex: '; *(?:ASSISTANT |)(AP)-?([1789]\d{2}[A-Z]{0,2}|80104) Build'
1719
1813
  device_replacement: 'Assistant $1-$2'
1720
1814
  brand_replacement: 'Assistant'
1721
1815
  model_replacement: '$1-$2'
@@ -1724,7 +1818,7 @@ device_parsers:
1724
1818
  # Asus
1725
1819
  # @ref: http://www.asus.com/uk/Tablets_Mobile/
1726
1820
  #########
1727
- - regex: '; *(ME17\d[^;/]*|ME3\d{2}[^;/]+|K00[A-Z]|Nexus 10|Nexus 7(?: 2013)?|PadFone[^;/]*|Transformer[^;/]*|TF\d{3}[^;/]*|eeepc) Build'
1821
+ - regex: '; *(ME17\d[^;/]*|ME3\d{2}[^;/]+|K00[A-Z]|Nexus 10|Nexus 7(?: 2013|)|PadFone[^;/]*|Transformer[^;/]*|TF\d{3}[^;/]*|eeepc) Build'
1728
1822
  device_replacement: 'Asus $1'
1729
1823
  brand_replacement: 'Asus'
1730
1824
  model_replacement: '$1'
@@ -2272,7 +2366,7 @@ device_parsers:
2272
2366
  # Gionee
2273
2367
  # @ref: http://www.gionee.com/
2274
2368
  #########
2275
- - regex: '; *(Gionee)[ _\-]([^;/]+)(?:/[^;/]+)? Build'
2369
+ - regex: '; *(Gionee)[ _\-]([^;/]+)(?:/[^;/]+|) Build'
2276
2370
  regex_flag: 'i'
2277
2371
  device_replacement: '$1 $2'
2278
2372
  brand_replacement: 'Gionee'
@@ -2436,7 +2530,7 @@ device_parsers:
2436
2530
  # @ref: http://www.huaweidevice.com
2437
2531
  # @note: Needs to be before HTC due to Desire HD Build on U8815
2438
2532
  #########
2439
- - regex: '; *(HUAWEI |Huawei-)?([UY][^;/]+) Build/(?:Huawei|HUAWEI)([UY][^\);]+)\)'
2533
+ - regex: '; *(HUAWEI |Huawei-|)([UY][^;/]+) Build/(?:Huawei|HUAWEI)([UY][^\);]+)\)'
2440
2534
  device_replacement: '$1$2'
2441
2535
  brand_replacement: 'Huawei'
2442
2536
  model_replacement: '$2'
@@ -2452,7 +2546,7 @@ device_parsers:
2452
2546
  device_replacement: '$1$2'
2453
2547
  brand_replacement: 'Huawei'
2454
2548
  model_replacement: '$2'
2455
- - regex: '; *((?:HUAWEI[ _]?|Huawei[ _])?Ascend[ _])([^;/]+) Build'
2549
+ - regex: '; *((?:HUAWEI[ _]?|Huawei[ _]|)Ascend[ _])([^;/]+) Build'
2456
2550
  device_replacement: '$1$2'
2457
2551
  brand_replacement: 'Huawei'
2458
2552
  model_replacement: '$2'
@@ -2488,6 +2582,10 @@ device_parsers:
2488
2582
  device_replacement: 'Huawei $1'
2489
2583
  brand_replacement: 'Huawei'
2490
2584
  model_replacement: '$1'
2585
+ - regex: '; *((?:[A-Z]{3})\-L[A-Za0-9]{2})[\)]'
2586
+ device_replacement: 'Huawei $1'
2587
+ brand_replacement: 'Huawei'
2588
+ model_replacement: '$1'
2491
2589
 
2492
2590
  #########
2493
2591
  # HTC
@@ -2507,33 +2605,33 @@ device_parsers:
2507
2605
  device_replacement: 'HTC $1'
2508
2606
  brand_replacement: 'HTC'
2509
2607
  model_replacement: '$1'
2510
- - regex: '; *(?:HTC[ _/])+([^ _/]+)(?:[ _/]([^ _/]+))?(?:[/\\]1\.0 | V|/| +)\d+\.\d[\d\.]*(?: *Build|\))'
2608
+ - regex: '; *(?:HTC[ _/])+([^ _/]+)(?:[ _/]([^ _/]+)|)(?:[/\\]1\.0 | V|/| +)\d+\.\d[\d\.]*(?: *Build|\))'
2511
2609
  device_replacement: 'HTC $1 $2'
2512
2610
  brand_replacement: 'HTC'
2513
2611
  model_replacement: '$1 $2'
2514
- - regex: '; *(?:HTC[ _/])+([^ _/]+)(?:[ _/]([^ _/]+)(?:[ _/]([^ _/]+))?)?(?:[/\\]1\.0 | V|/| +)\d+\.\d[\d\.]*(?: *Build|\))'
2612
+ - regex: '; *(?:HTC[ _/])+([^ _/]+)(?:[ _/]([^ _/]+)(?:[ _/]([^ _/]+)|)|)(?:[/\\]1\.0 | V|/| +)\d+\.\d[\d\.]*(?: *Build|\))'
2515
2613
  device_replacement: 'HTC $1 $2 $3'
2516
2614
  brand_replacement: 'HTC'
2517
2615
  model_replacement: '$1 $2 $3'
2518
- - regex: '; *(?:HTC[ _/])+([^ _/]+)(?:[ _/]([^ _/]+)(?:[ _/]([^ _/]+)(?:[ _/]([^ _/]+))?)?)?(?:[/\\]1\.0 | V|/| +)\d+\.\d[\d\.]*(?: *Build|\))'
2616
+ - regex: '; *(?:HTC[ _/])+([^ _/]+)(?:[ _/]([^ _/]+)(?:[ _/]([^ _/]+)(?:[ _/]([^ _/]+)|)|)|)(?:[/\\]1\.0 | V|/| +)\d+\.\d[\d\.]*(?: *Build|\))'
2519
2617
  device_replacement: 'HTC $1 $2 $3 $4'
2520
2618
  brand_replacement: 'HTC'
2521
2619
  model_replacement: '$1 $2 $3 $4'
2522
2620
 
2523
2621
  # Android HTC without Version Number matcher
2524
- - regex: '; *(?:(?:HTC|htc)(?:_blocked)*[ _/])+([^ _/;]+)(?: *Build|[;\)]| - )'
2622
+ - regex: '; *(?:(?:HTC|htc)(?:_blocked|)[ _/])+([^ _/;]+)(?: *Build|[;\)]| - )'
2525
2623
  device_replacement: 'HTC $1'
2526
2624
  brand_replacement: 'HTC'
2527
2625
  model_replacement: '$1'
2528
- - regex: '; *(?:(?:HTC|htc)(?:_blocked)*[ _/])+([^ _/]+)(?:[ _/]([^ _/;\)]+))?(?: *Build|[;\)]| - )'
2626
+ - regex: '; *(?:(?:HTC|htc)(?:_blocked|)[ _/])+([^ _/]+)(?:[ _/]([^ _/;\)]+)|)(?: *Build|[;\)]| - )'
2529
2627
  device_replacement: 'HTC $1 $2'
2530
2628
  brand_replacement: 'HTC'
2531
2629
  model_replacement: '$1 $2'
2532
- - regex: '; *(?:(?:HTC|htc)(?:_blocked)*[ _/])+([^ _/]+)(?:[ _/]([^ _/]+)(?:[ _/]([^ _/;\)]+))?)?(?: *Build|[;\)]| - )'
2630
+ - regex: '; *(?:(?:HTC|htc)(?:_blocked|)[ _/])+([^ _/]+)(?:[ _/]([^ _/]+)(?:[ _/]([^ _/;\)]+)|)|)(?: *Build|[;\)]| - )'
2533
2631
  device_replacement: 'HTC $1 $2 $3'
2534
2632
  brand_replacement: 'HTC'
2535
2633
  model_replacement: '$1 $2 $3'
2536
- - regex: '; *(?:(?:HTC|htc)(?:_blocked)*[ _/])+([^ _/]+)(?:[ _/]([^ _/]+)(?:[ _/]([^ _/]+)(?:[ _/]([^ /;]+))?)?)?(?: *Build|[;\)]| - )'
2634
+ - regex: '; *(?:(?:HTC|htc)(?:_blocked|)[ _/])+([^ _/]+)(?:[ _/]([^ _/]+)(?:[ _/]([^ _/]+)(?:[ _/]([^ /;]+)|)|)|)(?: *Build|[;\)]| - )'
2537
2635
  device_replacement: 'HTC $1 $2 $3 $4'
2538
2636
  brand_replacement: 'HTC'
2539
2637
  model_replacement: '$1 $2 $3 $4'
@@ -2544,7 +2642,7 @@ device_parsers:
2544
2642
  brand_replacement: 'HTC'
2545
2643
  model_replacement: '$1'
2546
2644
  # general matcher for anything else
2547
- - regex: '(?:[;,] *|^)(?:htccn_chs-)?HTC[ _-]?([^;]+?)(?: *Build|clay|Android|-?Mozilla| Opera| Profile| UNTRUSTED|[;/\(\)]|$)'
2645
+ - regex: '(?:[;,] *|^)(?:htccn_chs-|)HTC[ _-]?([^;]+?)(?: *Build|clay|Android|-?Mozilla| Opera| Profile| UNTRUSTED|[;/\(\)]|$)'
2548
2646
  regex_flag: 'i'
2549
2647
  device_replacement: 'HTC $1'
2550
2648
  brand_replacement: 'HTC'
@@ -2583,12 +2681,12 @@ device_parsers:
2583
2681
  # iBall
2584
2682
  # @ref: http://www.iball.co.in/Category/Mobiles/22
2585
2683
  #########
2586
- - regex: '; *(?:iBall[ _\-])?(Andi)[ _]?(\d[^;/]*) Build'
2684
+ - regex: '; *(?:iBall[ _\-]|)(Andi)[ _]?(\d[^;/]*) Build'
2587
2685
  regex_flag: 'i'
2588
2686
  device_replacement: '$1 $2'
2589
2687
  brand_replacement: 'iBall'
2590
2688
  model_replacement: '$1 $2'
2591
- - regex: '; *(IBall)(?:[ _]([^;/]+))? Build'
2689
+ - regex: '; *(IBall)(?:[ _]([^;/]+)|) Build'
2592
2690
  regex_flag: 'i'
2593
2691
  device_replacement: '$1 $2'
2594
2692
  brand_replacement: 'iBall'
@@ -2598,7 +2696,7 @@ device_parsers:
2598
2696
  # IconBIT
2599
2697
  # @ref: http://www.iconbit.com/catalog/tablets/
2600
2698
  #########
2601
- - regex: '; *(NT-\d+[^ ;/]*|Net[Tt]AB [^;/]+|Mercury [A-Z]+|iconBIT)(?: S/N:[^;/]+)? Build'
2699
+ - regex: '; *(NT-\d+[^ ;/]*|Net[Tt]AB [^;/]+|Mercury [A-Z]+|iconBIT)(?: S/N:[^;/]+|) Build'
2602
2700
  device_replacement: '$1'
2603
2701
  brand_replacement: 'IconBIT'
2604
2702
  model_replacement: '$1'
@@ -2671,17 +2769,17 @@ device_parsers:
2671
2769
  # @note: Zync also offers a "Cloud Z5" device
2672
2770
  #########
2673
2771
  # smartphones
2674
- - regex: '; *(?:Intex[ _])?(AQUA|Aqua)([ _\.\-])([^;/]+) *(?:Build|;)'
2772
+ - regex: '; *(?:Intex[ _]|)(AQUA|Aqua)([ _\.\-])([^;/]+) *(?:Build|;)'
2675
2773
  device_replacement: '$1$2$3'
2676
2774
  brand_replacement: 'Intex'
2677
2775
  model_replacement: '$1 $3'
2678
2776
  # matches "INTEX CLOUD X1"
2679
- - regex: '; *(?:INTEX|Intex)(?:[_ ]([^\ _;/]+))(?:[_ ]([^\ _;/]+))? *(?:Build|;)'
2777
+ - regex: '; *(?:INTEX|Intex)(?:[_ ]([^\ _;/]+))(?:[_ ]([^\ _;/]+)|) *(?:Build|;)'
2680
2778
  device_replacement: '$1 $2'
2681
2779
  brand_replacement: 'Intex'
2682
2780
  model_replacement: '$1 $2'
2683
2781
  # tablets
2684
- - regex: '; *([iI]Buddy)[ _]?(Connect)(?:_|\?_| )?([^;/]*) *(?:Build|;)'
2782
+ - regex: '; *([iI]Buddy)[ _]?(Connect)(?:_|\?_| |)([^;/]*) *(?:Build|;)'
2685
2783
  device_replacement: '$1 $2 $3'
2686
2784
  brand_replacement: 'Intex'
2687
2785
  model_replacement: 'iBuddy $2 $3'
@@ -2704,7 +2802,7 @@ device_parsers:
2704
2802
  # i.onik
2705
2803
  # @ref: http://www.i-onik.de/
2706
2804
  #########
2707
- - regex: '; *(TP\d+(?:\.\d+)?\-\d[^;/]+) Build'
2805
+ - regex: '; *(TP\d+(?:\.\d+|)\-\d[^;/]+) Build'
2708
2806
  device_replacement: 'ionik $1'
2709
2807
  brand_replacement: 'ionik'
2710
2808
  model_replacement: '$1'
@@ -2920,7 +3018,7 @@ device_parsers:
2920
3018
  # Lava
2921
3019
  # @ref: http://www.lavamobiles.com/
2922
3020
  #########
2923
- - regex: '; *(?:LAVA[ _])?IRIS[ _\-]?([^/;\)]+) *(?:;|\)|Build)'
3021
+ - regex: '; *(?:LAVA[ _]|)IRIS[ _\-]?([^/;\)]+) *(?:;|\)|Build)'
2924
3022
  regex_flag: 'i'
2925
3023
  device_replacement: 'Iris $1'
2926
3024
  brand_replacement: 'Lava'
@@ -2972,15 +3070,15 @@ device_parsers:
2972
3070
  device_replacement: 'Lenovo $1 $2'
2973
3071
  brand_replacement: 'Lenovo'
2974
3072
  model_replacement: '$1 $2'
2975
- - regex: '; *(?:LNV-)?(?:=?[Ll]enovo[ _\-]?|LENOVO[ _])+(.+?)(?:Build|[;/\)])'
3073
+ - regex: '; *(?:LNV-|)(?:=?[Ll]enovo[ _\-]?|LENOVO[ _])(.+?)(?:Build|[;/\)])'
2976
3074
  device_replacement: 'Lenovo $1'
2977
3075
  brand_replacement: 'Lenovo'
2978
3076
  model_replacement: '$1'
2979
- - regex: '[;,] (?:Vodafone )?(SmartTab) ?(II) ?(\d+) Build/'
3077
+ - regex: '[;,] (?:Vodafone |)(SmartTab) ?(II) ?(\d+) Build/'
2980
3078
  device_replacement: 'Lenovo $1 $2 $3'
2981
3079
  brand_replacement: 'Lenovo'
2982
3080
  model_replacement: '$1 $2 $3'
2983
- - regex: '; *(?:Ideapad )?K1 Build/'
3081
+ - regex: '; *(?:Ideapad |)K1 Build/'
2984
3082
  device_replacement: 'Lenovo Ideapad K1'
2985
3083
  brand_replacement: 'Lenovo'
2986
3084
  model_replacement: 'Ideapad K1'
@@ -3010,7 +3108,7 @@ device_parsers:
3010
3108
  device_replacement: '$1'
3011
3109
  brand_replacement: 'LG'
3012
3110
  model_replacement: '$1'
3013
- - regex: '[;:] *(L-\d+[A-Z]|LGL\d+[A-Z]?)(?:/V\d+)? *(?:Build|[;\)])'
3111
+ - regex: '[;:] *(L-\d+[A-Z]|LGL\d+[A-Z]?)(?:/V\d+|) *(?:Build|[;\)])'
3014
3112
  device_replacement: '$1'
3015
3113
  brand_replacement: 'LG'
3016
3114
  model_replacement: '$1'
@@ -3093,7 +3191,7 @@ device_parsers:
3093
3191
  # Medion
3094
3192
  # @ref: http://www.medion.com/en/
3095
3193
  #########
3096
- - regex: '; *(?:MD_)?LIFETAB[ _]([^;/]+) Build'
3194
+ - regex: '; *(?:MD_|)LIFETAB[ _]([^;/]+) Build'
3097
3195
  regex_flag: 'i'
3098
3196
  device_replacement: 'Medion Lifetab $1'
3099
3197
  brand_replacement: 'Medion'
@@ -3171,7 +3269,7 @@ device_parsers:
3171
3269
  # Modecom
3172
3270
  # @ref: http://www.modecom.eu/tablets/portal/
3173
3271
  #########
3174
- - regex: '; *(MODECOM )?(FreeTab) ?([^;/]+) Build'
3272
+ - regex: '; *(MODECOM |)(FreeTab) ?([^;/]+) Build'
3175
3273
  regex_flag: 'i'
3176
3274
  device_replacement: '$1$2 $3'
3177
3275
  brand_replacement: 'Modecom'
@@ -3229,7 +3327,7 @@ device_parsers:
3229
3327
  # MSI
3230
3328
  # @ref: http://www.msi.com/product/windpad/
3231
3329
  #########
3232
- - regex: '; *(?:MSI[ _])?(Primo\d+|Enjoy[ _\-][^;/]+) Build'
3330
+ - regex: '; *(?:MSI[ _]|)(Primo\d+|Enjoy[ _\-][^;/]+) Build'
3233
3331
  regex_flag: 'i'
3234
3332
  device_replacement: '$1'
3235
3333
  brand_replacement: 'Msi'
@@ -3256,7 +3354,7 @@ device_parsers:
3256
3354
  device_replacement: '$1$2 $3'
3257
3355
  brand_replacement: 'MyPhone'
3258
3356
  model_replacement: '$3'
3259
- - regex: '; *(A\d+)[ _](Duo)? Build'
3357
+ - regex: '; *(A\d+)[ _](Duo|) Build'
3260
3358
  regex_flag: 'i'
3261
3359
  device_replacement: '$1 $2'
3262
3360
  brand_replacement: 'MyPhone'
@@ -3325,7 +3423,7 @@ device_parsers:
3325
3423
  device_replacement: '$1$2'
3326
3424
  brand_replacement: 'Nook'
3327
3425
  model_replacement: '$2'
3328
- - regex: '; *(NOOK )?(BNRV200|BNRV200A|BNTV250|BNTV250A|BNTV400|BNTV600|LogicPD Zoom2) Build'
3426
+ - regex: '; *(NOOK |)(BNRV200|BNRV200A|BNTV250|BNTV250A|BNTV400|BNTV600|LogicPD Zoom2) Build'
3329
3427
  device_replacement: '$1$2'
3330
3428
  brand_replacement: 'Nook'
3331
3429
  model_replacement: '$2'
@@ -3410,7 +3508,7 @@ device_parsers:
3410
3508
  device_replacement: 'OnePlus $1'
3411
3509
  brand_replacement: 'OnePlus'
3412
3510
  model_replacement: '$1'
3413
- - regex: '; (ONEPLUS [a-zA-Z]\d+) Build/'
3511
+ - regex: '; (ONEPLUS [a-zA-Z]\d+)(?: Build/|)'
3414
3512
  device_replacement: 'OnePlus $1'
3415
3513
  brand_replacement: 'OnePlus'
3416
3514
  model_replacement: '$1'
@@ -3460,11 +3558,11 @@ device_parsers:
3460
3558
  # @href: http://www.pantech.co.kr/en/prod/prodList.do?gbrand=VEGA
3461
3559
  # @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
3462
3560
  #########
3463
- - regex: '; *(SKY[ _])?(IM\-[AT]\d{3}[^;/]+).* Build/'
3561
+ - regex: '; *(SKY[ _]|)(IM\-[AT]\d{3}[^;/]+).* Build/'
3464
3562
  device_replacement: 'Pantech $1$2'
3465
3563
  brand_replacement: 'Pantech'
3466
3564
  model_replacement: '$1$2'
3467
- - regex: '; *((?:ADR8995|ADR910L|ADR930L|ADR930VW|PTL21|P8000)(?: 4G)?) Build/'
3565
+ - regex: '; *((?:ADR8995|ADR910L|ADR930L|ADR930VW|PTL21|P8000)(?: 4G|)) Build/'
3468
3566
  device_replacement: '$1'
3469
3567
  brand_replacement: 'Pantech'
3470
3568
  model_replacement: '$1'
@@ -3547,7 +3645,7 @@ device_parsers:
3547
3645
  # Polaroid/ Acho
3548
3646
  # @ref: http://polaroidstore.com/store/start.asp?category_id=382&category_id2=0&order=title&filter1=&filter2=&filter3=&view=all
3549
3647
  #########
3550
- - regex: '; *(?:Polaroid[ _])?((?:MIDC\d{3,}|PMID\d{2,}|PTAB\d{3,})[^;/]*)(\/[^;/]*)? Build/'
3648
+ - regex: '; *(?:Polaroid[ _]|)((?:MIDC\d{3,}|PMID\d{2,}|PTAB\d{3,})[^;/]*)(\/[^;/]*|) Build/'
3551
3649
  device_replacement: '$1'
3552
3650
  brand_replacement: 'Polaroid'
3553
3651
  model_replacement: '$1'
@@ -3574,7 +3672,7 @@ device_parsers:
3574
3672
  device_replacement: '$1'
3575
3673
  brand_replacement: 'Positivo'
3576
3674
  model_replacement: '$1'
3577
- - regex: '; *(?:Positivo )?((?:YPY|Ypy)[^;/]+) Build/'
3675
+ - regex: '; *(?:Positivo |)((?:YPY|Ypy)[^;/]+) Build/'
3578
3676
  device_replacement: '$1'
3579
3677
  brand_replacement: 'Positivo'
3580
3678
  model_replacement: '$1'
@@ -3602,7 +3700,7 @@ device_parsers:
3602
3700
  # @ref: http://www.prestigio.com/catalogue/MultiPhones
3603
3701
  # @ref: http://www.prestigio.com/catalogue/MultiPads
3604
3702
  #########
3605
- - regex: '; *(?:Prestigio )?((?:PAP|PMP)\d[^;/]+) Build/'
3703
+ - regex: '; *(?:Prestigio |)((?:PAP|PMP)\d[^;/]+) Build/'
3606
3704
  device_replacement: 'Prestigio $1'
3607
3705
  brand_replacement: 'Prestigio'
3608
3706
  model_replacement: '$1'
@@ -3620,7 +3718,7 @@ device_parsers:
3620
3718
  # QMobile
3621
3719
  # @ref: http://www.qmobile.com.pk/
3622
3720
  #########
3623
- - regex: '; *(A2|A5|A8|A900)_?(Classic)? Build'
3721
+ - regex: '; *(A2|A5|A8|A900)_?(Classic|) Build'
3624
3722
  device_replacement: '$1 $2'
3625
3723
  brand_replacement: 'Qmobile'
3626
3724
  model_replacement: '$1 $2'
@@ -3686,11 +3784,11 @@ device_parsers:
3686
3784
  # Samsung Android Devices
3687
3785
  # @ref: http://www.samsung.com/us/mobile/cell-phones/all-products
3688
3786
  #########
3689
- - regex: '; *(SAMSUNG |Samsung )?((?:Galaxy (?:Note II|S\d)|GT-I9082|GT-I9205|GT-N7\d{3}|SM-N9005)[^;/]*)\/?[^;/]* Build/'
3787
+ - regex: '; *(SAMSUNG |Samsung |)((?:Galaxy (?:Note II|S\d)|GT-I9082|GT-I9205|GT-N7\d{3}|SM-N9005)[^;/]*)\/?[^;/]* Build/'
3690
3788
  device_replacement: 'Samsung $1$2'
3691
3789
  brand_replacement: 'Samsung'
3692
3790
  model_replacement: '$2'
3693
- - regex: '; *(Google )?(Nexus [Ss](?: 4G)?) Build/'
3791
+ - regex: '; *(Google |)(Nexus [Ss](?: 4G|)) Build/'
3694
3792
  device_replacement: 'Samsung $1$2'
3695
3793
  brand_replacement: 'Samsung'
3696
3794
  model_replacement: '$2'
@@ -3698,15 +3796,15 @@ device_parsers:
3698
3796
  device_replacement: 'Samsung $2'
3699
3797
  brand_replacement: 'Samsung'
3700
3798
  model_replacement: '$2'
3701
- - regex: '; *(Galaxy(?: Ace| Nexus| S ?II+|Nexus S| with MCR 1.2| Mini Plus 4G)?) Build/'
3799
+ - regex: '; *(Galaxy(?: Ace| Nexus| S ?II+|Nexus S| with MCR 1.2| Mini Plus 4G|)) Build/'
3702
3800
  device_replacement: 'Samsung $1'
3703
3801
  brand_replacement: 'Samsung'
3704
3802
  model_replacement: '$1'
3705
- - regex: '; *(SAMSUNG[ _\-] *)+([^;/]+) Build'
3803
+ - regex: '; *(SAMSUNG[ _\-]|)(?:SAMSUNG[ _\-])([^;/]+) Build'
3706
3804
  device_replacement: 'Samsung $2'
3707
3805
  brand_replacement: 'Samsung'
3708
3806
  model_replacement: '$2'
3709
- - regex: '; *(SAMSUNG-)?(GT\-[BINPS]\d{4}[^\/]*)(\/[^ ]*) Build'
3807
+ - regex: '; *(SAMSUNG-|)(GT\-[BINPS]\d{4}[^\/]*)(\/[^ ]*) Build'
3710
3808
  device_replacement: 'Samsung $1$2$3'
3711
3809
  brand_replacement: 'Samsung'
3712
3810
  model_replacement: '$2'
@@ -3718,11 +3816,15 @@ device_parsers:
3718
3816
  device_replacement: 'Samsung $1$2'
3719
3817
  brand_replacement: 'Samsung'
3720
3818
  model_replacement: '$2'
3721
- - regex: '; *((?:SCH|SGH|SHV|SHW|SPH|SC|SM)\-[A-Za-z0-9 ]+)(/?[^ ]*)? Build'
3819
+ - regex: '; *((?:SCH|SGH|SHV|SHW|SPH|SC|SM)\-[A-Za-z0-9 ]+)(/?[^ ]*|) Build'
3820
+ device_replacement: 'Samsung $1'
3821
+ brand_replacement: 'Samsung'
3822
+ model_replacement: '$1'
3823
+ - regex: '; *((?:SC)\-[A-Za-z0-9 ]+)(/?[^ ]*|)\)'
3722
3824
  device_replacement: 'Samsung $1'
3723
3825
  brand_replacement: 'Samsung'
3724
3826
  model_replacement: '$1'
3725
- - regex: ' ((?:SCH)\-[A-Za-z0-9 ]+)(/?[^ ]*)? Build'
3827
+ - regex: ' ((?:SCH)\-[A-Za-z0-9 ]+)(/?[^ ]*|) Build'
3726
3828
  device_replacement: 'Samsung $1'
3727
3829
  brand_replacement: 'Samsung'
3728
3830
  model_replacement: '$1'
@@ -3730,6 +3832,10 @@ device_parsers:
3730
3832
  device_replacement: 'Samsung $1'
3731
3833
  brand_replacement: 'Samsung'
3732
3834
  model_replacement: '$1'
3835
+ - regex: '; *((?:SCH|SGH|SHV|SHW|SPH|SC|SM)\-[A-Za-z0-9]{5,6})[\)]'
3836
+ device_replacement: 'Samsung $1'
3837
+ brand_replacement: 'Samsung'
3838
+ model_replacement: '$1'
3733
3839
 
3734
3840
  #########
3735
3841
  # Sharp
@@ -3859,7 +3965,7 @@ device_parsers:
3859
3965
  device_replacement: '$1$2'
3860
3966
  brand_replacement: 'SonyEricsson'
3861
3967
  model_replacement: '$2'
3862
- - regex: '; *((?:SK|ST|E|X|LT|MK|MT|WT)\d{2}[a-z0-9]*(?:-o)?|R800i|U20i) Build'
3968
+ - regex: '; *((?:SK|ST|E|X|LT|MK|MT|WT)\d{2}[a-z0-9]*(?:-o|)|R800i|U20i) Build'
3863
3969
  device_replacement: '$1'
3864
3970
  brand_replacement: 'SonyEricsson'
3865
3971
  model_replacement: '$1'
@@ -3923,7 +4029,7 @@ device_parsers:
3923
4029
  # Spice
3924
4030
  # @ref: http://www.spicemobilephones.co.in/
3925
4031
  #########
3926
- - regex: '; *((?:CSL_Spice|Spice|SPICE|CSL)[ _\-]?)?([Mm][Ii])([ _\-])?(\d{3}[^;/]*) Build/'
4032
+ - regex: '; *((?:CSL_Spice|Spice|SPICE|CSL)[ _\-]?|)([Mm][Ii])([ _\-]|)(\d{3}[^;/]*) Build/'
3927
4033
  device_replacement: '$1$2$3$4'
3928
4034
  brand_replacement: 'Spice'
3929
4035
  model_replacement: 'Mi$4'
@@ -4062,7 +4168,7 @@ device_parsers:
4062
4168
  device_replacement: '$1'
4063
4169
  brand_replacement: 'HTC'
4064
4170
  model_replacement: 'Dream'
4065
- - regex: '\b(T-Mobile ?)?(myTouch)[ _]?([34]G)[ _]?([^\/]*) (?:Mozilla|Build)'
4171
+ - regex: '\b(T-Mobile ?|)(myTouch)[ _]?([34]G)[ _]?([^\/]*) (?:Mozilla|Build)'
4066
4172
  device_replacement: '$1$2 $3 $4'
4067
4173
  brand_replacement: 'HTC'
4068
4174
  model_replacement: '$2 $3 $4'
@@ -4107,7 +4213,7 @@ device_parsers:
4107
4213
  device_replacement: '$1'
4108
4214
  brand_replacement: 'Toshiba'
4109
4215
  model_replacement: 'Folio 100'
4110
- - regex: '; *(AT[0-9]{2,3}(?:\-A|LE\-A|PE\-A|SE|a)?|AT7-A|AT1S0|Hikari-iFrame/WDPF-[^;/]+|THRiVE|Thrive) Build/'
4216
+ - regex: '; *(AT[0-9]{2,3}(?:\-A|LE\-A|PE\-A|SE|a|)|AT7-A|AT1S0|Hikari-iFrame/WDPF-[^;/]+|THRiVE|Thrive) Build/'
4111
4217
  device_replacement: 'Toshiba $1'
4112
4218
  brand_replacement: 'Toshiba'
4113
4219
  model_replacement: '$1'
@@ -4227,7 +4333,7 @@ device_parsers:
4227
4333
  # Walton
4228
4334
  # @ref: http://www.waltonbd.com/
4229
4335
  #########
4230
- - regex: '; *(?:Walton[ _\-])?(Primo[ _\-][^;/]+) Build'
4336
+ - regex: '; *(?:Walton[ _\-]|)(Primo[ _\-][^;/]+) Build'
4231
4337
  regex_flag: 'i'
4232
4338
  device_replacement: 'Walton $1'
4233
4339
  brand_replacement: 'Walton'
@@ -4237,7 +4343,7 @@ device_parsers:
4237
4343
  # Wiko
4238
4344
  # @ref: http://fr.wikomobile.com/collection.php?s=Smartphones
4239
4345
  #########
4240
- - regex: '; *(?:WIKO[ \-])?(CINK\+?|BARRY|BLOOM|DARKFULL|DARKMOON|DARKNIGHT|DARKSIDE|FIZZ|HIGHWAY|IGGY|OZZY|RAINBOW|STAIRWAY|SUBLIM|WAX|CINK [^;/]+) Build/'
4346
+ - regex: '; *(?:WIKO[ \-]|)(CINK\+?|BARRY|BLOOM|DARKFULL|DARKMOON|DARKNIGHT|DARKSIDE|FIZZ|HIGHWAY|IGGY|OZZY|RAINBOW|STAIRWAY|SUBLIM|WAX|CINK [^;/]+) Build/'
4241
4347
  regex_flag: 'i'
4242
4348
  device_replacement: 'Wiko $1'
4243
4349
  brand_replacement: 'Wiko'
@@ -4283,7 +4389,7 @@ device_parsers:
4283
4389
  # Yarvik Zania
4284
4390
  # @ref: http://yarvik.com
4285
4391
  #########
4286
- - 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/'
4392
+ - 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/'
4287
4393
  device_replacement: 'Yarvik $1'
4288
4394
  brand_replacement: 'Yarvik'
4289
4395
  model_replacement: '$1'
@@ -4306,7 +4412,19 @@ device_parsers:
4306
4412
  # XiaoMi
4307
4413
  # @ref: http://www.xiaomi.com/event/buyphone
4308
4414
  #########
4309
- - regex: '; *((Mi|MI|HM|MI-ONE|Redmi)[ -](NOTE |Note )?[^;/]*) (Build|MIUI)/'
4415
+ - regex: '; *((Mi|MI|HM|MI-ONE|Redmi)[ -](NOTE |Note |)[^;/]*) (Build|MIUI)/'
4416
+ device_replacement: 'XiaoMi $1'
4417
+ brand_replacement: 'XiaoMi'
4418
+ model_replacement: '$1'
4419
+ - regex: '; *((Mi|MI|HM|MI-ONE|Redmi)[ -](NOTE |Note |)[^;/\)]*)'
4420
+ device_replacement: 'XiaoMi $1'
4421
+ brand_replacement: 'XiaoMi'
4422
+ model_replacement: '$1'
4423
+ - regex: '; *(MIX) (Build|MIUI)/'
4424
+ device_replacement: 'XiaoMi $1'
4425
+ brand_replacement: 'XiaoMi'
4426
+ model_replacement: '$1'
4427
+ - regex: '; *((MIX) ([^;/]*)) (Build|MIUI)/'
4310
4428
  device_replacement: 'XiaoMi $1'
4311
4429
  brand_replacement: 'XiaoMi'
4312
4430
  model_replacement: '$1'
@@ -4472,7 +4590,7 @@ device_parsers:
4472
4590
  device_replacement: 'Kindle'
4473
4591
  brand_replacement: 'Amazon'
4474
4592
  model_replacement: 'Kindle'
4475
- - regex: '; ?(Silk)/(\d+)\.(\d+)(?:\.([0-9\-]+))? Build\b'
4593
+ - regex: '; ?(Silk)/(\d+)\.(\d+)(?:\.([0-9\-]+)|) Build\b'
4476
4594
  device_replacement: 'Kindle Fire'
4477
4595
  brand_replacement: 'Amazon'
4478
4596
  model_replacement: 'Kindle Fire$2'
@@ -4524,7 +4642,7 @@ device_parsers:
4524
4642
  #########
4525
4643
  # Alcatel Windows Phones
4526
4644
  #########
4527
- - regex: 'Windows Phone [^;]+; .*?IEMobile/[^;\)]+[;\)] ?(?:ARM; ?Touch; ?|Touch; ?)?(?:ALCATEL)[^;]*; *([^;,\)]+)'
4645
+ - regex: 'Windows Phone [^;]+; .*?IEMobile/[^;\)]+[;\)] ?(?:ARM; ?Touch; ?|Touch; ?|)(?:ALCATEL)[^;]*; *([^;,\)]+)'
4528
4646
  device_replacement: 'Alcatel $1'
4529
4647
  brand_replacement: 'Alcatel'
4530
4648
  model_replacement: '$1'
@@ -4532,8 +4650,8 @@ device_parsers:
4532
4650
  #########
4533
4651
  # Asus Windows Phones
4534
4652
  #########
4535
- #~ - regex: 'Windows Phone [^;]+; .*?IEMobile/[^;\)]+[;\)] ?(?:ARM; ?Touch; ?|Touch; ?|WpsLondonTest; ?)?(?:ASUS|Asus)[^;]*; *([^;,\)]+)'
4536
- - regex: 'Windows Phone [^;]+; .*?IEMobile/[^;\)]+[;\)] ?(?:ARM; ?Touch; ?|Touch; ?|WpsLondonTest; ?)?(?:ASUS|Asus)[^;]*; *([^;,\)]+)'
4653
+ #~ - regex: 'Windows Phone [^;]+; .*?IEMobile/[^;\)]+[;\)] ?(?:ARM; ?Touch; ?|Touch; ?|WpsLondonTest; ?|)(?:ASUS|Asus)[^;]*; *([^;,\)]+)'
4654
+ - regex: 'Windows Phone [^;]+; .*?IEMobile/[^;\)]+[;\)] ?(?:ARM; ?Touch; ?|Touch; ?|WpsLondonTest; ?|)(?:ASUS|Asus)[^;]*; *([^;,\)]+)'
4537
4655
  device_replacement: 'Asus $1'
4538
4656
  brand_replacement: 'Asus'
4539
4657
  model_replacement: '$1'
@@ -4541,7 +4659,7 @@ device_parsers:
4541
4659
  #########
4542
4660
  # Dell Windows Phones
4543
4661
  #########
4544
- - regex: 'Windows Phone [^;]+; .*?IEMobile/[^;\)]+[;\)] ?(?:ARM; ?Touch; ?|Touch; ?)?(?:DELL|Dell)[^;]*; *([^;,\)]+)'
4662
+ - regex: 'Windows Phone [^;]+; .*?IEMobile/[^;\)]+[;\)] ?(?:ARM; ?Touch; ?|Touch; ?|)(?:DELL|Dell)[^;]*; *([^;,\)]+)'
4545
4663
  device_replacement: 'Dell $1'
4546
4664
  brand_replacement: 'Dell'
4547
4665
  model_replacement: '$1'
@@ -4549,7 +4667,7 @@ device_parsers:
4549
4667
  #########
4550
4668
  # HTC Windows Phones
4551
4669
  #########
4552
- - regex: 'Windows Phone [^;]+; .*?IEMobile/[^;\)]+[;\)] ?(?:ARM; ?Touch; ?|Touch; ?|WpsLondonTest; ?)?(?:HTC|Htc|HTC_blocked[^;]*)[^;]*; *(?:HTC)?([^;,\)]+)'
4670
+ - regex: 'Windows Phone [^;]+; .*?IEMobile/[^;\)]+[;\)] ?(?:ARM; ?Touch; ?|Touch; ?|WpsLondonTest; ?|)(?:HTC|Htc|HTC_blocked[^;]*)[^;]*; *(?:HTC|)([^;,\)]+)'
4553
4671
  device_replacement: 'HTC $1'
4554
4672
  brand_replacement: 'HTC'
4555
4673
  model_replacement: '$1'
@@ -4557,7 +4675,7 @@ device_parsers:
4557
4675
  #########
4558
4676
  # Huawei Windows Phones
4559
4677
  #########
4560
- - regex: 'Windows Phone [^;]+; .*?IEMobile/[^;\)]+[;\)] ?(?:ARM; ?Touch; ?|Touch; ?)?(?:HUAWEI)[^;]*; *(?:HUAWEI )?([^;,\)]+)'
4678
+ - regex: 'Windows Phone [^;]+; .*?IEMobile/[^;\)]+[;\)] ?(?:ARM; ?Touch; ?|Touch; ?|)(?:HUAWEI)[^;]*; *(?:HUAWEI |)([^;,\)]+)'
4561
4679
  device_replacement: 'Huawei $1'
4562
4680
  brand_replacement: 'Huawei'
4563
4681
  model_replacement: '$1'
@@ -4565,7 +4683,7 @@ device_parsers:
4565
4683
  #########
4566
4684
  # LG Windows Phones
4567
4685
  #########
4568
- - regex: 'Windows Phone [^;]+; .*?IEMobile/[^;\)]+[;\)] ?(?:ARM; ?Touch; ?|Touch; ?)?(?:LG|Lg)[^;]*; *(?:LG[ \-])?([^;,\)]+)'
4686
+ - regex: 'Windows Phone [^;]+; .*?IEMobile/[^;\)]+[;\)] ?(?:ARM; ?Touch; ?|Touch; ?|)(?:LG|Lg)[^;]*; *(?:LG[ \-]|)([^;,\)]+)'
4569
4687
  device_replacement: 'LG $1'
4570
4688
  brand_replacement: 'LG'
4571
4689
  model_replacement: '$1'
@@ -4573,15 +4691,15 @@ device_parsers:
4573
4691
  #########
4574
4692
  # Noka Windows Phones
4575
4693
  #########
4576
- - regex: 'Windows Phone [^;]+; .*?IEMobile/[^;\)]+[;\)] ?(?:ARM; ?Touch; ?|Touch; ?)?(?:rv:11; )?(?:NOKIA|Nokia)[^;]*; *(?:NOKIA ?|Nokia ?|LUMIA ?|[Ll]umia ?)*(\d{3,}[^;\)]*)'
4694
+ - regex: 'Windows Phone [^;]+; .*?IEMobile/[^;\)]+[;\)] ?(?:ARM; ?Touch; ?|Touch; ?|)(?:rv:11; |)(?:NOKIA|Nokia)[^;]*; *(?:NOKIA ?|Nokia ?|LUMIA ?|[Ll]umia ?|)(\d{3,10}[^;\)]*)'
4577
4695
  device_replacement: 'Lumia $1'
4578
4696
  brand_replacement: 'Nokia'
4579
4697
  model_replacement: 'Lumia $1'
4580
- - regex: 'Windows Phone [^;]+; .*?IEMobile/[^;\)]+[;\)] ?(?:ARM; ?Touch; ?|Touch; ?)?(?:NOKIA|Nokia)[^;]*; *(RM-\d{3,})'
4698
+ - regex: 'Windows Phone [^;]+; .*?IEMobile/[^;\)]+[;\)] ?(?:ARM; ?Touch; ?|Touch; ?|)(?:NOKIA|Nokia)[^;]*; *(RM-\d{3,})'
4581
4699
  device_replacement: 'Nokia $1'
4582
4700
  brand_replacement: 'Nokia'
4583
4701
  model_replacement: '$1'
4584
- - regex: '(?:Windows Phone [^;]+; .*?IEMobile/[^;\)]+[;\)]|WPDesktop;) ?(?:ARM; ?Touch; ?|Touch; ?)?(?:NOKIA|Nokia)[^;]*; *(?:NOKIA ?|Nokia ?|LUMIA ?|[Ll]umia ?)*([^;\)]+)'
4702
+ - regex: '(?:Windows Phone [^;]+; .*?IEMobile/[^;\)]+[;\)]|WPDesktop;) ?(?:ARM; ?Touch; ?|Touch; ?|)(?:NOKIA|Nokia)[^;]*; *(?:NOKIA ?|Nokia ?|LUMIA ?|[Ll]umia ?|)([^;\)]+)'
4585
4703
  device_replacement: 'Nokia $1'
4586
4704
  brand_replacement: 'Nokia'
4587
4705
  model_replacement: '$1'
@@ -4589,7 +4707,7 @@ device_parsers:
4589
4707
  #########
4590
4708
  # Microsoft Windows Phones
4591
4709
  #########
4592
- - regex: 'Windows Phone [^;]+; .*?IEMobile/[^;\)]+[;\)] ?(?:ARM; ?Touch; ?|Touch; ?)?(?:Microsoft(?: Corporation)?)[^;]*; *([^;,\)]+)'
4710
+ - regex: 'Windows Phone [^;]+; .*?IEMobile/[^;\)]+[;\)] ?(?:ARM; ?Touch; ?|Touch; ?|)(?:Microsoft(?: Corporation|))[^;]*; *([^;,\)]+)'
4593
4711
  device_replacement: 'Microsoft $1'
4594
4712
  brand_replacement: 'Microsoft'
4595
4713
  model_replacement: '$1'
@@ -4597,7 +4715,7 @@ device_parsers:
4597
4715
  #########
4598
4716
  # Samsung Windows Phones
4599
4717
  #########
4600
- - regex: 'Windows Phone [^;]+; .*?IEMobile/[^;\)]+[;\)] ?(?:ARM; ?Touch; ?|Touch; ?|WpsLondonTest; ?)?(?:SAMSUNG)[^;]*; *(?:SAMSUNG )?([^;,\.\)]+)'
4718
+ - regex: 'Windows Phone [^;]+; .*?IEMobile/[^;\)]+[;\)] ?(?:ARM; ?Touch; ?|Touch; ?|WpsLondonTest; ?|)(?:SAMSUNG)[^;]*; *(?:SAMSUNG |)([^;,\.\)]+)'
4601
4719
  device_replacement: 'Samsung $1'
4602
4720
  brand_replacement: 'Samsung'
4603
4721
  model_replacement: '$1'
@@ -4605,7 +4723,7 @@ device_parsers:
4605
4723
  #########
4606
4724
  # Toshiba Windows Phones
4607
4725
  #########
4608
- - regex: 'Windows Phone [^;]+; .*?IEMobile/[^;\)]+[;\)] ?(?:ARM; ?Touch; ?|Touch; ?|WpsLondonTest; ?)?(?:TOSHIBA|FujitsuToshibaMobileCommun)[^;]*; *([^;,\)]+)'
4726
+ - regex: 'Windows Phone [^;]+; .*?IEMobile/[^;\)]+[;\)] ?(?:ARM; ?Touch; ?|Touch; ?|WpsLondonTest; ?|)(?:TOSHIBA|FujitsuToshibaMobileCommun)[^;]*; *([^;,\)]+)'
4609
4727
  device_replacement: 'Toshiba $1'
4610
4728
  brand_replacement: 'Toshiba'
4611
4729
  model_replacement: '$1'
@@ -4613,7 +4731,7 @@ device_parsers:
4613
4731
  #########
4614
4732
  # Generic Windows Phones
4615
4733
  #########
4616
- - regex: 'Windows Phone [^;]+; .*?IEMobile/[^;\)]+[;\)] ?(?:ARM; ?Touch; ?|Touch; ?|WpsLondonTest; ?)?([^;]+); *([^;,\)]+)'
4734
+ - regex: 'Windows Phone [^;]+; .*?IEMobile/[^;\)]+[;\)] ?(?:ARM; ?Touch; ?|Touch; ?|WpsLondonTest; ?|)([^;]+); *([^;,\)]+)'
4617
4735
  device_replacement: '$1 $2'
4618
4736
  brand_replacement: '$1'
4619
4737
  model_replacement: '$2'
@@ -4633,7 +4751,7 @@ device_parsers:
4633
4751
  #########
4634
4752
  # Firefox OS
4635
4753
  #########
4636
- - regex: '\(Mobile; ALCATEL ?(One|ONE) ?(Touch|TOUCH) ?([^;/]+)(?:/[^;]+)?; rv:[^\)]+\) Gecko/[^\/]+ Firefox/'
4754
+ - regex: '\(Mobile; ALCATEL ?(One|ONE) ?(Touch|TOUCH) ?([^;/]+)(?:/[^;]+|); rv:[^\)]+\) Gecko/[^\/]+ Firefox/'
4637
4755
  device_replacement: 'Alcatel $1 $2 $3'
4638
4756
  brand_replacement: 'Alcatel'
4639
4757
  model_replacement: 'One Touch $3'
@@ -4664,7 +4782,7 @@ device_parsers:
4664
4782
  brand_replacement: '$1'
4665
4783
  model_replacement: '$2'
4666
4784
  # Nokia Symbian
4667
- - regex: '\(Symbian(?:/3)?; U; ([^;]+);'
4785
+ - regex: '\(Symbian(?:/3|); U; ([^;]+);'
4668
4786
  device_replacement: 'Nokia $1'
4669
4787
  brand_replacement: 'Nokia'
4670
4788
  model_replacement: '$1'
@@ -4709,7 +4827,7 @@ device_parsers:
4709
4827
  device_replacement: 'Palm Treo $1'
4710
4828
  brand_replacement: 'Palm'
4711
4829
  model_replacement: 'Treo $1'
4712
- - regex: 'webOS.*(P160U(?:NA)?)/(\d+).(\d+)'
4830
+ - regex: 'webOS.*(P160U(?:NA|))/(\d+).(\d+)'
4713
4831
  device_replacement: 'HP Veer'
4714
4832
  brand_replacement: 'HP'
4715
4833
  model_replacement: 'Veer'
@@ -4768,6 +4886,10 @@ device_parsers:
4768
4886
  device_replacement: '$1'
4769
4887
  brand_replacement: 'Apple'
4770
4888
  model_replacement: '$1'
4889
+ - regex: '(Watch)(\d+,\d+)'
4890
+ device_replacement: 'Apple $1'
4891
+ brand_replacement: 'Apple'
4892
+ model_replacement: 'Apple $1 $2'
4771
4893
  - regex: '(Apple Watch)(?:;| Simulator;)'
4772
4894
  device_replacement: '$1'
4773
4895
  brand_replacement: 'Apple'
@@ -4836,7 +4958,11 @@ device_parsers:
4836
4958
  device_replacement: 'Asus $1'
4837
4959
  brand_replacement: 'Asus'
4838
4960
  model_replacement: '$1'
4839
- - regex: '(?:asus.*?ASUS|Asus|ASUS|asus)[\- ;]*((?:Transformer (?:Pad|Prime) |Transformer |Padfone |Nexus[ _])?[A-Za-z0-9]+)'
4961
+ - regex: '(?:asus.*?ASUS|Asus|ASUS|asus)[\- ;]*((?:Transformer (?:Pad|Prime) |Transformer |Padfone |Nexus[ _]|)[A-Za-z0-9]+)'
4962
+ device_replacement: 'Asus $1'
4963
+ brand_replacement: 'Asus'
4964
+ model_replacement: '$1'
4965
+ - regex: '(?:ASUS)_([A-Za-z0-9\-]+)'
4840
4966
  device_replacement: 'Asus $1'
4841
4967
  brand_replacement: 'Asus'
4842
4968
  model_replacement: '$1'
@@ -4877,7 +5003,7 @@ device_parsers:
4877
5003
  ##########
4878
5004
  # htc
4879
5005
  ##########
4880
- - regex: '\b(?:HTC/|HTC/[a-z0-9]+/)?HTC[ _\-;]? *(.*?)(?:-?Mozilla|fingerPrint|[;/\(\)]|$)'
5006
+ - regex: '\b(?:HTC/|HTC/[a-z0-9]+/|)HTC[ _\-;]? *(.*?)(?:-?Mozilla|fingerPrint|[;/\(\)]|$)'
4881
5007
  device_replacement: 'HTC $1'
4882
5008
  brand_replacement: 'HTC'
4883
5009
  model_replacement: '$1'
@@ -4893,6 +5019,10 @@ device_parsers:
4893
5019
  device_replacement: 'Huawei $1'
4894
5020
  brand_replacement: 'Huawei'
4895
5021
  model_replacement: '$1'
5022
+ - regex: 'HUAWEI ([A-Za-z0-9\-]+)'
5023
+ device_replacement: 'Huawei $1'
5024
+ brand_replacement: 'Huawei'
5025
+ model_replacement: '$1'
4896
5026
  - regex: 'vodafone([A-Za-z0-9]+)'
4897
5027
  device_replacement: 'Huawei Vodafone $1'
4898
5028
  brand_replacement: 'Huawei'
@@ -4934,11 +5064,11 @@ device_parsers:
4934
5064
  device_replacement: '$1'
4935
5065
  brand_replacement: '$2'
4936
5066
  model_replacement: '$3'
4937
- - regex: '(HbbTV)/1\.1\.1.*CE-HTML/1\.\d;(Vendor/)*(THOM[^;]*?)[;\s](?:.*SW-Version/.*)*(LF[^;]+);?'
5067
+ - regex: '(HbbTV)/1\.1\.1.*CE-HTML/1\.\d;(Vendor/|)(THOM[^;]*?)[;\s].{0,30}(LF[^;]+);?'
4938
5068
  device_replacement: '$1'
4939
5069
  brand_replacement: 'Thomson'
4940
5070
  model_replacement: '$4'
4941
- - regex: '(HbbTV)(?:/1\.1\.1)?(?: ?\(;;;;;\))?; *CE-HTML(?:/1\.\d)?; *([^ ]+) ([^;]+);'
5071
+ - regex: '(HbbTV)(?:/1\.1\.1|) ?(?: \(;;;;;\)|); *CE-HTML(?:/1\.\d|); *([^ ]+) ([^;]+);'
4942
5072
  device_replacement: '$1'
4943
5073
  brand_replacement: '$2'
4944
5074
  model_replacement: '$3'
@@ -4955,7 +5085,7 @@ device_parsers:
4955
5085
  ##########
4956
5086
  # LGE NetCast TV
4957
5087
  ##########
4958
- - regex: 'LGE; (?:Media\/)?([^;]*);[^;]*;[^;]*;?\); "?LG NetCast(\.TV|\.Media)?-\d+'
5088
+ - regex: 'LGE; (?:Media\/|)([^;]*);[^;]*;[^;]*;?\); "?LG NetCast(\.TV|\.Media|)-\d+'
4959
5089
  device_replacement: 'NetCast$2'
4960
5090
  brand_replacement: 'LG'
4961
5091
  model_replacement: '$1'
@@ -4984,7 +5114,7 @@ device_parsers:
4984
5114
  brand_replacement: '$1'
4985
5115
  model_replacement: '$2'
4986
5116
  # other LG phones
4987
- - regex: '\b(?:LGE[ \-]LG\-(?:AX)?|LGE |LGE?-LG|LGE?[ \-]|LG[ /\-]|lg[\-])([A-Za-z0-9]+)\b'
5117
+ - regex: '\b(?:LGE[ \-]LG\-(?:AX|)|LGE |LGE?-LG|LGE?[ \-]|LG[ /\-]|lg[\-])([A-Za-z0-9]+)\b'
4988
5118
  device_replacement: 'LG $1'
4989
5119
  brand_replacement: 'LG'
4990
5120
  model_replacement: '$1'
@@ -5129,7 +5259,7 @@ device_parsers:
5129
5259
  device_replacement: '$2 $1'
5130
5260
  brand_replacement: '$2'
5131
5261
  model_replacement: '$1'
5132
- - regex: '(Sony)(?:BDP\/|\/)?([^ /;\)]+)[ /;\)]'
5262
+ - regex: '(Sony)(?:BDP\/|\/|)([^ /;\)]+)[ /;\)]'
5133
5263
  device_replacement: '$1 $2'
5134
5264
  brand_replacement: '$1'
5135
5265
  model_replacement: '$2'
@@ -5159,27 +5289,27 @@ device_parsers:
5159
5289
  #########
5160
5290
  # Android General Device Matching (far from perfect)
5161
5291
  #########
5162
- - regex: 'Android[\- ][\d]+\.[\d]+; [A-Za-z]{2}\-[A-Za-z]{0,2}; WOWMobile (.+) Build[/ ]'
5292
+ - regex: 'Android[\- ][\d]+\.[\d]+; [A-Za-z]{2}\-[A-Za-z]{0,2}; WOWMobile (.+)( Build[/ ]|\))'
5163
5293
  brand_replacement: 'Generic_Android'
5164
5294
  model_replacement: '$1'
5165
- - regex: 'Android[\- ][\d]+\.[\d]+\-update1; [A-Za-z]{2}\-[A-Za-z]{0,2} *; *(.+?) Build[/ ]'
5295
+ - regex: 'Android[\- ][\d]+\.[\d]+\-update1; [A-Za-z]{2}\-[A-Za-z]{0,2} *; *(.+?)( Build[/ ]|\))'
5166
5296
  brand_replacement: 'Generic_Android'
5167
5297
  model_replacement: '$1'
5168
- - regex: 'Android[\- ][\d]+(?:\.[\d]+){1,2}; *[A-Za-z]{2}[_\-][A-Za-z]{0,2}\-? *; *(.+?) Build[/ ]'
5298
+ - regex: 'Android[\- ][\d]+(?:\.[\d]+)(?:\.[\d]+|); *[A-Za-z]{2}[_\-][A-Za-z]{0,2}\-? *; *(.+?)( Build[/ ]|\))'
5169
5299
  brand_replacement: 'Generic_Android'
5170
5300
  model_replacement: '$1'
5171
- - regex: 'Android[\- ][\d]+(?:\.[\d]+){1,2}; *[A-Za-z]{0,2}\- *; *(.+?) Build[/ ]'
5301
+ - regex: 'Android[\- ][\d]+(?:\.[\d]+)(?:\.[\d]+|); *[A-Za-z]{0,2}\- *; *(.+?)( Build[/ ]|\))'
5172
5302
  brand_replacement: 'Generic_Android'
5173
5303
  model_replacement: '$1'
5174
5304
  # No build info at all - "Build" follows locale immediately
5175
- - regex: 'Android[\- ][\d]+(?:\.[\d]+){1,2}; *[a-z]{0,2}[_\-]?[A-Za-z]{0,2};? Build[/ ]'
5305
+ - regex: 'Android[\- ][\d]+(?:\.[\d]+)(?:\.[\d]+|); *[a-z]{0,2}[_\-]?[A-Za-z]{0,2};?( Build[/ ]|\))'
5176
5306
  device_replacement: 'Generic Smartphone'
5177
5307
  brand_replacement: 'Generic'
5178
5308
  model_replacement: 'Smartphone'
5179
- - regex: 'Android[\- ][\d]+(?:\.[\d]+){1,2}; *\-?[A-Za-z]{2}; *(.+?) Build[/ ]'
5309
+ - regex: 'Android[\- ][\d]+(?:\.[\d]+)(?:\.[\d]+|); *\-?[A-Za-z]{2}; *(.+?)( Build[/ ]|\))'
5180
5310
  brand_replacement: 'Generic_Android'
5181
5311
  model_replacement: '$1'
5182
- - regex: 'Android[\- ][\d]+(?:\.[\d]+){1,2}(?:;.*)?; *(.+?) Build[/ ]'
5312
+ - regex: 'Android[\- ][\d]+(?:\.[\d]+)(?:\.[\d]+|)(?:;.*|); *(.+?)( Build[/ ]|\))'
5183
5313
  brand_replacement: 'Generic_Android'
5184
5314
  model_replacement: '$1'
5185
5315