diff --git a/regexes.yaml b/regexes.yaml
--- a/regexes.yaml
+++ b/regexes.yaml
@@ -1,9 +1,10 @@
 user_agent_parsers:
   #### SPECIAL CASES TOP ####
 
-  # must go before Opera
-  - regex: '^(Opera)/(\d+)\.(\d+) \(Nintendo Wii'
-    family_replacement: 'Wii'
+  # HbbTV standard defines what features the browser should understand.
+  # but it's like targeting "HTML5 browsers", effective browser support depends on the model
+  # See os_parsers if you want to target a specific TV
+  - regex: '(HbbTV)/(\d+)\.(\d+)\.(\d+) \('
 
   # must go before Firefox to catch SeaMonkey/Camino
   - regex: '(SeaMonkey|Camino)/(\d+)\.(\d+)\.?([ab]?\d+[a-z]*)'
@@ -65,17 +66,25 @@
   - regex: '(Opera Mini)/att/(\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+)'
+    family_replacement: 'Opera Mobile'
+
+  # Opera 15 for Desktop is similar to Chrome but includes an "OPR" Version string.
+  - regex: '(?:Chrome).*(OPR)/(\d+)\.(\d+)\.(\d+)'
+    family_replacement: 'Opera'
+
   # Palm WebOS looks a lot like Safari.
-  - regex: '(webOSBrowser)/(\d+)\.(\d+)'
-  - regex: '(webOS)/(\d+)\.(\d+)'
-    family_replacement: 'webOSBrowser'
-  - regex: '(wOSBrowser).+TouchPad/(\d+)\.(\d+)'
-    family_replacement: 'webOS TouchPad'
+  - regex: '(hpw|web)OS/(\d+)\.(\d+)(?:\.(\d+))?'
+    family_replacement: 'webOS Browser'
 
   # LuaKit has no version info.
   # http://luakit.org/projects/luakit/
   - regex: '(luakit)'
     family_replacement: 'LuaKit'
+    
+  # Snowshoe
+  - regex: '(Snowshoe)/(\d+)\.(\d+).(\d+)'
 
   # Lightning (for Thunderbird)
   # http://www.mozilla.org/projects/calendar/lightning/
@@ -88,6 +97,8 @@
     family_replacement: 'Swiftfox'
 
   # Rekonq
+  - regex: '(rekonq)/(\d+)\.(\d+)\.?(\d+)? Safari'
+    family_replacement: 'Rekonq'
   - regex: 'rekonq'
     family_replacement: 'Rekonq'
 
@@ -108,9 +119,6 @@
   # Bots
   - regex: '(YottaaMonitor|BrowserMob|HttpMonitor|YandexBot|Slurp|BingPreview|PagePeeker|ThumbShotsBot|WebThumb|URL2PNG|ZooShot|GomezA|Catchpoint bot|Willow Internet Crawler|Google SketchUp|Read%20Later)'
 
-  # must go before NetFront below
-  - regex: '(Kindle)/(\d+)\.(\d+)'
-
   - regex: '(Symphony) (\d+).(\d+)'
 
   - regex: '(Minimo)'
@@ -128,20 +136,23 @@
     family_replacement: 'Chrome Frame'
 
   # UC Browser
-  - regex: '(UC Browser)(\d+)\.(\d+)\.(\d+)'
+  - regex: '(UCBrowser)[ /](\d+)\.(\d+)\.(\d+)'
+    family_replacement: 'UC Browser'
+  - regex: '(UC Browser)[ /](\d+)\.(\d+)\.(\d+)'
+  - regex: '(UC Browser|UCBrowser|UCWEB)(\d+)\.(\d+)\.(\d+)'
+    family_replacement: 'UC Browser'
 
   # Tizen Browser (second case included in browser/major.minor regex)
   - regex: '(SLP Browser)/(\d+)\.(\d+)'
     family_replacement: 'Tizen Browser'
 
-  # Epiphany browser (identifies as Chromium)
-  - regex: '(Epiphany)/(\d+)\.(\d+).(\d+)'
-
   # Sogou Explorer 2.X
   - regex: '(SE 2\.X) MetaSr (\d+)\.(\d+)'
     family_replacement: 'Sogou Explorer'
-    
-  # Baidu Browser
+
+  # Baidu Browsers (desktop spoofs chrome & IE, explorer is mobile)
+  - regex: '(baidubrowser)[/\s](\d+)'
+    family_replacement: 'Baidu Browser'
   - regex: '(FlyFlow)/(\d+)\.(\d+)'
     family_replacement: 'Baidu Explorer'
 
@@ -157,24 +168,48 @@
   - regex: '(Twitterbot)/(\d+)\.(\d+)'
     family_replacement: 'TwitterBot'
 
+  # Rackspace Monitoring
+  - regex: '(Rackspace Monitoring)/(\d+)\.(\d+)'
+    family_replacement: 'RackspaceBot'
+
   # PyAMF
   - regex: '(PyAMF)/(\d+)\.(\d+)\.(\d+)'
 
+  # Yandex Browser
+  - regex: '(YaBrowser)/(\d+)\.(\d+)\.(\d+)'
+    family_replacement: 'Yandex Browser'
+
+  # Mail.ru Amigo/Internet Browser (Chromium-based)
+  - regex: '(Chrome)/(\d+)\.(\d+)\.(\d+).* MRCHROME'
+    family_replacement: 'Mail.ru Chromium Browser'
+
+  # AOL Browser (IE-based)
+  - regex: '(AOL) (\d+)\.(\d+); AOLBuild (\d+)'
+
   #### END SPECIAL CASES TOP ####
 
   #### MAIN CASES - this catches > 50% of all browsers ####
 
   # Browser/major_version.minor_version.beta_version
-  - regex: '(AdobeAIR|Chromium|FireWeb|Jasmine|ANTGalio|Midori|Fresco|Lobo|PaleMoon|Maxthon|Lynx|OmniWeb|Dillo|Camino|Demeter|Fluid|Fennec|Shiira|Sunrise|Chrome|Flock|Netscape|Lunascape|WebPilot|Vodafone|NetFront|Netfront|Konqueror|SeaMonkey|Kazehakase|Vienna|Iceape|Iceweasel|IceWeasel|Iron|K-Meleon|Sleipnir|Galeon|GranParadiso|Opera Mini|iCab|NetNewsWire|ThunderBrowse|Iris|UP\.Browser|Bunjaloo|Google Earth|Raven for Mac)/(\d+)\.(\d+)\.(\d+)'
+  - regex: '(AdobeAIR|FireWeb|Jasmine|ANTGalio|Midori|Fresco|Lobo|PaleMoon|Maxthon|Lynx|OmniWeb|Dillo|Camino|Demeter|Fluid|Fennec|Epiphany|Shiira|Sunrise|Flock|Netscape|Lunascape|WebPilot|Vodafone|NetFront|Netfront|Konqueror|SeaMonkey|Kazehakase|Vienna|Iceape|Iceweasel|IceWeasel|Iron|K-Meleon|Sleipnir|Galeon|GranParadiso|Opera Mini|iCab|NetNewsWire|ThunderBrowse|Iris|UP\.Browser|Bunjalloo|Google Earth|Raven for Mac|Openwave)/(\d+)\.(\d+)\.(\d+)'
 
+  # Chrome/Chromium/major_version.minor_version.beta_version
+  - regex: '(Chromium|Chrome)/(\d+)\.(\d+)\.(\d+)'
+
   # Browser/major_version.minor_version
