[Date Prev][Date Next] [Thread Prev][Thread Next] [Date Index] [Thread Index]

Bug#925229: marked as done (unblock: uap-core/20190213-2)



Your message dated Thu, 21 Mar 2019 18:14:00 +0000
with message-id <e78b6403-3aff-45a9-1422-7e16d5622d54@thykier.net>
and subject line Re: Bug#925229: unblock: uap-core/20190213-2
has caused the Debian Bug report #925229,
regarding unblock: uap-core/20190213-2
to be marked as done.

This means that you claim that the problem has been dealt with.
If this is not the case it is now your responsibility to reopen the
Bug report if necessary, and/or fix the problem forthwith.

(NB: If you are a system administrator and have no idea what this
message is talking about, this may indicate a serious mail system
misconfiguration somewhere. Please contact owner@bugs.debian.org
immediately.)


-- 
925229: https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=925229
Debian Bug Tracking System
Contact owner@bugs.debian.org with problems
--- Begin Message ---
Package: release.debian.org
Severity: normal
User: release.debian.org@packages.debian.org
Usertags: unblock

Dear Release Team,

Please consider unblocking package uap-core

This is a new release that fixes a A Regular Expression Denial of
Service (ReDoS) bug: CVE-2018-20164.

https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=922717

I've attached the output from debdiff between the versions in testing
and unstable.

Thanks,

Edward Betts

unblock uap-core/20190213-2
diff -Nru uap-core-20181019/CONTRIBUTING.md uap-core-20190213/CONTRIBUTING.md
--- uap-core-20181019/CONTRIBUTING.md	2018-10-19 17:08:22.000000000 +0100
+++ uap-core-20190213/CONTRIBUTING.md	2019-02-13 17:27:26.000000000 +0000
@@ -10,9 +10,10 @@
 	* `tests/test_device.yaml`
 	* `tests/test_os.yaml`
 	* `tests/test_ua.yaml`
-5. Push your branch to GitHub and submit a pull request
-6. Monitor the pull request to make sure the Travis build succeeds. If it fails simply make the necessary changes to your branch and push it. Travis will re-test the changes.
+5. Check that your regex is not vulnerable to [ReDoS](https://www.owasp.org/index.php/Regular_expression_Denial_of_Service_-_ReDoS) using the test in `tests/regexes.js`
+6. Push your branch to GitHub and submit a pull request
+7. Monitor the pull request to make sure the Travis build succeeds. If it fails simply make the necessary changes to your branch and push it. Travis will re-test the changes.
 
 That's it. If you don't feel comfortable forking the project or modifying the YAML you can also [submit an issue](https://github.com/ua-parser/uap-core/issues) that includes the appropriate user agent string and the expected results of parsing.
 
-Thanks!
\ No newline at end of file
+Thanks!
diff -Nru uap-core-20181019/debian/changelog uap-core-20190213/debian/changelog
--- uap-core-20181019/debian/changelog	2018-11-08 17:24:23.000000000 +0000
+++ uap-core-20190213/debian/changelog	2019-03-20 17:14:03.000000000 +0000
@@ -1,3 +1,19 @@
+uap-core (20190213-2) unstable; urgency=high
+
+  * The previous release was mistakenly based on 20180219-1, meaning that
+    the changes in 20180503-1 and 20181019-1 were missing.
+  * Restore missing changes. Closes: #924969
+
+ -- Edward Betts <edward@4angle.com>  Wed, 20 Mar 2019 17:14:03 +0000
+
+uap-core (20190213-1) unstable; urgency=high
+
+  * New upstream release Closes: #922717
+    - CVE-2018-20164: Regular Expression Denial of Service
+  * debian/control: update Standards-Version
+
+ -- Edward Betts <edward@4angle.com>  Tue, 05 Mar 2019 12:29:24 +0000
+
 uap-core (20181019-1) unstable; urgency=medium
 
   * New upstream release
diff -Nru uap-core-20181019/debian/control uap-core-20190213/debian/control
--- uap-core-20181019/debian/control	2018-11-08 17:24:23.000000000 +0000
+++ uap-core-20190213/debian/control	2019-03-20 17:14:03.000000000 +0000
@@ -3,7 +3,7 @@
 Priority: optional
 Maintainer: Edward Betts <edward@4angle.com>
 Build-Depends: debhelper (>= 11)
-Standards-Version: 4.2.1
+Standards-Version: 4.3.0
 Homepage: https://github.com/ua-parser/uap-core
 
 Package: uap-core
diff -Nru uap-core-20181019/.gitignore uap-core-20190213/.gitignore
--- uap-core-20181019/.gitignore	2018-10-19 17:08:22.000000000 +0100
+++ uap-core-20190213/.gitignore	2019-02-13 17:27:26.000000000 +0000
@@ -1,3 +1,5 @@
 .DS_Store
 node_modules/
 package-lock.json
+*.tgz
+*.log
diff -Nru uap-core-20181019/.npmignore uap-core-20190213/.npmignore
--- uap-core-20181019/.npmignore	1970-01-01 01:00:00.000000000 +0100
+++ uap-core-20190213/.npmignore	2019-02-13 17:27:26.000000000 +0000
@@ -0,0 +1,8 @@
+node_modules/
+test_resources/
+tests/
+tmp/
+*.bak
+*.tgz
+*.log
+.*
diff -Nru uap-core-20181019/.npmrc uap-core-20190213/.npmrc
--- uap-core-20181019/.npmrc	1970-01-01 01:00:00.000000000 +0100
+++ uap-core-20190213/.npmrc	2019-02-13 17:27:26.000000000 +0000
@@ -0,0 +1 @@
+package-lock=false
diff -Nru uap-core-20181019/package.json uap-core-20190213/package.json
--- uap-core-20181019/package.json	2018-10-19 17:08:22.000000000 +0100
+++ uap-core-20190213/package.json	2019-02-13 17:27:26.000000000 +0000
@@ -1,7 +1,7 @@
 {
   "name": "uap-core",
   "description": "The regex file necessary to build language ports of Browserscope's user agent parser.",
-  "version": "0.5.0",
+  "version": "0.6.5",
   "maintainers": [
     {
       "name": "Tobie Langel",
@@ -25,11 +25,12 @@
     }
   ],
   "devDependencies": {
-    "yamlparser": ">=0.0.2",
     "mocha": "*",
-    "uap-ref-impl": "ua-parser/uap-ref-impl"
+    "safe-regex": "^2.0.1",
+    "uap-ref-impl": "git+https://github.com/ua-parser/uap-ref-impl#master";,
+    "yamlparser": ">=0.0.2"
   },
   "scripts": {
-    "test": "mocha -u tdd -R min ./tests/test.js"
+    "test": "mocha --opts ./tests/mocha.opts ./tests"
   }
 }
diff -Nru uap-core-20181019/README.md uap-core-20190213/README.md
--- uap-core-20181019/README.md	2018-10-19 17:08:22.000000000 +0100
+++ uap-core-20190213/README.md	2019-02-13 17:27:26.000000000 +0000
@@ -8,6 +8,7 @@
 Maintainers
 -----------
 
+* [Com Menthol](https://github.com/commenthol)
 * [Lindsey Simon](https://github.com/elsigh) ([@elsigh](https://twitter.com/elsigh))
 * [Tobie Langel](https://github.com/tobie) ([@tobie](https://twitter.com/tobie))
 
diff -Nru uap-core-20181019/regexes.yaml uap-core-20190213/regexes.yaml
--- uap-core-20181019/regexes.yaml	2018-10-19 17:08:22.000000000 +0100
+++ uap-core-20190213/regexes.yaml	2019-02-13 17:27:26.000000000 +0000
@@ -7,9 +7,9 @@
     family_replacement: 'AntennaPod'
   - regex: '(TopPodcasts)Pro/(\d+) CFNetwork'
   - regex: '(MusicDownloader)Lite/(\d+)\.(\d+)\.(\d+) CFNetwork'
-  - regex: '^(.*)-iPad/(\d+)\.?(\d+)?.?(\d+)?.?(\d+)? CFNetwork'
-  - regex: '^(.*)-iPhone/(\d+)\.?(\d+)?.?(\d+)?.?(\d+)? CFNetwork'
-  - regex: '^(.*)/(\d+)\.?(\d+)?.?(\d+)?.?(\d+)? CFNetwork'
+  - regex: '^(.*)-iPad\/(\d+)(?:\.(\d+)|)(?:\.(\d+)|)(?:\.(\d+)|) CFNetwork'
+  - regex: '^(.*)-iPhone/(\d+)(?:\.(\d+)|)(?:\.(\d+)|)(?:\.(\d+)|) CFNetwork'
+  - regex: '^(.*)/(\d+)(?:\.(\d+)|)(?:\.(\d+)|)(?:\.(\d+)|) CFNetwork'
 
   # Podcast catchers
   - regex: '(espn\.go)'
@@ -23,16 +23,23 @@
   - regex: ' (Rivo) RHYTHM'
 
   # @note: iOS / OSX Applications
-  - regex: '(CFNetwork)(?:/(\d+)\.(\d+)\.?(\d+)?)?'
+  - regex: '(CFNetwork)(?:/(\d+)\.(\d+)(?:\.(\d+)|)|)'
     family_replacement: 'CFNetwork'
 
   # Pingdom
-  - regex: '(Pingdom.com_bot_version_)(\d+)\.(\d+)'
+  - regex: '(Pingdom\.com_bot_version_)(\d+)\.(\d+)'
     family_replacement: 'PingdomBot'
   # 'Mozilla/5.0 (Unknown; Linux x86_64) AppleWebKit/534.34 (KHTML, like Gecko) PingdomTMS/0.8.5 Safari/534.34'
   - regex: '(PingdomTMS)/(\d+)\.(\d+)\.(\d+)'
     family_replacement: 'PingdomBot'
 
+  # PTST / WebPageTest.org crawlers
+  - regex: ' (PTST)/(\d+)\.(\d+)$'
+    family_replacement: 'WebPageTest.org bot'
+
+  # Datanyze.com spider
+  - regex: 'X11; (Datanyze); Linux'
+
   # New Relic Pinger
   - regex: '(NewRelicPinger)/(\d+)\.(\d+)'
     family_replacement: 'NewRelicPingerBot'
@@ -57,11 +64,11 @@
     family_replacement: 'GooglePlusBot'
 
   # Gmail
-  - regex: 'via ggpht.com GoogleImageProxy'
+  - regex: 'via ggpht\.com GoogleImageProxy'
     family_replacement: 'GmailImageProxy'
 
   # Yahoo
-  - regex: 'YahooMailProxy; https://help.yahoo.com/kb/yahoo-mail-proxy-SLN28749.html'
+  - regex: 'YahooMailProxy; https://help\.yahoo\.com/kb/yahoo-mail-proxy-SLN28749\.html'
     family_replacement: 'YahooMailProxy'
 
   # Twitter
@@ -69,37 +76,37 @@
     family_replacement: 'TwitterBot'
 
   # Bots Pattern '/name-0.0'
-  - regex: '/((?:Ant-)?Nutch|[A-z]+[Bb]ot|[A-z]+[Ss]pider|Axtaris|fetchurl|Isara|ShopSalad|Tailsweep)[ \-](\d+)(?:\.(\d+)(?:\.(\d+))?)?'
+  - regex: '/((?:Ant-|)Nutch|[A-z]+[Bb]ot|[A-z]+[Ss]pider|Axtaris|fetchurl|Isara|ShopSalad|Tailsweep)[ \-](\d+)(?:\.(\d+)|)(?:\.(\d+)|)'
   # Bots Pattern 'name/0.0'
-  - 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+))?)?'
+  - 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+)|)'
 
   # MSIECrawler
-  - regex: '(MSIE) (\d+)\.(\d+)([a-z]\d?)?;.* MSIECrawler'
+  - regex: '(MSIE) (\d+)\.(\d+)([a-z]\d|[a-z]|);.* MSIECrawler'
     family_replacement: 'MSIECrawler'
 
   # DAVdroid
-  - regex: '(DAVdroid)/(\d+)\.(\d+)(?:\.(\d+))?'
+  - regex: '(DAVdroid)/(\d+)\.(\d+)(?:\.(\d+)|)'
 
   # Downloader ...
-  - 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+))?)?)?'
+  - 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+)|)|)'
 
   # Pinterestbot
-  - regex: '(Pinterest(?:bot)?)/(\d+)(?:\.(\d+)(?:\.(\d+))?)?[;\s\(]+\+https://www.pinterest.com/bot.html'
+  - regex: '(Pinterest(?:bot|))/(\d+)(?:\.(\d+)|)(?:\.(\d+)|)[;\s(]+\+https://www.pinterest.com/bot.html'
     family_replacement: 'Pinterestbot'
 
   # Bots
-  - 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+))?)?)?'
+  - 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+)|)|)|)'
 
   # AWS S3 Clients
   # must come before "Bots General matcher" to catch "boto"/"boto3" before "bot"
-  - regex: '\b(Boto3?|JetS3t|aws-(?:cli|sdk-(?:cpp|go|java|nodejs|ruby2?))|s3fs)/(\d+)\.(\d+)(?:\.(\d+))?'
+  - regex: '\b(Boto3?|JetS3t|aws-(?:cli|sdk-(?:cpp|go|java|nodejs|ruby2?))|s3fs)/(\d+)\.(\d+)(?:\.(\d+)|)'
 
   # Bots General matcher 'name/0.0'
-  - 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+))?)?'
-  # Bots General matcher 'name 0.0'
-  - 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+))?)?'
-  # Bots containing spider|scrape|bot(but not CUBOT)|Crawl
-  - 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+))?)?)?'
+  - 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+)|)|)'
+  # Bots containing bot(but not CUBOT)
+  - regex: '((?:[A-Za-z][A-Za-z0-9 -]{0,50}|)[^C][^Uu][Bb]ot)\b(?:(?:[ /]| v)(\d+)(?:\.(\d+)|)(?:\.(\d+)|)|)'
+  # Bots containing spider|scrape|Crawl
+  - 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+)|)|)'
 
   # HbbTV standard defines what features the browser should understand.
   # but it's like targeting "HTML5 browsers", effective browser support depends on the model
@@ -107,21 +114,21 @@
   - regex: '(HbbTV)/(\d+)\.(\d+)\.(\d+) \('
 
   # must go before Firefox to catch Chimera/SeaMonkey/Camino/Waterfox
-  - regex: '(Chimera|SeaMonkey|Camino|Waterfox)/(\d+)\.(\d+)\.?([ab]?\d+[a-z]*)?'
+  - regex: '(Chimera|SeaMonkey|Camino|Waterfox)/(\d+)\.(\d+)\.?([ab]?\d+[a-z]*|)'
 
   # Social Networks
   # Facebook Messenger must go before Facebook
-  - regex: '\[(FBAN/MessengerForiOS|FB_IAB/MESSENGER);FBAV/(\d+)(?:\.(\d+)(?:\.(\d+))?)?'
+  - regex: '\[(FBAN/MessengerForiOS|FB_IAB/MESSENGER);FBAV/(\d+)(?:\.(\d+)(?:\.(\d+)|)|)'
     family_replacement: 'Facebook Messenger'
   # Facebook
-  - regex: '\[FB.*;(FBAV)/(\d+)(?:\.(\d+)(?:\.(\d+))?)?'
+  - regex: '\[FB.*;(FBAV)/(\d+)(?:\.(\d+)|)(?:\.(\d+)|)'
     family_replacement: 'Facebook'
   # Sometimes Facebook does not specify a version (FBAV)
   - regex: '\[FB.*;'
     family_replacement: 'Facebook'
   # Pinterest
   - regex: '\[(Pinterest)/[^\]]+\]'
-  - regex: '(Pinterest)(?: for Android(?: Tablet)?)?/(\d+)(?:\.(\d+)(?:\.(\d+))?)?'
+  - regex: '(Pinterest)(?: for Android(?: Tablet|)|)/(\d+)(?:\.(\d+)|)(?:\.(\d+)|)'
   # Instagram app
   - regex: 'Mozilla.*Mobile.*(Instagram).(\d+)\.(\d+)\.(\d+)'
   # Flipboard app
