Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/matomo-org/matomo.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authormattab <matthieu.aubry@gmail.com>2013-05-24 15:23:17 +0400
committermattab <matthieu.aubry@gmail.com>2013-05-24 15:23:17 +0400
commit58c88c1b2980ee1c02a47cb3d35de1480402e6ac (patch)
treeb77a766fece69ee3888c4003799483da687b2619
parent4f4d377876adcf698c00ca2141f9cff26bf75a83 (diff)
Refs #3612
* making tests pass! * enabling DevicesDetection tests, even though DevicesDetection plugin is disabled by default.
-rw-r--r--core/Tracker.php30
-rw-r--r--libs/UserAgentParser/UserAgentParser.php9
-rw-r--r--plugins/DevicesDetection/DevicesDetection.php4
-rw-r--r--plugins/DevicesDetection/UserAgentParserEnhanced/UserAgentParserEnhanced.php1455
-rw-r--r--plugins/DevicesDetection/UserAgentParserEnhanced/regexes/browsers.yml814
-rw-r--r--plugins/DevicesDetection/UserAgentParserEnhanced/regexes/mobiles.yml1914
-rw-r--r--plugins/DevicesDetection/UserAgentParserEnhanced/regexes/oss.yml852
-rw-r--r--plugins/DevicesDetection/UserAgentParserEnhanced/spyc.php2090
-rw-r--r--plugins/DevicesDetection/functions.php12
-rw-r--r--plugins/DevicesDetection/lang/en.php2
-rwxr-xr-xtests/LocalTracker.php1
-rw-r--r--tests/PHPUnit/Core/PluginsFunctions/WidgetsListTest.php8
-rw-r--r--tests/PHPUnit/Core/SegmentTest.php5
-rwxr-xr-xtests/PHPUnit/IntegrationTestCase.php2
-rwxr-xr-xtests/PHPUnit/proxy/piwik.php7
15 files changed, 3622 insertions, 3583 deletions
diff --git a/core/Tracker.php b/core/Tracker.php
index 89fa433836..625d7d2175 100644
--- a/core/Tracker.php
+++ b/core/Tracker.php
@@ -46,6 +46,7 @@ class Piwik_Tracker
static protected $forcedVisitorId = null;
static protected $pluginsNotToLoad = array();
+ static protected $pluginsToLoad = array();
/**
* The set of visits to track.
@@ -126,6 +127,17 @@ class Piwik_Tracker
return self::$pluginsNotToLoad;
}
+ static public function getPluginsToLoad()
+ {
+ return self::$pluginsToLoad;
+ }
+ static public function setPluginsToLoad($plugins)
+ {
+ self::$pluginsToLoad = $plugins;
+ }
+
+
+
/**
* Update Tracker config
*
@@ -357,6 +369,7 @@ class Piwik_Tracker
$pluginsToLoad = Piwik_Config::getInstance()->Plugins['Plugins'];
$pluginsForcedNotToLoad = Piwik_Tracker::getPluginsNotToLoad();
$pluginsToLoad = array_diff($pluginsToLoad, $pluginsForcedNotToLoad);
+ $pluginsToLoad = array_merge($pluginsToLoad, Piwik_Tracker::getPluginsToLoad());
$pluginsManager->loadPlugins($pluginsToLoad);
}
}
@@ -589,15 +602,15 @@ class Piwik_Tracker
}
try {
- $pluginsTracker = Piwik_Config::getInstance()->Plugins_Tracker;
- if (is_array($pluginsTracker)
- && count($pluginsTracker) != 0
- ) {
- $pluginsTracker['Plugins_Tracker'] = array_diff($pluginsTracker['Plugins_Tracker'], self::getPluginsNotToLoad());
+ $pluginsTracker = Piwik_Config::getInstance()->Plugins_Tracker['Plugins_Tracker'];
+ if (count($pluginsTracker) > 0) {
+ $pluginsTracker = $pluginsTracker;
+ $pluginsTracker = array_diff($pluginsTracker, self::getPluginsNotToLoad());
Piwik_PluginsManager::getInstance()->doNotLoadAlwaysActivatedPlugins();
- Piwik_PluginsManager::getInstance()->loadPlugins($pluginsTracker['Plugins_Tracker']);
- printDebug("Loading plugins: { " . implode(",", $pluginsTracker['Plugins_Tracker']) . " }");
+ Piwik_PluginsManager::getInstance()->loadPlugins($pluginsTracker);
+
+ printDebug("Loading plugins: { " . implode(",", $pluginsTracker) . " }");
}
} catch (Exception $e) {
printDebug("ERROR: " . $e->getMessage());
@@ -757,6 +770,9 @@ class Piwik_Tracker
// Disable provider plugin, because it is so slow to do reverse ip lookup in dev environment somehow
self::setPluginsNotToLoad($pluginsDisabled);
+
+ // we load 'DevicesDetection' in tests only (disabled by default)
+ self::setPluginsToLoad( array('DevicesDetection') );
}
}
diff --git a/libs/UserAgentParser/UserAgentParser.php b/libs/UserAgentParser/UserAgentParser.php
index c65ed056f6..85c9225cc5 100644
--- a/libs/UserAgentParser/UserAgentParser.php
+++ b/libs/UserAgentParser/UserAgentParser.php
@@ -653,6 +653,11 @@ class UserAgentParser
if (isset(self::$browserIdToName[$browserId])) {
return self::$browserIdToName[$browserId];
}
+ if(class_exists('UserAgentParserEnhanced')) {
+ if( !empty(UserAgentParserEnhanced::$browsers[$browserId])) {
+ return UserAgentParserEnhanced::$browsers[$browserId];
+ }
+ }
return false;
}
@@ -684,6 +689,10 @@ class UserAgentParser
if (isset(self::$operatingSystemsIdToName[$osId])) {
return self::$operatingSystemsIdToName[$osId];
}
+
+ if(class_exists('UserAgentParserEnhanced')) {
+ return UserAgentParserEnhanced::getOsNameFromId($osId);
+ }
return false;
}
diff --git a/plugins/DevicesDetection/DevicesDetection.php b/plugins/DevicesDetection/DevicesDetection.php
index e9cb732e8c..d18f768b21 100644
--- a/plugins/DevicesDetection/DevicesDetection.php
+++ b/plugins/DevicesDetection/DevicesDetection.php
@@ -21,8 +21,8 @@ class Piwik_DevicesDetection extends Piwik_Plugin
public function getInformation()
{
return array(
- 'description' => Piwik_Translate("DevicesDetection_description"),
- 'author' => 'Clearcode.cc',
+ 'description' => "[Beta Plugin] " . Piwik_Translate("DevicesDetection_description"),
+ 'author' => 'Piwik and Clearcode.cc',
'author_homepage' => 'http://clearcode.cc',
'version' => '1.12-b6',
'TrackerPlugin' => true,
diff --git a/plugins/DevicesDetection/UserAgentParserEnhanced/UserAgentParserEnhanced.php b/plugins/DevicesDetection/UserAgentParserEnhanced/UserAgentParserEnhanced.php
index 9031b0fd33..f107455ad9 100644
--- a/plugins/DevicesDetection/UserAgentParserEnhanced/UserAgentParserEnhanced.php
+++ b/plugins/DevicesDetection/UserAgentParserEnhanced/UserAgentParserEnhanced.php
@@ -1,722 +1,735 @@
-<?php
-
-/**
- * Piwik - Open source web analytics
- *
- * @link http://piwik.org
- * @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
- *
- * @category Piwik_Plugins
- * @package Piwik_DevicesDetection
- */
-//yml parser
-require_once('spyc.php');
-
-class UserAgentParserEnhanced
-{
-
- public static $deviceTypes = array('car browser', 'console', 'desktop', 'feature phone', 'smartphone', 'tablet', 'tv');
- public static $deviceBrands = array(
- 'AC' => 'Acer',
- 'AI' => 'Airness',
- 'AL' => 'Alcatel',
- 'AO' => 'Amoi',
- 'AP' => 'Apple',
- 'AU' => 'Asus',
- 'AV' => 'Avvio',
- 'AX' => 'Audiovox',
- 'BE' => 'Becker',
- 'BI' => 'Bird',
- 'BL' => 'Beetel',
- 'BQ' => 'BenQ',
- 'BS' => 'BenQ-Siemens',
- 'CK' => 'Cricket',
- 'CL' => 'Compal',
- 'CT' => 'Capitel',
- 'DB' => 'Dbtel',
- 'DC' => 'DoCoMo',
- 'DI' => 'Dicam',
- 'DL' => 'Dell',
- 'DP' => 'Dopod',
- 'EC' => 'Ericsson',
- 'EI' => 'Ezio',
- 'ER' => 'Ericy',
- 'ET' => 'eTouch',
- 'EZ' => 'Ezze',
- 'FL' => 'Fly',
- 'GI' => 'Gionee',
- 'GO' => 'Google',
- 'GR' => 'Gradiente',
- 'GU' => 'Grundig',
- 'HA' => 'Haier',
- 'HP' => 'HP',
- 'HT' => 'HTC',
- 'HU' => 'Huawei',
- 'IK' => 'iKoMo',
- 'IM' => 'i-mate',
- 'IN' => 'Innostream',
- 'IO' => 'i-mobile',
- 'IQ' => 'INQ',
- 'KA' => 'Karbonn',
- 'KD' => 'KDDI',
- 'KN' => 'Kindle',
- 'KO' => 'Konka',
- 'KY' => 'Kyocera',
- 'LA' => 'Lanix',
- 'LC' => 'LCT',
- 'LE' => 'Lenovo',
- 'LG' => 'LG',
- 'LU' => 'LGUPlus',
- 'MI' => 'MicroMax',
- 'MO' => 'Mio',
- 'MR' => 'Motorola',
- 'MS' => 'Microsoft',
- 'MT' => 'Mitsubishi',
- 'MY' => 'MyPhone',
- 'NE' => 'NEC',
- 'NG' => 'NGM',
- 'NI' => 'Nintendo',
- 'NK' => 'Nokia',
- 'NW' => 'Newgen',
- 'NX' => 'Nexian',
- 'OD' => 'Onda',
- 'OP' => 'OPPO',
- 'OR' => 'Orange',
- 'OT' => 'O2',
- 'PA' => 'Panasonic',
- 'PH' => 'Philips',
- 'PM' => 'Palm',
- 'PO' => 'phoneOne',
- 'PT' => 'Pantech',
- 'QT' => 'Qtek',
- 'RM' => 'RIM',
- 'RO' => 'Rover',
- 'SA' => 'Samsung',
- 'SD' => 'Sega',
- 'SE' => 'Sony Ericsson',
- 'SF' => 'Softbank',
- 'SG' => 'Sagem',
- 'SH' => 'Sharp',
- 'SI' => 'Siemens',
- 'SN' => 'Sendo',
- 'SO' => 'Sony',
- 'SP' => 'Spice',
- 'SY' => 'Sanyo',
- 'TA' => 'Tesla',
- 'TC' => 'TCL',
- 'TE' => 'Telit',
- 'TH' => 'TiPhone',
- 'TI' => 'TIANYU',
- 'TM' => 'T-Mobile',
- 'TO' => 'Toplux',
- 'TS' => 'Toshiba',
- 'UT' => 'UTStarcom',
- 'VD' => 'Videocon',
- 'VE' => 'Vertu',
- 'VI' => 'Vitelcom',
- 'VK' => 'VK Mobile',
- 'VO' => 'Voxtel',
- 'WB' => 'Web TV',
- 'WE' => 'WellcoM',
- 'WO' => 'Wonu',
- 'XX' => 'Unknown',
- 'ZO' => 'Zonda',
- 'ZT' => 'ZTE',
- );
- public static $osShorts = array(
- 'AIX' => 'AIX',
- 'Android' => 'AND',
- 'Apple TV' => 'ATV',
- 'Arch Linux' => 'ARL',
- 'BackTrack' => 'BTR',
- 'Bada' => 'SBA',
- 'BlackBerry OS' => 'BLB',
- 'BlackBerry Tablet OS' => 'QNX',
- 'Bot' => 'BOT',
- 'Brew' => 'BMP',
- 'CentOS' => 'CES',
- 'Chrome OS' => 'COS',
- 'Debian' => 'DEB',
- 'DragonFly' => 'DFB',
- 'Fedora' => 'FED',
- 'Firefox OS' => 'FOS',
- 'FreeBSD' => 'BSD',
- 'Gentoo' => 'GNT',
- 'Google TV' => 'GTV',
- 'HP-UX' => 'HPX',
- 'IRIX' => 'IRI',
- 'Knoppix' => 'KNO',
- 'Kubuntu' => 'KBT',
- 'Linux' => 'LIN',
- 'Lubuntu' => 'LBT',
- 'Mac' => 'MAC',
- 'Mandriva' => 'MDR',
- 'MeeGo' => 'SMG',
- 'Mint' => 'MIN',
- 'NetBSD' => 'NBS',
- 'Nintendo' => 'WII',
- 'Nintendo Mobile' => 'NDS',
- 'OS/2' => 'OS2',
- 'OSF1' => 'T64',
- 'OpenBSD' => 'OBS',
- 'PlayStation' => 'PSP',
- 'PlayStation 3' => 'PS3',
- 'Presto' => 'PRS',
- 'Puppy' => 'PPY',
- 'Red Hat' => 'RHT',
- 'SUSE' => 'SSE',
- 'Slackware' => 'SLW',
- 'Solaris' => 'SOS',
- 'Syllable' => 'SYL',
- 'Symbian' => 'SYM',
- 'Symbian OS' => 'SYS',
- 'Symbian OS Series 40' => 'S40',
- 'Symbian OS Series 60' => 'S60',
- 'Symbian^3' => 'SY3',
- 'Talkatone' => 'TKT',
- 'Tizen' => 'TIZ',
- 'Ubuntu' => 'UBT',
- 'WebTV' => 'WTV',
- 'WinWAP' => 'WWP',
- 'Windows' => 'WIN',
- 'Windows 2000' => 'W2K',
- 'Windows 3.1' => 'W31',
- 'Windows 7' => 'WI7',
- 'Windows 8' => 'WI8',
- 'Windows 95' => 'W95',
- 'Windows 98' => 'W98',
- 'Windows CE' => 'WCE',
- 'Windows ME' => 'WME',
- 'Windows Mobile' => 'WMO',
- 'Windows NT' => 'WNT',
- 'Windows Phone' => 'WPH',
- 'Windows RT' => 'WRT',
- 'Windows Server 2003' => 'WS3',
- 'Windows Vista' => 'WVI',
- 'Windows XP' => 'WXP',
- 'Xbox' => 'XBX',
- 'Xubuntu' => 'XBT',
- 'YunOs' => 'YNS',
- 'iOS' => 'IOS',
- 'palmOS' => 'POS',
- 'webOS' => 'WOS'
- );
- protected static $desktopOsArray = array('IBM', 'Linux', 'Mac', 'Unix', 'Windows');
- public static $osFamilies = array(
- 'Android' => array('AND'),
- 'Apple TV' => array('ATV'),
- 'BlackBerry' => array('BLB'),
- 'Bot' => array('BOT'),
- 'Brew' => array('BMP'),
- 'Chrome OS' => array('COS'),
- 'Firefox OS' => array('FOS'),
- 'Gaming Console' => array('WII', 'PS3'),
- 'Google TV' => array('GTV'),
- 'IBM' => array('OS2'),
- 'iOS' => array('IOS'),
- 'Linux' => array('LIN', 'ARL', 'DEB', 'KNO', 'MIN', 'UBT', 'KBT', 'XBT', 'LBT', 'FED', 'RHT', 'MDR', 'GNT', 'SLW', 'SSE', 'PPY', 'CES', 'BTR', 'YNS', 'PRS'),
- 'Mac' => array('MAC'),
- 'Mobile Gaming Console' => array('PSP', 'NDS', 'XBX'),
- 'Other Mobile' => array('WOS', 'POS', 'QNX', 'SBA', 'TIZ'),
- 'Simulator' => array('TKT', 'WWP'),
- 'Symbian' => array('SYM', 'SYS', 'SY3', 'S60', 'S40', 'SMG'),
- 'Unix' => array('SOS', 'AIX', 'HPX', 'BSD', 'NBS', 'OBS', 'DFB', 'SYL', 'IRI', 'T64'),
- 'WebTV' => array('WTV'),
- 'Windows' => array('WI8', 'WI7', 'WVI', 'WS3', 'WXP', 'W2K', 'WNT', 'WME', 'W98', 'W95', 'WRT', 'W31', 'WIN'),
- 'Windows Mobile' => array('WPH', 'WMO', 'WCE')
- );
- public static $browserFamilies = array(
- 'Android Browser' => array('AN'),
- 'BlackBerry Browser' => array('BB'),
- 'Chrome' => array('CH', 'CM', 'CI', 'CF', 'CR', 'RM'),
- 'Firefox' => array('FF', 'FE', 'SX', 'FB', 'PX', 'MB'),
- 'Internet Explorer' => array('IE', 'IM'),
- 'Konqueror' => array('KO'),
- 'NetFront' => array('NF'),
- 'Nokia Browser' => array('NB'),
- 'Opera' => array('OP', 'OM', 'OI'),
- 'Safari' => array('SF', 'MF')
- );
- public static $browsers = array(
- 'AB' => 'ABrowse',
- 'AM' => 'Amaya',
- 'AN' => 'Android Browser',
- 'AR' => 'Arora',
- 'AV' => 'Amiga Voyager',
- 'AW' => 'Amiga Aweb',
- 'BB' => 'BlackBerry Browser',
- 'BD' => 'Baidu Browser',
- 'BE' => 'Beonex',
- 'BX' => 'BrowseX',
- 'CA' => 'Camino',
- 'CF' => 'Chrome Frame',
- 'CH' => 'Chrome',
- 'CI' => 'Chrome Mobile iOS',
- 'CK' => 'Conkeror',
- 'CM' => 'Chrome Mobile',
- 'CO' => 'CometBird',
- 'CR' => 'Chromium',
- 'CS' => 'Cheshire',
- 'DF' => 'Dolphin',
- 'DI' => 'Dillo',
- 'EL' => 'Elinks',
- 'EP' => 'Epiphany',
- 'FB' => 'Firebird',
- 'FD' => 'Fluid',
- 'FE' => 'Fennec',
- 'FF' => 'Firefox',
- 'FL' => 'Flock',
- 'FN' => 'Fireweb Navigator',
- 'GA' => 'Galeon',
- 'GE' => 'Google Earth',
- 'HJ' => 'HotJava',
- 'IB' => 'IBrowse',
- 'IC' => 'iCab',
- 'IE' => 'Internet Explorer',
- 'IM' => 'IE Mobile',
- 'IR' => 'Iron',
- 'JS' => 'Jasmine',
- 'KI' => 'Kindle Browser',
- 'KM' => 'K-meleon',
- 'KO' => 'Konqueror',
- 'KP' => 'Kapiko',
- 'KZ' => 'Kazehakase',
- 'LG' => 'Lightning',
- 'LI' => 'Links',
- 'LX' => 'Lynx',
- 'MB' => 'MicroB',
- 'MC' => 'NCSA Mosaic',
- 'MF' => 'Mobile Safari',
- 'MI' => 'Midori',
- 'MS' => 'Mobile Silk',
- 'MX' => 'Maxthon',
- 'NB' => 'Nokia Browser',
- 'NF' => 'NetFront',
- 'NL' => 'NetFront Life',
- 'NS' => 'Netscape',
- 'OB' => 'Obigo',
- 'OI' => 'Opera Mini',
- 'OM' => 'Opera Mobile',
- 'OP' => 'Opera',
- 'OV' => 'Openwave Mobile Browser',
- 'OW' => 'OmniWeb',
- 'PL' => 'Palm Blazer',
- 'PR' => 'Palm Pre',
- 'PX' => 'Phoenix',
- 'RK' => 'Rekonq',
- 'RM' => 'RockMelt',
- 'SF' => 'Safari',
- 'SM' => 'SeaMonkey',
- 'SN' => 'Snowshoe',
- 'SX' => 'Swiftfox',
- 'TZ' => 'Tizen Browser',
- 'UC' => 'UC Browser',
- 'WO' => 'wOSBrowser',
- 'YA' => 'Yandex Browser'
- );
-
- const UNKNOWN = "UNK";
- protected static $regexesDir = '/regexes/';
- protected static $osRegexesFile = 'oss.yml';
- protected static $browserRegexesFile = 'browsers.yml';
- protected static $mobileRegexesFile = 'mobiles.yml';
- protected $userAgent;
- protected $os;
- protected $browser;
- protected $device;
- protected $brand;
- protected $model;
- protected $debug = false;
-
- public function __construct($userAgent)
- {
- $this->userAgent = $userAgent;
- }
-
- protected function getOsRegexes()
- {
- return Spyc::YAMLLoad(__DIR__ . self::$regexesDir . self::$osRegexesFile);
- }
-
- protected function getBrowserRegexes()
- {
- return Spyc::YAMLLoad(__DIR__ . self::$regexesDir . self::$browserRegexesFile);
- }
-
- protected function getMobileRegexes()
- {
- return Spyc::YAMLLoad(__DIR__ . self::$regexesDir . self::$mobileRegexesFile);
- }
-
- public function parse()
- {
- $this->parseOs();
- if ($this->isBot() || $this->isSimulator())
- return;
-
- $this->parseBrowser();
-
- if ($this->isMobile()) {
- $this->parseMobile();
- } else {
- $this->device = array_search('desktop', self::$deviceTypes);
- }
- if ($this->debug) {
- var_dump($this->brand, $this->model, $this->device);
- }
- }
-
- protected function parseOs()
- {
- foreach ($this->getOsRegexes() as $osRegex) {
- $matches = $this->matchUserAgent($osRegex['regex']);
- if ($matches)
- break;
- }
-
- if (!$matches)
- return;
-
- if (in_array($osRegex['name'], self::$osShorts)) {
- $short = self::$osShorts[$osRegex['name']];
- } else {
- $short = 'UNK';
- }
-
- $this->os = array(
- 'name' => $this->buildOsName($osRegex['name'], $matches),
- 'short_name' => $short,
- 'version' => $this->buildOsVersion($osRegex['version'], $matches)
- );
-
- if (array_key_exists($this->os['name'], self::$osShorts)) {
- $this->os['short_name'] = self::$osShorts[$this->os['name']];
- }
- }
-
- protected function parseBrowser()
- {
- foreach ($this->getBrowserRegexes() as $browserRegex) {
- $matches = $this->matchUserAgent($browserRegex['regex']);
- if ($matches)
- break;
- }
-
- if (!$matches)
- return;
-
- if (in_array($browserRegex['name'], self::$browsers)) {
- $short = array_search($browserRegex['name'], self::$browsers);
- } else {
- $short = 'XX';
- }
-
- $this->browser = array(
- 'name' => $this->buildBrowserName($browserRegex['name'], $matches),
- 'short_name' => $short,
- 'version' => $this->buildBrowserVersion($browserRegex['version'], $matches)
- );
- }
-
- protected function parseMobile()
- {
- $mobileRegexes = $this->getMobileRegexes();
- $this->parseBrand($mobileRegexes);
- $this->parseModel($mobileRegexes);
- }
-
- protected function parseBrand($mobileRegexes)
- {
- foreach ($mobileRegexes as $brand => $mobileRegex) {
- $matches = $this->matchUserAgent($mobileRegex['regex']);
- if ($matches)
- break;
- }
-
- if (!$matches)
- return;
- $this->brand = array_search($brand, self::$deviceBrands);
- $this->fullName = $brand;
-
- if (isset($mobileRegex['device'])) {
- $this->device = array_search($mobileRegex['device'],self::$deviceTypes);
- }
-
- if (isset($mobileRegex['model'])) {
- $this->model = $this->buildModel($mobileRegex['model'], $matches);
- }
- }
-
- protected function parseModel($mobileRegexes)
- {
- if (empty($this->brand) || !empty($this->model))
- return;
-
- foreach ($mobileRegexes[$this->fullName]['models'] as $modelRegex) {
- $matches = $this->matchUserAgent($modelRegex['regex']);
- if ($matches)
- break;
- }
-
- if (!$matches) {
- return;
- }
-
- $this->model = $this->buildModel($modelRegex['model'], $matches);
-
- if (isset($modelRegex['device'])) {
- $this->device = array_search($modelRegex['device'], self::$deviceTypes);
- }
- }
-
- protected function matchUserAgent($regex)
- {
- $regex = '/' . str_replace('/', '\/', $regex) . '/i';
-
- if (preg_match($regex, $this->userAgent, $matches)) {
- return $matches;
- }
-
- return false;
- }
-
- protected function buildOsName($osName, $matches)
- {
- return $this->buildByMatch($osName, $matches);
- }
-
- protected function buildOsVersion($osVersion, $matches)
- {
- $osVersion = $this->buildByMatch($osVersion, $matches);
-
- $osVersion = $this->buildByMatch($osVersion, $matches, '2');
-
- $osVersion = str_replace('_', '.', $osVersion);
-
- return $osVersion;
- }
-
- protected function buildBrowserName($browserName, $matches)
- {
- return $this->buildByMatch($browserName, $matches);
- }
-
- protected function buildBrowserVersion($browserVersion, $matches)
- {
- $browserVersion = $this->buildByMatch($browserVersion, $matches);
-
- $browserVersion = $this->buildByMatch($browserVersion, $matches, '2');
-
- $browserVersion = str_replace('_', '.', $browserVersion);
-
- return $browserVersion;
- }
-
- protected function buildModel($model, $matches)
- {
- $model = $this->buildByMatch($model, $matches);
-
- $model = $this->buildByMatch($model, $matches, '2');
-
- $model = $this->buildModelExceptions($model);
-
- $model = str_replace('_', ' ', $model);
-
- return $model;
- }
-
- protected function buildModelExceptions($model)
- {
- if ($this->brand == 'O2') {
- $model = preg_replace('/([a-z])([A-Z])/', '$1 $2', $model);
- $model = ucwords(str_replace('_', ' ', $model));
- }
-
- return $model;
- }
-
- /**
- * This method is used in this class for processing results of pregmatch
- * results into string containing recognized information.
- *
- * General algorithm:
- * Parsing UserAgent string consists of trying to match it against list of
- * regular expressions for three different information:
- * browser + version,
- * OS + version,
- * device manufacturer + model.
- *
- * After match has been found iteration stops, and results are processed
- * by buildByMatch.
- * As $item we get decoded name (name of browser, name of OS, name of manufacturer).
- * In array $match we recieve preg_match results containing whole string matched at index 0
- * and following matches in further indexes. Desired action now is to concatenate
- * decoded name ($item) with matches found. First step is to append first found match,
- * which is located in index=1 (that's why $nb is 1 by default).
- * In other cases, where whe know that preg_match may return more than 1 result,
- * we call buildByMatch with $nb = 2 or more, depending on what will be returned from
- * regular expression.
- *
- * Example:
- * We are parsing UserAgent of Firefox 20.0 browser.
- * UserAgentParserEnhanced calls buildBrowserName() and buildBrowserVersion() in order
- * to retrieve those information.
- * In buildBrowserName() we only have one call of buildByMatch, where passed argument
- * is regular expression testing given string for browser name. In this case, we are only
- * interrested in first hit, so no $nb parameter will be set to 1. After finding match, and calling
- * buildByMatch - we will receive just the name of browser.
- *
- * Also after decoding browser we will get list of regular expressions for this browser name
- * testing UserAgent string for version number. Again we iterate over this list, and after finding first
- * occurence - we break loop and proceed to build by match. Since browser regular expressions can
- * contain two hits (major version and minor version) in function buildBrowserVersion() we have
- * two calls to buildByMatch, one without 3rd parameter, and second with $nb set to 2.
- * This way we can retrieve version number, and assign it to object property.
- *
- * In case of mobiles.yml this schema slightly varies, but general idea is the same.
- *
- * @param string $item
- * @param array $matches
- * @param int $nb
- * @return type
- */
- protected function buildByMatch($item, $matches, $nb = '1')
- {
- if (strpos($item, '$' . $nb) === false)
- return $item;
-
- $replace = isset($matches[$nb]) ? $matches[$nb] : '';
- return trim(str_replace('$' . $nb, $replace, $item));
- }
-
- public function isBot()
- {
- $decodedFamily = '';
- if (in_array($this->getOs('name'), self::$osShorts)) {
- $osShort = self::$osShorts[$this->getOs('name')];
- } else {
- $osShort = '';
- }
- foreach (self::$osFamilies as $family => $familyOs) {
- if (in_array($osShort, $familyOs)) {
- $decodedFamily = $family;
- break;
- }
- }
-
- return $decodedFamily == 'Bot';
- }
-
- public function isSimulator()
- {
- $decodedFamily = '';
- if (in_array($this->getOs('name'), self::$osShorts)) {
- $osShort = self::$osShorts[$this->getOs('name')];
- } else {
- $osShort = '';
- }
- foreach (self::$osFamilies as $family => $familyOs) {
- if (in_array($osShort, $familyOs)) {
- $decodedFamily = $family;
- break;
- }
- }
- return $decodedFamily == 'Simulator';
- }
-
- public function isMobile()
- {
- return !$this->isDesktop();
- }
-
- public function isDesktop()
- {
- $osName = $this->getOs('name');
- if (empty($osName) || empty(self::$osShorts[$osName])) {
- return false;
- }
-
- $osShort = self::$osShorts[$osName];
- foreach (self::$osFamilies as $family => $familyOs) {
- if (in_array($osShort, $familyOs)) {
- $decodedFamily = $family;
- break;
- }
- }
- return in_array($decodedFamily, self::$desktopOsArray);
- }
-
- public function getOs($attr = '')
- {
- if ($attr == '') {
- return $this->os;
- }
-
- if (!isset($this->os[$attr])) {
- return self::UNKNOWN;
- }
-
- if ($attr == 'version') {
- $this->os['version'] = $this->os['version'];
- }
- return $this->os[$attr];
- }
-
- public function getBrowser($attr = '')
- {
- if ($attr == '') {
- return $this->browser;
- }
-
- if (!isset($this->browser[$attr])) {
- return self::UNKNOWN;
- }
-
- return $this->browser[$attr];
- }
-
- public function getDevice()
- {
- return $this->device;
- }
-
- public function getBrand()
- {
- return $this->brand;
- }
-
- public function getModel()
- {
- return $this->model;
- }
-
- public function getUserAgent()
- {
- return $this->userAgent;
- }
-
- public static function getOsFamily($osLabel)
- {
- $osShortName = substr($osLabel, 0, 3);
-
- foreach (self::$osFamilies as $osFamily => $osShortNames) {
- if (in_array($osShortName, $osShortNames)) {
- return $osFamily;
- }
- }
-
- return 'Other';
- }
-
- public static function getBrowserFamily($browserLabel)
- {
- foreach (self::$browserFamilies as $browserFamily => $browserShortNames) {
- if (in_array($browserLabel, $browserShortNames)) {
- return $browserFamily;
- }
- }
-
- return 'Other';
- }
-
+<?php
+
+/**
+ * Piwik - Open source web analytics
+ *
+ * @link http://piwik.org
+ * @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
+ *
+ * @category Piwik_Plugins
+ * @package Piwik_DevicesDetection
+ */
+//yml parser
+require_once('spyc.php');
+
+class UserAgentParserEnhanced
+{
+
+ public static $deviceTypes = array('car browser', 'console', 'desktop', 'feature phone', 'smartphone', 'tablet', 'tv');
+ public static $deviceBrands = array(
+ 'AC' => 'Acer',
+ 'AI' => 'Airness',
+ 'AL' => 'Alcatel',
+ 'AO' => 'Amoi',
+ 'AP' => 'Apple',
+ 'AU' => 'Asus',
+ 'AV' => 'Avvio',
+ 'AX' => 'Audiovox',
+ 'BE' => 'Becker',
+ 'BI' => 'Bird',
+ 'BL' => 'Beetel',
+ 'BQ' => 'BenQ',
+ 'BS' => 'BenQ-Siemens',
+ 'CK' => 'Cricket',
+ 'CL' => 'Compal',
+ 'CT' => 'Capitel',
+ 'DB' => 'Dbtel',
+ 'DC' => 'DoCoMo',
+ 'DI' => 'Dicam',
+ 'DL' => 'Dell',
+ 'DP' => 'Dopod',
+ 'EC' => 'Ericsson',
+ 'EI' => 'Ezio',
+ 'ER' => 'Ericy',
+ 'ET' => 'eTouch',
+ 'EZ' => 'Ezze',
+ 'FL' => 'Fly',
+ 'GI' => 'Gionee',
+ 'GO' => 'Google',
+ 'GR' => 'Gradiente',
+ 'GU' => 'Grundig',
+ 'HA' => 'Haier',
+ 'HP' => 'HP',
+ 'HT' => 'HTC',
+ 'HU' => 'Huawei',
+ 'IK' => 'iKoMo',
+ 'IM' => 'i-mate',
+ 'IN' => 'Innostream',
+ 'IO' => 'i-mobile',
+ 'IQ' => 'INQ',
+ 'KA' => 'Karbonn',
+ 'KD' => 'KDDI',
+ 'KN' => 'Kindle',
+ 'KO' => 'Konka',
+ 'KY' => 'Kyocera',
+ 'LA' => 'Lanix',
+ 'LC' => 'LCT',
+ 'LE' => 'Lenovo',
+ 'LG' => 'LG',
+ 'LU' => 'LGUPlus',
+ 'MI' => 'MicroMax',
+ 'MO' => 'Mio',
+ 'MR' => 'Motorola',
+ 'MS' => 'Microsoft',
+ 'MT' => 'Mitsubishi',
+ 'MY' => 'MyPhone',
+ 'NE' => 'NEC',
+ 'NG' => 'NGM',
+ 'NI' => 'Nintendo',
+ 'NK' => 'Nokia',
+ 'NW' => 'Newgen',
+ 'NX' => 'Nexian',
+ 'OD' => 'Onda',
+ 'OP' => 'OPPO',
+ 'OR' => 'Orange',
+ 'OT' => 'O2',
+ 'PA' => 'Panasonic',
+ 'PH' => 'Philips',
+ 'PM' => 'Palm',
+ 'PO' => 'phoneOne',
+ 'PT' => 'Pantech',
+ 'QT' => 'Qtek',
+ 'RM' => 'RIM',
+ 'RO' => 'Rover',
+ 'SA' => 'Samsung',
+ 'SD' => 'Sega',
+ 'SE' => 'Sony Ericsson',
+ 'SF' => 'Softbank',
+ 'SG' => 'Sagem',
+ 'SH' => 'Sharp',
+ 'SI' => 'Siemens',
+ 'SN' => 'Sendo',
+ 'SO' => 'Sony',
+ 'SP' => 'Spice',
+ 'SY' => 'Sanyo',
+ 'TA' => 'Tesla',
+ 'TC' => 'TCL',
+ 'TE' => 'Telit',
+ 'TH' => 'TiPhone',
+ 'TI' => 'TIANYU',
+ 'TM' => 'T-Mobile',
+ 'TO' => 'Toplux',
+ 'TS' => 'Toshiba',
+ 'UT' => 'UTStarcom',
+ 'VD' => 'Videocon',
+ 'VE' => 'Vertu',
+ 'VI' => 'Vitelcom',
+ 'VK' => 'VK Mobile',
+ 'VO' => 'Voxtel',
+ 'WB' => 'Web TV',
+ 'WE' => 'WellcoM',
+ 'WO' => 'Wonu',
+ 'XX' => 'Unknown',
+ 'ZO' => 'Zonda',
+ 'ZT' => 'ZTE',
+ );
+ public static $osShorts = array(
+ 'AIX' => 'AIX',
+ 'Android' => 'AND',
+ 'Apple TV' => 'ATV',
+ 'Arch Linux' => 'ARL',
+ 'BackTrack' => 'BTR',
+ 'Bada' => 'SBA',
+ 'BlackBerry OS' => 'BLB',
+ 'BlackBerry Tablet OS' => 'QNX',
+ 'Bot' => 'BOT',
+ 'Brew' => 'BMP',
+ 'CentOS' => 'CES',
+ 'Chrome OS' => 'COS',
+ 'Debian' => 'DEB',
+ 'DragonFly' => 'DFB',
+ 'Fedora' => 'FED',
+ 'Firefox OS' => 'FOS',
+ 'FreeBSD' => 'BSD',
+ 'Gentoo' => 'GNT',
+ 'Google TV' => 'GTV',
+ 'HP-UX' => 'HPX',
+ 'IRIX' => 'IRI',
+ 'Knoppix' => 'KNO',
+ 'Kubuntu' => 'KBT',
+ 'Linux' => 'LIN',
+ 'Lubuntu' => 'LBT',
+ 'Mac' => 'MAC',
+ 'Mandriva' => 'MDR',
+ 'MeeGo' => 'SMG',
+ 'Mint' => 'MIN',
+ 'NetBSD' => 'NBS',
+ 'Nintendo' => 'WII',
+ 'Nintendo Mobile' => 'NDS',
+ 'OS/2' => 'OS2',
+ 'OSF1' => 'T64',
+ 'OpenBSD' => 'OBS',
+ 'PlayStation' => 'PSP',
+ 'PlayStation 3' => 'PS3',
+ 'Presto' => 'PRS',
+ 'Puppy' => 'PPY',
+ 'Red Hat' => 'RHT',
+ 'SUSE' => 'SSE',
+ 'Slackware' => 'SLW',
+ 'Solaris' => 'SOS',
+ 'Syllable' => 'SYL',
+ 'Symbian' => 'SYM',
+ 'Symbian OS' => 'SYS',
+ 'Symbian OS Series 40' => 'S40',
+ 'Symbian OS Series 60' => 'S60',
+ 'Symbian^3' => 'SY3',
+ 'Talkatone' => 'TKT',
+ 'Tizen' => 'TIZ',
+ 'Ubuntu' => 'UBT',
+ 'WebTV' => 'WTV',
+ 'WinWAP' => 'WWP',
+ 'Windows' => 'WIN',
+ 'Windows 2000' => 'W2K',
+ 'Windows 3.1' => 'W31',
+ 'Windows 7' => 'WI7',
+ 'Windows 8' => 'WI8',
+ 'Windows 95' => 'W95',
+ 'Windows 98' => 'W98',
+ 'Windows CE' => 'WCE',
+ 'Windows ME' => 'WME',
+ 'Windows Mobile' => 'WMO',
+ 'Windows NT' => 'WNT',
+ 'Windows Phone' => 'WPH',
+ 'Windows RT' => 'WRT',
+ 'Windows Server 2003' => 'WS3',
+ 'Windows Vista' => 'WVI',
+ 'Windows XP' => 'WXP',
+ 'Xbox' => 'XBX',
+ 'Xubuntu' => 'XBT',
+ 'YunOs' => 'YNS',
+ 'iOS' => 'IOS',
+ 'palmOS' => 'POS',
+ 'webOS' => 'WOS'
+ );
+ protected static $desktopOsArray = array('IBM', 'Linux', 'Mac', 'Unix', 'Windows');
+ public static $osFamilies = array(
+ 'Android' => array('AND'),
+ 'Apple TV' => array('ATV'),
+ 'BlackBerry' => array('BLB'),
+ 'Bot' => array('BOT'),
+ 'Brew' => array('BMP'),
+ 'Chrome OS' => array('COS'),
+ 'Firefox OS' => array('FOS'),
+ 'Gaming Console' => array('WII', 'PS3'),
+ 'Google TV' => array('GTV'),
+ 'IBM' => array('OS2'),
+ 'iOS' => array('IOS'),
+ 'Linux' => array('LIN', 'ARL', 'DEB', 'KNO', 'MIN', 'UBT', 'KBT', 'XBT', 'LBT', 'FED', 'RHT', 'MDR', 'GNT', 'SLW', 'SSE', 'PPY', 'CES', 'BTR', 'YNS', 'PRS'),
+ 'Mac' => array('MAC'),
+ 'Mobile Gaming Console' => array('PSP', 'NDS', 'XBX'),
+ 'Other Mobile' => array('WOS', 'POS', 'QNX', 'SBA', 'TIZ'),
+ 'Simulator' => array('TKT', 'WWP'),
+ 'Symbian' => array('SYM', 'SYS', 'SY3', 'S60', 'S40', 'SMG'),
+ 'Unix' => array('SOS', 'AIX', 'HPX', 'BSD', 'NBS', 'OBS', 'DFB', 'SYL', 'IRI', 'T64'),
+ 'WebTV' => array('WTV'),
+ 'Windows' => array('WI8', 'WI7', 'WVI', 'WS3', 'WXP', 'W2K', 'WNT', 'WME', 'W98', 'W95', 'WRT', 'W31', 'WIN'),
+ 'Windows Mobile' => array('WPH', 'WMO', 'WCE')
+ );
+ public static $browserFamilies = array(
+ 'Android Browser' => array('AN'),
+ 'BlackBerry Browser' => array('BB'),
+ 'Chrome' => array('CH', 'CM', 'CI', 'CF', 'CR', 'RM'),
+ 'Firefox' => array('FF', 'FE', 'SX', 'FB', 'PX', 'MB'),
+ 'Internet Explorer' => array('IE', 'IM'),
+ 'Konqueror' => array('KO'),
+ 'NetFront' => array('NF'),
+ 'Nokia Browser' => array('NB'),
+ 'Opera' => array('OP', 'OM', 'OI'),
+ 'Safari' => array('SF', 'MF')
+ );
+ public static $browsers = array(
+ 'AB' => 'ABrowse',
+ 'AM' => 'Amaya',
+ 'AN' => 'Android Browser',
+ 'AR' => 'Arora',
+ 'AV' => 'Amiga Voyager',
+ 'AW' => 'Amiga Aweb',
+ 'BB' => 'BlackBerry Browser',
+ 'BD' => 'Baidu Browser',
+ 'BE' => 'Beonex',
+ 'BX' => 'BrowseX',
+ 'CA' => 'Camino',
+ 'CF' => 'Chrome Frame',
+ 'CH' => 'Chrome',
+ 'CI' => 'Chrome Mobile iOS',
+ 'CK' => 'Conkeror',
+ 'CM' => 'Chrome Mobile',
+ 'CO' => 'CometBird',
+ 'CR' => 'Chromium',
+ 'CS' => 'Cheshire',
+ 'DF' => 'Dolphin',
+ 'DI' => 'Dillo',
+ 'EL' => 'Elinks',
+ 'EP' => 'Epiphany',
+ 'FB' => 'Firebird',
+ 'FD' => 'Fluid',
+ 'FE' => 'Fennec',
+ 'FF' => 'Firefox',
+ 'FL' => 'Flock',
+ 'FN' => 'Fireweb Navigator',
+ 'GA' => 'Galeon',
+ 'GE' => 'Google Earth',
+ 'HJ' => 'HotJava',
+ 'IB' => 'IBrowse',
+ 'IC' => 'iCab',
+ 'IE' => 'Internet Explorer',
+ 'IM' => 'IE Mobile',
+ 'IR' => 'Iron',
+ 'JS' => 'Jasmine',
+ 'KI' => 'Kindle Browser',
+ 'KM' => 'K-meleon',
+ 'KO' => 'Konqueror',
+ 'KP' => 'Kapiko',
+ 'KZ' => 'Kazehakase',
+ 'LG' => 'Lightning',
+ 'LI' => 'Links',
+ 'LX' => 'Lynx',
+ 'MB' => 'MicroB',
+ 'MC' => 'NCSA Mosaic',
+ 'MF' => 'Mobile Safari',
+ 'MI' => 'Midori',
+ 'MS' => 'Mobile Silk',
+ 'MX' => 'Maxthon',
+ 'NB' => 'Nokia Browser',
+ 'NF' => 'NetFront',
+ 'NL' => 'NetFront Life',
+ 'NS' => 'Netscape',
+ 'OB' => 'Obigo',
+ 'OI' => 'Opera Mini',
+ 'OM' => 'Opera Mobile',
+ 'OP' => 'Opera',
+ 'OV' => 'Openwave Mobile Browser',
+ 'OW' => 'OmniWeb',
+ 'PL' => 'Palm Blazer',
+ 'PR' => 'Palm Pre',
+ 'PX' => 'Phoenix',
+ 'RK' => 'Rekonq',
+ 'RM' => 'RockMelt',
+ 'SF' => 'Safari',
+ 'SM' => 'SeaMonkey',
+ 'SN' => 'Snowshoe',
+ 'SX' => 'Swiftfox',
+ 'TZ' => 'Tizen Browser',
+ 'UC' => 'UC Browser',
+ 'WO' => 'wOSBrowser',
+ 'YA' => 'Yandex Browser'
+ );
+
+ const UNKNOWN = "UNK";
+ protected static $regexesDir = '/regexes/';
+ protected static $osRegexesFile = 'oss.yml';
+ protected static $browserRegexesFile = 'browsers.yml';
+ protected static $mobileRegexesFile = 'mobiles.yml';
+ protected $userAgent;
+ protected $os;
+ protected $browser;
+ protected $device;
+ protected $brand;
+ protected $model;
+ protected $debug = false;
+
+ public function __construct($userAgent)
+ {
+ $this->userAgent = $userAgent;
+ }
+
+ protected function getOsRegexes()
+ {
+ return Spyc::YAMLLoad(__DIR__ . self::$regexesDir . self::$osRegexesFile);
+ }
+
+ protected function getBrowserRegexes()
+ {
+ return Spyc::YAMLLoad(__DIR__ . self::$regexesDir . self::$browserRegexesFile);
+ }
+
+ protected function getMobileRegexes()
+ {
+ return Spyc::YAMLLoad(__DIR__ . self::$regexesDir . self::$mobileRegexesFile);
+ }
+
+ public function parse()
+ {
+ $this->parseOs();
+ if ($this->isBot() || $this->isSimulator())
+ return;
+
+ $this->parseBrowser();
+
+ if ($this->isMobile()) {
+ $this->parseMobile();
+ } else {
+ $this->device = array_search('desktop', self::$deviceTypes);
+ }
+ if ($this->debug) {
+ var_dump($this->brand, $this->model, $this->device);
+ }
+ }
+
+ protected function parseOs()
+ {
+ foreach ($this->getOsRegexes() as $osRegex) {
+ $matches = $this->matchUserAgent($osRegex['regex']);
+ if ($matches)
+ break;
+ }
+
+ if (!$matches)
+ return;
+
+ if (in_array($osRegex['name'], self::$osShorts)) {
+ $short = self::$osShorts[$osRegex['name']];
+ } else {
+ $short = 'UNK';
+ }
+
+ $this->os = array(
+ 'name' => $this->buildOsName($osRegex['name'], $matches),
+ 'short_name' => $short,
+ 'version' => $this->buildOsVersion($osRegex['version'], $matches)
+ );
+
+ if (array_key_exists($this->os['name'], self::$osShorts)) {
+ $this->os['short_name'] = self::$osShorts[$this->os['name']];
+ }
+ }
+
+ protected function parseBrowser()
+ {
+ foreach ($this->getBrowserRegexes() as $browserRegex) {
+ $matches = $this->matchUserAgent($browserRegex['regex']);
+ if ($matches)
+ break;
+ }
+
+ if (!$matches)
+ return;
+
+ if (in_array($browserRegex['name'], self::$browsers)) {
+ $short = array_search($browserRegex['name'], self::$browsers);
+ } else {
+ $short = 'XX';
+ }
+
+ $this->browser = array(
+ 'name' => $this->buildBrowserName($browserRegex['name'], $matches),
+ 'short_name' => $short,
+ 'version' => $this->buildBrowserVersion($browserRegex['version'], $matches)
+ );
+ }
+
+ protected function parseMobile()
+ {
+ $mobileRegexes = $this->getMobileRegexes();
+ $this->parseBrand($mobileRegexes);
+ $this->parseModel($mobileRegexes);
+ }
+
+ protected function parseBrand($mobileRegexes)
+ {
+ foreach ($mobileRegexes as $brand => $mobileRegex) {
+ $matches = $this->matchUserAgent($mobileRegex['regex']);
+ if ($matches)
+ break;
+ }
+
+ if (!$matches)
+ return;
+ $this->brand = array_search($brand, self::$deviceBrands);
+ $this->fullName = $brand;
+
+ if (isset($mobileRegex['device'])) {
+ $this->device = array_search($mobileRegex['device'],self::$deviceTypes);
+ }
+
+ if (isset($mobileRegex['model'])) {
+ $this->model = $this->buildModel($mobileRegex['model'], $matches);
+ }
+ }
+
+ protected function parseModel($mobileRegexes)
+ {
+ if (empty($this->brand) || !empty($this->model))
+ return;
+
+ foreach ($mobileRegexes[$this->fullName]['models'] as $modelRegex) {
+ $matches = $this->matchUserAgent($modelRegex['regex']);
+ if ($matches)
+ break;
+ }
+
+ if (!$matches) {
+ return;
+ }
+
+ $this->model = $this->buildModel($modelRegex['model'], $matches);
+
+ if (isset($modelRegex['device'])) {
+ $this->device = array_search($modelRegex['device'], self::$deviceTypes);
+ }
+ }
+
+ protected function matchUserAgent($regex)
+ {
+ $regex = '/' . str_replace('/', '\/', $regex) . '/i';
+
+ if (preg_match($regex, $this->userAgent, $matches)) {
+ return $matches;
+ }
+
+ return false;
+ }
+
+ protected function buildOsName($osName, $matches)
+ {
+ return $this->buildByMatch($osName, $matches);
+ }
+
+ protected function buildOsVersion($osVersion, $matches)
+ {
+ $osVersion = $this->buildByMatch($osVersion, $matches);
+
+ $osVersion = $this->buildByMatch($osVersion, $matches, '2');
+
+ $osVersion = str_replace('_', '.', $osVersion);
+
+ return $osVersion;
+ }
+
+ protected function buildBrowserName($browserName, $matches)
+ {
+ return $this->buildByMatch($browserName, $matches);
+ }
+
+ protected function buildBrowserVersion($browserVersion, $matches)
+ {
+ $browserVersion = $this->buildByMatch($browserVersion, $matches);
+
+ $browserVersion = $this->buildByMatch($browserVersion, $matches, '2');
+
+ $browserVersion = str_replace('_', '.', $browserVersion);
+
+ return $browserVersion;
+ }
+
+ protected function buildModel($model, $matches)
+ {
+ $model = $this->buildByMatch($model, $matches);
+
+ $model = $this->buildByMatch($model, $matches, '2');
+
+ $model = $this->buildModelExceptions($model);
+
+ $model = str_replace('_', ' ', $model);
+
+ return $model;
+ }
+
+ protected function buildModelExceptions($model)
+ {
+ if ($this->brand == 'O2') {
+ $model = preg_replace('/([a-z])([A-Z])/', '$1 $2', $model);
+ $model = ucwords(str_replace('_', ' ', $model));
+ }
+
+ return $model;
+ }
+
+ /**
+ * This method is used in this class for processing results of pregmatch
+ * results into string containing recognized information.
+ *
+ * General algorithm:
+ * Parsing UserAgent string consists of trying to match it against list of
+ * regular expressions for three different information:
+ * browser + version,
+ * OS + version,
+ * device manufacturer + model.
+ *
+ * After match has been found iteration stops, and results are processed
+ * by buildByMatch.
+ * As $item we get decoded name (name of browser, name of OS, name of manufacturer).
+ * In array $match we recieve preg_match results containing whole string matched at index 0
+ * and following matches in further indexes. Desired action now is to concatenate
+ * decoded name ($item) with matches found. First step is to append first found match,
+ * which is located in index=1 (that's why $nb is 1 by default).
+ * In other cases, where whe know that preg_match may return more than 1 result,
+ * we call buildByMatch with $nb = 2 or more, depending on what will be returned from
+ * regular expression.
+ *
+ * Example:
+ * We are parsing UserAgent of Firefox 20.0 browser.
+ * UserAgentParserEnhanced calls buildBrowserName() and buildBrowserVersion() in order
+ * to retrieve those information.
+ * In buildBrowserName() we only have one call of buildByMatch, where passed argument
+ * is regular expression testing given string for browser name. In this case, we are only
+ * interrested in first hit, so no $nb parameter will be set to 1. After finding match, and calling
+ * buildByMatch - we will receive just the name of browser.
+ *
+ * Also after decoding browser we will get list of regular expressions for this browser name
+ * testing UserAgent string for version number. Again we iterate over this list, and after finding first
+ * occurence - we break loop and proceed to build by match. Since browser regular expressions can
+ * contain two hits (major version and minor version) in function buildBrowserVersion() we have
+ * two calls to buildByMatch, one without 3rd parameter, and second with $nb set to 2.
+ * This way we can retrieve version number, and assign it to object property.
+ *
+ * In case of mobiles.yml this schema slightly varies, but general idea is the same.
+ *
+ * @param string $item
+ * @param array $matches
+ * @param int $nb
+ * @return type
+ */
+ protected function buildByMatch($item, $matches, $nb = '1')
+ {
+ if (strpos($item, '$' . $nb) === false)
+ return $item;
+
+ $replace = isset($matches[$nb]) ? $matches[$nb] : '';
+ return trim(str_replace('$' . $nb, $replace, $item));
+ }
+
+ public function isBot()
+ {
+ $decodedFamily = '';
+ if (in_array($this->getOs('name'), self::$osShorts)) {
+ $osShort = self::$osShorts[$this->getOs('name')];
+ } else {
+ $osShort = '';
+ }
+ foreach (self::$osFamilies as $family => $familyOs) {
+ if (in_array($osShort, $familyOs)) {
+ $decodedFamily = $family;
+ break;
+ }
+ }
+
+ return $decodedFamily == 'Bot';
+ }
+
+ public function isSimulator()
+ {
+ $decodedFamily = '';
+ if (in_array($this->getOs('name'), self::$osShorts)) {
+ $osShort = self::$osShorts[$this->getOs('name')];
+ } else {
+ $osShort = '';
+ }
+ foreach (self::$osFamilies as $family => $familyOs) {
+ if (in_array($osShort, $familyOs)) {
+ $decodedFamily = $family;
+ break;
+ }
+ }
+ return $decodedFamily == 'Simulator';
+ }
+
+ public function isMobile()
+ {
+ return !$this->isDesktop();
+ }
+
+ public function isDesktop()
+ {
+ $osName = $this->getOs('name');
+ if (empty($osName) || empty(self::$osShorts[$osName])) {
+ return false;
+ }
+
+ $osShort = self::$osShorts[$osName];
+ foreach (self::$osFamilies as $family => $familyOs) {
+ if (in_array($osShort, $familyOs)) {
+ $decodedFamily = $family;
+ break;
+ }
+ }
+ return in_array($decodedFamily, self::$desktopOsArray);
+ }
+
+ public function getOs($attr = '')
+ {
+ if ($attr == '') {
+ return $this->os;
+ }
+
+ if (!isset($this->os[$attr])) {
+ return self::UNKNOWN;
+ }
+
+ if ($attr == 'version') {
+ $this->os['version'] = $this->os['version'];
+ }
+ return $this->os[$attr];
+ }
+
+ public function getBrowser($attr = '')
+ {
+ if ($attr == '') {
+ return $this->browser;
+ }
+
+ if (!isset($this->browser[$attr])) {
+ return self::UNKNOWN;
+ }
+
+ return $this->browser[$attr];
+ }
+
+ public function getDevice()
+ {
+ return $this->device;
+ }
+
+ public function getBrand()
+ {
+ return $this->brand;
+ }
+
+ public function getModel()
+ {
+ return $this->model;
+ }
+
+ public function getUserAgent()
+ {
+ return $this->userAgent;
+ }
+
+ public static function getOsFamily($osLabel)
+ {
+ $osShortName = substr($osLabel, 0, 3);
+
+ foreach (self::$osFamilies as $osFamily => $osShortNames) {
+ if (in_array($osShortName, $osShortNames)) {
+ return $osFamily;
+ }
+ }
+
+ return 'Other';
+ }
+
+ public static function getBrowserFamily($browserLabel)
+ {
+ foreach (self::$browserFamilies as $browserFamily => $browserShortNames) {
+ if (in_array($browserLabel, $browserShortNames)) {
+ return $browserFamily;
+ }
+ }
+
+ return 'Other';
+ }
+
+ public static function getOsNameFromId($os, $ver = false)
+ {
+ $osFullName = array_search($os, self::$osShorts);
+ if ($osFullName) {
+ if (in_array($os, self::$osFamilies['Windows'])) {
+ return $osFullName;
+ } else {
+ return trim($osFullName . " " . $ver);
+ }
+ }
+ return false;
+ }
+
} \ No newline at end of file
diff --git a/plugins/DevicesDetection/UserAgentParserEnhanced/regexes/browsers.yml b/plugins/DevicesDetection/UserAgentParserEnhanced/regexes/browsers.yml
index c9f3a72e5a..0a4d2a6669 100644
--- a/plugins/DevicesDetection/UserAgentParserEnhanced/regexes/browsers.yml
+++ b/plugins/DevicesDetection/UserAgentParserEnhanced/regexes/browsers.yml
@@ -1,408 +1,408 @@
-###############
-# Piwik - Open source web analytics
-#
-# @link http://piwik.org
-# @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
-#
-# @category Piwik_Plugins
-# @package Piwik_DevicesDetection
-###############
-
-# SeaMonkey
-- regex: '(Iceape|SeaMonkey)/(\d+\.\d+)'
- name: $1
- version: '$2'
-
-# Camino
-- regex: 'Camino/(\d+\.\d+)'
- name: Camino
- version: '$1'
-
-#Fennec (Firefox for mobile)
-- regex: 'Fennec/(\d+\.\d+)'
- name: Fennec
- version: '$1'
-
-#MicroB
-- regex: 'Firefox.*Tablet browser (\d+\.\d+)'
- name: MicroB
- version: '$1'
-
-#Firefox
-- regex: 'Firefox/(\d+\.\d+)'
- name: Firefox
- version: '$1'
-- regex: '(BonEcho|GranParadiso|Lorentz|Minefield|Namoroka|Shiretoko)/(\d+\.\d+)'
- name: Firefox '$1'
- version: '$2'
-
-#Flock
-- regex: 'Flock/(\d+\.\d+)'
- name: Flock
- version: '$1'
-
-#RockMelt
-- regex: 'RockMelt/(\d+\.\d+)'
- name: RockMelt
- version: '$1'
-
-#Netscape
-- regex: '(?:Navigator|Netscape6)/(\d+\.\d+)'
- name: Netscape
- version: '$1'
-
-#Opera
-- regex: '(:?Opera Tablet.*Version|Opera/.+Opera Mobi.+Version|Safari.*OPR)/(\d+\.\d+)'
- name: Opera Mobile
- version: '$2'
-- regex: 'Opera Mini/(:?att/)?(\d+\.\d+)'
- name: Opera Mini
- version: '$2'
-- regex: 'Opera[/ ](?:9.80.*Version/)?(\d+\.\d+)'
- name: Opera
- version: '$1'
-
-#wOSBrowser
-- regex: '(?:hpw|web)OS/(\d+\.\d+)'
- name: wOSBrowser
- version: '$1'
-
-#Swiftfox
-- regex: 'Firefox/(\d+\.\d+).*\(Swiftfox\)'
- name: Swiftfox
- version: '$1'
-
-#Rekonq
-- regex: 'rekonq'
- name: Rekonq
- version: ''
-
-#Conkeror
-- regex: 'Conkeror/(\d+\.\d+)'
- name: Conkeror
- version: '$1'
-
-#Konqueror
-- regex: 'Konqueror/(\d+\.\d+)'
- name: Konqueror
- version: '$1'
-
-#Baidu Browser
-- regex: 'baidubrowser[/ ](\d+)'
- name: Baidu Browser
- version: '$1'
-
-#Yandex Browser
-- regex: 'YaBrowser/(\d+)'
- name: Yandex Browser
- version: '$1'
-
-#Chrome
-- regex: 'CrMo/(\d+\.\d+)'
- name: Chrome Mobile
- version: '$1'
-- regex: 'CriOS/(\d+\.\d+)'
- name: Chrome Mobile iOS
- version: '$1'
-- regex: 'Chrome/(\d+\.\d+).*Mobile'
- name: Chrome Mobile
- version: '$1'
-- regex: 'chromeframe/(\d+\.\d+)'
- name: Chrome Frame
- version: '$1'
-- regex: 'Chrome/(\d+\.\d+)'
- name: Chrome
- version: '$1'
-- regex: 'Chromium/(\d+\.\d+)'
- name: Chromium
- version: '$1'
-
-#UC Browser
-- regex: 'UC[ ]?Browser[ /](\d+\.\d+)'
- name: UC Browser
- version: '$1'
-- regex: '(?:UC Browser|UCBrowser|UCWEB)(\d+\.\d+)'
- name: UC Browser
- version: '$1'
-
-#Tizen Browser
-- regex: '(?:Tizen|SLP) Browser/(\d+\.\d+)'
- name: Tizen Browser
- version: '$1'
-
-#Epiphany
-- regex: 'Epiphany/(\d+\.\d+)'
- name: Epiphany
- version: '$1'
-
-#Fireweb Navigator
-- regex: 'Fireweb Navigator/(\d+\.\d+)'
- name: Fireweb Navigator
- version: '$1'
-
-#Jasmine
-- regex: 'Jasmine[ /](\d+\.\d+)'
- name: Jasmine
- version: '$1'
-
-#Lynx
-- regex: 'Lynx/(\d+\.\d+)'
- name: Lynx
- version: '$1'
-
-#Midori
-- regex: 'Midori/(\d+\.\d+)'
- name: Midori
- version: '$1'
-
-#NCSA Mosaic
-- regex: 'NCSA_Mosaic/(\d+\.\d+)'
- name: NCSA Mosaic
- version: '$1'
-
-#ABrowse
-- regex: 'ABrowse (\d+\.\d+)'
- name: ABrowse
- version: '$1'
-
-#Amaya
-- regex: 'amaya/(\d+\.\d+)'
- name: Amaya
- version: '$1'
-
-#Amiga Voyager
-- regex: 'AmigaVoyager/(\d+\.\d+)'
- name: Amiga Voyager
- version: '$1'
-
-#Amiga Aweb
-- regex: 'Amiga-Aweb/(\d+\.\d+)'
- name: Amiga Aweb
- version: '$1'
-
-#Arora
-- regex: 'Arora/(\d+\.\d+)'
- name: Arora
- version: '$1'
-
-#Beonex
-- regex: 'Beonex/(\d+\.\d+)'
- name: Beonex
- version: '$1'
-
-#BlackBerry Browser
-- regex: 'Black[bB]erry|PlayBook|BB10'
- name: BlackBerry Browser
- version: ''
-
-#BrowseX
-- regex: 'BrowseX \((\d+\.\d+)'
- name: BrowseX
- version: '$1'
-
-#Cheshire
-- regex: 'Cheshire/(\d+\.\d+)'
- name: Cheshire
- version: '$1'
-
-#CometBird
-- regex: 'CometBird/(\d+\.\d+)'
- name: CometBird
- version: '$1'
-
-#Dillo
-- regex: 'Dillo/(\d+\.\d+)'
- name: Dillo
- version: '$1'
-
-#Dolphin
-- regex: 'Dolfin/(\d+\.\d+)|dolphin'
- name: Dolphin
- version: '$1'
-
-#Elinks
-- regex: 'Elinks/(\d+\.\d+)'
- name: Elinks
- version: '$1'
-
-#Firebird
-- regex: 'Firebird/(\d+\.\d+)'
- name: Firebird
- version: '$1'
-
-#Fluid
-- regex: 'Fluid/(\d+\.\d+)'
- name: Fluid
- version: '$1'
-
-#Galeon
-- regex: 'Galeon/(\d+\.\d+)'
- name: Galeon
- version: '$1'
-
-#Google Earth
-- regex: 'Google Earth/(\d+\.\d+)'
- name: Google Earth
- version: '$1'
-
-#HotJava
-- regex: 'HotJava/(\d+\.\d+)'
- name: HotJava
- version: '$1'
-
-#IBrowse
-- regex: 'IBrowse[ /](\d+\.\d+)'
- name: IBrowse
- version: '$1'
-
-#iCab
-- regex: 'iCab[ /](\d+\.\d+)'
- name: iCab
- version: '$1'
-
-#Internet Explorer
-- regex: 'IEMobile[ /](\d+\.\d+)'
- name: IE Mobile
- version: '$1'
-- regex: 'MSIE (\d+\.\d+).*XBLWP7'
- name: IE Mobile
- version: '$1'
-- regex: 'MSIE (\d+\.\d+)'
- name: Internet Explorer
- version: '$1'
-
-#Iron
-- regex: 'Iron/(\d+\.\d+)'
- name: Iron
- version: '$1'
-
-#Kapiko
-- regex: 'Kapiko/(\d+\.\d+)'
- name: Kapiko
- version: '$1'
-
-#Kazehakase
-- regex: 'Kazehakase/(\d+\.\d+)'
- name: Kazehakase
- version: '$1'
-
-#Kindle Browser
-- regex: 'Kindle/(\d+\.\d+)'
- name: Kindle Browser
- version: '$1'
-
-#K-meleon
-- regex: 'K-meleon/(\d+\.\d+)'
- name: K-meleon
- version: '$1'
-
-#Lightning
-- regex: 'Lightning/(\d+\.\d+)'
- name: Lightning
- version: '$1'
-
-#Links
-- regex: 'Links \((\d+\.\d+)'
- name: Links
- version: '$1'
-
-#Maxthon
-- regex: 'Maxthon (\d+\.\d+)'
- name: Maxthon
- version: '$1'
-- regex: '(?:Maxthon|MyIE2|Uzbl|Shiira)'
- name: Maxthon
- version: ''
-
-#Openwave Mobile Browser
-- regex: 'UP.Browser/(\d+\.\d+)'
- name: Openwave Mobile Browser
- version: '$1'
-
-#OmniWeb
-- regex: 'OmniWeb/[v]?(\d+\.\d+)'
- name: OmniWeb
- version: '$1'
-
-#Phoenix
-- regex: 'Phoenix/(\d+\.\d+)'
- name: Phoenix
- version: '$1'
-
-#Mobile Silk
-- regex: 'Silk/(\d+\.\d+)'
- name: Mobile Silk
- version: '$1'
-
-#Nokia Browser
-- regex: '(?:NokiaBrowser|BrowserNG)/(\d+\.\d+)'
- name: Nokia Browser
- version: '$1'
-- regex: 'Series60/5\.0'
- name: Nokia Browser
- version: '7.0'
-- regex: 'Series60/(\d+\.\d+)'
- name: Nokia OSS Browser
- version: '$1'
-- regex: 'S40OviBrowser/(\d+\.\d+)'
- name: Nokia Ovi Browser
- version: '$1'
-- regex: '^Nokia|Nokia[EN]?\d+'
- name: Nokia Browser
- version: ''
-
-#NetFront
-- regex: 'NetFrontLifeBrowser/(\d+\.\d+)'
- name: NetFront Life
- version: '$1'
-- regex: 'NetFront/(\d+\.\d+)'
- name: NetFront
- version: '$1'
-- regex: 'PLAYSTATION|NINTENDO 3|AppleWebKit.+ NX/\d+\.\d+\.\d+'
- name: NetFront
- version: ''
-
-#Obigo
-- regex: 'Obigo[ ]?(?:InternetBrowser|Browser)?[ /]([A-Za-z0-9]*)'
- name: Obigo
- version: '$1'
-- regex: 'Obigo|Teleca'
- name: Obigo
- version: ''
-
-#Palm Blazer
-- regex: 'Blazer/(\d+\.\d+)'
- name: Palm Blazer
- version: '$1'
-- regex: 'Pre/(\d+\.\d+)'
- name: Palm Pre
- version: '$1'
-
-#Polaris
-- regex: '(?:Polaris|Embider)/(\d+\.\d+)'
- name: Polaris
- version: '$1'
-
-#Snowshoe
-- regex: 'Snowshoe/(\d+\.\d+)'
- name: Snowshoe
- version: '$1'
-
-#Safari
-- regex: '(?:iPod|iPad|iPhone).+Version/(\d+\.\d+)'
- name: Mobile Safari
- version: '$1'
-- regex: 'Version/(\d+\.\d+).*Mobile.*Safari/'
- name: Mobile Safari
- version: '$1'
-- regex: '(?:iPod|iPhone|iPad)'
- name: Mobile Safari
- version: ''
-- regex: 'Version/(\d+\.\d+).*Safari/|Safari/\d+'
- name: Safari
- version: '$1'
-
-#Android Browser
-- regex: 'Android'
- name: Android Browser
+###############
+# Piwik - Open source web analytics
+#
+# @link http://piwik.org
+# @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
+#
+# @category Piwik_Plugins
+# @package Piwik_DevicesDetection
+###############
+
+# SeaMonkey
+- regex: '(Iceape|SeaMonkey)/(\d+\.\d+)'
+ name: $1
+ version: '$2'
+
+# Camino
+- regex: 'Camino/(\d+\.\d+)'
+ name: Camino
+ version: '$1'
+
+#Fennec (Firefox for mobile)
+- regex: 'Fennec/(\d+\.\d+)'
+ name: Fennec
+ version: '$1'
+
+#MicroB
+- regex: 'Firefox.*Tablet browser (\d+\.\d+)'
+ name: MicroB
+ version: '$1'
+
+#Firefox
+- regex: 'Firefox/(\d+\.\d+)'
+ name: Firefox
+ version: '$1'
+- regex: '(BonEcho|GranParadiso|Lorentz|Minefield|Namoroka|Shiretoko)/(\d+\.\d+)'
+ name: Firefox '$1'
+ version: '$2'
+
+#Flock
+- regex: 'Flock/(\d+\.\d+)'
+ name: Flock
+ version: '$1'
+
+#RockMelt
+- regex: 'RockMelt/(\d+\.\d+)'
+ name: RockMelt
+ version: '$1'
+
+#Netscape
+- regex: '(?:Navigator|Netscape6)/(\d+\.\d+)'
+ name: Netscape
+ version: '$1'
+
+#Opera
+- regex: '(:?Opera Tablet.*Version|Opera/.+Opera Mobi.+Version|Safari.*OPR)/(\d+\.\d+)'
+ name: Opera Mobile
+ version: '$2'
+- regex: 'Opera Mini/(:?att/)?(\d+\.\d+)'
+ name: Opera Mini
+ version: '$2'
+- regex: 'Opera[/ ](?:9.80.*Version/)?(\d+\.\d+)'
+ name: Opera
+ version: '$1'
+
+#wOSBrowser
+- regex: '(?:hpw|web)OS/(\d+\.\d+)'
+ name: wOSBrowser
+ version: '$1'
+
+#Swiftfox
+- regex: 'Firefox/(\d+\.\d+).*\(Swiftfox\)'
+ name: Swiftfox
+ version: '$1'
+
+#Rekonq
+- regex: 'rekonq'
+ name: Rekonq
+ version: ''
+
+#Conkeror
+- regex: 'Conkeror/(\d+\.\d+)'
+ name: Conkeror
+ version: '$1'
+
+#Konqueror
+- regex: 'Konqueror/(\d+\.\d+)'
+ name: Konqueror
+ version: '$1'
+
+#Baidu Browser
+- regex: 'baidubrowser[/ ](\d+)'
+ name: Baidu Browser
+ version: '$1'
+
+#Yandex Browser
+- regex: 'YaBrowser/(\d+)'
+ name: Yandex Browser
+ version: '$1'
+
+#Chrome
+- regex: 'CrMo/(\d+\.\d+)'
+ name: Chrome Mobile
+ version: '$1'
+- regex: 'CriOS/(\d+\.\d+)'
+ name: Chrome Mobile iOS
+ version: '$1'
+- regex: 'Chrome/(\d+\.\d+).*Mobile'
+ name: Chrome Mobile
+ version: '$1'
+- regex: 'chromeframe/(\d+\.\d+)'
+ name: Chrome Frame
+ version: '$1'
+- regex: 'Chrome/(\d+\.\d+)'
+ name: Chrome
+ version: '$1'
+- regex: 'Chromium/(\d+\.\d+)'
+ name: Chromium
+ version: '$1'
+
+#UC Browser
+- regex: 'UC[ ]?Browser[ /](\d+\.\d+)'
+ name: UC Browser
+ version: '$1'
+- regex: '(?:UC Browser|UCBrowser|UCWEB)(\d+\.\d+)'
+ name: UC Browser
+ version: '$1'
+
+#Tizen Browser
+- regex: '(?:Tizen|SLP) Browser/(\d+\.\d+)'
+ name: Tizen Browser
+ version: '$1'
+
+#Epiphany
+- regex: 'Epiphany/(\d+\.\d+)'
+ name: Epiphany
+ version: '$1'
+
+#Fireweb Navigator
+- regex: 'Fireweb Navigator/(\d+\.\d+)'
+ name: Fireweb Navigator
+ version: '$1'
+
+#Jasmine
+- regex: 'Jasmine[ /](\d+\.\d+)'
+ name: Jasmine
+ version: '$1'
+
+#Lynx
+- regex: 'Lynx/(\d+\.\d+)'
+ name: Lynx
+ version: '$1'
+
+#Midori
+- regex: 'Midori/(\d+\.\d+)'
+ name: Midori
+ version: '$1'
+
+#NCSA Mosaic
+- regex: 'NCSA_Mosaic/(\d+\.\d+)'
+ name: NCSA Mosaic
+ version: '$1'
+
+#ABrowse
+- regex: 'ABrowse (\d+\.\d+)'
+ name: ABrowse
+ version: '$1'
+
+#Amaya
+- regex: 'amaya/(\d+\.\d+)'
+ name: Amaya
+ version: '$1'
+
+#Amiga Voyager
+- regex: 'AmigaVoyager/(\d+\.\d+)'
+ name: Amiga Voyager
+ version: '$1'
+
+#Amiga Aweb
+- regex: 'Amiga-Aweb/(\d+\.\d+)'
+ name: Amiga Aweb
+ version: '$1'
+
+#Arora
+- regex: 'Arora/(\d+\.\d+)'
+ name: Arora
+ version: '$1'
+
+#Beonex
+- regex: 'Beonex/(\d+\.\d+)'
+ name: Beonex
+ version: '$1'
+
+#BlackBerry Browser
+- regex: 'Black[bB]erry|PlayBook|BB10'
+ name: BlackBerry Browser
+ version: ''
+
+#BrowseX
+- regex: 'BrowseX \((\d+\.\d+)'
+ name: BrowseX
+ version: '$1'
+
+#Cheshire
+- regex: 'Cheshire/(\d+\.\d+)'
+ name: Cheshire
+ version: '$1'
+
+#CometBird
+- regex: 'CometBird/(\d+\.\d+)'
+ name: CometBird
+ version: '$1'
+
+#Dillo
+- regex: 'Dillo/(\d+\.\d+)'
+ name: Dillo
+ version: '$1'
+
+#Dolphin
+- regex: 'Dolfin/(\d+\.\d+)|dolphin'
+ name: Dolphin
+ version: '$1'
+
+#Elinks
+- regex: 'Elinks/(\d+\.\d+)'
+ name: Elinks
+ version: '$1'
+
+#Firebird
+- regex: 'Firebird/(\d+\.\d+)'
+ name: Firebird
+ version: '$1'
+
+#Fluid
+- regex: 'Fluid/(\d+\.\d+)'
+ name: Fluid
+ version: '$1'
+
+#Galeon
+- regex: 'Galeon/(\d+\.\d+)'
+ name: Galeon
+ version: '$1'
+
+#Google Earth
+- regex: 'Google Earth/(\d+\.\d+)'
+ name: Google Earth
+ version: '$1'
+
+#HotJava
+- regex: 'HotJava/(\d+\.\d+)'
+ name: HotJava
+ version: '$1'
+
+#IBrowse
+- regex: 'IBrowse[ /](\d+\.\d+)'
+ name: IBrowse
+ version: '$1'
+
+#iCab
+- regex: 'iCab[ /](\d+\.\d+)'
+ name: iCab
+ version: '$1'
+
+#Internet Explorer
+- regex: 'IEMobile[ /](\d+\.\d+)'
+ name: IE Mobile
+ version: '$1'
+- regex: 'MSIE (\d+\.\d+).*XBLWP7'
+ name: IE Mobile
+ version: '$1'
+- regex: 'MSIE (\d+\.\d+)'
+ name: Internet Explorer
+ version: '$1'
+
+#Iron
+- regex: 'Iron/(\d+\.\d+)'
+ name: Iron
+ version: '$1'
+
+#Kapiko
+- regex: 'Kapiko/(\d+\.\d+)'
+ name: Kapiko
+ version: '$1'
+
+#Kazehakase
+- regex: 'Kazehakase/(\d+\.\d+)'
+ name: Kazehakase
+ version: '$1'
+
+#Kindle Browser
+- regex: 'Kindle/(\d+\.\d+)'
+ name: Kindle Browser
+ version: '$1'
+
+#K-meleon
+- regex: 'K-meleon/(\d+\.\d+)'
+ name: K-meleon
+ version: '$1'
+
+#Lightning
+- regex: 'Lightning/(\d+\.\d+)'
+ name: Lightning
+ version: '$1'
+
+#Links
+- regex: 'Links \((\d+\.\d+)'
+ name: Links
+ version: '$1'
+
+#Maxthon
+- regex: 'Maxthon (\d+\.\d+)'
+ name: Maxthon
+ version: '$1'
+- regex: '(?:Maxthon|MyIE2|Uzbl|Shiira)'
+ name: Maxthon
+ version: ''
+
+#Openwave Mobile Browser
+- regex: 'UP.Browser/(\d+\.\d+)'
+ name: Openwave Mobile Browser
+ version: '$1'
+
+#OmniWeb
+- regex: 'OmniWeb/[v]?(\d+\.\d+)'
+ name: OmniWeb
+ version: '$1'
+
+#Phoenix
+- regex: 'Phoenix/(\d+\.\d+)'
+ name: Phoenix
+ version: '$1'
+
+#Mobile Silk
+- regex: 'Silk/(\d+\.\d+)'
+ name: Mobile Silk
+ version: '$1'
+
+#Nokia Browser
+- regex: '(?:NokiaBrowser|BrowserNG)/(\d+\.\d+)'
+ name: Nokia Browser
+ version: '$1'
+- regex: 'Series60/5\.0'
+ name: Nokia Browser
+ version: '7.0'
+- regex: 'Series60/(\d+\.\d+)'
+ name: Nokia OSS Browser
+ version: '$1'
+- regex: 'S40OviBrowser/(\d+\.\d+)'
+ name: Nokia Ovi Browser
+ version: '$1'
+- regex: '^Nokia|Nokia[EN]?\d+'
+ name: Nokia Browser
+ version: ''
+
+#NetFront
+- regex: 'NetFrontLifeBrowser/(\d+\.\d+)'
+ name: NetFront Life
+ version: '$1'
+- regex: 'NetFront/(\d+\.\d+)'
+ name: NetFront
+ version: '$1'
+- regex: 'PLAYSTATION|NINTENDO 3|AppleWebKit.+ NX/\d+\.\d+\.\d+'
+ name: NetFront
+ version: ''
+
+#Obigo
+- regex: 'Obigo[ ]?(?:InternetBrowser|Browser)?[ /]([A-Za-z0-9]*)'
+ name: Obigo
+ version: '$1'
+- regex: 'Obigo|Teleca'
+ name: Obigo
+ version: ''
+
+#Palm Blazer
+- regex: 'Blazer/(\d+\.\d+)'
+ name: Palm Blazer
+ version: '$1'
+- regex: 'Pre/(\d+\.\d+)'
+ name: Palm Pre
+ version: '$1'
+
+#Polaris
+- regex: '(?:Polaris|Embider)/(\d+\.\d+)'
+ name: Polaris
+ version: '$1'
+
+#Snowshoe
+- regex: 'Snowshoe/(\d+\.\d+)'
+ name: Snowshoe
+ version: '$1'
+
+#Safari
+- regex: '(?:iPod|iPad|iPhone).+Version/(\d+\.\d+)'
+ name: Mobile Safari
+ version: '$1'
+- regex: 'Version/(\d+\.\d+).*Mobile.*Safari/'
+ name: Mobile Safari
+ version: '$1'
+- regex: '(?:iPod|iPhone|iPad)'
+ name: Mobile Safari
+ version: ''
+- regex: 'Version/(\d+\.\d+).*Safari/|Safari/\d+'
+ name: Safari
+ version: '$1'
+
+#Android Browser
+- regex: 'Android'
+ name: Android Browser
version: '' \ No newline at end of file
diff --git a/plugins/DevicesDetection/UserAgentParserEnhanced/regexes/mobiles.yml b/plugins/DevicesDetection/UserAgentParserEnhanced/regexes/mobiles.yml
index 64b1470ef2..d9a2a22f88 100644
--- a/plugins/DevicesDetection/UserAgentParserEnhanced/regexes/mobiles.yml
+++ b/plugins/DevicesDetection/UserAgentParserEnhanced/regexes/mobiles.yml
@@ -1,958 +1,958 @@
-###############
-# Piwik - Open source web analytics
-#
-# @link http://piwik.org
-# @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
-#
-# @category Piwik_Plugins
-# @package Piwik_DevicesDetection
-###############
-
-# HTC
-HTC:
- regex: 'HTC|Sprint APA|ADR[A-Za-z0-9]+'
- device: 'smartphone'
- models:
- - regex: 'HTC ([A-Za-z0-9]+) Build'
- model: '$1'
- - regex: 'HTC ([A-Za-z0-9]+(?: [A-Za-z0-9]+)?)'
- model: '$1'
- - regex: 'USCCHTC(\d+)'
- model: '$1'
- - regex: 'Sprint APA(9292)'
- model: '$1 (Sprint)'
- - regex: 'HTC_([A-Za-z0-9_]+)'
- model: '$1'
- - regex: 'HTC(?:[\-/ ])?([A-Za-z0-9]+)'
- model: '$1'
- - regex: 'HTC;(?: )?([A-Za-z0-9 ]+)'
- model: '$1'
- - regex: '(ADR[A-Za-z0-9]+)'
- model: '$1'
-
-# Tesla Model S
-Tesla:
- regex: 'QtCarBrowser'
- device: 'car browser'
- model: 'Model S'
-
-# Kindle
-Kindle:
- regex: 'KF(?:OT|TT|JWI|JWA) Build|Kindle|Silk/(\d+)\.(\d+)'
- device: 'tablet'
- models:
- - regex: 'KFOT|Kindle Fire|Silk/(\d+)\.(\d+)'
- model: 'Fire'
- - regex: 'KFTT'
- model: 'Fire HD'
- - regex: 'KFJWI'
- model: 'Fire HD 8.9" WiFi'
- - regex: 'KFJWA'
- model: 'Fire HD 8.9" 4G'
-
-# NOKIA
-Nokia:
- regex: 'Nokia|Lumia|Maemo RX|portalmmm/2\.0 N7|portalmmm/2\.0 NK|nok[0-9]+|Symbian.*\s([a-zA-Z0-9]+)$'
- device: 'smartphone'
- models:
- - regex: 'NokiaInternal|Nokia-WAP-Toolkit|Nokia-MIT-Browser|Nokia Mobile|Nokia Browser|Nokia/Series'
- model: ''
- - regex: 'Nokia(N[0-9]+)'
- model: '$1'
- - regex: 'Nokia-([A-Za-z0-9]+)'
- model: 'N$1'
- - regex: 'NOKIA; ([A-Za-z0-9\- ]+)'
- model: '$1'
- - regex: 'NOKIA[ ]?([A-Za-z0-9\-]+)'
- model: '$1'
- - regex: 'NOKIA/([A-Za-z0-9 ]+)'
- model: '$1'
- - regex: '(Lumia [A-Za-z0-9\-]+)'
- model: '$1'
- - regex: 'Maemo RX-51 ([A-Za-z0-9]+)'
- model: '$1'
- - regex: 'Maemo RX-34'
- model: 'N800'
- - regex: 'portalmmm/2\.0 (N7[37]|NK[A-Za-z0-9]+)'
- model: '$1'
- - regex: 'nok([0-9]+)'
- model: '$1'
- - regex: 'Symbian.*\s([a-zA-Z0-9]+)$'
- device: 'feature phone'
- model: '$1'
-
-# RIM/BlackBerry
-RIM:
- regex: 'BB10;|BlackBerry|rim[0-9]+|PlayBook'
- device: 'smartphone'
-
- models:
- - regex: 'BB10; ([A-Za-z0-9\- ]+)\)'
- model: 'BlackBerry $1'
- - regex: 'PlayBook.+RIM Tablet OS'
- model: 'BlackBerry Playbook'
- device: 'tablet'
- - regex: 'BlackBerry(?: )?([A-Za-z0-9]+)'
- model: 'BlackBerry $1'
- - regex: 'rim([0-9]+)'
- model: 'BlackBerry $1'
- - regex: 'BlackBerry'
- model: 'BlackBerry'
-
-# PALM
-Palm:
- regex: '(?:Pre|Pixi)/(\d+)\.(\d+)|Palm|Treo'
- device: 'smartphone'
- models:
- - regex: '((?:Pre|Pixi))/(\d+\.\d+)'
- model: '$1 $2'
- - regex: 'Palm(?: )?([A-Za-z0-9]+)'
- model: '$1'
- - regex: 'Treo([A-Za-z0-9]+)'
- model: 'Treo $1'
-
-# HP
-HP:
- regex: 'Touch[Pp]ad|hp-tablet|HP(?: )?iPAQ|webOS.*(P160U)'
- device: 'smartphone'
- models:
- - regex: 'Touch[Pp]ad/(\d+\.\d+)|hp-tablet'
- model: 'TouchPad'
- device: 'tablet'
- - regex: 'HP(?: )?iPAQ(?: )?([A-Za-z0-9]+)'
- model: 'iPAQ $1'
- - regex: 'webOS.*(P160U)'
- model: 'Veer'
-
-# TiPhone
-TiPhone:
- regex: 'TiPhone(?: )?([A-Za-z0-9]+)'
- device: 'smartphone'
- model: '$1'
-
-# Apple
-Apple:
- regex: 'AppleTV|iPad|iPod|iPhone'
- models:
- - regex: 'AppleTV'
- model: 'Apple TV'
- device: 'tv'
- - regex: 'iPad'
- model: 'iPad'
- device: 'tablet'
- - regex: 'iPod'
- model: 'iPod Touch'
- device: 'palmtop'
- - regex: 'iPhone'
- model: 'iPhone'
- device: 'smartphone'
-
-# Acer
-Acer:
- regex: 'acer[\-_]([A-Za-z0-9]+)'
- device: 'smartphone'
- model: '$1'
-
-# Airness
-Airness:
- regex: 'AIRNESS-([A-Za-z0-9]+)'
- device: 'feature phone'
- model: '$1'
-
-# Alcatel
-Alcatel:
- regex: 'Alcatel|Alc([A-Za-z0-9]+)'
- device: 'smartphone'
- models:
- - regex: 'Alcatel UP'
- model: ''
- - regex: 'ALCATEL[ \-]([A-Za-z0-9\-]+)'
- model: '$1'
- - regex: 'ALCATEL_([A-Za-z0-9_]+)'
- model: '$1'
- - regex: 'Alc([A-Za-z0-9]+)'
- model: '$1'
-
-# Amoi
-Amoi:
- regex: 'Amoi'
- device: 'smartphone'
- models:
- - regex: 'Amoi[\- /](A-Za-z0-9]+)'
- mobile: '$1'
- - regex: 'Amoisonic-([A-Za-z0-9]+)'
- model: '$1'
-
-# Asus
-Asus:
- regex: 'Asus'
- device: 'smartphone'
- models:
- - regex: 'Asus(?:-|;)?([A-Za-z0-9]+)'
- model: '$1'
- - regex: 'ASUS (Transformer Pad TF300T)'
- device: 'tablet'
- model: '$1'
-
-# Audiovox
-Audiovox:
- regex: 'Audiovox|CDM|UTS(?:TARCOM)?\-|audio([A-Za-z0-9\-]+)'
- device: 'smartphone'
- models:
- - regex: 'Audiovox[_\-]([A-Za-z0-9\-]+)'
- model: '$1'
- - regex: 'CDM(?:-)?([A-Za-z0-9]+)'
- model: 'CDM-$1'
- - regex: 'UTS(?:TARCOM)?-([A-Za-z0-9\-]+)'
- model: 'CDM-$1'
- - regex: 'audio([A-Za-z0-9\-]+)'
- model: 'CDM-$1'
-
-# Avvio
-Avvio:
- regex: 'Avvio[ _]([A-Za-z0-9\-]+)'
- device: 'smartphone'
- model: '$1'
-
-# Bird
-Bird:
- regex: 'BIRD[\-. _]([A-Za-z0-9]+)'
- device: 'feature phone'
- model: '$1'
-
-# Becker
-Becker:
- regex: 'Becker-([A-Za-z0-9]+)'
- device: 'feature phone'
- model: '$1'
-
-# Beetel
-Beetel:
- regex: 'Beetel ([A-Za-z0-9]+)'
- device: 'feature phone'
- model: '$1'
-
-# BenQ-Siemens
-BenQ-Siemens:
- regex: 'BENQ-SIEMENS - ([A-Za-z0-9]+)'
- device: 'feature phone'
- model: '$1'
-
-# BenQ
-BenQ:
- regex: 'BENQ(?:[ \-])?([A-Za-z0-9]+)'
- device: 'feature phone'
- model: '$1'
-
-# Capitel
-Capitel:
- regex: 'Capitel-([A-Za-z0-9]+)'
- device: 'feature phone'
- model: '$1'
-
-# Compal
-Compal:
- regex: 'Compal-([A-Za-z0-9]+)'
- device: 'feature phone'
- model: '$1'
-
-# Cricket
-Cricket:
- regex: 'Cricket-([A-Za-z0-9]+)'
- device: 'feature phone'
- model: '$1'
-
-# Dell
-Dell:
- regex: 'Dell ([A-Za-z0-9]+)'
- device: 'smartphone'
- model: '$1'
-
-# Dbtel
-Dbtel:
- regex: 'DBTEL(?:[\-/])?([A-Za-z0-9]+)'
- device: 'feature phone'
- model: '$1'
-
-# Dicam
-Dicam:
- regex: 'DICAM-([A-Za-z0-9]+)'
- device: 'feature phone'
- model: '$1'
-
-# DoCoMo
-DoCoMo:
- regex: 'DoCoMo|\;FOMA|KGT/1\.0'
- device: 'feature phone'
- models:
- - regex: 'DoCoMo/[12]\.0[/ ]([A-Za-z0-9]+)'
- model: '$1'
- - regex: '([A-Za-z0-9]+)(?:_W)?\;FOMA'
- model: '$1'
- - regex: 'KGT/1\.0 ([A-Za-z0-9]+)'
- model: '$1'
-
-# Dopod
-Dopod:
- regex: 'Dopod(?: )?([A-Za-z0-9]+)'
- device: 'feature phone'
- model: '$1'
-
-# Ericy
-Ericy:
- regex: 'Ericy-([A-Za-z0-9]+)'
- device: 'feature phone'
- model: '$1'
-
-# Sony Ericsson
-Sony Ericsson:
- regex: 'Sony(?: )?Ericsson|portalmmm/2\.0 K'
- device: 'smartphone'
- models:
- - regex: 'SonyEricsson([A-Za-z0-9]+)'
- model: '$1'
- - regex: 'Sony(?: )?Ericsson ([A-Za-z0-9\-]+)'
- model: '$1'
- - regex: 'portalmmm/2.0 K([A-Za-z0-9]+)'
- model: 'K$1'
-
-# Ericsson
-Ericsson:
- regex: 'Ericsson(?:/ )?([A-Za-z0-9]+)'
- device: 'feature phone'
- model: '$1'
-
-# eTouch
-eTouch:
- regex: 'eTouch(?: )?([A-Za-z0-9]+)'
- device: 'smartphone'
- model: '$1'
-
-# Ezze
-Ezze:
- regex: 'EZZE-|EZ([A-Za-z0-9]+)'
- device: 'feature phone'
- models:
- - regex: 'EZZE-([A-Za-z0-9]+)'
- model: '$1'
- - regex: 'EZ([A-Za-z0-9]+)'
- model: 'EZ$1'
-
-# Ezio
-Ezio:
- regex: 'EZIO-([A-Za-z0-9]+)'
- device: 'feature phone'
- model: '$1'
-
-# Gionee
-Gionee:
- regex: 'GIONEE-([A-Za-z0-9]+)'
- device: 'feature phone'
- model: '$1'
-
-# Google
-Google:
- regex: 'Nexus|GoogleTV'
- device: 'smartphone'
- models:
- - regex: '(Galaxy Nexus)'
- model: '$1'
- - regex: '(Nexus (:?S|4|One))'
- model: '$1'
- - regex: '(Nexus (:?7|10))'
- device: 'tablet'
- model: '$1'
- - regex: '(GoogleTV)'
- device: 'tv'
- model: '$1'
-
-# Gradiente
-Gradiente:
- regex: 'GRADIENTE'
- device: 'feature phone'
- models:
- - regex: 'GRADIENTE-([A-Za-z0-9]+)'
- model: '$1'
- - regex: 'GRADIENTE ([A-Za-z0-9\-]+)'
- model: '$1'
-
-# Grundig
-Grundig:
- regex: 'GRUNDIG|portalmmm/2\.0 G'
- device: 'tv'
- models:
- - regex: 'GRUNDIG ([A-Za-z0-9]+)'
- model: '$1'
- - regex: 'portalmmm/2\.0 G([A-Za-z0-9]+)'
- model: 'G$1'
-
-# Haier
-Haier:
- regex: 'Haier[ -]([A-Za-z0-9\-]+)'
- device: 'feature phone'
- model: '$1'
-
-# Huawei
-Huawei:
- regex: 'Huawei|vodafone([A-Za-z0-9]+)'
- device: 'smartphone'
- models:
- - regex: 'Huawei(?:[\- /_]|/1\.0/)?([A-Za-z0-9]+)'
- model: '$1'
- - regex: 'vodafone([A-Za-z0-9]+)'
- model: 'Vodafone $1'
-
-# Innostream
-Innostream:
- regex: 'INNO([A-Za-z0-9]+)'
- device: 'feature phone'
- model: 'INNO$1'
-
-# Inq
-INQ:
- regex: 'INQ/([A-Za-z0-9\-]+)'
- device: 'feature phone'
- model: '$1'
-
-# i-mate
-i-mate:
- regex: 'i-mate ([A-Za-z0-9]+)'
- device: 'feature phone'
- model: '$1'
-
-# i-mobile
-i-mobile:
- regex: 'i-mobile(?: )?([A-Za-z0-9]+)'
- device: 'feature phone'
- model: '$1'
-
-# ikomo
-iKoMo:
- regex: 'iKoMo ([A-Za-z0-9]+)'
- device: 'feature phone'
- model: '$1'
-
-# kddi
-KDDI:
- regex: 'kddi-([A-Za-z0-9]+)'
- device: 'feature phone'
- model: '$1'
-
-# kyocera
-Kyocera:
- regex: 'Kyocera|KWC-|QC-'
- device: 'smartphone'
- models:
- - regex: 'Kyocera-KZ-([A-Za-z0-9]+)'
- model: 'KZ $1'
- - regex: 'Kyocera(:?[\-/])?([A-Za-z0-9]+)'
- model: '$1'
- - regex: '(?:KWC|QC)-([A-Za-z0-9]+)'
- model: '$1'
-
-# lanix
-Lanix:
- regex: 'LANIX-([A-Za-z0-9]+)'
- device: 'feature phone'
- model: '$1'
-
-# lct
-LCT:
- regex: 'LCT_([A-Za-z0-9]+)'
- device: 'feature phone'
- model: '$1'
-
-# lenovo
-Lenovo:
- regex: 'Lenovo[\-_]([A-Za-z0-9]+)'
- device: 'smartphone'
- model: '$1'
-
-# lguplus
-LGUPlus:
- regex: 'LGUPlus'
- device: 'smartphone'
- model: ''
-
-# lg
-LG:
- regex: 'LG|portalmmm/2\.0 (?:KE|KG|KP|L3)|VX[0-9]+'
- device: 'smartphone'
- models:
- - regex: 'LGE_DLNA_SDK'
- device: 'tv'
- model: 'NetCast'
- - regex: 'LGE(?: |-LG| LG-AX|-)([A-Za-z0-9]+)'
- model: '$1'
- - regex: 'LGE;([A-Za-z0-9\-]+)'
- model: '$1'
- - regex: 'LG(?:/|-LG| |-)?([A-Za-z0-9]+)'
- model: '$1'
- - regex: 'LG; ([A-Za-z0-9 ]+)'
- model: '$1'
- - regex: 'portalmmm/2.0 ((?:KE|KG|KP|L3)[A-Za-z0-9]+)'
- model: '$1'
- - regex: '(VX[0-9]+)'
- model: '$1'
-
-# microsoft
-Microsoft:
- regex: 'Xbox|KIN\.(?:One|Two)'
- device: 'console'
- model: 'Xbox 360'
-
-# Konka
-Konka:
- regex: 'KONKA_([A-Za-z0-9]+)'
- device: 'feature phone'
- model: '$1'
-
-# Karbonn
-Karbonn:
- regex: 'Karbonn_([A-Za-z0-9]+)'
- device: 'smartphone'
- model: '$1'
-
-# Sagem
-Sagem:
- regex: 'SAGEM|portalmmm/2.0 (?:SG|my)'
- device: 'smartphone'
- models:
- - regex: 'SAGEM ([A-Za-z0-9]+)'
- model: '$1'
- - regex: 'SAGEM-([A-Za-z0-9\-]+)'
- model: '$1'
- - regex: 'portalmmm/2.0 ((?:SG|my)[A-Za-z0-9]+)'
- model: '$1'
-
-# micromax
-MicroMax:
- regex: 'MicroMax(?:[ \-])?([A-Za-z0-9]+)'
- device: 'smartphone'
- model: '$1'
-
-# mio
-Mio:
- regex: 'MIO(?:/)?([A-Za-z0-9]+)'
- device: 'smartphone'
- model: '$1'
-
-# mitsubishi
-Mitsubishi:
- regex: 'MITSU|portalmmm/[12]\.0 M'
- device: 'feature phone'
- models:
- - regex: 'MITSU/[A-Za-z0-9.]+ \(([A-Za-z0-9]+)\)'
- model: '$1'
- - regex: 'MITSU[ \-]?([A-Za-z0-9]+)'
- model: '$1'
- - regex: 'portalmmm/[12]\.0 (M[A-Za-z0-9]+)'
- model: '$1'
-
-# motorola
-Motorola:
- regex: 'MOT|(?<!AN)DROID (?:Build|([A-Za-z0-9]+))|portalmmm/2.0 (?:E378i|L6|L7|v3)'
- device: 'smartphone'
- models:
- - regex: 'Motorola[ \-]([A-Za-z0-9]+)'
- model: '$1'
- - regex: 'MOTORAZR[ \-]([A-Za-z0-9]+)'
- model: 'RAZR $1'
- - regex: 'MOTORIZR[ \-]([A-Za-z0-9]+)'
- model: 'RIZR $1'
- - regex: 'MOT[O]?[\-]?([A-Za-z0-9.]+)'
- model: '$1'
- - regex: '(?<!AN)DROID (?:Build|([A-Za-z0-9]+))'
- model: 'DROID $1'
- - regex: 'portalmmm/2.0 ((?:E378i|L6|L7|V3)[A-Za-z0-9]+)'
- model: '$1'
-
-# myphone
-MyPhone:
- regex: 'MyPhone([A-Za-z0-9]+)'
- device: 'smartphone'
- model: '$1'
-
-# nec
-NEC:
- regex: 'NEC|KGT/2\.0|portalmmm/1\.0 (?:DB|N)|(?:portalmmm|o2imode)/2.0[ ,]N'
- device: 'smartphone'
- models:
- - regex: '(?:NEC-|KGT/2\.0 )([A-Za-z0-9]+)'
- model: '$1'
- - regex: 'portalmmm/1\.0 ((?:DB|N)[A-Za-z0-9]+)'
- model: '$1'
- - regex: '(?:portalmmm|o2imode)/2\.0[ ,](N[A-Za-z0-9]+)'
- model: '$1'
-
-# newgen
-Newgen:
- regex: 'NEWGEN\-([A-Za-z0-9]+)'
- device: 'feature phone'
- model: '$1'
-
-# nintendo
-Nintendo:
- regex: 'Nintendo (([3]?DS[i]?)|Wii[U]?)'
- device: 'console'
- model: '$1'
-
-# ngm
-NGM:
- regex: 'NGM_([A-Za-z0-9]+)'
- device: 'smartphone'
- model: '$1'
-
-# nexian
-Nexian:
- regex: 'Nexian'
- device: 'smartphone'
- models:
- - regex: 'Nexian[ ]?([A-Za-z0-9\-]+)'
- model: '$1'
- - regex: 'Nexian-([A-Za-z0-9]+)'
- model: '$1'
-
-# o2
-O2:
- regex: 'Xda|O2[ \-]|COCOON'
- device: 'smartphone'
- models:
- - regex: '(Xda[ _][A-Za-z0-9_]+)'
- models: '$1'
- - regex: '(COCOON)'
- models: '$1'
- - regex: 'O2 ([A-Za-z0-9 ]+)'
- models: '$1'
- - regex: 'O2-([A-Za-z0-9]+)'
- models: '$1'
-
-# onda
-Onda:
- regex: 'Onda'
- device: 'smartphone'
- models:
- regex: '([A-Za-z0-9]+)[ _]Onda'
- model: '$1'
- regex: 'Onda ([A-Za-z0-9]+)'
- model: '$1'
-
-# oppo
-OPPO:
- regex: 'OPPO[ ]?([A-Za-z0-9]+)'
- device: 'smartphone'
- model: '$1'
-
-# orange
-Orange:
- regex: 'SPV[ \-]?([A-Za-z0-9]+)'
- device: 'smartphone'
- model: 'SPV $1'
-
-# panasonic
-Panasonic:
- regex: 'Panasonic'
- device: 'smartphone'
- models:
- - regex: 'Panasonic MIL DLNA'
- device: 'tv'
- model: 'Viera Cast'
- - regex: 'Panasonic[ \-]?([A-Za-z0-9]+)'
- model: '$1'
- - regex: 'portalmmm/2.0 (P[A-Za-z0-9]+)'
- model: '$1'
-
-# philips
-Philips:
- regex: 'Philips'
- device: 'smartphone'
- models:
- - regex: 'Philips-FISIO ([A-Za-z0-9]+)'
- model: 'Fisio $1'
- - regex: 'Philips[ ]?([A-Za-z0-9]+)'
- model: '$1'
- - regex: 'Philips-([A-Za-z0-9\-@]+)'
- model: '$1'
-
-# phoneOne
-phoneOne:
- regex: 'phoneOne[ \-]?([A-Za-z0-9]+)'
- device: 'smartphone'
- model: '$1'
-
-# Rover
-Rover:
- regex: 'Rover ([0-9]+)'
- device: 'feature phone'
- model: '$1'
-
-# Siemens
-Siemens:
- regex: 'SIEMENS|SIE-|portalmmm/2\.0 SI|S55|SL45i'
- device: 'smartphone'
- models:
- - regex: 'SIEMENS[ \-]([A-Za-z0-9]+)'
- model: '$1'
- - regex: 'SIE(?:MENS )?[\-]?([A-Za-z0-9]+)'
- model: '$1'
- - regex: '(S55|SL45i)'
- model: '$1'
- - regex: 'portalmmm/2.0 (SI[A-Za-z0-9]+)'
- model: '$1'
-
-# Samsung
-Samsung:
- regex: 'SAMSUNG|S(?:CH|GH|PH|EC|AM)-|SMART-TV|GT-|Galaxy|(?:portalmmm|o2imode)/2\.0 [SZ]|sam[rua]'
- device: 'smartphone'
- models:
- - regex: 'SAMSUNG[\-;][ ]?([A-Za-z0-9]+[\-_][A-Za-z0-9]+)'
- model: '$1'
- - regex: 'SAMSUNG[ _/]?([A-Za-z0-9\-]+)'
- model: '$1'
- - regex: 'SAMSUNG;[ ]?([A-Za-z0-9 ]+)'
- model: '$1'
- - regex: '((?:SCH|SGH|SPH|GT)-[A-Za-z0-9]+)'
- model: '$1'
- - regex: 'SEC-([A-Za-z0-9]+)'
- model: '$1'
- - regex: 'SAM-([A-Za-z0-9]+)'
- model: 'SCH-$1'
- - regex: 'SMART-TV'
- device: 'tv'
- model: 'Smart TV'
- - regex: '(Galaxy [A-Za-z0-9]+)'
- model: '$1'
- - regex: '(?:portalmmm|o2imode)/2\.0 ([SZ][A-Za-z0-9]+)'
- model: '$1'
- - regex: 'sam([rua][0-9]+)'
- model: 'SCH-$1'
-
-# pantech
-Pantech:
- regex: 'Pantech|P[GTN]-|TX[T]?[0-9]+'
- device: 'smartphone'
- models:
- - regex: 'Pantech[ \-]?([A-Za-z0-9]+)'
- model: '$1'
- - regex: 'Pantech_([A-Za-z0-9\-]+)'
- model: '$1'
- - regex: '(P[GTN]-[A-Za-z0-9]+)'
- model: '$1'
- - regex: '(TX[T]?[0-9]+)'
- model: '$1'
-
-# Sanyo
-Sanyo:
- regex: 'Sanyo|MobilePhone '
- device: 'smartphone'
- models:
- - regex: 'SANYO[ \-_]([A-Za-z0-9\-]+)'
- model: '$1'
- - regex: 'MobilePhone ([A-Za-z0-9\-]+)'
- model: '$1'
-
-# Sega
-Sega:
- regex: 'Dreamcast'
- device: 'console'
- model: 'Dreamcast'
-
-# Sendo
-Sendo:
- regex: 'Sendo([A-Za-z0-9]+)'
- device: 'feature phone'
- model: '$1'
-
-# Spice
-Spice:
- regex: 'Spice'
- device: 'smartphone'
- models:
- - regex: 'Spice ([A-Za-z0-9\-]+)'
- model: '$1'
- - regex: 'Spice-([A-Za-z0-9]+)'
- model: '$1'
-
-# Sharp
-Sharp:
- regex: 'SHARP|SBM'
- device: 'smartphone'
- models:
- - regex: 'SHARP-AQUOS'
- device: 'tv'
- model: 'Aquos Net Plus'
- - regex: 'SHARP[ \-]([A-Za-z0-9\-]+)'
- model: '$1'
- - regex: '(?:SHARP|SBM)([A-Za-z0-9]+)'
- model: '$1'
-
-# Softbank
-Softbank:
- regex: 'Softbank|J-PHONE'
- device: 'smartphone'
- models:
- - regex: 'Softbank/[12]\.0/([A-Za-z0-9]+)'
- model: '$1'
- - regex: '([A-Za-z0-9]+);Softbank;'
- model: '$1'
- - regex: 'J-PHONE/[0-9]\.[0-9]/([A-Za-z0-9\-]+)'
- model: '$1'
-
-# Sony
-Sony:
- regex: 'Sony|PlayStation'
- device: 'smartphone'
- models:
- - regex: 'Sony[ ]?([A-Za-z0-9\-]+)'
- model: '$1'
- - regex: '(PlayStation (?:3|Portable|Vita))'
- device: 'console'
- model: '$1'
-
-# Qtek
-Qtek:
- regex: 'Qtek[ _]?([A-Za-z0-9]+)'
- device: 'smartphone'
- model: '$1'
-
-# T-Mobile
-T-Mobile:
- regex: 'T-Mobile[ _]([A-Za-z0-9 ]+)'
- device: 'smartphone'
- model: '$1'
-
-# Tcl
-TCL:
- regex: 'TCL-([A-Za-z0-9]+)'
- device: 'smartphone'
- model: '$1'
-
-# Telit
-Telit:
- regex: 'Telit'
- device: 'feature phone'
- models:
- - regex: 'Telit_Mobile_Terminals-([A-Za-z0-9]+)'
- model: '$1'
- - regex: 'Telit[\-_]?([A-Za-z0-9]+)'
- model: '$1'
-
-# Tianyu
-TIANYU:
- regex: 'TIANYU'
- device: 'feature phone'
- models:
- - regex: 'TIANYU ([A-Za-z0-9]+)'
- model: '$1'
- - regex: 'TIANYU-KTOUCH/([A-Za-z0-9]+)'
- model: '$1'
-
-# Toplux
-Toplux:
- regex: 'Toplux ([A-Za-z0-9]+)'
- device: 'feature phone'
- model: '$1'
-
-# UTStarcom
-UTStarcom:
- regex: 'utstar([A-Za-z0-9]+)'
- device: 'feature phone'
- model: '$1'
-
-# Vitelcom
-Vitelcom:
- regex: 'Vitelcom|portalmmm/[12].0 TSM'
- device: 'feature phone'
- models:
- - regex: 'TSM-([A-Za-z0-9]+)'
- model: '$1'
- - regex: 'TSM([A-Za-z0-9\-]+)'
- model: '$1'
- - regex: 'portalmmm/[12].0 (TSM[A-Za-z0-9 ]+)'
- model: '$1'
-
-# VK Mobile
-VK Mobile:
- regex: 'VK[\-]?([A-Za-z0-9 ]+)'
- device: 'feature phone'
- model: '$1'
-
-# Vertu
-Vertu:
- regex: 'Vertu[ ]?([A-Za-z0-9]+)'
- device: 'feature phone'
- model: '$1'
-
-# Videocon
-Videocon:
- regex: 'Videocon_([A-Za-z0-9]+)'
- device: 'smartphone'
- model: '$1'
-
-# Voxtel
-Voxtel:
- regex: 'Voxtel_([A-Za-z0-9]+)'
- device: 'feature phone'
- model: '$1'
-
-# Wellcom
-WellcoM:
- regex: 'WELLCOM[ _\-/]([A-Za-z0-9]+)'
- device: 'smartphone'
- model: '$1'
-
-# Wonu
-Wonu:
- regex: 'Wonu ([A-Za-z0-9]+)'
- device: 'feature phone'
- model: '$1'
-
-# Zonda
-Zonda:
- regex: '(ZM(?:CK|EM|TFTV|TN)[A-Za-z0-9]+)'
- device: 'feature phone'
- model: '$1'
-
-# Toshiba
-Toshiba:
- regex: 'Toshiba|portalmmm/[12].0 TS'
- device: 'smartphone'
- models:
- - regex: 'Toshiba[ /_\-]?([A-Za-z0-9 ]+)'
- model: '$1'
- - regex: 'portalmmm/[12].0 (TS[A-Za-z0-9 ]+)'
- model: '$1'
-
-# Fly
-Fly:
- regex: 'Fly|MERIDIAN-'
- device: 'smartphone'
- models:
- - regex: 'Fly[ _\-]?([A-Za-z0-9]+)'
- model: '$1'
- - regex: 'MERIDIAN-([A-Za-z0-9]+)'
- model: '$1'
-
-# WebTV
-WebTV:
- regex: 'WebTV/(\d+\.\d+)'
- device: 'tv'
- model: '$1'
-
-# ZTE
-ZTE:
- regex: 'ZTE|Z331'
- device: 'smartphone'
- models:
- - regex: '(Z331)'
- model: '$1'
- - regex: 'ZTE-(?:G |G-)?([A-Za-z0-9 _]+)'
- model: '$1'
- - regex: 'ZTE ([A-Za-z0-9]+)'
- model: '$1'
-
-# Symbian to Nokia ??
-# Change name from Nokia to other to not change above Nokia element
-#Nokia:
-# regex: 'Symbian'
+###############
+# Piwik - Open source web analytics
+#
+# @link http://piwik.org
+# @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
+#
+# @category Piwik_Plugins
+# @package Piwik_DevicesDetection
+###############
+
+# HTC
+HTC:
+ regex: 'HTC|Sprint APA|ADR[A-Za-z0-9]+'
+ device: 'smartphone'
+ models:
+ - regex: 'HTC ([A-Za-z0-9]+) Build'
+ model: '$1'
+ - regex: 'HTC ([A-Za-z0-9]+(?: [A-Za-z0-9]+)?)'
+ model: '$1'
+ - regex: 'USCCHTC(\d+)'
+ model: '$1'
+ - regex: 'Sprint APA(9292)'
+ model: '$1 (Sprint)'
+ - regex: 'HTC_([A-Za-z0-9_]+)'
+ model: '$1'
+ - regex: 'HTC(?:[\-/ ])?([A-Za-z0-9]+)'
+ model: '$1'
+ - regex: 'HTC;(?: )?([A-Za-z0-9 ]+)'
+ model: '$1'
+ - regex: '(ADR[A-Za-z0-9]+)'
+ model: '$1'
+
+# Tesla Model S
+Tesla:
+ regex: 'QtCarBrowser'
+ device: 'car browser'
+ model: 'Model S'
+
+# Kindle
+Kindle:
+ regex: 'KF(?:OT|TT|JWI|JWA) Build|Kindle|Silk/(\d+)\.(\d+)'
+ device: 'tablet'
+ models:
+ - regex: 'KFOT|Kindle Fire|Silk/(\d+)\.(\d+)'
+ model: 'Fire'
+ - regex: 'KFTT'
+ model: 'Fire HD'
+ - regex: 'KFJWI'
+ model: 'Fire HD 8.9" WiFi'
+ - regex: 'KFJWA'
+ model: 'Fire HD 8.9" 4G'
+
+# NOKIA
+Nokia:
+ regex: 'Nokia|Lumia|Maemo RX|portalmmm/2\.0 N7|portalmmm/2\.0 NK|nok[0-9]+|Symbian.*\s([a-zA-Z0-9]+)$'
+ device: 'smartphone'
+ models:
+ - regex: 'NokiaInternal|Nokia-WAP-Toolkit|Nokia-MIT-Browser|Nokia Mobile|Nokia Browser|Nokia/Series'
+ model: ''
+ - regex: 'Nokia(N[0-9]+)'
+ model: '$1'
+ - regex: 'Nokia-([A-Za-z0-9]+)'
+ model: 'N$1'
+ - regex: 'NOKIA; ([A-Za-z0-9\- ]+)'
+ model: '$1'
+ - regex: 'NOKIA[ ]?([A-Za-z0-9\-]+)'
+ model: '$1'
+ - regex: 'NOKIA/([A-Za-z0-9 ]+)'
+ model: '$1'
+ - regex: '(Lumia [A-Za-z0-9\-]+)'
+ model: '$1'
+ - regex: 'Maemo RX-51 ([A-Za-z0-9]+)'
+ model: '$1'
+ - regex: 'Maemo RX-34'
+ model: 'N800'
+ - regex: 'portalmmm/2\.0 (N7[37]|NK[A-Za-z0-9]+)'
+ model: '$1'
+ - regex: 'nok([0-9]+)'
+ model: '$1'
+ - regex: 'Symbian.*\s([a-zA-Z0-9]+)$'
+ device: 'feature phone'
+ model: '$1'
+
+# RIM/BlackBerry
+RIM:
+ regex: 'BB10;|BlackBerry|rim[0-9]+|PlayBook'
+ device: 'smartphone'
+
+ models:
+ - regex: 'BB10; ([A-Za-z0-9\- ]+)\)'
+ model: 'BlackBerry $1'
+ - regex: 'PlayBook.+RIM Tablet OS'
+ model: 'BlackBerry Playbook'
+ device: 'tablet'
+ - regex: 'BlackBerry(?: )?([A-Za-z0-9]+)'
+ model: 'BlackBerry $1'
+ - regex: 'rim([0-9]+)'
+ model: 'BlackBerry $1'
+ - regex: 'BlackBerry'
+ model: 'BlackBerry'
+
+# PALM
+Palm:
+ regex: '(?:Pre|Pixi)/(\d+)\.(\d+)|Palm|Treo'
+ device: 'smartphone'
+ models:
+ - regex: '((?:Pre|Pixi))/(\d+\.\d+)'
+ model: '$1 $2'
+ - regex: 'Palm(?: )?([A-Za-z0-9]+)'
+ model: '$1'
+ - regex: 'Treo([A-Za-z0-9]+)'
+ model: 'Treo $1'
+
+# HP
+HP:
+ regex: 'Touch[Pp]ad|hp-tablet|HP(?: )?iPAQ|webOS.*(P160U)'
+ device: 'smartphone'
+ models:
+ - regex: 'Touch[Pp]ad/(\d+\.\d+)|hp-tablet'
+ model: 'TouchPad'
+ device: 'tablet'
+ - regex: 'HP(?: )?iPAQ(?: )?([A-Za-z0-9]+)'
+ model: 'iPAQ $1'
+ - regex: 'webOS.*(P160U)'
+ model: 'Veer'
+
+# TiPhone
+TiPhone:
+ regex: 'TiPhone(?: )?([A-Za-z0-9]+)'
+ device: 'smartphone'
+ model: '$1'
+
+# Apple
+Apple:
+ regex: 'AppleTV|iPad|iPod|iPhone'
+ models:
+ - regex: 'AppleTV'
+ model: 'Apple TV'
+ device: 'tv'
+ - regex: 'iPad'
+ model: 'iPad'
+ device: 'tablet'
+ - regex: 'iPod'
+ model: 'iPod Touch'
+ device: 'palmtop'
+ - regex: 'iPhone'
+ model: 'iPhone'
+ device: 'smartphone'
+
+# Acer
+Acer:
+ regex: 'acer[\-_]([A-Za-z0-9]+)'
+ device: 'smartphone'
+ model: '$1'
+
+# Airness
+Airness:
+ regex: 'AIRNESS-([A-Za-z0-9]+)'
+ device: 'feature phone'
+ model: '$1'
+
+# Alcatel
+Alcatel:
+ regex: 'Alcatel|Alc([A-Za-z0-9]+)'
+ device: 'smartphone'
+ models:
+ - regex: 'Alcatel UP'
+ model: ''
+ - regex: 'ALCATEL[ \-]([A-Za-z0-9\-]+)'
+ model: '$1'
+ - regex: 'ALCATEL_([A-Za-z0-9_]+)'
+ model: '$1'
+ - regex: 'Alc([A-Za-z0-9]+)'
+ model: '$1'
+
+# Amoi
+Amoi:
+ regex: 'Amoi'
+ device: 'smartphone'
+ models:
+ - regex: 'Amoi[\- /](A-Za-z0-9]+)'
+ mobile: '$1'
+ - regex: 'Amoisonic-([A-Za-z0-9]+)'
+ model: '$1'
+
+# Asus
+Asus:
+ regex: 'Asus'
+ device: 'smartphone'
+ models:
+ - regex: 'Asus(?:-|;)?([A-Za-z0-9]+)'
+ model: '$1'
+ - regex: 'ASUS (Transformer Pad TF300T)'
+ device: 'tablet'
+ model: '$1'
+
+# Audiovox
+Audiovox:
+ regex: 'Audiovox|CDM|UTS(?:TARCOM)?\-|audio([A-Za-z0-9\-]+)'
+ device: 'smartphone'
+ models:
+ - regex: 'Audiovox[_\-]([A-Za-z0-9\-]+)'
+ model: '$1'
+ - regex: 'CDM(?:-)?([A-Za-z0-9]+)'
+ model: 'CDM-$1'
+ - regex: 'UTS(?:TARCOM)?-([A-Za-z0-9\-]+)'
+ model: 'CDM-$1'
+ - regex: 'audio([A-Za-z0-9\-]+)'
+ model: 'CDM-$1'
+
+# Avvio
+Avvio:
+ regex: 'Avvio[ _]([A-Za-z0-9\-]+)'
+ device: 'smartphone'
+ model: '$1'
+
+# Bird
+Bird:
+ regex: 'BIRD[\-. _]([A-Za-z0-9]+)'
+ device: 'feature phone'
+ model: '$1'
+
+# Becker
+Becker:
+ regex: 'Becker-([A-Za-z0-9]+)'
+ device: 'feature phone'
+ model: '$1'
+
+# Beetel
+Beetel:
+ regex: 'Beetel ([A-Za-z0-9]+)'
+ device: 'feature phone'
+ model: '$1'
+
+# BenQ-Siemens
+BenQ-Siemens:
+ regex: 'BENQ-SIEMENS - ([A-Za-z0-9]+)'
+ device: 'feature phone'
+ model: '$1'
+
+# BenQ
+BenQ:
+ regex: 'BENQ(?:[ \-])?([A-Za-z0-9]+)'
+ device: 'feature phone'
+ model: '$1'
+
+# Capitel
+Capitel:
+ regex: 'Capitel-([A-Za-z0-9]+)'
+ device: 'feature phone'
+ model: '$1'
+
+# Compal
+Compal:
+ regex: 'Compal-([A-Za-z0-9]+)'
+ device: 'feature phone'
+ model: '$1'
+
+# Cricket
+Cricket:
+ regex: 'Cricket-([A-Za-z0-9]+)'
+ device: 'feature phone'
+ model: '$1'
+
+# Dell
+Dell:
+ regex: 'Dell ([A-Za-z0-9]+)'
+ device: 'smartphone'
+ model: '$1'
+
+# Dbtel
+Dbtel:
+ regex: 'DBTEL(?:[\-/])?([A-Za-z0-9]+)'
+ device: 'feature phone'
+ model: '$1'
+
+# Dicam
+Dicam:
+ regex: 'DICAM-([A-Za-z0-9]+)'
+ device: 'feature phone'
+ model: '$1'
+
+# DoCoMo
+DoCoMo:
+ regex: 'DoCoMo|\;FOMA|KGT/1\.0'
+ device: 'feature phone'
+ models:
+ - regex: 'DoCoMo/[12]\.0[/ ]([A-Za-z0-9]+)'
+ model: '$1'
+ - regex: '([A-Za-z0-9]+)(?:_W)?\;FOMA'
+ model: '$1'
+ - regex: 'KGT/1\.0 ([A-Za-z0-9]+)'
+ model: '$1'
+
+# Dopod
+Dopod:
+ regex: 'Dopod(?: )?([A-Za-z0-9]+)'
+ device: 'feature phone'
+ model: '$1'
+
+# Ericy
+Ericy:
+ regex: 'Ericy-([A-Za-z0-9]+)'
+ device: 'feature phone'
+ model: '$1'
+
+# Sony Ericsson
+Sony Ericsson:
+ regex: 'Sony(?: )?Ericsson|portalmmm/2\.0 K'
+ device: 'smartphone'
+ models:
+ - regex: 'SonyEricsson([A-Za-z0-9]+)'
+ model: '$1'
+ - regex: 'Sony(?: )?Ericsson ([A-Za-z0-9\-]+)'
+ model: '$1'
+ - regex: 'portalmmm/2.0 K([A-Za-z0-9]+)'
+ model: 'K$1'
+
+# Ericsson
+Ericsson:
+ regex: 'Ericsson(?:/ )?([A-Za-z0-9]+)'
+ device: 'feature phone'
+ model: '$1'
+
+# eTouch
+eTouch:
+ regex: 'eTouch(?: )?([A-Za-z0-9]+)'
+ device: 'smartphone'
+ model: '$1'
+
+# Ezze
+Ezze:
+ regex: 'EZZE-|EZ([A-Za-z0-9]+)'
+ device: 'feature phone'
+ models:
+ - regex: 'EZZE-([A-Za-z0-9]+)'
+ model: '$1'
+ - regex: 'EZ([A-Za-z0-9]+)'
+ model: 'EZ$1'
+
+# Ezio
+Ezio:
+ regex: 'EZIO-([A-Za-z0-9]+)'
+ device: 'feature phone'
+ model: '$1'
+
+# Gionee
+Gionee:
+ regex: 'GIONEE-([A-Za-z0-9]+)'
+ device: 'feature phone'
+ model: '$1'
+
+# Google
+Google:
+ regex: 'Nexus|GoogleTV'
+ device: 'smartphone'
+ models:
+ - regex: '(Galaxy Nexus)'
+ model: '$1'
+ - regex: '(Nexus (:?S|4|One))'
+ model: '$1'
+ - regex: '(Nexus (:?7|10))'
+ device: 'tablet'
+ model: '$1'
+ - regex: '(GoogleTV)'
+ device: 'tv'
+ model: '$1'
+
+# Gradiente
+Gradiente:
+ regex: 'GRADIENTE'
+ device: 'feature phone'
+ models:
+ - regex: 'GRADIENTE-([A-Za-z0-9]+)'
+ model: '$1'
+ - regex: 'GRADIENTE ([A-Za-z0-9\-]+)'
+ model: '$1'
+
+# Grundig
+Grundig:
+ regex: 'GRUNDIG|portalmmm/2\.0 G'
+ device: 'tv'
+ models:
+ - regex: 'GRUNDIG ([A-Za-z0-9]+)'
+ model: '$1'
+ - regex: 'portalmmm/2\.0 G([A-Za-z0-9]+)'
+ model: 'G$1'
+
+# Haier
+Haier:
+ regex: 'Haier[ -]([A-Za-z0-9\-]+)'
+ device: 'feature phone'
+ model: '$1'
+
+# Huawei
+Huawei:
+ regex: 'Huawei|vodafone([A-Za-z0-9]+)'
+ device: 'smartphone'
+ models:
+ - regex: 'Huawei(?:[\- /_]|/1\.0/)?([A-Za-z0-9]+)'
+ model: '$1'
+ - regex: 'vodafone([A-Za-z0-9]+)'
+ model: 'Vodafone $1'
+
+# Innostream
+Innostream:
+ regex: 'INNO([A-Za-z0-9]+)'
+ device: 'feature phone'
+ model: 'INNO$1'
+
+# Inq
+INQ:
+ regex: 'INQ/([A-Za-z0-9\-]+)'
+ device: 'feature phone'
+ model: '$1'
+
+# i-mate
+i-mate:
+ regex: 'i-mate ([A-Za-z0-9]+)'
+ device: 'feature phone'
+ model: '$1'
+
+# i-mobile
+i-mobile:
+ regex: 'i-mobile(?: )?([A-Za-z0-9]+)'
+ device: 'feature phone'
+ model: '$1'
+
+# ikomo
+iKoMo:
+ regex: 'iKoMo ([A-Za-z0-9]+)'
+ device: 'feature phone'
+ model: '$1'
+
+# kddi
+KDDI:
+ regex: 'kddi-([A-Za-z0-9]+)'
+ device: 'feature phone'
+ model: '$1'
+
+# kyocera
+Kyocera:
+ regex: 'Kyocera|KWC-|QC-'
+ device: 'smartphone'
+ models:
+ - regex: 'Kyocera-KZ-([A-Za-z0-9]+)'
+ model: 'KZ $1'
+ - regex: 'Kyocera(:?[\-/])?([A-Za-z0-9]+)'
+ model: '$1'
+ - regex: '(?:KWC|QC)-([A-Za-z0-9]+)'
+ model: '$1'
+
+# lanix
+Lanix:
+ regex: 'LANIX-([A-Za-z0-9]+)'
+ device: 'feature phone'
+ model: '$1'
+
+# lct
+LCT:
+ regex: 'LCT_([A-Za-z0-9]+)'
+ device: 'feature phone'
+ model: '$1'
+
+# lenovo
+Lenovo:
+ regex: 'Lenovo[\-_]([A-Za-z0-9]+)'
+ device: 'smartphone'
+ model: '$1'
+
+# lguplus
+LGUPlus:
+ regex: 'LGUPlus'
+ device: 'smartphone'
+ model: ''
+
+# lg
+LG:
+ regex: 'LG|portalmmm/2\.0 (?:KE|KG|KP|L3)|VX[0-9]+'
+ device: 'smartphone'
+ models:
+ - regex: 'LGE_DLNA_SDK'
+ device: 'tv'
+ model: 'NetCast'
+ - regex: 'LGE(?: |-LG| LG-AX|-)([A-Za-z0-9]+)'
+ model: '$1'
+ - regex: 'LGE;([A-Za-z0-9\-]+)'
+ model: '$1'
+ - regex: 'LG(?:/|-LG| |-)?([A-Za-z0-9]+)'
+ model: '$1'
+ - regex: 'LG; ([A-Za-z0-9 ]+)'
+ model: '$1'
+ - regex: 'portalmmm/2.0 ((?:KE|KG|KP|L3)[A-Za-z0-9]+)'
+ model: '$1'
+ - regex: '(VX[0-9]+)'
+ model: '$1'
+
+# microsoft
+Microsoft:
+ regex: 'Xbox|KIN\.(?:One|Two)'
+ device: 'console'
+ model: 'Xbox 360'
+
+# Konka
+Konka:
+ regex: 'KONKA_([A-Za-z0-9]+)'
+ device: 'feature phone'
+ model: '$1'
+
+# Karbonn
+Karbonn:
+ regex: 'Karbonn_([A-Za-z0-9]+)'
+ device: 'smartphone'
+ model: '$1'
+
+# Sagem
+Sagem:
+ regex: 'SAGEM|portalmmm/2.0 (?:SG|my)'
+ device: 'smartphone'
+ models:
+ - regex: 'SAGEM ([A-Za-z0-9]+)'
+ model: '$1'
+ - regex: 'SAGEM-([A-Za-z0-9\-]+)'
+ model: '$1'
+ - regex: 'portalmmm/2.0 ((?:SG|my)[A-Za-z0-9]+)'
+ model: '$1'
+
+# micromax
+MicroMax:
+ regex: 'MicroMax(?:[ \-])?([A-Za-z0-9]+)'
+ device: 'smartphone'
+ model: '$1'
+
+# mio
+Mio:
+ regex: 'MIO(?:/)?([A-Za-z0-9]+)'
+ device: 'smartphone'
+ model: '$1'
+
+# mitsubishi
+Mitsubishi:
+ regex: 'MITSU|portalmmm/[12]\.0 M'
+ device: 'feature phone'
+ models:
+ - regex: 'MITSU/[A-Za-z0-9.]+ \(([A-Za-z0-9]+)\)'
+ model: '$1'
+ - regex: 'MITSU[ \-]?([A-Za-z0-9]+)'
+ model: '$1'
+ - regex: 'portalmmm/[12]\.0 (M[A-Za-z0-9]+)'
+ model: '$1'
+
+# motorola
+Motorola:
+ regex: 'MOT|(?<!AN)DROID (?:Build|([A-Za-z0-9]+))|portalmmm/2.0 (?:E378i|L6|L7|v3)'
+ device: 'smartphone'
+ models:
+ - regex: 'Motorola[ \-]([A-Za-z0-9]+)'
+ model: '$1'
+ - regex: 'MOTORAZR[ \-]([A-Za-z0-9]+)'
+ model: 'RAZR $1'
+ - regex: 'MOTORIZR[ \-]([A-Za-z0-9]+)'
+ model: 'RIZR $1'
+ - regex: 'MOT[O]?[\-]?([A-Za-z0-9.]+)'
+ model: '$1'
+ - regex: '(?<!AN)DROID (?:Build|([A-Za-z0-9]+))'
+ model: 'DROID $1'
+ - regex: 'portalmmm/2.0 ((?:E378i|L6|L7|V3)[A-Za-z0-9]+)'
+ model: '$1'
+
+# myphone
+MyPhone:
+ regex: 'MyPhone([A-Za-z0-9]+)'
+ device: 'smartphone'
+ model: '$1'
+
+# nec
+NEC:
+ regex: 'NEC|KGT/2\.0|portalmmm/1\.0 (?:DB|N)|(?:portalmmm|o2imode)/2.0[ ,]N'
+ device: 'smartphone'
+ models:
+ - regex: '(?:NEC-|KGT/2\.0 )([A-Za-z0-9]+)'
+ model: '$1'
+ - regex: 'portalmmm/1\.0 ((?:DB|N)[A-Za-z0-9]+)'
+ model: '$1'
+ - regex: '(?:portalmmm|o2imode)/2\.0[ ,](N[A-Za-z0-9]+)'
+ model: '$1'
+
+# newgen
+Newgen:
+ regex: 'NEWGEN\-([A-Za-z0-9]+)'
+ device: 'feature phone'
+ model: '$1'
+
+# nintendo
+Nintendo:
+ regex: 'Nintendo (([3]?DS[i]?)|Wii[U]?)'
+ device: 'console'
+ model: '$1'
+
+# ngm
+NGM:
+ regex: 'NGM_([A-Za-z0-9]+)'
+ device: 'smartphone'
+ model: '$1'
+
+# nexian
+Nexian:
+ regex: 'Nexian'
+ device: 'smartphone'
+ models:
+ - regex: 'Nexian[ ]?([A-Za-z0-9\-]+)'
+ model: '$1'
+ - regex: 'Nexian-([A-Za-z0-9]+)'
+ model: '$1'
+
+# o2
+O2:
+ regex: 'Xda|O2[ \-]|COCOON'
+ device: 'smartphone'
+ models:
+ - regex: '(Xda[ _][A-Za-z0-9_]+)'
+ models: '$1'
+ - regex: '(COCOON)'
+ models: '$1'
+ - regex: 'O2 ([A-Za-z0-9 ]+)'
+ models: '$1'
+ - regex: 'O2-([A-Za-z0-9]+)'
+ models: '$1'
+
+# onda
+Onda:
+ regex: 'Onda'
+ device: 'smartphone'
+ models:
+ regex: '([A-Za-z0-9]+)[ _]Onda'
+ model: '$1'
+ regex: 'Onda ([A-Za-z0-9]+)'
+ model: '$1'
+
+# oppo
+OPPO:
+ regex: 'OPPO[ ]?([A-Za-z0-9]+)'
+ device: 'smartphone'
+ model: '$1'
+
+# orange
+Orange:
+ regex: 'SPV[ \-]?([A-Za-z0-9]+)'
+ device: 'smartphone'
+ model: 'SPV $1'
+
+# panasonic
+Panasonic:
+ regex: 'Panasonic'
+ device: 'smartphone'
+ models:
+ - regex: 'Panasonic MIL DLNA'
+ device: 'tv'
+ model: 'Viera Cast'
+ - regex: 'Panasonic[ \-]?([A-Za-z0-9]+)'
+ model: '$1'
+ - regex: 'portalmmm/2.0 (P[A-Za-z0-9]+)'
+ model: '$1'
+
+# philips
+Philips:
+ regex: 'Philips'
+ device: 'smartphone'
+ models:
+ - regex: 'Philips-FISIO ([A-Za-z0-9]+)'
+ model: 'Fisio $1'
+ - regex: 'Philips[ ]?([A-Za-z0-9]+)'
+ model: '$1'
+ - regex: 'Philips-([A-Za-z0-9\-@]+)'
+ model: '$1'
+
+# phoneOne
+phoneOne:
+ regex: 'phoneOne[ \-]?([A-Za-z0-9]+)'
+ device: 'smartphone'
+ model: '$1'
+
+# Rover
+Rover:
+ regex: 'Rover ([0-9]+)'
+ device: 'feature phone'
+ model: '$1'
+
+# Siemens
+Siemens:
+ regex: 'SIEMENS|SIE-|portalmmm/2\.0 SI|S55|SL45i'
+ device: 'smartphone'
+ models:
+ - regex: 'SIEMENS[ \-]([A-Za-z0-9]+)'
+ model: '$1'
+ - regex: 'SIE(?:MENS )?[\-]?([A-Za-z0-9]+)'
+ model: '$1'
+ - regex: '(S55|SL45i)'
+ model: '$1'
+ - regex: 'portalmmm/2.0 (SI[A-Za-z0-9]+)'
+ model: '$1'
+
+# Samsung
+Samsung:
+ regex: 'SAMSUNG|S(?:CH|GH|PH|EC|AM)-|SMART-TV|GT-|Galaxy|(?:portalmmm|o2imode)/2\.0 [SZ]|sam[rua]'
+ device: 'smartphone'
+ models:
+ - regex: 'SAMSUNG[\-;][ ]?([A-Za-z0-9]+[\-_][A-Za-z0-9]+)'
+ model: '$1'
+ - regex: 'SAMSUNG[ _/]?([A-Za-z0-9\-]+)'
+ model: '$1'
+ - regex: 'SAMSUNG;[ ]?([A-Za-z0-9 ]+)'
+ model: '$1'
+ - regex: '((?:SCH|SGH|SPH|GT)-[A-Za-z0-9]+)'
+ model: '$1'
+ - regex: 'SEC-([A-Za-z0-9]+)'
+ model: '$1'
+ - regex: 'SAM-([A-Za-z0-9]+)'
+ model: 'SCH-$1'
+ - regex: 'SMART-TV'
+ device: 'tv'
+ model: 'Smart TV'
+ - regex: '(Galaxy [A-Za-z0-9]+)'
+ model: '$1'
+ - regex: '(?:portalmmm|o2imode)/2\.0 ([SZ][A-Za-z0-9]+)'
+ model: '$1'
+ - regex: 'sam([rua][0-9]+)'
+ model: 'SCH-$1'
+
+# pantech
+Pantech:
+ regex: 'Pantech|P[GTN]-|TX[T]?[0-9]+'
+ device: 'smartphone'
+ models:
+ - regex: 'Pantech[ \-]?([A-Za-z0-9]+)'
+ model: '$1'
+ - regex: 'Pantech_([A-Za-z0-9\-]+)'
+ model: '$1'
+ - regex: '(P[GTN]-[A-Za-z0-9]+)'
+ model: '$1'
+ - regex: '(TX[T]?[0-9]+)'
+ model: '$1'
+
+# Sanyo
+Sanyo:
+ regex: 'Sanyo|MobilePhone '
+ device: 'smartphone'
+ models:
+ - regex: 'SANYO[ \-_]([A-Za-z0-9\-]+)'
+ model: '$1'
+ - regex: 'MobilePhone ([A-Za-z0-9\-]+)'
+ model: '$1'
+
+# Sega
+Sega:
+ regex: 'Dreamcast'
+ device: 'console'
+ model: 'Dreamcast'
+
+# Sendo
+Sendo:
+ regex: 'Sendo([A-Za-z0-9]+)'
+ device: 'feature phone'
+ model: '$1'
+
+# Spice
+Spice:
+ regex: 'Spice'
+ device: 'smartphone'
+ models:
+ - regex: 'Spice ([A-Za-z0-9\-]+)'
+ model: '$1'
+ - regex: 'Spice-([A-Za-z0-9]+)'
+ model: '$1'
+
+# Sharp
+Sharp:
+ regex: 'SHARP|SBM'
+ device: 'smartphone'
+ models:
+ - regex: 'SHARP-AQUOS'
+ device: 'tv'
+ model: 'Aquos Net Plus'
+ - regex: 'SHARP[ \-]([A-Za-z0-9\-]+)'
+ model: '$1'
+ - regex: '(?:SHARP|SBM)([A-Za-z0-9]+)'
+ model: '$1'
+
+# Softbank
+Softbank:
+ regex: 'Softbank|J-PHONE'
+ device: 'smartphone'
+ models:
+ - regex: 'Softbank/[12]\.0/([A-Za-z0-9]+)'
+ model: '$1'
+ - regex: '([A-Za-z0-9]+);Softbank;'
+ model: '$1'
+ - regex: 'J-PHONE/[0-9]\.[0-9]/([A-Za-z0-9\-]+)'
+ model: '$1'
+
+# Sony
+Sony:
+ regex: 'Sony|PlayStation'
+ device: 'smartphone'
+ models:
+ - regex: 'Sony[ ]?([A-Za-z0-9\-]+)'
+ model: '$1'
+ - regex: '(PlayStation (?:3|Portable|Vita))'
+ device: 'console'
+ model: '$1'
+
+# Qtek
+Qtek:
+ regex: 'Qtek[ _]?([A-Za-z0-9]+)'
+ device: 'smartphone'
+ model: '$1'
+
+# T-Mobile
+T-Mobile:
+ regex: 'T-Mobile[ _]([A-Za-z0-9 ]+)'
+ device: 'smartphone'
+ model: '$1'
+
+# Tcl
+TCL:
+ regex: 'TCL-([A-Za-z0-9]+)'
+ device: 'smartphone'
+ model: '$1'
+
+# Telit
+Telit:
+ regex: 'Telit'
+ device: 'feature phone'
+ models:
+ - regex: 'Telit_Mobile_Terminals-([A-Za-z0-9]+)'
+ model: '$1'
+ - regex: 'Telit[\-_]?([A-Za-z0-9]+)'
+ model: '$1'
+
+# Tianyu
+TIANYU:
+ regex: 'TIANYU'
+ device: 'feature phone'
+ models:
+ - regex: 'TIANYU ([A-Za-z0-9]+)'
+ model: '$1'
+ - regex: 'TIANYU-KTOUCH/([A-Za-z0-9]+)'
+ model: '$1'
+
+# Toplux
+Toplux:
+ regex: 'Toplux ([A-Za-z0-9]+)'
+ device: 'feature phone'
+ model: '$1'
+
+# UTStarcom
+UTStarcom:
+ regex: 'utstar([A-Za-z0-9]+)'
+ device: 'feature phone'
+ model: '$1'
+
+# Vitelcom
+Vitelcom:
+ regex: 'Vitelcom|portalmmm/[12].0 TSM'
+ device: 'feature phone'
+ models:
+ - regex: 'TSM-([A-Za-z0-9]+)'
+ model: '$1'
+ - regex: 'TSM([A-Za-z0-9\-]+)'
+ model: '$1'
+ - regex: 'portalmmm/[12].0 (TSM[A-Za-z0-9 ]+)'
+ model: '$1'
+
+# VK Mobile
+VK Mobile:
+ regex: 'VK[\-]?([A-Za-z0-9 ]+)'
+ device: 'feature phone'
+ model: '$1'
+
+# Vertu
+Vertu:
+ regex: 'Vertu[ ]?([A-Za-z0-9]+)'
+ device: 'feature phone'
+ model: '$1'
+
+# Videocon
+Videocon:
+ regex: 'Videocon_([A-Za-z0-9]+)'
+ device: 'smartphone'
+ model: '$1'
+
+# Voxtel
+Voxtel:
+ regex: 'Voxtel_([A-Za-z0-9]+)'
+ device: 'feature phone'
+ model: '$1'
+
+# Wellcom
+WellcoM:
+ regex: 'WELLCOM[ _\-/]([A-Za-z0-9]+)'
+ device: 'smartphone'
+ model: '$1'
+
+# Wonu
+Wonu:
+ regex: 'Wonu ([A-Za-z0-9]+)'
+ device: 'feature phone'
+ model: '$1'
+
+# Zonda
+Zonda:
+ regex: '(ZM(?:CK|EM|TFTV|TN)[A-Za-z0-9]+)'
+ device: 'feature phone'
+ model: '$1'
+
+# Toshiba
+Toshiba:
+ regex: 'Toshiba|portalmmm/[12].0 TS'
+ device: 'smartphone'
+ models:
+ - regex: 'Toshiba[ /_\-]?([A-Za-z0-9 ]+)'
+ model: '$1'
+ - regex: 'portalmmm/[12].0 (TS[A-Za-z0-9 ]+)'
+ model: '$1'
+
+# Fly
+Fly:
+ regex: 'Fly|MERIDIAN-'
+ device: 'smartphone'
+ models:
+ - regex: 'Fly[ _\-]?([A-Za-z0-9]+)'
+ model: '$1'
+ - regex: 'MERIDIAN-([A-Za-z0-9]+)'
+ model: '$1'
+
+# WebTV
+WebTV:
+ regex: 'WebTV/(\d+\.\d+)'
+ device: 'tv'
+ model: '$1'
+
+# ZTE
+ZTE:
+ regex: 'ZTE|Z331'
+ device: 'smartphone'
+ models:
+ - regex: '(Z331)'
+ model: '$1'
+ - regex: 'ZTE-(?:G |G-)?([A-Za-z0-9 _]+)'
+ model: '$1'
+ - regex: 'ZTE ([A-Za-z0-9]+)'
+ model: '$1'
+
+# Symbian to Nokia ??
+# Change name from Nokia to other to not change above Nokia element
+#Nokia:
+# regex: 'Symbian'
# device: 'feature phone' \ No newline at end of file
diff --git a/plugins/DevicesDetection/UserAgentParserEnhanced/regexes/oss.yml b/plugins/DevicesDetection/UserAgentParserEnhanced/regexes/oss.yml
index f1660d636f..71b85f987f 100644
--- a/plugins/DevicesDetection/UserAgentParserEnhanced/regexes/oss.yml
+++ b/plugins/DevicesDetection/UserAgentParserEnhanced/regexes/oss.yml
@@ -1,427 +1,427 @@
-###############
-# Piwik - Open source web analytics
-#
-# @link http://piwik.org
-# @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
-#
-# @category Piwik_Plugins
-# @package Piwik_DevicesDetection
-###############
-
-##########
-# Tizen
-##########
-- regex: 'Tizen'
- name: 'Tizen'
- version: ''
-
-
-
-##########
-# Android
-##########
-- regex: 'Android[ /](\d+\.\d+)'
- name: 'Android'
- version: '$1'
-
-
-- regex: 'Android|Silk-Accelerated=[a-z]{4,5}'
- name: 'Android'
- version: ''
-
-
-
-##########
-# Linux
-##########
-- regex: 'Linux; .*((?:Arch Linux|Debian|Knoppix|Mint|Ubuntu|Kubuntu|Xubuntu|Lubuntu|Fedora|Red Hat|Mandriva|Gentoo|Slackware|SUSE|Puppy|CentOS|BackTrack|YunOs|Presto))[ /](\d+\.\d+)'
- name: '$1'
- version: '$2'
-
-
-- regex: '((?:Arch Linux|Debian|Knoppix|Mint|Ubuntu|Kubuntu|Xubuntu|Lubuntu|Fedora|Red Hat|Mandriva|Gentoo|Slackware|SUSE|Puppy|CentOS|BackTrack|YunOs|Presto));.*Linux'
- name: '$1'
- version: ''
-
-
-- regex: 'Linux; |Linux (?:x86_64|zbov|i686)'
- name: 'Linux'
- version: ''
-
-
-
-##########
-# Windows Mobile
-##########
-- regex: 'Windows Phone (?:OS)?[ ]?(\d+\.\d+)'
- name: 'Windows Phone'
- version: '$1'
-
-
-- regex: 'XBLWP7|Windows Phone'
- name: 'Windows Phone'
- version: ''
-
-- regex: 'Windows CE'
- name: 'Windows CE'
- version: ''
-
-
-- regex: '(?:IEMobile|Windows Mobile)(?: (\d+\.\d+))?'
- name: 'Windows Mobile'
- version: '$1'
-
-
-- regex: 'Windows NT 6.2; ARM;'
- name: 'Windows RT'
- version: ''
-
-
-
-##########
-# Windows
-##########
-- regex: 'CYGWIN_NT-6.2|Windows NT 6.2|Windows 8'
- name: 'Windows 8'
- version: '8'
-
-
-- regex: 'CYGWIN_NT-6.1|Windows NT 6.1|Windows 7'
- name: 'Windows 7'
- version: '7'
-
-
-- regex: 'CYGWIN_NT-6.0|Windows NT 6.0|Windows Vista'
- name: 'Windows Vista'
- version: 'Vista'
-
-
-- regex: 'CYGWIN_NT-5.2|Windows NT 5.2|Windows Server 2003 / XP x64'
- name: 'Windows Server 2003'
- version: 'Server 2003'
-
-
-- regex: 'CYGWIN_NT-5.1|Windows NT 5.1|Windows XP'
- name: 'Windows XP'
- version: 'XP'
-
-
-- regex: 'CYGWIN_NT-5.0|Windows NT 5.0|Windows 2000'
- name: 'Windows 2000'
- version: '2000'
-
-
-- regex: 'CYGWIN_NT-4.0|Windows NT 4.0|WinNT|Windows NT'
- name: 'Windows NT'
- version: 'NT'
-
-
-- regex: 'CYGWIN_ME-4.90|Win 9x 4.90|Windows ME'
- name: 'Windows ME'
- version: 'ME'
-
-
-- regex: 'CYGWIN_98-4.10|Win98|Windows 98'
- name: 'Windows 98'
- version: '98'
-
-
-- regex: 'CYGWIN_95-4.0|Win32|Win95|Windows 95|Windows_95'
- name: 'Windows 95'
- version: '95'
-
-
-- regex: 'Windows 3.1'
- name: 'Windows 3.1'
- version: '3.1'
-
-
-- regex: 'Windows'
- name: 'Windows'
- version: ''
-
-
-
-##########
-# Mac
-##########
-- regex: 'Mac OS X (\d+[_.]\d+)'
- name: 'Mac'
-
- version: '$1'
-
-- regex: 'Darwin|Macintosh|Mac_PowerPC|PPC|Mac PowerPC'
- name: 'Mac'
- version: ''
-
-
-
-##########
-# iOS
-##########
-- regex: '(?:CPU OS|iPhone OS) (\d+_\d+)'
- name: 'iOS'
-
- version: '$1'
-
-- regex: '(?:iPhone|iPad|iPod)(?:.*Mac OS X.*Version/(\d+\.\d+)|; Opera)'
- name: 'iOS'
- version: '$1'
-
-
-
-##########
-# webOS
-##########
-- regex: '(?:webOS|Palm webOS)(?:/(\d+\.\d+))?'
- name: 'webOS'
- version: '$1'
-
-
-- regex: '(?:PalmOS|Palm OS)(?:/(\d+\.\d+))?'
- name: 'PalmOS'
- version: ''
-
-
-
-##########
-# ChromeOS
-##########
-- regex: 'CrOS [a-z0-9_]+ (\d+\.\d+)'
- name: 'Chrome OS'
- version: '$1'
-
-
-
-##########
-# BlackBerry
-##########
-- regex: '(?:BB10;.+Version|Black[Bb]erry[0-9a-z]+|Black[Bb]erry.+Version)/(\d+\.\d+)'
- name: 'BlackBerry OS'
- version: '$1'
-
-
-- regex: 'RIM Tablet OS (\d+\.\d+)'
- name: 'BlackBerry Tablet OS'
- version: '$1'
-
-
-- regex: 'RIM Tablet OS|QNX|Play[Bb]ook'
- name: 'BlackBerry Tablet OS'
- version: ''
-
-
-- regex: 'Black[Bb]erry'
- name: 'BlackBerry OS'
- version: ''
-
-
-
-##########
-# Symbian
-##########
-- regex: 'Symbian[Oo][Ss]/(\d+\.\d+)'
- name: 'Symbian OS'
- version: '$1'
-
-
-- regex: 'Symbian/3.+NokiaBrowser/7\.3'
- name: 'Symbian'
- version: '^3 Anna'
-
-
-- regex: 'Symbian/3.+NokiaBrowser/7\.4'
- name: 'Symbian'
- version: '^3 Belle'
-
-
-- regex: 'Symbian[/]?3'
- name: 'Symbian^3'
- version: '^3'
-
-
-- regex: '(?:Series 60|SymbOS|S60)(?:[ /]?(\d+\.\d+|V\d+))?'
- name: 'Symbian OS Series 60'
- version: '$1'
-
-
-- regex: 'Series40'
- name: 'Symbian OS Series 40'
- version: ''
-
-
-- regex: 'MeeGo|WeTab'
- name: 'MeeGo'
- version: ''
-
-
-- regex: 'Symbian [Oo][Ss]|SymbOS'
- name: 'Symbian OS'
- version: ''
-
-
-- regex: 'Nokia'
- name: 'Symbian'
- version: ''
-
-
-
-##########
-# Firefox OS
-##########
-- regex: '(?:Mobile|Tablet);.+Firefox/\d+\.\d+'
- name: 'Firefox OS'
- version: ''
-
-
-
-##########
-# Bada
-##########
-- regex: 'bada'
- name: 'Bada'
- version: ''
-
-
-
-##########
-# Brew
-##########
-- regex: '(?:Brew MP|BREW|BMP)(?:[ /](\d+\.\d+))?'
- name: 'Brew'
- version: '$1'
-
-
-
-##########
-# Web TV
-##########
-- regex: 'GoogleTV[ /](\d+\.\d+)|GoogleTV'
- name: 'Google TV'
- version: '$1'
-
-
-- regex: 'AppleTV/(\d+\.\d+)'
- name: 'Apple TV'
- version: '$1'
-
-
-- regex: 'WebTV/(\d+\.\d+)'
- name: 'WebTV'
- version: '$1'
-
-
-
-##########
-# Unix
-##########
-- regex: 'SunOS'
- name: 'Solaris'
- version: ''
-
-
-- regex: 'AIX'
- name: 'AIX'
- version: ''
-
-
-- regex: 'HP-UX'
- name: 'HP-UX'
- version: ''
-
-
-- regex: 'FreeBSD'
- name: 'FreeBSD'
- version: ''
-
-
-- regex: 'NetBSD'
- name: 'NetBSD'
- version: ''
-
-
-- regex: 'OpenBSD'
- name: 'OpenBSD'
- version: ''
-
-
-- regex: 'DragonFly'
- name: 'DragonFly'
- version: ''
-
-
-- regex: 'Syllable'
- name: 'Syllable'
- version: ''
-
-
-- regex: 'IRIX'
- name: 'IRIX'
- version: ''
-
-
-- regex: 'OSF1'
- name: 'OSF1'
- version: ''
-
-
-
-##########
-# Gaming Console
-##########
-- regex: 'Nintendo Wii'
- name: 'Nintendo'
- version: 'Wii'
-
-
-- regex: 'PlayStation 3|PlayStation3'
- name: 'PlayStation'
- version: '3'
-
-
-- regex: 'Xbox|KIN\.(?:One|Two)'
- name: 'Xbox'
- version: '360'
-
-
-
-##########
-# Mobile Gaming Console
-##########
-- regex: 'Nitro|Nintendo ([3]?DS[i]?)'
- name: 'Nintendo Mobile'
- version: '$1'
-
-
-- regex: 'PlayStation ((?:Portable|Vita))'
- name: 'PlayStation'
- version: '$1'
-
-
-
-##########
-# IBM
-##########
-- regex: 'OS/2'
- name: 'OS/2'
- version: ''
-
-
-
-##########
-# Simulators
-##########
-- regex: '(Talkatone|WinWAP)'
- name: '$1'
- version: ''
-
-
-
-##########
-# Bot
-##########
-- regex: '(nuhk|Googlebot|Yammybot|Openbot|Slurp|MSNBot|Ask Jeeves/Teoma|ia_archiver|ScoutJet|Gulper Web Bot|EmailWolf|grub-client|Download Demon|OmniWeb|SearchExpress|Microsoft URL Control|bot|borg|yahoo|slurp|msnbot|msrbot|openbot|archiver|netresearch|transcoder|crawler|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|findlinksYottaaMonitor|BrowserMob|HttpMonitor|YandexBot|Slurp|BingPreview|PagePeeker|ThumbShotsBot|WebThumb|URL2PNG|ZooShot|GomezA|Catchpoint bot|Willow Internet Crawler|Google SketchUp|Read%20Later|Minimo|Pingdom.com|facebookexternalhit|Twitterbot|RackspaceBot)'
- name: 'Bot '
- version: ''
-
+###############
+# Piwik - Open source web analytics
+#
+# @link http://piwik.org
+# @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
+#
+# @category Piwik_Plugins
+# @package Piwik_DevicesDetection
+###############
+
+##########
+# Tizen
+##########
+- regex: 'Tizen'
+ name: 'Tizen'
+ version: ''
+
+
+
+##########
+# Android
+##########
+- regex: 'Android[ /](\d+\.\d+)'
+ name: 'Android'
+ version: '$1'
+
+
+- regex: 'Android|Silk-Accelerated=[a-z]{4,5}'
+ name: 'Android'
+ version: ''
+
+
+
+##########
+# Linux
+##########
+- regex: 'Linux; .*((?:Arch Linux|Debian|Knoppix|Mint|Ubuntu|Kubuntu|Xubuntu|Lubuntu|Fedora|Red Hat|Mandriva|Gentoo|Slackware|SUSE|Puppy|CentOS|BackTrack|YunOs|Presto))[ /](\d+\.\d+)'
+ name: '$1'
+ version: '$2'
+
+
+- regex: '((?:Arch Linux|Debian|Knoppix|Mint|Ubuntu|Kubuntu|Xubuntu|Lubuntu|Fedora|Red Hat|Mandriva|Gentoo|Slackware|SUSE|Puppy|CentOS|BackTrack|YunOs|Presto));.*Linux'
+ name: '$1'
+ version: ''
+
+
+- regex: 'Linux; |Linux (?:x86_64|zbov|i686)'
+ name: 'Linux'
+ version: ''
+
+
+
+##########
+# Windows Mobile
+##########
+- regex: 'Windows Phone (?:OS)?[ ]?(\d+\.\d+)'
+ name: 'Windows Phone'
+ version: '$1'
+
+
+- regex: 'XBLWP7|Windows Phone'
+ name: 'Windows Phone'
+ version: ''
+
+- regex: 'Windows CE'
+ name: 'Windows CE'
+ version: ''
+
+
+- regex: '(?:IEMobile|Windows Mobile)(?: (\d+\.\d+))?'
+ name: 'Windows Mobile'
+ version: '$1'
+
+
+- regex: 'Windows NT 6.2; ARM;'
+ name: 'Windows RT'
+ version: ''
+
+
+
+##########
+# Windows
+##########
+- regex: 'CYGWIN_NT-6.2|Windows NT 6.2|Windows 8'
+ name: 'Windows 8'
+ version: '8'
+
+
+- regex: 'CYGWIN_NT-6.1|Windows NT 6.1|Windows 7'
+ name: 'Windows 7'
+ version: '7'
+
+
+- regex: 'CYGWIN_NT-6.0|Windows NT 6.0|Windows Vista'
+ name: 'Windows Vista'
+ version: 'Vista'
+
+
+- regex: 'CYGWIN_NT-5.2|Windows NT 5.2|Windows Server 2003 / XP x64'
+ name: 'Windows Server 2003'
+ version: 'Server 2003'
+
+
+- regex: 'CYGWIN_NT-5.1|Windows NT 5.1|Windows XP'
+ name: 'Windows XP'
+ version: 'XP'
+
+
+- regex: 'CYGWIN_NT-5.0|Windows NT 5.0|Windows 2000'
+ name: 'Windows 2000'
+ version: '2000'
+
+
+- regex: 'CYGWIN_NT-4.0|Windows NT 4.0|WinNT|Windows NT'
+ name: 'Windows NT'
+ version: 'NT'
+
+
+- regex: 'CYGWIN_ME-4.90|Win 9x 4.90|Windows ME'
+ name: 'Windows ME'
+ version: 'ME'
+
+
+- regex: 'CYGWIN_98-4.10|Win98|Windows 98'
+ name: 'Windows 98'
+ version: '98'
+
+
+- regex: 'CYGWIN_95-4.0|Win32|Win95|Windows 95|Windows_95'
+ name: 'Windows 95'
+ version: '95'
+
+
+- regex: 'Windows 3.1'
+ name: 'Windows 3.1'
+ version: '3.1'
+
+
+- regex: 'Windows'
+ name: 'Windows'
+ version: ''
+
+
+
+##########
+# Mac
+##########
+- regex: 'Mac OS X (\d+[_.]\d+)'
+ name: 'Mac'
+
+ version: '$1'
+
+- regex: 'Darwin|Macintosh|Mac_PowerPC|PPC|Mac PowerPC'
+ name: 'Mac'
+ version: ''
+
+
+
+##########
+# iOS
+##########
+- regex: '(?:CPU OS|iPhone OS) (\d+_\d+)'
+ name: 'iOS'
+
+ version: '$1'
+
+- regex: '(?:iPhone|iPad|iPod)(?:.*Mac OS X.*Version/(\d+\.\d+)|; Opera)'
+ name: 'iOS'
+ version: '$1'
+
+
+
+##########
+# webOS
+##########
+- regex: '(?:webOS|Palm webOS)(?:/(\d+\.\d+))?'
+ name: 'webOS'
+ version: '$1'
+
+
+- regex: '(?:PalmOS|Palm OS)(?:/(\d+\.\d+))?'
+ name: 'PalmOS'
+ version: ''
+
+
+
+##########
+# ChromeOS
+##########
+- regex: 'CrOS [a-z0-9_]+ (\d+\.\d+)'
+ name: 'Chrome OS'
+ version: '$1'
+
+
+
+##########
+# BlackBerry
+##########
+- regex: '(?:BB10;.+Version|Black[Bb]erry[0-9a-z]+|Black[Bb]erry.+Version)/(\d+\.\d+)'
+ name: 'BlackBerry OS'
+ version: '$1'
+
+
+- regex: 'RIM Tablet OS (\d+\.\d+)'
+ name: 'BlackBerry Tablet OS'
+ version: '$1'
+
+
+- regex: 'RIM Tablet OS|QNX|Play[Bb]ook'
+ name: 'BlackBerry Tablet OS'
+ version: ''
+
+
+- regex: 'Black[Bb]erry'
+ name: 'BlackBerry OS'
+ version: ''
+
+
+
+##########
+# Symbian
+##########
+- regex: 'Symbian[Oo][Ss]/(\d+\.\d+)'
+ name: 'Symbian OS'
+ version: '$1'
+
+
+- regex: 'Symbian/3.+NokiaBrowser/7\.3'
+ name: 'Symbian'
+ version: '^3 Anna'
+
+
+- regex: 'Symbian/3.+NokiaBrowser/7\.4'
+ name: 'Symbian'
+ version: '^3 Belle'
+
+
+- regex: 'Symbian[/]?3'
+ name: 'Symbian^3'
+ version: '^3'
+
+
+- regex: '(?:Series 60|SymbOS|S60)(?:[ /]?(\d+\.\d+|V\d+))?'
+ name: 'Symbian OS Series 60'
+ version: '$1'
+
+
+- regex: 'Series40'
+ name: 'Symbian OS Series 40'
+ version: ''
+
+
+- regex: 'MeeGo|WeTab'
+ name: 'MeeGo'
+ version: ''
+
+
+- regex: 'Symbian [Oo][Ss]|SymbOS'
+ name: 'Symbian OS'
+ version: ''
+
+
+- regex: 'Nokia'
+ name: 'Symbian'
+ version: ''
+
+
+
+##########
+# Firefox OS
+##########
+- regex: '(?:Mobile|Tablet);.+Firefox/\d+\.\d+'
+ name: 'Firefox OS'
+ version: ''
+
+
+
+##########
+# Bada
+##########
+- regex: 'bada'
+ name: 'Bada'
+ version: ''
+
+
+
+##########
+# Brew
+##########
+- regex: '(?:Brew MP|BREW|BMP)(?:[ /](\d+\.\d+))?'
+ name: 'Brew'
+ version: '$1'
+
+
+
+##########
+# Web TV
+##########
+- regex: 'GoogleTV[ /](\d+\.\d+)|GoogleTV'
+ name: 'Google TV'
+ version: '$1'
+
+
+- regex: 'AppleTV/(\d+\.\d+)'
+ name: 'Apple TV'
+ version: '$1'
+
+
+- regex: 'WebTV/(\d+\.\d+)'
+ name: 'WebTV'
+ version: '$1'
+
+
+
+##########
+# Unix
+##########
+- regex: 'SunOS'
+ name: 'Solaris'
+ version: ''
+
+
+- regex: 'AIX'
+ name: 'AIX'
+ version: ''
+
+
+- regex: 'HP-UX'
+ name: 'HP-UX'
+ version: ''
+
+
+- regex: 'FreeBSD'
+ name: 'FreeBSD'
+ version: ''
+
+
+- regex: 'NetBSD'
+ name: 'NetBSD'
+ version: ''
+
+
+- regex: 'OpenBSD'
+ name: 'OpenBSD'
+ version: ''
+
+
+- regex: 'DragonFly'
+ name: 'DragonFly'
+ version: ''
+
+
+- regex: 'Syllable'
+ name: 'Syllable'
+ version: ''
+
+
+- regex: 'IRIX'
+ name: 'IRIX'
+ version: ''
+
+
+- regex: 'OSF1'
+ name: 'OSF1'
+ version: ''
+
+
+
+##########
+# Gaming Console
+##########
+- regex: 'Nintendo Wii'
+ name: 'Nintendo'
+ version: 'Wii'
+
+
+- regex: 'PlayStation 3|PlayStation3'
+ name: 'PlayStation'
+ version: '3'
+
+
+- regex: 'Xbox|KIN\.(?:One|Two)'
+ name: 'Xbox'
+ version: '360'
+
+
+
+##########
+# Mobile Gaming Console
+##########
+- regex: 'Nitro|Nintendo ([3]?DS[i]?)'
+ name: 'Nintendo Mobile'
+ version: '$1'
+
+
+- regex: 'PlayStation ((?:Portable|Vita))'
+ name: 'PlayStation'
+ version: '$1'
+
+
+
+##########
+# IBM
+##########
+- regex: 'OS/2'
+ name: 'OS/2'
+ version: ''
+
+
+
+##########
+# Simulators
+##########
+- regex: '(Talkatone|WinWAP)'
+ name: '$1'
+ version: ''
+
+
+
+##########
+# Bot
+##########
+- regex: '(nuhk|Googlebot|Yammybot|Openbot|Slurp|MSNBot|Ask Jeeves/Teoma|ia_archiver|ScoutJet|Gulper Web Bot|EmailWolf|grub-client|Download Demon|OmniWeb|SearchExpress|Microsoft URL Control|bot|borg|yahoo|slurp|msnbot|msrbot|openbot|archiver|netresearch|transcoder|crawler|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|findlinksYottaaMonitor|BrowserMob|HttpMonitor|YandexBot|Slurp|BingPreview|PagePeeker|ThumbShotsBot|WebThumb|URL2PNG|ZooShot|GomezA|Catchpoint bot|Willow Internet Crawler|Google SketchUp|Read%20Later|Minimo|Pingdom.com|facebookexternalhit|Twitterbot|RackspaceBot)'
+ name: 'Bot '
+ version: ''
+
\ No newline at end of file
diff --git a/plugins/DevicesDetection/UserAgentParserEnhanced/spyc.php b/plugins/DevicesDetection/UserAgentParserEnhanced/spyc.php
index ed3233ee1b..e19d562035 100644
--- a/plugins/DevicesDetection/UserAgentParserEnhanced/spyc.php
+++ b/plugins/DevicesDetection/UserAgentParserEnhanced/spyc.php
@@ -1,1046 +1,1046 @@
-<?php
-/**
- * Spyc -- A Simple PHP YAML Class
- * @version 0.5
- * @author Vlad Andersen <vlad.andersen@gmail.com>
- * @author Chris Wanstrath <chris@ozmm.org>
- * @link http://code.google.com/p/spyc/
- * @copyright Copyright 2005-2006 Chris Wanstrath, 2006-2011 Vlad Andersen
- * @license http://www.opensource.org/licenses/mit-license.php MIT License
- * @package Spyc
- */
-
-if (!function_exists('spyc_load')) {
- /**
- * Parses YAML to array.
- * @param string $string YAML string.
- * @return array
- */
- function spyc_load ($string) {
- return Spyc::YAMLLoadString($string);
- }
-}
-
-if (!function_exists('spyc_load_file')) {
- /**
- * Parses YAML to array.
- * @param string $file Path to YAML file.
- * @return array
- */
- function spyc_load_file ($file) {
- return Spyc::YAMLLoad($file);
- }
-}
-
-/**
- * The Simple PHP YAML Class.
- *
- * This class can be used to read a YAML file and convert its contents
- * into a PHP array. It currently supports a very limited subsection of
- * the YAML spec.
- *
- * Usage:
- * <code>
- * $Spyc = new Spyc;
- * $array = $Spyc->load($file);
- * </code>
- * or:
- * <code>
- * $array = Spyc::YAMLLoad($file);
- * </code>
- * or:
- * <code>
- * $array = spyc_load_file($file);
- * </code>
- * @package Spyc
- */
-class Spyc {
-
- // SETTINGS
-
- const REMPTY = "\0\0\0\0\0";
-
- /**
- * Setting this to true will force YAMLDump to enclose any string value in
- * quotes. False by default.
- *
- * @var bool
- */
- public $setting_dump_force_quotes = false;
-
- /**
- * Setting this to true will forse YAMLLoad to use syck_load function when
- * possible. False by default.
- * @var bool
- */
- public $setting_use_syck_is_possible = false;
-
-
-
- /**#@+
- * @access private
- * @var mixed
- */
- private $_dumpIndent;
- private $_dumpWordWrap;
- private $_containsGroupAnchor = false;
- private $_containsGroupAlias = false;
- private $path;
- private $result;
- private $LiteralPlaceHolder = '___YAML_Literal_Block___';
- private $SavedGroups = array();
- private $indent;
- /**
- * Path modifier that should be applied after adding current element.
- * @var array
- */
- private $delayedPath = array();
-
- /**#@+
- * @access public
- * @var mixed
- */
- public $_nodeId;
-
-/**
- * Load a valid YAML string to Spyc.
- * @param string $input
- * @return array
- */
- public function load ($input) {
- return $this->__loadString($input);
- }
-
- /**
- * Load a valid YAML file to Spyc.
- * @param string $file
- * @return array
- */
- public function loadFile ($file) {
- return $this->__load($file);
- }
-
- /**
- * Load YAML into a PHP array statically
- *
- * The load method, when supplied with a YAML stream (string or file),
- * will do its best to convert YAML in a file into a PHP array. Pretty
- * simple.
- * Usage:
- * <code>
- * $array = Spyc::YAMLLoad('lucky.yaml');
- * print_r($array);
- * </code>
- * @access public
- * @return array
- * @param string $input Path of YAML file or string containing YAML
- */
- public static function YAMLLoad($input) {
- $Spyc = new Spyc;
- return $Spyc->__load($input);
- }
-
- /**
- * Load a string of YAML into a PHP array statically
- *
- * The load method, when supplied with a YAML string, will do its best
- * to convert YAML in a string into a PHP array. Pretty simple.
- *
- * Note: use this function if you don't want files from the file system
- * loaded and processed as YAML. This is of interest to people concerned
- * about security whose input is from a string.
- *
- * Usage:
- * <code>
- * $array = Spyc::YAMLLoadString("---\n0: hello world\n");
- * print_r($array);
- * </code>
- * @access public
- * @return array
- * @param string $input String containing YAML
- */
- public static function YAMLLoadString($input) {
- $Spyc = new Spyc;
- return $Spyc->__loadString($input);
- }
-
- /**
- * Dump YAML from PHP array statically
- *
- * The dump method, when supplied with an array, will do its best
- * to convert the array into friendly YAML. Pretty simple. Feel free to
- * save the returned string as nothing.yaml and pass it around.
- *
- * Oh, and you can decide how big the indent is and what the wordwrap
- * for folding is. Pretty cool -- just pass in 'false' for either if
- * you want to use the default.
- *
- * Indent's default is 2 spaces, wordwrap's default is 40 characters. And
- * you can turn off wordwrap by passing in 0.
- *
- * @access public
- * @return string
- * @param array $array PHP array
- * @param int $indent Pass in false to use the default, which is 2
- * @param int $wordwrap Pass in 0 for no wordwrap, false for default (40)
- */
- public static function YAMLDump($array,$indent = false,$wordwrap = false) {
- $spyc = new Spyc;
- return $spyc->dump($array,$indent,$wordwrap);
- }
-
-
- /**
- * Dump PHP array to YAML
- *
- * The dump method, when supplied with an array, will do its best
- * to convert the array into friendly YAML. Pretty simple. Feel free to
- * save the returned string as tasteful.yaml and pass it around.
- *
- * Oh, and you can decide how big the indent is and what the wordwrap
- * for folding is. Pretty cool -- just pass in 'false' for either if
- * you want to use the default.
- *
- * Indent's default is 2 spaces, wordwrap's default is 40 characters. And
- * you can turn off wordwrap by passing in 0.
- *
- * @access public
- * @return string
- * @param array $array PHP array
- * @param int $indent Pass in false to use the default, which is 2
- * @param int $wordwrap Pass in 0 for no wordwrap, false for default (40)
- */
- public function dump($array,$indent = false,$wordwrap = false) {
- // Dumps to some very clean YAML. We'll have to add some more features
- // and options soon. And better support for folding.
-
- // New features and options.
- if ($indent === false or !is_numeric($indent)) {
- $this->_dumpIndent = 2;
- } else {
- $this->_dumpIndent = $indent;
- }
-
- if ($wordwrap === false or !is_numeric($wordwrap)) {
- $this->_dumpWordWrap = 40;
- } else {
- $this->_dumpWordWrap = $wordwrap;
- }
-
- // New YAML document
- $string = "---\n";
-
- // Start at the base of the array and move through it.
- if ($array) {
- $array = (array)$array;
- $previous_key = -1;
- foreach ($array as $key => $value) {
- if (!isset($first_key)) $first_key = $key;
- $string .= $this->_yamlize($key,$value,0,$previous_key, $first_key, $array);
- $previous_key = $key;
- }
- }
- return $string;
- }
-
- /**
- * Attempts to convert a key / value array item to YAML
- * @access private
- * @return string
- * @param $key The name of the key
- * @param $value The value of the item
- * @param $indent The indent of the current node
- */
- private function _yamlize($key,$value,$indent, $previous_key = -1, $first_key = 0, $source_array = null) {
- if (is_array($value)) {
- if (empty ($value))
- return $this->_dumpNode($key, array(), $indent, $previous_key, $first_key, $source_array);
- // It has children. What to do?
- // Make it the right kind of item
- $string = $this->_dumpNode($key, self::REMPTY, $indent, $previous_key, $first_key, $source_array);
- // Add the indent
- $indent += $this->_dumpIndent;
- // Yamlize the array
- $string .= $this->_yamlizeArray($value,$indent);
- } elseif (!is_array($value)) {
- // It doesn't have children. Yip.
- $string = $this->_dumpNode($key, $value, $indent, $previous_key, $first_key, $source_array);
- }
- return $string;
- }
-
- /**
- * Attempts to convert an array to YAML
- * @access private
- * @return string
- * @param $array The array you want to convert
- * @param $indent The indent of the current level
- */
- private function _yamlizeArray($array,$indent) {
- if (is_array($array)) {
- $string = '';
- $previous_key = -1;
- foreach ($array as $key => $value) {
- if (!isset($first_key)) $first_key = $key;
- $string .= $this->_yamlize($key, $value, $indent, $previous_key, $first_key, $array);
- $previous_key = $key;
- }
- return $string;
- } else {
- return false;
- }
- }
-
- /**
- * Returns YAML from a key and a value
- * @access private
- * @return string
- * @param $key The name of the key
- * @param $value The value of the item
- * @param $indent The indent of the current node
- */
- private function _dumpNode($key, $value, $indent, $previous_key = -1, $first_key = 0, $source_array = null) {
- // do some folding here, for blocks
- if (is_string ($value) && ((strpos($value,"\n") !== false || strpos($value,": ") !== false || strpos($value,"- ") !== false ||
- strpos($value,"*") !== false || strpos($value,"#") !== false || strpos($value,"<") !== false || strpos($value,">") !== false || strpos ($value, ' ') !== false ||
- strpos($value,"[") !== false || strpos($value,"]") !== false || strpos($value,"{") !== false || strpos($value,"}") !== false) || strpos($value,"&") !== false || strpos($value, "'") !== false || strpos($value, "!") === 0 ||
- substr ($value, -1, 1) == ':')
- ) {
- $value = $this->_doLiteralBlock($value,$indent);
- } else {
- $value = $this->_doFolding($value,$indent);
- }
-
- if ($value === array()) $value = '[ ]';
- if (in_array ($value, array ('true', 'TRUE', 'false', 'FALSE', 'y', 'Y', 'n', 'N', 'null', 'NULL'), true)) {
- $value = $this->_doLiteralBlock($value,$indent);
- }
- if (trim ($value) != $value)
- $value = $this->_doLiteralBlock($value,$indent);
-
- if (is_bool($value)) {
- $value = ($value) ? "true" : "false";
- }
-
- if ($value === null) $value = 'null';
- if ($value === "'" . self::REMPTY . "'") $value = null;
-
- $spaces = str_repeat(' ',$indent);
-
- //if (is_int($key) && $key - 1 == $previous_key && $first_key===0) {
- if (is_array ($source_array) && array_keys($source_array) === range(0, count($source_array) - 1)) {
- // It's a sequence
- $string = $spaces.'- '.$value."\n";
- } else {
- // if ($first_key===0) throw new Exception('Keys are all screwy. The first one was zero, now it\'s "'. $key .'"');
- // It's mapped
- if (strpos($key, ":") !== false || strpos($key, "#") !== false) { $key = '"' . $key . '"'; }
- $string = rtrim ($spaces.$key.': '.$value)."\n";
- }
- return $string;
- }
-
- /**
- * Creates a literal block for dumping
- * @access private
- * @return string
- * @param $value
- * @param $indent int The value of the indent
- */
- private function _doLiteralBlock($value,$indent) {
- if ($value === "\n") return '\n';
- if (strpos($value, "\n") === false && strpos($value, "'") === false) {
- return sprintf ("'%s'", $value);
- }
- if (strpos($value, "\n") === false && strpos($value, '"') === false) {
- return sprintf ('"%s"', $value);
- }
- $exploded = explode("\n",$value);
- $newValue = '|';
- $indent += $this->_dumpIndent;
- $spaces = str_repeat(' ',$indent);
- foreach ($exploded as $line) {
- $newValue .= "\n" . $spaces . ($line);
- }
- return $newValue;
- }
-
- /**
- * Folds a string of text, if necessary
- * @access private
- * @return string
- * @param $value The string you wish to fold
- */
- private function _doFolding($value,$indent) {
- // Don't do anything if wordwrap is set to 0
-
- if ($this->_dumpWordWrap !== 0 && is_string ($value) && strlen($value) > $this->_dumpWordWrap) {
- $indent += $this->_dumpIndent;
- $indent = str_repeat(' ',$indent);
- $wrapped = wordwrap($value,$this->_dumpWordWrap,"\n$indent");
- $value = ">\n".$indent.$wrapped;
- } else {
- if ($this->setting_dump_force_quotes && is_string ($value) && $value !== self::REMPTY)
- $value = '"' . $value . '"';
- }
-
-
- return $value;
- }
-
-// LOADING FUNCTIONS
-
- private function __load($input) {
- $Source = $this->loadFromSource($input);
- return $this->loadWithSource($Source);
- }
-
- private function __loadString($input) {
- $Source = $this->loadFromString($input);
- return $this->loadWithSource($Source);
- }
-
- private function loadWithSource($Source) {
- if (empty ($Source)) return array();
- if ($this->setting_use_syck_is_possible && function_exists ('syck_load')) {
- $array = syck_load (implode ('', $Source));
- return is_array($array) ? $array : array();
- }
-
- $this->path = array();
- $this->result = array();
-
- $cnt = count($Source);
- for ($i = 0; $i < $cnt; $i++) {
- $line = $Source[$i];
-
- $this->indent = strlen($line) - strlen(ltrim($line));
- $tempPath = $this->getParentPathByIndent($this->indent);
- $line = self::stripIndent($line, $this->indent);
- if (self::isComment($line)) continue;
- if (self::isEmpty($line)) continue;
- $this->path = $tempPath;
-
- $literalBlockStyle = self::startsLiteralBlock($line);
- if ($literalBlockStyle) {
- $line = rtrim ($line, $literalBlockStyle . " \n");
- $literalBlock = '';
- $line .= $this->LiteralPlaceHolder;
- $literal_block_indent = strlen($Source[$i+1]) - strlen(ltrim($Source[$i+1]));
- while (++$i < $cnt && $this->literalBlockContinues($Source[$i], $this->indent)) {
- $literalBlock = $this->addLiteralLine($literalBlock, $Source[$i], $literalBlockStyle, $literal_block_indent);
- }
- $i--;
- }
-
- while (++$i < $cnt && self::greedilyNeedNextLine($line)) {
- $line = rtrim ($line, " \n\t\r") . ' ' . ltrim ($Source[$i], " \t");
- }
- $i--;
-
-
-
- if (strpos ($line, '#')) {
- if (strpos ($line, '"') === false && strpos ($line, "'") === false)
- $line = preg_replace('/\s+#(.+)$/','',$line);
- }
-
- $lineArray = $this->_parseLine($line);
-
- if ($literalBlockStyle)
- $lineArray = $this->revertLiteralPlaceHolder ($lineArray, $literalBlock);
-
- $this->addArray($lineArray, $this->indent);
-
- foreach ($this->delayedPath as $indent => $delayedPath)
- $this->path[$indent] = $delayedPath;
-
- $this->delayedPath = array();
-
- }
- return $this->result;
- }
-
- private function loadFromSource ($input) {
- if (!empty($input) && strpos($input, "\n") === false && file_exists($input))
- return file($input);
-
- return $this->loadFromString($input);
- }
-
- private function loadFromString ($input) {
- $lines = explode("\n",$input);
- foreach ($lines as $k => $_) {
- $lines[$k] = rtrim ($_, "\r");
- }
- return $lines;
- }
-
- /**
- * Parses YAML code and returns an array for a node
- * @access private
- * @return array
- * @param string $line A line from the YAML file
- */
- private function _parseLine($line) {
- if (!$line) return array();
- $line = trim($line);
- if (!$line) return array();
-
- $array = array();
-
- $group = $this->nodeContainsGroup($line);
- if ($group) {
- $this->addGroup($line, $group);
- $line = $this->stripGroup ($line, $group);
- }
-
- if ($this->startsMappedSequence($line))
- return $this->returnMappedSequence($line);
-
- if ($this->startsMappedValue($line))
- return $this->returnMappedValue($line);
-
- if ($this->isArrayElement($line))
- return $this->returnArrayElement($line);
-
- if ($this->isPlainArray($line))
- return $this->returnPlainArray($line);
-
-
- return $this->returnKeyValuePair($line);
-
- }
-
- /**
- * Finds the type of the passed value, returns the value as the new type.
- * @access private
- * @param string $value
- * @return mixed
- */
- private function _toType($value) {
- if ($value === '') return null;
- $first_character = $value[0];
- $last_character = substr($value, -1, 1);
-
- $is_quoted = false;
- do {
- if (!$value) break;
- if ($first_character != '"' && $first_character != "'") break;
- if ($last_character != '"' && $last_character != "'") break;
- $is_quoted = true;
- } while (0);
-
- if ($is_quoted)
- return strtr(substr ($value, 1, -1), array ('\\"' => '"', '\'\'' => '\'', '\\\'' => '\''));
-
- if (strpos($value, ' #') !== false && !$is_quoted)
- $value = preg_replace('/\s+#(.+)$/','',$value);
-
- if (!$is_quoted) $value = str_replace('\n', "\n", $value);
-
- if ($first_character == '[' && $last_character == ']') {
- // Take out strings sequences and mappings
- $innerValue = trim(substr ($value, 1, -1));
- if ($innerValue === '') return array();
- $explode = $this->_inlineEscape($innerValue);
- // Propagate value array
- $value = array();
- foreach ($explode as $v) {
- $value[] = $this->_toType($v);
- }
- return $value;
- }
-
- if (strpos($value,': ')!==false && $first_character != '{') {
- $array = explode(': ',$value);
- $key = trim($array[0]);
- array_shift($array);
- $value = trim(implode(': ',$array));
- $value = $this->_toType($value);
- return array($key => $value);
- }
-
- if ($first_character == '{' && $last_character == '}') {
- $innerValue = trim(substr ($value, 1, -1));
- if ($innerValue === '') return array();
- // Inline Mapping
- // Take out strings sequences and mappings
- $explode = $this->_inlineEscape($innerValue);
- // Propagate value array
- $array = array();
- foreach ($explode as $v) {
- $SubArr = $this->_toType($v);
- if (empty($SubArr)) continue;
- if (is_array ($SubArr)) {
- $array[key($SubArr)] = $SubArr[key($SubArr)]; continue;
- }
- $array[] = $SubArr;
- }
- return $array;
- }
-
- if ($value == 'null' || $value == 'NULL' || $value == 'Null' || $value == '' || $value == '~') {
- return null;
- }
-
- if ( is_numeric($value) && preg_match ('/^(-|)[1-9]+[0-9]*$/', $value) ){
- $intvalue = (int)$value;
- if ($intvalue != PHP_INT_MAX)
- $value = $intvalue;
- return $value;
- }
-
- if (in_array($value,
- array('true', 'on', '+', 'yes', 'y', 'True', 'TRUE', 'On', 'ON', 'YES', 'Yes', 'Y'))) {
- return true;
- }
-
- if (in_array(strtolower($value),
- array('false', 'off', '-', 'no', 'n'))) {
- return false;
- }
-
- if (is_numeric($value)) {
- if ($value === '0') return 0;
- if (rtrim ($value, 0) === $value)
- $value = (float)$value;
- return $value;
- }
-
- return $value;
- }
-
- /**
- * Used in inlines to check for more inlines or quoted strings
- * @access private
- * @return array
- */
- private function _inlineEscape($inline) {
- // There's gotta be a cleaner way to do this...
- // While pure sequences seem to be nesting just fine,
- // pure mappings and mappings with sequences inside can't go very
- // deep. This needs to be fixed.
-
- $seqs = array();
- $maps = array();
- $saved_strings = array();
-
- // Check for strings
- $regex = '/(?:(")|(?:\'))((?(1)[^"]+|[^\']+))(?(1)"|\')/';
- if (preg_match_all($regex,$inline,$strings)) {
- $saved_strings = $strings[0];
- $inline = preg_replace($regex,'YAMLString',$inline);
- }
- unset($regex);
-
- $i = 0;
- do {
-
- // Check for sequences
- while (preg_match('/\[([^{}\[\]]+)\]/U',$inline,$matchseqs)) {
- $seqs[] = $matchseqs[0];
- $inline = preg_replace('/\[([^{}\[\]]+)\]/U', ('YAMLSeq' . (count($seqs) - 1) . 's'), $inline, 1);
- }
-
- // Check for mappings
- while (preg_match('/{([^\[\]{}]+)}/U',$inline,$matchmaps)) {
- $maps[] = $matchmaps[0];
- $inline = preg_replace('/{([^\[\]{}]+)}/U', ('YAMLMap' . (count($maps) - 1) . 's'), $inline, 1);
- }
-
- if ($i++ >= 10) break;
-
- } while (strpos ($inline, '[') !== false || strpos ($inline, '{') !== false);
-
- $explode = explode(', ',$inline);
- $stringi = 0; $i = 0;
-
- while (1) {
-
- // Re-add the sequences
- if (!empty($seqs)) {
- foreach ($explode as $key => $value) {
- if (strpos($value,'YAMLSeq') !== false) {
- foreach ($seqs as $seqk => $seq) {
- $explode[$key] = str_replace(('YAMLSeq'.$seqk.'s'),$seq,$value);
- $value = $explode[$key];
- }
- }
- }
- }
-
- // Re-add the mappings
- if (!empty($maps)) {
- foreach ($explode as $key => $value) {
- if (strpos($value,'YAMLMap') !== false) {
- foreach ($maps as $mapk => $map) {
- $explode[$key] = str_replace(('YAMLMap'.$mapk.'s'), $map, $value);
- $value = $explode[$key];
- }
- }
- }
- }
-
-
- // Re-add the strings
- if (!empty($saved_strings)) {
- foreach ($explode as $key => $value) {
- while (strpos($value,'YAMLString') !== false) {
- $explode[$key] = preg_replace('/YAMLString/',$saved_strings[$stringi],$value, 1);
- unset($saved_strings[$stringi]);
- ++$stringi;
- $value = $explode[$key];
- }
- }
- }
-
- $finished = true;
- foreach ($explode as $key => $value) {
- if (strpos($value,'YAMLSeq') !== false) {
- $finished = false; break;
- }
- if (strpos($value,'YAMLMap') !== false) {
- $finished = false; break;
- }
- if (strpos($value,'YAMLString') !== false) {
- $finished = false; break;
- }
- }
- if ($finished) break;
-
- $i++;
- if ($i > 10)
- break; // Prevent infinite loops.
- }
-
- return $explode;
- }
-
- private function literalBlockContinues ($line, $lineIndent) {
- if (!trim($line)) return true;
- if (strlen($line) - strlen(ltrim($line)) > $lineIndent) return true;
- return false;
- }
-
- private function referenceContentsByAlias ($alias) {
- do {
- if (!isset($this->SavedGroups[$alias])) { echo "Bad group name: $alias."; break; }
- $groupPath = $this->SavedGroups[$alias];
- $value = $this->result;
- foreach ($groupPath as $k) {
- $value = $value[$k];
- }
- } while (false);
- return $value;
- }
-
- private function addArrayInline ($array, $indent) {
- $CommonGroupPath = $this->path;
- if (empty ($array)) return false;
-
- foreach ($array as $k => $_) {
- $this->addArray(array($k => $_), $indent);
- $this->path = $CommonGroupPath;
- }
- return true;
- }
-
- private function addArray ($incoming_data, $incoming_indent) {
-
- // print_r ($incoming_data);
-
- if (count ($incoming_data) > 1)
- return $this->addArrayInline ($incoming_data, $incoming_indent);
-
- $key = key ($incoming_data);
- $value = isset($incoming_data[$key]) ? $incoming_data[$key] : null;
- if ($key === '__!YAMLZero') $key = '0';
-
- if ($incoming_indent == 0 && !$this->_containsGroupAlias && !$this->_containsGroupAnchor) { // Shortcut for root-level values.
- if ($key || $key === '' || $key === '0') {
- $this->result[$key] = $value;
- } else {
- $this->result[] = $value; end ($this->result); $key = key ($this->result);
- }
- $this->path[$incoming_indent] = $key;
- return;
- }
-
-
-
- $history = array();
- // Unfolding inner array tree.
- $history[] = $_arr = $this->result;
- foreach ($this->path as $k) {
- $history[] = $_arr = $_arr[$k];
- }
-
- if ($this->_containsGroupAlias) {
- $value = $this->referenceContentsByAlias($this->_containsGroupAlias);
- $this->_containsGroupAlias = false;
- }
-
-
- // Adding string or numeric key to the innermost level or $this->arr.
- if (is_string($key) && $key == '<<') {
- if (!is_array ($_arr)) { $_arr = array (); }
-
- $_arr = array_merge ($_arr, $value);
- } else if ($key || $key === '' || $key === '0') {
- if (!is_array ($_arr))
- $_arr = array ($key=>$value);
- else
- $_arr[$key] = $value;
- } else {
- if (!is_array ($_arr)) { $_arr = array ($value); $key = 0; }
- else { $_arr[] = $value; end ($_arr); $key = key ($_arr); }
- }
-
- $reverse_path = array_reverse($this->path);
- $reverse_history = array_reverse ($history);
- $reverse_history[0] = $_arr;
- $cnt = count($reverse_history) - 1;
- for ($i = 0; $i < $cnt; $i++) {
- $reverse_history[$i+1][$reverse_path[$i]] = $reverse_history[$i];
- }
- $this->result = $reverse_history[$cnt];
-
- $this->path[$incoming_indent] = $key;
-
- if ($this->_containsGroupAnchor) {
- $this->SavedGroups[$this->_containsGroupAnchor] = $this->path;
- if (is_array ($value)) {
- $k = key ($value);
- if (!is_int ($k)) {
- $this->SavedGroups[$this->_containsGroupAnchor][$incoming_indent + 2] = $k;
- }
- }
- $this->_containsGroupAnchor = false;
- }
-
- }
-
- private static function startsLiteralBlock ($line) {
- $lastChar = substr (trim($line), -1);
- if ($lastChar != '>' && $lastChar != '|') return false;
- if ($lastChar == '|') return $lastChar;
- // HTML tags should not be counted as literal blocks.
- if (preg_match ('#<.*?>$#', $line)) return false;
- return $lastChar;
- }
-
- private static function greedilyNeedNextLine($line) {
- $line = trim ($line);
- if (!strlen($line)) return false;
- if (substr ($line, -1, 1) == ']') return false;
- if ($line[0] == '[') return true;
- if (preg_match ('#^[^:]+?:\s*\[#', $line)) return true;
- return false;
- }
-
- private function addLiteralLine ($literalBlock, $line, $literalBlockStyle, $indent = -1) {
- $line = self::stripIndent($line, $indent);
- if ($literalBlockStyle !== '|') {
- $line = self::stripIndent($line);
- }
- $line = rtrim ($line, "\r\n\t ") . "\n";
- if ($literalBlockStyle == '|') {
- return $literalBlock . $line;
- }
- if (strlen($line) == 0)
- return rtrim($literalBlock, ' ') . "\n";
- if ($line == "\n" && $literalBlockStyle == '>') {
- return rtrim ($literalBlock, " \t") . "\n";
- }
- if ($line != "\n")
- $line = trim ($line, "\r\n ") . " ";
- return $literalBlock . $line;
- }
-
- function revertLiteralPlaceHolder ($lineArray, $literalBlock) {
- foreach ($lineArray as $k => $_) {
- if (is_array($_))
- $lineArray[$k] = $this->revertLiteralPlaceHolder ($_, $literalBlock);
- else if (substr($_, -1 * strlen ($this->LiteralPlaceHolder)) == $this->LiteralPlaceHolder)
- $lineArray[$k] = rtrim ($literalBlock, " \r\n");
- }
- return $lineArray;
- }
-
- private static function stripIndent ($line, $indent = -1) {
- if ($indent == -1) $indent = strlen($line) - strlen(ltrim($line));
- return substr ($line, $indent);
- }
-
- private function getParentPathByIndent ($indent) {
- if ($indent == 0) return array();
- $linePath = $this->path;
- do {
- end($linePath); $lastIndentInParentPath = key($linePath);
- if ($indent <= $lastIndentInParentPath) array_pop ($linePath);
- } while ($indent <= $lastIndentInParentPath);
- return $linePath;
- }
-
-
- private function clearBiggerPathValues ($indent) {
-
-
- if ($indent == 0) $this->path = array();
- if (empty ($this->path)) return true;
-
- foreach ($this->path as $k => $_) {
- if ($k > $indent) unset ($this->path[$k]);
- }
-
- return true;
- }
-
-
- private static function isComment ($line) {
- if (!$line) return false;
- if ($line[0] == '#') return true;
- if (trim($line, " \r\n\t") == '---') return true;
- return false;
- }
-
- private static function isEmpty ($line) {
- return (trim ($line) === '');
- }
-
-
- private function isArrayElement ($line) {
- if (!$line) return false;
- if ($line[0] != '-') return false;
- if (strlen ($line) > 3)
- if (substr($line,0,3) == '---') return false;
-
- return true;
- }
-
- private function isHashElement ($line) {
- return strpos($line, ':');
- }
-
- private function isLiteral ($line) {
- if ($this->isArrayElement($line)) return false;
- if ($this->isHashElement($line)) return false;
- return true;
- }
-
-
- private static function unquote ($value) {
- if (!$value) return $value;
- if (!is_string($value)) return $value;
- if ($value[0] == '\'') return trim ($value, '\'');
- if ($value[0] == '"') return trim ($value, '"');
- return $value;
- }
-
- private function startsMappedSequence ($line) {
- return ($line[0] == '-' && substr ($line, -1, 1) == ':');
- }
-
- private function returnMappedSequence ($line) {
- $array = array();
- $key = self::unquote(trim(substr($line,1,-1)));
- $array[$key] = array();
- $this->delayedPath = array(strpos ($line, $key) + $this->indent => $key);
- return array($array);
- }
-
- private function returnMappedValue ($line) {
- $array = array();
- $key = self::unquote (trim(substr($line,0,-1)));
- $array[$key] = '';
- return $array;
- }
-
- private function startsMappedValue ($line) {
- return (substr ($line, -1, 1) == ':');
- }
-
- private function isPlainArray ($line) {
- return ($line[0] == '[' && substr ($line, -1, 1) == ']');
- }
-
- private function returnPlainArray ($line) {
- return $this->_toType($line);
- }
-
- private function returnKeyValuePair ($line) {
- $array = array();
- $key = '';
- if (strpos ($line, ':')) {
- // It's a key/value pair most likely
- // If the key is in double quotes pull it out
- if (($line[0] == '"' || $line[0] == "'") && preg_match('/^(["\'](.*)["\'](\s)*:)/',$line,$matches)) {
- $value = trim(str_replace($matches[1],'',$line));
- $key = $matches[2];
- } else {
- // Do some guesswork as to the key and the value
- $explode = explode(':',$line);
- $key = trim($explode[0]);
- array_shift($explode);
- $value = trim(implode(':',$explode));
- }
- // Set the type of the value. Int, string, etc
- $value = $this->_toType($value);
- if ($key === '0') $key = '__!YAMLZero';
- $array[$key] = $value;
- } else {
- $array = array ($line);
- }
- return $array;
-
- }
-
-
- private function returnArrayElement ($line) {
- if (strlen($line) <= 1) return array(array()); // Weird %)
- $array = array();
- $value = trim(substr($line,1));
- $value = $this->_toType($value);
- $array[] = $value;
- return $array;
- }
-
-
- private function nodeContainsGroup ($line) {
- $symbolsForReference = 'A-z0-9_\-';
- if (strpos($line, '&') === false && strpos($line, '*') === false) return false; // Please die fast ;-)
- if ($line[0] == '&' && preg_match('/^(&['.$symbolsForReference.']+)/', $line, $matches)) return $matches[1];
- if ($line[0] == '*' && preg_match('/^(\*['.$symbolsForReference.']+)/', $line, $matches)) return $matches[1];
- if (preg_match('/(&['.$symbolsForReference.']+)$/', $line, $matches)) return $matches[1];
- if (preg_match('/(\*['.$symbolsForReference.']+$)/', $line, $matches)) return $matches[1];
- if (preg_match ('#^\s*<<\s*:\s*(\*[^\s]+).*$#', $line, $matches)) return $matches[1];
- return false;
-
- }
-
- private function addGroup ($line, $group) {
- if ($group[0] == '&') $this->_containsGroupAnchor = substr ($group, 1);
- if ($group[0] == '*') $this->_containsGroupAlias = substr ($group, 1);
- //print_r ($this->path);
- }
-
- private function stripGroup ($line, $group) {
- $line = trim(str_replace($group, '', $line));
- return $line;
- }
-}
-
-// Enable use of Spyc from command line
-// The syntax is the following: php spyc.php spyc.yaml
-
-define ('SPYC_FROM_COMMAND_LINE', false);
-
-do {
- if (!SPYC_FROM_COMMAND_LINE) break;
- if (empty ($_SERVER['argc']) || $_SERVER['argc'] < 2) break;
- if (empty ($_SERVER['PHP_SELF']) || $_SERVER['PHP_SELF'] != 'spyc.php') break;
- $file = $argv[1];
- printf ("Spyc loading file: %s\n", $file);
- print_r (spyc_load_file ($file));
+<?php
+/**
+ * Spyc -- A Simple PHP YAML Class
+ * @version 0.5
+ * @author Vlad Andersen <vlad.andersen@gmail.com>
+ * @author Chris Wanstrath <chris@ozmm.org>
+ * @link http://code.google.com/p/spyc/
+ * @copyright Copyright 2005-2006 Chris Wanstrath, 2006-2011 Vlad Andersen
+ * @license http://www.opensource.org/licenses/mit-license.php MIT License
+ * @package Spyc
+ */
+
+if (!function_exists('spyc_load')) {
+ /**
+ * Parses YAML to array.
+ * @param string $string YAML string.
+ * @return array
+ */
+ function spyc_load ($string) {
+ return Spyc::YAMLLoadString($string);
+ }
+}
+
+if (!function_exists('spyc_load_file')) {
+ /**
+ * Parses YAML to array.
+ * @param string $file Path to YAML file.
+ * @return array
+ */
+ function spyc_load_file ($file) {
+ return Spyc::YAMLLoad($file);
+ }
+}
+
+/**
+ * The Simple PHP YAML Class.
+ *
+ * This class can be used to read a YAML file and convert its contents
+ * into a PHP array. It currently supports a very limited subsection of
+ * the YAML spec.
+ *
+ * Usage:
+ * <code>
+ * $Spyc = new Spyc;
+ * $array = $Spyc->load($file);
+ * </code>
+ * or:
+ * <code>
+ * $array = Spyc::YAMLLoad($file);
+ * </code>
+ * or:
+ * <code>
+ * $array = spyc_load_file($file);
+ * </code>
+ * @package Spyc
+ */
+class Spyc {
+
+ // SETTINGS
+
+ const REMPTY = "\0\0\0\0\0";
+
+ /**
+ * Setting this to true will force YAMLDump to enclose any string value in
+ * quotes. False by default.
+ *
+ * @var bool
+ */
+ public $setting_dump_force_quotes = false;
+
+ /**
+ * Setting this to true will forse YAMLLoad to use syck_load function when
+ * possible. False by default.
+ * @var bool
+ */
+ public $setting_use_syck_is_possible = false;
+
+
+
+ /**#@+
+ * @access private
+ * @var mixed
+ */
+ private $_dumpIndent;
+ private $_dumpWordWrap;
+ private $_containsGroupAnchor = false;
+ private $_containsGroupAlias = false;
+ private $path;
+ private $result;
+ private $LiteralPlaceHolder = '___YAML_Literal_Block___';
+ private $SavedGroups = array();
+ private $indent;
+ /**
+ * Path modifier that should be applied after adding current element.
+ * @var array
+ */
+ private $delayedPath = array();
+
+ /**#@+
+ * @access public
+ * @var mixed
+ */
+ public $_nodeId;
+
+/**
+ * Load a valid YAML string to Spyc.
+ * @param string $input
+ * @return array
+ */
+ public function load ($input) {
+ return $this->__loadString($input);
+ }
+
+ /**
+ * Load a valid YAML file to Spyc.
+ * @param string $file
+ * @return array
+ */
+ public function loadFile ($file) {
+ return $this->__load($file);
+ }
+
+ /**
+ * Load YAML into a PHP array statically
+ *
+ * The load method, when supplied with a YAML stream (string or file),
+ * will do its best to convert YAML in a file into a PHP array. Pretty
+ * simple.
+ * Usage:
+ * <code>
+ * $array = Spyc::YAMLLoad('lucky.yaml');
+ * print_r($array);
+ * </code>
+ * @access public
+ * @return array
+ * @param string $input Path of YAML file or string containing YAML
+ */
+ public static function YAMLLoad($input) {
+ $Spyc = new Spyc;
+ return $Spyc->__load($input);
+ }
+
+ /**
+ * Load a string of YAML into a PHP array statically
+ *
+ * The load method, when supplied with a YAML string, will do its best
+ * to convert YAML in a string into a PHP array. Pretty simple.
+ *
+ * Note: use this function if you don't want files from the file system
+ * loaded and processed as YAML. This is of interest to people concerned
+ * about security whose input is from a string.
+ *
+ * Usage:
+ * <code>
+ * $array = Spyc::YAMLLoadString("---\n0: hello world\n");
+ * print_r($array);
+ * </code>
+ * @access public
+ * @return array
+ * @param string $input String containing YAML
+ */
+ public static function YAMLLoadString($input) {
+ $Spyc = new Spyc;
+ return $Spyc->__loadString($input);
+ }
+
+ /**
+ * Dump YAML from PHP array statically
+ *
+ * The dump method, when supplied with an array, will do its best
+ * to convert the array into friendly YAML. Pretty simple. Feel free to
+ * save the returned string as nothing.yaml and pass it around.
+ *
+ * Oh, and you can decide how big the indent is and what the wordwrap
+ * for folding is. Pretty cool -- just pass in 'false' for either if
+ * you want to use the default.
+ *
+ * Indent's default is 2 spaces, wordwrap's default is 40 characters. And
+ * you can turn off wordwrap by passing in 0.
+ *
+ * @access public
+ * @return string
+ * @param array $array PHP array
+ * @param int $indent Pass in false to use the default, which is 2
+ * @param int $wordwrap Pass in 0 for no wordwrap, false for default (40)
+ */
+ public static function YAMLDump($array,$indent = false,$wordwrap = false) {
+ $spyc = new Spyc;
+ return $spyc->dump($array,$indent,$wordwrap);
+ }
+
+
+ /**
+ * Dump PHP array to YAML
+ *
+ * The dump method, when supplied with an array, will do its best
+ * to convert the array into friendly YAML. Pretty simple. Feel free to
+ * save the returned string as tasteful.yaml and pass it around.
+ *
+ * Oh, and you can decide how big the indent is and what the wordwrap
+ * for folding is. Pretty cool -- just pass in 'false' for either if
+ * you want to use the default.
+ *
+ * Indent's default is 2 spaces, wordwrap's default is 40 characters. And
+ * you can turn off wordwrap by passing in 0.
+ *
+ * @access public
+ * @return string
+ * @param array $array PHP array
+ * @param int $indent Pass in false to use the default, which is 2
+ * @param int $wordwrap Pass in 0 for no wordwrap, false for default (40)
+ */
+ public function dump($array,$indent = false,$wordwrap = false) {
+ // Dumps to some very clean YAML. We'll have to add some more features
+ // and options soon. And better support for folding.
+
+ // New features and options.
+ if ($indent === false or !is_numeric($indent)) {
+ $this->_dumpIndent = 2;
+ } else {
+ $this->_dumpIndent = $indent;
+ }
+
+ if ($wordwrap === false or !is_numeric($wordwrap)) {
+ $this->_dumpWordWrap = 40;
+ } else {
+ $this->_dumpWordWrap = $wordwrap;
+ }
+
+ // New YAML document
+ $string = "---\n";
+
+ // Start at the base of the array and move through it.
+ if ($array) {
+ $array = (array)$array;
+ $previous_key = -1;
+ foreach ($array as $key => $value) {
+ if (!isset($first_key)) $first_key = $key;
+ $string .= $this->_yamlize($key,$value,0,$previous_key, $first_key, $array);
+ $previous_key = $key;
+ }
+ }
+ return $string;
+ }
+
+ /**
+ * Attempts to convert a key / value array item to YAML
+ * @access private
+ * @return string
+ * @param $key The name of the key
+ * @param $value The value of the item
+ * @param $indent The indent of the current node
+ */
+ private function _yamlize($key,$value,$indent, $previous_key = -1, $first_key = 0, $source_array = null) {
+ if (is_array($value)) {
+ if (empty ($value))
+ return $this->_dumpNode($key, array(), $indent, $previous_key, $first_key, $source_array);
+ // It has children. What to do?
+ // Make it the right kind of item
+ $string = $this->_dumpNode($key, self::REMPTY, $indent, $previous_key, $first_key, $source_array);
+ // Add the indent
+ $indent += $this->_dumpIndent;
+ // Yamlize the array
+ $string .= $this->_yamlizeArray($value,$indent);
+ } elseif (!is_array($value)) {
+ // It doesn't have children. Yip.
+ $string = $this->_dumpNode($key, $value, $indent, $previous_key, $first_key, $source_array);
+ }
+ return $string;
+ }
+
+ /**
+ * Attempts to convert an array to YAML
+ * @access private
+ * @return string
+ * @param $array The array you want to convert
+ * @param $indent The indent of the current level
+ */
+ private function _yamlizeArray($array,$indent) {
+ if (is_array($array)) {
+ $string = '';
+ $previous_key = -1;
+ foreach ($array as $key => $value) {
+ if (!isset($first_key)) $first_key = $key;
+ $string .= $this->_yamlize($key, $value, $indent, $previous_key, $first_key, $array);
+ $previous_key = $key;
+ }
+ return $string;
+ } else {
+ return false;
+ }
+ }
+
+ /**
+ * Returns YAML from a key and a value
+ * @access private
+ * @return string
+ * @param $key The name of the key
+ * @param $value The value of the item
+ * @param $indent The indent of the current node
+ */
+ private function _dumpNode($key, $value, $indent, $previous_key = -1, $first_key = 0, $source_array = null) {
+ // do some folding here, for blocks
+ if (is_string ($value) && ((strpos($value,"\n") !== false || strpos($value,": ") !== false || strpos($value,"- ") !== false ||
+ strpos($value,"*") !== false || strpos($value,"#") !== false || strpos($value,"<") !== false || strpos($value,">") !== false || strpos ($value, ' ') !== false ||
+ strpos($value,"[") !== false || strpos($value,"]") !== false || strpos($value,"{") !== false || strpos($value,"}") !== false) || strpos($value,"&") !== false || strpos($value, "'") !== false || strpos($value, "!") === 0 ||
+ substr ($value, -1, 1) == ':')
+ ) {
+ $value = $this->_doLiteralBlock($value,$indent);
+ } else {
+ $value = $this->_doFolding($value,$indent);
+ }
+
+ if ($value === array()) $value = '[ ]';
+ if (in_array ($value, array ('true', 'TRUE', 'false', 'FALSE', 'y', 'Y', 'n', 'N', 'null', 'NULL'), true)) {
+ $value = $this->_doLiteralBlock($value,$indent);
+ }
+ if (trim ($value) != $value)
+ $value = $this->_doLiteralBlock($value,$indent);
+
+ if (is_bool($value)) {
+ $value = ($value) ? "true" : "false";
+ }
+
+ if ($value === null) $value = 'null';
+ if ($value === "'" . self::REMPTY . "'") $value = null;
+
+ $spaces = str_repeat(' ',$indent);
+
+ //if (is_int($key) && $key - 1 == $previous_key && $first_key===0) {
+ if (is_array ($source_array) && array_keys($source_array) === range(0, count($source_array) - 1)) {
+ // It's a sequence
+ $string = $spaces.'- '.$value."\n";
+ } else {
+ // if ($first_key===0) throw new Exception('Keys are all screwy. The first one was zero, now it\'s "'. $key .'"');
+ // It's mapped
+ if (strpos($key, ":") !== false || strpos($key, "#") !== false) { $key = '"' . $key . '"'; }
+ $string = rtrim ($spaces.$key.': '.$value)."\n";
+ }
+ return $string;
+ }
+
+ /**
+ * Creates a literal block for dumping
+ * @access private
+ * @return string
+ * @param $value
+ * @param $indent int The value of the indent
+ */
+ private function _doLiteralBlock($value,$indent) {
+ if ($value === "\n") return '\n';
+ if (strpos($value, "\n") === false && strpos($value, "'") === false) {
+ return sprintf ("'%s'", $value);
+ }
+ if (strpos($value, "\n") === false && strpos($value, '"') === false) {
+ return sprintf ('"%s"', $value);
+ }
+ $exploded = explode("\n",$value);
+ $newValue = '|';
+ $indent += $this->_dumpIndent;
+ $spaces = str_repeat(' ',$indent);
+ foreach ($exploded as $line) {
+ $newValue .= "\n" . $spaces . ($line);
+ }
+ return $newValue;
+ }
+
+ /**
+ * Folds a string of text, if necessary
+ * @access private
+ * @return string
+ * @param $value The string you wish to fold
+ */
+ private function _doFolding($value,$indent) {
+ // Don't do anything if wordwrap is set to 0
+
+ if ($this->_dumpWordWrap !== 0 && is_string ($value) && strlen($value) > $this->_dumpWordWrap) {
+ $indent += $this->_dumpIndent;
+ $indent = str_repeat(' ',$indent);
+ $wrapped = wordwrap($value,$this->_dumpWordWrap,"\n$indent");
+ $value = ">\n".$indent.$wrapped;
+ } else {
+ if ($this->setting_dump_force_quotes && is_string ($value) && $value !== self::REMPTY)
+ $value = '"' . $value . '"';
+ }
+
+
+ return $value;
+ }
+
+// LOADING FUNCTIONS
+
+ private function __load($input) {
+ $Source = $this->loadFromSource($input);
+ return $this->loadWithSource($Source);
+ }
+
+ private function __loadString($input) {
+ $Source = $this->loadFromString($input);
+ return $this->loadWithSource($Source);
+ }
+
+ private function loadWithSource($Source) {
+ if (empty ($Source)) return array();
+ if ($this->setting_use_syck_is_possible && function_exists ('syck_load')) {
+ $array = syck_load (implode ('', $Source));
+ return is_array($array) ? $array : array();
+ }
+
+ $this->path = array();
+ $this->result = array();
+
+ $cnt = count($Source);
+ for ($i = 0; $i < $cnt; $i++) {
+ $line = $Source[$i];
+
+ $this->indent = strlen($line) - strlen(ltrim($line));
+ $tempPath = $this->getParentPathByIndent($this->indent);
+ $line = self::stripIndent($line, $this->indent);
+ if (self::isComment($line)) continue;
+ if (self::isEmpty($line)) continue;
+ $this->path = $tempPath;
+
+ $literalBlockStyle = self::startsLiteralBlock($line);
+ if ($literalBlockStyle) {
+ $line = rtrim ($line, $literalBlockStyle . " \n");
+ $literalBlock = '';
+ $line .= $this->LiteralPlaceHolder;
+ $literal_block_indent = strlen($Source[$i+1]) - strlen(ltrim($Source[$i+1]));
+ while (++$i < $cnt && $this->literalBlockContinues($Source[$i], $this->indent)) {
+ $literalBlock = $this->addLiteralLine($literalBlock, $Source[$i], $literalBlockStyle, $literal_block_indent);
+ }
+ $i--;
+ }
+
+ while (++$i < $cnt && self::greedilyNeedNextLine($line)) {
+ $line = rtrim ($line, " \n\t\r") . ' ' . ltrim ($Source[$i], " \t");
+ }
+ $i--;
+
+
+
+ if (strpos ($line, '#')) {
+ if (strpos ($line, '"') === false && strpos ($line, "'") === false)
+ $line = preg_replace('/\s+#(.+)$/','',$line);
+ }
+
+ $lineArray = $this->_parseLine($line);
+
+ if ($literalBlockStyle)
+ $lineArray = $this->revertLiteralPlaceHolder ($lineArray, $literalBlock);
+
+ $this->addArray($lineArray, $this->indent);
+
+ foreach ($this->delayedPath as $indent => $delayedPath)
+ $this->path[$indent] = $delayedPath;
+
+ $this->delayedPath = array();
+
+ }
+ return $this->result;
+ }
+
+ private function loadFromSource ($input) {
+ if (!empty($input) && strpos($input, "\n") === false && file_exists($input))
+ return file($input);
+
+ return $this->loadFromString($input);
+ }
+
+ private function loadFromString ($input) {
+ $lines = explode("\n",$input);
+ foreach ($lines as $k => $_) {
+ $lines[$k] = rtrim ($_, "\r");
+ }
+ return $lines;
+ }
+
+ /**
+ * Parses YAML code and returns an array for a node
+ * @access private
+ * @return array
+ * @param string $line A line from the YAML file
+ */
+ private function _parseLine($line) {
+ if (!$line) return array();
+ $line = trim($line);
+ if (!$line) return array();
+
+ $array = array();
+
+ $group = $this->nodeContainsGroup($line);
+ if ($group) {
+ $this->addGroup($line, $group);
+ $line = $this->stripGroup ($line, $group);
+ }
+
+ if ($this->startsMappedSequence($line))
+ return $this->returnMappedSequence($line);
+
+ if ($this->startsMappedValue($line))
+ return $this->returnMappedValue($line);
+
+ if ($this->isArrayElement($line))
+ return $this->returnArrayElement($line);
+
+ if ($this->isPlainArray($line))
+ return $this->returnPlainArray($line);
+
+
+ return $this->returnKeyValuePair($line);
+
+ }
+
+ /**
+ * Finds the type of the passed value, returns the value as the new type.
+ * @access private
+ * @param string $value
+ * @return mixed
+ */
+ private function _toType($value) {
+ if ($value === '') return null;
+ $first_character = $value[0];
+ $last_character = substr($value, -1, 1);
+
+ $is_quoted = false;
+ do {
+ if (!$value) break;
+ if ($first_character != '"' && $first_character != "'") break;
+ if ($last_character != '"' && $last_character != "'") break;
+ $is_quoted = true;
+ } while (0);
+
+ if ($is_quoted)
+ return strtr(substr ($value, 1, -1), array ('\\"' => '"', '\'\'' => '\'', '\\\'' => '\''));
+
+ if (strpos($value, ' #') !== false && !$is_quoted)
+ $value = preg_replace('/\s+#(.+)$/','',$value);
+
+ if (!$is_quoted) $value = str_replace('\n', "\n", $value);
+
+ if ($first_character == '[' && $last_character == ']') {
+ // Take out strings sequences and mappings
+ $innerValue = trim(substr ($value, 1, -1));
+ if ($innerValue === '') return array();
+ $explode = $this->_inlineEscape($innerValue);
+ // Propagate value array
+ $value = array();
+ foreach ($explode as $v) {
+ $value[] = $this->_toType($v);
+ }
+ return $value;
+ }
+
+ if (strpos($value,': ')!==false && $first_character != '{') {
+ $array = explode(': ',$value);
+ $key = trim($array[0]);
+ array_shift($array);
+ $value = trim(implode(': ',$array));
+ $value = $this->_toType($value);
+ return array($key => $value);
+ }
+
+ if ($first_character == '{' && $last_character == '}') {
+ $innerValue = trim(substr ($value, 1, -1));
+ if ($innerValue === '') return array();
+ // Inline Mapping
+ // Take out strings sequences and mappings
+ $explode = $this->_inlineEscape($innerValue);
+ // Propagate value array
+ $array = array();
+ foreach ($explode as $v) {
+ $SubArr = $this->_toType($v);
+ if (empty($SubArr)) continue;
+ if (is_array ($SubArr)) {
+ $array[key($SubArr)] = $SubArr[key($SubArr)]; continue;
+ }
+ $array[] = $SubArr;
+ }
+ return $array;
+ }
+
+ if ($value == 'null' || $value == 'NULL' || $value == 'Null' || $value == '' || $value == '~') {
+ return null;
+ }
+
+ if ( is_numeric($value) && preg_match ('/^(-|)[1-9]+[0-9]*$/', $value) ){
+ $intvalue = (int)$value;
+ if ($intvalue != PHP_INT_MAX)
+ $value = $intvalue;
+ return $value;
+ }
+
+ if (in_array($value,
+ array('true', 'on', '+', 'yes', 'y', 'True', 'TRUE', 'On', 'ON', 'YES', 'Yes', 'Y'))) {
+ return true;
+ }
+
+ if (in_array(strtolower($value),
+ array('false', 'off', '-', 'no', 'n'))) {
+ return false;
+ }
+
+ if (is_numeric($value)) {
+ if ($value === '0') return 0;
+ if (rtrim ($value, 0) === $value)
+ $value = (float)$value;
+ return $value;
+ }
+
+ return $value;
+ }
+
+ /**
+ * Used in inlines to check for more inlines or quoted strings
+ * @access private
+ * @return array
+ */
+ private function _inlineEscape($inline) {
+ // There's gotta be a cleaner way to do this...
+ // While pure sequences seem to be nesting just fine,
+ // pure mappings and mappings with sequences inside can't go very
+ // deep. This needs to be fixed.
+
+ $seqs = array();
+ $maps = array();
+ $saved_strings = array();
+
+ // Check for strings
+ $regex = '/(?:(")|(?:\'))((?(1)[^"]+|[^\']+))(?(1)"|\')/';
+ if (preg_match_all($regex,$inline,$strings)) {
+ $saved_strings = $strings[0];
+ $inline = preg_replace($regex,'YAMLString',$inline);
+ }
+ unset($regex);
+
+ $i = 0;
+ do {
+
+ // Check for sequences
+ while (preg_match('/\[([^{}\[\]]+)\]/U',$inline,$matchseqs)) {
+ $seqs[] = $matchseqs[0];
+ $inline = preg_replace('/\[([^{}\[\]]+)\]/U', ('YAMLSeq' . (count($seqs) - 1) . 's'), $inline, 1);
+ }
+
+ // Check for mappings
+ while (preg_match('/{([^\[\]{}]+)}/U',$inline,$matchmaps)) {
+ $maps[] = $matchmaps[0];
+ $inline = preg_replace('/{([^\[\]{}]+)}/U', ('YAMLMap' . (count($maps) - 1) . 's'), $inline, 1);
+ }
+
+ if ($i++ >= 10) break;
+
+ } while (strpos ($inline, '[') !== false || strpos ($inline, '{') !== false);
+
+ $explode = explode(', ',$inline);
+ $stringi = 0; $i = 0;
+
+ while (1) {
+
+ // Re-add the sequences
+ if (!empty($seqs)) {
+ foreach ($explode as $key => $value) {
+ if (strpos($value,'YAMLSeq') !== false) {
+ foreach ($seqs as $seqk => $seq) {
+ $explode[$key] = str_replace(('YAMLSeq'.$seqk.'s'),$seq,$value);
+ $value = $explode[$key];
+ }
+ }
+ }
+ }
+
+ // Re-add the mappings
+ if (!empty($maps)) {
+ foreach ($explode as $key => $value) {
+ if (strpos($value,'YAMLMap') !== false) {
+ foreach ($maps as $mapk => $map) {
+ $explode[$key] = str_replace(('YAMLMap'.$mapk.'s'), $map, $value);
+ $value = $explode[$key];
+ }
+ }
+ }
+ }
+
+
+ // Re-add the strings
+ if (!empty($saved_strings)) {
+ foreach ($explode as $key => $value) {
+ while (strpos($value,'YAMLString') !== false) {
+ $explode[$key] = preg_replace('/YAMLString/',$saved_strings[$stringi],$value, 1);
+ unset($saved_strings[$stringi]);
+ ++$stringi;
+ $value = $explode[$key];
+ }
+ }
+ }
+
+ $finished = true;
+ foreach ($explode as $key => $value) {
+ if (strpos($value,'YAMLSeq') !== false) {
+ $finished = false; break;
+ }
+ if (strpos($value,'YAMLMap') !== false) {
+ $finished = false; break;
+ }
+ if (strpos($value,'YAMLString') !== false) {
+ $finished = false; break;
+ }
+ }
+ if ($finished) break;
+
+ $i++;
+ if ($i > 10)
+ break; // Prevent infinite loops.
+ }
+
+ return $explode;
+ }
+
+ private function literalBlockContinues ($line, $lineIndent) {
+ if (!trim($line)) return true;
+ if (strlen($line) - strlen(ltrim($line)) > $lineIndent) return true;
+ return false;
+ }
+
+ private function referenceContentsByAlias ($alias) {
+ do {
+ if (!isset($this->SavedGroups[$alias])) { echo "Bad group name: $alias."; break; }
+ $groupPath = $this->SavedGroups[$alias];
+ $value = $this->result;
+ foreach ($groupPath as $k) {
+ $value = $value[$k];
+ }
+ } while (false);
+ return $value;
+ }
+
+ private function addArrayInline ($array, $indent) {
+ $CommonGroupPath = $this->path;
+ if (empty ($array)) return false;
+
+ foreach ($array as $k => $_) {
+ $this->addArray(array($k => $_), $indent);
+ $this->path = $CommonGroupPath;
+ }
+ return true;
+ }
+
+ private function addArray ($incoming_data, $incoming_indent) {
+
+ // print_r ($incoming_data);
+
+ if (count ($incoming_data) > 1)
+ return $this->addArrayInline ($incoming_data, $incoming_indent);
+
+ $key = key ($incoming_data);
+ $value = isset($incoming_data[$key]) ? $incoming_data[$key] : null;
+ if ($key === '__!YAMLZero') $key = '0';
+
+ if ($incoming_indent == 0 && !$this->_containsGroupAlias && !$this->_containsGroupAnchor) { // Shortcut for root-level values.
+ if ($key || $key === '' || $key === '0') {
+ $this->result[$key] = $value;
+ } else {
+ $this->result[] = $value; end ($this->result); $key = key ($this->result);
+ }
+ $this->path[$incoming_indent] = $key;
+ return;
+ }
+
+
+
+ $history = array();
+ // Unfolding inner array tree.
+ $history[] = $_arr = $this->result;
+ foreach ($this->path as $k) {
+ $history[] = $_arr = $_arr[$k];
+ }
+
+ if ($this->_containsGroupAlias) {
+ $value = $this->referenceContentsByAlias($this->_containsGroupAlias);
+ $this->_containsGroupAlias = false;
+ }
+
+
+ // Adding string or numeric key to the innermost level or $this->arr.
+ if (is_string($key) && $key == '<<') {
+ if (!is_array ($_arr)) { $_arr = array (); }
+
+ $_arr = array_merge ($_arr, $value);
+ } else if ($key || $key === '' || $key === '0') {
+ if (!is_array ($_arr))
+ $_arr = array ($key=>$value);
+ else
+ $_arr[$key] = $value;
+ } else {
+ if (!is_array ($_arr)) { $_arr = array ($value); $key = 0; }
+ else { $_arr[] = $value; end ($_arr); $key = key ($_arr); }
+ }
+
+ $reverse_path = array_reverse($this->path);
+ $reverse_history = array_reverse ($history);
+ $reverse_history[0] = $_arr;
+ $cnt = count($reverse_history) - 1;
+ for ($i = 0; $i < $cnt; $i++) {
+ $reverse_history[$i+1][$reverse_path[$i]] = $reverse_history[$i];
+ }
+ $this->result = $reverse_history[$cnt];
+
+ $this->path[$incoming_indent] = $key;
+
+ if ($this->_containsGroupAnchor) {
+ $this->SavedGroups[$this->_containsGroupAnchor] = $this->path;
+ if (is_array ($value)) {
+ $k = key ($value);
+ if (!is_int ($k)) {
+ $this->SavedGroups[$this->_containsGroupAnchor][$incoming_indent + 2] = $k;
+ }
+ }
+ $this->_containsGroupAnchor = false;
+ }
+
+ }
+
+ private static function startsLiteralBlock ($line) {
+ $lastChar = substr (trim($line), -1);
+ if ($lastChar != '>' && $lastChar != '|') return false;
+ if ($lastChar == '|') return $lastChar;
+ // HTML tags should not be counted as literal blocks.
+ if (preg_match ('#<.*?>$#', $line)) return false;
+ return $lastChar;
+ }
+
+ private static function greedilyNeedNextLine($line) {
+ $line = trim ($line);
+ if (!strlen($line)) return false;
+ if (substr ($line, -1, 1) == ']') return false;
+ if ($line[0] == '[') return true;
+ if (preg_match ('#^[^:]+?:\s*\[#', $line)) return true;
+ return false;
+ }
+
+ private function addLiteralLine ($literalBlock, $line, $literalBlockStyle, $indent = -1) {
+ $line = self::stripIndent($line, $indent);
+ if ($literalBlockStyle !== '|') {
+ $line = self::stripIndent($line);
+ }
+ $line = rtrim ($line, "\r\n\t ") . "\n";
+ if ($literalBlockStyle == '|') {
+ return $literalBlock . $line;
+ }
+ if (strlen($line) == 0)
+ return rtrim($literalBlock, ' ') . "\n";
+ if ($line == "\n" && $literalBlockStyle == '>') {
+ return rtrim ($literalBlock, " \t") . "\n";
+ }
+ if ($line != "\n")
+ $line = trim ($line, "\r\n ") . " ";
+ return $literalBlock . $line;
+ }
+
+ function revertLiteralPlaceHolder ($lineArray, $literalBlock) {
+ foreach ($lineArray as $k => $_) {
+ if (is_array($_))
+ $lineArray[$k] = $this->revertLiteralPlaceHolder ($_, $literalBlock);
+ else if (substr($_, -1 * strlen ($this->LiteralPlaceHolder)) == $this->LiteralPlaceHolder)
+ $lineArray[$k] = rtrim ($literalBlock, " \r\n");
+ }
+ return $lineArray;
+ }
+
+ private static function stripIndent ($line, $indent = -1) {
+ if ($indent == -1) $indent = strlen($line) - strlen(ltrim($line));
+ return substr ($line, $indent);
+ }
+
+ private function getParentPathByIndent ($indent) {
+ if ($indent == 0) return array();
+ $linePath = $this->path;
+ do {
+ end($linePath); $lastIndentInParentPath = key($linePath);
+ if ($indent <= $lastIndentInParentPath) array_pop ($linePath);
+ } while ($indent <= $lastIndentInParentPath);
+ return $linePath;
+ }
+
+
+ private function clearBiggerPathValues ($indent) {
+
+
+ if ($indent == 0) $this->path = array();
+ if (empty ($this->path)) return true;
+
+ foreach ($this->path as $k => $_) {
+ if ($k > $indent) unset ($this->path[$k]);
+ }
+
+ return true;
+ }
+
+
+ private static function isComment ($line) {
+ if (!$line) return false;
+ if ($line[0] == '#') return true;
+ if (trim($line, " \r\n\t") == '---') return true;
+ return false;
+ }
+
+ private static function isEmpty ($line) {
+ return (trim ($line) === '');
+ }
+
+
+ private function isArrayElement ($line) {
+ if (!$line) return false;
+ if ($line[0] != '-') return false;
+ if (strlen ($line) > 3)
+ if (substr($line,0,3) == '---') return false;
+
+ return true;
+ }
+
+ private function isHashElement ($line) {
+ return strpos($line, ':');
+ }
+
+ private function isLiteral ($line) {
+ if ($this->isArrayElement($line)) return false;
+ if ($this->isHashElement($line)) return false;
+ return true;
+ }
+
+
+ private static function unquote ($value) {
+ if (!$value) return $value;
+ if (!is_string($value)) return $value;
+ if ($value[0] == '\'') return trim ($value, '\'');
+ if ($value[0] == '"') return trim ($value, '"');
+ return $value;
+ }
+
+ private function startsMappedSequence ($line) {
+ return ($line[0] == '-' && substr ($line, -1, 1) == ':');
+ }
+
+ private function returnMappedSequence ($line) {
+ $array = array();
+ $key = self::unquote(trim(substr($line,1,-1)));
+ $array[$key] = array();
+ $this->delayedPath = array(strpos ($line, $key) + $this->indent => $key);
+ return array($array);
+ }
+
+ private function returnMappedValue ($line) {
+ $array = array();
+ $key = self::unquote (trim(substr($line,0,-1)));
+ $array[$key] = '';
+ return $array;
+ }
+
+ private function startsMappedValue ($line) {
+ return (substr ($line, -1, 1) == ':');
+ }
+
+ private function isPlainArray ($line) {
+ return ($line[0] == '[' && substr ($line, -1, 1) == ']');
+ }
+
+ private function returnPlainArray ($line) {
+ return $this->_toType($line);
+ }
+
+ private function returnKeyValuePair ($line) {
+ $array = array();
+ $key = '';
+ if (strpos ($line, ':')) {
+ // It's a key/value pair most likely
+ // If the key is in double quotes pull it out
+ if (($line[0] == '"' || $line[0] == "'") && preg_match('/^(["\'](.*)["\'](\s)*:)/',$line,$matches)) {
+ $value = trim(str_replace($matches[1],'',$line));
+ $key = $matches[2];
+ } else {
+ // Do some guesswork as to the key and the value
+ $explode = explode(':',$line);
+ $key = trim($explode[0]);
+ array_shift($explode);
+ $value = trim(implode(':',$explode));
+ }
+ // Set the type of the value. Int, string, etc
+ $value = $this->_toType($value);
+ if ($key === '0') $key = '__!YAMLZero';
+ $array[$key] = $value;
+ } else {
+ $array = array ($line);
+ }
+ return $array;
+
+ }
+
+
+ private function returnArrayElement ($line) {
+ if (strlen($line) <= 1) return array(array()); // Weird %)
+ $array = array();
+ $value = trim(substr($line,1));
+ $value = $this->_toType($value);
+ $array[] = $value;
+ return $array;
+ }
+
+
+ private function nodeContainsGroup ($line) {
+ $symbolsForReference = 'A-z0-9_\-';
+ if (strpos($line, '&') === false && strpos($line, '*') === false) return false; // Please die fast ;-)
+ if ($line[0] == '&' && preg_match('/^(&['.$symbolsForReference.']+)/', $line, $matches)) return $matches[1];
+ if ($line[0] == '*' && preg_match('/^(\*['.$symbolsForReference.']+)/', $line, $matches)) return $matches[1];
+ if (preg_match('/(&['.$symbolsForReference.']+)$/', $line, $matches)) return $matches[1];
+ if (preg_match('/(\*['.$symbolsForReference.']+$)/', $line, $matches)) return $matches[1];
+ if (preg_match ('#^\s*<<\s*:\s*(\*[^\s]+).*$#', $line, $matches)) return $matches[1];
+ return false;
+
+ }
+
+ private function addGroup ($line, $group) {
+ if ($group[0] == '&') $this->_containsGroupAnchor = substr ($group, 1);
+ if ($group[0] == '*') $this->_containsGroupAlias = substr ($group, 1);
+ //print_r ($this->path);
+ }
+
+ private function stripGroup ($line, $group) {
+ $line = trim(str_replace($group, '', $line));
+ return $line;
+ }
+}
+
+// Enable use of Spyc from command line
+// The syntax is the following: php spyc.php spyc.yaml
+
+define ('SPYC_FROM_COMMAND_LINE', false);
+
+do {
+ if (!SPYC_FROM_COMMAND_LINE) break;
+ if (empty ($_SERVER['argc']) || $_SERVER['argc'] < 2) break;
+ if (empty ($_SERVER['PHP_SELF']) || $_SERVER['PHP_SELF'] != 'spyc.php') break;
+ $file = $argv[1];
+ printf ("Spyc loading file: %s\n", $file);
+ print_r (spyc_load_file ($file));
} while (0); \ No newline at end of file
diff --git a/plugins/DevicesDetection/functions.php b/plugins/DevicesDetection/functions.php
index 34f8ed8690..0812741aec 100644
--- a/plugins/DevicesDetection/functions.php
+++ b/plugins/DevicesDetection/functions.php
@@ -130,18 +130,16 @@ function Piwik_getOsFullNameExtended($label)
if (!empty($label) && $label != ";") {
$os = substr($label, 0, 3);
$ver = substr($label, 4, 15);
- $osFullName = array_search($os, UserAgentParserEnhanced::$osShorts);
- if ($osFullName) {
- if (in_array($os, UserAgentParserEnhanced::$osFamilies['Windows'])) {
- return $osFullName;
- } else {
- return trim($osFullName . " " . $ver);
- }
+ $name = UserAgentParserEnhanced::getOsNameFromId($os, $ver);
+ if(!empty($name)) {
+ return $name;
}
}
return Piwik_Translate('General_Unknown');
}
+
+
function Piwik_getOsLogoExtended($label)
{
$short = substr($label, 0, 3);
diff --git a/plugins/DevicesDetection/lang/en.php b/plugins/DevicesDetection/lang/en.php
index 3df87d9fd5..d6470a95fe 100644
--- a/plugins/DevicesDetection/lang/en.php
+++ b/plugins/DevicesDetection/lang/en.php
@@ -1,7 +1,7 @@
<?php
$translations = array(
- "DevicesDetection_description" => "Plugin providing extended information about mobile devices visiting page. Also new, more specific reports are available.",
+ "DevicesDetection_description" => "This plugin provides extended information about mobile devices, such as Brand (manufacturer), Model (device version), better Device type detection (tv, consoles, smart phones, desktop, etc) and more. This plugin adds a new report in 'Visitors > Devices'.",
"DevicesDetection_submenu" => "Devices",
'DevicesDetection_DevicesDetection' => "Visitor devices",
// DataTable label translations for reports
diff --git a/tests/LocalTracker.php b/tests/LocalTracker.php
index 961fa17fe3..52d46b4c2b 100755
--- a/tests/LocalTracker.php
+++ b/tests/LocalTracker.php
@@ -47,6 +47,7 @@ class Piwik_LocalTracker extends PiwikTracker
// save some values
$plugins = Piwik_Config::getInstance()->Plugins['Plugins'];
+ $plugins[] = 'DevicesDetection';
$pluginsTracker = Piwik_Config::getInstance()->Plugins_Tracker['Plugins_Tracker'];
$oldTrackerConfig = Piwik_Config::getInstance()->Tracker;
diff --git a/tests/PHPUnit/Core/PluginsFunctions/WidgetsListTest.php b/tests/PHPUnit/Core/PluginsFunctions/WidgetsListTest.php
index 7c2c0e598c..f5861b94ca 100644
--- a/tests/PHPUnit/Core/PluginsFunctions/WidgetsListTest.php
+++ b/tests/PHPUnit/Core/PluginsFunctions/WidgetsListTest.php
@@ -70,9 +70,7 @@ class WidgetsListTest extends DatabaseTestCase
$_GET['idSite'] = 1;
- $pluginsManager = Piwik_PluginsManager::getInstance();
- $pluginsToLoad = Piwik_Config::getInstance()->Plugins['Plugins'];
- $pluginsManager->loadPlugins($pluginsToLoad);
+ IntegrationTestCase::loadAllPlugins();
Piwik_WidgetsList::_reset();
$widgets = Piwik_GetWidgetsList();
@@ -109,9 +107,7 @@ class WidgetsListTest extends DatabaseTestCase
$_GET['idSite'] = 1;
- $pluginsManager = Piwik_PluginsManager::getInstance();
- $pluginsToLoad = Piwik_Config::getInstance()->Plugins['Plugins'];
- $pluginsManager->loadPlugins($pluginsToLoad);
+ IntegrationTestCase::loadAllPlugins();
Piwik_WidgetsList::_reset();
$widgets = Piwik_GetWidgetsList();
diff --git a/tests/PHPUnit/Core/SegmentTest.php b/tests/PHPUnit/Core/SegmentTest.php
index c007cc9d20..2a00a0a9b9 100644
--- a/tests/PHPUnit/Core/SegmentTest.php
+++ b/tests/PHPUnit/Core/SegmentTest.php
@@ -17,14 +17,13 @@ class SegmentTest extends PHPUnit_Framework_TestCase
Zend_Registry::set('access', $pseudoMockAccess);
// Load and install plugins
- $pluginsManager = Piwik_PluginsManager::getInstance();
- $pluginsManager->loadPlugins(Piwik_Config::getInstance()->Plugins['Plugins']);
+ IntegrationTestCase::loadAllPlugins();
}
public function tearDown()
{
parent::tearDown();
- Piwik_PluginsManager::getInstance()->unloadPlugins();
+ IntegrationTestCase::unloadAllPlugins();
}
protected function _filterWhitsSpaces($valueToFilter)
diff --git a/tests/PHPUnit/IntegrationTestCase.php b/tests/PHPUnit/IntegrationTestCase.php
index 5dae1def65..a1a5c9948d 100755
--- a/tests/PHPUnit/IntegrationTestCase.php
+++ b/tests/PHPUnit/IntegrationTestCase.php
@@ -69,11 +69,11 @@ abstract class IntegrationTestCase extends PHPUnit_Framework_TestCase
}
}
-
public static function loadAllPlugins()
{
$pluginsManager = Piwik_PluginsManager::getInstance();
$pluginsToLoad = Piwik_Config::getInstance()->Plugins['Plugins'];
+ $pluginsToLoad[] = 'DevicesDetection';
$pluginsManager->loadPlugins($pluginsToLoad);
}
diff --git a/tests/PHPUnit/proxy/piwik.php b/tests/PHPUnit/proxy/piwik.php
index f70183ed16..0be50af23b 100755
--- a/tests/PHPUnit/proxy/piwik.php
+++ b/tests/PHPUnit/proxy/piwik.php
@@ -25,6 +25,13 @@ require_once PIWIK_INCLUDE_PATH . '/core/Loader.php';
Piwik::createConfigObject();
Piwik_Config::getInstance()->setTestEnvironment();
Piwik_Config::getInstance()->PluginsInstalled['PluginsInstalled'] = array();
+try {
+ $trackerPlugins = Piwik_Config::getInstance()->Plugins_Tracker['Plugins_Tracker'];
+}catch(Exception $e) {
+ $trackerPlugins = array();
+}
+$trackerPlugins[] = 'DevicesDetection';
+Piwik_Config::getInstance()->Plugins_Tracker['Plugins_Tracker'] = $trackerPlugins;
Piwik_UserCountry_LocationProvider_GeoIp::$geoIPDatabaseDir = 'tests/lib/geoip-files';
Piwik_Tracker::setTestEnvironment();