-  - regex: '(Bolt|Jasmine|IceCat|Skyfire|Midori|Maxthon|Lynx|Arora|IBrowse|Dillo|Camino|Shiira|Fennec|Phoenix|Chrome|Flock|Netscape|Lunascape|Epiphany|WebPilot|Opera Mini|Opera|Vodafone|NetFront|Netfront|Konqueror|Googlebot|SeaMonkey|Kazehakase|Vienna|Iceape|Iceweasel|IceWeasel|Iron|K-Meleon|Sleipnir|Galeon|GranParadiso|iCab|NetNewsWire|Space Bison|Stainless|Orca|Dolfin|BOLT|Minimo|Tizen Browser|Polaris|Abrowser)/(\d+)\.(\d+)'
+  - regex: '(Bolt|Jasmine|IceCat|Skyfire|Midori|Maxthon|Lynx|Arora|IBrowse|Dillo|Camino|Shiira|Fennec|Phoenix|Chrome|Flock|Netscape|Lunascape|Epiphany|WebPilot|Opera Mini|Opera|Vodafone|NetFront|Netfront|Konqueror|Googlebot|SeaMonkey|Kazehakase|Vienna|Iceape|Iceweasel|IceWeasel|Iron|K-Meleon|Sleipnir|Galeon|GranParadiso|iCab|NetNewsWire|Space Bison|Stainless|Orca|Dolfin|BOLT|Minimo|Tizen Browser|Polaris|Abrowser|Planetweb|ICE Browser)/(\d+)\.(\d+)'
 
+  # Chrome/Chromium/major_version.minor_version
+  - regex: '(Chromium|Chrome)/(\d+)\.(\d+)'
+
   # 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|BREW) (\d+)\.(\d+)\.?(\d+)?'
-
+  - regex: '(iCab|Lunascape|Opera|Android|Jasmine|Polaris) (\d+)\.(\d+)\.?(\d+)?'
+  
+  # Kindle WebKit
+  - regex: '(Kindle)/(\d+)\.(\d+)'
+  
   # weird android UAs
   - regex: '(Android) Donut'
     v1_replacement: '1'
@@ -213,18 +248,32 @@
   - regex: '(Obigo)InternetBrowser'
   - regex: '(Obigo)\-Browser'
   - regex: '(Obigo|OBIGO)[^\d]*(\d+)(?:.(\d+))?'
+    family_replacement: 'Obigo'
 
   - regex: '(MAXTHON|Maxthon) (\d+)\.(\d+)'
     family_replacement: 'Maxthon'
   - regex: '(Maxthon|MyIE2|Uzbl|Shiira)'
     v1_replacement: '0'
 
-  - regex: '(PLAYSTATION) (\d+)'
-    family_replacement: 'PlayStation'
-  - regex: '(PlayStation Portable)[^\d]+(\d+).(\d+)'
+  - regex: 'PLAYSTATION 3.+WebKit'
+    family_replacement: 'NetFront NX'
+  - regex: 'PLAYSTATION 3'
+    family_replacement: 'NetFront'
+  - regex: '(PlayStation Portable)'
+    family_replacement: 'NetFront'
+  - regex: '(PlayStation Vita)'
+    family_replacement: 'NetFront NX'
+  
+  - regex: 'AppleWebKit.+ (NX)/(\d+)\.(\d+)\.(\d+)'
+    family_replacement: 'NetFront NX'
+  - regex: '(Nintendo 3DS)'
+    family_replacement: 'NetFront NX'
 
   - regex: '(BrowseX) \((\d+)\.(\d+)\.(\d+)'
 
+  - regex: '(NCSA_Mosaic)/(\d+)\.(\d+)'
+    family_replacement: 'NCSA Mosaic'
+
   # Polaris/d.d is above
   - regex: '(POLARIS)/(\d+)\.(\d+)'
     family_replacement: 'Polaris'
@@ -234,6 +283,9 @@
   - regex: '(BonEcho)/(\d+)\.(\d+)\.(\d+)'
     family_replacement: 'Bon Echo'
 
+  - regex: 'M?QQBrowser'
+    family_replacement: 'QQ Browser'
+
   - regex: '(iPod).+Version/(\d+)\.(\d+)\.(\d+)'
     family_replacement: 'Mobile Safari'
   - regex: '(iPod).*Version/(\d+)\.(\d+)'
@@ -252,36 +304,50 @@
     family_replacement: 'Mobile Safari'
 
   - regex: '(AvantGo) (\d+).(\d+)'
+  
+  - regex: '(OneBrowser)/(\d+).(\d+)'
+    family_replacement: 'ONE Browser'
 
   - regex: '(Avant)'
     v1_replacement: '1'
 
+  # This is the Tesla Model S (see similar entry in device parsers)
+  - regex: '(QtCarBrowser)'
+    v1_replacement: '1'
+
+  - regex: '(iBrowser/Mini)(\d+).(\d+)'
+    family_replacement: 'iBrowser Mini'
   # nokia browsers
   # based on: http://www.developer.nokia.com/Community/Wiki/User-Agent_headers_for_Nokia_devices
   - regex: '^(Nokia)'
     family_replacement: 'Nokia Services (WAP) Browser'
   - regex: '(NokiaBrowser)/(\d+)\.(\d+).(\d+)\.(\d+)'
+    family_replacement: 'Nokia Browser'
   - regex: '(NokiaBrowser)/(\d+)\.(\d+).(\d+)'
+    family_replacement: 'Nokia Browser'
   - regex: '(NokiaBrowser)/(\d+)\.(\d+)'
+    family_replacement: 'Nokia Browser'
   - regex: '(BrowserNG)/(\d+)\.(\d+).(\d+)'
-    family_replacement: 'NokiaBrowser'
+    family_replacement: 'Nokia Browser'
   - regex: '(Series60)/5\.0'
-    family_replacement: 'NokiaBrowser'
+    family_replacement: 'Nokia Browser'
     v1_replacement: '7'
     v2_replacement: '0'
   - regex: '(Series60)/(\d+)\.(\d+)'
     family_replacement: 'Nokia OSS Browser'
   - regex: '(S40OviBrowser)/(\d+)\.(\d+)\.(\d+)\.(\d+)'
-    family_replacement: 'Nokia Series 40 Ovi Browser'
+    family_replacement: 'Ovi Browser'
   - regex: '(Nokia)[EN]?(\d+)'
 
   # BlackBerry devices
+  - regex: '(BB10);'
+    family_replacement: 'BlackBerry WebKit'
   - regex: '(PlayBook).+RIM Tablet OS (\d+)\.(\d+)\.(\d+)'
-    family_replacement: 'Blackberry WebKit'
+    family_replacement: 'BlackBerry WebKit'
   - regex: '(Black[bB]erry).+Version/(\d+)\.(\d+)\.(\d+)'
-    family_replacement: 'Blackberry WebKit'
+    family_replacement: 'BlackBerry WebKit'
   - regex: '(Black[bB]erry)\s?(\d+)'
-    family_replacement: 'Blackberry'
+    family_replacement: 'BlackBerry'
 
   - regex: '(OmniWeb)/v(\d+)\.(\d+)'
 
@@ -291,6 +357,9 @@
   - regex: '(Pre)/(\d+)\.(\d+)'
     family_replacement: 'Palm Pre'
 
+  # fork of Links
+  - regex: '(ELinks)/(\d+)\.(\d+)'
+  - regex: '(ELinks) \((\d+)\.(\d+)'
   - regex: '(Links) \((\d+)\.(\d+)'
 
   - regex: '(QtWeb) Internet Browser/(\d+)\.(\d+)'
@@ -300,7 +369,11 @@
 
   # Amazon Silk, should go before Safari
   - regex: '(Silk)/(\d+)\.(\d+)(?:\.([0-9\-]+))?'