@@ -138,7 +145,7 @@
     family_replacement: 'Basilisk'
 
   # Pale Moon
-  - regex: '(PaleMoon)/(\d+)\.(\d+)\.?(\d+)?'
+  - regex: '(PaleMoon)/(\d+)\.(\d+)(?:\.(\d+)|)'
     family_replacement: 'Pale Moon'
 
   # Firefox
@@ -150,22 +157,22 @@
     family_replacement: 'Firefox Mobile'
   - regex: '(?:Mobile|Tablet);.*(Firefox)/(\d+)\.(\d+)'
     family_replacement: 'Firefox Mobile'
-  - regex: '(Namoroka|Shiretoko|Minefield)/(\d+)\.(\d+)\.(\d+(?:pre)?)'
+  - regex: '(Namoroka|Shiretoko|Minefield)/(\d+)\.(\d+)\.(\d+(?:pre|))'
     family_replacement: 'Firefox ($1)'
   - regex: '(Firefox)/(\d+)\.(\d+)(a\d+[a-z]*)'
     family_replacement: 'Firefox Alpha'
   - regex: '(Firefox)/(\d+)\.(\d+)(b\d+[a-z]*)'
     family_replacement: 'Firefox Beta'
-  - regex: '(Firefox)-(?:\d+\.\d+)?/(\d+)\.(\d+)(a\d+[a-z]*)'
+  - regex: '(Firefox)-(?:\d+\.\d+|)/(\d+)\.(\d+)(a\d+[a-z]*)'
     family_replacement: 'Firefox Alpha'
-  - regex: '(Firefox)-(?:\d+\.\d+)?/(\d+)\.(\d+)(b\d+[a-z]*)'
+  - regex: '(Firefox)-(?:\d+\.\d+|)/(\d+)\.(\d+)(b\d+[a-z]*)'
     family_replacement: 'Firefox Beta'
-  - regex: '(Namoroka|Shiretoko|Minefield)/(\d+)\.(\d+)([ab]\d+[a-z]*)?'
+  - regex: '(Namoroka|Shiretoko|Minefield)/(\d+)\.(\d+)([ab]\d+[a-z]*|)'
     family_replacement: 'Firefox ($1)'
   - regex: '(Firefox).*Tablet browser (\d+)\.(\d+)\.(\d+)'
     family_replacement: 'MicroB'
-  - regex: '(MozillaDeveloperPreview)/(\d+)\.(\d+)([ab]\d+[a-z]*)?'
-  - regex: '(FxiOS)/(\d+)\.(\d+)(\.(\d+))?(\.(\d+))?'
+  - regex: '(MozillaDeveloperPreview)/(\d+)\.(\d+)([ab]\d+[a-z]*|)'
+  - regex: '(FxiOS)/(\d+)\.(\d+)(\.(\d+)|)(\.(\d+)|)'
     family_replacement: 'Firefox iOS'
 
   # e.g.: Flock/2.0b2
@@ -181,7 +188,7 @@
   - regex: '(Navigator)/(\d+)\.(\d+)([ab]\d+)'
     family_replacement: 'Netscape'
 
-  - regex: '(Netscape6)/(\d+)\.(\d+)\.?([ab]?\d+)?'
+  - regex: '(Netscape6)/(\d+)\.(\d+)\.?([ab]?\d+|)'
     family_replacement: 'Netscape'
 
   - regex: '(MyIBrow)/(\d+)\.(\d+)'
@@ -194,8 +201,8 @@
 
   # Opera will stop at 9.80 and hide the real version in the Version string.
   # see: http://dev.opera.com/articles/view/opera-ua-string-changes/
-  - regex: '(Opera Tablet).*Version/(\d+)\.(\d+)(?:\.(\d+))?'
-  - regex: '(Opera Mini)(?:/att)?/?(\d+)?(?:\.(\d+))?(?:\.(\d+))?'
+  - regex: '(Opera Tablet).*Version/(\d+)\.(\d+)(?:\.(\d+)|)'
+  - regex: '(Opera Mini)(?:/att|)/?(\d+|)(?:\.(\d+)|)(?:\.(\d+)|)'
   - regex: '(Opera)/.+Opera Mobi.+Version/(\d+)\.(\d+)'
     family_replacement: 'Opera Mobile'
   - regex: '(Opera)/(\d+)\.(\d+).+Opera Mobi'
@@ -204,7 +211,7 @@
     family_replacement: 'Opera Mobile'
   - regex: 'Opera Mobi'
     family_replacement: 'Opera Mobile'
-  - regex: '(Opera)/9.80.*Version/(\d+)\.(\d+)(?:\.(\d+))?'
+  - regex: '(Opera)/9.80.*Version/(\d+)\.(\d+)(?:\.(\d+)|)'
 
   # Opera 14 for Android uses a WebKit render engine.
   - regex: '(?:Mobile Safari).*(OPR)/(\d+)\.(\d+)\.(\d+)'
@@ -227,7 +234,7 @@
     family_replacement: 'Opera Neon'
 
   # Palm WebOS looks a lot like Safari.
-  - regex: '(hpw|web)OS/(\d+)\.(\d+)(?:\.(\d+))?'
+  - regex: '(hpw|web)OS/(\d+)\.(\d+)(?:\.(\d+)|)'
     family_replacement: 'webOS Browser'
 
   # LuaKit has no version info.
@@ -243,20 +250,20 @@
   - regex: 'Gecko/\d+ (Lightning)/(\d+)\.(\d+)\.?((?:[ab]?\d+[a-z]*)|(?:\d*))'
 
   # Swiftfox
-  - regex: '(Firefox)/(\d+)\.(\d+)\.(\d+(?:pre)?) \(Swiftfox\)'
+  - regex: '(Firefox)/(\d+)\.(\d+)\.(\d+(?:pre|)) \(Swiftfox\)'
     family_replacement: 'Swiftfox'
-  - regex: '(Firefox)/(\d+)\.(\d+)([ab]\d+[a-z]*)? \(Swiftfox\)'
+  - regex: '(Firefox)/(\d+)\.(\d+)([ab]\d+[a-z]*|) \(Swiftfox\)'
     family_replacement: 'Swiftfox'
 
   # Rekonq
-  - regex: '(rekonq)/(\d+)\.(\d+)\.?(\d+)? Safari'
+  - regex: '(rekonq)/(\d+)\.(\d+)(?:\.(\d+)|) Safari'
     family_replacement: 'Rekonq'
   - regex: 'rekonq'
     family_replacement: 'Rekonq'
 
   # Conkeror lowercase/uppercase
   # http://conkeror.org/
-  - regex: '(conkeror|Conkeror)/(\d+)\.(\d+)\.?(\d+)?'
+  - regex: '(conkeror|Conkeror)/(\d+)\.(\d+)(?:\.(\d+)|)'
     family_replacement: 'Conkeror'
 
   # catches lower case konqueror
@@ -285,11 +292,11 @@
     family_replacement: 'NetFront NX'
 
   # Amazon Silk, should go before Safari and Chrome Mobile
-  - regex: '(Silk)/(\d+)\.(\d+)(?:\.([0-9\-]+))?'
+  - regex: '(Silk)/(\d+)\.(\d+)(?:\.([0-9\-]+)|)'
     family_replacement: 'Amazon Silk'
 
   # @ref: http://www.puffinbrowser.com
-  - regex: '(Puffin)/(\d+)\.(\d+)(?:\.(\d+))?'
+  - regex: '(Puffin)/(\d+)\.(\d+)(?:\.(\d+)|)'
 
   # Edge Mobile
   - regex: 'Windows Phone .*(Edge)/(\d+)\.(\d+)'
@@ -300,26 +307,43 @@
     family_replacement: 'Samsung Internet'
 
   # Seznam.cz browser (based on WebKit)
-  - regex: '(SznProhlizec)/(\d+)\.(\d+)(?:\.(\d+))?'
+  - regex: '(SznProhlizec)/(\d+)\.(\d+)(?:\.(\d+)|)'
     family_replacement: 'Seznam prohlížeč'
 
   # Coc Coc browser, based on Chrome (used in Vietnam)
-  - regex: '(coc_coc_browser)/(\d+)\.(\d+)(?:\.(\d+))?'
+  - regex: '(coc_coc_browser)/(\d+)\.(\d+)(?:\.(\d+)|)'
     family_replacement: 'Coc Coc'
 
   # Baidu Browsers (desktop spoofs chrome & IE, explorer is mobile)
-  - regex: '(baidubrowser)[/\s](\d+)(?:\.(\d+)(?:\.(\d+))?)?'
+  - regex: '(baidubrowser)[/\s](\d+)(?:\.(\d+)|)(?:\.(\d+)|)'
     family_replacement: 'Baidu Browser'
   - regex: '(FlyFlow)/(\d+)\.(\d+)'
     family_replacement: 'Baidu Explorer'
 
   # MxBrowser is Maxthon. Must go before Mobile Chrome for Android
-  - regex: '(MxBrowser)/(\d+)\.(\d+)(?:\.(\d+))?'
+  - regex: '(MxBrowser)/(\d+)\.(\d+)(?:\.(\d+)|)'
     family_replacement: 'Maxthon'
 
   # Crosswalk must go before Mobile Chrome for Android
   - regex: '(Crosswalk)/(\d+)\.(\d+)\.(\d+)\.(\d+)'
 
+  # LINE https://line.me/en/
+  # Must go before Mobile Chrome for Android
+  - regex: '(Line)/(\d+)\.(\d+)\.(\d+)'
+    family_replacement: 'LINE'
+
+  # MiuiBrowser should got before Mobile Chrome for Android
+  - regex: '(MiuiBrowser)/(\d+)\.(\d+)\.(\d+)'
+    family_replacement: 'MiuiBrowser'
+  
+  # Mint Browser should got before Mobile Chrome for Android
+  - regex: '(Mint Browser)/(\d+)\.(\d+)\.(\d+)'
+    family_replacement: 'Mint Browser'
+
+  # Google Search App on Android, eg:
+  - regex: 'Mozilla.+Android.+(GSA)/(\d+)\.(\d+)\.(\d+)'
+    family_replacement: 'Google'
+
   # Chrome Mobile
   - regex: 'Version/.+(Chrome)/(\d+)\.(\d+)\.(\d+)\.(\d+)'
     family_replacement: 'Chrome Mobile WebView'
@@ -347,11 +371,11 @@
     family_replacement: 'Sogou Explorer'
 
   # QQ Browsers
-  - regex: '(MQQBrowser/Mini)(?:(\d+)(?:\.(\d+)(?:\.(\d+))?)?)?'
+  - regex: '(MQQBrowser/Mini)(?:(\d+)(?:\.(\d+)|)(?:\.(\d+)|)|)'
     family_replacement: 'QQ Browser Mini'
-  - regex: '(MQQBrowser)(?:/(\d+)(?:\.(\d+)(?:\.(\d+))?)?)?'
+  - regex: '(MQQBrowser)(?:/(\d+)(?:\.(\d+)|)(?:\.(\d+)|)|)'
     family_replacement: 'QQ Browser Mobile'
-  - regex: '(QQBrowser)(?:/(\d+)(?:\.(\d+)\.(\d+)(?:\.(\d+))?)?)?'
+  - regex: '(QQBrowser)(?:/(\d+)(?:\.(\d+)\.(\d+)(?:\.(\d+)|)|)|)'
     family_replacement: 'QQ Browser'
 
   # Rackspace Monitoring
@@ -373,7 +397,7 @@
   - regex: '(AOL) (\d+)\.(\d+); AOLBuild (\d+)'
 
   # Podcast catcher Applications using iTunes
-  - regex: '(PodCruncher|Downcast)[ /]?(\d+)\.?(\d+)?\.?(\d+)?\.?(\d+)?'
+  - regex: '(PodCruncher|Downcast)[ /]?(\d+)(?:\.(\d+)|)(?:\.(\d+)|)(?:\.(\d+)|)'
 
   # Box Notes https://www.box.com/resources/downloads
   # Must be before Electron
@@ -397,7 +421,7 @@
 
   # HipChat provides a version on Mac, but not on Windows.
   # Needs to be before Chrome on Windows, and AppleMail on Mac.
-  - regex: '(HipChat)/?(\d+)?'
+  - regex: '(HipChat)/?(\d+|)'
     family_replacement: 'HipChat Desktop Client'
 
   # Browser/major_version.minor_version.beta_version
@@ -423,15 +447,18 @@
     family_replacement: 'Outlook'
     v1_replacement: '2016'
 
+  # Word 2014
+  - regex: 'Microsoft Office (Word) 2014'
+
   # Windows Live Mail
   - regex: 'Outlook-Express\/7\.0.*'
     family_replacement: 'Windows Live Mail'
 
   # Apple Air Mail
-  - regex: '(Airmail) (\d+)\.(\d+)(?:\.(\d+))?'
+  - regex: '(Airmail) (\d+)\.(\d+)(?:\.(\d+)|)'
 
   # Thunderbird
-  - regex: '(Thunderbird)/(\d+)\.(\d+)(?:\.(\d+(?:pre)?))?'
+  - regex: '(Thunderbird)/(\d+)\.(\d+)(?:\.(\d+(?:pre|))|)'
     family_replacement: 'Thunderbird'
 
   # Postbox
@@ -439,18 +466,18 @@
     family_replacement: 'Postbox'
 
   # Barca
-  - regex: '(Barca(?:Pro)?)/(\d+)\.(\d+)(?:\.(\d+))?'
+  - regex: '(Barca(?:Pro)?)/(\d+)\.(\d+)(?:\.(\d+)|)'
     family_replacement: 'Barca'
 
   # Lotus Notes
-  - regex: '(Lotus-Notes)/(\d+)\.(\d+)(?:\.(\d+))?'
+  - regex: '(Lotus-Notes)/(\d+)\.(\d+)(?:\.(\d+)|)'
     family_replacement: 'Lotus Notes'
 
   # Vivaldi uses "Vivaldi"
   - regex: '(Vivaldi)/(\d+)\.(\d+)\.(\d+)'
 
   # Edge/major_version.minor_version
-  - regex: '(Edge)/(\d+)(?:\.(\d+))?'
+  - regex: '(Edge)/(\d+)(?:\.(\d+)|)'
 
   # Brave Browser https://brave.com/
   - regex: '(brave)/(\d+)\.(\d+)\.(\d+) Chrome'
@@ -462,23 +489,23 @@
 
   # Dolphin Browser
   # @ref: http://www.dolphin.com
-  - regex: '\b(Dolphin)(?: |HDCN/|/INT\-)(\d+)\.(\d+)\.?(\d+)?'
+  - regex: '\b(Dolphin)(?: |HDCN/|/INT\-)(\d+)\.(\d+)(?:\.(\d+)|)'
 
   # Headless Chrome
   # https://chromium.googlesource.com/chromium/src/+/lkgr/headless/README.md
-  - regex: '(HeadlessChrome)(?:/(\d+)\.(\d+)\.(\d+))?'
+  - regex: '(HeadlessChrome)(?:/(\d+)\.(\d+)\.(\d+)|)'
 
   # Evolution Mail CardDav/CalDav integration
   - regex: '(Evolution)/(\d+)\.(\d+)\.(\d+\.\d+)'
 
   # Roundcube Mail CardDav plugin
-  - regex: '(RCM CardDAV plugin)/(\d+)\.(\d+)\.(\d+(?:-dev)?)'
+  - regex: '(RCM CardDAV plugin)/(\d+)\.(\d+)\.(\d+(?:-dev|))'
 
   # Browser/major_version.minor_version
-  - 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+))?'
+  - 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+)|)'
 
   # Chrome/Chromium/major_version.minor_version
-  - regex: '(Chromium|Chrome)/(\d+)\.(\d+)(?:\.(\d+))?(?:\.(\d+))?'
+  - regex: '(Chromium|Chrome)/(\d+)\.(\d+)(?:\.(\d+)|)(?:\.(\d+)|)'
 
   ##########
   # IE Mobile needs to happen before Android to catch cases such as:
@@ -498,8 +525,8 @@
   # Podcast catchers
   - regex: '^(bPod|Pocket Casts|Player FM)$'
   - regex: '^(AlexaMediaPlayer|VLC)/(\d+)\.(\d+)\.([^.\s]+)'
-  - 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+)?'
-  - regex: '^(Peapod|Liferea)/([^.\s]+)\.([^.\s]+)?\.?([^.\s]+)?'
+  - 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+)|)'
+  - regex: '^(Peapod|Liferea)/([^.\s]+)\.([^.\s]+|)\.?([^.\s]+|)'
   - regex: '^(bPod|Player FM) BMID/(\S+)'
   - regex: '^(Podcast ?Addict)/v(\d+) '
   - regex: '^(Podcast ?Addict) '
@@ -509,8 +536,8 @@
   - regex: '(CITA) RSS Aggregator/(\d+)\.(\d+)'
   - regex: '(Pocket Casts)$'
   - regex: '(Player FM)$'
-  - regex: '(LG Player|Doppler|FancyMusic|MediaMonkey|Clementine) (\d+)\.(\d+)\.?([^.\s]+)?\.?([^.\s]+)?'
-  - regex: '(philpodder)/(\d+)\.(\d+)\.?([^.\s]+)?\.?([^.\s]+)?'
+  - regex: '(LG Player|Doppler|FancyMusic|MediaMonkey|Clementine) (\d+)\.(\d+)\.?([^.\s]+|)\.?([^.\s]+|)'
+  - regex: '(philpodder)/(\d+)\.(\d+)\.?([^.\s]+|)\.?([^.\s]+|)'
   - regex: '(Player FM|Pocket Casts|DoggCatcher|Spotify|MediaMonkey|MediaGo|BashPodder)'
   - regex: '(QuickTime)\.(\d+)\.(\d+)\.(\d+)'
   - regex: '(Kinoma)(\d+)'
@@ -518,35 +545,35 @@
     family_replacement: 'FancyMusic'
   - regex: 'EspnDownloadManager'
     family_replacement: 'ESPN'
-  - regex: '(ESPN) Radio (\d+)\.(\d+)\.?(\d+)? ?(?:rv:(\d+))? '
-  - regex: '(podracer|jPodder) v ?(\d+)\.(\d+)\.?(\d+)?'
+  - regex: '(ESPN) Radio (\d+)\.(\d+)(?:\.(\d+)|) ?(?:rv:(\d+)|) '
+  - regex: '(podracer|jPodder) v ?(\d+)\.(\d+)(?:\.(\d+)|)'
   - regex: '(ZDM)/(\d+)\.(\d+)[; ]?'
-  - regex: '(Zune|BeyondPod) (\d+)\.?(\d+)?[\);]'
+  - regex: '(Zune|BeyondPod) (\d+)(?:\.(\d+)|)[\);]'
   - regex: '(WMPlayer)/(\d+)\.(\d+)\.(\d+)\.(\d+)'
   - regex: '^(Lavf)'
     family_replacement: 'WMPlayer'
-  - regex: '^(RSSRadio)[ /]?(\d+)?'
+  - regex: '^(RSSRadio)[ /]?(\d+|)'
   - regex: '(RSS_Radio) (\d+)\.(\d+)'
     family_replacement: 'RSSRadio'
   - regex: '(Podkicker) \S+/(\d+)\.(\d+)\.(\d+)'
     family_replacement: 'Podkicker'
-  - regex: '^(HTC) Streaming Player \S+ / \S+ / \S+ / (\d+)\.(\d+)\.?(\d+)?'
+  - regex: '^(HTC) Streaming Player \S+ / \S+ / \S+ / (\d+)\.(\d+)(?:\.(\d+)|)'
   - regex: '^(Stitcher)/iOS'
   - regex: '^(Stitcher)/Android'
   - regex: '^(VLC) .*version (\d+)\.(\d+)\.(\d+)'
   - regex: ' (VLC) for'
   - regex: '(vlc)/(\d+)\.(\d+)\.(\d+)'
     family_replacement: 'VLC'
-  - regex: '^(foobar)\S+/([^.\s]+)\.([^.\s]+)?\.?([^.\s]+)?'
-  - regex: '^(Clementine)\S+ ([^.\s]+)\.([^.\s]+)?\.?([^.\s]+)?'
-  - regex: '(amarok)/([^.\s]+)\.([^.\s]+)?\.?([^.\s]+)?'
+  - regex: '^(foobar)\S+/([^.\s]+)\.([^.\s]+|)\.?([^.\s]+|)'
+  - regex: '^(Clementine)\S+ ([^.\s]+)\.([^.\s]+|)\.?([^.\s]+|)'
+  - regex: '(amarok)/([^.\s]+)\.([^.\s]+|)\.?([^.\s]+|)'
     family_replacement: 'Amarok'
   - regex: '(Custom)-Feed Reader'
 
   # Browser major_version.minor_version.beta_version (space instead of slash)
   - regex: '(iRider|Crazy Browser|SkipStone|iCab|Lunascape|Sleipnir|Maemo Browser) (\d+)\.(\d+)\.(\d+)'
   # Browser major_version.minor_version (space instead of slash)
-  - regex: '(iCab|Lunascape|Opera|Android|Jasmine|Polaris|Microsoft SkyDriveSync|The Bat!) (\d+)\.(\d+)\.?(\d+)?'
+  - regex: '(iCab|Lunascape|Opera|Android|Jasmine|Polaris|Microsoft SkyDriveSync|The Bat!) (\d+)\.(\d+)(?:\.(\d+)|)'
 
   # Kindle WebKit
   - regex: '(Kindle)/(\d+)\.(\d+)'
@@ -586,12 +613,16 @@
   - regex: '(ownCloud-android)/(\d+)\.(\d+)\.(\d+)'
     family_replacement: 'Owncloud'
 
+  # Skype for Business
+  - regex: '(OC)/(\d+)\.(\d+)\.(\d+)\.(\d+) \(Skype for Business\)'
+    family_replacement: 'Skype'
+
   #### END MAIN CASES ####
 
   #### SPECIAL CASES ####
   - regex: '(Obigo)InternetBrowser'
   - regex: '(Obigo)\-Browser'
-  - regex: '(Obigo|OBIGO)[^\d]*(\d+)(?:.(\d+))?'
+  - regex: '(Obigo|OBIGO)[^\d]*(\d+)(?:.(\d+)|)'
     family_replacement: 'Obigo'
 
   - regex: '(MAXTHON|Maxthon) (\d+)\.(\d+)'
@@ -610,21 +641,21 @@
   - regex: '(Embider)/(\d+)\.(\d+)'
     family_replacement: 'Polaris'
 
-  - regex: '(BonEcho)/(\d+)\.(\d+)\.?([ab]?\d+)?'
+  - regex: '(BonEcho)/(\d+)\.(\d+)\.?([ab]?\d+|)'
     family_replacement: 'Bon Echo'
 
   # @note: iOS / OSX Applications
   - regex: '(iPod|iPhone|iPad).+GSA/(\d+)\.(\d+)\.(\d+) Mobile'
     family_replacement: 'Google'
-  - regex: '(iPod|iPhone|iPad).+Version/(\d+)\.(\d+)(?:\.(\d+))?.*[ +]Safari'
+  - regex: '(iPod|iPhone|iPad).+Version/(\d+)\.(\d+)(?:\.(\d+)|).*[ +]Safari'
     family_replacement: 'Mobile Safari'
-  - regex: '(iPod|iPod touch|iPhone|iPad);.*CPU.*OS[ +](\d+)_(\d+)(?:_(\d+))?.* AppleNews\/\d+\.\d+\.\d+?'
+  - regex: '(iPod|iPod touch|iPhone|iPad);.*CPU.*OS[ +](\d+)_(\d+)(?:_(\d+)|).* AppleNews\/\d+\.\d+\.\d+?'
     family_replacement: 'Mobile Safari UI/WKWebView'
-  - regex: '(iPod|iPhone|iPad).+Version/(\d+)\.(\d+)(?:\.(\d+))?'
+  - regex: '(iPod|iPhone|iPad).+Version/(\d+)\.(\d+)(?:\.(\d+)|)'
     family_replacement: 'Mobile Safari UI/WKWebView'
-  - regex: '(iPod|iPod touch|iPhone|iPad);.*CPU.*OS[ +](\d+)_(\d+)(?:_(\d+))?.*Mobile.*[ +]Safari'
+  - regex: '(iPod|iPod touch|iPhone|iPad);.*CPU.*OS[ +](\d+)_(\d+)(?:_(\d+)|).*Mobile.*[ +]Safari'
     family_replacement: 'Mobile Safari'
-  - regex: '(iPod|iPod touch|iPhone|iPad);.*CPU.*OS[ +](\d+)_(\d+)(?:_(\d+))?.*Mobile'
+  - regex: '(iPod|iPod touch|iPhone|iPad);.*CPU.*OS[ +](\d+)_(\d+)(?:_(\d+)|).*Mobile'
     family_replacement: 'Mobile Safari UI/WKWebView'
   - regex: '(iPod|iPhone|iPad).* Safari'
     family_replacement: 'Mobile Safari'
@@ -697,18 +728,18 @@
 
   - regex: '(QtWeb) Internet Browser/(\d+)\.(\d+)'
 
-  #- regex: '\(iPad;.+(Version)/(\d+)\.(\d+)(?:\.(\d+))?.*Safari/'
+  #- regex: '\(iPad;.+(Version)/(\d+)\.(\d+)(?:\.(\d+)|).*Safari/'
   #  family_replacement: 'iPad'
 
   # Phantomjs, should go before Safari
   - regex: '(PhantomJS)/(\d+)\.(\d+)\.(\d+)'
 
   # WebKit Nightly
-  - regex: '(AppleWebKit)/(\d+)\.?(\d+)?\+ .* Safari'
+  - regex: '(AppleWebKit)/(\d+)(?:\.(\d+)|)\+ .* Safari'
     family_replacement: 'WebKit Nightly'
 
   # Safari
-  - regex: '(Version)/(\d+)\.(\d+)(?:\.(\d+))?.*Safari/'
+  - regex: '(Version)/(\d+)\.(\d+)(?:\.(\d+)|).*Safari/'
     family_replacement: 'Safari'
   # Safari didn't provide "Version/d.d.d" prior to 3.0
   - regex: '(Safari)/\d+'
@@ -743,7 +774,7 @@
     v1_replacement: '8'
 
   # Espial
-  - regex: '(Espial)/(\d+)(?:\.(\d+))?(?:\.(\d+))?'
+  - regex: '(Espial)/(\d+)(?:\.(\d+)|)(?:\.(\d+)|)'
 
  # Apple Mail
 
@@ -755,7 +786,7 @@
   # AFTER IE11
   # BEFORE all other IE
   - regex: '(Firefox)/(\d+)\.(\d+)\.(\d+)'
-  - regex: '(Firefox)/(\d+)\.(\d+)(pre|[ab]\d+[a-z]*)?'
+  - regex: '(Firefox)/(\d+)\.(\d+)(pre|[ab]\d+[a-z]*|)'
 
   - regex: '([MS]?IE) (\d+)\.(\d+)'
     family_replacement: 'IE'
@@ -764,13 +795,13 @@
     family_replacement: 'Python Requests'
 
   # headless user-agents
-  - 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+))?)?)?'
+  - 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+)|)|)'
 
-  - regex: '(Java)[/ ]{0,1}\d+\.(\d+)\.(\d+)[_-]*([a-zA-Z0-9]+)*'
+  - regex: '(Java)[/ ]{0,1}\d+\.(\d+)\.(\d+)[_-]*([a-zA-Z0-9]+|)'
 
   # Cloud Storage Clients
-  - regex: '^(Cyberduck)/(\d+)\.(\d+)\.(\d+)(?:\.\d+)?'
-  - regex: '^(S3 Browser) (\d+)-(\d+)-(\d+)(?:\s*http://s3browser\.com)?'
+  - regex: '^(Cyberduck)/(\d+)\.(\d+)\.(\d+)(?:\.\d+|)'
+  - regex: '^(S3 Browser) (\d+)-(\d+)-(\d+)(?:\s*http://s3browser\.com|)'
   # rclone - rsync for cloud storage - https://rclone.org/
   - regex: '^(rclone)/v(\d+)\.(\d+)'
 
@@ -784,6 +815,10 @@
   # Box Drive and Box Sync https://www.box.com/resources/downloads
   - regex: '^(Box(?: Sync)?)/(\d+)\.(\d+)\.(\d+)'
 
+  # ViaFree streaming app https://www.viafree.{dk|se|no}
+  - regex: '^(ViaFree|Viafree)-(?:tvOS-)?[A-Z]{2}/(\d+)\.(\d+)\.(\d+)'
+    family_replacement: 'ViaFree'
+
 os_parsers:
   ##########
   # HbbTV vendors
@@ -829,11 +864,11 @@
   # Philips : not found any other way than a manual mapping
   # 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
   # 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
-  - regex: 'HbbTV/1.1.1 \(; (Philips);.*NETTV/4'
+  - regex: 'HbbTV/1\.1\.1 \(; (Philips);.*NETTV/4'
     os_v1_replacement: '2013'
-  - regex: 'HbbTV/1.1.1 \(; (Philips);.*NETTV/3'
+  - regex: 'HbbTV/1\.1\.1 \(; (Philips);.*NETTV/3'
     os_v1_replacement: '2012'
-  - regex: 'HbbTV/1.1.1 \(; (Philips);.*NETTV/2'
+  - regex: 'HbbTV/1\.1\.1 \(; (Philips);.*NETTV/2'
     os_v1_replacement: '2011'
 
   # the HbbTV emulator developers use HbbTV/1.1.1 (;;;;;) firetv-firefox-plugin 1.1.20
@@ -854,14 +889,14 @@
   - regex: '(Windows Phone) (?:OS[ /])?(\d+)\.(\d+)'
 
   # Again a MS-special one: iPhone.*Outlook-iOS-Android/x.x is erroneously detected as Android
-  - regex: '(CPU[ +]OS|iPhone[ +]OS|CPU[ +]iPhone)[ +]+(\d+)[_\.](\d+)(?:[_\.](\d+))?.*Outlook-iOS-Android'
+  - regex: '(CPU[ +]OS|iPhone[ +]OS|CPU[ +]iPhone)[ +]+(\d+)[_\.](\d+)(?:[_\.](\d+)|).*Outlook-iOS-Android'
     os_replacement: 'iOS'
 
   ##########
   # Android
   # can actually detect rooted android os. do we care?
   ##########
-  - regex: '(Android)[ \-/](\d+)\.?(\d+)?(?:[.\-]([a-z0-9]+))?'
+  - regex: '(Android)[ \-/](\d+)(?:\.(\d+)|)(?:[.\-]([a-z0-9]+)|)'
 
   - regex: '(Android) Donut'
     os_v1_replacement: '1'
@@ -883,18 +918,18 @@
     os_v1_replacement: '3'
 
   # UCWEB
-  - regex: '^UCWEB.*; (Adr) (\d+)\.(\d+)(?:[.\-]([a-z0-9]+))?;'
+  - regex: '^UCWEB.*; (Adr) (\d+)\.(\d+)(?:[.\-]([a-z0-9]+)|);'
     os_replacement: 'Android'
-  - regex: '^UCWEB.*; (iPad|iPh|iPd) OS (\d+)_(\d+)(?:_(\d+))?;'
+  - regex: '^UCWEB.*; (iPad|iPh|iPd) OS (\d+)_(\d+)(?:_(\d+)|);'
     os_replacement: 'iOS'
-  - regex: '^UCWEB.*; (wds) (\d+)\.(\d+)(?:\.(\d+))?;'
+  - regex: '^UCWEB.*; (wds) (\d+)\.(\d+)(?:\.(\d+)|);'
     os_replacement: 'Windows Phone'
   # JUC