+    family_replacement: 'Amazon Silk'
 
+  # Phantomjs, should go before Safari
+  - regex: '(PhantomJS)/(\d+)\.(\d+)\.(\d+)'
+
   # WebKit Nightly
   - regex: '(AppleWebKit)/(\d+)\.?(\d+)?\+ .* Safari'
     family_replacement: 'WebKit Nightly'
@@ -320,14 +393,78 @@
 
   - regex: '(Teleca)'
     family_replacement: 'Teleca Browser'
+    
+  - regex: '(Phantom)/V(\d+)\.(\d+)'
+    family_replacement: 'Phantom Browser'
 
-  - regex: '(MSIE) (\d+)\.(\d+)'
+  - regex: '([MS]?IE) (\d+)\.(\d+)'
     family_replacement: 'IE'
 
-  - regex: '(Nintendo 3DS).* Version/(\d+)\.(\d+)(?:\.(\w+))'
+  - regex: 'Trident(.*)rv.(\d+)\.(\d+)'
+    family_replacement: 'IE'
 
+  - regex: '(python-requests)/(\d+)\.(\d+)'
+    family_replacement: 'Python Requests'
+
 os_parsers:
+  ##########
+  # HbbTV vendors
+  ##########
 
+  # starts with the easy one : Panasonic seems consistent across years, hope it will continue
+  #HbbTV/1.1.1 (;Panasonic;VIERA 2011;f.532;0071-0802 2000-0000;)
+  #HbbTV/1.1.1 (;Panasonic;VIERA 2012;1.261;0071-3103 2000-0000;)
+  #HbbTV/1.2.1 (;Panasonic;VIERA 2013;3.672;4101-0003 0002-0000;)
+  #- regex: 'HbbTV/\d+\.\d+\.\d+ \(;(Panasonic);VIERA ([0-9]{4});'
+
+  # Sony is consistent too but do not place year like the other
+  # Opera/9.80 (Linux armv7l; HbbTV/1.1.1 (; Sony; KDL32W650A; PKG3.211EUA; 2013;); ) Presto/2.12.362 Version/12.11
+  # Opera/9.80 (Linux mips; U;  HbbTV/1.1.1 (; Sony; KDL40HX751; PKG1.902EUA; 2012;);; en) Presto/2.10.250 Version/11.60
+  # Opera/9.80 (Linux mips; U;  HbbTV/1.1.1 (; Sony; KDL22EX320; PKG4.017EUA; 2011;);; en) Presto/2.7.61 Version/11.00
+  #- regex: 'HbbTV/\d+\.\d+\.\d+ \(; (Sony);.*;.*; ([0-9]{4});\)'
+
+
+  # LG is consistent too, but we need to add manually the year model
+  #Mozilla/5.0 (Unknown; Linux armv7l) AppleWebKit/537.1+ (KHTML, like Gecko) Safari/537.1+ HbbTV/1.1.1 ( ;LGE ;NetCast 4.0 ;03.20.30 ;1.0M ;)
+  #Mozilla/5.0 (DirectFB; Linux armv7l) AppleWebKit/534.26+ (KHTML, like Gecko) Version/5.0 Safari/534.26+ HbbTV/1.1.1 ( ;LGE ;NetCast 3.0 ;1.0 ;1.0M ;)
+  - regex: 'HbbTV/\d+\.\d+\.\d+ \( ;(LG)E ;NetCast 4.0'
+    os_v1_replacement: '2013'
+  - regex: 'HbbTV/\d+\.\d+\.\d+ \( ;(LG)E ;NetCast 3.0'
+    os_v1_replacement: '2012'
+
+  # Samsung is on its way of normalizing their user-agent
+  # HbbTV/1.1.1 (;Samsung;SmartTV2013;T-FXPDEUC-1102.2;;) WebKit
+  # HbbTV/1.1.1 (;Samsung;SmartTV2013;T-MST12DEUC-1102.1;;) WebKit
+  # HbbTV/1.1.1 (;Samsung;SmartTV2012;;;) WebKit
+  # HbbTV/1.1.1 (;;;;;) Maple_2011
+  - regex: 'HbbTV/1.1.1 \(;;;;;\) Maple_2011'
+    os_replacement: 'Samsung'
+    os_v1_replacement: '2011'
+  # manage the two models of 2013
+  - regex: 'HbbTV/\d+\.\d+\.\d+ \(;(Samsung);SmartTV([0-9]{4});.*FXPDEUC'
+    os_v2_replacement: 'UE40F7000'
+  - regex: 'HbbTV/\d+\.\d+\.\d+ \(;(Samsung);SmartTV([0-9]{4});.*MST12DEUC'
+    os_v2_replacement: 'UE32F4500'
+  # generic Samsung (works starting in 2012)
+  #- regex: 'HbbTV/\d+\.\d+\.\d+ \(;(Samsung);SmartTV([0-9]{4});'
+
+  # 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'
+    os_v1_replacement: '2013'
+  - regex: 'HbbTV/1.1.1 \(; (Philips);.*NETTV/3'
+    os_v1_replacement: '2012'
+  - 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
+  - regex: 'HbbTV/\d+\.\d+\.\d+.*(firetv)-firefox-plugin (\d+).(\d+).(\d+)'
+    os_replacement: 'FireHbbTV'
+
+  # generic HbbTV, hoping to catch manufacturer name (always after 2nd comma) and the first string that looks like a 2011-2019 year
+  - regex: 'HbbTV/\d+\.\d+\.\d+ \(.*; ?([a-zA-Z]+) ?;.*(201[1-9]).*\)'
+
   ##########
   # Android
   # can actually detect rooted android os. do we care?
@@ -355,6 +492,12 @@
     os_v1_replacement: '3'
 
   ##########
+  # Kindle Android
+  ##########
+  - regex: '(Silk-Accelerated=[a-z]{4,5})'
+    os_replacement: 'Android'
+
+  ##########
   # Windows
   # http://en.wikipedia.org/wiki/Windows_NT#Releases
   # possibility of false positive when different marketing names share same NT kernel
@@ -362,7 +505,6 @@
   # lots of ua strings have Windows NT 4.1 !?!?!?!? !?!? !? !????!?! !!! ??? !?!?! ?
   # (very) roughly ordered in terms of frequency of occurence of regex (win xp currently most frequent, etc)
   ##########
-  - regex: '(Windows Phone 6\.5)'
 
   - regex: '(Windows (?:NT 5\.2|NT 5\.1))'
     os_replacement: 'Windows XP'
@@ -370,7 +512,7 @@
   # ie mobile des ktop mode
   # spoofs nt 6.1. must come before windows 7
   - regex: '(XBLWP7)'
-    os_replacement: 'Windows Phone OS'
+    os_replacement: 'Windows Phone'
 
   - regex: '(Windows NT 6\.1)'
     os_replacement: 'Windows 7'
@@ -378,8 +520,14 @@
   - regex: '(Windows NT 6\.0)'
     os_replacement: 'Windows Vista'
 
-  - regex: '(Windows 98|Windows XP|Windows ME|Windows 95|Windows CE|Windows 7|Windows NT 4\.0|Windows Vista|Windows 2000)'
+  - regex: '(Win 9x 4\.90)'
+    os_replacement: 'Windows 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 RT'
+
   # is this a spoof or is nt 6.2 out and about in some capacity?
   - regex: '(Windows NT 6\.2)'
     os_replacement: 'Windows 8'
@@ -387,8 +535,8 @@
   - regex: '(Windows NT 5\.0)'
     os_replacement: 'Windows 2000'
 