-  - regex: '^(JUC).*; ?U; ?(?:Android)?(\d+)\.(\d+)(?:[\.\-]([a-z0-9]+))?'
+  - regex: '^(JUC).*; ?U; ?(?:Android|)(\d+)\.(\d+)(?:[\.\-]([a-z0-9]+)|)'
     os_replacement: 'Android'
 
   # Salesforce
-  - regex: '(android)\s(?:mobile\/)(\d+)(?:\.?(\d+))?(?:\.?(\d+))?'
+  - regex: '(android)\s(?:mobile\/)(\d+)(?:\.(\d+)(?:\.(\d+)|)|)'
     os_replacement: 'Android'
 
   ##########
@@ -908,7 +943,7 @@
   # properly identify as Chrome OS
   #
   # 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
-  - regex: '(x86_64|aarch64)\ (\d+)+\.(\d+)+\.(\d+)+.*Chrome.*(?:CitrixChromeApp)$'
+  - regex: '(x86_64|aarch64)\ (\d+)\.(\d+)\.(\d+).*Chrome.*(?:CitrixChromeApp)$'
     os_replacement: 'Chrome OS'
 
   ##########
@@ -945,8 +980,6 @@
     os_replacement: 'Windows'
     os_v1_replacement: 'ME'
 
-  - regex: '(Windows 98|Windows XP|Windows ME|Windows 95|Windows CE|Windows 7|Windows NT 4\.0|Windows Vista|Windows 2000|Windows 3.1)'
-
   - regex: '(Windows NT 6\.2; ARM;)'
     os_replacement: 'Windows'
     os_v1_replacement: 'RT'
@@ -989,7 +1022,7 @@
     os_replacement: 'Windows'
     os_v1_replacement: 'CE'
 
-  - regex: 'Win ?(95|98|3.1|NT|ME|2000)'
+  - regex: 'Win(?:dows)? ?(95|98|3.1|NT|ME|2000|XP|Vista|7|CE)'
     os_replacement: 'Windows'
     os_v1_replacement: '$1'
 
@@ -1017,13 +1050,13 @@
   # @ref: http://en.wikipedia.org/wiki/Mac_OS_X#Versions
   # @ref: http://www.puredarwin.org/curious/versions
   ##########
-  - regex: '((?:Mac[ +]?|; )OS[ +]X)[\s+/](?:(\d+)[_.](\d+)(?:[_.](\d+))?|Mach-O)'
+  - regex: '((?:Mac[ +]?|; )OS[ +]X)[\s+/](?:(\d+)[_.](\d+)(?:[_.](\d+)|)|Mach-O)'
     os_replacement: 'Mac OS X'
-  - regex: '(\w+\s+Mac OS X\s+\w+\s+(\d+).(\d+).(\d+).*)'
+  - regex: '\w+\s+Mac OS X\s+\w+\s+(\d+).(\d+).(\d+).*'
     os_replacement: 'Mac OS X'
-    os_v1_replacement: '$2'
-    os_v2_replacement: '$3'
-    os_v3_replacement: '$4'
+    os_v1_replacement: '$1'
+    os_v2_replacement: '$2'
+    os_v3_replacement: '$3'
   # Leopard
   - regex: ' (Dar)(win)/(9).(\d+).*\((?:i386|x86_64|Power Macintosh)\)'
     os_replacement: 'Mac OS X'
@@ -1062,7 +1095,7 @@
   - regex: '(?:PPC|Intel) (Mac OS X)'
 
   # Box Drive and Box Sync on Mac OS X use OSX version numbers, not Darwin
-  - regex: '^Box.*;(Darwin)/(10)\.(1\d)(?:\.(\d+))?'
+  - regex: '^Box.*;(Darwin)/(10)\.(1\d)(?:\.(\d+)|)'
     os_replacement: 'Mac OS X'
 
   ##########
@@ -1070,10 +1103,10 @@
   # http://en.wikipedia.org/wiki/IOS_version_history
   ##########
   # keep this above generic iOS, since AppleTV UAs contain 'CPU OS'
-  - regex: '(Apple\s?TV)(?:/(\d+)\.(\d+))?'
+  - regex: '(Apple\s?TV)(?:/(\d+)\.(\d+)|)'
     os_replacement: 'ATV OS X'
 
-  - regex: '(CPU[ +]OS|iPhone[ +]OS|CPU[ +]iPhone|CPU IPhone OS)[ +]+(\d+)[_\.](\d+)(?:[_\.](\d+))?'
+  - regex: '(CPU[ +]OS|iPhone[ +]OS|CPU[ +]iPhone|CPU IPhone OS)[ +]+(\d+)[_\.](\d+)(?:[_\.](\d+)|)'
     os_replacement: 'iOS'
 
   # remaining cases are mostly only opera uas, so catch opera as to not catch iphone spoofs
@@ -1255,7 +1288,7 @@
     os_replacement: 'iOS'
 
   # iOS Apps
-  - regex: '\b(iOS[ /]|iOS; |iPhone(?:/| v|[ _]OS[/,]|; | OS : |\d,\d/|\d,\d; )|iPad/)(\d{1,2})[_\.](\d{1,2})(?:[_\.](\d+))?'
+  - regex: '\b(iOS[ /]|iOS; |iPhone(?:/| v|[ _]OS[/,]|; | OS : |\d,\d/|\d,\d; )|iPad/)(\d{1,2})[_\.](\d{1,2})(?:[_\.](\d+)|)'
     os_replacement: 'iOS'
   - regex: '\((iOS);'
 
@@ -1264,10 +1297,16 @@
   ##########################
   - regex: 'Outlook-(iOS)/\d+\.\d+\.prod\.iphone'
 
+  ##########################
+  # iOS devices, the same regex matches mobile safari webviews
+  ##########################
+  - regex: '(iPod|iPhone|iPad)'
+    os_replacement: 'iOS'
+
   ##########
   # Apple TV
   ##########
-  - regex: '(tvOS)/(\d+).(\d+)'
+  - regex: '(tvOS)[/ ](\d+)\.(\d+)(?:\.(\d+)|)'
     os_replacement: 'tvOS'
 
   ##########
@@ -1276,7 +1315,7 @@
   # http://code.google.com/p/chromium-os/issues/detail?id=11573
   # http://code.google.com/p/chromium-os/issues/detail?id=13790
   ##########
-  - regex: '(CrOS) [a-z0-9_]+ (\d+)\.(\d+)(?:\.(\d+))?'
+  - regex: '(CrOS) [a-z0-9_]+ (\d+)\.(\d+)(?:\.(\d+)|)'
     os_replacement: 'Chrome OS'
 
   ##########
@@ -1284,8 +1323,8 @@
   ##########
   - regex: '([Dd]ebian)'
     os_replacement: 'Debian'
-  - regex: '(Linux Mint)(?:/(\d+))?'
-  - regex: '(Mandriva)(?: Linux)?/(?:[\d.-]+m[a-z]{2}(\d+).(\d))?'
+  - regex: '(Linux Mint)(?:/(\d+)|)'
+  - regex: '(Mandriva)(?: Linux|)/(?:[\d.-]+m[a-z]{2}(\d+).(\d)|)'
 
   ##########
   # Symbian + Symbian OS
@@ -1314,9 +1353,9 @@
   ##########
   - regex: '(BB10);.+Version/(\d+)\.(\d+)\.(\d+)'
     os_replacement: 'BlackBerry OS'
-  - regex: '(Black[Bb]erry)[0-9a-z]+/(\d+)\.(\d+)\.(\d+)(?:\.(\d+))?'
+  - regex: '(Black[Bb]erry)[0-9a-z]+/(\d+)\.(\d+)\.(\d+)(?:\.(\d+)|)'
     os_replacement: 'BlackBerry OS'
-  - regex: '(Black[Bb]erry).+Version/(\d+)\.(\d+)\.(\d+)(?:\.(\d+))?'
+  - regex: '(Black[Bb]erry).+Version/(\d+)\.(\d+)\.(\d+)(?:\.(\d+)|)'
     os_replacement: 'BlackBerry OS'
   - regex: '(RIM Tablet OS) (\d+)\.(\d+)\.(\d+)'
     os_replacement: 'BlackBerry Tablet OS'
@@ -1383,20 +1422,20 @@
   ##########
   # Google TV
   ##########
-  - regex: '(GoogleTV)(?: (\d+)\.(\d+)(?:\.(\d+))?|/[\da-z]+)'
+  - regex: '(GoogleTV)(?: (\d+)\.(\d+)(?:\.(\d+)|)|/[\da-z]+)'
 
   - regex: '(WebTV)/(\d+).(\d+)'
 
   ##########
   # Chromecast
   ##########
-  - regex: '(CrKey)(?:[/](\d+)\.(\d+)(?:\.(\d+))?)?'
+  - regex: '(CrKey)(?:[/](\d+)\.(\d+)(?:\.(\d+)|)|)'
     os_replacement: 'Chromecast'
 
   ##########
   # Misc mobile
   ##########
-  - regex: '(hpw|web)OS/(\d+)\.(\d+)(?:\.(\d+))?'
+  - regex: '(hpw|web)OS/(\d+)\.(\d+)(?:\.(\d+)|)'
     os_replacement: 'webOS'
   - regex: '(VRE);'
 
@@ -1404,10 +1443,10 @@
   # Generic patterns
   # since the majority of os cases are very specific, these go last
   ##########
-  - regex: '(Fedora|Red Hat|PCLinuxOS|Puppy|Ubuntu|Kindle|Bada|Lubuntu|BackTrack|Slackware|(?:Free|Open|Net|\b)BSD)[/ ](\d+)\.(\d+)(?:\.(\d+)(?:\.(\d+))?)?'
+  - regex: '(Fedora|Red Hat|PCLinuxOS|Puppy|Ubuntu|Kindle|Bada|Lubuntu|BackTrack|Slackware|(?:Free|Open|Net|\b)BSD)[/ ](\d+)\.(\d+)(?:\.(\d+)|)(?:\.(\d+)|)'
 
   # Gentoo Linux + Kernel Version
-  - regex: '(Linux)[ /](\d+)\.(\d+)(?:\.(\d+))?.*gentoo'
+  - regex: '(Linux)[ /](\d+)\.(\d+)(?:\.(\d+)|).*gentoo'
     os_replacement: 'Gentoo'
 
   # Opera Mini Bada
@@ -1417,7 +1456,7 @@
   - regex: '(Windows|Android|WeTab|Maemo|Web0S)'
   - regex: '(Ubuntu|Kubuntu|Arch Linux|CentOS|Slackware|Gentoo|openSUSE|SUSE|Red Hat|Fedora|PCLinuxOS|Mageia|(?:Free|Open|Net|\b)BSD)'
   # Linux + Kernel Version
-  - regex: '(Linux)(?:[ /](\d+)\.(\d+)(?:\.(\d+))?)?'
+  - regex: '(Linux)(?:[ /](\d+)\.(\d+)(?:\.(\d+)|)|)'
   - regex: 'SunOS'
     os_replacement: 'Solaris'
   # Wget/x.x.x (linux-gnu)
@@ -1448,6 +1487,16 @@
     brand_replacement: 'Spider'
     model_replacement: 'Feature Phone'
 
+  # PTST / WebPageTest.org crawlers
+  - regex: ' PTST/\d+\.\d+$'
+    device_replacement: 'Spider'
+    brand_replacement: 'Spider'
+
+  # Datanyze.com spider
+  - regex: 'X11; Datanyze; Linux'
+    device_replacement: 'Spider'
+    brand_replacement: 'Spider'
+
   #########
   # WebBrowser for SmartWatch
   # @ref: https://play.google.com/store/apps/details?id=se.vaggan.webbrowser&hl=en
@@ -1464,7 +1513,7 @@
   ######################################################################
 
   # Android Application
-  - regex: 'Android Application[^\-]+ - (Sony) ?(Ericsson)? (.+) \w+ - '
+  - regex: 'Android Application[^\-]+ - (Sony) ?(Ericsson|) (.+) \w+ - '
     device_replacement: '$1 $2'
     brand_replacement: '$1$2'
     model_replacement: '$3'
@@ -1495,7 +1544,7 @@
   # Acer
   # @ref: http://us.acer.com/ac/en/US/content/group/tablets
   #########
-  - 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'
+  - 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'
     device_replacement: '$1'
     brand_replacement: 'Acer'
     model_replacement: '$1'
@@ -1518,7 +1567,7 @@
   # @note: VegaBean and VegaComb (names derived from jellybean, honeycomb) are
   #   custom ROM builds for Vega
   #########
-  - regex: '; *(Advent )?(Vega(?:Bean|Comb)?).* Build'
+  - regex: '; *(Advent |)(Vega(?:Bean|Comb|)).* Build'
     device_replacement: '$1$2'
     brand_replacement: 'Advent'
     model_replacement: '$2'
@@ -1527,7 +1576,7 @@
   # Ainol
   # @ref: http://www.ainol.com/plugin.php?identifier=ainol&module=product
   #########
-  - regex: '; *(Ainol )?((?:NOVO|[Nn]ovo)[^;/]+) Build'
+  - regex: '; *(Ainol |)((?:NOVO|[Nn]ovo)[^;/]+) Build'
     device_replacement: '$1$2'
     brand_replacement: 'Ainol'
     model_replacement: '$2'
@@ -1564,7 +1613,7 @@
     device_replacement: 'Alcatel One Touch $2'
     brand_replacement: 'Alcatel'
     model_replacement: 'One Touch $2'
-  - regex: '; *(?:alcatel[ _])?(?:(?:one[ _]?touch[ _])|ot[ \-])([^;/]+);? Build'
+  - regex: '; *(?:alcatel[ _]|)(?:(?:one[ _]?touch[ _])|ot[ \-])([^;/]+);? Build'
     regex_flag: 'i'
     device_replacement: 'Alcatel One Touch $1'
     brand_replacement: 'Alcatel'
@@ -1604,7 +1653,7 @@
     device_replacement: '$1$2'
     brand_replacement: 'Allview'
     model_replacement: '$2'
-  - regex: '; *(ALLVIEW[ _]?|Allview[ _]?)?(AX1_Shine|AX2_Frenzy) Build'
+  - regex: '; *(ALLVIEW[ _]?|Allview[ _]?|)(AX1_Shine|AX2_Frenzy) Build'
     device_replacement: '$1$2'
     brand_replacement: 'Allview'
     model_replacement: '$2'
@@ -1664,7 +1713,7 @@
   # @ref: http://www.luckystar.com.cn/en/mobiletel.aspx?page=1
   # @note: brand owned by luckystar
   #########
-  - 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'
+  - 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'
     device_replacement: 'Aoson $1'
     brand_replacement: 'Aoson'
     model_replacement: '$1'
@@ -1739,7 +1788,7 @@
   # Assistant
   # @ref: http://www.assistant.ua
   #########
-  - regex: '; *(?:ASSISTANT )?(AP)-?([1789]\d{2}[A-Z]{0,2}|80104) Build'
+  - regex: '; *(?:ASSISTANT |)(AP)-?([1789]\d{2}[A-Z]{0,2}|80104) Build'
     device_replacement: 'Assistant $1-$2'
     brand_replacement: 'Assistant'
     model_replacement: '$1-$2'
@@ -1748,7 +1797,7 @@
   # Asus
   # @ref: http://www.asus.com/uk/Tablets_Mobile/
   #########
-  - regex: '; *(ME17\d[^;/]*|ME3\d{2}[^;/]+|K00[A-Z]|Nexus 10|Nexus 7(?: 2013)?|PadFone[^;/]*|Transformer[^;/]*|TF\d{3}[^;/]*|eeepc) Build'
+  - regex: '; *(ME17\d[^;/]*|ME3\d{2}[^;/]+|K00[A-Z]|Nexus 10|Nexus 7(?: 2013|)|PadFone[^;/]*|Transformer[^;/]*|TF\d{3}[^;/]*|eeepc) Build'
     device_replacement: 'Asus $1'
     brand_replacement: 'Asus'
     model_replacement: '$1'
@@ -2296,7 +2345,7 @@
   # Gionee
   # @ref: http://www.gionee.com/
   #########