-  - regex: '(Windows Phone OS) (\d+)\.(\d+)'
-
+  - regex: '(Windows Phone) (\d+)\.(\d+)'
+  - regex: '(Windows Phone) OS (\d+)\.(\d+)'
   - regex: '(Windows ?Mobile)'
     os_replacement: 'Windows Mobile'
 
@@ -404,13 +552,15 @@
   ##########
   - regex: '(Tizen)/(\d+)\.(\d+)'
 
-
-
   ##########
   # Mac OS
   # http://en.wikipedia.org/wiki/Mac_OS_X#Versions
   ##########
   - regex: '(Mac OS X) (\d+)[_.](\d+)(?:[_.](\d+))?'
+  
+  # IE on Mac doesn't specify version number
+  - regex: 'Mac_PowerPC'
+    os_replacement: 'Mac OS'
 
   # builds before tiger don't seem to specify version?
 
@@ -434,8 +584,6 @@
 
   - regex: '(AppleTV)/(\d+)\.(\d+)'
     os_replacement: 'ATV OS X'
-    os_v1_replacement: '$1'
-    os_v2_replacement: '$2'
 
   ##########
   # Chrome OS
@@ -449,9 +597,10 @@
   ##########
   # Linux distros
   ##########
-  - regex: '(Debian)-(\d+)\.(\d+)\.(\d+)(?:\.(\d+))?'
+  - regex: '([Dd]ebian)'
+    os_replacement: 'Debian'
   - regex: '(Linux Mint)(?:/(\d+))?'
-  - regex: '(Mandriva)(?: Linux)?/(\d+)\.(\d+)\.(\d+)(?:\.(\d+))?'
+  - regex: '(Mandriva)(?: Linux)?/(?:[\d.-]+m[a-z]{2}(\d+).(\d))?'
 
   ##########
   # Symbian + Symbian OS
@@ -470,10 +619,14 @@
   - regex: '(MeeGo)'
   - regex: 'Symbian [Oo][Ss]'
     os_replacement: 'Symbian OS'
+  - regex: 'Series40;'
+    os_replacement: 'Nokia Series 40'
 
   ##########
   # BlackBerry devices
   ##########
+  - regex: '(BB10);.+Version/(\d+)\.(\d+)\.(\d+)'
+    os_replacement: 'BlackBerry OS'
   - regex: '(Black[Bb]erry)[0-9a-z]+/(\d+)\.(\d+)\.(\d+)(?:\.(\d+))?'
     os_replacement: 'BlackBerry OS'
   - regex: '(Black[Bb]erry).+Version/(\d+)\.(\d+)\.(\d+)(?:\.(\d+))?'
@@ -483,31 +636,61 @@
   - regex: '(Play[Bb]ook)'
     os_replacement: 'BlackBerry Tablet OS'
   - regex: '(Black[Bb]erry)'
-    os_replacement: 'Blackberry OS'
+    os_replacement: 'BlackBerry OS'
 
   ##########
+  # Firefox OS
+  ##########
+  - regex: '\(Mobile;.+Firefox/\d+\.\d+'
+    os_replacement: 'Firefox OS'
+
+  ##########
+  # BREW
+  # yes, Brew is lower-cased for Brew MP
+  ##########
+  - regex: '(BREW)[ /](\d+)\.(\d+)\.(\d+)'
+  - regex: '(BREW);'
+  - regex: '(Brew MP|BMP)[ /](\d+)\.(\d+)\.(\d+)'
+    os_replacement: 'Brew MP'
+  - regex: 'BMP;'
+    os_replacement: 'Brew MP'
+
+  ##########
+  # Google TV
+  ##########
+  - regex: '(GoogleTV) (\d+)\.(\d+)\.(\d+)'
+  # Old style
+  - regex: '(GoogleTV)/[\da-z]+'
+
+  - regex: '(WebTV)/(\d+).(\d+)'
+  
+  ##########
   # Misc mobile
   ##########
-  - regex: '(webOS|hpwOS)/(\d+)\.(\d+)(?:\.(\d+))?'
+  - regex: '(hpw|web)OS/(\d+)\.(\d+)(?:\.(\d+))?'
     os_replacement: 'webOS'
+  - regex: '(VRE);'
 
   ##########
   # Generic patterns
   # since the majority of os cases are very specific, these go last
   ##########
   # first.second.third.fourth bits
-  - regex: '(SUSE|Fedora|Red Hat|PCLinuxOS)/(\d+)\.(\d+)\.(\d+)\.(\d+)'
+  - regex: '(Fedora|Red Hat|PCLinuxOS)/(\d+)\.(\d+)\.(\d+)\.(\d+)'
 
   # first.second.third bits
-  - regex: '(SUSE|Fedora|Red Hat|Puppy|PCLinuxOS|CentOS)/(\d+)\.(\d+)\.(\d+)'
+  - regex: '(Red Hat|Puppy|PCLinuxOS)/(\d+)\.(\d+)\.(\d+)'
 
   # first.second bits
   - regex: '(Ubuntu|Kindle|Bada|Lubuntu|BackTrack|Red Hat|Slackware)/(\d+)\.(\d+)'
-  - regex: '(PlayStation Vita) (\d+)\.(\d+)'
 
   # just os
-  - regex: '(Windows|OpenBSD|FreeBSD|NetBSD|Ubuntu|Kubuntu|Android|Arch Linux|CentOS|WeTab|Slackware)'
+  - regex: '(Windows|OpenBSD|FreeBSD|NetBSD|Android|WeTab)'
+  - regex: '(Ubuntu|Kubuntu|Arch Linux|CentOS|Slackware|Gentoo|openSUSE|SUSE|Red Hat|Fedora|PCLinuxOS|Gentoo|Mageia)'
+  - regex: '(Linux)/(\d+)\.(\d+)'
   - regex: '(Linux|BSD)'
+  - regex: 'SunOS'
+    os_replacement: 'Solaris'
 
 device_parsers:
   ##########
@@ -538,16 +721,16 @@
     device_replacement: 'HTC $1 (Sprint)'
   - regex: 'HTC ([A-Za-z0-9]+ [A-Z])'
     device_replacement: 'HTC $1'
-  - regex: 'HTC-([A-Za-z0-9]+)'
-    device_replacement: 'HTC $1'
-  - regex: 'HTC_([A-Za-z0-9]+)'
-    device_replacement: 'HTC $1'
-  - regex: 'HTC ([A-Za-z0-9]+)'
+  - regex: 'HTC[-_/\s]([A-Za-z0-9]+)'
     device_replacement: 'HTC $1'
   - regex: '(ADR[A-Za-z0-9]+)'
     device_replacement: 'HTC $1'
   - regex: '(HTC)'
 
+  # Tesla Model S
+  - regex: '(QtCarBrowser)'
+    device_replacement: 'Tesla Model S'
+
   # Samsung
   - regex: '(SamsungSGHi560)'
     device_replacement: 'Samsung SGHi560'
@@ -558,14 +741,43 @@
   - regex: 'SonyEricsson([A-Za-z0-9]+)/'
     device_replacement: 'Ericsson $1'
 