-  - regex: '; *(Gionee)[ _\-]([^;/]+)(?:/[^;/]+)? Build'
+  - regex: '; *(Gionee)[ _\-]([^;/]+)(?:/[^;/]+|) Build'
     regex_flag: 'i'
     device_replacement: '$1 $2'
     brand_replacement: 'Gionee'
@@ -2460,7 +2509,7 @@
   # @ref: http://www.huaweidevice.com
   # @note: Needs to be before HTC due to Desire HD Build on U8815
   #########
-  - regex: '; *(HUAWEI |Huawei-)?([UY][^;/]+) Build/(?:Huawei|HUAWEI)([UY][^\);]+)\)'
+  - regex: '; *(HUAWEI |Huawei-|)([UY][^;/]+) Build/(?:Huawei|HUAWEI)([UY][^\);]+)\)'
     device_replacement: '$1$2'
     brand_replacement: 'Huawei'
     model_replacement: '$2'
@@ -2476,7 +2525,7 @@
     device_replacement: '$1$2'
     brand_replacement: 'Huawei'
     model_replacement: '$2'
-  - regex: '; *((?:HUAWEI[ _]?|Huawei[ _])?Ascend[ _])([^;/]+) Build'
+  - regex: '; *((?:HUAWEI[ _]?|Huawei[ _]|)Ascend[ _])([^;/]+) Build'
     device_replacement: '$1$2'
     brand_replacement: 'Huawei'
     model_replacement: '$2'
@@ -2531,33 +2580,33 @@
     device_replacement: 'HTC $1'
     brand_replacement: 'HTC'
     model_replacement: '$1'
-  - regex: '; *(?:HTC[ _/])+([^ _/]+)(?:[ _/]([^ _/]+))?(?:[/\\]1\.0 | V|/| +)\d+\.\d[\d\.]*(?: *Build|\))'
+  - regex: '; *(?:HTC[ _/])+([^ _/]+)(?:[ _/]([^ _/]+)|)(?:[/\\]1\.0 | V|/| +)\d+\.\d[\d\.]*(?: *Build|\))'
     device_replacement: 'HTC $1 $2'
     brand_replacement: 'HTC'
     model_replacement: '$1 $2'
-  - regex: '; *(?:HTC[ _/])+([^ _/]+)(?:[ _/]([^ _/]+)(?:[ _/]([^ _/]+))?)?(?:[/\\]1\.0 | V|/| +)\d+\.\d[\d\.]*(?: *Build|\))'
+  - regex: '; *(?:HTC[ _/])+([^ _/]+)(?:[ _/]([^ _/]+)(?:[ _/]([^ _/]+)|)|)(?:[/\\]1\.0 | V|/| +)\d+\.\d[\d\.]*(?: *Build|\))'
     device_replacement: 'HTC $1 $2 $3'
     brand_replacement: 'HTC'
     model_replacement: '$1 $2 $3'
-  - regex: '; *(?:HTC[ _/])+([^ _/]+)(?:[ _/]([^ _/]+)(?:[ _/]([^ _/]+)(?:[ _/]([^ _/]+))?)?)?(?:[/\\]1\.0 | V|/| +)\d+\.\d[\d\.]*(?: *Build|\))'
+  - regex: '; *(?:HTC[ _/])+([^ _/]+)(?:[ _/]([^ _/]+)(?:[ _/]([^ _/]+)(?:[ _/]([^ _/]+)|)|)|)(?:[/\\]1\.0 | V|/| +)\d+\.\d[\d\.]*(?: *Build|\))'
     device_replacement: 'HTC $1 $2 $3 $4'
     brand_replacement: 'HTC'
     model_replacement: '$1 $2 $3 $4'
 
   # Android HTC without Version Number matcher
-  - regex: '; *(?:(?:HTC|htc)(?:_blocked)*[ _/])+([^ _/;]+)(?: *Build|[;\)]| - )'
+  - regex: '; *(?:(?:HTC|htc)(?:_blocked|)[ _/])+([^ _/;]+)(?: *Build|[;\)]| - )'
     device_replacement: 'HTC $1'
     brand_replacement: 'HTC'
     model_replacement: '$1'
-  - regex: '; *(?:(?:HTC|htc)(?:_blocked)*[ _/])+([^ _/]+)(?:[ _/]([^ _/;\)]+))?(?: *Build|[;\)]| - )'
+  - regex: '; *(?:(?:HTC|htc)(?:_blocked|)[ _/])+([^ _/]+)(?:[ _/]([^ _/;\)]+)|)(?: *Build|[;\)]| - )'
     device_replacement: 'HTC $1 $2'
     brand_replacement: 'HTC'
     model_replacement: '$1 $2'
-  - regex: '; *(?:(?:HTC|htc)(?:_blocked)*[ _/])+([^ _/]+)(?:[ _/]([^ _/]+)(?:[ _/]([^ _/;\)]+))?)?(?: *Build|[;\)]| - )'
+  - regex: '; *(?:(?:HTC|htc)(?:_blocked|)[ _/])+([^ _/]+)(?:[ _/]([^ _/]+)(?:[ _/]([^ _/;\)]+)|)|)(?: *Build|[;\)]| - )'
     device_replacement: 'HTC $1 $2 $3'
     brand_replacement: 'HTC'
     model_replacement: '$1 $2 $3'
-  - regex: '; *(?:(?:HTC|htc)(?:_blocked)*[ _/])+([^ _/]+)(?:[ _/]([^ _/]+)(?:[ _/]([^ _/]+)(?:[ _/]([^ /;]+))?)?)?(?: *Build|[;\)]| - )'
+  - regex: '; *(?:(?:HTC|htc)(?:_blocked|)[ _/])+([^ _/]+)(?:[ _/]([^ _/]+)(?:[ _/]([^ _/]+)(?:[ _/]([^ /;]+)|)|)|)(?: *Build|[;\)]| - )'
     device_replacement: 'HTC $1 $2 $3 $4'
     brand_replacement: 'HTC'
     model_replacement: '$1 $2 $3 $4'
@@ -2568,7 +2617,7 @@
     brand_replacement: 'HTC'
     model_replacement: '$1'
   # general matcher for anything else
-  - regex: '(?:[;,] *|^)(?:htccn_chs-)?HTC[ _-]?([^;]+?)(?: *Build|clay|Android|-?Mozilla| Opera| Profile| UNTRUSTED|[;/\(\)]|$)'
+  - regex: '(?:[;,] *|^)(?:htccn_chs-|)HTC[ _-]?([^;]+?)(?: *Build|clay|Android|-?Mozilla| Opera| Profile| UNTRUSTED|[;/\(\)]|$)'
     regex_flag: 'i'
     device_replacement: 'HTC $1'
     brand_replacement: 'HTC'
@@ -2607,12 +2656,12 @@
   # iBall
   # @ref: http://www.iball.co.in/Category/Mobiles/22
   #########
-  - regex: '; *(?:iBall[ _\-])?(Andi)[ _]?(\d[^;/]*) Build'
+  - regex: '; *(?:iBall[ _\-]|)(Andi)[ _]?(\d[^;/]*) Build'
     regex_flag: 'i'
     device_replacement: '$1 $2'
     brand_replacement: 'iBall'
     model_replacement: '$1 $2'
-  - regex: '; *(IBall)(?:[ _]([^;/]+))? Build'
+  - regex: '; *(IBall)(?:[ _]([^;/]+)|) Build'
     regex_flag: 'i'
     device_replacement: '$1 $2'
     brand_replacement: 'iBall'
@@ -2622,7 +2671,7 @@
   # IconBIT
   # @ref: http://www.iconbit.com/catalog/tablets/
   #########
-  - regex: '; *(NT-\d+[^ ;/]*|Net[Tt]AB [^;/]+|Mercury [A-Z]+|iconBIT)(?: S/N:[^;/]+)? Build'
+  - regex: '; *(NT-\d+[^ ;/]*|Net[Tt]AB [^;/]+|Mercury [A-Z]+|iconBIT)(?: S/N:[^;/]+|) Build'
     device_replacement: '$1'
     brand_replacement: 'IconBIT'
     model_replacement: '$1'
@@ -2695,17 +2744,17 @@
   # @note: Zync also offers a "Cloud Z5" device
   #########
   # smartphones
-  - regex: '; *(?:Intex[ _])?(AQUA|Aqua)([ _\.\-])([^;/]+) *(?:Build|;)'
+  - regex: '; *(?:Intex[ _]|)(AQUA|Aqua)([ _\.\-])([^;/]+) *(?:Build|;)'
     device_replacement: '$1$2$3'
     brand_replacement: 'Intex'
     model_replacement: '$1 $3'
   # matches "INTEX CLOUD X1"
-  - regex: '; *(?:INTEX|Intex)(?:[_ ]([^\ _;/]+))(?:[_ ]([^\ _;/]+))? *(?:Build|;)'
+  - regex: '; *(?:INTEX|Intex)(?:[_ ]([^\ _;/]+))(?:[_ ]([^\ _;/]+)|) *(?:Build|;)'
     device_replacement: '$1 $2'
     brand_replacement: 'Intex'
     model_replacement: '$1 $2'
   # tablets
-  - regex: '; *([iI]Buddy)[ _]?(Connect)(?:_|\?_| )?([^;/]*) *(?:Build|;)'
+  - regex: '; *([iI]Buddy)[ _]?(Connect)(?:_|\?_| |)([^;/]*) *(?:Build|;)'
     device_replacement: '$1 $2 $3'
     brand_replacement: 'Intex'
     model_replacement: 'iBuddy $2 $3'
@@ -2728,7 +2777,7 @@
   # i.onik
   # @ref: http://www.i-onik.de/
   #########
-  - regex: '; *(TP\d+(?:\.\d+)?\-\d[^;/]+) Build'
+  - regex: '; *(TP\d+(?:\.\d+|)\-\d[^;/]+) Build'
     device_replacement: 'ionik $1'
     brand_replacement: 'ionik'
     model_replacement: '$1'
@@ -2944,7 +2993,7 @@
   # Lava
   # @ref: http://www.lavamobiles.com/
   #########
-  - regex: '; *(?:LAVA[ _])?IRIS[ _\-]?([^/;\)]+) *(?:;|\)|Build)'
+  - regex: '; *(?:LAVA[ _]|)IRIS[ _\-]?([^/;\)]+) *(?:;|\)|Build)'
     regex_flag: 'i'
     device_replacement: 'Iris $1'
     brand_replacement: 'Lava'
@@ -2996,15 +3045,15 @@
     device_replacement: 'Lenovo $1 $2'
     brand_replacement: 'Lenovo'
     model_replacement: '$1 $2'
-  - regex: '; *(?:LNV-)?(?:=?[Ll]enovo[ _\-]?|LENOVO[ _])+(.+?)(?:Build|[;/\)])'
+  - regex: '; *(?:LNV-|)(?:=?[Ll]enovo[ _\-]?|LENOVO[ _])(.+?)(?:Build|[;/\)])'
     device_replacement: 'Lenovo $1'
     brand_replacement: 'Lenovo'
     model_replacement: '$1'
-  - regex: '[;,] (?:Vodafone )?(SmartTab) ?(II) ?(\d+) Build/'
+  - regex: '[;,] (?:Vodafone |)(SmartTab) ?(II) ?(\d+) Build/'
     device_replacement: 'Lenovo $1 $2 $3'
     brand_replacement: 'Lenovo'
     model_replacement: '$1 $2 $3'
-  - regex: '; *(?:Ideapad )?K1 Build/'
+  - regex: '; *(?:Ideapad |)K1 Build/'
     device_replacement: 'Lenovo Ideapad K1'
     brand_replacement: 'Lenovo'
     model_replacement: 'Ideapad K1'
@@ -3034,7 +3083,7 @@
     device_replacement: '$1'
     brand_replacement: 'LG'
     model_replacement: '$1'
-  - regex: '[;:] *(L-\d+[A-Z]|LGL\d+[A-Z]?)(?:/V\d+)? *(?:Build|[;\)])'
+  - regex: '[;:] *(L-\d+[A-Z]|LGL\d+[A-Z]?)(?:/V\d+|) *(?:Build|[;\)])'
     device_replacement: '$1'
     brand_replacement: 'LG'
     model_replacement: '$1'
@@ -3117,7 +3166,7 @@
   # Medion
   # @ref: http://www.medion.com/en/
   #########
-  - regex: '; *(?:MD_)?LIFETAB[ _]([^;/]+) Build'
+  - regex: '; *(?:MD_|)LIFETAB[ _]([^;/]+) Build'
     regex_flag: 'i'
     device_replacement: 'Medion Lifetab $1'
     brand_replacement: 'Medion'
@@ -3195,7 +3244,7 @@
   # Modecom
   # @ref: http://www.modecom.eu/tablets/portal/
   #########
-  - regex: '; *(MODECOM )?(FreeTab) ?([^;/]+) Build'
+  - regex: '; *(MODECOM |)(FreeTab) ?([^;/]+) Build'
     regex_flag: 'i'
     device_replacement: '$1$2 $3'
     brand_replacement: 'Modecom'
@@ -3253,7 +3302,7 @@
   # MSI
   # @ref: http://www.msi.com/product/windpad/
   #########
-  - regex: '; *(?:MSI[ _])?(Primo\d+|Enjoy[ _\-][^;/]+) Build'
+  - regex: '; *(?:MSI[ _]|)(Primo\d+|Enjoy[ _\-][^;/]+) Build'
     regex_flag: 'i'
     device_replacement: '$1'
     brand_replacement: 'Msi'
@@ -3280,7 +3329,7 @@
     device_replacement: '$1$2 $3'
     brand_replacement: 'MyPhone'
     model_replacement: '$3'
-  - regex: '; *(A\d+)[ _](Duo)? Build'
+  - regex: '; *(A\d+)[ _](Duo|) Build'
     regex_flag: 'i'
     device_replacement: '$1 $2'
     brand_replacement: 'MyPhone'
@@ -3349,7 +3398,7 @@
     device_replacement: '$1$2'
     brand_replacement: 'Nook'
     model_replacement: '$2'
-  - regex: '; *(NOOK )?(BNRV200|BNRV200A|BNTV250|BNTV250A|BNTV400|BNTV600|LogicPD Zoom2) Build'
+  - regex: '; *(NOOK |)(BNRV200|BNRV200A|BNTV250|BNTV250A|BNTV400|BNTV600|LogicPD Zoom2) Build'
     device_replacement: '$1$2'
     brand_replacement: 'Nook'
     model_replacement: '$2'
@@ -3484,11 +3533,11 @@
   # @href: http://www.pantech.co.kr/en/prod/prodList.do?gbrand=VEGA
   # @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
   #########
-  - regex: '; *(SKY[ _])?(IM\-[AT]\d{3}[^;/]+).* Build/'
+  - regex: '; *(SKY[ _]|)(IM\-[AT]\d{3}[^;/]+).* Build/'
     device_replacement: 'Pantech $1$2'
     brand_replacement: 'Pantech'
     model_replacement: '$1$2'
-  - regex: '; *((?:ADR8995|ADR910L|ADR930L|ADR930VW|PTL21|P8000)(?: 4G)?) Build/'
+  - regex: '; *((?:ADR8995|ADR910L|ADR930L|ADR930VW|PTL21|P8000)(?: 4G|)) Build/'
     device_replacement: '$1'
     brand_replacement: 'Pantech'
     model_replacement: '$1'
@@ -3571,7 +3620,7 @@
   # Polaroid/ Acho
   # @ref: http://polaroidstore.com/store/start.asp?category_id=382&category_id2=0&order=title&filter1=&filter2=&filter3=&view=all
   #########
-  - regex: '; *(?:Polaroid[ _])?((?:MIDC\d{3,}|PMID\d{2,}|PTAB\d{3,})[^;/]*)(\/[^;/]*)? Build/'
+  - regex: '; *(?:Polaroid[ _]|)((?:MIDC\d{3,}|PMID\d{2,}|PTAB\d{3,})[^;/]*)(\/[^;/]*|) Build/'
     device_replacement: '$1'
     brand_replacement: 'Polaroid'
     model_replacement: '$1'