+  ##########
+  # PlayStation
+  # The Vita spoofs the Kindle
+  ##########
+  - regex: 'PLAYSTATION 3'
+    device_replacement: 'PlayStation 3'
+  - regex: '(PlayStation Portable)'
+  - regex: '(PlayStation Vita)'
+
+  ##########
+  # incomplete!
+  # Kindle
+  # http://amazonsilk.wordpress.com/useful-bits/silk-user-agent/
+  ##########
+  - regex: '(KFOT Build)'
+    device_replacement: 'Kindle Fire'
+  - regex: '(KFTT Build)'
+    device_replacement: 'Kindle Fire HD'
+  - regex: '(KFJWI Build)'
+    device_replacement: 'Kindle Fire HD 8.9" WiFi'
+  - regex: '(KFJWA Build)'
+    device_replacement: 'Kindle Fire HD 8.9" 4G'
+  - regex: '(Kindle Fire)'
+  - regex: '(Kindle)'
+  - regex: '(Silk)/(\d+)\.(\d+)(?:\.([0-9\-]+))?'
+    device_replacement: 'Kindle Fire'
+      
   #########
   # Android General Device Matching (far from perfect)
   #########
-  - regex: 'Android[\- ][\d]+\.[\d]+\; [A-Za-z]{2}\-[A-Za-z]{2}\; WOWMobile (.+) Build'
-  - regex: 'Android[\- ][\d]+\.[\d]+\.[\d]+; [A-Za-z]{2}\-[A-Za-z]{2}\; (.+) Build'
-  - regex: 'Android[\- ][\d]+\.[\d]+\-update1\; [A-Za-z]{2}\-[A-Za-z]{2}\; (.+) Build'
-  - regex: 'Android[\- ][\d]+\.[\d]+\; [A-Za-z]{2}\-[A-Za-z]{2}\; (.+) Build'
+  - regex: 'Android[\- ][\d]+\.[\d]+; [A-Za-z]{2}\-[A-Za-z]{0,2}; WOWMobile (.+) Build'
+  - regex: 'Android[\- ][\d]+\.[\d]+\-update1; [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'
+  - regex: 'Android[\- ][\d]+\.[\d]+\.[\d]+;[A-Za-z]{2}\-[A-Za-z]{0,2};(.+) Build'
+  - regex: 'Android[\- ][\d]+\.[\d]+; [A-Za-z]{2}\-[A-Za-z]{0,2}; (.+) Build'
   - regex: 'Android[\- ][\d]+\.[\d]+\.[\d]+; (.+) Build'
+  - regex: 'Android[\- ][\d]+\.[\d]+; (.+) Build'
 
   ##########
   # NOKIA
@@ -573,6 +785,8 @@
   ##########
   - regex: 'NokiaN([0-9]+)'
     device_replacement: 'Nokia N$1'
+  - regex: 'NOKIA([A-Za-z0-9\v-]+)'
+    device_replacement: 'Nokia $1'
   - regex: 'Nokia([A-Za-z0-9\v-]+)'
     device_replacement: 'Nokia $1'
   - regex: 'NOKIA ([A-Za-z0-9\-]+)'
@@ -585,14 +799,19 @@
     device_replacement: 'Nokia'
 
   ##########
-  # Blackberry
+  # BlackBerry
   # http://www.useragentstring.com/pages/BlackBerry/
   ##########
+  - regex: 'BB10; ([A-Za-z0-9\- ]+)\)'
+    device_replacement: 'BlackBerry $1'
   - regex: '(PlayBook).+RIM Tablet OS'
-    device_replacement: 'Blackberry Playbook'
-  - regex: '(Black[Bb]erry [0-9]+);'
+    device_replacement: 'BlackBerry Playbook'
+  - regex: 'Black[Bb]erry ([0-9]+);'
+    device_replacement: 'BlackBerry $1'
   - regex: 'Black[Bb]erry([0-9]+)'
     device_replacement: 'BlackBerry $1'
+  - regex: 'Black[Bb]erry;'
+    device_replacement: 'BlackBerry'
 
   ##########
   # PALM / HP
@@ -602,8 +821,8 @@
     device_replacement: 'Palm Pre'
   - regex: '(Pixi)/(\d+)\.(\d+)'
     device_replacement: 'Palm Pixi'
-  - regex: '(Touchpad)/(\d+)\.(\d+)'
-    device_replacement: 'HP Touchpad'
+  - regex: '(Touch[Pp]ad)/(\d+)\.(\d+)'
+    device_replacement: 'HP TouchPad'
   - regex: 'HPiPAQ([A-Za-z0-9]+)/(\d+).(\d+)'
     device_replacement: 'HP iPAQ $1'
   - regex: 'Palm([A-Za-z0-9]+)'
@@ -614,21 +833,6 @@
     device_replacement: 'HP Veer'
 
   ##########
-  # PlayStation
-  ##########
-  - regex: '(PlayStation Portable)'
-  - regex: '(PlayStation Vita)'
-  
-  ##########
-  # incomplete!
-  # Kindle
-  ##########
-  - regex: '(Kindle Fire)'
-  - regex: '(Kindle)'
-  - regex: '(Silk)/(\d+)\.(\d+)(?:\.([0-9\-]+))?'
-    device_replacement: 'Kindle Fire'
-
-  ##########
   # AppleTV
   # No built in browser that I can tell
   # Stack Overflow indicated iTunes-AppleTV/4.1 as a known UA for app available and I'm seeing it in live traffic
@@ -637,6 +841,16 @@
     device_replacement: 'AppleTV'
 
   ##########
+  # Catch the google mobile crawler before checking for iPhones.
+  ##########
+
+  - regex: 'AdsBot-Google-Mobile'
+    device_replacement: 'Spider'
+   
+  - regex: 'Googlebot-Mobile/(\d+).(\d+)'
+    device_replacement: 'Spider'
+    
+  ##########
   # complete but probably catches spoofs
   # iSTUFF
   ##########
@@ -644,6 +858,7 @@
   # cannot determine specific device type from ua string. (3g, 3gs, 4, etc)
   - regex: '(iPad) Simulator;'
   - regex: '(iPad);'
+  - regex: '(iPod) touch;'
   - regex: '(iPod);'
   - regex: '(iPhone) Simulator;'
   - regex: '(iPhone);'
@@ -656,7 +871,15 @@
   - regex: 'acer_([A-Za-z0-9]+)_'
     device_replacement: 'Acer $1'
 
+  ##########   
+  # Alcatel
   ##########
+  - regex: 'ALCATEL-([A-Za-z0-9]+)'
+    device_replacement: 'Alcatel $1'
+  - regex: 'Alcatel-([A-Za-z0-9]+)'
+    device_replacement: 'Alcatel $1'
+
+  ##########
   # Amoi
   ##########
   - regex: 'Amoi\-([A-Za-z0-9]+)'
@@ -693,14 +916,18 @@
   ##########
   - regex: 'DoCoMo/2\.0 ([A-Za-z0-9]+)'
     device_replacement: 'DoCoMo $1'
-  - regex: '([A-Za-z0-9]+)\_W\;FOMA'
+  - regex: '([A-Za-z0-9]+)_W\;FOMA'
     device_replacement: 'DoCoMo $1'
   - regex: '([A-Za-z0-9]+)\;FOMA'
     device_replacement: 'DoCoMo $1'
 
   ##########
-  # Huawei Vodafone
+  # Huawei
   ##########
+  - regex: 'Huawei([A-Za-z0-9]+)'
+    device_replacement: 'Huawei $1'
+  - regex: 'HUAWEI-([A-Za-z0-9]+)'
+    device_replacement: 'Huawei $1'
   - regex: 'vodafone([A-Za-z0-9]+)'
     device_replacement: 'Huawei Vodafone $1'
 
@@ -723,10 +950,16 @@
   ##########
   - regex: 'Lenovo\-([A-Za-z0-9]+)'
     device_replacement: 'Lenovo $1'