@@ -3598,7 +3647,7 @@
     device_replacement: '$1'
     brand_replacement: 'Positivo'
     model_replacement: '$1'
-  - regex: '; *(?:Positivo )?((?:YPY|Ypy)[^;/]+) Build/'
+  - regex: '; *(?:Positivo |)((?:YPY|Ypy)[^;/]+) Build/'
     device_replacement: '$1'
     brand_replacement: 'Positivo'
     model_replacement: '$1'
@@ -3626,7 +3675,7 @@
   # @ref: http://www.prestigio.com/catalogue/MultiPhones
   # @ref: http://www.prestigio.com/catalogue/MultiPads
   #########
-  - regex: '; *(?:Prestigio )?((?:PAP|PMP)\d[^;/]+) Build/'
+  - regex: '; *(?:Prestigio |)((?:PAP|PMP)\d[^;/]+) Build/'
     device_replacement: 'Prestigio $1'
     brand_replacement: 'Prestigio'
     model_replacement: '$1'
@@ -3644,7 +3693,7 @@
   # QMobile
   # @ref: http://www.qmobile.com.pk/
   #########
-  - regex: '; *(A2|A5|A8|A900)_?(Classic)? Build'
+  - regex: '; *(A2|A5|A8|A900)_?(Classic|) Build'
     device_replacement: '$1 $2'
     brand_replacement: 'Qmobile'
     model_replacement: '$1 $2'
@@ -3710,11 +3759,11 @@
   # Samsung Android Devices
   # @ref: http://www.samsung.com/us/mobile/cell-phones/all-products
   #########
-  - regex: '; *(SAMSUNG |Samsung )?((?:Galaxy (?:Note II|S\d)|GT-I9082|GT-I9205|GT-N7\d{3}|SM-N9005)[^;/]*)\/?[^;/]* Build/'
+  - regex: '; *(SAMSUNG |Samsung |)((?:Galaxy (?:Note II|S\d)|GT-I9082|GT-I9205|GT-N7\d{3}|SM-N9005)[^;/]*)\/?[^;/]* Build/'
     device_replacement: 'Samsung $1$2'
     brand_replacement: 'Samsung'
     model_replacement: '$2'
-  - regex: '; *(Google )?(Nexus [Ss](?: 4G)?) Build/'
+  - regex: '; *(Google |)(Nexus [Ss](?: 4G|)) Build/'
     device_replacement: 'Samsung $1$2'
     brand_replacement: 'Samsung'
     model_replacement: '$2'
@@ -3722,15 +3771,15 @@
     device_replacement: 'Samsung $2'
     brand_replacement: 'Samsung'
     model_replacement: '$2'
-  - regex: '; *(Galaxy(?: Ace| Nexus| S ?II+|Nexus S| with MCR 1.2| Mini Plus 4G)?) Build/'
+  - regex: '; *(Galaxy(?: Ace| Nexus| S ?II+|Nexus S| with MCR 1.2| Mini Plus 4G|)) Build/'
     device_replacement: 'Samsung $1'
     brand_replacement: 'Samsung'
     model_replacement: '$1'
-  - regex: '; *(SAMSUNG[ _\-] *)+([^;/]+) Build'
+  - regex: '; *(SAMSUNG[ _\-]|)(?:SAMSUNG[ _\-])([^;/]+) Build'
     device_replacement: 'Samsung $2'
     brand_replacement: 'Samsung'
     model_replacement: '$2'
-  - regex: '; *(SAMSUNG-)?(GT\-[BINPS]\d{4}[^\/]*)(\/[^ ]*) Build'
+  - regex: '; *(SAMSUNG-|)(GT\-[BINPS]\d{4}[^\/]*)(\/[^ ]*) Build'
     device_replacement: 'Samsung $1$2$3'
     brand_replacement: 'Samsung'
     model_replacement: '$2'
@@ -3742,11 +3791,11 @@
     device_replacement: 'Samsung $1$2'
     brand_replacement: 'Samsung'
     model_replacement: '$2'
-  - regex: '; *((?:SCH|SGH|SHV|SHW|SPH|SC|SM)\-[A-Za-z0-9 ]+)(/?[^ ]*)? Build'
+  - regex: '; *((?:SCH|SGH|SHV|SHW|SPH|SC|SM)\-[A-Za-z0-9 ]+)(/?[^ ]*|) Build'
     device_replacement: 'Samsung $1'
     brand_replacement: 'Samsung'
     model_replacement: '$1'
-  - regex: ' ((?:SCH)\-[A-Za-z0-9 ]+)(/?[^ ]*)? Build'
+  - regex: ' ((?:SCH)\-[A-Za-z0-9 ]+)(/?[^ ]*|) Build'
     device_replacement: 'Samsung $1'
     brand_replacement: 'Samsung'
     model_replacement: '$1'
@@ -3883,7 +3932,7 @@
     device_replacement: '$1$2'
     brand_replacement: 'SonyEricsson'
     model_replacement: '$2'
-  - regex: '; *((?:SK|ST|E|X|LT|MK|MT|WT)\d{2}[a-z0-9]*(?:-o)?|R800i|U20i) Build'
+  - regex: '; *((?:SK|ST|E|X|LT|MK|MT|WT)\d{2}[a-z0-9]*(?:-o|)|R800i|U20i) Build'
     device_replacement: '$1'
     brand_replacement: 'SonyEricsson'
     model_replacement: '$1'
@@ -3947,7 +3996,7 @@
   # Spice
   # @ref: http://www.spicemobilephones.co.in/
   #########
-  - regex: '; *((?:CSL_Spice|Spice|SPICE|CSL)[ _\-]?)?([Mm][Ii])([ _\-])?(\d{3}[^;/]*) Build/'
+  - regex: '; *((?:CSL_Spice|Spice|SPICE|CSL)[ _\-]?|)([Mm][Ii])([ _\-]|)(\d{3}[^;/]*) Build/'
     device_replacement: '$1$2$3$4'
     brand_replacement: 'Spice'
     model_replacement: 'Mi$4'
@@ -4086,7 +4135,7 @@
     device_replacement: '$1'
     brand_replacement: 'HTC'
     model_replacement: 'Dream'
-  - regex: '\b(T-Mobile ?)?(myTouch)[ _]?([34]G)[ _]?([^\/]*) (?:Mozilla|Build)'
+  - regex: '\b(T-Mobile ?|)(myTouch)[ _]?([34]G)[ _]?([^\/]*) (?:Mozilla|Build)'
     device_replacement: '$1$2 $3 $4'
     brand_replacement: 'HTC'
     model_replacement: '$2 $3 $4'
@@ -4131,7 +4180,7 @@
     device_replacement: '$1'
     brand_replacement: 'Toshiba'
     model_replacement: 'Folio 100'
-  - regex: '; *(AT[0-9]{2,3}(?:\-A|LE\-A|PE\-A|SE|a)?|AT7-A|AT1S0|Hikari-iFrame/WDPF-[^;/]+|THRiVE|Thrive) Build/'
+  - regex: '; *(AT[0-9]{2,3}(?:\-A|LE\-A|PE\-A|SE|a|)|AT7-A|AT1S0|Hikari-iFrame/WDPF-[^;/]+|THRiVE|Thrive) Build/'
     device_replacement: 'Toshiba $1'
     brand_replacement: 'Toshiba'
     model_replacement: '$1'
@@ -4251,7 +4300,7 @@
   # Walton
   # @ref: http://www.waltonbd.com/
   #########
-  - regex: '; *(?:Walton[ _\-])?(Primo[ _\-][^;/]+) Build'
+  - regex: '; *(?:Walton[ _\-]|)(Primo[ _\-][^;/]+) Build'
     regex_flag: 'i'
     device_replacement: 'Walton $1'
     brand_replacement: 'Walton'
@@ -4261,7 +4310,7 @@
   # Wiko
   # @ref: http://fr.wikomobile.com/collection.php?s=Smartphones
   #########
-  - regex: '; *(?:WIKO[ \-])?(CINK\+?|BARRY|BLOOM|DARKFULL|DARKMOON|DARKNIGHT|DARKSIDE|FIZZ|HIGHWAY|IGGY|OZZY|RAINBOW|STAIRWAY|SUBLIM|WAX|CINK [^;/]+) Build/'
+  - regex: '; *(?:WIKO[ \-]|)(CINK\+?|BARRY|BLOOM|DARKFULL|DARKMOON|DARKNIGHT|DARKSIDE|FIZZ|HIGHWAY|IGGY|OZZY|RAINBOW|STAIRWAY|SUBLIM|WAX|CINK [^;/]+) Build/'
     regex_flag: 'i'
     device_replacement: 'Wiko $1'
     brand_replacement: 'Wiko'
@@ -4307,7 +4356,7 @@
   # Yarvik Zania
   # @ref: http://yarvik.com
   #########
-  - 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/'
+  - 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/'
     device_replacement: 'Yarvik $1'
     brand_replacement: 'Yarvik'
     model_replacement: '$1'
@@ -4330,7 +4379,7 @@
   # XiaoMi
   # @ref: http://www.xiaomi.com/event/buyphone
   #########
-  - regex: '; *((Mi|MI|HM|MI-ONE|Redmi)[ -](NOTE |Note )?[^;/]*) (Build|MIUI)/'
+  - regex: '; *((Mi|MI|HM|MI-ONE|Redmi)[ -](NOTE |Note |)[^;/]*) (Build|MIUI)/'
     device_replacement: 'XiaoMi $1'
     brand_replacement: 'XiaoMi'
     model_replacement: '$1'
@@ -4496,7 +4545,7 @@
     device_replacement: 'Kindle'
     brand_replacement: 'Amazon'
     model_replacement: 'Kindle'
-  - regex: '; ?(Silk)/(\d+)\.(\d+)(?:\.([0-9\-]+))? Build\b'
+  - regex: '; ?(Silk)/(\d+)\.(\d+)(?:\.([0-9\-]+)|) Build\b'
     device_replacement: 'Kindle Fire'
     brand_replacement: 'Amazon'
     model_replacement: 'Kindle Fire$2'
@@ -4548,7 +4597,7 @@
   #########
   # Alcatel Windows Phones
   #########
-  - regex: 'Windows Phone [^;]+; .*?IEMobile/[^;\)]+[;\)] ?(?:ARM; ?Touch; ?|Touch; ?)?(?:ALCATEL)[^;]*; *([^;,\)]+)'
+  - regex: 'Windows Phone [^;]+; .*?IEMobile/[^;\)]+[;\)] ?(?:ARM; ?Touch; ?|Touch; ?|)(?:ALCATEL)[^;]*; *([^;,\)]+)'
     device_replacement: 'Alcatel $1'
     brand_replacement: 'Alcatel'
     model_replacement: '$1'
@@ -4556,8 +4605,8 @@
   #########
   # Asus Windows Phones
   #########
-  #~ - regex: 'Windows Phone [^;]+; .*?IEMobile/[^;\)]+[;\)] ?(?:ARM; ?Touch; ?|Touch; ?|WpsLondonTest; ?)?(?:ASUS|Asus)[^;]*; *([^;,\)]+)'
-  - regex: 'Windows Phone [^;]+; .*?IEMobile/[^;\)]+[;\)] ?(?:ARM; ?Touch; ?|Touch; ?|WpsLondonTest; ?)?(?:ASUS|Asus)[^;]*; *([^;,\)]+)'
+  #~ - regex: 'Windows Phone [^;]+; .*?IEMobile/[^;\)]+[;\)] ?(?:ARM; ?Touch; ?|Touch; ?|WpsLondonTest; ?|)(?:ASUS|Asus)[^;]*; *([^;,\)]+)'
+  - regex: 'Windows Phone [^;]+; .*?IEMobile/[^;\)]+[;\)] ?(?:ARM; ?Touch; ?|Touch; ?|WpsLondonTest; ?|)(?:ASUS|Asus)[^;]*; *([^;,\)]+)'
     device_replacement: 'Asus $1'
     brand_replacement: 'Asus'
     model_replacement: '$1'
@@ -4565,7 +4614,7 @@
   #########
   # Dell Windows Phones
   #########
-  - regex: 'Windows Phone [^;]+; .*?IEMobile/[^;\)]+[;\)] ?(?:ARM; ?Touch; ?|Touch; ?)?(?:DELL|Dell)[^;]*; *([^;,\)]+)'
+  - regex: 'Windows Phone [^;]+; .*?IEMobile/[^;\)]+[;\)] ?(?:ARM; ?Touch; ?|Touch; ?|)(?:DELL|Dell)[^;]*; *([^;,\)]+)'
     device_replacement: 'Dell $1'
     brand_replacement: 'Dell'
     model_replacement: '$1'
@@ -4573,7 +4622,7 @@
   #########
   # HTC Windows Phones
   #########
-  - regex: 'Windows Phone [^;]+; .*?IEMobile/[^;\)]+[;\)] ?(?:ARM; ?Touch; ?|Touch; ?|WpsLondonTest; ?)?(?:HTC|Htc|HTC_blocked[^;]*)[^;]*; *(?:HTC)?([^;,\)]+)'
+  - regex: 'Windows Phone [^;]+; .*?IEMobile/[^;\)]+[;\)] ?(?:ARM; ?Touch; ?|Touch; ?|WpsLondonTest; ?|)(?:HTC|Htc|HTC_blocked[^;]*)[^;]*; *(?:HTC|)([^;,\)]+)'
     device_replacement: 'HTC $1'
     brand_replacement: 'HTC'
     model_replacement: '$1'
@@ -4581,7 +4630,7 @@
   #########
   # Huawei Windows Phones
   #########
-  - regex: 'Windows Phone [^;]+; .*?IEMobile/[^;\)]+[;\)] ?(?:ARM; ?Touch; ?|Touch; ?)?(?:HUAWEI)[^;]*; *(?:HUAWEI )?([^;,\)]+)'
+  - regex: 'Windows Phone [^;]+; .*?IEMobile/[^;\)]+[;\)] ?(?:ARM; ?Touch; ?|Touch; ?|)(?:HUAWEI)[^;]*; *(?:HUAWEI |)([^;,\)]+)'
     device_replacement: 'Huawei $1'
     brand_replacement: 'Huawei'
     model_replacement: '$1'
@@ -4589,7 +4638,7 @@
   #########
   # LG Windows Phones
   #########
-  - regex: 'Windows Phone [^;]+; .*?IEMobile/[^;\)]+[;\)] ?(?:ARM; ?Touch; ?|Touch; ?)?(?:LG|Lg)[^;]*; *(?:LG[ \-])?([^;,\)]+)'
+  - regex: 'Windows Phone [^;]+; .*?IEMobile/[^;\)]+[;\)] ?(?:ARM; ?Touch; ?|Touch; ?|)(?:LG|Lg)[^;]*; *(?:LG[ \-]|)([^;,\)]+)'
     device_replacement: 'LG $1'
     brand_replacement: 'LG'
     model_replacement: '$1'
@@ -4597,15 +4646,15 @@
   #########
   # Noka Windows Phones
   #########
-  - regex: 'Windows Phone [^;]+; .*?IEMobile/[^;\)]+[;\)] ?(?:ARM; ?Touch; ?|Touch; ?)?(?:rv:11; )?(?:NOKIA|Nokia)[^;]*; *(?:NOKIA ?|Nokia ?|LUMIA ?|[Ll]umia ?)*(\d{3,}[^;\)]*)'
+  - regex: 'Windows Phone [^;]+; .*?IEMobile/[^;\)]+[;\)] ?(?:ARM; ?Touch; ?|Touch; ?|)(?:rv:11; |)(?:NOKIA|Nokia)[^;]*; *(?:NOKIA ?|Nokia ?|LUMIA ?|[Ll]umia ?|)(\d{3,10}[^;\)]*)'
     device_replacement: 'Lumia $1'
     brand_replacement: 'Nokia'
     model_replacement: 'Lumia $1'
-  - regex: 'Windows Phone [^;]+; .*?IEMobile/[^;\)]+[;\)] ?(?:ARM; ?Touch; ?|Touch; ?)?(?:NOKIA|Nokia)[^;]*; *(RM-\d{3,})'
+  - regex: 'Windows Phone [^;]+; .*?IEMobile/[^;\)]+[;\)] ?(?:ARM; ?Touch; ?|Touch; ?|)(?:NOKIA|Nokia)[^;]*; *(RM-\d{3,})'
     device_replacement: 'Nokia $1'
     brand_replacement: 'Nokia'
     model_replacement: '$1'
-  - regex: '(?:Windows Phone [^;]+; .*?IEMobile/[^;\)]+[;\)]|WPDesktop;) ?(?:ARM; ?Touch; ?|Touch; ?)?(?:NOKIA|Nokia)[^;]*; *(?:NOKIA ?|Nokia ?|LUMIA ?|[Ll]umia ?)*([^;\)]+)'
+  - regex: '(?:Windows Phone [^;]+; .*?IEMobile/[^;\)]+[;\)]|WPDesktop;) ?(?:ARM; ?Touch; ?|Touch; ?|)(?:NOKIA|Nokia)[^;]*; *(?:NOKIA ?|Nokia ?|LUMIA ?|[Ll]umia ?|)([^;\)]+)'
     device_replacement: 'Nokia $1'
     brand_replacement: 'Nokia'
     model_replacement: '$1'
@@ -4613,7 +4662,7 @@
   #########
   # Microsoft Windows Phones
   #########
-  - regex: 'Windows Phone [^;]+; .*?IEMobile/[^;\)]+[;\)] ?(?:ARM; ?Touch; ?|Touch; ?)?(?:Microsoft(?: Corporation)?)[^;]*; *([^;,\)]+)'
+  - regex: 'Windows Phone [^;]+; .*?IEMobile/[^;\)]+[;\)] ?(?:ARM; ?Touch; ?|Touch; ?|)(?:Microsoft(?: Corporation|))[^;]*; *([^;,\)]+)'
     device_replacement: 'Microsoft $1'
     brand_replacement: 'Microsoft'
     model_replacement: '$1'
@@ -4621,7 +4670,7 @@
   #########
   # Samsung Windows Phones
   #########
-  - regex: 'Windows Phone [^;]+; .*?IEMobile/[^;\)]+[;\)] ?(?:ARM; ?Touch; ?|Touch; ?|WpsLondonTest; ?)?(?:SAMSUNG)[^;]*; *(?:SAMSUNG )?([^;,\.\)]+)'
+  - regex: 'Windows Phone [^;]+; .*?IEMobile/[^;\)]+[;\)] ?(?:ARM; ?Touch; ?|Touch; ?|WpsLondonTest; ?|)(?:SAMSUNG)[^;]*; *(?:SAMSUNG |)([^;,\.\)]+)'
     device_replacement: 'Samsung $1'
     brand_replacement: 'Samsung'
     model_replacement: '$1'
@@ -4629,7 +4678,7 @@
   #########
   # Toshiba Windows Phones
   #########
-  - regex: 'Windows Phone [^;]+; .*?IEMobile/[^;\)]+[;\)] ?(?:ARM; ?Touch; ?|Touch; ?|WpsLondonTest; ?)?(?:TOSHIBA|FujitsuToshibaMobileCommun)[^;]*; *([^;,\)]+)'
+  - regex: 'Windows Phone [^;]+; .*?IEMobile/[^;\)]+[;\)] ?(?:ARM; ?Touch; ?|Touch; ?|WpsLondonTest; ?|)(?:TOSHIBA|FujitsuToshibaMobileCommun)[^;]*; *([^;,\)]+)'
     device_replacement: 'Toshiba $1'
     brand_replacement: 'Toshiba'
     model_replacement: '$1'
@@ -4637,7 +4686,7 @@
   #########
   # Generic Windows Phones
   #########
-  - regex: 'Windows Phone [^;]+; .*?IEMobile/[^;\)]+[;\)] ?(?:ARM; ?Touch; ?|Touch; ?|WpsLondonTest; ?)?([^;]+); *([^;,\)]+)'
+  - regex: 'Windows Phone [^;]+; .*?IEMobile/[^;\)]+[;\)] ?(?:ARM; ?Touch; ?|Touch; ?|WpsLondonTest; ?|)([^;]+); *([^;,\)]+)'
     device_replacement: '$1 $2'
     brand_replacement: '$1'
     model_replacement: '$2'
@@ -4657,7 +4706,7 @@
   #########
   # Firefox OS
   #########
-  - regex: '\(Mobile; ALCATEL ?(One|ONE) ?(Touch|TOUCH) ?([^;/]+)(?:/[^;]+)?; rv:[^\)]+\) Gecko/[^\/]+ Firefox/'
+  - regex: '\(Mobile; ALCATEL ?(One|ONE) ?(Touch|TOUCH) ?([^;/]+)(?:/[^;]+|); rv:[^\)]+\) Gecko/[^\/]+ Firefox/'
     device_replacement: 'Alcatel $1 $2 $3'
     brand_replacement: 'Alcatel'
     model_replacement: 'One Touch $3'
@@ -4688,7 +4737,7 @@
     brand_replacement: '$1'
     model_replacement: '$2'
   # Nokia Symbian
-  - regex: '\(Symbian(?:/3)?; U; ([^;]+);'
+  - regex: '\(Symbian(?:/3|); U; ([^;]+);'
     device_replacement: 'Nokia $1'
     brand_replacement: 'Nokia'
     model_replacement: '$1'
@@ -4733,7 +4782,7 @@
     device_replacement: 'Palm Treo $1'
     brand_replacement: 'Palm'
     model_replacement: 'Treo $1'
-  - regex: 'webOS.*(P160U(?:NA)?)/(\d+).(\d+)'
+  - regex: 'webOS.*(P160U(?:NA|))/(\d+).(\d+)'
     device_replacement: 'HP Veer'
     brand_replacement: 'HP'
     model_replacement: 'Veer'
@@ -4860,7 +4909,7 @@
     device_replacement: 'Asus $1'
     brand_replacement: 'Asus'
     model_replacement: '$1'
-  - regex: '(?:asus.*?ASUS|Asus|ASUS|asus)[\- ;]*((?:Transformer (?:Pad|Prime) |Transformer |Padfone |Nexus[ _])?[A-Za-z0-9]+)'
+  - regex: '(?:asus.*?ASUS|Asus|ASUS|asus)[\- ;]*((?:Transformer (?:Pad|Prime) |Transformer |Padfone |Nexus[ _]|)[A-Za-z0-9]+)'
     device_replacement: 'Asus $1'
     brand_replacement: 'Asus'
     model_replacement: '$1'
@@ -4901,7 +4950,7 @@
   ##########
   # htc
   ##########
-  - regex: '\b(?:HTC/|HTC/[a-z0-9]+/)?HTC[ _\-;]? *(.*?)(?:-?Mozilla|fingerPrint|[;/\(\)]|$)'
+  - regex: '\b(?:HTC/|HTC/[a-z0-9]+/|)HTC[ _\-;]? *(.*?)(?:-?Mozilla|fingerPrint|[;/\(\)]|$)'
     device_replacement: 'HTC $1'
     brand_replacement: 'HTC'
     model_replacement: '$1'
@@ -4958,11 +5007,11 @@
     device_replacement: '$1'
     brand_replacement: '$2'
     model_replacement: '$3'
-  - regex: '(HbbTV)/1\.1\.1.*CE-HTML/1\.\d;(Vendor/)*(THOM[^;]*?)[;\s](?:.*SW-Version/.*)*(LF[^;]+);?'
+  - regex: '(HbbTV)/1\.1\.1.*CE-HTML/1\.\d;(Vendor/|)(THOM[^;]*?)[;\s].{0,30}(LF[^;]+);?'
     device_replacement: '$1'
     brand_replacement: 'Thomson'
     model_replacement: '$4'
-  - regex: '(HbbTV)(?:/1\.1\.1)?(?: ?\(;;;;;\))?; *CE-HTML(?:/1\.\d)?; *([^ ]+) ([^;]+);'
+  - regex: '(HbbTV)(?:/1\.1\.1|) ?(?: \(;;;;;\)|); *CE-HTML(?:/1\.\d|); *([^ ]+) ([^;]+);'
     device_replacement: '$1'
     brand_replacement: '$2'
     model_replacement: '$3'
@@ -4979,7 +5028,7 @@
   ##########
   # LGE NetCast TV
   ##########
-  - regex: 'LGE; (?:Media\/)?([^;]*);[^;]*;[^;]*;?\); "?LG NetCast(\.TV|\.Media)?-\d+'
+  - regex: 'LGE; (?:Media\/|)([^;]*);[^;]*;[^;]*;?\); "?LG NetCast(\.TV|\.Media|)-\d+'
     device_replacement: 'NetCast$2'
     brand_replacement: 'LG'
     model_replacement: '$1'
@@ -5008,7 +5057,7 @@
     brand_replacement: '$1'
     model_replacement: '$2'
   # other LG phones
-  - regex: '\b(?:LGE[ \-]LG\-(?:AX)?|LGE |LGE?-LG|LGE?[ \-]|LG[ /\-]|lg[\-])([A-Za-z0-9]+)\b'
+  - regex: '\b(?:LGE[ \-]LG\-(?:AX|)|LGE |LGE?-LG|LGE?[ \-]|LG[ /\-]|lg[\-])([A-Za-z0-9]+)\b'
     device_replacement: 'LG $1'
     brand_replacement: 'LG'
     model_replacement: '$1'
@@ -5153,7 +5202,7 @@
     device_replacement: '$2 $1'
     brand_replacement: '$2'
     model_replacement: '$1'
-  - regex: '(Sony)(?:BDP\/|\/)?([^ /;\)]+)[ /;\)]'
+  - regex: '(Sony)(?:BDP\/|\/|)([^ /;\)]+)[ /;\)]'
     device_replacement: '$1 $2'
     brand_replacement: '$1'
     model_replacement: '$2'
@@ -5189,21 +5238,21 @@
   - regex: 'Android[\- ][\d]+\.[\d]+\-update1; [A-Za-z]{2}\-[A-Za-z]{0,2} *; *(.+?) Build[/ ]'
     brand_replacement: 'Generic_Android'
     model_replacement: '$1'
-  - regex: 'Android[\- ][\d]+(?:\.[\d]+){1,2}; *[A-Za-z]{2}[_\-][A-Za-z]{0,2}\-? *; *(.+?) Build[/ ]'
+  - regex: 'Android[\- ][\d]+(?:\.[\d]+)(?:\.[\d]+|); *[A-Za-z]{2}[_\-][A-Za-z]{0,2}\-? *; *(.+?) Build[/ ]'
     brand_replacement: 'Generic_Android'
     model_replacement: '$1'
-  - regex: 'Android[\- ][\d]+(?:\.[\d]+){1,2}; *[A-Za-z]{0,2}\- *; *(.+?) Build[/ ]'
+  - regex: 'Android[\- ][\d]+(?:\.[\d]+)(?:\.[\d]+|); *[A-Za-z]{0,2}\- *; *(.+?) Build[/ ]'
     brand_replacement: 'Generic_Android'
     model_replacement: '$1'
   # No build info at all - "Build" follows locale immediately
-  - regex: 'Android[\- ][\d]+(?:\.[\d]+){1,2}; *[a-z]{0,2}[_\-]?[A-Za-z]{0,2};? Build[/ ]'
+  - regex: 'Android[\- ][\d]+(?:\.[\d]+)(?:\.[\d]+|); *[a-z]{0,2}[_\-]?[A-Za-z]{0,2};? Build[/ ]'
     device_replacement: 'Generic Smartphone'
     brand_replacement: 'Generic'
     model_replacement: 'Smartphone'
-  - regex: 'Android[\- ][\d]+(?:\.[\d]+){1,2}; *\-?[A-Za-z]{2}; *(.+?) Build[/ ]'
+  - regex: 'Android[\- ][\d]+(?:\.[\d]+)(?:\.[\d]+|); *\-?[A-Za-z]{2}; *(.+?) Build[/ ]'
     brand_replacement: 'Generic_Android'
     model_replacement: '$1'
-  - regex: 'Android[\- ][\d]+(?:\.[\d]+){1,2}(?:;.*)?; *(.+?) Build[/ ]'
+  - regex: 'Android[\- ][\d]+(?:\.[\d]+)(?:\.[\d]+|)(?:;.*|); *(.+?) Build[/ ]'
     brand_replacement: 'Generic_Android'
     model_replacement: '$1'
 
diff -Nru uap-core-20181019/test_resources/pgts_browser_list.yaml uap-core-20190213/test_resources/pgts_browser_list.yaml
--- uap-core-20181019/test_resources/pgts_browser_list.yaml	2018-10-19 17:08:22.000000000 +0100
+++ uap-core-20190213/test_resources/pgts_browser_list.yaml	2019-02-13 17:27:26.000000000 +0000
@@ -39415,9 +39415,9 @@
     patch:
 
   - user_agent_string: 'Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 4.0; 3COM U.S. Robotics)'
-    family: 'Robotics'
-    major:
-    minor:
+    family: 'IE'
+    major: '6'
+    minor: '0'
     patch:
 
   - user_agent_string: 'Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 4.0; ABN AMRO)'
@@ -63409,7 +63409,7 @@
     patch:
 
   - user_agent_string: 'Mozilla/4.0 (compatible; MSIE 6.0; Windows XP Professional Bot v.5.)'
-    family: 'XP Professional Bot'
+    family: 'Windows XP Professional Bot'
     major:
     minor:
     patch:
diff -Nru uap-core-20181019/tests/mocha.opts uap-core-20190213/tests/mocha.opts
--- uap-core-20181019/tests/mocha.opts	1970-01-01 01:00:00.000000000 +0100
+++ uap-core-20190213/tests/mocha.opts	2019-02-13 17:27:26.000000000 +0000
@@ -0,0 +1,3 @@
+--ui tdd
+--reporter min
+--check-leaks
diff -Nru uap-core-20181019/tests/regexes.js uap-core-20190213/tests/regexes.js
--- uap-core-20181019/tests/regexes.js	1970-01-01 01:00:00.000000000 +0100
+++ uap-core-20190213/tests/regexes.js	2019-02-13 17:27:26.000000000 +0000
@@ -0,0 +1,36 @@
+'use strict'
+
+var assert = require('assert')
+var path = require('path')
+var fs = require('fs')
+var yaml = require('yamlparser')
+var regexes = readYAML('../regexes.yaml')
+var safe = require('safe-regex')
+var refImpl = require('uap-ref-impl')
+
+function readYAML (fileName) {
+  var file = path.join(__dirname, fileName)
+  var data = fs.readFileSync(file, 'utf8')
+  return yaml.eval(data)
+}
+
+suite('regexes', function () {
+  Object.keys(regexes).forEach(function (parser) {
+    suite(parser, function () {
+      regexes[parser].forEach(function(item) {
+        test(item.regex, function () {
+          assert.ok(safe(item.regex))
+        })
+      })
+    })
+  })
+
+  test('should not backtrack', function () {
+    var parse = refImpl(regexes).parse
+    var ua = Array(3200).fill('a').join('')
+    var start = Date.now()
+    parse(ua)
+    var diff = Date.now() - start
+    assert.ok(diff < 500, diff)
+  })
+})
diff -Nru uap-core-20181019/tests/test_device.yaml uap-core-20190213/tests/test_device.yaml
--- uap-core-20181019/tests/test_device.yaml	2018-10-19 17:08:22.000000000 +0100
+++ uap-core-20190213/tests/test_device.yaml	2019-02-13 17:27:26.000000000 +0000
@@ -650,6 +650,26 @@
     brand: 'Spider'
     model: 'Desktop'
 