-  - regex: 'Lenovo\_([A-Za-z0-9]+)'
+  - regex: 'Lenovo_([A-Za-z0-9]+)'
     device_replacement: 'Lenovo $1'
 
   ##########
+  # HbbTV (European and Australian standard)
+  # written before the LG regexes, as LG is making HbbTV too
+  ##########
+  - regex: '(HbbTV)/[0-9]+\.[0-9]+\.[0-9]+'
+
+  ##########
   # lg
   ##########
   - regex: 'LG/([A-Za-z0-9]+)'
@@ -764,8 +997,22 @@
     device_replacement: 'Motorola $1'
   - regex: 'MOT\-([A-Za-z0-9]+)'
     device_replacement: 'Motorola $1'
+    
+  ##########
+  # nintendo
+  ##########
+  - regex: '(Nintendo WiiU)'
+    device_replacement: 'Nintendo Wii U'
+  - regex: 'Nintendo (DS|3DS|DSi|Wii);'
+    device_replacement: 'Nintendo $1'
 
   ##########
+  # pantech
+  ##########
+  - regex: 'Pantech([A-Za-z0-9]+)'
+    device_replacement: 'Pantech $1'
+ 
+  ##########
   # philips
   ##########
   - regex: 'Philips([A-Za-z0-9]+)'
@@ -782,6 +1029,12 @@
     device_replacement: 'Samsung $1'
 
   ##########
+  # Sega
+  ##########
+  - regex: 'Dreamcast'
+    device_replacement: 'Sega Dreamcast'
+
+  ##########
   # Softbank
   ##########
   - regex: 'Softbank/1\.0/([A-Za-z0-9]+)'
@@ -790,10 +1043,9 @@
     device_replacement: 'Softbank $1'
 
   ##########
-  # Sony
+  # WebTV
   ##########
-  - regex: '(PlayStation3 PPC)'
-    device_replacement: 'Playstation 3'
+  - regex: '(WebTV)/(\d+).(\d+)'
 
   ##########
   # Generic Smart Phone
@@ -804,58 +1056,18 @@
   ##########
   # Generic Feature Phone
   ##########
-  - regex: '^(1207|3gso|4thp|501i|502i|503i|504i|505i|506i|6310|6590|770s|802s|a wa|acer|acs\-|airn|alav|asus|attw|au\-m|aur |aus |abac|acoo|aiko|alco|alca|amoi|anex|anny|anyw|aptu|arch|argo|bell|bird|bw\-n|bw\-u|beck|benq|bilb|blac|c55/|cdm\-|chtm|capi|comp|cond|craw|dall|dbte|dc\-s|dica|ds\-d|ds12|dait|devi|dmob|doco|dopo|el49|erk0|esl8|ez40|ez60|ez70|ezos|ezze|elai|emul|eric|ezwa|fake|fly\-|fly\_|g\-mo|g1 u|g560|gf\-5|grun|gene|go.w|good|grad|hcit|hd\-m|hd\-p|hd\-t|hei\-|hp i|hpip|hs\-c|htc |htc\-|htca|htcg)'
+  - regex: '^(1207|3gso|4thp|501i|502i|503i|504i|505i|506i|6310|6590|770s|802s|a wa|acer|acs\-|airn|alav|asus|attw|au\-m|aur |aus |abac|acoo|aiko|alco|alca|amoi|anex|anny|anyw|aptu|arch|argo|bell|bird|bw\-n|bw\-u|beck|benq|bilb|blac|c55/|cdm\-|chtm|capi|comp|cond|craw|dall|dbte|dc\-s|dica|ds\-d|ds12|dait|devi|dmob|doco|dopo|el49|erk0|esl8|ez40|ez60|ez70|ezos|ezze|elai|emul|eric|ezwa|fake|fly\-|fly_|g\-mo|g1 u|g560|gf\-5|grun|gene|go.w|good|grad|hcit|hd\-m|hd\-p|hd\-t|hei\-|hp i|hpip|hs\-c|htc |htc\-|htca|htcg)'
     device_replacement: 'Generic Feature Phone'
-  - regex: '^(htcp|htcs|htct|htc\_|haie|hita|huaw|hutc|i\-20|i\-go|i\-ma|i230|iac|iac\-|iac/|ig01|im1k|inno|iris|jata|java|kddi|kgt|kgt/|kpt |kwc\-|klon|lexi|lg g|lg\-a|lg\-b|lg\-c|lg\-d|lg\-f|lg\-g|lg\-k|lg\-l|lg\-m|lg\-o|lg\-p|lg\-s|lg\-t|lg\-u|lg\-w|lg/k|lg/l|lg/u|lg50|lg54|lge\-|lge/|lynx|leno|m1\-w|m3ga|m50/|maui|mc01|mc21|mcca|medi|meri|mio8|mioa|mo01|mo02|mode|modo|mot |mot\-|mt50|mtp1|mtv |mate|maxo|merc|mits|mobi|motv|mozz|n100|n101|n102|n202|n203|n300|n302|n500|n502|n505|n700|n701|n710|nec\-|nem\-|newg|neon)'
+  - regex: '^(htcp|htcs|htct|htc_|haie|hita|huaw|hutc|i\-20|i\-go|i\-ma|i230|iac|iac\-|iac/|ig01|im1k|inno|iris|jata|java|kddi|kgt|kgt/|kpt |kwc\-|klon|lexi|lg g|lg\-a|lg\-b|lg\-c|lg\-d|lg\-f|lg\-g|lg\-k|lg\-l|lg\-m|lg\-o|lg\-p|lg\-s|lg\-t|lg\-u|lg\-w|lg/k|lg/l|lg/u|lg50|lg54|lge\-|lge/|lynx|leno|m1\-w|m3ga|m50/|maui|mc01|mc21|mcca|medi|meri|mio8|mioa|mo01|mo02|mode|modo|mot |mot\-|mt50|mtp1|mtv |mate|maxo|merc|mits|mobi|motv|mozz|n100|n101|n102|n202|n203|n300|n302|n500|n502|n505|n700|n701|n710|nec\-|nem\-|newg|neon)'
     device_replacement: 'Generic Feature Phone'
   - regex: '^(netf|noki|nzph|o2 x|o2\-x|opwv|owg1|opti|oran|ot\-s|p800|pand|pg\-1|pg\-2|pg\-3|pg\-6|pg\-8|pg\-c|pg13|phil|pn\-2|pt\-g|palm|pana|pire|pock|pose|psio|qa\-a|qc\-2|qc\-3|qc\-5|qc\-7|qc07|qc12|qc21|qc32|qc60|qci\-|qwap|qtek|r380|r600|raks|rim9|rove|s55/|sage|sams|sc01|sch\-|scp\-|sdk/|se47|sec\-|sec0|sec1|semc|sgh\-|shar|sie\-|sk\-0|sl45|slid|smb3|smt5|sp01|sph\-|spv |spv\-|sy01|samm|sany|sava|scoo|send|siem|smar|smit|soft|sony|t\-mo|t218|t250|t600|t610|t618|tcl\-|tdg\-|telm|tim\-|ts70|tsm\-|tsm3|tsm5|tx\-9|tagt)'
     device_replacement: 'Generic Feature Phone'
-  - regex: '^(talk|teli|topl|tosh|up.b|upg1|utst|v400|v750|veri|vk\-v|vk40|vk50|vk52|vk53|vm40|vx98|virg|vite|voda|vulc|w3c |w3c\-|wapj|wapp|wapu|wapm|wig |wapi|wapr|wapv|wapy|wapa|waps|wapt|winc|winw|wonu|x700|xda2|xdag|yas\-|your|zte\-|zeto|aste|audi|avan|blaz|brew|brvw|bumb|ccwa|cell|cldc|cmd\-|dang|eml2|fetc|hipt|http|ibro|idea|ikom|ipaq|jbro|jemu|jigs|keji|kyoc|kyok|libw|m\-cr|midp|mmef|moto|mwbp|mywa|newt|nok6|o2im|pant|pdxg|play|pluc|port|prox|rozo|sama|seri|smal|symb|treo|upsi|vx52|vx53|vx60|vx61|vx70|vx80|vx81|vx83|vx85|wap\-|webc|whit|wmlb|xda\-|xda\_)'
+  - regex: '^(talk|teli|topl|tosh|up.b|upg1|utst|v400|v750|veri|vk\-v|vk40|vk50|vk52|vk53|vm40|vx98|virg|vite|voda|vulc|w3c |w3c\-|wapj|wapp|wapu|wapm|wig |wapi|wapr|wapv|wapy|wapa|waps|wapt|winc|winw|wonu|x700|xda2|xdag|yas\-|your|zte\-|zeto|aste|audi|avan|blaz|brew|brvw|bumb|ccwa|cell|cldc|cmd\-|dang|eml2|fetc|hipt|http|ibro|idea|ikom|ipaq|jbro|jemu|jigs|keji|kyoc|kyok|libw|m\-cr|midp|mmef|moto|mwbp|mywa|newt|nok6|o2im|pant|pdxg|play|pluc|port|prox|rozo|sama|seri|smal|symb|treo|upsi|vx52|vx53|vx60|vx61|vx70|vx80|vx81|vx83|vx85|wap\-|webc|whit|wmlb|xda\-|xda_)'
     device_replacement: 'Generic Feature Phone'
 
   ##########
   # Spiders (this is hack...)
   ##########
-  - regex: '(bot|borg|google(^tv)|yahoo|slurp|msnbot|msrbot|openbot|archiver|netresearch|lycos|scooter|altavista|teoma|gigabot|baiduspider|blitzbot|oegp|charlotte|furlbot|http%20client|polybot|htdig|ichiro|mogimogi|larbin|pompos|scrubby|searchsight|seekbot|semanticdiscovery|silk|snappy|speedy|spider|voila|vortex|voyager|zao|zeal|fast\-webcrawler|converacrawler|dataparksearch|findlinks)'
+  - regex: '(bot|borg|google(^tv)|yahoo|slurp|msnbot|msrbot|openbot|archiver|netresearch|lycos|scooter|altavista|teoma|gigabot|baiduspider|blitzbot|oegp|charlotte|furlbot|http%20client|polybot|htdig|ichiro|mogimogi|larbin|pompos|scrubby|searchsight|seekbot|semanticdiscovery|silk|snappy|speedy|spider|voila|vortex|voyager|zao|zeal|fast\-webcrawler|converacrawler|dataparksearch|findlinks|crawler)'
     device_replacement: 'Spider'
 
-
-mobile_user_agent_families:
-  - 'Firefox Mobile'
-  - 'Opera Mobile'
-  - 'Opera Mini'
-  - 'Mobile Safari'
-  - 'webOS'
-  - 'IE Mobile'
-  - 'Playstation Portable'
-  - 'Nokia'
-  - 'Blackberry'
-  - 'Palm'
-  - 'Silk'
-  - 'Android'
-  - 'Maemo'
-  - 'Obigo'
-  - 'Netfront'
-  - 'AvantGo'
-  - 'Teleca'
-  - 'SEMC-Browser'
-  - 'Bolt'
-  - 'Iris'
-  - 'UP.Browser'
-  - 'Symphony'
-  - 'Minimo'
-  - 'Bunjaloo'
-  - 'Jasmine'
-  - 'Dolfin'
-  - 'Polaris'
-  - 'BREW'
-  - 'Chrome Mobile'
-  - 'UC Browser'
-  - 'Tizen Browser'
-
-# Some select mobile OSs report a desktop browser.
-# make sure we note they're mobile
-mobile_os_families:
-  - 'Windows Phone 6.5'
-  - 'Windows CE'
-  - 'Symbian OS'
diff --git a/src/Web/UAParser/Core.hs b/src/Web/UAParser/Core.hs
--- a/src/Web/UAParser/Core.hs
+++ b/src/Web/UAParser/Core.hs
@@ -84,10 +84,10 @@
 -- | Results datatype for the parsed User-Agent
 data UAResult = UAResult {
       uarFamily :: Text
-    , uarV1 :: Maybe Text
-    , uarV2 :: Maybe Text
-    , uarV3 :: Maybe Text
-    } deriving (Show, Eq, Typeable, Data)
+    , uarV1     :: Maybe Text
+    , uarV2     :: Maybe Text
+    , uarV3     :: Maybe Text
+    } deriving (Show, Read, Eq, Typeable, Data)
 
 
 -------------------------------------------------------------------------------
@@ -137,11 +137,11 @@
 -- | Result type for 'parseOS'
 data OSResult = OSResult {
       osrFamily :: Text
-    , osrV1 :: Maybe Text
-    , osrV2 :: Maybe Text
-    , osrV3 :: Maybe Text
-    , osrV4 :: Maybe Text
-    } deriving (Show,Eq,Typeable,Data)
+    , osrV1     :: Maybe Text
+    , osrV2     :: Maybe Text
+    , osrV3     :: Maybe Text
+    , osrV4     :: Maybe Text
+    } deriving (Show,Read,Eq,Typeable,Data)
 
 instance Default OSResult where
     def = OSResult "" Nothing Nothing Nothing Nothing
@@ -171,32 +171,32 @@
 -------------------------------------------------------------------------------
 -- | User-Agent string parser data
 data UAConfig = UAConfig {
-      uaParsers :: [UAParser]
-    , osParsers :: [OSParser]
+      uaParsers  :: [UAParser]
+    , osParsers  :: [OSParser]
     , devParsers :: [DevParser]
     } deriving (Eq,Show)
 
 
 -------------------------------------------------------------------------------
 data UAParser = UAParser {
-      uaRegex :: Regex
+      uaRegex  :: Regex
     , uaFamRep :: Maybe Text
-    , uaV1Rep :: Maybe Text
+    , uaV1Rep  :: Maybe Text
     } deriving (Eq,Show)
 
 
 -------------------------------------------------------------------------------
 data OSParser = OSParser {
-      osRegex :: Regex
+      osRegex  :: Regex
     , osFamRep :: Maybe Text
-    , osRep1 :: Maybe Text
-    , osRep2 :: Maybe Text
+    , osRep1   :: Maybe Text
+    , osRep2   :: Maybe Text
     } deriving (Eq,Show)
 
 
 data DevParser = DevParser {
       devRegex :: Regex
-    , devRep :: Maybe Text
+    , devRep   :: Maybe Text
     } deriving (Eq,Show)
 
 
diff --git a/test/src/TestSuite.hs b/test/src/TestSuite.hs
new file mode 100644
--- /dev/null
+++ b/test/src/TestSuite.hs
@@ -0,0 +1,200 @@
+{-# LANGUAGE OverloadedStrings #-}
+{-# LANGUAGE RecordWildCards   #-}
+{-# LANGUAGE TemplateHaskell   #-}
+
+module Main where
+
+
+-------------------------------------------------------------------------------
+import           Control.Applicative
+import           Control.DeepSeq
+import           Control.Monad
+import           Criterion.Main                 as C
+import           Data.Aeson
+import           Data.ByteString.Char8          (ByteString)
+import           Data.DeriveTH
+import           Data.Text                      (Text)
+import qualified Data.Text                      as T
+import qualified Data.Text.Encoding             as T
+import           Data.Yaml
+import           System.Environment
+import           System.FilePath.Posix
+import           Test.Framework                 (defaultMain, testGroup)
+import           Test.Framework                 as T
+import           Test.Framework.Providers.HUnit as T
+import           Test.HUnit                     hiding (Test, path)
+import           Text.Regex.PCRE.Light
+-------------------------------------------------------------------------------
+import           Web.UAParser.Core
+-------------------------------------------------------------------------------
+
+
+-------------------------------------------------------------------------------
+main = do
+  arg <- getArgs
+  case arg of
+    ["bench"] -> benchMain
+    _ -> testMain
+
+
+
+                              ------------------
+                              -- Benchmarking --
+                              ------------------
+
+
+-------------------------------------------------------------------------------
+benchMain = do
+  conf <- loadConfig "../regexes.yaml"
+  cases <- loadTests "test_user_agent_parser.yaml"
+  cases2 <- loadTests "firefox_user_agent_strings.yaml"
+  let allC = cases ++ cases2
+      ua = bench "UA Parsing" $ nf (map (parseUA conf . uatcString)) allC
+  print $ show (length allC) ++ " strings being parsed."
+  C.defaultMain [ua]
+
+
+
+                                 -------------
+                                 -- Testing --
+                                 -------------
+
+
+testMain = T.defaultMain tests
+    where
+      tests =
+        [ uaTests
+        , osTests ]
+
+
+                               ----------------
+                               -- UA Testing --
+                               ----------------
+
+
+-------------------------------------------------------------------------------
+uaTests = buildTest $ do
+  conf <- loadConfig "../regexes.yaml"
+  cases <- loadTests "test_user_agent_parser.yaml"
+  cases2 <- loadTests "firefox_user_agent_strings.yaml"
+  let allC = cases ++ cases2
+  return $ testGroup "UA Parsing Tests" $ map (testUAParser conf) allC
+
+
+
+-------------------------------------------------------------------------------
+testUAParser :: UAConfig -> UserAgentTestCase -> Test
+testUAParser config UATC{..} = testCase tn $ do
+  case parsed of
+    Nothing -> assertFailure "Can't produce UAResult"
+    Just UAResult{..} -> do
+     assertEqual "family is same" uatcFamily uarFamily
+     -- assertEqual "v1 is the same" uatcV1 uarV1
+     -- assertEqual "v2 is the same" uatcV2 uarV2
+     -- assertEqual "v3 is the same" uatcV3 uarV3
+  where
+    parsed = parseUA config uatcString
+    tn = T.unpack $ T.intercalate "/" ["UA Test: ", uatcFamily, m uatcV1, m uatcV2, m uatcV3]
+    m x = maybe "-" id x
+
+
+                               ----------------
+                               -- OS Testing --
+                               ----------------
+
+
+
+-------------------------------------------------------------------------------
+osTests = buildTest $ do
+  conf <- loadConfig "../regexes.yaml"
+  cases <- loadTests "test_user_agent_parser_os.yaml"
+  return $ testGroup "OS Parsing Tests" $ map (testOSParser conf) cases
+
+
+
+-------------------------------------------------------------------------------
+testOSParser :: UAConfig -> OSTestCase -> Test
+testOSParser config OSTC{..} = testCase tn $ do
+  case parsed of
+    Nothing -> assertFailure "Can't produce OSResult"
+    Just OSResult{..} -> do
+     assertEqual "family is same" ostcFamily osrFamily
+     assertEqual "major is the same" ostcV1 osrV1
+     assertEqual "minor is the same" ostcV2  osrV2
+     assertEqual "patch is the same" ostcV3  osrV3
+     assertEqual "patch_minor is the same" ostcV4  osrV4
+  where
+    parsed = parseOS config ostcString
+    tn = T.unpack $ T.intercalate "/"
+         ["OS Test: ", ostcFamily, m ostcV1, m ostcV2, m ostcV3, m ostcV4]
+    m x = maybe "-" id x
+
+
+
+
+                           ------------------------
+                           -- Loading Test Cases --
+                           ------------------------
+
+
+
+-------------------------------------------------------------------------------
+loadTests :: FromJSON a => FilePath -> IO a
+loadTests fp = parseMonad p =<< either error id `fmap` decodeFile' fp'
+  where
+    fp' = "../test_resources" </> fp
+    p (Object x) = x .: "test_cases"
+
+
+-------------------------------------------------------------------------------
+data UserAgentTestCase = UATC {
+      uatcString :: ByteString
+    , uatcFamily :: Text
+    , uatcV1     :: Maybe Text
+    , uatcV2     :: Maybe Text
+    , uatcV3     :: Maybe Text
+    } deriving (Show)
+
+
+-------------------------------------------------------------------------------
+instance FromJSON UserAgentTestCase where
+    parseJSON (Object v) =
+      UATC <$> v .: "user_agent_string"
+           <*> (v .: "family" <|> return "")
+           <*> (v .:? "v1" <|> return Nothing)
+           <*> (v .:? "v2" <|> return Nothing)
+           <*> (v .:? "v3" <|> return Nothing)
+
+
+-------------------------------------------------------------------------------
+data OSTestCase = OSTC {
+      ostcString :: ByteString
+    , ostcFamily :: Text
+    , ostcV1     :: Maybe Text
+    , ostcV2     :: Maybe Text
+    , ostcV3     :: Maybe Text
+    , ostcV4     :: Maybe Text
+    } deriving (Show)
+
+
+-------------------------------------------------------------------------------
+instance FromJSON OSTestCase where
+    parseJSON (Object v) =
+      OSTC <$> (v .: "user_agent_string" <|> return "")
+           <*> (v .: "family" <|> return "")
+           <*> nonBlank (v .:? "major" <|> return Nothing)
+           <*> nonBlank (v .:? "minor" <|> return Nothing)
+           <*> nonBlank (v .:? "patch" <|> return Nothing)
+           <*> nonBlank (v .:? "patch_minor" <|> return Nothing)
+
+-------------------------------------------------------------------------------
+nonBlank f = do
+  res <- f
+  return $ case res of
+    Just "" -> Nothing
+    Just x -> Just x
+    Nothing -> Nothing
+
+
+
+$(derives [makeNFData] [''UAResult])
diff --git a/ua-parser.cabal b/ua-parser.cabal
--- a/ua-parser.cabal
+++ b/ua-parser.cabal
@@ -1,6 +1,6 @@
 Name:                ua-parser
 Description:         Please refer to the git/github README on the project for example usage.
-Version:             0.2.1
+Version:             0.3
 Synopsis:            Port of ua-parser in Haskell
 License:             BSD3
 License-file:        LICENSE
@@ -8,7 +8,7 @@
 Maintainer:          ozgun.ataman@soostone.com
 Category:            Web
 Build-type:          Simple
-Cabal-version:       >=1.6
+Cabal-version:       >=1.8
 
 data-files: ./*.yaml
 
@@ -38,3 +38,30 @@
     , syb
 
   ghc-options: -O2 -Wall  
+
+
+test-suite test
+  type: exitcode-stdio-1.0
+  main-is: TestSuite.hs
+  hs-source-dirs: src test/src
+  ghc-options: -O2 -Wall -fwarn-tabs
+
+  Build-depends:       
+      base
+    , bytestring
+    , text
+    , criterion
+    , deepseq
+    , derive
+    , HUnit
+    , pcre-light
+    , yaml >= 0.7
+    , aeson
+    , test-framework
+    , test-framework-hunit
+    , test-framework-quickcheck2
+    , data-default
+    , syb
+    , filepath
+
+