+  - user_agent_string: 'Mozilla/5.0 (Windows NT 6.3; WOW64; Trident/7.0; rv:11.0) like Gecko PTST/1.0'
+    family: 'Spider'
+    brand: 'Spider'
+    model:
+
+  - user_agent_string: 'Mozilla/5.0 (Windows NT 6.2; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/64.0.3282.0 Safari/537.36 PTST/1.0'
+    family: 'Spider'
+    brand: 'Spider'
+    model:
+
+  - user_agent_string: 'Mozilla/5.0 (Linux; Android 6.0.1; Moto G (4) Build/MPJ24.139-64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/65.0.3325.146 Mobile Safari/537.36 PTST/180521.140508'
+    family: 'Spider'
+    brand: 'Spider'
+    model:
+
+  - user_agent_string: 'Mozilla/5.0 (X11; Datanyze; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/65.0.3325.181 Safari/537.36'
+    family: 'Spider'
+    brand: 'Spider'
+    model:
+
   - user_agent_string: 'Mozilla/5.0 (Unknown; Linux x86_64) AppleWebKit/534.34 (KHTML, like Gecko) PingdomTMS/0.8.5 Safari/534.34'
     family: 'Spider'
     brand: 'Spider'
diff -Nru uap-core-20181019/tests/test_os.yaml uap-core-20190213/tests/test_os.yaml
--- uap-core-20181019/tests/test_os.yaml	2018-10-19 17:08:22.000000000 +0100
+++ uap-core-20190213/tests/test_os.yaml	2019-02-13 17:27:26.000000000 +0000
@@ -427,6 +427,13 @@
     patch:
     patch_minor:
 
+  - user_agent_string: 'Mozilla/5.0 (X11; Datanyze; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/65.0.3325.181 Safari/537.36'
+    family: 'Linux'
+    major:
+    minor:
+    patch:
+    patch_minor:
+
   - user_agent_string: 'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko; Google Web Preview) Chrome/27.0 .1453 Safari/537.36.'
     family: 'Linux'
     major:
@@ -736,15 +743,15 @@
     patch_minor:
 
   - user_agent_string: 'ICE Browser/5.05 (Java 1.4.0; Windows 2000 5.0 x86)'
-    family: 'Windows 2000'
-    major:
+    family: 'Windows'
+    major: '2000'
     minor:
     patch:
     patch_minor:
 
   - user_agent_string: 'NCSA_Mosaic/2.0 (Windows 3.1)'
-    family: 'Windows 3.1'
-    major:
+    family: 'Windows'
+    major: '3.1'
     minor:
     patch:
     patch_minor:
@@ -2419,6 +2426,13 @@
     patch: '4'
     patch_minor:
 
+  - user_agent_string: 'Zendesk for iPhone 1.2.1 (4395)'
+    family: 'iOS'
+    major:
+    minor:
+    patch:
+    patch_minor:
+
   - user_agent_string: 'Mozilla/5.0+(Macintosh;+Intel+Mac+OS+X+10_11_6)+AppleWebKit/537.36+(KHTML,+like+Gecko)+Chrome/52.0.2743.116+Safari/537.36'
     family: 'Mac OS X'
     major: '10'
@@ -2580,21 +2594,21 @@
     minor: '2'
     patch: '5'
     patch_minor:
- 
+
   - user_agent_string: 'Mozilla/5.0 (iPhone; CPU iPhone OS 11_2_6 like Mac OS X) AppleWebKit/604.5.6 (KHTML, like Gecko) Mobile/15D100 Flipboard/4.2.2'
     family: 'iOS'
     major: '11'
     minor: '2'
     patch: '6'
     patch_minor:
-    
+
   - user_agent_string: 'Mozilla/5.0 (Linux; Android 7.0; SM-G610F Build/NRD90M; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/63.0.3239.111 Mobile Safari/537.36 Flipboard/4.1.9/4323,4.1.9.4323'
     family: 'Android'
     major: '7'
     minor: '0'
     patch:
     patch_minor:
-    
+
   - user_agent_string: 'Mozilla/5.0 (Linux; Android 7.0; SM-G930F Build/NRD90M; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/64.0.3282.137 Mobile Safari/537.36 Onefootball/Android/9.10.6'
     family: 'Android'
     major: '7'
@@ -2608,7 +2622,7 @@
     minor: '0'
     patch:
     patch_minor:
-    
+
   - user_agent_string: 'Wget/1.18 (linux-gnu)'
     family: 'Linux'
     major:
@@ -2635,28 +2649,28 @@
     major: '8'
     minor: '0'
     patch: '0'
-    patch_minor: 
+    patch_minor:
 
   - user_agent_string: 'SalesforceMobileSDK/5.3.0 android mobile/7.0 (SM-G955U) Salesforce1/15.2 Native uid_4ec4068eddf27447 ftr_ Cordova/6.2.3'
     family: 'Android'
     major: '7'
     minor: '0'
-    patch: 
-    patch_minor: 
-    
+    patch:
+    patch_minor:
+
   - user_agent_string: 'SalesforceMobileSDK/5.3.0 android mobile/9 (SM-G955U) Salesforce1/15.2 Native uid_4ec4068eddf27447 ftr_ Cordova/6.2.3'
     family: 'Android'
     major: '9'
     minor:
-    patch: 
-    patch_minor: 
+    patch:
+    patch_minor:
 
   - user_agent_string: 'Mozilla/5.0 (Linux; Android 9; Pixel Build/PPP3.180510.008) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.81 Mobile Safari/537.36'
     family: 'Android'
     major: '9'
     minor:
-    patch: 
-    patch_minor: 
+    patch:
+    patch_minor:
 
   - user_agent_string: 'Mozilla/5.0 (X11; Windows aarch64 10718.88.2) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3440.118 Safari/537.36 CitrixChromeApp'
     family: 'Chrome OS'
@@ -2679,3 +2693,86 @@
     patch:
     patch_minor:
 
+  - user_agent_string: 'ViaFree-DK/3.8.3 (com.MTGx.ViaFree.dk; build:7383; iOS 12.1.0) Alamofire/4.7.0'
+    family: 'iOS'
+    major: '12'
+    minor: '1'
+    patch: '0'
+    patch_minor:
+
+  - user_agent_string: 'Viafree-tvOS-DK/3.7.1 (com.MTGx.ViaFree.dk; build:7341; tvOS 12.1.0) Alamofire/4.7.0'
+    family: 'tvOS'
+    major: '12'
+    minor: '1'
+    patch: '0'
+    patch_minor:
+
+  - user_agent_string: 'iTunes/12.7.1 (Windows; Microsoft Windows 7 Ultimate Edition Service Pack 1 (Build 7601)) AppleWebKit/7604.3005.2001.1'
+    family: 'Windows'
+    major: '7'
+    minor:
+    patch:
+    patch_minor:
+
+  - user_agent_string: 'iTunes/12.1.3 (Windows; Microsoft Windows XP Professional Service Pack 3 (Build 2600)) AppleWebKit/7600.1017.9000.3'
+    family: 'Windows'
+    major: 'XP'
+    minor:
+    patch:
+    patch_minor:
+
+  - user_agent_string: 'iTunes/12.1.3 (Windows; Microsoft Windows Vista Business Edition Service Pack 2 (Build 6002)) AppleWebKit/7600.1017.9000.3  '
+    family: 'Windows'
+    major: 'Vista'
+    minor:
+    patch:
+    patch_minor:
+
+  - user_agent_string: 'Mozilla/4.0 (compatible; MSIE 5.01; Windows 98; Linux 3.3.8-3.3) [Netgem; 7.7.01-51; i-Player; netbox; sezmi_totalgem]'
+    family: 'Windows'
+    major: '98'
+    minor:
+    patch:
+    patch_minor:
+
+  - user_agent_string: 'Mozilla/2.0 (compatible; MSIE 3.0; Windows 3.1)'
+    family: 'Windows'
+    major: '3.1'
+    minor:
+    patch:
+    patch_minor:
+
+  - user_agent_string: 'Mozilla/5.0 (Windows NT 4.0; rv:52.0) Gecko/20100101 Firefox/52.0'
+    family: 'Windows'
+    major: 'NT'
+    minor:
+    patch:
+    patch_minor:
+
+  - user_agent_string: 'Mozilla/4.0 (compatible; MSIE 5.0; Windows ME) Opera 5.11 [de]'
+    family: 'Windows'
+    major: 'ME'
+    minor:
+    patch:
+    patch_minor:
+
+  - user_agent_string: 'Microsoft Internet Explorer/1.0 (Windows 95)'
+    family: 'Windows'
+    major: '95'
+    minor:
+    patch:
+    patch_minor:
+
+  - user_agent_string: 'Mozilla/4.0 (compatible; MSIE 6.0; Windows CE,BrailleNote; IEMobile 7.11)'
+    family: 'Windows'
+    major: 'CE'
+    minor:
+    patch:
+    patch_minor:
+
+  - user_agent_string: 'Mozilla/5.0 (Windows 2000; U) Opera 7.0 [en]'
+    family: 'Windows'
+    major: '2000'
+    minor:
+    patch:
+    patch_minor:
diff -Nru uap-core-20181019/tests/test_ua.yaml uap-core-20190213/tests/test_ua.yaml
--- uap-core-20181019/tests/test_ua.yaml	2018-10-19 17:08:22.000000000 +0100
+++ uap-core-20190213/tests/test_ua.yaml	2019-02-13 17:27:26.000000000 +0000
@@ -1797,6 +1797,30 @@
     minor: '0'
     patch: '1'
 
+  - user_agent_string: 'Mozilla/5.0 (Windows NT 6.3; WOW64; Trident/7.0; rv:11.0) like Gecko PTST/1.0'
+    family: 'WebPageTest.org bot'
+    major: '1'
+    minor: '0'
+    patch: 
+
+  - user_agent_string: 'Mozilla/5.0 (Windows NT 6.2; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/64.0.3282.0 Safari/537.36 PTST/1.0'
+    family: 'WebPageTest.org bot'
+    major: '1'
+    minor: '0'
+    patch:
+
+  - user_agent_string: 'Mozilla/5.0 (Linux; Android 6.0.1; Moto G (4) Build/MPJ24.139-64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/65.0.3325.146 Mobile Safari/537.36 PTST/180521.140508'
+    family: 'WebPageTest.org bot'
+    major: '180521'
+    minor: '140508'
+    patch:
+
+  - user_agent_string: 'Mozilla/5.0 (X11; Datanyze; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/65.0.3325.181 Safari/537.36'
+    family: 'Datanyze'
+    major:
+    minor:
+    patch:
+
   - user_agent_string: 'CazoodleBot/CazoodleBot-0.1 (CazoodleBot Crawler; http://www.cazoodle.com/cazoodlebot; cazoodlebot@cazoodle.com)'
     family: 'CazoodleBot'
     major: '0'
@@ -4741,7 +4765,7 @@
     patch:
 
   - user_agent_string: 'FAST-mSEARCH Crawler 0.1 (bergum@fast.no)'
-    family: 'mSEARCH Crawler'
+    family: 'FAST-mSEARCH Crawler'
     major: '0'
     minor: '1'
     patch:
@@ -6908,6 +6932,18 @@
     minor: '45'
     patch: '2454'
 
+  - user_agent_string: 'Mozilla/5.0 (iPhone; CPU iPhone OS 11_0 like Mac OS X) AppleWebKit/604.1.38 (KHTML, like Gecko) Mobile/15A372 Safari Line/7.12.0'
+    family: 'LINE'
+    major: '7'
+    minor: '12'
+    patch: '0'
+
+  - user_agent_string: 'Mozilla/5.0 (Linux; Android 5.1; FTJ152B Build/LMY47D; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/51.0.2704.81 Mobile Safari/537.36 Line/6.4.1'
+    family: 'LINE'
+    major: '6'
+    minor: '4'
+    patch: '1'
+
   - user_agent_string: 'Mozilla/5.0 (Linux; Android 4.1.2; GT-S7710 Build/JZO54K) AppleWebKit/535.19 (KHTML, like Gecko) Chrome/18.0.1025.166 Mobile'
     family: 'Chrome Mobile'
     major: '18'
@@ -6929,6 +6965,18 @@
     patch: '0'
     patch_minor: '0'
 
+  - user_agent_string: 'Mozilla/5.0 (Linux; U; Android 6.0.1; ru-ru; Redmi 4 Build/MMB29M) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/61.0.3163.128 Mobile Safari/537.36 XiaoMi/MiuiBrowser/10.3.6-g'
+    family: 'MiuiBrowser'
+    major: '10'
+    minor: '3'
+    patch: '6'
+
+  - user_agent_string: 'Mozilla/5.0 (Linux; U; Android 7.1.2; ru-ru; Redmi 4A Build/N2G47H) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/61.0.3163.128 Mobile Safari/537.36 XiaoMi/Mint Browser/1.3.3'
+    family: 'Mint Browser'
+    major: '1'
+    minor: '3'
+    patch: '3'
+
   - user_agent_string: 'Mozilla/5.0 (Web0S; Linux/SmartTV) AppleWebKit/537.41 (KHTML, like Gecko) Large Screen WebAppManager Safari/537.41'
     family: 'Safari'
     major:
@@ -7724,3 +7772,45 @@
     minor: '0'
     patch: '169645775'
 
+  - user_agent_string: 'ViaFree-DK/3.8.3 (com.MTGx.ViaFree.dk; build:7383; iOS 12.1.0) Alamofire/4.7.0'
+    family: 'ViaFree'
+    major: '3'
+    minor: '8'
+    patch: '3'
+
+  - user_agent_string: 'Viafree-tvOS-DK/3.7.1 (com.MTGx.ViaFree.dk; build:7341; tvOS 12.1.0) Alamofire/4.7.0'
+    family: 'ViaFree'
+    major: '3'
+    minor: '7'
+    patch: '1'
+
+  - user_agent_string: 'OC/15.0.5071.1000 (Skype for Business)'
+    family: 'Skype'
+    major: '15'
+    minor: '0'
+    patch: '5071'
+    patch_minor: '1000'
+
+  - user_agent_string: 'Mozilla/5.0 (Linux; Android 8.1.0; TA-1024 Build/OPR1.170623.026; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/71.0.3578.99 Mobile Safari/537.36 GSA/8.65.5.21.arm64'
+    family: 'Google'
+    major: '8'
+    minor: '65'
+    patch: '5'
+
+  - user_agent_string: 'Mozilla/5.0 (Linux; Android 8.0.0; SM-G960F Build/R16NW; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/71.0.3578.99 Mobile Safari/537.36 GSA/8.65.5.21.arm64'
+    family: 'Google'
+    major: '8'
+    minor: '65'
+    patch: '5'
+
+  - user_agent_string: 'Mozilla/5.0 (Linux; Android 9; Pixel 3 Build/PQ1A.181205.006; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/71.0.3578.99 Mobile Safari/537.36 GSA/8.65.5.21.arm64'
+    family: 'Google'
+    major: '8'
+    minor: '65'
+    patch: '5'
+
+  - user_agent_string: 'Microsoft Office Word 2014'
+    family: 'Word'
+    major:
+    minor:
+    patch:
diff -Nru uap-core-20181019/.travis.yml uap-core-20190213/.travis.yml
--- uap-core-20181019/.travis.yml	2018-10-19 17:08:22.000000000 +0100
+++ uap-core-20190213/.travis.yml	2019-02-13 17:27:26.000000000 +0000
@@ -1,14 +1,13 @@
 sudo: false
 language: node_js
 node_js:
-  - 4
-  - 6
   - 8
+  - 10
   - node
 
 script:
   - "npm test"
-  
+
 notifications:
   irc: "chat.freenode.net#ua-parser"
 

--- End Message ---
--- Begin Message ---
Edward Betts:
> Package: release.debian.org
> Severity: normal
> User: release.debian.org@packages.debian.org
> Usertags: unblock
> 
> Dear Release Team,
> 
> Please consider unblocking package uap-core
> 
> This is a new release that fixes a A Regular Expression Denial of
> Service (ReDoS) bug: CVE-2018-20164.
> 
> https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=922717
> 
> I've attached the output from debdiff between the versions in testing
> and unstable.
> 
> Thanks,
> 
> Edward Betts
> 
> unblock uap-core/20190213-2
> 

Unblocked, thanks.
~Niels

--- End Message ---

Reply to: